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