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