[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.22

1.22    ! deraadt     1: /*     $OpenBSD: lndir.c,v 1.21 2015/01/16 06:40:09 deraadt Exp $      */
1.1       downsj      2: /* $XConsortium: lndir.c /main/15 1995/08/30 10:56:18 gildea $ */
1.5       ericj       3:
1.15      mickey      4: /*
1.5       ericj       5:  * Create shadow link tree (after X11R4 script of the same name)
1.15      mickey      6:  * Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990
1.5       ericj       7:  */
1.1       downsj      8:
1.15      mickey      9: /*
1.1       downsj     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:
1.10      deraadt    45:        %  mkdir /usr/local/src/new-X
1.1       downsj     46:        %  cd /usr/local/src/new-X
1.10      deraadt    47:        %  lndir ../X
1.1       downsj     48: */
                     49:
                     50: #include <sys/stat.h>
1.12      millert    51:
                     52: #include <dirent.h>
1.5       ericj      53: #include <err.h>
1.1       downsj     54: #include <errno.h>
                     55: #include <stdarg.h>
1.12      millert    56: #include <stdio.h>
                     57: #include <stdlib.h>
1.1       downsj     58: #include <string.h>
1.5       ericj      59: #include <unistd.h>
1.21      deraadt    60: #include <limits.h>
1.5       ericj      61:
1.15      mickey     62: extern char *__progname;
1.1       downsj     63:
1.19      tedu       64: int silent;                    /* -silent */
                     65: int ignore_links;              /* -ignorelinks */
1.1       downsj     66:
                     67: char *rcurdir;
                     68: char *curdir;
                     69:
1.7       millert    70: int equivalent(char *, char *);
                     71: void addexcept(char *);
                     72: int dodir(char *, struct stat *, struct stat *, int);
                     73: void usage(void);
1.5       ericj      74:
1.1       downsj     75: struct except {
                     76:        char *name;
                     77:        struct except *next;
                     78: };
1.5       ericj      79:
1.19      tedu       80: struct except *exceptions;
1.1       downsj     81:
1.5       ericj      82: int
1.10      deraadt    83: main(int argc, char *argv[])
1.1       downsj     84: {
1.10      deraadt    85:        struct stat fs, ts;
1.6       jasoni     86:        char *fn, *tn;
1.22    ! deraadt    87:
        !            88:        if (pledge("stdio rpath wpath cpath", NULL) == -1)
        !            89:                err(1, "pledge");
1.5       ericj      90:
1.10      deraadt    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:        if (argc < 1 || argc > 2)
                    112:                usage();
                    113:
                    114:        fn = argv[0];
                    115:        if (argc == 2)
                    116:                tn = argv[1];
                    117:        else
                    118:                tn = ".";
                    119:
                    120:        /* to directory */
                    121:        if (stat(tn, &ts) < 0)
                    122:                err(1, "%s", tn);
                    123:        if (!(S_ISDIR(ts.st_mode)))
1.20      guenther  124:                errc(2, ENOTDIR, "%s", tn);
1.10      deraadt   125:        if (chdir(tn) < 0)
                    126:                err(1, "%s", tn);
                    127:
                    128:        /* from directory */
                    129:        if (stat(fn, &fs) < 0)
                    130:                err(1, "%s", fn);
                    131:        if (!(S_ISDIR(fs.st_mode)))
1.20      guenther  132:                errc(2, ENOTDIR, "%s", fn);
1.1       downsj    133:
1.10      deraadt   134:        exit(dodir(fn, &fs, &ts, 0));
1.1       downsj    135: }
                    136:
1.5       ericj     137: int
1.10      deraadt   138: equivalent(char *lname, char *rname)
1.1       downsj    139: {
1.13      millert   140:        char *s, *ns;
1.1       downsj    141:
1.12      millert   142:        if (strcmp(lname, rname) == 0)
1.10      deraadt   143:                return(1);
                    144:        for (s = lname; *s && (s = strchr(s, '/')); s++) {
1.13      millert   145:                if (s[1] == '/') {
                    146:                        /* collapse multiple slashes in lname */
                    147:                        for (ns = s + 1; *ns == '/'; ns++)
                    148:                                ;
                    149:                        memmove(s + 1, ns, strlen(ns) + 1);
                    150:                }
1.10      deraadt   151:        }
1.19      tedu      152:        return (strcmp(lname, rname) == 0);
1.1       downsj    153: }
                    154:
1.5       ericj     155: void
1.10      deraadt   156: addexcept(char *name)
1.1       downsj    157: {
1.10      deraadt   158:        struct except *new;
                    159:
1.19      tedu      160:        new = malloc(sizeof(struct except));
                    161:        if (new == NULL)
1.12      millert   162:                err(1, NULL);
1.10      deraadt   163:        new->name = strdup(name);
1.19      tedu      164:        if (new->name == NULL)
1.12      millert   165:                err(1, NULL);
1.1       downsj    166:
1.10      deraadt   167:        new->next = exceptions;
                    168:        exceptions = new;
1.1       downsj    169: }
                    170:
                    171:
1.15      mickey    172: /*
1.5       ericj     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:  */
1.10      deraadt   176: #if 0
1.5       ericj     177:        char *fn;               /* name of "from" directory, either absolute or
1.1       downsj    178:                                   relative to cwd */
1.5       ericj     179:        struct stat *fs, *ts;   /* stats for the "from" directory and cwd */
                    180:        int rel;                /* if true, prepend "../" to fn before using */
1.10      deraadt   181: #endif
                    182: int
                    183: dodir(char *fn, struct stat *fs, struct stat *ts, int rel)
1.1       downsj    184: {
1.21      deraadt   185:        char buf[PATH_MAX + 1], symbuf[PATH_MAX + 1];
                    186:        char basesym[PATH_MAX + 1];
1.10      deraadt   187:        int n_dirs, symlen, basesymlen = -1;
                    188:        struct stat sb, sc;
                    189:        struct except *cur;
                    190:        struct dirent *dp;
                    191:        char *ocurdir, *p;
                    192:        DIR *df;
                    193:
                    194:        if (fs->st_dev == ts->st_dev && fs->st_ino == ts->st_ino) {
1.12      millert   195:                warnx("%s: From and to directories are identical!", fn);
1.10      deraadt   196:                return(1);
                    197:        }
                    198:
                    199:        if (rel)
1.13      millert   200:                strlcpy(buf, "../", sizeof(buf));
1.10      deraadt   201:        else
                    202:                buf[0] = '\0';
1.13      millert   203:        strlcat(buf, fn, sizeof(buf));
1.15      mickey    204:
1.10      deraadt   205:        if (!(df = opendir(buf))) {
                    206:                warn("%s: Cannot opendir", buf);
                    207:                return(1);
1.3       downsj    208:        }
1.1       downsj    209:
1.10      deraadt   210:        p = buf + strlen(buf);
                    211:        *p++ = '/';
                    212:        n_dirs = fs->st_nlink;
                    213:        while ((dp = readdir(df))) {
1.16      matthieu  214:                if (dp->d_namlen == 0 || dp->d_name[dp->d_namlen - 1] == '~' ||
                    215:                    strncmp(dp->d_name, ".#", 2) == 0)
1.1       downsj    216:                        continue;
1.14      millert   217:                for (cur = exceptions; cur != NULL; cur = cur->next) {
                    218:                        if (!strcmp(dp->d_name, cur->name))
1.10      deraadt   219:                                goto next;      /* can't continue */
1.1       downsj    220:                }
1.13      millert   221:                strlcpy(p, dp->d_name, buf + sizeof(buf) - p);
1.10      deraadt   222:
                    223:                if (n_dirs > 0) {
                    224:                        if (stat(buf, &sb) < 0) {
                    225:                                warn("%s", buf);
                    226:                                continue;
                    227:                        }
                    228:
                    229:                        if (S_ISDIR(sb.st_mode)) {
                    230:                                /* directory */
                    231:                                n_dirs--;
                    232:                                if (dp->d_name[0] == '.' &&
1.19      tedu      233:                                    (dp->d_name[1] == '\0' ||
                    234:                                    (dp->d_name[1] == '.' &&
1.10      deraadt   235:                                    dp->d_name[2] == '\0')))
                    236:                                        continue;
                    237:                                if (!strcmp(dp->d_name, "RCS"))
                    238:                                        continue;
                    239:                                if (!strcmp(dp->d_name, "SCCS"))
                    240:                                        continue;
                    241:                                if (!strcmp(dp->d_name, "CVS"))
                    242:                                        continue;
                    243:                                if (!strcmp(dp->d_name, "CVS.adm"))
                    244:                                        continue;
                    245:                                ocurdir = rcurdir;
                    246:                                rcurdir = buf;
                    247:                                curdir = silent ? buf : NULL;
                    248:                                if (!silent)
                    249:                                        printf("%s:\n", buf);
1.19      tedu      250:                                if (stat(dp->d_name, &sc) < 0 &&
                    251:                                    errno == ENOENT) {
1.10      deraadt   252:                                        if (mkdir(dp->d_name, 0777) < 0 ||
                    253:                                            stat(dp->d_name, &sc) < 0) {
                    254:                                                warn("%s", dp->d_name);
                    255:                                                curdir = rcurdir = ocurdir;
                    256:                                                continue;
                    257:                                        }
                    258:                                }
                    259:                                if (readlink(dp->d_name, symbuf,
                    260:                                    sizeof(symbuf) - 1) >= 0) {
                    261:                                        fprintf(stderr,
1.19      tedu      262:                                            "%s: is a link instead of a "
                    263:                                            "directory\n",
1.10      deraadt   264:                                            dp->d_name);
                    265:                                        curdir = rcurdir = ocurdir;
                    266:                                        continue;
                    267:                                }
                    268:                                if (chdir(dp->d_name) < 0) {
                    269:                                        warn("%s", dp->d_name);
                    270:                                        curdir = rcurdir = ocurdir;
                    271:                                        continue;
                    272:                                }
                    273:                                dodir(buf, &sb, &sc, (buf[0] != '/'));
                    274:                                if (chdir("..") < 0)
                    275:                                        err(1, "..");
                    276:                                curdir = rcurdir = ocurdir;
                    277:                                continue;
                    278:                        }
1.1       downsj    279:                }
1.10      deraadt   280:
                    281:                /* non-directory */
                    282:                symlen = readlink(dp->d_name, symbuf, sizeof(symbuf) - 1);
                    283:                if (symlen >= 0)
                    284:                        symbuf[symlen] = '\0';
                    285:
1.15      mickey    286:                /*
1.10      deraadt   287:                 * The option to ignore links exists mostly because
                    288:                 * checking for them slows us down by 10-20%.
1.19      tedu      289:                 * But it is off by default because this is a useful check.
1.10      deraadt   290:                 */
                    291:                if (!ignore_links) {
                    292:                        /* see if the file in the base tree was a symlink */
1.19      tedu      293:                        basesymlen = readlink(buf, basesym,
                    294:                            sizeof(basesym) - 1);
1.10      deraadt   295:                        if (basesymlen >= 0)
                    296:                                basesym[basesymlen] = '\0';
1.1       downsj    297:                }
                    298:
1.10      deraadt   299:                if (symlen >= 0) {
                    300:                        /*
                    301:                         * Link exists in new tree.  Print message if
                    302:                         * it doesn't match.
                    303:                         */
1.19      tedu      304:                        if (!equivalent(basesymlen >= 0 ? basesym : buf,
                    305:                            symbuf))
1.10      deraadt   306:                                fprintf(stderr,"%s: %s\n", dp->d_name, symbuf);
                    307:                } else {
1.19      tedu      308:                        if (symlink(basesymlen >= 0 ? basesym : buf,
                    309:                            dp->d_name) < 0)
1.10      deraadt   310:                                warn("%s", dp->d_name);
                    311:                }
                    312: next:
1.11      millert   313:        ;
1.1       downsj    314:        }
                    315:
1.10      deraadt   316:        closedir(df);
1.19      tedu      317:        return (0);
1.1       downsj    318: }
                    319:
1.5       ericj     320: void
1.10      deraadt   321: usage(void)
1.1       downsj    322: {
1.19      tedu      323:        fprintf(stderr, "usage: %s [-is] [-e exceptfile] fromdir [todir]\n",
1.10      deraadt   324:            __progname);
1.5       ericj     325:        exit(1);
1.1       downsj    326: }