Annotation of src/usr.bin/lndir/lndir.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* $XConsortium: lndir.c /main/15 1995/08/30 10:56:18 gildea $ */
! 3: /* Create shadow link tree (after X11R4 script of the same name)
! 4: Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */
! 5:
! 6: /*
! 7: Copyright (c) 1990, X Consortium
! 8:
! 9: Permission is hereby granted, free of charge, to any person obtaining a copy
! 10: of this software and associated documentation files (the "Software"), to deal
! 11: in the Software without restriction, including without limitation the rights
! 12: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 13: copies of the Software, and to permit persons to whom the Software is
! 14: furnished to do so, subject to the following conditions:
! 15:
! 16: The above copyright notice and this permission notice shall be included in
! 17: all copies or substantial portions of the Software.
! 18:
! 19: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 20: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 21: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 22: X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
! 23: AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
! 24: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
! 25:
! 26: Except as contained in this notice, the name of the X Consortium shall not be
! 27: used in advertising or otherwise to promote the sale, use or other dealings
! 28: in this Software without prior written authorization from the X Consortium.
! 29:
! 30: */
! 31:
! 32: /* From the original /bin/sh script:
! 33:
! 34: Used to create a copy of the a directory tree that has links for all
! 35: non-directories (except those named RCS, SCCS or CVS.adm). If you are
! 36: building the distribution on more than one machine, you should use
! 37: this technique.
! 38:
! 39: If your master sources are located in /usr/local/src/X and you would like
! 40: your link tree to be in /usr/local/src/new-X, do the following:
! 41:
! 42: % mkdir /usr/local/src/new-X
! 43: % cd /usr/local/src/new-X
! 44: % lndir ../X
! 45: */
! 46:
! 47: #include <stdio.h>
! 48: #include <sys/types.h>
! 49: #include <sys/stat.h>
! 50: #include <sys/param.h>
! 51: #include <errno.h>
! 52: #include <dirent.h>
! 53: #include <stdarg.h>
! 54: #include <string.h>
! 55:
! 56: int silent = 0; /* -silent */
! 57: int ignore_links = 0; /* -ignorelinks */
! 58:
! 59: char *rcurdir;
! 60: char *curdir;
! 61:
! 62: struct except {
! 63: char *name;
! 64:
! 65: struct except *next;
! 66: };
! 67: struct except *exceptions = (struct except *)NULL;
! 68:
! 69: void
! 70: quit (int code, char * fmt, ...)
! 71: {
! 72: va_list args;
! 73: va_start(args, fmt);
! 74: vfprintf (stderr, fmt, args);
! 75: va_end(args);
! 76: putc ('\n', stderr);
! 77: exit (code);
! 78: }
! 79:
! 80: void
! 81: quiterr (code, s)
! 82: char *s;
! 83: {
! 84: perror (s);
! 85: exit (code);
! 86: }
! 87:
! 88: void
! 89: msg (char * fmt, ...)
! 90: {
! 91: va_list args;
! 92: if (curdir) {
! 93: fprintf (stderr, "%s:\n", curdir);
! 94: curdir = 0;
! 95: }
! 96: va_start(args, fmt);
! 97: vfprintf (stderr, fmt, args);
! 98: va_end(args);
! 99: putc ('\n', stderr);
! 100: }
! 101:
! 102: void
! 103: mperror (s)
! 104: char *s;
! 105: {
! 106: if (curdir) {
! 107: fprintf (stderr, "%s:\n", curdir);
! 108: curdir = 0;
! 109: }
! 110: perror (s);
! 111: }
! 112:
! 113:
! 114: int equivalent(lname, rname)
! 115: char *lname;
! 116: char *rname;
! 117: {
! 118: char *s;
! 119:
! 120: if (!strcmp(lname, rname))
! 121: return 1;
! 122: for (s = lname; *s && (s = strchr(s, '/')); s++) {
! 123: while (s[1] == '/')
! 124: strcpy(s+1, s+2);
! 125: }
! 126: return !strcmp(lname, rname);
! 127: }
! 128:
! 129:
! 130: addexcept(name)
! 131: char *name;
! 132: {
! 133: struct except *new;
! 134:
! 135: new = (struct except *)malloc(sizeof(struct except));
! 136: if (new == (struct except *)NULL)
! 137: quiterr(1, "addexcept");
! 138: new->name = strdup(name);
! 139: if (new->name == (char *)NULL)
! 140: quiterr(1, "addexcept");
! 141:
! 142: new->next = exceptions;
! 143: exceptions = new;
! 144: }
! 145:
! 146:
! 147: /* Recursively create symbolic links from the current directory to the "from"
! 148: directory. Assumes that files described by fs and ts are directories. */
! 149:
! 150: dodir (fn, fs, ts, rel)
! 151: char *fn; /* name of "from" directory, either absolute or
! 152: relative to cwd */
! 153: struct stat *fs, *ts; /* stats for the "from" directory and cwd */
! 154: int rel; /* if true, prepend "../" to fn before using */
! 155: {
! 156: DIR *df;
! 157: struct dirent *dp;
! 158: char buf[MAXPATHLEN + 1], *p;
! 159: char symbuf[MAXPATHLEN + 1];
! 160: char basesym[MAXPATHLEN + 1];
! 161: struct stat sb, sc;
! 162: int n_dirs;
! 163: int symlen;
! 164: int basesymlen = -1;
! 165: char *ocurdir;
! 166: struct except *cur;
! 167:
! 168: if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
! 169: msg ("%s: From and to directories are identical!", fn);
! 170: return 1;
! 171: }
! 172:
! 173: if (rel)
! 174: strcpy (buf, "../");
! 175: else
! 176: buf[0] = '\0';
! 177: strcat (buf, fn);
! 178:
! 179: if (!(df = opendir (buf))) {
! 180: msg ("%s: Cannot opendir", buf);
! 181: return 1;
! 182: }
! 183:
! 184: p = buf + strlen (buf);
! 185: *p++ = '/';
! 186: n_dirs = fs->st_nlink;
! 187: while (dp = readdir (df)) {
! 188: if (dp->d_name[strlen(dp->d_name) - 1] == '~')
! 189: continue;
! 190: strcpy (p, dp->d_name);
! 191:
! 192: if (n_dirs > 0) {
! 193: if (stat (buf, &sb) < 0) {
! 194: mperror (buf);
! 195: continue;
! 196: }
! 197:
! 198: if(S_ISDIR(sb.st_mode)) {
! 199: /* directory */
! 200: n_dirs--;
! 201: if (dp->d_name[0] == '.' &&
! 202: (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
! 203: dp->d_name[2] == '\0')))
! 204: continue;
! 205: for (cur = exceptions; cur != (struct except *)NULL;
! 206: cur = cur->next) {
! 207: if (!strcmp (dp->d_name, cur->name))
! 208: goto next; /* can't continue */
! 209: }
! 210: if (!strcmp (dp->d_name, "RCS"))
! 211: continue;
! 212: if (!strcmp (dp->d_name, "SCCS"))
! 213: continue;
! 214: if (!strcmp (dp->d_name, "CVS"))
! 215: continue;
! 216: if (!strcmp (dp->d_name, "CVS.adm"))
! 217: continue;
! 218: ocurdir = rcurdir;
! 219: rcurdir = buf;
! 220: curdir = silent ? buf : (char *)0;
! 221: if (!silent)
! 222: printf ("%s:\n", buf);
! 223: if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
! 224: if (mkdir (dp->d_name, 0777) < 0 ||
! 225: stat (dp->d_name, &sc) < 0) {
! 226: mperror (dp->d_name);
! 227: curdir = rcurdir = ocurdir;
! 228: continue;
! 229: }
! 230: }
! 231: if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
! 232: msg ("%s: is a link instead of a directory", dp->d_name);
! 233: curdir = rcurdir = ocurdir;
! 234: continue;
! 235: }
! 236: if (chdir (dp->d_name) < 0) {
! 237: mperror (dp->d_name);
! 238: curdir = rcurdir = ocurdir;
! 239: continue;
! 240: }
! 241: dodir (buf, &sb, &sc, (buf[0] != '/'));
! 242: if (chdir ("..") < 0)
! 243: quiterr (1, "..");
! 244: curdir = rcurdir = ocurdir;
! 245: continue;
! 246: }
! 247: }
! 248:
! 249: /* non-directory */
! 250: symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
! 251: if (symlen >= 0)
! 252: symbuf[symlen] = '\0';
! 253:
! 254: /* The option to ignore links exists mostly because
! 255: checking for them slows us down by 10-20%.
! 256: But it is off by default because this really is a useful check. */
! 257: if (!ignore_links) {
! 258: /* see if the file in the base tree was a symlink */
! 259: basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
! 260: if (basesymlen >= 0)
! 261: basesym[basesymlen] = '\0';
! 262: }
! 263:
! 264: if (symlen >= 0) {
! 265: /* Link exists in new tree. Print message if it doesn't match. */
! 266: if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf))
! 267: msg ("%s: %s", dp->d_name, symbuf);
! 268: } else {
! 269: if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
! 270: mperror (dp->d_name);
! 271: }
! 272: next:
! 273: }
! 274:
! 275: closedir (df);
! 276: return 0;
! 277: }
! 278:
! 279:
! 280: main (ac, av)
! 281: int ac;
! 282: char **av;
! 283: {
! 284: char *prog_name = av[0];
! 285: char *fn, *tn;
! 286: struct stat fs, ts;
! 287:
! 288: while (++av, --ac) {
! 289: if ((strcmp(*av, "-silent") == 0) || (strcmp(*av, "-s") == 0))
! 290: silent = 1;
! 291: else if ((strcmp(*av, "-ignorelinks") == 0) || (strcmp(*av, "-i") == 0))
! 292: ignore_links = 1;
! 293: else if (strcmp(*av, "-e") == 0) {
! 294: ++av, --ac;
! 295:
! 296: if (ac < 2)
! 297: quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
! 298: prog_name);
! 299: addexcept(*av);
! 300: }
! 301: else if (strcmp(*av, "--") == 0) {
! 302: ++av, --ac;
! 303: break;
! 304: }
! 305: else
! 306: break;
! 307: }
! 308:
! 309: if (ac < 1 || ac > 2)
! 310: quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
! 311: prog_name);
! 312:
! 313: fn = av[0];
! 314: if (ac == 2)
! 315: tn = av[1];
! 316: else
! 317: tn = ".";
! 318:
! 319: /* to directory */
! 320: if (stat (tn, &ts) < 0)
! 321: quiterr (1, tn);
! 322: #ifdef S_ISDIR
! 323: if (!(S_ISDIR(ts.st_mode)))
! 324: #else
! 325: if (!(ts.st_mode & S_IFDIR))
! 326: #endif
! 327: quit (2, "%s: Not a directory", tn);
! 328: if (chdir (tn) < 0)
! 329: quiterr (1, tn);
! 330:
! 331: /* from directory */
! 332: if (stat (fn, &fs) < 0)
! 333: quiterr (1, fn);
! 334: #ifdef S_ISDIR
! 335: if (!(S_ISDIR(fs.st_mode)))
! 336: #else
! 337: if (!(fs.st_mode & S_IFDIR))
! 338: #endif
! 339: quit (2, "%s: Not a directory", fn);
! 340:
! 341: exit (dodir (fn, &fs, &ts, 0));
! 342: }