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