diff options
Diffstat (limited to 'usr.bin/lndir')
-rw-r--r-- | usr.bin/lndir/Makefile | 5 | ||||
-rw-r--r-- | usr.bin/lndir/lndir.1 | 139 | ||||
-rw-r--r-- | usr.bin/lndir/lndir.c | 342 |
3 files changed, 486 insertions, 0 deletions
diff --git a/usr.bin/lndir/Makefile b/usr.bin/lndir/Makefile new file mode 100644 index 00000000000..acd7907dedb --- /dev/null +++ b/usr.bin/lndir/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 1996/08/19 05:47:25 downsj Exp $ + +PROG= lndir + +.include <bsd.prog.mk> diff --git a/usr.bin/lndir/lndir.1 b/usr.bin/lndir/lndir.1 new file mode 100644 index 00000000000..69be6d9b329 --- /dev/null +++ b/usr.bin/lndir/lndir.1 @@ -0,0 +1,139 @@ +.\" $OpenBSD: lndir.1,v 1.1 1996/08/19 05:47:26 downsj Exp $ +.\" $XConsortium: lndir.man /main/9 1995/12/15 14:00:35 gildea $ +.\" +.\" Copyright (c) 1993, 1994 X Consortium +.\" +.\" Permission is hereby granted, free of charge, to any person obtaining +.\" a copy of this software and associated documentation files (the +.\" "Software"), to deal in the Software without restriction, including +.\" without limitation the rights to use, copy, modify, merge, publish, +.\" distribute, sublicense, and/or sell copies of the Software, and to +.\" permit persons to whom the Software is furnished to do so, subject to +.\" the following conditions: +.\" +.\" The above copyright notice and this permission notice shall be +.\" included in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" Except as contained in this notice, the name of the X Consortium shall +.\" not be used in advertising or otherwise to promote the sale, use or +.\" other dealings in this Software without prior written authorization +.\" from the X Consortium. +.\" +.TH LNDIR 1 "" "OpenBSD" +.SH NAME +lndir \- create a shadow directory of symbolic links to another directory tree +.SH SYNOPSIS +.B lndir +[ +.B \-e +.I exceptfile +] +[ +.B \-s +] [ +.B \-i +] +.I \|fromdir\| +[ +.I todir +] +.SH DESCRIPTION +The +.I lndir +program makes a shadow copy +.I todir +of a directory tree +.I fromdir, +except that the shadow is not +populated with real files but instead with symbolic links pointing at +the real files in the +.I fromdir +directory tree. This is usually useful for maintaining source code for +different machine architectures. You create a shadow directory +containing links to the real source, which you will have usually +mounted from a remote machine. You can build in the shadow tree, and +the object files will be in the shadow directory, while the +source files in the shadow directory are just symlinks to the real +files. +.PP +This scheme has the advantage that if you update the source, you need not +propagate the change to the other architectures by hand, since all +source in all shadow directories are symlinks to the real thing: just cd +to the shadow directory and recompile away. +.PP +The +.I todir +argument is optional and defaults to the current directory. The +.I fromdir +argument may be relative (e.g., ../src) and is relative to +.I todir +(not the current directory). +.PP +.\" CVS.adm is used by the Concurrent Versions System. +Note that RCS, SCCS, CVS and CVS.adm directories are not shadowed, in +addition to any specified on the command line with \fB\-e\fP arguments. +.PP +If you add files, simply run +.I lndir +again. New files will be silently added. Old files will be +checked that they have the correct link. +.PP +Deleting files is a more painful problem; the symlinks will +just point into never never land. +.PP +If a file in \fIfromdir\fP is a symbolic link, \fIlndir\fP will make +the same link in \fItodir\fP rather than making a link back to the +(symbolic link) entry in \fIfromdir.\fP The \fB\-i\fP flag +changes this behavior. +.SH OPTIONS +.IP \-e +Add the specified file to the list of excluded files/directories. This is +effective in all directories searched by \fIlndir\fP. This option may be +specified as many times as needed. +.IP \-s +Normally \fIlndir\fP outputs the name of each subdirectory as it +descends into it. The \fB\-s\fP option suppresses these status +messages. +.IP \-i +Causes the program to not treat symbolic links in \fIfromdir\fP +specially. The link created in \fItodir\fP will point back to the +corresponding (symbolic link) file in \fIfromdir\fP. +If the link is to a directory, this is almost certainly the wrong thing. +.IP +This option exists mostly to emulate the behavior the C version of +\fIlndir\fP had in X11R6. Its use is not recommended. +.SH DIAGNOSTICS +The program displays the name of each subdirectory it enters, followed +by a colon. The \fB\-s\fP option suppresses these messages. +.PP +A warning message is displayed if the symbolic link cannot be created. +The usual problem is that a regular file of the same name already +exists. +.PP +If the link already exists but doesn't point to the correct file, the +program prints the link name and the location where it does point. +.SH BUGS +The +.I patch +program gets upset if it cannot change the files. You should never run +.I patch +from a shadow directory anyway. +.PP +You need to use something like +.nf + find todir \|\-type l \|\-print \||\| xargs rm +.fi +to clear out all files before you can relink (if fromdir moved, for instance). +Something like +.nf + find . \|\\! \|\-type d \|\-print +.fi +will find all files that are not directories. diff --git a/usr.bin/lndir/lndir.c b/usr.bin/lndir/lndir.c new file mode 100644 index 00000000000..cd54f378256 --- /dev/null +++ b/usr.bin/lndir/lndir.c @@ -0,0 +1,342 @@ +/* $OpenBSD: lndir.c,v 1.1 1996/08/19 05:47:26 downsj Exp $ */ +/* $XConsortium: lndir.c /main/15 1995/08/30 10:56:18 gildea $ */ +/* Create shadow link tree (after X11R4 script of the same name) + Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */ + +/* +Copyright (c) 1990, X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + +*/ + +/* From the original /bin/sh script: + + Used to create a copy of the a directory tree that has links for all + non-directories (except those named RCS, SCCS or CVS.adm). If you are + building the distribution on more than one machine, you should use + this technique. + + If your master sources are located in /usr/local/src/X and you would like + your link tree to be in /usr/local/src/new-X, do the following: + + % mkdir /usr/local/src/new-X + % cd /usr/local/src/new-X + % lndir ../X +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <errno.h> +#include <dirent.h> +#include <stdarg.h> +#include <string.h> + +int silent = 0; /* -silent */ +int ignore_links = 0; /* -ignorelinks */ + +char *rcurdir; +char *curdir; + +struct except { + char *name; + + struct except *next; +}; +struct except *exceptions = (struct except *)NULL; + +void +quit (int code, char * fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf (stderr, fmt, args); + va_end(args); + putc ('\n', stderr); + exit (code); +} + +void +quiterr (code, s) + char *s; +{ + perror (s); + exit (code); +} + +void +msg (char * fmt, ...) +{ + va_list args; + if (curdir) { + fprintf (stderr, "%s:\n", curdir); + curdir = 0; + } + va_start(args, fmt); + vfprintf (stderr, fmt, args); + va_end(args); + putc ('\n', stderr); +} + +void +mperror (s) + char *s; +{ + if (curdir) { + fprintf (stderr, "%s:\n", curdir); + curdir = 0; + } + perror (s); +} + + +int equivalent(lname, rname) + char *lname; + char *rname; +{ + char *s; + + if (!strcmp(lname, rname)) + return 1; + for (s = lname; *s && (s = strchr(s, '/')); s++) { + while (s[1] == '/') + strcpy(s+1, s+2); + } + return !strcmp(lname, rname); +} + + +addexcept(name) + char *name; +{ + struct except *new; + + new = (struct except *)malloc(sizeof(struct except)); + if (new == (struct except *)NULL) + quiterr(1, "addexcept"); + new->name = strdup(name); + if (new->name == (char *)NULL) + quiterr(1, "addexcept"); + + new->next = exceptions; + exceptions = new; +} + + +/* Recursively create symbolic links from the current directory to the "from" + directory. Assumes that files described by fs and ts are directories. */ + +dodir (fn, fs, ts, rel) +char *fn; /* name of "from" directory, either absolute or + relative to cwd */ +struct stat *fs, *ts; /* stats for the "from" directory and cwd */ +int rel; /* if true, prepend "../" to fn before using */ +{ + DIR *df; + struct dirent *dp; + char buf[MAXPATHLEN + 1], *p; + char symbuf[MAXPATHLEN + 1]; + char basesym[MAXPATHLEN + 1]; + struct stat sb, sc; + int n_dirs; + int symlen; + int basesymlen = -1; + char *ocurdir; + struct except *cur; + + if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) { + msg ("%s: From and to directories are identical!", fn); + return 1; + } + + if (rel) + strcpy (buf, "../"); + else + buf[0] = '\0'; + strcat (buf, fn); + + if (!(df = opendir (buf))) { + msg ("%s: Cannot opendir", buf); + return 1; + } + + p = buf + strlen (buf); + *p++ = '/'; + n_dirs = fs->st_nlink; + while (dp = readdir (df)) { + if (dp->d_name[strlen(dp->d_name) - 1] == '~') + continue; + strcpy (p, dp->d_name); + + if (n_dirs > 0) { + if (stat (buf, &sb) < 0) { + mperror (buf); + continue; + } + + if(S_ISDIR(sb.st_mode)) { + /* directory */ + n_dirs--; + if (dp->d_name[0] == '.' && + (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && + dp->d_name[2] == '\0'))) + continue; + for (cur = exceptions; cur != (struct except *)NULL; + cur = cur->next) { + if (!strcmp (dp->d_name, cur->name)) + goto next; /* can't continue */ + } + if (!strcmp (dp->d_name, "RCS")) + continue; + if (!strcmp (dp->d_name, "SCCS")) + continue; + if (!strcmp (dp->d_name, "CVS")) + continue; + if (!strcmp (dp->d_name, "CVS.adm")) + continue; + ocurdir = rcurdir; + rcurdir = buf; + curdir = silent ? buf : (char *)0; + if (!silent) + printf ("%s:\n", buf); + if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) { + if (mkdir (dp->d_name, 0777) < 0 || + stat (dp->d_name, &sc) < 0) { + mperror (dp->d_name); + curdir = rcurdir = ocurdir; + continue; + } + } + if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) { + msg ("%s: is a link instead of a directory", dp->d_name); + curdir = rcurdir = ocurdir; + continue; + } + if (chdir (dp->d_name) < 0) { + mperror (dp->d_name); + curdir = rcurdir = ocurdir; + continue; + } + dodir (buf, &sb, &sc, (buf[0] != '/')); + if (chdir ("..") < 0) + quiterr (1, ".."); + curdir = rcurdir = ocurdir; + continue; + } + } + + /* non-directory */ + symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1); + if (symlen >= 0) + symbuf[symlen] = '\0'; + + /* The option to ignore links exists mostly because + checking for them slows us down by 10-20%. + But it is off by default because this really is a useful check. */ + if (!ignore_links) { + /* see if the file in the base tree was a symlink */ + basesymlen = readlink(buf, basesym, sizeof(basesym) - 1); + if (basesymlen >= 0) + basesym[basesymlen] = '\0'; + } + + if (symlen >= 0) { + /* Link exists in new tree. Print message if it doesn't match. */ + if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf)) + msg ("%s: %s", dp->d_name, symbuf); + } else { + if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0) + mperror (dp->d_name); + } +next: + } + + closedir (df); + return 0; +} + + +main (ac, av) +int ac; +char **av; +{ + char *prog_name = av[0]; + char *fn, *tn; + struct stat fs, ts; + + while (++av, --ac) { + if ((strcmp(*av, "-silent") == 0) || (strcmp(*av, "-s") == 0)) + silent = 1; + else if ((strcmp(*av, "-ignorelinks") == 0) || (strcmp(*av, "-i") == 0)) + ignore_links = 1; + else if (strcmp(*av, "-e") == 0) { + ++av, --ac; + + if (ac < 2) + quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]", + prog_name); + addexcept(*av); + } + else if (strcmp(*av, "--") == 0) { + ++av, --ac; + break; + } + else + break; + } + + if (ac < 1 || ac > 2) + quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]", + prog_name); + + fn = av[0]; + if (ac == 2) + tn = av[1]; + else + tn = "."; + + /* to directory */ + if (stat (tn, &ts) < 0) + quiterr (1, tn); +#ifdef S_ISDIR + if (!(S_ISDIR(ts.st_mode))) +#else + if (!(ts.st_mode & S_IFDIR)) +#endif + quit (2, "%s: Not a directory", tn); + if (chdir (tn) < 0) + quiterr (1, tn); + + /* from directory */ + if (stat (fn, &fs) < 0) + quiterr (1, fn); +#ifdef S_ISDIR + if (!(S_ISDIR(fs.st_mode))) +#else + if (!(fs.st_mode & S_IFDIR)) +#endif + quit (2, "%s: Not a directory", fn); + + exit (dodir (fn, &fs, &ts, 0)); +} |