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
free_thr_data(void * arg)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 *
get_thr_data(void)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
defopen(char * fn)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 *
defopen_r(const char * fn)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
defopen_common(const char * fn,struct thr_data * thr_data)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 *
defread(char * cp)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 *
defread_r(const char * cp,void * ptr)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
defcntl(int cmd,int newflags)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
defcntl_r(int cmd,int newflags,void * ptr)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
defclose_r(void * ptr)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
strip_quotes(char * ptr)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