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