[BACK]Return to lndir.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / lndir

Annotation of src/usr.bin/lndir/lndir.c, Revision 1.5

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