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