1 /* 2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10 #include <sm/gen.h> 11 SM_IDSTR(id, "@(#)$Id: smstdio.c,v 1.29 2001/09/11 04:04:49 gshapiro Exp $") 12 #include <unistd.h> 13 #include <stdio.h> 14 #include <fcntl.h> 15 #include <errno.h> 16 #include <sm/assert.h> 17 #include <sm/io.h> 18 #include <sm/string.h> 19 #include "local.h" 20 21 /* 22 ** Overall: 23 ** This is a file type which implements a layer on top of the system 24 ** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be 25 ** "bound late" because of the manner which Linux implements stdio. 26 ** When binding late (when fp->f_cookie==NULL) then the value of 27 ** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or 28 ** stderr. 29 */ 30 31 /* 32 ** SM_STDIOOPEN -- open a file to system stdio implementation 33 ** 34 ** Parameters: 35 ** fp -- file pointer assign for this open 36 ** info -- info about file to open 37 ** flags -- indicating method of opening 38 ** rpool -- ignored 39 ** 40 ** Returns: 41 ** Failure: -1 42 ** Success: 0 (zero) 43 */ 44 45 /* ARGSUSED3 */ 46 int 47 sm_stdioopen(fp, info, flags, rpool) 48 SM_FILE_T *fp; 49 const void *info; 50 int flags; 51 const void *rpool; 52 { 53 register FILE *s; 54 char *stdiomode; 55 56 switch (flags) 57 { 58 case SM_IO_RDONLY: 59 stdiomode = "r"; 60 break; 61 case SM_IO_WRONLY: 62 stdiomode = "w"; 63 break; 64 case SM_IO_APPEND: 65 stdiomode = "a"; 66 break; 67 case SM_IO_APPENDRW: 68 stdiomode = "a+"; 69 break; 70 case SM_IO_RDWR: 71 default: 72 stdiomode = "r+"; 73 break; 74 } 75 76 if ((s = fopen((char *)info, stdiomode)) == NULL) 77 return -1; 78 fp->f_cookie = s; 79 return 0; 80 } 81 82 /* 83 ** SETUP -- assign file type cookie when not already assigned 84 ** 85 ** Parameters: 86 ** fp - the file pointer to get the cookie assigned 87 ** 88 ** Return: 89 ** none. 90 */ 91 92 static void 93 setup(fp) 94 SM_FILE_T *fp; 95 { 96 if (fp->f_cookie == NULL) 97 { 98 switch (fp->f_ival) 99 { 100 case 0: 101 fp->f_cookie = stdin; 102 break; 103 case 1: 104 fp->f_cookie = stdout; 105 break; 106 case 2: 107 fp->f_cookie = stderr; 108 break; 109 default: 110 sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival); 111 break; 112 } 113 } 114 } 115 116 /* 117 ** SM_STDIOREAD -- read from the file 118 ** 119 ** Parameters: 120 ** fp -- the file pointer 121 ** buf -- location to place the read data 122 ** n - number of bytes to read 123 ** 124 ** Returns: 125 ** result from fread(). 126 */ 127 128 ssize_t 129 sm_stdioread(fp, buf, n) 130 SM_FILE_T *fp; 131 char *buf; 132 size_t n; 133 { 134 register FILE *s; 135 136 if (fp->f_cookie == NULL) 137 setup(fp); 138 s = fp->f_cookie; 139 return fread(buf, 1, n, s); 140 } 141 142 /* 143 ** SM_STDIOWRITE -- write to the file 144 ** 145 ** Parameters: 146 ** fp -- the file pointer 147 ** buf -- location of data to write 148 ** n - number of bytes to write 149 ** 150 ** Returns: 151 ** result from fwrite(). 152 */ 153 154 ssize_t 155 sm_stdiowrite(fp, buf, n) 156 SM_FILE_T *fp; 157 char const *buf; 158 size_t n; 159 { 160 register FILE *s; 161 162 if (fp->f_cookie == NULL) 163 setup(fp); 164 s = fp->f_cookie; 165 return fwrite(buf, 1, n, s); 166 } 167 168 /* 169 ** SM_STDIOSEEK -- set position within file 170 ** 171 ** Parameters: 172 ** fp -- the file pointer 173 ** offset -- new location based on 'whence' 174 ** whence -- indicates "base" for 'offset' 175 ** 176 ** Returns: 177 ** result from fseek(). 178 */ 179 180 off_t 181 sm_stdioseek(fp, offset, whence) 182 SM_FILE_T *fp; 183 off_t offset; 184 int whence; 185 { 186 register FILE *s; 187 188 if (fp->f_cookie == NULL) 189 setup(fp); 190 s = fp->f_cookie; 191 return fseek(s, offset, whence); 192 } 193 194 /* 195 ** SM_STDIOCLOSE -- close the file 196 ** 197 ** Parameters: 198 ** fp -- close file pointer 199 ** 200 ** Return: 201 ** status from fclose() 202 */ 203 204 int 205 sm_stdioclose(fp) 206 SM_FILE_T *fp; 207 { 208 register FILE *s; 209 210 if (fp->f_cookie == NULL) 211 setup(fp); 212 s = fp->f_cookie; 213 return fclose(s); 214 } 215 216 /* 217 ** SM_STDIOSETINFO -- set info for this open file 218 ** 219 ** Parameters: 220 ** fp -- the file pointer 221 ** what -- type of information setting 222 ** valp -- memory location of info to set 223 ** 224 ** Return: 225 ** Failure: -1 and sets errno 226 ** Success: none (currently). 227 */ 228 229 /* ARGSUSED2 */ 230 int 231 sm_stdiosetinfo(fp, what, valp) 232 SM_FILE_T *fp; 233 int what; 234 void *valp; 235 { 236 switch (what) 237 { 238 case SM_IO_WHAT_MODE: 239 default: 240 errno = EINVAL; 241 return -1; 242 } 243 } 244 245 /* 246 ** SM_STDIOGETINFO -- get info for this open file 247 ** 248 ** Parameters: 249 ** fp -- the file pointer 250 ** what -- type of information request 251 ** valp -- memory location to place info 252 ** 253 ** Return: 254 ** Failure: -1 and sets errno 255 ** Success: none (currently). 256 */ 257 258 /* ARGSUSED2 */ 259 int 260 sm_stdiogetinfo(fp, what, valp) 261 SM_FILE_T *fp; 262 int what; 263 void *valp; 264 { 265 switch (what) 266 { 267 case SM_IO_WHAT_MODE: 268 default: 269 errno = EINVAL; 270 return -1; 271 } 272 } 273 274 /* 275 ** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE 276 ** 277 ** Parameters: 278 ** stream -- an open stdio stream, as returned by fopen() 279 ** mode -- the mode argument to fopen() which describes stream 280 ** 281 ** Return: 282 ** On success, return a pointer to an SM_FILE object which 283 ** can be used for reading and writing 'stream'. 284 ** Abort if mode is gibberish or stream is bad. 285 ** Raise an exception if we can't allocate memory. 286 */ 287 288 SM_FILE_T * 289 sm_io_stdioopen(stream, mode) 290 FILE *stream; 291 char *mode; 292 { 293 int fd; 294 bool r, w; 295 int ioflags; 296 SM_FILE_T *fp; 297 298 fd = fileno(stream); 299 SM_REQUIRE(fd >= 0); 300 301 r = w = false; 302 switch (mode[0]) 303 { 304 case 'r': 305 r = true; 306 break; 307 case 'w': 308 case 'a': 309 w = true; 310 break; 311 default: 312 sm_abort("sm_io_stdioopen: mode '%s' is bad", mode); 313 } 314 if (strchr(&mode[1], '+') != NULL) 315 r = w = true; 316 if (r && w) 317 ioflags = SMRW; 318 else if (r) 319 ioflags = SMRD; 320 else 321 ioflags = SMWR; 322 323 fp = sm_fp(SmFtRealStdio, ioflags, NULL); 324 fp->f_file = fd; 325 fp->f_cookie = stream; 326 return fp; 327 } 328