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