12923Sraf /*
22923Sraf * CDDL HEADER START
32923Sraf *
42923Sraf * The contents of this file are subject to the terms of the
52923Sraf * Common Development and Distribution License (the "License").
62923Sraf * You may not use this file except in compliance with the License.
72923Sraf *
82923Sraf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92923Sraf * or http://www.opensolaris.org/os/licensing.
102923Sraf * See the License for the specific language governing permissions
112923Sraf * and limitations under the License.
122923Sraf *
132923Sraf * When distributing Covered Code, include this CDDL HEADER in each
142923Sraf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152923Sraf * If applicable, add the following below this CDDL HEADER, with the
162923Sraf * fields enclosed by brackets "[]" replaced with your own identifying
172923Sraf * information: Portions Copyright [yyyy] [name of copyright owner]
182923Sraf *
192923Sraf * CDDL HEADER END
202923Sraf */
212923Sraf
222923Sraf /*
23*8563SKenjiro.Tsuji@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
242923Sraf * Use is subject to license terms.
252923Sraf */
262923Sraf
272923Sraf /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
282923Sraf /* All Rights Reserved */
292923Sraf
302923Sraf /* Copyright (c) 1987, 1988 Microsoft Corporation */
312923Sraf /* All Rights Reserved */
322923Sraf
336812Sraf #include "lint.h"
342923Sraf #include "libc.h"
352923Sraf #include <stdio.h>
362923Sraf #include <stdlib.h>
372923Sraf #include <deflt.h>
382923Sraf #include <sys/types.h>
392923Sraf #include <string.h>
402923Sraf #include <ctype.h>
412923Sraf #include <unistd.h>
422923Sraf #include "tsd.h"
432923Sraf
442923Sraf #define TSTBITS(flags, mask) (((flags) & (mask)) == (mask))
452923Sraf
462923Sraf struct thr_data {
472923Sraf int Dcflags; /* [re-]initialized on each call to defopen() */
482923Sraf FILE *fp;
492923Sraf char *buf;
502923Sraf };
512923Sraf
52*8563SKenjiro.Tsuji@Sun.COM static int defopen_common(const char *, struct thr_data *);
53*8563SKenjiro.Tsuji@Sun.COM static void strip_quotes(char *);
54*8563SKenjiro.Tsuji@Sun.COM
552923Sraf #define BUFFERSIZE 1024
562923Sraf
572923Sraf /*
582923Sraf * destructor for per-thread data, registered with tsdalloc()
592923Sraf */
602923Sraf static void
free_thr_data(void * arg)612923Sraf free_thr_data(void *arg)
622923Sraf {
632923Sraf struct thr_data *thr_data = (struct thr_data *)arg;
642923Sraf
652923Sraf if (thr_data->fp) {
662923Sraf (void) fclose(thr_data->fp);
672923Sraf thr_data->fp = NULL;
682923Sraf }
692923Sraf if (thr_data->buf) {
702923Sraf lfree(thr_data->buf, BUFFERSIZE);
712923Sraf thr_data->buf = NULL;
722923Sraf }
732923Sraf }
742923Sraf
752923Sraf /*
762923Sraf * get the per-thread-data-item for the calling thread
772923Sraf */
782923Sraf static struct thr_data *
get_thr_data(void)792923Sraf get_thr_data(void)
802923Sraf {
812923Sraf struct thr_data *thr_data =
822923Sraf tsdalloc(_T_DEFREAD, sizeof (*thr_data), free_thr_data);
832923Sraf
842923Sraf return (thr_data);
852923Sraf }
862923Sraf
872923Sraf /*
882923Sraf * defopen() - declare defopen filename
892923Sraf *
902923Sraf * defopen(fn)
912923Sraf * char *fn
922923Sraf *
932923Sraf * If 'fn' is non-null; it is a full pathname of a file
942923Sraf * which becomes the one read by subsequent defread() calls.
952923Sraf * If 'fn' is null the defopen file is closed.
962923Sraf *
972923Sraf * see defread() for more details.
982923Sraf *
992923Sraf * EXIT returns 0 if ok
1002923Sraf * returns -1 if error
1012923Sraf */
1022923Sraf int
defopen(char * fn)1032923Sraf defopen(char *fn)
1042923Sraf {
1052923Sraf struct thr_data *thr_data = get_thr_data();
1062923Sraf
107*8563SKenjiro.Tsuji@Sun.COM return (defopen_common(fn, thr_data));
108*8563SKenjiro.Tsuji@Sun.COM }
109*8563SKenjiro.Tsuji@Sun.COM
110*8563SKenjiro.Tsuji@Sun.COM /*
111*8563SKenjiro.Tsuji@Sun.COM * defopen_r() - declare defopen filename (reentrant)
112*8563SKenjiro.Tsuji@Sun.COM *
113*8563SKenjiro.Tsuji@Sun.COM * defopen_r(const char *fn)
114*8563SKenjiro.Tsuji@Sun.COM *
115*8563SKenjiro.Tsuji@Sun.COM * 'fn' is a full pathname of a file which becomes the one read
116*8563SKenjiro.Tsuji@Sun.COM * by subsequent defread_r() calls. defopen_r returns a pointer
117*8563SKenjiro.Tsuji@Sun.COM * to the internally allocated buffer containing the file descriptor.
118*8563SKenjiro.Tsuji@Sun.COM * The pointer should be specified to the following defread_r and
119*8563SKenjiro.Tsuji@Sun.COM * defcntl_r functions. As the pointer to be returned points to
120*8563SKenjiro.Tsuji@Sun.COM * the libc lmalloc'd memory, defclose_r must be used to close
121*8563SKenjiro.Tsuji@Sun.COM * the defopen file and to release the allocated memory. Caller
122*8563SKenjiro.Tsuji@Sun.COM * must not try to release the memory by free().
123*8563SKenjiro.Tsuji@Sun.COM *
124*8563SKenjiro.Tsuji@Sun.COM * see defread_r() for more details.
125*8563SKenjiro.Tsuji@Sun.COM *
126*8563SKenjiro.Tsuji@Sun.COM * EXIT returns non-NULL pointer if success
127*8563SKenjiro.Tsuji@Sun.COM * returns NULL if error
128*8563SKenjiro.Tsuji@Sun.COM */
129*8563SKenjiro.Tsuji@Sun.COM void *
defopen_r(const char * fn)130*8563SKenjiro.Tsuji@Sun.COM defopen_r(const char *fn)
131*8563SKenjiro.Tsuji@Sun.COM {
132*8563SKenjiro.Tsuji@Sun.COM /* memory allocated by lmalloc gets initialized to zeros */
133*8563SKenjiro.Tsuji@Sun.COM struct thr_data *thr_data = lmalloc(sizeof (struct thr_data));
134*8563SKenjiro.Tsuji@Sun.COM
135*8563SKenjiro.Tsuji@Sun.COM if (defopen_common(fn, thr_data) < 0) {
136*8563SKenjiro.Tsuji@Sun.COM if (thr_data != NULL)
137*8563SKenjiro.Tsuji@Sun.COM lfree(thr_data, sizeof (struct thr_data));
138*8563SKenjiro.Tsuji@Sun.COM return (NULL);
139*8563SKenjiro.Tsuji@Sun.COM }
140*8563SKenjiro.Tsuji@Sun.COM
141*8563SKenjiro.Tsuji@Sun.COM return ((void *)thr_data);
142*8563SKenjiro.Tsuji@Sun.COM }
143*8563SKenjiro.Tsuji@Sun.COM
144*8563SKenjiro.Tsuji@Sun.COM static int
defopen_common(const char * fn,struct thr_data * thr_data)145*8563SKenjiro.Tsuji@Sun.COM defopen_common(const char *fn, struct thr_data *thr_data)
146*8563SKenjiro.Tsuji@Sun.COM {
1472923Sraf if (thr_data == NULL)
1482923Sraf return (-1);
1492923Sraf
1502923Sraf if (thr_data->fp != NULL) {
1512923Sraf (void) fclose(thr_data->fp);
1522923Sraf thr_data->fp = NULL;
1532923Sraf }
1542923Sraf
1552923Sraf if (fn == NULL)
1562923Sraf return (0);
1572923Sraf
1582923Sraf if ((thr_data->fp = fopen(fn, "rF")) == NULL)
1592923Sraf return (-1);
1602923Sraf
1612923Sraf /*
1622923Sraf * We allocate the big buffer only if the fopen() succeeds.
163*8563SKenjiro.Tsuji@Sun.COM * Notice that we deallocate the buffer only when the thread exits
164*8563SKenjiro.Tsuji@Sun.COM * for defopen().
1652923Sraf * There are misguided applications that assume that data returned
1662923Sraf * by defread() continues to exist after defopen(NULL) is called.
1672923Sraf */
1682923Sraf if (thr_data->buf == NULL &&
1692923Sraf (thr_data->buf = lmalloc(BUFFERSIZE)) == NULL) {
1702923Sraf (void) fclose(thr_data->fp);
1712923Sraf thr_data->fp = NULL;
1722923Sraf return (-1);
1732923Sraf }
1742923Sraf
1752923Sraf thr_data->Dcflags = DC_STD;
1762923Sraf
1772923Sraf return (0);
1782923Sraf }
1792923Sraf
1802923Sraf /*
1812923Sraf * defread() - read an entry from the defopen file
1822923Sraf *
1832923Sraf * defread(cp)
1842923Sraf * char *cp
1852923Sraf *
1862923Sraf * The defopen data file must have been previously opened by
1872923Sraf * defopen(). defread scans the data file looking for a line
1882923Sraf * which begins with the string '*cp'. If such a line is found,
1892923Sraf * defread returns a pointer to the first character following
1902923Sraf * the matched string (*cp). If no line is found or no file
1912923Sraf * is open, defread() returns NULL.
1922923Sraf *
193*8563SKenjiro.Tsuji@Sun.COM * Note that there is no way to simultaneously peruse multiple
1942923Sraf * defopen files; since there is no way of indicating 'which one'
1952923Sraf * to defread(). If you want to peruse a secondary file you must
1962923Sraf * recall defopen(). If you need to go back to the first file,
1972923Sraf * you must call defopen() again.
1982923Sraf */
1992923Sraf char *
defread(char * cp)2002923Sraf defread(char *cp)
2012923Sraf {
2022923Sraf struct thr_data *thr_data = get_thr_data();
203*8563SKenjiro.Tsuji@Sun.COM
204*8563SKenjiro.Tsuji@Sun.COM return (defread_r(cp, thr_data));
205*8563SKenjiro.Tsuji@Sun.COM }
206*8563SKenjiro.Tsuji@Sun.COM
207*8563SKenjiro.Tsuji@Sun.COM /*
208*8563SKenjiro.Tsuji@Sun.COM * defread_r() - read an entry from the defopen file
209*8563SKenjiro.Tsuji@Sun.COM *
210*8563SKenjiro.Tsuji@Sun.COM * defread_r(const char *cp, void *defp)
211*8563SKenjiro.Tsuji@Sun.COM *
212*8563SKenjiro.Tsuji@Sun.COM * defread_r scans the data file associated with the pointer
213*8563SKenjiro.Tsuji@Sun.COM * specified by 'defp' that was returned by defopen_r(), and
214*8563SKenjiro.Tsuji@Sun.COM * looks for a line which begins with the string '*cp'.
215*8563SKenjiro.Tsuji@Sun.COM * If such a line is found, defread_r returns a pointer to
216*8563SKenjiro.Tsuji@Sun.COM * the first character following the matched string (*cp).
217*8563SKenjiro.Tsuji@Sun.COM * If no line is found or no file is open, defread_r() returns NULL.
218*8563SKenjiro.Tsuji@Sun.COM */
219*8563SKenjiro.Tsuji@Sun.COM char *
defread_r(const char * cp,void * ptr)220*8563SKenjiro.Tsuji@Sun.COM defread_r(const char *cp, void *ptr)
221*8563SKenjiro.Tsuji@Sun.COM {
222*8563SKenjiro.Tsuji@Sun.COM struct thr_data *thr_data = (struct thr_data *)ptr;
2232923Sraf int (*compare)(const char *, const char *, size_t);
224*8563SKenjiro.Tsuji@Sun.COM char *buf_tmp;
225*8563SKenjiro.Tsuji@Sun.COM char *ret_ptr = NULL;
2262923Sraf size_t off, patlen;
2272923Sraf
2282923Sraf if (thr_data == NULL || thr_data->fp == NULL)
2292923Sraf return (NULL);
2302923Sraf
2312923Sraf compare = TSTBITS(thr_data->Dcflags, DC_CASE) ? strncmp : strncasecmp;
2322923Sraf patlen = strlen(cp);
2332923Sraf
2342923Sraf if (!TSTBITS(thr_data->Dcflags, DC_NOREWIND))
2352923Sraf rewind(thr_data->fp);
2362923Sraf
2372923Sraf while (fgets(thr_data->buf, BUFFERSIZE, thr_data->fp)) {
2382923Sraf for (buf_tmp = thr_data->buf; *buf_tmp == ' '; buf_tmp++)
2392923Sraf ;
2402923Sraf off = strlen(buf_tmp) - 1;
2412923Sraf if (buf_tmp[off] == '\n')
2422923Sraf buf_tmp[off] = 0;
2432923Sraf else
2442923Sraf break; /* line too long */
2452923Sraf if ((*compare)(cp, buf_tmp, patlen) == 0) {
2462923Sraf /* found it */
2472923Sraf /* strip quotes if requested */
2482923Sraf if (TSTBITS(thr_data->Dcflags, DC_STRIP_QUOTES)) {
2492923Sraf strip_quotes(buf_tmp);
2502923Sraf }
2512923Sraf ret_ptr = &buf_tmp[patlen];
2522923Sraf break;
2532923Sraf }
2542923Sraf }
2552923Sraf
2562923Sraf return (ret_ptr);
2572923Sraf }
2582923Sraf
2592923Sraf /*
2602923Sraf * defcntl -- default control
2612923Sraf *
2622923Sraf * SYNOPSIS
2632923Sraf * oldflags = defcntl(cmd, arg);
2642923Sraf *
2652923Sraf * ENTRY
2662923Sraf * cmd Command. One of DC_GET, DC_SET.
267*8563SKenjiro.Tsuji@Sun.COM * arg Depends on command. If DC_GET, ignored.
268*8563SKenjiro.Tsuji@Sun.COM * If DC_SET, new flags value, created by ORing
269*8563SKenjiro.Tsuji@Sun.COM * the DC_* bits.
2702923Sraf * RETURN
2712923Sraf * oldflags Old value of flags. -1 on error.
2722923Sraf * NOTES
273*8563SKenjiro.Tsuji@Sun.COM * The following commands are implemented:
274*8563SKenjiro.Tsuji@Sun.COM *
275*8563SKenjiro.Tsuji@Sun.COM * DC_CASE: respect(on)/ignore(off) case
276*8563SKenjiro.Tsuji@Sun.COM * DC_NOREWIND: don't(on)/do(off) reqind in defread
277*8563SKenjiro.Tsuji@Sun.COM * DC_STRIP_QUOTES: strip(on)/leave(off) qoates
2782923Sraf */
2792923Sraf int
defcntl(int cmd,int newflags)2802923Sraf defcntl(int cmd, int newflags)
2812923Sraf {
2822923Sraf struct thr_data *thr_data = get_thr_data();
283*8563SKenjiro.Tsuji@Sun.COM
284*8563SKenjiro.Tsuji@Sun.COM return (defcntl_r(cmd, newflags, thr_data));
285*8563SKenjiro.Tsuji@Sun.COM }
286*8563SKenjiro.Tsuji@Sun.COM
287*8563SKenjiro.Tsuji@Sun.COM /*
288*8563SKenjiro.Tsuji@Sun.COM * defcntl_r -- default control
289*8563SKenjiro.Tsuji@Sun.COM *
290*8563SKenjiro.Tsuji@Sun.COM * SYNOPSIS
291*8563SKenjiro.Tsuji@Sun.COM * oldflags = defcntl_r(int cmd, int arg, void *defp);
292*8563SKenjiro.Tsuji@Sun.COM *
293*8563SKenjiro.Tsuji@Sun.COM * ENTRY
294*8563SKenjiro.Tsuji@Sun.COM * cmd Command. One of DC_GET, DC_SET.
295*8563SKenjiro.Tsuji@Sun.COM * arg Depends on command. If DC_GET, ignored.
296*8563SKenjiro.Tsuji@Sun.COM * If DC_SET, new flags value, created by ORing
297*8563SKenjiro.Tsuji@Sun.COM * the DC_* bits.
298*8563SKenjiro.Tsuji@Sun.COM * defp pointer to the defopen'd descriptor
299*8563SKenjiro.Tsuji@Sun.COM *
300*8563SKenjiro.Tsuji@Sun.COM * RETURN
301*8563SKenjiro.Tsuji@Sun.COM * oldflags Old value of flags. -1 on error.
302*8563SKenjiro.Tsuji@Sun.COM * NOTES
303*8563SKenjiro.Tsuji@Sun.COM * The following commands are implemented:
304*8563SKenjiro.Tsuji@Sun.COM *
305*8563SKenjiro.Tsuji@Sun.COM * DC_CASE: respect(on)/ignore(off) case
306*8563SKenjiro.Tsuji@Sun.COM * DC_NOREWIND: don't(on)/do(off) reqind in defread
307*8563SKenjiro.Tsuji@Sun.COM * DC_STRIP_QUOTES: strip(on)/leave(off) qoates
308*8563SKenjiro.Tsuji@Sun.COM */
309*8563SKenjiro.Tsuji@Sun.COM int
defcntl_r(int cmd,int newflags,void * ptr)310*8563SKenjiro.Tsuji@Sun.COM defcntl_r(int cmd, int newflags, void *ptr)
311*8563SKenjiro.Tsuji@Sun.COM {
312*8563SKenjiro.Tsuji@Sun.COM struct thr_data *thr_data = (struct thr_data *)ptr;
3132923Sraf int oldflags;
3142923Sraf
3152923Sraf if (thr_data == NULL)
3162923Sraf return (-1);
3172923Sraf
3182923Sraf switch (cmd) {
3192923Sraf case DC_GETFLAGS: /* query */
3202923Sraf oldflags = thr_data->Dcflags;
3212923Sraf break;
3222923Sraf case DC_SETFLAGS: /* set */
3232923Sraf oldflags = thr_data->Dcflags;
3242923Sraf thr_data->Dcflags = newflags;
3252923Sraf break;
3262923Sraf default: /* error */
3272923Sraf oldflags = -1;
3282923Sraf break;
3292923Sraf }
3302923Sraf
3312923Sraf return (oldflags);
3322923Sraf }
3332923Sraf
3342923Sraf /*
335*8563SKenjiro.Tsuji@Sun.COM * defclose_r() - close defopen file
336*8563SKenjiro.Tsuji@Sun.COM *
337*8563SKenjiro.Tsuji@Sun.COM * defclose_r(void *defp)
338*8563SKenjiro.Tsuji@Sun.COM *
339*8563SKenjiro.Tsuji@Sun.COM * defclose_r closes the defopen file associated with the specified
340*8563SKenjiro.Tsuji@Sun.COM * pointer and releases the allocated resources.
341*8563SKenjiro.Tsuji@Sun.COM */
342*8563SKenjiro.Tsuji@Sun.COM void
defclose_r(void * ptr)343*8563SKenjiro.Tsuji@Sun.COM defclose_r(void *ptr)
344*8563SKenjiro.Tsuji@Sun.COM {
345*8563SKenjiro.Tsuji@Sun.COM struct thr_data *thr_data = (struct thr_data *)ptr;
346*8563SKenjiro.Tsuji@Sun.COM
347*8563SKenjiro.Tsuji@Sun.COM (void) fclose(thr_data->fp);
348*8563SKenjiro.Tsuji@Sun.COM lfree(thr_data->buf, BUFFERSIZE);
349*8563SKenjiro.Tsuji@Sun.COM lfree(thr_data, sizeof (struct thr_data));
350*8563SKenjiro.Tsuji@Sun.COM }
351*8563SKenjiro.Tsuji@Sun.COM
352*8563SKenjiro.Tsuji@Sun.COM /*
3532923Sraf * strip_quotes -- strip double (") or single (') quotes from a buffer
3542923Sraf *
3552923Sraf * ENTRY
3562923Sraf * ptr initial string
3572923Sraf *
3582923Sraf * EXIT
3592923Sraf * ptr string with quotes (if any) removed
3602923Sraf */
3612923Sraf static void
strip_quotes(char * ptr)3622923Sraf strip_quotes(char *ptr)
3632923Sraf {
3642923Sraf char *strip_ptr = NULL;
3652923Sraf
3662923Sraf while (*ptr != '\0') {
3672923Sraf if ((*ptr == '"') || (*ptr == '\'')) {
3682923Sraf if (strip_ptr == NULL)
3692923Sraf strip_ptr = ptr; /* skip over quote */
3702923Sraf } else {
3712923Sraf if (strip_ptr != NULL) {
3722923Sraf *strip_ptr = *ptr;
3732923Sraf strip_ptr++;
3742923Sraf }
3752923Sraf }
3762923Sraf ptr++;
3772923Sraf }
3782923Sraf if (strip_ptr != NULL) {
3792923Sraf *strip_ptr = '\0';
3802923Sraf }
3812923Sraf }
382