xref: /aosp_15_r20/external/e2fsprogs/util/symlinks.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS 64
2*6a54128fSAndroid Build Coastguard Worker #ifndef _LARGEFILE_SOURCE
3*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE_SOURCE
4*6a54128fSAndroid Build Coastguard Worker #endif
5*6a54128fSAndroid Build Coastguard Worker #ifndef _LARGEFILE64_SOURCE
6*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
7*6a54128fSAndroid Build Coastguard Worker #endif
8*6a54128fSAndroid Build Coastguard Worker 
9*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
10*6a54128fSAndroid Build Coastguard Worker #ifndef _POSIX_SOURCE
11*6a54128fSAndroid Build Coastguard Worker #define _POSIX_SOURCE
12*6a54128fSAndroid Build Coastguard Worker #endif
13*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
14*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
15*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_MALLOC_H
16*6a54128fSAndroid Build Coastguard Worker #include <malloc.h>
17*6a54128fSAndroid Build Coastguard Worker #endif
18*6a54128fSAndroid Build Coastguard Worker #include <string.h>
19*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
20*6a54128fSAndroid Build Coastguard Worker #include <sys/param.h>
21*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
22*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
23*6a54128fSAndroid Build Coastguard Worker #include <dirent.h>
24*6a54128fSAndroid Build Coastguard Worker #include <time.h>
25*6a54128fSAndroid Build Coastguard Worker #include <stddef.h>
26*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
27*6a54128fSAndroid Build Coastguard Worker 
28*6a54128fSAndroid Build Coastguard Worker #ifndef S_ISLNK
29*6a54128fSAndroid Build Coastguard Worker #define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK))
30*6a54128fSAndroid Build Coastguard Worker #endif
31*6a54128fSAndroid Build Coastguard Worker 
32*6a54128fSAndroid Build Coastguard Worker #ifndef PATH_MAX
33*6a54128fSAndroid Build Coastguard Worker #define PATH_MAX 1024
34*6a54128fSAndroid Build Coastguard Worker #endif
35*6a54128fSAndroid Build Coastguard Worker 
36*6a54128fSAndroid Build Coastguard Worker #define progver "%s: scan/change symbolic links - v1.3 - by Mark Lord\n\n"
37*6a54128fSAndroid Build Coastguard Worker static char *progname;
38*6a54128fSAndroid Build Coastguard Worker static int verbose = 0, fix_links = 0, recurse = 0, delete = 0, shorten = 0,
39*6a54128fSAndroid Build Coastguard Worker 		testing = 0, single_fs = 1;
40*6a54128fSAndroid Build Coastguard Worker 
41*6a54128fSAndroid Build Coastguard Worker /*
42*6a54128fSAndroid Build Coastguard Worker  * tidypath removes excess slashes and "." references from a path string
43*6a54128fSAndroid Build Coastguard Worker  */
44*6a54128fSAndroid Build Coastguard Worker 
substr(char * s,char * old,char * new)45*6a54128fSAndroid Build Coastguard Worker static int substr (char *s, char *old, char *new)
46*6a54128fSAndroid Build Coastguard Worker {
47*6a54128fSAndroid Build Coastguard Worker 	char *tmp = NULL;
48*6a54128fSAndroid Build Coastguard Worker 	int oldlen = strlen(old), newlen = 0;
49*6a54128fSAndroid Build Coastguard Worker 
50*6a54128fSAndroid Build Coastguard Worker 	if (NULL == strstr(s, old))
51*6a54128fSAndroid Build Coastguard Worker 		return 0;
52*6a54128fSAndroid Build Coastguard Worker 
53*6a54128fSAndroid Build Coastguard Worker 	if (new)
54*6a54128fSAndroid Build Coastguard Worker 		newlen = strlen(new);
55*6a54128fSAndroid Build Coastguard Worker 
56*6a54128fSAndroid Build Coastguard Worker 	if (newlen > oldlen) {
57*6a54128fSAndroid Build Coastguard Worker 		if ((tmp = malloc(strlen(s))) == NULL) {
58*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "no memory\n");
59*6a54128fSAndroid Build Coastguard Worker 			exit (1);
60*6a54128fSAndroid Build Coastguard Worker 		}
61*6a54128fSAndroid Build Coastguard Worker 	}
62*6a54128fSAndroid Build Coastguard Worker 
63*6a54128fSAndroid Build Coastguard Worker 	while (NULL != (s = strstr(s, old))) {
64*6a54128fSAndroid Build Coastguard Worker 		char *p, *old_s = s;
65*6a54128fSAndroid Build Coastguard Worker 
66*6a54128fSAndroid Build Coastguard Worker 		if (new) {
67*6a54128fSAndroid Build Coastguard Worker 			if (newlen > oldlen)
68*6a54128fSAndroid Build Coastguard Worker 				old_s = strcpy(tmp, s);
69*6a54128fSAndroid Build Coastguard Worker 			p = new;
70*6a54128fSAndroid Build Coastguard Worker 			while (*p)
71*6a54128fSAndroid Build Coastguard Worker 				*s++ = *p++;
72*6a54128fSAndroid Build Coastguard Worker 		}
73*6a54128fSAndroid Build Coastguard Worker 		p = old_s + oldlen;
74*6a54128fSAndroid Build Coastguard Worker 		while ((*s++ = *p++));
75*6a54128fSAndroid Build Coastguard Worker 	}
76*6a54128fSAndroid Build Coastguard Worker 	if (tmp)
77*6a54128fSAndroid Build Coastguard Worker 		free(tmp);
78*6a54128fSAndroid Build Coastguard Worker 	return 1;
79*6a54128fSAndroid Build Coastguard Worker }
80*6a54128fSAndroid Build Coastguard Worker 
81*6a54128fSAndroid Build Coastguard Worker 
tidy_path(char * path)82*6a54128fSAndroid Build Coastguard Worker static int tidy_path (char *path)
83*6a54128fSAndroid Build Coastguard Worker {
84*6a54128fSAndroid Build Coastguard Worker 	int tidied = 0;
85*6a54128fSAndroid Build Coastguard Worker 	char *s, *p;
86*6a54128fSAndroid Build Coastguard Worker 
87*6a54128fSAndroid Build Coastguard Worker 	s = path + strlen(path) - 1;
88*6a54128fSAndroid Build Coastguard Worker 	if (s[0] != '/') {	/* tmp trailing slash simplifies things */
89*6a54128fSAndroid Build Coastguard Worker 		s[1] = '/';
90*6a54128fSAndroid Build Coastguard Worker 		s[2] = '\0';
91*6a54128fSAndroid Build Coastguard Worker 	}
92*6a54128fSAndroid Build Coastguard Worker 	while (substr(path, "/./", "/"))
93*6a54128fSAndroid Build Coastguard Worker 		tidied = 1;
94*6a54128fSAndroid Build Coastguard Worker 	while (substr(path, "//", "/"))
95*6a54128fSAndroid Build Coastguard Worker 		tidied = 1;
96*6a54128fSAndroid Build Coastguard Worker 
97*6a54128fSAndroid Build Coastguard Worker 	while ((p = strstr(path,"/../")) != NULL) {
98*6a54128fSAndroid Build Coastguard Worker 		s = p+3;
99*6a54128fSAndroid Build Coastguard Worker 		for (p--; p != path; p--) if (*p == '/') break;
100*6a54128fSAndroid Build Coastguard Worker 		if (*p != '/')
101*6a54128fSAndroid Build Coastguard Worker 			break;
102*6a54128fSAndroid Build Coastguard Worker 		while ((*p++ = *s++));
103*6a54128fSAndroid Build Coastguard Worker 		tidied = 1;
104*6a54128fSAndroid Build Coastguard Worker 	}
105*6a54128fSAndroid Build Coastguard Worker 	if (*path == '\0')
106*6a54128fSAndroid Build Coastguard Worker 		strcpy(path,"/");
107*6a54128fSAndroid Build Coastguard Worker 	p = path + strlen(path) - 1;
108*6a54128fSAndroid Build Coastguard Worker 	if (p != path && *p == '/')
109*6a54128fSAndroid Build Coastguard Worker 		*p-- = '\0';	/* remove tmp trailing slash */
110*6a54128fSAndroid Build Coastguard Worker 	while (p != path && *p == '/') {	/* remove any others */
111*6a54128fSAndroid Build Coastguard Worker 		*p-- = '\0';
112*6a54128fSAndroid Build Coastguard Worker 		tidied = 1;
113*6a54128fSAndroid Build Coastguard Worker 	}
114*6a54128fSAndroid Build Coastguard Worker 	while (!strncmp(path,"./",2)) {
115*6a54128fSAndroid Build Coastguard Worker 		for (p = path, s = path+2; (*p++ = *s++););
116*6a54128fSAndroid Build Coastguard Worker 		tidied = 1;
117*6a54128fSAndroid Build Coastguard Worker 	}
118*6a54128fSAndroid Build Coastguard Worker 	return tidied;
119*6a54128fSAndroid Build Coastguard Worker }
120*6a54128fSAndroid Build Coastguard Worker 
shorten_path(char * path,char * abspath)121*6a54128fSAndroid Build Coastguard Worker static int shorten_path (char *path, char *abspath)
122*6a54128fSAndroid Build Coastguard Worker {
123*6a54128fSAndroid Build Coastguard Worker 	static char dir[PATH_MAX];
124*6a54128fSAndroid Build Coastguard Worker 	int shortened = 0;
125*6a54128fSAndroid Build Coastguard Worker 	char *p;
126*6a54128fSAndroid Build Coastguard Worker 
127*6a54128fSAndroid Build Coastguard Worker 	/* get rid of unnecessary "../dir" sequences */
128*6a54128fSAndroid Build Coastguard Worker 	while (abspath && strlen(abspath) > 1 && (p = strstr(path,"../"))) {
129*6a54128fSAndroid Build Coastguard Worker 		/* find innermost occurrence of "../dir", and save "dir" */
130*6a54128fSAndroid Build Coastguard Worker 		int slashes = 2;
131*6a54128fSAndroid Build Coastguard Worker 		char *a, *s, *d = dir;
132*6a54128fSAndroid Build Coastguard Worker 		while ((s = strstr(p+3, "../"))) {
133*6a54128fSAndroid Build Coastguard Worker 			++slashes;
134*6a54128fSAndroid Build Coastguard Worker 			p = s;
135*6a54128fSAndroid Build Coastguard Worker 		}
136*6a54128fSAndroid Build Coastguard Worker 		s = p+3;
137*6a54128fSAndroid Build Coastguard Worker 		*d++ = '/';
138*6a54128fSAndroid Build Coastguard Worker 		while (*s && *s != '/')
139*6a54128fSAndroid Build Coastguard Worker 			*d++ = *s++;
140*6a54128fSAndroid Build Coastguard Worker 		*d++ = '/';
141*6a54128fSAndroid Build Coastguard Worker 		*d = '\0';
142*6a54128fSAndroid Build Coastguard Worker 		if (!strcmp(dir,"//"))
143*6a54128fSAndroid Build Coastguard Worker 			break;
144*6a54128fSAndroid Build Coastguard Worker 		/* note: p still points at ../dir */
145*6a54128fSAndroid Build Coastguard Worker 		if (*s != '/' || !*++s)
146*6a54128fSAndroid Build Coastguard Worker 			break;
147*6a54128fSAndroid Build Coastguard Worker 		a = abspath + strlen(abspath) - 1;
148*6a54128fSAndroid Build Coastguard Worker 		while (slashes-- > 0) {
149*6a54128fSAndroid Build Coastguard Worker 			if (a <= abspath)
150*6a54128fSAndroid Build Coastguard Worker 				goto ughh;
151*6a54128fSAndroid Build Coastguard Worker 			while (*--a != '/') {
152*6a54128fSAndroid Build Coastguard Worker 				if (a <= abspath)
153*6a54128fSAndroid Build Coastguard Worker 					goto ughh;
154*6a54128fSAndroid Build Coastguard Worker 			}
155*6a54128fSAndroid Build Coastguard Worker 		}
156*6a54128fSAndroid Build Coastguard Worker 		if (strncmp(dir, a, strlen(dir)))
157*6a54128fSAndroid Build Coastguard Worker 			break;
158*6a54128fSAndroid Build Coastguard Worker 		while ((*p++ = *s++)); /* delete the ../dir */
159*6a54128fSAndroid Build Coastguard Worker 		shortened = 1;
160*6a54128fSAndroid Build Coastguard Worker 	}
161*6a54128fSAndroid Build Coastguard Worker ughh:
162*6a54128fSAndroid Build Coastguard Worker 	return shortened;
163*6a54128fSAndroid Build Coastguard Worker }
164*6a54128fSAndroid Build Coastguard Worker 
165*6a54128fSAndroid Build Coastguard Worker 
fix_symlink(char * path,dev_t my_dev)166*6a54128fSAndroid Build Coastguard Worker static void fix_symlink (char *path, dev_t my_dev)
167*6a54128fSAndroid Build Coastguard Worker {
168*6a54128fSAndroid Build Coastguard Worker 	static char lpath[PATH_MAX], new[PATH_MAX], abspath[PATH_MAX];
169*6a54128fSAndroid Build Coastguard Worker 	char *p, *np, *lp, *tail, *msg;
170*6a54128fSAndroid Build Coastguard Worker 	struct stat stbuf, lstbuf;
171*6a54128fSAndroid Build Coastguard Worker 	int c, fix_abs = 0, fix_messy = 0, fix_long = 0;
172*6a54128fSAndroid Build Coastguard Worker 
173*6a54128fSAndroid Build Coastguard Worker 	if ((c = readlink(path, lpath, sizeof(lpath) - 1)) == -1) {
174*6a54128fSAndroid Build Coastguard Worker 		perror(path);
175*6a54128fSAndroid Build Coastguard Worker 		return;
176*6a54128fSAndroid Build Coastguard Worker 	}
177*6a54128fSAndroid Build Coastguard Worker 	lpath[c] = '\0';	/* readlink does not null terminate it */
178*6a54128fSAndroid Build Coastguard Worker 
179*6a54128fSAndroid Build Coastguard Worker 	/* construct the absolute address of the link */
180*6a54128fSAndroid Build Coastguard Worker 	abspath[0] = '\0';
181*6a54128fSAndroid Build Coastguard Worker 	if (lpath[0] != '/') {
182*6a54128fSAndroid Build Coastguard Worker 		strcat(abspath,path);
183*6a54128fSAndroid Build Coastguard Worker 		c = strlen(abspath);
184*6a54128fSAndroid Build Coastguard Worker 		if ((c > 0) && (abspath[c-1] == '/'))
185*6a54128fSAndroid Build Coastguard Worker 			abspath[c-1] = '\0'; /* cut trailing / */
186*6a54128fSAndroid Build Coastguard Worker 		if ((p = strrchr(abspath,'/')) != NULL)
187*6a54128fSAndroid Build Coastguard Worker 			*p = '\0'; /* cut last component */
188*6a54128fSAndroid Build Coastguard Worker 		strcat(abspath,"/");
189*6a54128fSAndroid Build Coastguard Worker 	}
190*6a54128fSAndroid Build Coastguard Worker 	strcat(abspath,lpath);
191*6a54128fSAndroid Build Coastguard Worker 	(void) tidy_path(abspath);
192*6a54128fSAndroid Build Coastguard Worker 
193*6a54128fSAndroid Build Coastguard Worker 	/* check for various things */
194*6a54128fSAndroid Build Coastguard Worker 	if (stat(abspath, &stbuf) == -1) {
195*6a54128fSAndroid Build Coastguard Worker 		printf("dangling: %s -> %s\n", path, lpath);
196*6a54128fSAndroid Build Coastguard Worker 		if (delete) {
197*6a54128fSAndroid Build Coastguard Worker 			if (unlink (path)) {
198*6a54128fSAndroid Build Coastguard Worker 				perror(path);
199*6a54128fSAndroid Build Coastguard Worker 			} else
200*6a54128fSAndroid Build Coastguard Worker 				printf("deleted:  %s -> %s\n", path, lpath);
201*6a54128fSAndroid Build Coastguard Worker 		}
202*6a54128fSAndroid Build Coastguard Worker 		return;
203*6a54128fSAndroid Build Coastguard Worker 	}
204*6a54128fSAndroid Build Coastguard Worker 
205*6a54128fSAndroid Build Coastguard Worker 	if (single_fs)
206*6a54128fSAndroid Build Coastguard Worker 		lstat(abspath, &lstbuf); /* if the above didn't fail, then this shouldn't */
207*6a54128fSAndroid Build Coastguard Worker 
208*6a54128fSAndroid Build Coastguard Worker 	if (single_fs && lstbuf.st_dev != my_dev) {
209*6a54128fSAndroid Build Coastguard Worker 		msg = "other_fs:";
210*6a54128fSAndroid Build Coastguard Worker 	} else if (lpath[0] == '/') {
211*6a54128fSAndroid Build Coastguard Worker 		msg = "absolute:";
212*6a54128fSAndroid Build Coastguard Worker 		fix_abs = 1;
213*6a54128fSAndroid Build Coastguard Worker 	} else if (verbose) {
214*6a54128fSAndroid Build Coastguard Worker 		msg = "relative:";
215*6a54128fSAndroid Build Coastguard Worker 	} else
216*6a54128fSAndroid Build Coastguard Worker 		msg = NULL;
217*6a54128fSAndroid Build Coastguard Worker 	fix_messy = tidy_path(strcpy(new,lpath));
218*6a54128fSAndroid Build Coastguard Worker 	if (shorten)
219*6a54128fSAndroid Build Coastguard Worker 		fix_long = shorten_path(new, path);
220*6a54128fSAndroid Build Coastguard Worker 	if (!fix_abs) {
221*6a54128fSAndroid Build Coastguard Worker 		if (fix_messy)
222*6a54128fSAndroid Build Coastguard Worker 			msg = "messy:   ";
223*6a54128fSAndroid Build Coastguard Worker 		else if (fix_long)
224*6a54128fSAndroid Build Coastguard Worker 			msg = "lengthy: ";
225*6a54128fSAndroid Build Coastguard Worker 	}
226*6a54128fSAndroid Build Coastguard Worker 	if (msg != NULL)
227*6a54128fSAndroid Build Coastguard Worker 		printf("%s %s -> %s\n", msg, path, lpath);
228*6a54128fSAndroid Build Coastguard Worker 	if (!(fix_links || testing) || !(fix_messy || fix_abs || fix_long))
229*6a54128fSAndroid Build Coastguard Worker 		return;
230*6a54128fSAndroid Build Coastguard Worker 
231*6a54128fSAndroid Build Coastguard Worker 	if (fix_abs) {
232*6a54128fSAndroid Build Coastguard Worker 		/* convert an absolute link to relative: */
233*6a54128fSAndroid Build Coastguard Worker 		/* point tail at first part of lpath that differs from path */
234*6a54128fSAndroid Build Coastguard Worker 		/* point p    at first part of path  that differs from lpath */
235*6a54128fSAndroid Build Coastguard Worker 		(void) tidy_path(lpath);
236*6a54128fSAndroid Build Coastguard Worker 		tail = lp = lpath;
237*6a54128fSAndroid Build Coastguard Worker 		p = path;
238*6a54128fSAndroid Build Coastguard Worker 		while (*p && (*p == *lp)) {
239*6a54128fSAndroid Build Coastguard Worker 			if (*lp++ == '/') {
240*6a54128fSAndroid Build Coastguard Worker 				tail = lp;
241*6a54128fSAndroid Build Coastguard Worker 				while (*++p == '/');
242*6a54128fSAndroid Build Coastguard Worker 			}
243*6a54128fSAndroid Build Coastguard Worker 		}
244*6a54128fSAndroid Build Coastguard Worker 
245*6a54128fSAndroid Build Coastguard Worker 		/* now create new, with "../"s followed by tail */
246*6a54128fSAndroid Build Coastguard Worker 		np = new;
247*6a54128fSAndroid Build Coastguard Worker 		while (*p) {
248*6a54128fSAndroid Build Coastguard Worker 			if (*p++ == '/') {
249*6a54128fSAndroid Build Coastguard Worker 				*np++ = '.';
250*6a54128fSAndroid Build Coastguard Worker 				*np++ = '.';
251*6a54128fSAndroid Build Coastguard Worker 				*np++ = '/';
252*6a54128fSAndroid Build Coastguard Worker 				while (*p == '/') ++p;
253*6a54128fSAndroid Build Coastguard Worker 			}
254*6a54128fSAndroid Build Coastguard Worker 		}
255*6a54128fSAndroid Build Coastguard Worker 		strcpy (np, tail);
256*6a54128fSAndroid Build Coastguard Worker 		(void) tidy_path(new);
257*6a54128fSAndroid Build Coastguard Worker 		if (shorten) (void) shorten_path(new, path);
258*6a54128fSAndroid Build Coastguard Worker 	}
259*6a54128fSAndroid Build Coastguard Worker 	shorten_path(new,path);
260*6a54128fSAndroid Build Coastguard Worker 	if (!testing) {
261*6a54128fSAndroid Build Coastguard Worker 		if (unlink (path)) {
262*6a54128fSAndroid Build Coastguard Worker 			perror(path);
263*6a54128fSAndroid Build Coastguard Worker 			return;
264*6a54128fSAndroid Build Coastguard Worker 		}
265*6a54128fSAndroid Build Coastguard Worker 		if (symlink(new, path)) {
266*6a54128fSAndroid Build Coastguard Worker 			perror(path);
267*6a54128fSAndroid Build Coastguard Worker 			return;
268*6a54128fSAndroid Build Coastguard Worker 		}
269*6a54128fSAndroid Build Coastguard Worker 	}
270*6a54128fSAndroid Build Coastguard Worker 	printf("changed:  %s -> %s\n", path, new);
271*6a54128fSAndroid Build Coastguard Worker }
272*6a54128fSAndroid Build Coastguard Worker 
dirwalk(char * path,int pathlen,dev_t dev)273*6a54128fSAndroid Build Coastguard Worker static void dirwalk (char *path, int pathlen, dev_t dev)
274*6a54128fSAndroid Build Coastguard Worker {
275*6a54128fSAndroid Build Coastguard Worker  	char *name;
276*6a54128fSAndroid Build Coastguard Worker 	DIR *dfd;
277*6a54128fSAndroid Build Coastguard Worker 	static struct stat st;
278*6a54128fSAndroid Build Coastguard Worker 	static struct dirent *dp;
279*6a54128fSAndroid Build Coastguard Worker 
280*6a54128fSAndroid Build Coastguard Worker 	if ((dfd = opendir(path)) == NULL) {
281*6a54128fSAndroid Build Coastguard Worker 		perror(path);
282*6a54128fSAndroid Build Coastguard Worker 		return;
283*6a54128fSAndroid Build Coastguard Worker 	}
284*6a54128fSAndroid Build Coastguard Worker 
285*6a54128fSAndroid Build Coastguard Worker 	name = path + pathlen;
286*6a54128fSAndroid Build Coastguard Worker 	if (*(name-1) != '/')
287*6a54128fSAndroid Build Coastguard Worker 		*name++ = '/';
288*6a54128fSAndroid Build Coastguard Worker 
289*6a54128fSAndroid Build Coastguard Worker 	while ((dp = readdir(dfd)) != NULL ) {
290*6a54128fSAndroid Build Coastguard Worker 		strcpy(name, dp->d_name);
291*6a54128fSAndroid Build Coastguard Worker                 if (strcmp(name, ".") && strcmp(name,"..")) {
292*6a54128fSAndroid Build Coastguard Worker 			if (lstat(path, &st) == -1) {
293*6a54128fSAndroid Build Coastguard Worker 				perror(path);
294*6a54128fSAndroid Build Coastguard Worker 			} else if (st.st_dev == dev) {
295*6a54128fSAndroid Build Coastguard Worker 				if (S_ISLNK(st.st_mode)) {
296*6a54128fSAndroid Build Coastguard Worker 					fix_symlink (path, dev);
297*6a54128fSAndroid Build Coastguard Worker 				} else if (recurse && S_ISDIR(st.st_mode)) {
298*6a54128fSAndroid Build Coastguard Worker 					dirwalk(path, strlen(path), dev);
299*6a54128fSAndroid Build Coastguard Worker 				}
300*6a54128fSAndroid Build Coastguard Worker 			}
301*6a54128fSAndroid Build Coastguard Worker 		}
302*6a54128fSAndroid Build Coastguard Worker 	}
303*6a54128fSAndroid Build Coastguard Worker 	closedir(dfd);
304*6a54128fSAndroid Build Coastguard Worker 	path[pathlen] = '\0';
305*6a54128fSAndroid Build Coastguard Worker }
306*6a54128fSAndroid Build Coastguard Worker 
usage_error(void)307*6a54128fSAndroid Build Coastguard Worker static void usage_error (void)
308*6a54128fSAndroid Build Coastguard Worker {
309*6a54128fSAndroid Build Coastguard Worker 	fprintf(stderr, progver, progname);
310*6a54128fSAndroid Build Coastguard Worker 	fprintf(stderr, "Usage:\t%s [-cdorstv] LINK|DIR ...\n\n", progname);
311*6a54128fSAndroid Build Coastguard Worker 	fprintf(stderr, "Flags:"
312*6a54128fSAndroid Build Coastguard Worker 		"\t-c == change absolute/messy links to relative\n"
313*6a54128fSAndroid Build Coastguard Worker 		"\t-d == delete dangling links\n"
314*6a54128fSAndroid Build Coastguard Worker 		"\t-o == warn about links across file systems\n"
315*6a54128fSAndroid Build Coastguard Worker 		"\t-r == recurse into subdirs\n"
316*6a54128fSAndroid Build Coastguard Worker 		"\t-s == shorten lengthy links (displayed in output only when -c not specified)\n"
317*6a54128fSAndroid Build Coastguard Worker 		"\t-t == show what would be done by -c\n"
318*6a54128fSAndroid Build Coastguard Worker 		"\t-v == verbose (show all symlinks)\n\n");
319*6a54128fSAndroid Build Coastguard Worker 	exit(1);
320*6a54128fSAndroid Build Coastguard Worker }
321*6a54128fSAndroid Build Coastguard Worker 
main(int argc,char ** argv)322*6a54128fSAndroid Build Coastguard Worker int main(int argc, char **argv)
323*6a54128fSAndroid Build Coastguard Worker {
324*6a54128fSAndroid Build Coastguard Worker #if defined (_GNU_SOURCE) && defined (__GLIBC__)
325*6a54128fSAndroid Build Coastguard Worker 	static char path[PATH_MAX+2];
326*6a54128fSAndroid Build Coastguard Worker 	char* cwd = get_current_dir_name();
327*6a54128fSAndroid Build Coastguard Worker #else
328*6a54128fSAndroid Build Coastguard Worker 	static char path[PATH_MAX+2], cwd[PATH_MAX+2];
329*6a54128fSAndroid Build Coastguard Worker #endif
330*6a54128fSAndroid Build Coastguard Worker 	int dircount = 0;
331*6a54128fSAndroid Build Coastguard Worker 	char c, *p;
332*6a54128fSAndroid Build Coastguard Worker 
333*6a54128fSAndroid Build Coastguard Worker 	if  ((progname = (char *) strrchr(*argv, '/')) == NULL)
334*6a54128fSAndroid Build Coastguard Worker                 progname = *argv;
335*6a54128fSAndroid Build Coastguard Worker         else
336*6a54128fSAndroid Build Coastguard Worker                 progname++;
337*6a54128fSAndroid Build Coastguard Worker 
338*6a54128fSAndroid Build Coastguard Worker #if defined (_GNU_SOURCE) && defined (__GLIBC__)
339*6a54128fSAndroid Build Coastguard Worker 	if (NULL == cwd) {
340*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr,"get_current_dir_name() failed\n");
341*6a54128fSAndroid Build Coastguard Worker #else
342*6a54128fSAndroid Build Coastguard Worker 	if (NULL == getcwd(cwd,PATH_MAX)) {
343*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr,"getcwd() failed\n");
344*6a54128fSAndroid Build Coastguard Worker #endif
345*6a54128fSAndroid Build Coastguard Worker 		exit (1);
346*6a54128fSAndroid Build Coastguard Worker 	}
347*6a54128fSAndroid Build Coastguard Worker #if defined (_GNU_SOURCE) && defined (__GLIBC__)
348*6a54128fSAndroid Build Coastguard Worker 	cwd = realloc(cwd, strlen(cwd)+2);
349*6a54128fSAndroid Build Coastguard Worker 	if (cwd == NULL) {
350*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "realloc() failed\n");
351*6a54128fSAndroid Build Coastguard Worker 		exit (1);
352*6a54128fSAndroid Build Coastguard Worker 	}
353*6a54128fSAndroid Build Coastguard Worker #endif
354*6a54128fSAndroid Build Coastguard Worker 	if (!*cwd || cwd[strlen(cwd)-1] != '/')
355*6a54128fSAndroid Build Coastguard Worker 		strcat(cwd,"/");
356*6a54128fSAndroid Build Coastguard Worker 
357*6a54128fSAndroid Build Coastguard Worker 	while (--argc) {
358*6a54128fSAndroid Build Coastguard Worker 		p = *++argv;
359*6a54128fSAndroid Build Coastguard Worker 		if (*p == '-') {
360*6a54128fSAndroid Build Coastguard Worker 			if (*++p == '\0')
361*6a54128fSAndroid Build Coastguard Worker 				usage_error();
362*6a54128fSAndroid Build Coastguard Worker 			while ((c = *p++)) {
363*6a54128fSAndroid Build Coastguard Worker 				     if (c == 'c')	fix_links = 1;
364*6a54128fSAndroid Build Coastguard Worker 				else if (c == 'd')	delete    = 1;
365*6a54128fSAndroid Build Coastguard Worker 				else if (c == 'o')	single_fs = 0;
366*6a54128fSAndroid Build Coastguard Worker 				else if (c == 'r')	recurse   = 1;
367*6a54128fSAndroid Build Coastguard Worker 				else if (c == 's')	shorten   = 1;
368*6a54128fSAndroid Build Coastguard Worker 				else if (c == 't')	testing   = 1;
369*6a54128fSAndroid Build Coastguard Worker 				else if (c == 'v')	verbose   = 1;
370*6a54128fSAndroid Build Coastguard Worker 				else			usage_error();
371*6a54128fSAndroid Build Coastguard Worker 			}
372*6a54128fSAndroid Build Coastguard Worker 		} else {
373*6a54128fSAndroid Build Coastguard Worker 			struct stat st;
374*6a54128fSAndroid Build Coastguard Worker 			if (*p == '/')
375*6a54128fSAndroid Build Coastguard Worker 				*path = '\0';
376*6a54128fSAndroid Build Coastguard Worker 			else
377*6a54128fSAndroid Build Coastguard Worker 				strcpy(path,cwd);
378*6a54128fSAndroid Build Coastguard Worker 			tidy_path(strcat(path, p));
379*6a54128fSAndroid Build Coastguard Worker 			if (lstat(path, &st) == -1)
380*6a54128fSAndroid Build Coastguard Worker 				perror(path);
381*6a54128fSAndroid Build Coastguard Worker 			else if (S_ISLNK(st.st_mode))
382*6a54128fSAndroid Build Coastguard Worker 				fix_symlink(path, st.st_dev);
383*6a54128fSAndroid Build Coastguard Worker 			else
384*6a54128fSAndroid Build Coastguard Worker 				dirwalk(path, strlen(path), st.st_dev);
385*6a54128fSAndroid Build Coastguard Worker 			++dircount;
386*6a54128fSAndroid Build Coastguard Worker 		}
387*6a54128fSAndroid Build Coastguard Worker 	}
388*6a54128fSAndroid Build Coastguard Worker 	if (dircount == 0)
389*6a54128fSAndroid Build Coastguard Worker 		usage_error();
390*6a54128fSAndroid Build Coastguard Worker 	exit (0);
391*6a54128fSAndroid Build Coastguard Worker }
392