1/** \ingroup popt
2 * \file popt/poptconfig.c
3 */
4
5/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
6   file accompanying popt source distributions, available from
7   ftp://ftp.rpm.org/pub/rpm/dist. */
8
9#include "system.h"
10#include "poptint.h"
11
12/*@-compmempass@*/	/* FIX: item->option.longName kept, not dependent. */
13static void configLine(poptContext con, unsigned char * line)
14	/*@modifies con @*/
15{
16    /*@-type@*/
17    int nameLength = strlen(con->appName);
18    /*@=type@*/
19    const char * entryType;
20    const char * opt;
21    poptItem item = (poptItem) alloca(sizeof(*item));
22    int i, j;
23
24    memset(item, 0, sizeof(*item));
25
26    /*@-type@*/
27    if (strncmp(line, con->appName, nameLength)) return;
28    /*@=type@*/
29
30    line += nameLength;
31    if (*line == '\0' || !isspace(*line)) return;
32
33    while (*line != '\0' && isspace(*line)) line++;
34    entryType = line;
35    while (*line == '\0' || !isspace(*line)) line++;
36    *line++ = '\0';
37
38    while (*line != '\0' && isspace(*line)) line++;
39    if (*line == '\0') return;
40    opt = line;
41    while (*line == '\0' || !isspace(*line)) line++;
42    *line++ = '\0';
43
44    while (*line != '\0' && isspace(*line)) line++;
45    if (*line == '\0') return;
46
47    /*@-temptrans@*/ /* FIX: line alias is saved */
48    if (opt[0] == '-' && opt[1] == '-')
49	item->option.longName = opt + 2;
50    else if (opt[0] == '-' && opt[2] == '\0')
51	item->option.shortName = opt[1];
52    /*@=temptrans@*/
53
54    if (poptParseArgvString(line, &item->argc, &item->argv)) return;
55
56    /*@-modobserver@*/
57    item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
58    for (i = 0, j = 0; i < item->argc; i++, j++) {
59	const char * f;
60	if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
61	    f = item->argv[i] + sizeof("--POPTdesc=");
62	    if (f[0] == '$' && f[1] == '"') f++;
63	    item->option.descrip = f;
64	    item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
65	    j--;
66	} else
67	if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
68	    f = item->argv[i] + sizeof("--POPTargs=");
69	    if (f[0] == '$' && f[1] == '"') f++;
70	    item->option.argDescrip = f;
71	    item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
72	    item->option.argInfo |= POPT_ARG_STRING;
73	    j--;
74	} else
75	if (j != i)
76	    item->argv[j] = item->argv[i];
77    }
78    if (j != i) {
79	item->argv[j] = NULL;
80	item->argc = j;
81    }
82    /*@=modobserver@*/
83
84    /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
85    if (!strcmp(entryType, "alias"))
86	(void) poptAddItem(con, item, 0);
87    else if (!strcmp(entryType, "exec"))
88	(void) poptAddItem(con, item, 1);
89    /*@=nullstate@*/
90}
91/*@=compmempass@*/
92
93int poptReadConfigFile(poptContext con, const char * fn)
94{
95    const unsigned char * file, * chptr, * end;
96    unsigned char * buf;
97/*@dependent@*/ unsigned char * dst;
98    int fd, rc;
99    off_t fileLength;
100
101    fd = open(fn, O_RDONLY);
102    if (fd < 0)
103	return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
104
105    fileLength = lseek(fd, 0, SEEK_END);
106    if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
107	rc = errno;
108	(void) close(fd);
109	/*@-mods@*/
110	errno = rc;
111	/*@=mods@*/
112	return POPT_ERROR_ERRNO;
113    }
114
115    file = alloca(fileLength + 1);
116    if (read(fd, (char *)file, fileLength) != fileLength) {
117	rc = errno;
118	(void) close(fd);
119	/*@-mods@*/
120	errno = rc;
121	/*@=mods@*/
122	return POPT_ERROR_ERRNO;
123    }
124    if (close(fd) == -1)
125	return POPT_ERROR_ERRNO;
126
127    dst = buf = alloca(fileLength + 1);
128
129    chptr = file;
130    end = (file + fileLength);
131    /*@-infloops@*/	/* LCL: can't detect chptr++ */
132    while (chptr < end) {
133	switch (*chptr) {
134	  case '\n':
135	    *dst = '\0';
136	    dst = buf;
137	    while (*dst && isspace(*dst)) dst++;
138	    if (*dst && *dst != '#')
139		configLine(con, dst);
140	    chptr++;
141	    /*@switchbreak@*/ break;
142	  case '\\':
143	    *dst++ = *chptr++;
144	    if (chptr < end) {
145		if (*chptr == '\n')
146		    dst--, chptr++;
147		    /* \ at the end of a line does not insert a \n */
148		else
149		    *dst++ = *chptr++;
150	    }
151	    /*@switchbreak@*/ break;
152	  default:
153	    *dst++ = *chptr++;
154	    /*@switchbreak@*/ break;
155	}
156    }
157    /*@=infloops@*/
158
159    return 0;
160}
161
162int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
163{
164    char * fn, * home;
165    int rc;
166
167    /*@-type@*/
168    if (!con->appName) return 0;
169    /*@=type@*/
170
171    rc = poptReadConfigFile(con, "/etc/popt");
172    if (rc) return rc;
173    if (getuid() != geteuid()) return 0;
174
175    if ((home = getenv("HOME"))) {
176	fn = alloca(strlen(home) + 20);
177	strcpy(fn, home);
178	strcat(fn, "/.popt");
179	rc = poptReadConfigFile(con, fn);
180	if (rc) return rc;
181    }
182
183    return 0;
184}
185