1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31 /* All Rights Reserved */ 32 33 #include "lint.h" 34 #include "libc.h" 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <deflt.h> 38 #include <sys/types.h> 39 #include <string.h> 40 #include <ctype.h> 41 #include <unistd.h> 42 #include "tsd.h" 43 44 #define TSTBITS(flags, mask) (((flags) & (mask)) == (mask)) 45 46 struct thr_data { 47 int Dcflags; /* [re-]initialized on each call to defopen() */ 48 FILE *fp; 49 char *buf; 50 }; 51 52 static int defopen_common(const char *, struct thr_data *); 53 static void strip_quotes(char *); 54 55 #define BUFFERSIZE 1024 56 57 /* 58 * destructor for per-thread data, registered with tsdalloc() 59 */ 60 static void 61 free_thr_data(void *arg) 62 { 63 struct thr_data *thr_data = (struct thr_data *)arg; 64 65 if (thr_data->fp) { 66 (void) fclose(thr_data->fp); 67 thr_data->fp = NULL; 68 } 69 if (thr_data->buf) { 70 lfree(thr_data->buf, BUFFERSIZE); 71 thr_data->buf = NULL; 72 } 73 } 74 75 /* 76 * get the per-thread-data-item for the calling thread 77 */ 78 static struct thr_data * 79 get_thr_data(void) 80 { 81 struct thr_data *thr_data = 82 tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data); 83 84 return (thr_data); 85 } 86 87 /* 88 * defopen() - declare defopen filename 89 * 90 * defopen(fn) 91 * char *fn 92 * 93 * If 'fn' is non-null; it is a full pathname of a file 94 * which becomes the one read by subsequent defread() calls. 95 * If 'fn' is null the defopen file is closed. 96 * 97 * see defread() for more details. 98 * 99 * EXIT returns 0 if ok 100 * returns -1 if error 101 */ 102 int 103 defopen(char *fn) 104 { 105 struct thr_data *thr_data = get_thr_data(); 106 107 return (defopen_common(fn, thr_data)); 108 } 109 110 /* 111 * defopen_r() - declare defopen filename (reentrant) 112 * 113 * defopen_r(const char *fn) 114 * 115 * 'fn' is a full pathname of a file which becomes the one read 116 * by subsequent defread_r() calls. defopen_r returns a pointer 117 * to the internally allocated buffer containing the file descriptor. 118 * The pointer should be specified to the following defread_r and 119 * defcntl_r functions. As the pointer to be returned points to 120 * the libc lmalloc'd memory, defclose_r must be used to close 121 * the defopen file and to release the allocated memory. Caller 122 * must not try to release the memory by free(). 123 * 124 * see defread_r() for more details. 125 * 126 * EXIT returns non-NULL pointer if success 127 * returns NULL if error 128 */ 129 void * 130 defopen_r(const char *fn) 131 { 132 /* memory allocated by lmalloc gets initialized to zeros */ 133 struct thr_data *thr_data = lmalloc(sizeof (struct thr_data)); 134 135 if (defopen_common(fn, thr_data) < 0) { 136 if (thr_data != NULL) 137 lfree(thr_data, sizeof (struct thr_data)); 138 return (NULL); 139 } 140 141 return ((void *)thr_data); 142 } 143 144 static int 145 defopen_common(const char *fn, struct thr_data *thr_data) 146 { 147 if (thr_data == NULL) 148 return (-1); 149 150 if (thr_data->fp != NULL) { 151 (void) fclose(thr_data->fp); 152 thr_data->fp = NULL; 153 } 154 155 if (fn == NULL) 156 return (0); 157 158 if ((thr_data->fp = fopen(fn, "rF")) == NULL) 159 return (-1); 160 161 /* 162 * We allocate the big buffer only if the fopen() succeeds. 163 * Notice that we deallocate the buffer only when the thread exits 164 * for defopen(). 165 * There are misguided applications that assume that data returned 166 * by defread() continues to exist after defopen(NULL) is called. 167 */ 168 if (thr_data->buf == NULL && 169 (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) { 170 (void) fclose(thr_data->fp); 171 thr_data->fp = NULL; 172 return (-1); 173 } 174 175 thr_data->Dcflags = DC_STD; 176 177 return (0); 178 } 179 180 /* 181 * defread() - read an entry from the defopen file 182 * 183 * defread(cp) 184 * char *cp 185 * 186 * The defopen data file must have been previously opened by 187 * defopen(). defread scans the data file looking for a line 188 * which begins with the string '*cp'. If such a line is found, 189 * defread returns a pointer to the first character following 190 * the matched string (*cp). If no line is found or no file 191 * is open, defread() returns NULL. 192 * 193 * Note that there is no way to simultaneously peruse multiple 194 * defopen files; since there is no way of indicating 'which one' 195 * to defread(). If you want to peruse a secondary file you must 196 * recall defopen(). If you need to go back to the first file, 197 * you must call defopen() again. 198 */ 199 char * 200 defread(char *cp) 201 { 202 struct thr_data *thr_data = get_thr_data(); 203 204 return (defread_r(cp, thr_data)); 205 } 206 207 /* 208 * defread_r() - read an entry from the defopen file 209 * 210 * defread_r(const char *cp, void *defp) 211 * 212 * defread_r scans the data file associated with the pointer 213 * specified by 'defp' that was returned by defopen_r(), and 214 * looks for a line which begins with the string '*cp'. 215 * If such a line is found, defread_r returns a pointer to 216 * the first character following the matched string (*cp). 217 * If no line is found or no file is open, defread_r() returns NULL. 218 */ 219 char * 220 defread_r(const char *cp, void *ptr) 221 { 222 struct thr_data *thr_data = (struct thr_data *)ptr; 223 int (*compare)(const char *, const char *, size_t); 224 char *buf_tmp; 225 char *ret_ptr = NULL; 226 size_t off, patlen; 227 228 if (thr_data == NULL || thr_data->fp == NULL) 229 return (NULL); 230 231 compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp; 232 patlen = strlen(cp); 233 234 if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND)) 235 rewind(thr_data->fp); 236 237 while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) { 238 for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++) 239 ; 240 off = strlen(buf_tmp) - 1; 241 if (buf_tmp[off] == '\n') 242 buf_tmp[off] = 0; 243 else 244 break; /* line too long */ 245 if ((*compare)(cp, buf_tmp, patlen) == 0) { 246 /* found it */ 247 /* strip quotes if requested */ 248 if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) { 249 strip_quotes(buf_tmp); 250 } 251 ret_ptr = &buf_tmp[patlen]; 252 break; 253 } 254 } 255 256 return (ret_ptr); 257 } 258 259 /* 260 * defcntl -- default control 261 * 262 * SYNOPSIS 263 * oldflags = defcntl(cmd, arg); 264 * 265 * ENTRY 266 * cmd Command. One of DC_GET, DC_SET. 267 * arg Depends on command. If DC_GET, ignored. 268 * If DC_SET, new flags value, created by ORing 269 * the DC_* bits. 270 * RETURN 271 * oldflags Old value of flags. -1 on error. 272 * NOTES 273 * The following commands are implemented: 274 * 275 * DC_CASE: respect(on)/ignore(off) case 276 * DC_NOREWIND: don't(on)/do(off) reqind in defread 277 * DC_STRIP_QUOTES: strip(on)/leave(off) qoates 278 */ 279 int 280 defcntl(int cmd, int newflags) 281 { 282 struct thr_data *thr_data = get_thr_data(); 283 284 return (defcntl_r(cmd, newflags, thr_data)); 285 } 286 287 /* 288 * defcntl_r -- default control 289 * 290 * SYNOPSIS 291 * oldflags = defcntl_r(int cmd, int arg, void *defp); 292 * 293 * ENTRY 294 * cmd Command. One of DC_GET, DC_SET. 295 * arg Depends on command. If DC_GET, ignored. 296 * If DC_SET, new flags value, created by ORing 297 * the DC_* bits. 298 * defp pointer to the defopen'd descriptor 299 * 300 * RETURN 301 * oldflags Old value of flags. -1 on error. 302 * NOTES 303 * The following commands are implemented: 304 * 305 * DC_CASE: respect(on)/ignore(off) case 306 * DC_NOREWIND: don't(on)/do(off) reqind in defread 307 * DC_STRIP_QUOTES: strip(on)/leave(off) qoates 308 */ 309 int 310 defcntl_r(int cmd, int newflags, void *ptr) 311 { 312 struct thr_data *thr_data = (struct thr_data *)ptr; 313 int oldflags; 314 315 if (thr_data == NULL) 316 return (-1); 317 318 switch (cmd) { 319 case DC_GETFLAGS: /* query */ 320 oldflags = thr_data->Dcflags; 321 break; 322 case DC_SETFLAGS: /* set */ 323 oldflags = thr_data->Dcflags; 324 thr_data->Dcflags = newflags; 325 break; 326 default: /* error */ 327 oldflags = -1; 328 break; 329 } 330 331 return (oldflags); 332 } 333 334 /* 335 * defclose_r() - close defopen file 336 * 337 * defclose_r(void *defp) 338 * 339 * defclose_r closes the defopen file associated with the specified 340 * pointer and releases the allocated resources. 341 */ 342 void 343 defclose_r(void *ptr) 344 { 345 struct thr_data *thr_data = (struct thr_data *)ptr; 346 347 (void) fclose(thr_data->fp); 348 lfree(thr_data->buf, BUFFERSIZE); 349 lfree(thr_data, sizeof (struct thr_data)); 350 } 351 352 /* 353 * strip_quotes -- strip double (") or single (') quotes from a buffer 354 * 355 * ENTRY 356 * ptr initial string 357 * 358 * EXIT 359 * ptr string with quotes (if any) removed 360 */ 361 static void 362 strip_quotes(char *ptr) 363 { 364 char *strip_ptr = NULL; 365 366 while (*ptr != '\0') { 367 if ((*ptr == '"') || (*ptr == '\'')) { 368 if (strip_ptr == NULL) 369 strip_ptr = ptr; /* skip over quote */ 370 } else { 371 if (strip_ptr != NULL) { 372 *strip_ptr = *ptr; 373 strip_ptr++; 374 } 375 } 376 ptr++; 377 } 378 if (strip_ptr != NULL) { 379 *strip_ptr = '\0'; 380 } 381 } 382