xref: /aosp_15_r20/external/e2fsprogs/util/subst.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * subst.c --- substitution program
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Subst is used as a quickie program to do @ substitutions
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  */
7*6a54128fSAndroid Build Coastguard Worker 
8*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
9*6a54128fSAndroid Build Coastguard Worker #include "config.h"
10*6a54128fSAndroid Build Coastguard Worker #else
11*6a54128fSAndroid Build Coastguard Worker #define HAVE_SYS_STAT_H
12*6a54128fSAndroid Build Coastguard Worker #define HAVE_SYS_TIME_H
13*6a54128fSAndroid Build Coastguard Worker #endif
14*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
15*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
16*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
17*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
18*6a54128fSAndroid Build Coastguard Worker #include <string.h>
19*6a54128fSAndroid Build Coastguard Worker #include <ctype.h>
20*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_TIME_H
21*6a54128fSAndroid Build Coastguard Worker #include <sys/time.h>
22*6a54128fSAndroid Build Coastguard Worker #endif
23*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_TYPES_H
24*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
25*6a54128fSAndroid Build Coastguard Worker #endif
26*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_STAT_H
27*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
28*6a54128fSAndroid Build Coastguard Worker #endif
29*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
30*6a54128fSAndroid Build Coastguard Worker #include <time.h>
31*6a54128fSAndroid Build Coastguard Worker #include <utime.h>
32*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_TIME_H
33*6a54128fSAndroid Build Coastguard Worker #include <sys/time.h>
34*6a54128fSAndroid Build Coastguard Worker #endif
35*6a54128fSAndroid Build Coastguard Worker 
36*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETOPT_H
37*6a54128fSAndroid Build Coastguard Worker #include <getopt.h>
38*6a54128fSAndroid Build Coastguard Worker #else
39*6a54128fSAndroid Build Coastguard Worker extern char *optarg;
40*6a54128fSAndroid Build Coastguard Worker extern int optind;
41*6a54128fSAndroid Build Coastguard Worker #endif
42*6a54128fSAndroid Build Coastguard Worker 
43*6a54128fSAndroid Build Coastguard Worker 
44*6a54128fSAndroid Build Coastguard Worker struct subst_entry {
45*6a54128fSAndroid Build Coastguard Worker 	char *name;
46*6a54128fSAndroid Build Coastguard Worker 	char *value;
47*6a54128fSAndroid Build Coastguard Worker 	struct subst_entry *next;
48*6a54128fSAndroid Build Coastguard Worker };
49*6a54128fSAndroid Build Coastguard Worker 
50*6a54128fSAndroid Build Coastguard Worker static struct subst_entry *subst_table = 0;
51*6a54128fSAndroid Build Coastguard Worker 
add_subst(char * name,char * value)52*6a54128fSAndroid Build Coastguard Worker static int add_subst(char *name, char *value)
53*6a54128fSAndroid Build Coastguard Worker {
54*6a54128fSAndroid Build Coastguard Worker 	struct subst_entry	*ent = 0;
55*6a54128fSAndroid Build Coastguard Worker 
56*6a54128fSAndroid Build Coastguard Worker 	ent = (struct subst_entry *) malloc(sizeof(struct subst_entry));
57*6a54128fSAndroid Build Coastguard Worker 	if (!ent)
58*6a54128fSAndroid Build Coastguard Worker 		goto fail;
59*6a54128fSAndroid Build Coastguard Worker 	ent->name = (char *) malloc(strlen(name)+1);
60*6a54128fSAndroid Build Coastguard Worker 	if (!ent->name)
61*6a54128fSAndroid Build Coastguard Worker 		goto fail;
62*6a54128fSAndroid Build Coastguard Worker 	ent->value = (char *) malloc(strlen(value)+1);
63*6a54128fSAndroid Build Coastguard Worker 	if (!ent->value)
64*6a54128fSAndroid Build Coastguard Worker 		goto fail;
65*6a54128fSAndroid Build Coastguard Worker 	strcpy(ent->name, name);
66*6a54128fSAndroid Build Coastguard Worker 	strcpy(ent->value, value);
67*6a54128fSAndroid Build Coastguard Worker 	ent->next = subst_table;
68*6a54128fSAndroid Build Coastguard Worker 	subst_table = ent;
69*6a54128fSAndroid Build Coastguard Worker 	return 0;
70*6a54128fSAndroid Build Coastguard Worker fail:
71*6a54128fSAndroid Build Coastguard Worker 	if (ent) {
72*6a54128fSAndroid Build Coastguard Worker 		free(ent->name);
73*6a54128fSAndroid Build Coastguard Worker 		free(ent);
74*6a54128fSAndroid Build Coastguard Worker 	}
75*6a54128fSAndroid Build Coastguard Worker 	return ENOMEM;
76*6a54128fSAndroid Build Coastguard Worker }
77*6a54128fSAndroid Build Coastguard Worker 
fetch_subst_entry(char * name)78*6a54128fSAndroid Build Coastguard Worker static struct subst_entry *fetch_subst_entry(char *name)
79*6a54128fSAndroid Build Coastguard Worker {
80*6a54128fSAndroid Build Coastguard Worker 	struct subst_entry *ent;
81*6a54128fSAndroid Build Coastguard Worker 
82*6a54128fSAndroid Build Coastguard Worker 	for (ent = subst_table; ent; ent = ent->next) {
83*6a54128fSAndroid Build Coastguard Worker 		if (strcmp(name, ent->name) == 0)
84*6a54128fSAndroid Build Coastguard Worker 			break;
85*6a54128fSAndroid Build Coastguard Worker 	}
86*6a54128fSAndroid Build Coastguard Worker 	return ent;
87*6a54128fSAndroid Build Coastguard Worker }
88*6a54128fSAndroid Build Coastguard Worker 
89*6a54128fSAndroid Build Coastguard Worker /*
90*6a54128fSAndroid Build Coastguard Worker  * Given the starting and ending position of the replacement name,
91*6a54128fSAndroid Build Coastguard Worker  * check to see if it is valid, and pull it out if it is.
92*6a54128fSAndroid Build Coastguard Worker  */
get_subst_symbol(const char * begin,size_t len,char prefix)93*6a54128fSAndroid Build Coastguard Worker static char *get_subst_symbol(const char *begin, size_t len, char prefix)
94*6a54128fSAndroid Build Coastguard Worker {
95*6a54128fSAndroid Build Coastguard Worker 	static char replace_name[128];
96*6a54128fSAndroid Build Coastguard Worker 	char *cp, *start;
97*6a54128fSAndroid Build Coastguard Worker 
98*6a54128fSAndroid Build Coastguard Worker 	start = replace_name;
99*6a54128fSAndroid Build Coastguard Worker 	if (prefix)
100*6a54128fSAndroid Build Coastguard Worker 		*start++ = prefix;
101*6a54128fSAndroid Build Coastguard Worker 
102*6a54128fSAndroid Build Coastguard Worker 	if (len > sizeof(replace_name)-2)
103*6a54128fSAndroid Build Coastguard Worker 		return NULL;
104*6a54128fSAndroid Build Coastguard Worker 	memcpy(start, begin, len);
105*6a54128fSAndroid Build Coastguard Worker 	start[len] = 0;
106*6a54128fSAndroid Build Coastguard Worker 
107*6a54128fSAndroid Build Coastguard Worker 	/*
108*6a54128fSAndroid Build Coastguard Worker 	 * The substitution variable must all be in the of [0-9A-Za-z_].
109*6a54128fSAndroid Build Coastguard Worker 	 * If it isn't, this must be an invalid symbol name.
110*6a54128fSAndroid Build Coastguard Worker 	 */
111*6a54128fSAndroid Build Coastguard Worker 	for (cp = start; *cp; cp++) {
112*6a54128fSAndroid Build Coastguard Worker 		if (!(*cp >= 'a' && *cp <= 'z') &&
113*6a54128fSAndroid Build Coastguard Worker 		    !(*cp >= 'A' && *cp <= 'Z') &&
114*6a54128fSAndroid Build Coastguard Worker 		    !(*cp >= '0' && *cp <= '9') &&
115*6a54128fSAndroid Build Coastguard Worker 		    !(*cp == '_'))
116*6a54128fSAndroid Build Coastguard Worker 			return NULL;
117*6a54128fSAndroid Build Coastguard Worker 	}
118*6a54128fSAndroid Build Coastguard Worker 	return (replace_name);
119*6a54128fSAndroid Build Coastguard Worker }
120*6a54128fSAndroid Build Coastguard Worker 
replace_string(char * begin,char * end,char * newstr)121*6a54128fSAndroid Build Coastguard Worker static void replace_string(char *begin, char *end, char *newstr)
122*6a54128fSAndroid Build Coastguard Worker {
123*6a54128fSAndroid Build Coastguard Worker 	int	replace_len, len;
124*6a54128fSAndroid Build Coastguard Worker 
125*6a54128fSAndroid Build Coastguard Worker 	replace_len = strlen(newstr);
126*6a54128fSAndroid Build Coastguard Worker 	len = end - begin;
127*6a54128fSAndroid Build Coastguard Worker 	if (replace_len == 0)
128*6a54128fSAndroid Build Coastguard Worker 		memmove(begin, end+1, strlen(end)+1);
129*6a54128fSAndroid Build Coastguard Worker 	else if (replace_len != len+1)
130*6a54128fSAndroid Build Coastguard Worker 		memmove(end+(replace_len-len-1), end,
131*6a54128fSAndroid Build Coastguard Worker 			strlen(end)+1);
132*6a54128fSAndroid Build Coastguard Worker 	memcpy(begin, newstr, replace_len);
133*6a54128fSAndroid Build Coastguard Worker }
134*6a54128fSAndroid Build Coastguard Worker 
substitute_line(char * line)135*6a54128fSAndroid Build Coastguard Worker static void substitute_line(char *line)
136*6a54128fSAndroid Build Coastguard Worker {
137*6a54128fSAndroid Build Coastguard Worker 	char	*ptr, *name_ptr, *end_ptr;
138*6a54128fSAndroid Build Coastguard Worker 	struct subst_entry *ent;
139*6a54128fSAndroid Build Coastguard Worker 	char	*replace_name;
140*6a54128fSAndroid Build Coastguard Worker 	size_t	len;
141*6a54128fSAndroid Build Coastguard Worker 
142*6a54128fSAndroid Build Coastguard Worker 	/*
143*6a54128fSAndroid Build Coastguard Worker 	 * Expand all @FOO@ substitutions
144*6a54128fSAndroid Build Coastguard Worker 	 */
145*6a54128fSAndroid Build Coastguard Worker 	ptr = line;
146*6a54128fSAndroid Build Coastguard Worker 	while (ptr) {
147*6a54128fSAndroid Build Coastguard Worker 		name_ptr = strchr(ptr, '@');
148*6a54128fSAndroid Build Coastguard Worker 		if (!name_ptr)
149*6a54128fSAndroid Build Coastguard Worker 			break;	/* No more */
150*6a54128fSAndroid Build Coastguard Worker 		if (*(++name_ptr) == '@') {
151*6a54128fSAndroid Build Coastguard Worker 			/*
152*6a54128fSAndroid Build Coastguard Worker 			 * Handle tytso@@mit.edu --> [email protected]
153*6a54128fSAndroid Build Coastguard Worker 			 */
154*6a54128fSAndroid Build Coastguard Worker 			memmove(name_ptr-1, name_ptr, strlen(name_ptr)+1);
155*6a54128fSAndroid Build Coastguard Worker 			ptr = name_ptr+1;
156*6a54128fSAndroid Build Coastguard Worker 			continue;
157*6a54128fSAndroid Build Coastguard Worker 		}
158*6a54128fSAndroid Build Coastguard Worker 		end_ptr = strchr(name_ptr, '@');
159*6a54128fSAndroid Build Coastguard Worker 		if (!end_ptr)
160*6a54128fSAndroid Build Coastguard Worker 			break;
161*6a54128fSAndroid Build Coastguard Worker 		len = end_ptr - name_ptr;
162*6a54128fSAndroid Build Coastguard Worker 		replace_name = get_subst_symbol(name_ptr, len, 0);
163*6a54128fSAndroid Build Coastguard Worker 		if (!replace_name) {
164*6a54128fSAndroid Build Coastguard Worker 			ptr = name_ptr;
165*6a54128fSAndroid Build Coastguard Worker 			continue;
166*6a54128fSAndroid Build Coastguard Worker 		}
167*6a54128fSAndroid Build Coastguard Worker 		ent = fetch_subst_entry(replace_name);
168*6a54128fSAndroid Build Coastguard Worker 		if (!ent) {
169*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "Unfound expansion: '%s'\n",
170*6a54128fSAndroid Build Coastguard Worker 				replace_name);
171*6a54128fSAndroid Build Coastguard Worker 			ptr = end_ptr + 1;
172*6a54128fSAndroid Build Coastguard Worker 			continue;
173*6a54128fSAndroid Build Coastguard Worker 		}
174*6a54128fSAndroid Build Coastguard Worker #if 0
175*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "Replace name = '%s' with '%s'\n",
176*6a54128fSAndroid Build Coastguard Worker 		       replace_name, ent->value);
177*6a54128fSAndroid Build Coastguard Worker #endif
178*6a54128fSAndroid Build Coastguard Worker 		ptr = name_ptr-1;
179*6a54128fSAndroid Build Coastguard Worker 		replace_string(ptr, end_ptr, ent->value);
180*6a54128fSAndroid Build Coastguard Worker 		if ((ent->value[0] == '@') &&
181*6a54128fSAndroid Build Coastguard Worker 		    (strlen(replace_name) == strlen(ent->value)-2) &&
182*6a54128fSAndroid Build Coastguard Worker 		    !strncmp(replace_name, ent->value+1,
183*6a54128fSAndroid Build Coastguard Worker 			     strlen(ent->value)-2))
184*6a54128fSAndroid Build Coastguard Worker 			/* avoid an infinite loop */
185*6a54128fSAndroid Build Coastguard Worker 			ptr += strlen(ent->value);
186*6a54128fSAndroid Build Coastguard Worker 	}
187*6a54128fSAndroid Build Coastguard Worker 	/*
188*6a54128fSAndroid Build Coastguard Worker 	 * Now do a second pass to expand ${FOO}
189*6a54128fSAndroid Build Coastguard Worker 	 */
190*6a54128fSAndroid Build Coastguard Worker 	ptr = line;
191*6a54128fSAndroid Build Coastguard Worker 	while (ptr) {
192*6a54128fSAndroid Build Coastguard Worker 		name_ptr = strchr(ptr, '$');
193*6a54128fSAndroid Build Coastguard Worker 		if (!name_ptr)
194*6a54128fSAndroid Build Coastguard Worker 			break;	/* No more */
195*6a54128fSAndroid Build Coastguard Worker 		if (*(++name_ptr) != '{') {
196*6a54128fSAndroid Build Coastguard Worker 			ptr = name_ptr;
197*6a54128fSAndroid Build Coastguard Worker 			continue;
198*6a54128fSAndroid Build Coastguard Worker 		}
199*6a54128fSAndroid Build Coastguard Worker 		name_ptr++;
200*6a54128fSAndroid Build Coastguard Worker 		end_ptr = strchr(name_ptr, '}');
201*6a54128fSAndroid Build Coastguard Worker 		if (!end_ptr)
202*6a54128fSAndroid Build Coastguard Worker 			break;
203*6a54128fSAndroid Build Coastguard Worker 		len = end_ptr - name_ptr;
204*6a54128fSAndroid Build Coastguard Worker 		replace_name = get_subst_symbol(name_ptr, len, '$');
205*6a54128fSAndroid Build Coastguard Worker 		if (!replace_name) {
206*6a54128fSAndroid Build Coastguard Worker 			ptr = name_ptr;
207*6a54128fSAndroid Build Coastguard Worker 			continue;
208*6a54128fSAndroid Build Coastguard Worker 		}
209*6a54128fSAndroid Build Coastguard Worker 		ent = fetch_subst_entry(replace_name);
210*6a54128fSAndroid Build Coastguard Worker 		if (!ent) {
211*6a54128fSAndroid Build Coastguard Worker 			ptr = end_ptr + 1;
212*6a54128fSAndroid Build Coastguard Worker 			continue;
213*6a54128fSAndroid Build Coastguard Worker 		}
214*6a54128fSAndroid Build Coastguard Worker #if 0
215*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "Replace name = '%s' with '%s'\n",
216*6a54128fSAndroid Build Coastguard Worker 		       replace_name, ent->value);
217*6a54128fSAndroid Build Coastguard Worker #endif
218*6a54128fSAndroid Build Coastguard Worker 		ptr = name_ptr-2;
219*6a54128fSAndroid Build Coastguard Worker 		replace_string(ptr, end_ptr, ent->value);
220*6a54128fSAndroid Build Coastguard Worker 	}
221*6a54128fSAndroid Build Coastguard Worker }
222*6a54128fSAndroid Build Coastguard Worker 
parse_config_file(FILE * f)223*6a54128fSAndroid Build Coastguard Worker static void parse_config_file(FILE *f)
224*6a54128fSAndroid Build Coastguard Worker {
225*6a54128fSAndroid Build Coastguard Worker 	char	line[2048];
226*6a54128fSAndroid Build Coastguard Worker 	char	*cp, *ptr;
227*6a54128fSAndroid Build Coastguard Worker 
228*6a54128fSAndroid Build Coastguard Worker 	while (!feof(f)) {
229*6a54128fSAndroid Build Coastguard Worker 		memset(line, 0, sizeof(line));
230*6a54128fSAndroid Build Coastguard Worker 		if (fgets(line, sizeof(line), f) == NULL)
231*6a54128fSAndroid Build Coastguard Worker 			break;
232*6a54128fSAndroid Build Coastguard Worker 		/*
233*6a54128fSAndroid Build Coastguard Worker 		 * Strip newlines and comments.
234*6a54128fSAndroid Build Coastguard Worker 		 */
235*6a54128fSAndroid Build Coastguard Worker 		cp = strchr(line, '\n');
236*6a54128fSAndroid Build Coastguard Worker 		if (cp)
237*6a54128fSAndroid Build Coastguard Worker 			*cp = 0;
238*6a54128fSAndroid Build Coastguard Worker 		cp = strchr(line, '#');
239*6a54128fSAndroid Build Coastguard Worker 		if (cp)
240*6a54128fSAndroid Build Coastguard Worker 			*cp = 0;
241*6a54128fSAndroid Build Coastguard Worker 		/*
242*6a54128fSAndroid Build Coastguard Worker 		 * Skip trailing and leading whitespace
243*6a54128fSAndroid Build Coastguard Worker 		 */
244*6a54128fSAndroid Build Coastguard Worker 		for (cp = line + strlen(line) - 1; cp >= line; cp--) {
245*6a54128fSAndroid Build Coastguard Worker 			if (*cp == ' ' || *cp == '\t')
246*6a54128fSAndroid Build Coastguard Worker 				*cp = 0;
247*6a54128fSAndroid Build Coastguard Worker 			else
248*6a54128fSAndroid Build Coastguard Worker 				break;
249*6a54128fSAndroid Build Coastguard Worker 		}
250*6a54128fSAndroid Build Coastguard Worker 		cp = line;
251*6a54128fSAndroid Build Coastguard Worker 		while (*cp && isspace(*cp))
252*6a54128fSAndroid Build Coastguard Worker 			cp++;
253*6a54128fSAndroid Build Coastguard Worker 		ptr = cp;
254*6a54128fSAndroid Build Coastguard Worker 		/*
255*6a54128fSAndroid Build Coastguard Worker 		 * Skip empty lines
256*6a54128fSAndroid Build Coastguard Worker 		 */
257*6a54128fSAndroid Build Coastguard Worker 		if (*ptr == 0)
258*6a54128fSAndroid Build Coastguard Worker 			continue;
259*6a54128fSAndroid Build Coastguard Worker 		/*
260*6a54128fSAndroid Build Coastguard Worker 		 * Ignore future extensions
261*6a54128fSAndroid Build Coastguard Worker 		 */
262*6a54128fSAndroid Build Coastguard Worker 		if (*ptr == '@')
263*6a54128fSAndroid Build Coastguard Worker 			continue;
264*6a54128fSAndroid Build Coastguard Worker 		/*
265*6a54128fSAndroid Build Coastguard Worker 		 * Parse substitutions
266*6a54128fSAndroid Build Coastguard Worker 		 */
267*6a54128fSAndroid Build Coastguard Worker 		for (cp = ptr; *cp; cp++)
268*6a54128fSAndroid Build Coastguard Worker 			if (isspace(*cp))
269*6a54128fSAndroid Build Coastguard Worker 				break;
270*6a54128fSAndroid Build Coastguard Worker 		*cp = 0;
271*6a54128fSAndroid Build Coastguard Worker 		for (cp++; *cp; cp++)
272*6a54128fSAndroid Build Coastguard Worker 			if (!isspace(*cp))
273*6a54128fSAndroid Build Coastguard Worker 				break;
274*6a54128fSAndroid Build Coastguard Worker #if 0
275*6a54128fSAndroid Build Coastguard Worker 		printf("Substitute: '%s' for '%s'\n", ptr, cp ? cp : "<NULL>");
276*6a54128fSAndroid Build Coastguard Worker #endif
277*6a54128fSAndroid Build Coastguard Worker 		add_subst(ptr, cp);
278*6a54128fSAndroid Build Coastguard Worker 	}
279*6a54128fSAndroid Build Coastguard Worker }
280*6a54128fSAndroid Build Coastguard Worker 
281*6a54128fSAndroid Build Coastguard Worker /*
282*6a54128fSAndroid Build Coastguard Worker  * Return 0 if the files are different, 1 if the files are the same.
283*6a54128fSAndroid Build Coastguard Worker  */
compare_file(FILE * old_f,FILE * new_f)284*6a54128fSAndroid Build Coastguard Worker static int compare_file(FILE *old_f, FILE *new_f)
285*6a54128fSAndroid Build Coastguard Worker {
286*6a54128fSAndroid Build Coastguard Worker 	char	oldbuf[2048], newbuf[2048], *oldcp, *newcp;
287*6a54128fSAndroid Build Coastguard Worker 	int	retval;
288*6a54128fSAndroid Build Coastguard Worker 
289*6a54128fSAndroid Build Coastguard Worker 	while (1) {
290*6a54128fSAndroid Build Coastguard Worker 		oldcp = fgets(oldbuf, sizeof(oldbuf), old_f);
291*6a54128fSAndroid Build Coastguard Worker 		newcp = fgets(newbuf, sizeof(newbuf), new_f);
292*6a54128fSAndroid Build Coastguard Worker 		if (!oldcp && !newcp) {
293*6a54128fSAndroid Build Coastguard Worker 			retval = 1;
294*6a54128fSAndroid Build Coastguard Worker 			break;
295*6a54128fSAndroid Build Coastguard Worker 		}
296*6a54128fSAndroid Build Coastguard Worker 		if (!oldcp || !newcp || strcmp(oldbuf, newbuf)) {
297*6a54128fSAndroid Build Coastguard Worker 			retval = 0;
298*6a54128fSAndroid Build Coastguard Worker 			break;
299*6a54128fSAndroid Build Coastguard Worker 		}
300*6a54128fSAndroid Build Coastguard Worker 	}
301*6a54128fSAndroid Build Coastguard Worker 	return retval;
302*6a54128fSAndroid Build Coastguard Worker }
303*6a54128fSAndroid Build Coastguard Worker 
set_utimes(const char * filename,int fd,const struct timeval times[2])304*6a54128fSAndroid Build Coastguard Worker void set_utimes(const char *filename, int fd, const struct timeval times[2])
305*6a54128fSAndroid Build Coastguard Worker {
306*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_FUTIMES
307*6a54128fSAndroid Build Coastguard Worker 	if (futimes(fd, times) < 0)
308*6a54128fSAndroid Build Coastguard Worker 		perror("futimes");
309*6a54128fSAndroid Build Coastguard Worker #elif HAVE_UTIMES
310*6a54128fSAndroid Build Coastguard Worker 	if (utimes(filename, times) < 0)
311*6a54128fSAndroid Build Coastguard Worker 		perror("utimes");
312*6a54128fSAndroid Build Coastguard Worker #else
313*6a54128fSAndroid Build Coastguard Worker 	struct utimbuf ut;
314*6a54128fSAndroid Build Coastguard Worker 
315*6a54128fSAndroid Build Coastguard Worker 	ut.actime = times[0].tv_sec;
316*6a54128fSAndroid Build Coastguard Worker 	ut.modtime = times[1].tv_sec;
317*6a54128fSAndroid Build Coastguard Worker 	if (utime(filename, &ut) < 0)
318*6a54128fSAndroid Build Coastguard Worker 		perror("utime");
319*6a54128fSAndroid Build Coastguard Worker #endif
320*6a54128fSAndroid Build Coastguard Worker }
321*6a54128fSAndroid Build Coastguard Worker 
322*6a54128fSAndroid Build Coastguard Worker 
main(int argc,char ** argv)323*6a54128fSAndroid Build Coastguard Worker int main(int argc, char **argv)
324*6a54128fSAndroid Build Coastguard Worker {
325*6a54128fSAndroid Build Coastguard Worker 	char	line[2048];
326*6a54128fSAndroid Build Coastguard Worker 	int	c;
327*6a54128fSAndroid Build Coastguard Worker 	int	fd, ofd = -1;
328*6a54128fSAndroid Build Coastguard Worker 	FILE	*in, *out, *old = NULL;
329*6a54128fSAndroid Build Coastguard Worker 	char	*outfn = NULL, *newfn = NULL;
330*6a54128fSAndroid Build Coastguard Worker 	int	verbose = 0;
331*6a54128fSAndroid Build Coastguard Worker 	int	adjust_timestamp = 0;
332*6a54128fSAndroid Build Coastguard Worker 	int	got_atime = 0;
333*6a54128fSAndroid Build Coastguard Worker 	struct stat stbuf;
334*6a54128fSAndroid Build Coastguard Worker 	struct timeval tv[2];
335*6a54128fSAndroid Build Coastguard Worker 
336*6a54128fSAndroid Build Coastguard Worker 	while ((c = getopt (argc, argv, "f:tv")) != EOF) {
337*6a54128fSAndroid Build Coastguard Worker 		switch (c) {
338*6a54128fSAndroid Build Coastguard Worker 		case 'f':
339*6a54128fSAndroid Build Coastguard Worker 			in = fopen(optarg, "r");
340*6a54128fSAndroid Build Coastguard Worker 			if (!in) {
341*6a54128fSAndroid Build Coastguard Worker 				perror(optarg);
342*6a54128fSAndroid Build Coastguard Worker 				exit(1);
343*6a54128fSAndroid Build Coastguard Worker 			}
344*6a54128fSAndroid Build Coastguard Worker 			parse_config_file(in);
345*6a54128fSAndroid Build Coastguard Worker 			fclose(in);
346*6a54128fSAndroid Build Coastguard Worker 			break;
347*6a54128fSAndroid Build Coastguard Worker 		case 't':
348*6a54128fSAndroid Build Coastguard Worker 			adjust_timestamp++;
349*6a54128fSAndroid Build Coastguard Worker 			break;
350*6a54128fSAndroid Build Coastguard Worker 		case 'v':
351*6a54128fSAndroid Build Coastguard Worker 			verbose++;
352*6a54128fSAndroid Build Coastguard Worker 			break;
353*6a54128fSAndroid Build Coastguard Worker 		default:
354*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "%s: [-f config-file] [file]\n",
355*6a54128fSAndroid Build Coastguard Worker 				argv[0]);
356*6a54128fSAndroid Build Coastguard Worker 			break;
357*6a54128fSAndroid Build Coastguard Worker 		}
358*6a54128fSAndroid Build Coastguard Worker 	}
359*6a54128fSAndroid Build Coastguard Worker 	if (optind < argc) {
360*6a54128fSAndroid Build Coastguard Worker 		in = fopen(argv[optind], "r");
361*6a54128fSAndroid Build Coastguard Worker 		if (!in) {
362*6a54128fSAndroid Build Coastguard Worker 			perror(argv[optind]);
363*6a54128fSAndroid Build Coastguard Worker 			exit(1);
364*6a54128fSAndroid Build Coastguard Worker 		}
365*6a54128fSAndroid Build Coastguard Worker 		optind++;
366*6a54128fSAndroid Build Coastguard Worker 	} else
367*6a54128fSAndroid Build Coastguard Worker 		in = stdin;
368*6a54128fSAndroid Build Coastguard Worker 
369*6a54128fSAndroid Build Coastguard Worker 	if (optind < argc) {
370*6a54128fSAndroid Build Coastguard Worker 		outfn = argv[optind];
371*6a54128fSAndroid Build Coastguard Worker 		newfn = (char *) malloc(strlen(outfn)+20);
372*6a54128fSAndroid Build Coastguard Worker 		if (!newfn) {
373*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "Memory error!  Exiting.\n");
374*6a54128fSAndroid Build Coastguard Worker 			exit(1);
375*6a54128fSAndroid Build Coastguard Worker 		}
376*6a54128fSAndroid Build Coastguard Worker 		strcpy(newfn, outfn);
377*6a54128fSAndroid Build Coastguard Worker 		strcat(newfn, ".new");
378*6a54128fSAndroid Build Coastguard Worker 		ofd = open(newfn, O_CREAT|O_TRUNC|O_RDWR, 0644);
379*6a54128fSAndroid Build Coastguard Worker 		if (ofd < 0) {
380*6a54128fSAndroid Build Coastguard Worker 			perror(newfn);
381*6a54128fSAndroid Build Coastguard Worker 			exit(1);
382*6a54128fSAndroid Build Coastguard Worker 		}
383*6a54128fSAndroid Build Coastguard Worker 		out = fdopen(ofd, "w+");
384*6a54128fSAndroid Build Coastguard Worker 		if (!out) {
385*6a54128fSAndroid Build Coastguard Worker 			perror("fdopen");
386*6a54128fSAndroid Build Coastguard Worker 			exit(1);
387*6a54128fSAndroid Build Coastguard Worker 		}
388*6a54128fSAndroid Build Coastguard Worker 
389*6a54128fSAndroid Build Coastguard Worker 		fd = open(outfn, O_RDONLY);
390*6a54128fSAndroid Build Coastguard Worker 		if (fd > 0) {
391*6a54128fSAndroid Build Coastguard Worker 			/* save the original atime, if possible */
392*6a54128fSAndroid Build Coastguard Worker 			if (fstat(fd, &stbuf) == 0) {
393*6a54128fSAndroid Build Coastguard Worker #if HAVE_STRUCT_STAT_ST_ATIM
394*6a54128fSAndroid Build Coastguard Worker 				tv[0].tv_sec = stbuf.st_atim.tv_sec;
395*6a54128fSAndroid Build Coastguard Worker 				tv[0].tv_usec = stbuf.st_atim.tv_nsec / 1000;
396*6a54128fSAndroid Build Coastguard Worker #else
397*6a54128fSAndroid Build Coastguard Worker 				tv[0].tv_sec = stbuf.st_atime;
398*6a54128fSAndroid Build Coastguard Worker 				tv[0].tv_usec = 0;
399*6a54128fSAndroid Build Coastguard Worker #endif
400*6a54128fSAndroid Build Coastguard Worker 				got_atime = 1;
401*6a54128fSAndroid Build Coastguard Worker 			}
402*6a54128fSAndroid Build Coastguard Worker 			old = fdopen(fd, "r");
403*6a54128fSAndroid Build Coastguard Worker 			if (!old)
404*6a54128fSAndroid Build Coastguard Worker 				close(fd);
405*6a54128fSAndroid Build Coastguard Worker 		}
406*6a54128fSAndroid Build Coastguard Worker 	} else {
407*6a54128fSAndroid Build Coastguard Worker 		out = stdout;
408*6a54128fSAndroid Build Coastguard Worker 		outfn = 0;
409*6a54128fSAndroid Build Coastguard Worker 	}
410*6a54128fSAndroid Build Coastguard Worker 
411*6a54128fSAndroid Build Coastguard Worker 	while (!feof(in)) {
412*6a54128fSAndroid Build Coastguard Worker 		if (fgets(line, sizeof(line), in) == NULL)
413*6a54128fSAndroid Build Coastguard Worker 			break;
414*6a54128fSAndroid Build Coastguard Worker 		substitute_line(line);
415*6a54128fSAndroid Build Coastguard Worker 		fputs(line, out);
416*6a54128fSAndroid Build Coastguard Worker 	}
417*6a54128fSAndroid Build Coastguard Worker 	fclose(in);
418*6a54128fSAndroid Build Coastguard Worker 	if (outfn) {
419*6a54128fSAndroid Build Coastguard Worker 		fflush(out);
420*6a54128fSAndroid Build Coastguard Worker 		rewind(out);
421*6a54128fSAndroid Build Coastguard Worker 		if (old && compare_file(old, out)) {
422*6a54128fSAndroid Build Coastguard Worker 			if (verbose)
423*6a54128fSAndroid Build Coastguard Worker 				printf("No change, keeping %s.\n", outfn);
424*6a54128fSAndroid Build Coastguard Worker 			if (adjust_timestamp) {
425*6a54128fSAndroid Build Coastguard Worker 				if (verbose)
426*6a54128fSAndroid Build Coastguard Worker 					printf("Updating modtime for %s\n", outfn);
427*6a54128fSAndroid Build Coastguard Worker 				if (gettimeofday(&tv[1], NULL) < 0) {
428*6a54128fSAndroid Build Coastguard Worker 					perror("gettimeofday");
429*6a54128fSAndroid Build Coastguard Worker 					exit(1);
430*6a54128fSAndroid Build Coastguard Worker 				}
431*6a54128fSAndroid Build Coastguard Worker 				if (got_atime == 0)
432*6a54128fSAndroid Build Coastguard Worker 					tv[0] = tv[1];
433*6a54128fSAndroid Build Coastguard Worker 				else if (verbose)
434*6a54128fSAndroid Build Coastguard Worker 					printf("Using original atime\n");
435*6a54128fSAndroid Build Coastguard Worker 				set_utimes(outfn, fileno(old), tv);
436*6a54128fSAndroid Build Coastguard Worker 			}
437*6a54128fSAndroid Build Coastguard Worker #ifndef _WIN32
438*6a54128fSAndroid Build Coastguard Worker 			if (ofd >= 0)
439*6a54128fSAndroid Build Coastguard Worker 				(void) fchmod(ofd, 0444);
440*6a54128fSAndroid Build Coastguard Worker #endif
441*6a54128fSAndroid Build Coastguard Worker 			fclose(out);
442*6a54128fSAndroid Build Coastguard Worker 			if (unlink(newfn) < 0)
443*6a54128fSAndroid Build Coastguard Worker 				perror("unlink");
444*6a54128fSAndroid Build Coastguard Worker 		} else {
445*6a54128fSAndroid Build Coastguard Worker 			if (verbose)
446*6a54128fSAndroid Build Coastguard Worker 				printf("Creating or replacing %s.\n", outfn);
447*6a54128fSAndroid Build Coastguard Worker #ifndef _WIN32
448*6a54128fSAndroid Build Coastguard Worker 			if (ofd >= 0)
449*6a54128fSAndroid Build Coastguard Worker 				(void) fchmod(ofd, 0444);
450*6a54128fSAndroid Build Coastguard Worker #endif
451*6a54128fSAndroid Build Coastguard Worker 			fclose(out);
452*6a54128fSAndroid Build Coastguard Worker 			if (old)
453*6a54128fSAndroid Build Coastguard Worker 				fclose(old);
454*6a54128fSAndroid Build Coastguard Worker 			old = NULL;
455*6a54128fSAndroid Build Coastguard Worker 			if (rename(newfn, outfn) < 0) {
456*6a54128fSAndroid Build Coastguard Worker 				perror("rename");
457*6a54128fSAndroid Build Coastguard Worker 				exit(1);
458*6a54128fSAndroid Build Coastguard Worker 			}
459*6a54128fSAndroid Build Coastguard Worker 		}
460*6a54128fSAndroid Build Coastguard Worker 	}
461*6a54128fSAndroid Build Coastguard Worker 	if (old)
462*6a54128fSAndroid Build Coastguard Worker 		fclose(old);
463*6a54128fSAndroid Build Coastguard Worker 	if (newfn)
464*6a54128fSAndroid Build Coastguard Worker 		free(newfn);
465*6a54128fSAndroid Build Coastguard Worker 	return (0);
466*6a54128fSAndroid Build Coastguard Worker }
467*6a54128fSAndroid Build Coastguard Worker 
468*6a54128fSAndroid Build Coastguard Worker 
469