106e1a714Sraf /* 206e1a714Sraf * CDDL HEADER START 306e1a714Sraf * 406e1a714Sraf * The contents of this file are subject to the terms of the 506e1a714Sraf * Common Development and Distribution License (the "License"). 606e1a714Sraf * You may not use this file except in compliance with the License. 706e1a714Sraf * 806e1a714Sraf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 906e1a714Sraf * or http://www.opensolaris.org/os/licensing. 1006e1a714Sraf * See the License for the specific language governing permissions 1106e1a714Sraf * and limitations under the License. 1206e1a714Sraf * 1306e1a714Sraf * When distributing Covered Code, include this CDDL HEADER in each 1406e1a714Sraf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1506e1a714Sraf * If applicable, add the following below this CDDL HEADER, with the 1606e1a714Sraf * fields enclosed by brackets "[]" replaced with your own identifying 1706e1a714Sraf * information: Portions Copyright [yyyy] [name of copyright owner] 1806e1a714Sraf * 1906e1a714Sraf * CDDL HEADER END 2006e1a714Sraf */ 2106e1a714Sraf 2206e1a714Sraf /* 23*b9175c69SKenjiro Tsuji * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2406e1a714Sraf * Use is subject to license terms. 2506e1a714Sraf */ 2606e1a714Sraf 2706e1a714Sraf /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 2806e1a714Sraf /* All Rights Reserved */ 2906e1a714Sraf 3006e1a714Sraf /* Copyright (c) 1987, 1988 Microsoft Corporation */ 3106e1a714Sraf /* All Rights Reserved */ 3206e1a714Sraf 337257d1b4Sraf #include "lint.h" 3406e1a714Sraf #include "libc.h" 3506e1a714Sraf #include <stdio.h> 3606e1a714Sraf #include <stdlib.h> 3706e1a714Sraf #include <deflt.h> 3806e1a714Sraf #include <sys/types.h> 3906e1a714Sraf #include <string.h> 4006e1a714Sraf #include <ctype.h> 4106e1a714Sraf #include <unistd.h> 4206e1a714Sraf #include "tsd.h" 4306e1a714Sraf 4406e1a714Sraf #define TSTBITS(flags, mask) (((flags) & (mask)) == (mask)) 4506e1a714Sraf 4606e1a714Sraf struct thr_data { 4706e1a714Sraf int Dcflags; /* [re-]initialized on each call to defopen() */ 4806e1a714Sraf FILE *fp; 4906e1a714Sraf char *buf; 5006e1a714Sraf }; 5106e1a714Sraf 52*b9175c69SKenjiro Tsuji static int defopen_common(const char *, struct thr_data *); 53*b9175c69SKenjiro Tsuji static void strip_quotes(char *); 54*b9175c69SKenjiro Tsuji 5506e1a714Sraf #define BUFFERSIZE 1024 5606e1a714Sraf 5706e1a714Sraf /* 5806e1a714Sraf * destructor for per-thread data, registered with tsdalloc() 5906e1a714Sraf */ 6006e1a714Sraf static void 6106e1a714Sraf free_thr_data(void *arg) 6206e1a714Sraf { 6306e1a714Sraf struct thr_data *thr_data = (struct thr_data *)arg; 6406e1a714Sraf 6506e1a714Sraf if (thr_data->fp) { 6606e1a714Sraf (void) fclose(thr_data->fp); 6706e1a714Sraf thr_data->fp = NULL; 6806e1a714Sraf } 6906e1a714Sraf if (thr_data->buf) { 7006e1a714Sraf lfree(thr_data->buf, BUFFERSIZE); 7106e1a714Sraf thr_data->buf = NULL; 7206e1a714Sraf } 7306e1a714Sraf } 7406e1a714Sraf 7506e1a714Sraf /* 7606e1a714Sraf * get the per-thread-data-item for the calling thread 7706e1a714Sraf */ 7806e1a714Sraf static struct thr_data * 7906e1a714Sraf get_thr_data(void) 8006e1a714Sraf { 8106e1a714Sraf struct thr_data *thr_data = 8206e1a714Sraf tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data); 8306e1a714Sraf 8406e1a714Sraf return (thr_data); 8506e1a714Sraf } 8606e1a714Sraf 8706e1a714Sraf /* 8806e1a714Sraf * defopen() - declare defopen filename 8906e1a714Sraf * 9006e1a714Sraf * defopen(fn) 9106e1a714Sraf * char *fn 9206e1a714Sraf * 9306e1a714Sraf * If 'fn' is non-null; it is a full pathname of a file 9406e1a714Sraf * which becomes the one read by subsequent defread() calls. 9506e1a714Sraf * If 'fn' is null the defopen file is closed. 9606e1a714Sraf * 9706e1a714Sraf * see defread() for more details. 9806e1a714Sraf * 9906e1a714Sraf * EXIT returns 0 if ok 10006e1a714Sraf * returns -1 if error 10106e1a714Sraf */ 10206e1a714Sraf int 10306e1a714Sraf defopen(char *fn) 10406e1a714Sraf { 10506e1a714Sraf struct thr_data *thr_data = get_thr_data(); 10606e1a714Sraf 107*b9175c69SKenjiro Tsuji return (defopen_common(fn, thr_data)); 108*b9175c69SKenjiro Tsuji } 109*b9175c69SKenjiro Tsuji 110*b9175c69SKenjiro Tsuji /* 111*b9175c69SKenjiro Tsuji * defopen_r() - declare defopen filename (reentrant) 112*b9175c69SKenjiro Tsuji * 113*b9175c69SKenjiro Tsuji * defopen_r(const char *fn) 114*b9175c69SKenjiro Tsuji * 115*b9175c69SKenjiro Tsuji * 'fn' is a full pathname of a file which becomes the one read 116*b9175c69SKenjiro Tsuji * by subsequent defread_r() calls. defopen_r returns a pointer 117*b9175c69SKenjiro Tsuji * to the internally allocated buffer containing the file descriptor. 118*b9175c69SKenjiro Tsuji * The pointer should be specified to the following defread_r and 119*b9175c69SKenjiro Tsuji * defcntl_r functions. As the pointer to be returned points to 120*b9175c69SKenjiro Tsuji * the libc lmalloc'd memory, defclose_r must be used to close 121*b9175c69SKenjiro Tsuji * the defopen file and to release the allocated memory. Caller 122*b9175c69SKenjiro Tsuji * must not try to release the memory by free(). 123*b9175c69SKenjiro Tsuji * 124*b9175c69SKenjiro Tsuji * see defread_r() for more details. 125*b9175c69SKenjiro Tsuji * 126*b9175c69SKenjiro Tsuji * EXIT returns non-NULL pointer if success 127*b9175c69SKenjiro Tsuji * returns NULL if error 128*b9175c69SKenjiro Tsuji */ 129*b9175c69SKenjiro Tsuji void * 130*b9175c69SKenjiro Tsuji defopen_r(const char *fn) 131*b9175c69SKenjiro Tsuji { 132*b9175c69SKenjiro Tsuji /* memory allocated by lmalloc gets initialized to zeros */ 133*b9175c69SKenjiro Tsuji struct thr_data *thr_data = lmalloc(sizeof (struct thr_data)); 134*b9175c69SKenjiro Tsuji 135*b9175c69SKenjiro Tsuji if (defopen_common(fn, thr_data) < 0) { 136*b9175c69SKenjiro Tsuji if (thr_data != NULL) 137*b9175c69SKenjiro Tsuji lfree(thr_data, sizeof (struct thr_data)); 138*b9175c69SKenjiro Tsuji return (NULL); 139*b9175c69SKenjiro Tsuji } 140*b9175c69SKenjiro Tsuji 141*b9175c69SKenjiro Tsuji return ((void *)thr_data); 142*b9175c69SKenjiro Tsuji } 143*b9175c69SKenjiro Tsuji 144*b9175c69SKenjiro Tsuji static int 145*b9175c69SKenjiro Tsuji defopen_common(const char *fn, struct thr_data *thr_data) 146*b9175c69SKenjiro Tsuji { 14706e1a714Sraf if (thr_data == NULL) 14806e1a714Sraf return (-1); 14906e1a714Sraf 15006e1a714Sraf if (thr_data->fp != NULL) { 15106e1a714Sraf (void) fclose(thr_data->fp); 15206e1a714Sraf thr_data->fp = NULL; 15306e1a714Sraf } 15406e1a714Sraf 15506e1a714Sraf if (fn == NULL) 15606e1a714Sraf return (0); 15706e1a714Sraf 15806e1a714Sraf if ((thr_data->fp = fopen(fn, "rF")) == NULL) 15906e1a714Sraf return (-1); 16006e1a714Sraf 16106e1a714Sraf /* 16206e1a714Sraf * We allocate the big buffer only if the fopen() succeeds. 163*b9175c69SKenjiro Tsuji * Notice that we deallocate the buffer only when the thread exits 164*b9175c69SKenjiro Tsuji * for defopen(). 16506e1a714Sraf * There are misguided applications that assume that data returned 16606e1a714Sraf * by defread() continues to exist after defopen(NULL) is called. 16706e1a714Sraf */ 16806e1a714Sraf if (thr_data->buf == NULL && 16906e1a714Sraf (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) { 17006e1a714Sraf (void) fclose(thr_data->fp); 17106e1a714Sraf thr_data->fp = NULL; 17206e1a714Sraf return (-1); 17306e1a714Sraf } 17406e1a714Sraf 17506e1a714Sraf thr_data->Dcflags = DC_STD; 17606e1a714Sraf 17706e1a714Sraf return (0); 17806e1a714Sraf } 17906e1a714Sraf 18006e1a714Sraf /* 18106e1a714Sraf * defread() - read an entry from the defopen file 18206e1a714Sraf * 18306e1a714Sraf * defread(cp) 18406e1a714Sraf * char *cp 18506e1a714Sraf * 18606e1a714Sraf * The defopen data file must have been previously opened by 18706e1a714Sraf * defopen(). defread scans the data file looking for a line 18806e1a714Sraf * which begins with the string '*cp'. If such a line is found, 18906e1a714Sraf * defread returns a pointer to the first character following 19006e1a714Sraf * the matched string (*cp). If no line is found or no file 19106e1a714Sraf * is open, defread() returns NULL. 19206e1a714Sraf * 193*b9175c69SKenjiro Tsuji * Note that there is no way to simultaneously peruse multiple 19406e1a714Sraf * defopen files; since there is no way of indicating 'which one' 19506e1a714Sraf * to defread(). If you want to peruse a secondary file you must 19606e1a714Sraf * recall defopen(). If you need to go back to the first file, 19706e1a714Sraf * you must call defopen() again. 19806e1a714Sraf */ 19906e1a714Sraf char * 20006e1a714Sraf defread(char *cp) 20106e1a714Sraf { 20206e1a714Sraf struct thr_data *thr_data = get_thr_data(); 203*b9175c69SKenjiro Tsuji 204*b9175c69SKenjiro Tsuji return (defread_r(cp, thr_data)); 205*b9175c69SKenjiro Tsuji } 206*b9175c69SKenjiro Tsuji 207*b9175c69SKenjiro Tsuji /* 208*b9175c69SKenjiro Tsuji * defread_r() - read an entry from the defopen file 209*b9175c69SKenjiro Tsuji * 210*b9175c69SKenjiro Tsuji * defread_r(const char *cp, void *defp) 211*b9175c69SKenjiro Tsuji * 212*b9175c69SKenjiro Tsuji * defread_r scans the data file associated with the pointer 213*b9175c69SKenjiro Tsuji * specified by 'defp' that was returned by defopen_r(), and 214*b9175c69SKenjiro Tsuji * looks for a line which begins with the string '*cp'. 215*b9175c69SKenjiro Tsuji * If such a line is found, defread_r returns a pointer to 216*b9175c69SKenjiro Tsuji * the first character following the matched string (*cp). 217*b9175c69SKenjiro Tsuji * If no line is found or no file is open, defread_r() returns NULL. 218*b9175c69SKenjiro Tsuji */ 219*b9175c69SKenjiro Tsuji char * 220*b9175c69SKenjiro Tsuji defread_r(const char *cp, void *ptr) 221*b9175c69SKenjiro Tsuji { 222*b9175c69SKenjiro Tsuji struct thr_data *thr_data = (struct thr_data *)ptr; 22306e1a714Sraf int (*compare)(const char *, const char *, size_t); 224*b9175c69SKenjiro Tsuji char *buf_tmp; 225*b9175c69SKenjiro Tsuji char *ret_ptr = NULL; 22606e1a714Sraf size_t off, patlen; 22706e1a714Sraf 22806e1a714Sraf if (thr_data == NULL || thr_data->fp == NULL) 22906e1a714Sraf return (NULL); 23006e1a714Sraf 23106e1a714Sraf compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp; 23206e1a714Sraf patlen = strlen(cp); 23306e1a714Sraf 23406e1a714Sraf if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND)) 23506e1a714Sraf rewind(thr_data->fp); 23606e1a714Sraf 23706e1a714Sraf while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) { 23806e1a714Sraf for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++) 23906e1a714Sraf ; 24006e1a714Sraf off = strlen(buf_tmp) - 1; 24106e1a714Sraf if (buf_tmp[off] == '\n') 24206e1a714Sraf buf_tmp[off] = 0; 24306e1a714Sraf else 24406e1a714Sraf break; /* line too long */ 24506e1a714Sraf if ((*compare)(cp, buf_tmp, patlen) == 0) { 24606e1a714Sraf /* found it */ 24706e1a714Sraf /* strip quotes if requested */ 24806e1a714Sraf if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) { 24906e1a714Sraf strip_quotes(buf_tmp); 25006e1a714Sraf } 25106e1a714Sraf ret_ptr = &buf_tmp[patlen]; 25206e1a714Sraf break; 25306e1a714Sraf } 25406e1a714Sraf } 25506e1a714Sraf 25606e1a714Sraf return (ret_ptr); 25706e1a714Sraf } 25806e1a714Sraf 25906e1a714Sraf /* 26006e1a714Sraf * defcntl -- default control 26106e1a714Sraf * 26206e1a714Sraf * SYNOPSIS 26306e1a714Sraf * oldflags = defcntl(cmd, arg); 26406e1a714Sraf * 26506e1a714Sraf * ENTRY 26606e1a714Sraf * cmd Command. One of DC_GET, DC_SET. 267*b9175c69SKenjiro Tsuji * arg Depends on command. If DC_GET, ignored. 268*b9175c69SKenjiro Tsuji * If DC_SET, new flags value, created by ORing 269*b9175c69SKenjiro Tsuji * the DC_* bits. 27006e1a714Sraf * RETURN 27106e1a714Sraf * oldflags Old value of flags. -1 on error. 27206e1a714Sraf * NOTES 273*b9175c69SKenjiro Tsuji * The following commands are implemented: 274*b9175c69SKenjiro Tsuji * 275*b9175c69SKenjiro Tsuji * DC_CASE: respect(on)/ignore(off) case 276*b9175c69SKenjiro Tsuji * DC_NOREWIND: don't(on)/do(off) reqind in defread 277*b9175c69SKenjiro Tsuji * DC_STRIP_QUOTES: strip(on)/leave(off) qoates 27806e1a714Sraf */ 27906e1a714Sraf int 28006e1a714Sraf defcntl(int cmd, int newflags) 28106e1a714Sraf { 28206e1a714Sraf struct thr_data *thr_data = get_thr_data(); 283*b9175c69SKenjiro Tsuji 284*b9175c69SKenjiro Tsuji return (defcntl_r(cmd, newflags, thr_data)); 285*b9175c69SKenjiro Tsuji } 286*b9175c69SKenjiro Tsuji 287*b9175c69SKenjiro Tsuji /* 288*b9175c69SKenjiro Tsuji * defcntl_r -- default control 289*b9175c69SKenjiro Tsuji * 290*b9175c69SKenjiro Tsuji * SYNOPSIS 291*b9175c69SKenjiro Tsuji * oldflags = defcntl_r(int cmd, int arg, void *defp); 292*b9175c69SKenjiro Tsuji * 293*b9175c69SKenjiro Tsuji * ENTRY 294*b9175c69SKenjiro Tsuji * cmd Command. One of DC_GET, DC_SET. 295*b9175c69SKenjiro Tsuji * arg Depends on command. If DC_GET, ignored. 296*b9175c69SKenjiro Tsuji * If DC_SET, new flags value, created by ORing 297*b9175c69SKenjiro Tsuji * the DC_* bits. 298*b9175c69SKenjiro Tsuji * defp pointer to the defopen'd descriptor 299*b9175c69SKenjiro Tsuji * 300*b9175c69SKenjiro Tsuji * RETURN 301*b9175c69SKenjiro Tsuji * oldflags Old value of flags. -1 on error. 302*b9175c69SKenjiro Tsuji * NOTES 303*b9175c69SKenjiro Tsuji * The following commands are implemented: 304*b9175c69SKenjiro Tsuji * 305*b9175c69SKenjiro Tsuji * DC_CASE: respect(on)/ignore(off) case 306*b9175c69SKenjiro Tsuji * DC_NOREWIND: don't(on)/do(off) reqind in defread 307*b9175c69SKenjiro Tsuji * DC_STRIP_QUOTES: strip(on)/leave(off) qoates 308*b9175c69SKenjiro Tsuji */ 309*b9175c69SKenjiro Tsuji int 310*b9175c69SKenjiro Tsuji defcntl_r(int cmd, int newflags, void *ptr) 311*b9175c69SKenjiro Tsuji { 312*b9175c69SKenjiro Tsuji struct thr_data *thr_data = (struct thr_data *)ptr; 31306e1a714Sraf int oldflags; 31406e1a714Sraf 31506e1a714Sraf if (thr_data == NULL) 31606e1a714Sraf return (-1); 31706e1a714Sraf 31806e1a714Sraf switch (cmd) { 31906e1a714Sraf case DC_GETFLAGS: /* query */ 32006e1a714Sraf oldflags = thr_data->Dcflags; 32106e1a714Sraf break; 32206e1a714Sraf case DC_SETFLAGS: /* set */ 32306e1a714Sraf oldflags = thr_data->Dcflags; 32406e1a714Sraf thr_data->Dcflags = newflags; 32506e1a714Sraf break; 32606e1a714Sraf default: /* error */ 32706e1a714Sraf oldflags = -1; 32806e1a714Sraf break; 32906e1a714Sraf } 33006e1a714Sraf 33106e1a714Sraf return (oldflags); 33206e1a714Sraf } 33306e1a714Sraf 33406e1a714Sraf /* 335*b9175c69SKenjiro Tsuji * defclose_r() - close defopen file 336*b9175c69SKenjiro Tsuji * 337*b9175c69SKenjiro Tsuji * defclose_r(void *defp) 338*b9175c69SKenjiro Tsuji * 339*b9175c69SKenjiro Tsuji * defclose_r closes the defopen file associated with the specified 340*b9175c69SKenjiro Tsuji * pointer and releases the allocated resources. 341*b9175c69SKenjiro Tsuji */ 342*b9175c69SKenjiro Tsuji void 343*b9175c69SKenjiro Tsuji defclose_r(void *ptr) 344*b9175c69SKenjiro Tsuji { 345*b9175c69SKenjiro Tsuji struct thr_data *thr_data = (struct thr_data *)ptr; 346*b9175c69SKenjiro Tsuji 347*b9175c69SKenjiro Tsuji (void) fclose(thr_data->fp); 348*b9175c69SKenjiro Tsuji lfree(thr_data->buf, BUFFERSIZE); 349*b9175c69SKenjiro Tsuji lfree(thr_data, sizeof (struct thr_data)); 350*b9175c69SKenjiro Tsuji } 351*b9175c69SKenjiro Tsuji 352*b9175c69SKenjiro Tsuji /* 35306e1a714Sraf * strip_quotes -- strip double (") or single (') quotes from a buffer 35406e1a714Sraf * 35506e1a714Sraf * ENTRY 35606e1a714Sraf * ptr initial string 35706e1a714Sraf * 35806e1a714Sraf * EXIT 35906e1a714Sraf * ptr string with quotes (if any) removed 36006e1a714Sraf */ 36106e1a714Sraf static void 36206e1a714Sraf strip_quotes(char *ptr) 36306e1a714Sraf { 36406e1a714Sraf char *strip_ptr = NULL; 36506e1a714Sraf 36606e1a714Sraf while (*ptr != '\0') { 36706e1a714Sraf if ((*ptr == '"') || (*ptr == '\'')) { 36806e1a714Sraf if (strip_ptr == NULL) 36906e1a714Sraf strip_ptr = ptr; /* skip over quote */ 37006e1a714Sraf } else { 37106e1a714Sraf if (strip_ptr != NULL) { 37206e1a714Sraf *strip_ptr = *ptr; 37306e1a714Sraf strip_ptr++; 37406e1a714Sraf } 37506e1a714Sraf } 37606e1a714Sraf ptr++; 37706e1a714Sraf } 37806e1a714Sraf if (strip_ptr != NULL) { 37906e1a714Sraf *strip_ptr = '\0'; 38006e1a714Sraf } 38106e1a714Sraf } 382