xref: /minix/external/bsd/pkg_install/dist/lib/var.c (revision a824f5a1)
1 /*	$NetBSD: var.c,v 1.2 2013/05/16 19:19:44 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Dieter Baron, Thomas Klausner, Johnny Lam, and Joerg Sonnenberger.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The NetBSD Foundation nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #if HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 #include <nbcompat.h>
39 #if HAVE_SYS_CDEFS_H
40 #include <sys/cdefs.h>
41 #endif
42 __RCSID("$NetBSD: var.c,v 1.2 2013/05/16 19:19:44 martin Exp $");
43 
44 #if HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47 #if HAVE_ERR_H
48 #include <err.h>
49 #endif
50 #if HAVE_ERRNO_H
51 #include <errno.h>
52 #endif
53 #if HAVE_STDIO_H
54 #include <stdio.h>
55 #endif
56 
57 #include "lib.h"
58 
59 static const char *var_cmp(const char *, size_t, const char *, size_t);
60 static void var_print(FILE *, const char *, const char *);
61 
62 /*
63  * Copy the specified varibales from the file fname to stdout.
64  */
65 int
var_copy_list(const char * buf,const char ** variables)66 var_copy_list(const char *buf, const char **variables)
67 {
68 	const char *eol, *next;
69 	size_t len;
70 	int i;
71 
72 	for (; *buf; buf = next) {
73 		if ((eol = strchr(buf, '\n')) != NULL) {
74 			next = eol + 1;
75 			len = eol - buf;
76 		} else {
77 			next = eol;
78 			len = strlen(buf);
79 		}
80 
81 		for (i=0; variables[i]; i++) {
82 			if (var_cmp(buf, len, variables[i],
83 				       strlen(variables[i])) != NULL) {
84 				printf("%.*s\n", (int)len, buf);
85 				break;
86 			}
87 		}
88 	}
89 	return 0;
90 }
91 
92 /*
93  * Print the value of variable from the file fname to stdout.
94  */
95 char *
var_get(const char * fname,const char * variable)96 var_get(const char *fname, const char *variable)
97 {
98 	FILE   *fp;
99 	char   *line;
100 	size_t  len;
101 	size_t  varlen;
102 	char   *value;
103 	size_t  valuelen;
104 	size_t  thislen;
105 	const char *p;
106 
107 	varlen = strlen(variable);
108 	if (varlen == 0)
109 		return NULL;
110 
111 	fp = fopen(fname, "r");
112 	if (!fp) {
113 		if (errno != ENOENT)
114 			warn("var_get: can't open '%s' for reading", fname);
115 		return NULL;
116 	}
117 
118 	value = NULL;
119 	valuelen = 0;
120 
121 	while ((line = fgetln(fp, &len)) != (char *) NULL) {
122 		if (line[len - 1] == '\n')
123 			--len;
124 		if ((p=var_cmp(line, len, variable, varlen)) == NULL)
125 			continue;
126 
127 		thislen = line+len - p;
128 		if (value) {
129 			value = xrealloc(value, valuelen+thislen+2);
130 			value[valuelen++] = '\n';
131 		}
132 		else {
133 			value = xmalloc(thislen+1);
134 		}
135 		sprintf(value+valuelen, "%.*s", (int)thislen, p);
136 		valuelen += thislen;
137 	}
138 	(void) fclose(fp);
139 	return value;
140 }
141 
142 /*
143  * Print the value of variable from the memory buffer to stdout.
144  */
145 char *
var_get_memory(const char * buf,const char * variable)146 var_get_memory(const char *buf, const char *variable)
147 {
148 	const char *eol, *next, *data;
149 	size_t len, varlen, thislen, valuelen;
150 	char *value;
151 
152 	varlen = strlen(variable);
153 	if (varlen == 0)
154 		return NULL;
155 
156 	value = NULL;
157 	valuelen = 0;
158 
159 	for (; buf && *buf; buf = next) {
160 		if ((eol = strchr(buf, '\n')) != NULL) {
161 			next = eol + 1;
162 			len = eol - buf;
163 		} else {
164 			next = eol;
165 			len = strlen(buf);
166 		}
167 		if ((data = var_cmp(buf, len, variable, varlen)) == NULL)
168 			continue;
169 
170 		thislen = buf + len - data;
171 		if (value) {
172 			value = xrealloc(value, valuelen+thislen+2);
173 			value[valuelen++] = '\n';
174 		}
175 		else {
176 			value = xmalloc(thislen+1);
177 		}
178 		sprintf(value + valuelen, "%.*s", (int)thislen, data);
179 		valuelen += thislen;
180 	}
181 	return value;
182 }
183 
184 /*
185  * Add given variable with given value to file, overwriting any
186  * previous occurrence.
187  */
188 int
var_set(const char * fname,const char * variable,const char * value)189 var_set(const char *fname, const char *variable, const char *value)
190 {
191 	FILE   *fp;
192 	FILE   *fout;
193 	char   *tmpname;
194 	int     fd;
195 	char   *line;
196 	size_t  len;
197 	size_t  varlen;
198 	Boolean done;
199 	struct stat st;
200 
201 	varlen = strlen(variable);
202 	if (varlen == 0)
203 		return 0;
204 
205 	fp = fopen(fname, "r");
206 	if (fp == NULL) {
207 		if (errno != ENOENT) {
208 			warn("var_set: can't open '%s' for reading", fname);
209 			return -1;
210 		}
211 		if (value == NULL)
212 			return 0; /* Nothing to do */
213 	}
214 
215 	tmpname = xasprintf("%s.XXXXXX", fname);
216 	if ((fd = mkstemp(tmpname)) < 0) {
217 		free(tmpname);
218 		if (fp != NULL)
219 			fclose(fp);
220 		warn("var_set: can't open temp file for '%s' for writing",
221 		      fname);
222 		return -1;
223 	}
224 	if (chmod(tmpname, 0644) < 0) {
225 		close(fd);
226 		if (fp != NULL)
227 			fclose(fp);
228 		free(tmpname);
229 		warn("var_set: can't set permissions for temp file for '%s'",
230 		      fname);
231 		return -1;
232 	}
233 	if ((fout=fdopen(fd, "w")) == NULL) {
234 		close(fd);
235 		remove(tmpname);
236 		free(tmpname);
237 		if (fp != NULL)
238 			fclose(fp);
239 		warn("var_set: can't open temp file for '%s' for writing",
240 		      fname);
241 		return -1;
242 	}
243 
244 	done = FALSE;
245 
246 	if (fp) {
247 		while ((line = fgetln(fp, &len)) != (char *) NULL) {
248 			if (var_cmp(line, len, variable, varlen) == NULL)
249 				fprintf(fout, "%.*s", (int)len, line);
250 			else {
251 				if (!done && value) {
252 					var_print(fout, variable, value);
253 					done = TRUE;
254 				}
255 			}
256 		}
257 		(void) fclose(fp);
258 	}
259 
260 	if (!done && value)
261 		var_print(fout, variable, value);
262 
263 	if (fclose(fout) < 0) {
264 		free(tmpname);
265 		warn("var_set: write error for '%s'", fname);
266 		return -1;
267 	}
268 
269 	if (stat(tmpname, &st) < 0) {
270 		free(tmpname);
271 		warn("var_set: cannot stat tempfile for '%s'", fname);
272 		return -1;
273 	}
274 
275 	if (st.st_size == 0) {
276 		if (remove(tmpname) < 0) {
277 			free(tmpname);
278 			warn("var_set: cannot remove tempfile for '%s'",
279 			     fname);
280 			return -1;
281 		}
282 		free(tmpname);
283 		if (remove(fname) < 0) {
284 			warn("var_set: cannot remove '%s'", fname);
285 			return -1;
286 		}
287 		return 0;
288 	}
289 
290 	if (rename(tmpname, fname) < 0) {
291 		free(tmpname);
292 		warn("var_set: cannot move tempfile to '%s'", fname);
293 		return -1;
294 	}
295 	free(tmpname);
296 	return 0;
297 }
298 
299 /*
300  * Check if line contains variable var, return pointer to its value or NULL.
301  */
302 static const char *
var_cmp(const char * line,size_t linelen,const char * var,size_t varlen)303 var_cmp(const char *line, size_t linelen, const char *var, size_t varlen)
304 {
305 	/*
306 	 * We expect lines to look like one of the following
307 	 * forms:
308 	 *      VAR=value
309 	 *      VAR= value
310 	 * We print out the value of VAR, or nothing if it
311 	 * doesn't exist.
312 	 */
313 	if (linelen < varlen+1)
314 		return NULL;
315 	if (strncmp(var, line, varlen) != 0)
316 		return NULL;
317 
318 	line += varlen;
319 	if (*line != '=')
320 		return NULL;
321 
322 	++line;
323 	linelen -= varlen+1;
324 	if (linelen > 0 && *line == ' ')
325 		++line;
326 	return line;
327 }
328 
329 /*
330  * Print given variable with value to file f.
331  */
332 static void
var_print(FILE * f,const char * variable,const char * value)333 var_print(FILE *f, const char *variable, const char *value)
334 {
335 	const char *p;
336 
337 	while ((p=strchr(value, '\n')) != NULL) {
338 		if (p != value)
339 			fprintf(f, "%s=%.*s\n", variable, (int)(p-value), value);
340 		value = p+1;
341 	}
342 
343 	if (*value)
344 		fprintf(f, "%s=%s\n", variable, value);
345 }
346