1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2000-2004 Sendmail, Inc. and its suppliers.
3*0Sstevel@tonic-gate  *      All rights reserved.
4*0Sstevel@tonic-gate  * Copyright (c) 1990, 1993
5*0Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
8*0Sstevel@tonic-gate  * Chris Torek.
9*0Sstevel@tonic-gate  *
10*0Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
11*0Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
12*0Sstevel@tonic-gate  * the sendmail distribution.
13*0Sstevel@tonic-gate  */
14*0Sstevel@tonic-gate 
15*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate #include <sm/gen.h>
18*0Sstevel@tonic-gate SM_RCSID("@(#)$Id: stdio.c,v 1.69 2004/08/03 20:46:34 ca Exp $")
19*0Sstevel@tonic-gate #include <unistd.h>
20*0Sstevel@tonic-gate #include <errno.h>
21*0Sstevel@tonic-gate #include <fcntl.h>
22*0Sstevel@tonic-gate #include <string.h>	/* FreeBSD: FD_ZERO needs <string.h> */
23*0Sstevel@tonic-gate #include <sys/stat.h>
24*0Sstevel@tonic-gate #include <sys/time.h>
25*0Sstevel@tonic-gate #include <sm/heap.h>
26*0Sstevel@tonic-gate #include <sm/assert.h>
27*0Sstevel@tonic-gate #include <sm/varargs.h>
28*0Sstevel@tonic-gate #include <sm/io.h>
29*0Sstevel@tonic-gate #include <sm/setjmp.h>
30*0Sstevel@tonic-gate #include <sm/conf.h>
31*0Sstevel@tonic-gate #include <sm/fdset.h>
32*0Sstevel@tonic-gate #include "local.h"
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate static int	sm_stdsetmode __P((SM_FILE_T *, const int *));
35*0Sstevel@tonic-gate static int	sm_stdgetmode __P((SM_FILE_T *, int *));
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate **  Overall:
39*0Sstevel@tonic-gate **  Small standard I/O/seek/close functions.
40*0Sstevel@tonic-gate **  These maintain the `known seek offset' for seek optimization.
41*0Sstevel@tonic-gate */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate /*
44*0Sstevel@tonic-gate **  SM_STDOPEN -- open a file with stdio behavior
45*0Sstevel@tonic-gate **
46*0Sstevel@tonic-gate **  Not associated with the system's stdio in libc.
47*0Sstevel@tonic-gate **
48*0Sstevel@tonic-gate **	Parameters:
49*0Sstevel@tonic-gate **		fp -- file pointer to be associated with the open
50*0Sstevel@tonic-gate **		info -- pathname of the file to be opened
51*0Sstevel@tonic-gate **		flags -- indicates type of access methods
52*0Sstevel@tonic-gate **		rpool -- ignored
53*0Sstevel@tonic-gate **
54*0Sstevel@tonic-gate **	Returns:
55*0Sstevel@tonic-gate **		Failure: -1 and set errno
56*0Sstevel@tonic-gate **		Success: 0 or greater (fd of file from open(2)).
57*0Sstevel@tonic-gate **
58*0Sstevel@tonic-gate */
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /* ARGSUSED3 */
61*0Sstevel@tonic-gate int
62*0Sstevel@tonic-gate sm_stdopen(fp, info, flags, rpool)
63*0Sstevel@tonic-gate 	SM_FILE_T *fp;
64*0Sstevel@tonic-gate 	const void *info;
65*0Sstevel@tonic-gate 	int flags;
66*0Sstevel@tonic-gate 	const void *rpool;
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	char *path = (char *) info;
69*0Sstevel@tonic-gate 	int oflags;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	switch (SM_IO_MODE(flags))
72*0Sstevel@tonic-gate 	{
73*0Sstevel@tonic-gate 	  case SM_IO_RDWR:
74*0Sstevel@tonic-gate 		oflags = O_RDWR;
75*0Sstevel@tonic-gate 		break;
76*0Sstevel@tonic-gate 	  case SM_IO_RDWRTR:
77*0Sstevel@tonic-gate 		oflags = O_RDWR | O_CREAT | O_TRUNC;
78*0Sstevel@tonic-gate 		break;
79*0Sstevel@tonic-gate 	  case SM_IO_RDONLY:
80*0Sstevel@tonic-gate 		oflags = O_RDONLY;
81*0Sstevel@tonic-gate 		break;
82*0Sstevel@tonic-gate 	  case SM_IO_WRONLY:
83*0Sstevel@tonic-gate 		oflags = O_WRONLY | O_CREAT | O_TRUNC;
84*0Sstevel@tonic-gate 		break;
85*0Sstevel@tonic-gate 	  case SM_IO_APPEND:
86*0Sstevel@tonic-gate 		oflags = O_APPEND | O_WRONLY | O_CREAT;
87*0Sstevel@tonic-gate 		break;
88*0Sstevel@tonic-gate 	  case SM_IO_APPENDRW:
89*0Sstevel@tonic-gate 		oflags = O_APPEND | O_RDWR | O_CREAT;
90*0Sstevel@tonic-gate 		break;
91*0Sstevel@tonic-gate 	  default:
92*0Sstevel@tonic-gate 		errno = EINVAL;
93*0Sstevel@tonic-gate 		return -1;
94*0Sstevel@tonic-gate 	}
95*0Sstevel@tonic-gate #ifdef O_BINARY
96*0Sstevel@tonic-gate 	if (SM_IS_BINARY(flags))
97*0Sstevel@tonic-gate 		oflags |= O_BINARY;
98*0Sstevel@tonic-gate #endif /* O_BINARY */
99*0Sstevel@tonic-gate 	fp->f_file = open(path, oflags,
100*0Sstevel@tonic-gate 			  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
101*0Sstevel@tonic-gate 	if (fp->f_file < 0)
102*0Sstevel@tonic-gate 		return -1; /* errno set by open() */
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	if (oflags & O_APPEND)
105*0Sstevel@tonic-gate 		(void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END);
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	return fp->f_file;
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate /*
111*0Sstevel@tonic-gate **  SM_STDREAD -- read from the file
112*0Sstevel@tonic-gate **
113*0Sstevel@tonic-gate **	Parameters:
114*0Sstevel@tonic-gate **		fp -- file pointer to read from
115*0Sstevel@tonic-gate **		buf -- location to place read data
116*0Sstevel@tonic-gate **		n -- number of bytes to read
117*0Sstevel@tonic-gate **
118*0Sstevel@tonic-gate **	Returns:
119*0Sstevel@tonic-gate **		Failure: -1 and sets errno
120*0Sstevel@tonic-gate **		Success: number of bytes read
121*0Sstevel@tonic-gate **
122*0Sstevel@tonic-gate **	Side Effects:
123*0Sstevel@tonic-gate **		Updates internal offset into file.
124*0Sstevel@tonic-gate */
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate ssize_t
127*0Sstevel@tonic-gate sm_stdread(fp, buf, n)
128*0Sstevel@tonic-gate 	SM_FILE_T *fp;
129*0Sstevel@tonic-gate 	char *buf;
130*0Sstevel@tonic-gate 	size_t n;
131*0Sstevel@tonic-gate {
132*0Sstevel@tonic-gate 	register int ret;
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	ret = read(fp->f_file, buf, n);
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	/* if the read succeeded, update the current offset */
137*0Sstevel@tonic-gate 	if (ret > 0)
138*0Sstevel@tonic-gate 		fp->f_lseekoff += ret;
139*0Sstevel@tonic-gate 	return ret;
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate /*
143*0Sstevel@tonic-gate **  SM_STDWRITE -- write to the file
144*0Sstevel@tonic-gate **
145*0Sstevel@tonic-gate **	Parameters:
146*0Sstevel@tonic-gate **		fp -- file pointer ro write to
147*0Sstevel@tonic-gate **		buf -- location of data to be written
148*0Sstevel@tonic-gate **		n - number of bytes to write
149*0Sstevel@tonic-gate **
150*0Sstevel@tonic-gate **	Returns:
151*0Sstevel@tonic-gate **		Failure: -1 and sets errno
152*0Sstevel@tonic-gate **		Success: number of bytes written
153*0Sstevel@tonic-gate */
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate ssize_t
156*0Sstevel@tonic-gate sm_stdwrite(fp, buf, n)
157*0Sstevel@tonic-gate 	SM_FILE_T *fp;
158*0Sstevel@tonic-gate 	char const *buf;
159*0Sstevel@tonic-gate 	size_t n;
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	return write(fp->f_file, buf, n);
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate /*
165*0Sstevel@tonic-gate **  SM_STDSEEK -- set the file offset position
166*0Sstevel@tonic-gate **
167*0Sstevel@tonic-gate **	Parmeters:
168*0Sstevel@tonic-gate **		fp -- file pointer to position
169*0Sstevel@tonic-gate **		offset -- how far to position from "base" (set by 'whence')
170*0Sstevel@tonic-gate **		whence -- indicates where the "base" of the 'offset' to start
171*0Sstevel@tonic-gate **
172*0Sstevel@tonic-gate **	Results:
173*0Sstevel@tonic-gate **		Failure: -1 and sets errno
174*0Sstevel@tonic-gate **		Success: the current offset
175*0Sstevel@tonic-gate **
176*0Sstevel@tonic-gate **	Side Effects:
177*0Sstevel@tonic-gate **		Updates the internal value of the offset.
178*0Sstevel@tonic-gate */
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate off_t
181*0Sstevel@tonic-gate sm_stdseek(fp, offset, whence)
182*0Sstevel@tonic-gate 	SM_FILE_T *fp;
183*0Sstevel@tonic-gate 	off_t offset;
184*0Sstevel@tonic-gate 	int whence;
185*0Sstevel@tonic-gate {
186*0Sstevel@tonic-gate 	register off_t ret;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	ret = lseek(fp->f_file, (off_t) offset, whence);
189*0Sstevel@tonic-gate 	if (ret != (off_t) -1)
190*0Sstevel@tonic-gate 		fp->f_lseekoff = ret;
191*0Sstevel@tonic-gate 	return ret;
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate /*
195*0Sstevel@tonic-gate **  SM_STDCLOSE -- close the file
196*0Sstevel@tonic-gate **
197*0Sstevel@tonic-gate **	Parameters:
198*0Sstevel@tonic-gate **		fp -- the file pointer to close
199*0Sstevel@tonic-gate **
200*0Sstevel@tonic-gate **	Returns:
201*0Sstevel@tonic-gate **		Success: 0 (zero)
202*0Sstevel@tonic-gate **		Failure: -1 and sets errno
203*0Sstevel@tonic-gate */
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate int
206*0Sstevel@tonic-gate sm_stdclose(fp)
207*0Sstevel@tonic-gate 	SM_FILE_T *fp;
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	return close(fp->f_file);
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate **  SM_STDSETMODE -- set the access mode for the file
214*0Sstevel@tonic-gate **
215*0Sstevel@tonic-gate **  Called by sm_stdsetinfo().
216*0Sstevel@tonic-gate **
217*0Sstevel@tonic-gate **	Parameters:
218*0Sstevel@tonic-gate **		fp -- file pointer
219*0Sstevel@tonic-gate **		mode -- new mode to set the file access to
220*0Sstevel@tonic-gate **
221*0Sstevel@tonic-gate **	Results:
222*0Sstevel@tonic-gate **		Success: 0 (zero);
223*0Sstevel@tonic-gate **		Failure: -1 and sets errno
224*0Sstevel@tonic-gate */
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate int
227*0Sstevel@tonic-gate sm_stdsetmode(fp, mode)
228*0Sstevel@tonic-gate 	SM_FILE_T *fp;
229*0Sstevel@tonic-gate 	const int *mode;
230*0Sstevel@tonic-gate {
231*0Sstevel@tonic-gate 	int flags = 0;
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	switch (SM_IO_MODE(*mode))
234*0Sstevel@tonic-gate 	{
235*0Sstevel@tonic-gate 	  case SM_IO_RDWR:
236*0Sstevel@tonic-gate 		flags |= SMRW;
237*0Sstevel@tonic-gate 		break;
238*0Sstevel@tonic-gate 	  case SM_IO_RDONLY:
239*0Sstevel@tonic-gate 		flags |= SMRD;
240*0Sstevel@tonic-gate 		break;
241*0Sstevel@tonic-gate 	  case SM_IO_WRONLY:
242*0Sstevel@tonic-gate 		flags |= SMWR;
243*0Sstevel@tonic-gate 		break;
244*0Sstevel@tonic-gate 	  case SM_IO_APPEND:
245*0Sstevel@tonic-gate 	  default:
246*0Sstevel@tonic-gate 		errno = EINVAL;
247*0Sstevel@tonic-gate 		return -1;
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 	fp->f_flags = fp->f_flags & ~SMMODEMASK;
250*0Sstevel@tonic-gate 	fp->f_flags |= flags;
251*0Sstevel@tonic-gate 	return 0;
252*0Sstevel@tonic-gate }
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate /*
255*0Sstevel@tonic-gate **  SM_STDGETMODE -- for getinfo determine open mode
256*0Sstevel@tonic-gate **
257*0Sstevel@tonic-gate **  Called by sm_stdgetinfo().
258*0Sstevel@tonic-gate **
259*0Sstevel@tonic-gate **	Parameters:
260*0Sstevel@tonic-gate **		fp -- the file mode being determined
261*0Sstevel@tonic-gate **		mode -- internal mode to map to external value
262*0Sstevel@tonic-gate **
263*0Sstevel@tonic-gate **	Results:
264*0Sstevel@tonic-gate **		Failure: -1 and sets errno
265*0Sstevel@tonic-gate **		Success: external mode value
266*0Sstevel@tonic-gate */
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate static int
269*0Sstevel@tonic-gate sm_stdgetmode(fp, mode)
270*0Sstevel@tonic-gate 	SM_FILE_T *fp;
271*0Sstevel@tonic-gate 	int *mode;
272*0Sstevel@tonic-gate {
273*0Sstevel@tonic-gate 	switch (fp->f_flags & SMMODEMASK)
274*0Sstevel@tonic-gate 	{
275*0Sstevel@tonic-gate 	  case SMRW:
276*0Sstevel@tonic-gate 		*mode = SM_IO_RDWR;
277*0Sstevel@tonic-gate 		break;
278*0Sstevel@tonic-gate 	  case SMRD:
279*0Sstevel@tonic-gate 		*mode = SM_IO_RDONLY;
280*0Sstevel@tonic-gate 		break;
281*0Sstevel@tonic-gate 	  case SMWR:
282*0Sstevel@tonic-gate 		*mode = SM_IO_WRONLY;
283*0Sstevel@tonic-gate 		break;
284*0Sstevel@tonic-gate 	  default:
285*0Sstevel@tonic-gate 		errno = EINVAL;
286*0Sstevel@tonic-gate 		return -1;
287*0Sstevel@tonic-gate 	}
288*0Sstevel@tonic-gate 	return 0;
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate /*
292*0Sstevel@tonic-gate **  SM_STDSETINFO -- set/modify information for a file
293*0Sstevel@tonic-gate **
294*0Sstevel@tonic-gate **	Parameters:
295*0Sstevel@tonic-gate **		fp -- file to set info for
296*0Sstevel@tonic-gate **		what -- type of info to set
297*0Sstevel@tonic-gate **		valp -- location of data used for setting
298*0Sstevel@tonic-gate **
299*0Sstevel@tonic-gate **	Returns:
300*0Sstevel@tonic-gate **		Failure: -1 and sets errno
301*0Sstevel@tonic-gate **		Success: >=0
302*0Sstevel@tonic-gate */
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate int
305*0Sstevel@tonic-gate sm_stdsetinfo(fp, what, valp)
306*0Sstevel@tonic-gate 	SM_FILE_T *fp;
307*0Sstevel@tonic-gate 	int what;
308*0Sstevel@tonic-gate 	void *valp;
309*0Sstevel@tonic-gate {
310*0Sstevel@tonic-gate 	switch (what)
311*0Sstevel@tonic-gate 	{
312*0Sstevel@tonic-gate 	  case SM_IO_WHAT_MODE:
313*0Sstevel@tonic-gate 		return sm_stdsetmode(fp, (const int *)valp);
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	  default:
316*0Sstevel@tonic-gate 		errno = EINVAL;
317*0Sstevel@tonic-gate 		return -1;
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate }
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate /*
322*0Sstevel@tonic-gate **  SM_GETINFO -- get information about the open file
323*0Sstevel@tonic-gate **
324*0Sstevel@tonic-gate **	Parameters:
325*0Sstevel@tonic-gate **		fp -- file to get info for
326*0Sstevel@tonic-gate **		what -- type of info to get
327*0Sstevel@tonic-gate **		valp -- location to place found info
328*0Sstevel@tonic-gate **
329*0Sstevel@tonic-gate **	Returns:
330*0Sstevel@tonic-gate **		Success: may or may not place info in 'valp' depending
331*0Sstevel@tonic-gate **			on 'what' value, and returns values >=0. Return
332*0Sstevel@tonic-gate **			value may be the obtained info
333*0Sstevel@tonic-gate **		Failure: -1 and sets errno
334*0Sstevel@tonic-gate */
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate int
337*0Sstevel@tonic-gate sm_stdgetinfo(fp, what, valp)
338*0Sstevel@tonic-gate 	SM_FILE_T *fp;
339*0Sstevel@tonic-gate 	int what;
340*0Sstevel@tonic-gate 	void *valp;
341*0Sstevel@tonic-gate {
342*0Sstevel@tonic-gate 	switch (what)
343*0Sstevel@tonic-gate 	{
344*0Sstevel@tonic-gate 	  case SM_IO_WHAT_MODE:
345*0Sstevel@tonic-gate 		return sm_stdgetmode(fp, (int *)valp);
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	  case SM_IO_WHAT_FD:
348*0Sstevel@tonic-gate 		return fp->f_file;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	  case SM_IO_WHAT_SIZE:
351*0Sstevel@tonic-gate 	  {
352*0Sstevel@tonic-gate 		  struct stat st;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		  if (fstat(fp->f_file, &st) == 0)
355*0Sstevel@tonic-gate 			  return st.st_size;
356*0Sstevel@tonic-gate 		  else
357*0Sstevel@tonic-gate 			  return -1;
358*0Sstevel@tonic-gate 	  }
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	  case SM_IO_IS_READABLE:
361*0Sstevel@tonic-gate 	  {
362*0Sstevel@tonic-gate 		  fd_set readfds;
363*0Sstevel@tonic-gate 		  struct timeval timeout;
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 		  if (SM_FD_SETSIZE > 0 && fp->f_file >= SM_FD_SETSIZE)
366*0Sstevel@tonic-gate 		  {
367*0Sstevel@tonic-gate 			  errno = EINVAL;
368*0Sstevel@tonic-gate 			  return -1;
369*0Sstevel@tonic-gate 		  }
370*0Sstevel@tonic-gate 		  FD_ZERO(&readfds);
371*0Sstevel@tonic-gate 		  SM_FD_SET(fp->f_file, &readfds);
372*0Sstevel@tonic-gate 		  timeout.tv_sec = 0;
373*0Sstevel@tonic-gate 		  timeout.tv_usec = 0;
374*0Sstevel@tonic-gate 		  if (select(fp->f_file + 1, FDSET_CAST &readfds,
375*0Sstevel@tonic-gate 			     NULL, NULL, &timeout) > 0 &&
376*0Sstevel@tonic-gate 		      SM_FD_ISSET(fp->f_file, &readfds))
377*0Sstevel@tonic-gate 			  return 1;
378*0Sstevel@tonic-gate 		  return 0;
379*0Sstevel@tonic-gate 	  }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	  default:
382*0Sstevel@tonic-gate 		errno = EINVAL;
383*0Sstevel@tonic-gate 		return -1;
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate }
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate /*
388*0Sstevel@tonic-gate **  SM_STDFDOPEN -- open file by primitive 'fd' rather than pathname
389*0Sstevel@tonic-gate **
390*0Sstevel@tonic-gate **	I/O function to handle fdopen() stdio equivalence. The rest of
391*0Sstevel@tonic-gate **	the functions are the same as the sm_stdopen() above.
392*0Sstevel@tonic-gate **
393*0Sstevel@tonic-gate **	Parameters:
394*0Sstevel@tonic-gate **		fp -- the file pointer to be associated with the open
395*0Sstevel@tonic-gate **		name -- the primitive file descriptor for association
396*0Sstevel@tonic-gate **		flags -- indicates type of access methods
397*0Sstevel@tonic-gate **		rpool -- ignored
398*0Sstevel@tonic-gate **
399*0Sstevel@tonic-gate **	Results:
400*0Sstevel@tonic-gate **		Success: primitive file descriptor value
401*0Sstevel@tonic-gate **		Failure: -1 and sets errno
402*0Sstevel@tonic-gate */
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate /* ARGSUSED3 */
405*0Sstevel@tonic-gate int
406*0Sstevel@tonic-gate sm_stdfdopen(fp, info, flags, rpool)
407*0Sstevel@tonic-gate 	SM_FILE_T *fp;
408*0Sstevel@tonic-gate 	const void *info;
409*0Sstevel@tonic-gate 	int flags;
410*0Sstevel@tonic-gate 	const void *rpool;
411*0Sstevel@tonic-gate {
412*0Sstevel@tonic-gate 	int oflags, tmp, fdflags, fd = *((int *) info);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	switch (SM_IO_MODE(flags))
415*0Sstevel@tonic-gate 	{
416*0Sstevel@tonic-gate 	  case SM_IO_RDWR:
417*0Sstevel@tonic-gate 		oflags = O_RDWR | O_CREAT;
418*0Sstevel@tonic-gate 		break;
419*0Sstevel@tonic-gate 	  case SM_IO_RDONLY:
420*0Sstevel@tonic-gate 		oflags = O_RDONLY;
421*0Sstevel@tonic-gate 		break;
422*0Sstevel@tonic-gate 	  case SM_IO_WRONLY:
423*0Sstevel@tonic-gate 		oflags = O_WRONLY | O_CREAT | O_TRUNC;
424*0Sstevel@tonic-gate 		break;
425*0Sstevel@tonic-gate 	  case SM_IO_APPEND:
426*0Sstevel@tonic-gate 		oflags = O_APPEND | O_WRONLY | O_CREAT;
427*0Sstevel@tonic-gate 		break;
428*0Sstevel@tonic-gate 	  case SM_IO_APPENDRW:
429*0Sstevel@tonic-gate 		oflags = O_APPEND | O_RDWR | O_CREAT;
430*0Sstevel@tonic-gate 		break;
431*0Sstevel@tonic-gate 	  default:
432*0Sstevel@tonic-gate 		errno = EINVAL;
433*0Sstevel@tonic-gate 		return -1;
434*0Sstevel@tonic-gate 	}
435*0Sstevel@tonic-gate #ifdef O_BINARY
436*0Sstevel@tonic-gate 	if (SM_IS_BINARY(flags))
437*0Sstevel@tonic-gate 		oflags |= O_BINARY;
438*0Sstevel@tonic-gate #endif /* O_BINARY */
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	/* Make sure the mode the user wants is a subset of the actual mode. */
441*0Sstevel@tonic-gate 	if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0)
442*0Sstevel@tonic-gate 		return -1;
443*0Sstevel@tonic-gate 	tmp = fdflags & O_ACCMODE;
444*0Sstevel@tonic-gate 	if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE)))
445*0Sstevel@tonic-gate 	{
446*0Sstevel@tonic-gate 		errno = EINVAL;
447*0Sstevel@tonic-gate 		return -1;
448*0Sstevel@tonic-gate 	}
449*0Sstevel@tonic-gate 	fp->f_file = fd;
450*0Sstevel@tonic-gate 	if (oflags & O_APPEND)
451*0Sstevel@tonic-gate 		(void) (*fp->f_seek)(fp, (off_t)0, SEEK_END);
452*0Sstevel@tonic-gate 	return fp->f_file;
453*0Sstevel@tonic-gate }
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate /*
456*0Sstevel@tonic-gate **  SM_IO_FOPEN -- open a file
457*0Sstevel@tonic-gate **
458*0Sstevel@tonic-gate **	Same interface and semantics as the open() system call,
459*0Sstevel@tonic-gate **	except that it returns SM_FILE_T* instead of a file descriptor.
460*0Sstevel@tonic-gate **
461*0Sstevel@tonic-gate **	Parameters:
462*0Sstevel@tonic-gate **		pathname -- path of file to open
463*0Sstevel@tonic-gate **		flags -- flags controlling the open
464*0Sstevel@tonic-gate **		...  -- option "mode" for opening the file
465*0Sstevel@tonic-gate **
466*0Sstevel@tonic-gate **	Returns:
467*0Sstevel@tonic-gate **		Raises an exception on heap exhaustion.
468*0Sstevel@tonic-gate **		Returns NULL and sets errno if open() fails.
469*0Sstevel@tonic-gate **		Returns an SM_FILE_T pointer on success.
470*0Sstevel@tonic-gate */
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate SM_FILE_T *
473*0Sstevel@tonic-gate #if SM_VA_STD
474*0Sstevel@tonic-gate sm_io_fopen(char *pathname, int flags, ...)
475*0Sstevel@tonic-gate #else /* SM_VA_STD */
476*0Sstevel@tonic-gate sm_io_fopen(pathname, flags, va_alist)
477*0Sstevel@tonic-gate 	char *pathname;
478*0Sstevel@tonic-gate 	int flags;
479*0Sstevel@tonic-gate 	va_dcl
480*0Sstevel@tonic-gate #endif /* SM_VA_STD */
481*0Sstevel@tonic-gate {
482*0Sstevel@tonic-gate 	MODE_T mode;
483*0Sstevel@tonic-gate 	SM_FILE_T *fp;
484*0Sstevel@tonic-gate 	int ioflags;
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	if (flags & O_CREAT)
487*0Sstevel@tonic-gate 	{
488*0Sstevel@tonic-gate 		SM_VA_LOCAL_DECL
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		SM_VA_START(ap, flags);
491*0Sstevel@tonic-gate 		mode = (MODE_T) SM_VA_ARG(ap, int);
492*0Sstevel@tonic-gate 		SM_VA_END(ap);
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 	else
495*0Sstevel@tonic-gate 		mode = 0;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	switch (flags & O_ACCMODE)
498*0Sstevel@tonic-gate 	{
499*0Sstevel@tonic-gate 	  case O_RDONLY:
500*0Sstevel@tonic-gate 		ioflags = SMRD;
501*0Sstevel@tonic-gate 		break;
502*0Sstevel@tonic-gate 	  case O_WRONLY:
503*0Sstevel@tonic-gate 		ioflags = SMWR;
504*0Sstevel@tonic-gate 		break;
505*0Sstevel@tonic-gate 	  case O_RDWR:
506*0Sstevel@tonic-gate 		ioflags = SMRW;
507*0Sstevel@tonic-gate 		break;
508*0Sstevel@tonic-gate 	  default:
509*0Sstevel@tonic-gate 		sm_abort("sm_io_fopen: bad flags 0%o", flags);
510*0Sstevel@tonic-gate 	}
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 	fp = sm_fp(SmFtStdio, ioflags, NULL);
513*0Sstevel@tonic-gate 	fp->f_file = open(pathname, flags, mode);
514*0Sstevel@tonic-gate 	if (fp->f_file == -1)
515*0Sstevel@tonic-gate 	{
516*0Sstevel@tonic-gate 		fp->f_flags = 0;
517*0Sstevel@tonic-gate 		fp->sm_magic = NULL;
518*0Sstevel@tonic-gate 		return NULL;
519*0Sstevel@tonic-gate 	}
520*0Sstevel@tonic-gate 	return fp;
521*0Sstevel@tonic-gate }
522