symlinks-1.4/0000755000000000000000000000000011263641727011736 5ustar rootrootsymlinks-1.4/Makefile0000644000000000000000000000050011263640601013357 0ustar rootroot# Makefile for symlinks CC = gcc all: symlinks symlinks: symlinks.c $(CC) -Wall -Wstrict-prototypes -O2 ${CFLAGS} -o symlinks symlinks.c install: all symlinks.8 install -m 755 -o root -g root symlinks /usr/local/bin install -m 644 -o root -g root symlinks.8 /usr/local/man/man8 clean: rm -f symlinks *.o core symlinks-1.4/symlinks.c0000644000000000000000000001730111263641313013744 0ustar rootroot#include #ifndef _POSIX_SOURCE #define _POSIX_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifndef S_ISLNK #define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK)) #endif #ifndef PATH_MAX #define PATH_MAX 1024 #endif #define progver "%s: scan/change symbolic links - v1.3 - by Mark Lord\n\n" static char *progname; static int verbose = 0, fix_links = 0, recurse = 0, delete = 0, shorten = 0, testing = 0, single_fs = 1; /* * tidypath removes excess slashes and "." references from a path string */ static int substr (char *s, char *old, char *new) { char *tmp = NULL; int oldlen = strlen(old), newlen = 0; if (NULL == strstr(s, old)) return 0; if (new) newlen = strlen(new); if (newlen > oldlen) { if ((tmp = malloc(strlen(s))) == NULL) { fprintf(stderr, "no memory\n"); exit (1); } } while (NULL != (s = strstr(s, old))) { char *p, *old_s = s; if (new) { if (newlen > oldlen) old_s = strcpy(tmp, s); p = new; while (*p) *s++ = *p++; } p = old_s + oldlen; while ((*s++ = *p++)); } if (tmp) free(tmp); return 1; } static int tidy_path (char *path) { int tidied = 0; char *s, *p; s = path + strlen(path) - 1; if (s[0] != '/') { /* tmp trailing slash simplifies things */ s[1] = '/'; s[2] = '\0'; } while (substr(path, "/./", "/")) tidied = 1; while (substr(path, "//", "/")) tidied = 1; while ((p = strstr(path,"/../")) != NULL) { s = p+3; for (p--; p != path; p--) if (*p == '/') break; if (*p != '/') break; while ((*p++ = *s++)); tidied = 1; } if (*path == '\0') strcpy(path,"/"); p = path + strlen(path) - 1; if (p != path && *p == '/') *p-- = '\0'; /* remove tmp trailing slash */ while (p != path && *p == '/') { /* remove any others */ *p-- = '\0'; tidied = 1; } while (!strncmp(path,"./",2)) { for (p = path, s = path+2; (*p++ = *s++);); tidied = 1; } return tidied; } static int shorten_path (char *path, char *abspath) { static char dir[PATH_MAX]; int shortened = 0; char *p; /* get rid of unnecessary "../dir" sequences */ while (abspath && strlen(abspath) > 1 && (p = strstr(path,"../"))) { /* find innermost occurance of "../dir", and save "dir" */ int slashes = 2; char *a, *s, *d = dir; while ((s = strstr(p+3, "../"))) { ++slashes; p = s; } s = p+3; *d++ = '/'; while (*s && *s != '/') *d++ = *s++; *d++ = '/'; *d = '\0'; if (!strcmp(dir,"//")) break; /* note: p still points at ../dir */ if (*s != '/' || !*++s) break; a = abspath + strlen(abspath) - 1; while (slashes-- > 0) { if (a <= abspath) goto ughh; while (*--a != '/') { if (a <= abspath) goto ughh; } } if (strncmp(dir, a, strlen(dir))) break; while ((*p++ = *s++)); /* delete the ../dir */ shortened = 1; } ughh: return shortened; } static void fix_symlink (char *path, dev_t my_dev) { static char lpath[PATH_MAX], new[PATH_MAX], abspath[PATH_MAX]; char *p, *np, *lp, *tail, *msg; struct stat stbuf, lstbuf; int c, fix_abs = 0, fix_messy = 0, fix_long = 0; if ((c = readlink(path, lpath, sizeof(lpath))) == -1) { perror(path); return; } lpath[c] = '\0'; /* readlink does not null terminate it */ /* construct the absolute address of the link */ abspath[0] = '\0'; if (lpath[0] != '/') { strcat(abspath,path); c = strlen(abspath); if ((c > 0) && (abspath[c-1] == '/')) abspath[c-1] = '\0'; /* cut trailing / */ if ((p = strrchr(abspath,'/')) != NULL) *p = '\0'; /* cut last component */ strcat(abspath,"/"); } strcat(abspath,lpath); (void) tidy_path(abspath); /* check for various things */ if (stat(abspath, &stbuf) == -1) { printf("dangling: %s -> %s\n", path, lpath); if (delete) { if (unlink (path)) { perror(path); } else printf("deleted: %s -> %s\n", path, lpath); } return; } if (single_fs) lstat(abspath, &lstbuf); /* if the above didn't fail, then this shouldn't */ if (single_fs && lstbuf.st_dev != my_dev) { msg = "other_fs:"; } else if (lpath[0] == '/') { msg = "absolute:"; fix_abs = 1; } else if (verbose) { msg = "relative:"; } else msg = NULL; fix_messy = tidy_path(strcpy(new,lpath)); if (shorten) fix_long = shorten_path(new, path); if (!fix_abs) { if (fix_messy) msg = "messy: "; else if (fix_long) msg = "lengthy: "; } if (msg != NULL) printf("%s %s -> %s\n", msg, path, lpath); if (!(fix_links || testing) || !(fix_messy || fix_abs || fix_long)) return; if (fix_abs) { /* convert an absolute link to relative: */ /* point tail at first part of lpath that differs from path */ /* point p at first part of path that differs from lpath */ (void) tidy_path(lpath); tail = lp = lpath; p = path; while (*p && (*p == *lp)) { if (*lp++ == '/') { tail = lp; while (*++p == '/'); } } /* now create new, with "../"s followed by tail */ np = new; while (*p) { if (*p++ == '/') { *np++ = '.'; *np++ = '.'; *np++ = '/'; while (*p == '/') ++p; } } strcpy (np, tail); (void) tidy_path(new); if (shorten) (void) shorten_path(new, path); } shorten_path(new,path); if (!testing) { if (unlink (path)) { perror(path); return; } if (symlink(new, path)) { perror(path); return; } } printf("changed: %s -> %s\n", path, new); } static void dirwalk (char *path, int pathlen, dev_t dev) { char *name; DIR *dfd; static struct stat st; static struct dirent *dp; if ((dfd = opendir(path)) == NULL) { perror(path); return; } name = path + pathlen; if (*(name-1) != '/') *name++ = '/'; while ((dp = readdir(dfd)) != NULL ) { strcpy(name, dp->d_name); if (strcmp(name, ".") && strcmp(name,"..")) { if (lstat(path, &st) == -1) { perror(path); } else if (st.st_dev == dev) { if (S_ISLNK(st.st_mode)) { fix_symlink (path, dev); } else if (recurse && S_ISDIR(st.st_mode)) { dirwalk(path, strlen(path), dev); } } } } closedir(dfd); path[pathlen] = '\0'; } static void usage_error (void) { fprintf(stderr, progver, progname); fprintf(stderr, "Usage:\t%s [-cdorstv] dirlist\n\n", progname); fprintf(stderr, "Flags:" "\t-c == change absolute/messy links to relative\n" "\t-d == delete dangling links\n" "\t-o == warn about links across file systems\n" "\t-r == recurse into subdirs\n" "\t-s == shorten lengthy links (displayed in output only when -c not specified)\n" "\t-t == show what would be done by -c\n" "\t-v == verbose (show all symlinks)\n\n"); exit(1); } int main(int argc, char **argv) { static char path[PATH_MAX+2], cwd[PATH_MAX+2]; int dircount = 0; char c, *p; if ((progname = (char *) strrchr(*argv, '/')) == NULL) progname = *argv; else progname++; if (NULL == getcwd(cwd,PATH_MAX)) { fprintf(stderr,"getcwd() failed\n"); exit (1); } if (!*cwd || cwd[strlen(cwd)-1] != '/') strcat(cwd,"/"); while (--argc) { p = *++argv; if (*p == '-') { if (*++p == '\0') usage_error(); while ((c = *p++)) { if (c == 'c') fix_links = 1; else if (c == 'd') delete = 1; else if (c == 'o') single_fs = 0; else if (c == 'r') recurse = 1; else if (c == 's') shorten = 1; else if (c == 't') testing = 1; else if (c == 'v') verbose = 1; else usage_error(); } } else { struct stat st; if (*p == '/') *path = '\0'; else strcpy(path,cwd); tidy_path(strcat(path, p)); if (lstat(path, &st) == -1) perror(path); else dirwalk(path, strlen(path), st.st_dev); ++dircount; } } if (dircount == 0) usage_error(); exit (0); } symlinks-1.4/symlinks.80000644000000200000020000000553311263641455013262 0ustar binbin.TH SYMLINKS 8 "October 2008" "Version 1.4" .SH NAME symlinks \- symbolic link maintenance utility .SH SYNOPSIS .B symlinks [ .B -cdorstv ] dirlist .SH DESCRIPTION .BI symlinks is a useful utility for maintainers of FTP sites, CDROMs, and Linux software distributions. It scans directories for symbolic links and lists them on stdout, often revealing flaws in the filesystem tree. .PP Each link is output with a classification of .B relative, .B absolute, .B dangling, .B messy, .B lengthy, or .B other_fs. .PP .B relative links are those expressed as paths relative to the directory in which the links reside, usually independent of the mount point of the filesystem. .PP .B absolute links are those given as an absolute path from the root directory as indicated by a leading slash (/). .PP .B dangling links are those for which the target of the link does not currently exist. This commonly occurs for .B absolute links when a filesystem is mounted at other than its customary mount point (such as when the normal root filesystem is mounted at /mnt after booting from alternative media). .PP .B messy links are links which contain unnecessary slashes or dots in the path. These are cleaned up as well when .B -c is specified. .PP .B lengthy links are links which use "../" more than necessary in the path (eg. /bin/vi -> ../bin/vim) These are only detected when .B -s is specified, and are only cleaned up when .B -c is also specified. .PP .B other_fs are those links whose target currently resides on a different filesystem from where symlinks was run (most useful with .B -r ). .PP .SH OPTIONS .TP .I -c convert absolute links (within the same filesystem) to relative links. This permits links to maintain their validity regardless of the mount point used for the filesystem -- a desirable setup in most cases. This option also causes any .B messy links to be cleaned up, and, if .B -s was also specified, then .B lengthy links are also shortened. Links affected by .B -c are prefixed with .B changed in the output. .TP .I -d causes .B dangling links to be removed. .TP .I -o fix links on other filesystems encountered while recursing. Normally, other filesystems encountered are not modified by symlinks. .TP .I -r recursively operate on subdirectories within the same filesystem. .TP .I -s causes .B lengthy links to be detected. .TP .I -t is used to test for what .B symlinks would do if .B -c were specified, but without really changing anything. .TP .I -v show all symbolic links. By default, .B relative links are not shown unless .B -v is specified. .PP .SH BUGS .B symlinks does not recurse or change links across filesystems. .PP .SH AUTHOR .B symlinks has been written by Mark Lord , the original developer and maintainer of the IDE Performance Package for linux, the Linux IDE Driver subsystem, hdparm, and a current day libata hacker. .SH SEE ALSO .BR symlink (2) symlinks-1.4/symlinks.lsm0000644000000000000000000000235611263641727014332 0ustar rootrootBegin2 Title =symlinks - scan/change symbolic links Version =1.4 Desc1 =Scans directories for symbolic links, and identifies dangling, Desc2 =relative, absolute, messy, and other_fs links. Can optionally Desc3 =change absolute links to relative within a given filesystem. Desc4 =Recommended for use by anyone developing and/or maintaining Desc5 =a Linux FTP site or distribution or CD-ROM. Author =Mark Lord AuthorEmail =mlord@pobox.com Maintainer =Mark Lord MaintEmail =mlord@pobox.com Site1 =tsx-11.mit.edu Path1 =/pub/linux/sources/usr.bin File1 =symlinks-1.4.tar.gz FileSize1 =5KB Required1 = Required2 = Required3 = Required4 = CopyPolicy1 =(c) Mark Lord, freely distributable CopyPolicy2 = Keywords =symbolic links cd cdrom CD-ROM distribution Comment1 =v1.4 incorporate patches from Fedora Comment1 =v1.3 more messy-link fixes, new -o flag for other_fs Comment2 =v1.2 added -s flag to shorten links with redundant Comment3 =path elements. Also includes code to remove excess Comment4 =slashes from paths. RelFiles1 = RelFiles2 = RelFiles3 = Entered =09OCT2009 EnteredBy =Mark Lord CheckedEmail =mlord@pobox.com End