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

1.10    ! deraadt     1: /*     $OpenBSD: lndir.c,v 1.9 2002/05/29 18:33:39 deraadt 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:
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 <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.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.1       downsj     80: struct except *exceptions = (struct except *)NULL;
                     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.5       ericj      87:
1.10    ! deraadt    88:        while (++argv, --argc) {
        !            89:                if ((strcmp(*argv, "-silent") == 0) ||
        !            90:                    (strcmp(*argv, "-s") == 0))
        !            91:                        silent = 1;
        !            92:                else if ((strcmp(*argv, "-ignorelinks") == 0) ||
        !            93:                    (strcmp(*argv, "-i") == 0))
        !            94:                        ignore_links = 1;
        !            95:                else if (strcmp(*argv, "-e") == 0) {
        !            96:                        ++argv, --argc;
        !            97:
        !            98:                        if (argc < 2)
        !            99:                                usage();
        !           100:                        addexcept(*argv);
        !           101:                } else if (strcmp(*argv, "--") == 0) {
        !           102:                        ++argv, --argc;
        !           103:                        break;
        !           104:                } else
        !           105:                        break;
        !           106:        }
        !           107:
        !           108:        if (argc < 1 || argc > 2)
        !           109:                usage();
        !           110:
        !           111:        fn = argv[0];
        !           112:        if (argc == 2)
        !           113:                tn = argv[1];
        !           114:        else
        !           115:                tn = ".";
        !           116:
        !           117:        /* to directory */
        !           118:        if (stat(tn, &ts) < 0)
        !           119:                err(1, "%s", tn);
        !           120:        if (!(S_ISDIR(ts.st_mode)))
        !           121:                errx(2, "%s: %s", tn, strerror(ENOTDIR));
        !           122:        if (chdir(tn) < 0)
        !           123:                err(1, "%s", tn);
        !           124:
        !           125:        /* from directory */
        !           126:        if (stat(fn, &fs) < 0)
        !           127:                err(1, "%s", fn);
        !           128:        if (!(S_ISDIR(fs.st_mode)))
        !           129:                err(2, "%s: %s", fn, strerror(ENOTDIR));
1.1       downsj    130:
1.10    ! deraadt   131:        exit(dodir(fn, &fs, &ts, 0));
1.1       downsj    132: }
                    133:
1.5       ericj     134: int
1.10    ! deraadt   135: equivalent(char *lname, char *rname)
1.1       downsj    136: {
1.10    ! deraadt   137:        char *s;
1.1       downsj    138:
1.10    ! deraadt   139:        if (!strcmp(lname, rname))
        !           140:                return(1);
        !           141:        for (s = lname; *s && (s = strchr(s, '/')); s++) {
        !           142:                while (s[1] == '/')
        !           143:                        strcpy(s+1, s+2);
        !           144:        }
        !           145:        return(!strcmp(lname, rname));
1.1       downsj    146: }
                    147:
1.5       ericj     148: void
1.10    ! deraadt   149: addexcept(char *name)
1.1       downsj    150: {
1.10    ! deraadt   151:        struct except *new;
        !           152:
        !           153:        new = (struct except *)malloc(sizeof(struct except));
        !           154:        if (new == (struct except *)NULL)
        !           155:                err(1, "addexcept");
        !           156:        new->name = strdup(name);
        !           157:        if (new->name == (char *)NULL)
        !           158:                err(1, "addexcept");
1.1       downsj    159:
1.10    ! deraadt   160:        new->next = exceptions;
        !           161:        exceptions = new;
1.1       downsj    162: }
                    163:
                    164:
1.5       ericj     165: /*
                    166:  * Recursively create symbolic links from the current directory to the "from"
                    167:  * directory.  Assumes that files described by fs and ts are directories.
                    168:  */
1.10    ! deraadt   169: #if 0
1.5       ericj     170:        char *fn;               /* name of "from" directory, either absolute or
1.1       downsj    171:                                   relative to cwd */
1.5       ericj     172:        struct stat *fs, *ts;   /* stats for the "from" directory and cwd */
                    173:        int rel;                /* if true, prepend "../" to fn before using */
1.10    ! deraadt   174: #endif
        !           175: int
        !           176: dodir(char *fn, struct stat *fs, struct stat *ts, int rel)
1.1       downsj    177: {
1.10    ! deraadt   178:        char buf[MAXPATHLEN + 1], symbuf[MAXPATHLEN + 1], basesym[MAXPATHLEN + 1];
        !           179:        int n_dirs, symlen, basesymlen = -1;
        !           180:        struct stat sb, sc;
        !           181:        struct except *cur;
        !           182:        struct dirent *dp;
        !           183:        char *ocurdir, *p;
        !           184:        DIR *df;
        !           185:
        !           186:        if (fs->st_dev == ts->st_dev && fs->st_ino == ts->st_ino) {
        !           187:                warn("%s: From and to directories are identical!", fn);
        !           188:                return(1);
        !           189:        }
        !           190:
        !           191:        if (rel)
        !           192:                strlcpy(buf, "../", sizeof buf);
        !           193:        else
        !           194:                buf[0] = '\0';
        !           195:        strlcat(buf, fn, sizeof buf);
1.1       downsj    196:
1.10    ! deraadt   197:        if (!(df = opendir(buf))) {
        !           198:                warn("%s: Cannot opendir", buf);
        !           199:                return(1);
1.3       downsj    200:        }
1.1       downsj    201:
1.10    ! deraadt   202:        p = buf + strlen(buf);
        !           203:        *p++ = '/';
        !           204:        n_dirs = fs->st_nlink;
        !           205:        while ((dp = readdir(df))) {
        !           206:                if (dp->d_name[strlen(dp->d_name) - 1] == '~')
1.1       downsj    207:                        continue;
1.10    ! deraadt   208:                for (cur = exceptions; cur != (struct except *)NULL;
        !           209:                    cur = cur->next) {
        !           210:                        if (!strcmp (dp->d_name, cur->name))
        !           211:                                goto next;      /* can't continue */
1.1       downsj    212:                }
1.10    ! deraadt   213:                strcpy(p, dp->d_name);
        !           214:
        !           215:                if (n_dirs > 0) {
        !           216:                        if (stat(buf, &sb) < 0) {
        !           217:                                warn("%s", buf);
        !           218:                                continue;
        !           219:                        }
        !           220:
        !           221:                        if (S_ISDIR(sb.st_mode)) {
        !           222:                                /* directory */
        !           223:                                n_dirs--;
        !           224:                                if (dp->d_name[0] == '.' &&
        !           225:                                    (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
        !           226:                                    dp->d_name[2] == '\0')))
        !           227:                                        continue;
        !           228:                                if (!strcmp(dp->d_name, "RCS"))
        !           229:                                        continue;
        !           230:                                if (!strcmp(dp->d_name, "SCCS"))
        !           231:                                        continue;
        !           232:                                if (!strcmp(dp->d_name, "CVS"))
        !           233:                                        continue;
        !           234:                                if (!strcmp(dp->d_name, "CVS.adm"))
        !           235:                                        continue;
        !           236:                                ocurdir = rcurdir;
        !           237:                                rcurdir = buf;
        !           238:                                curdir = silent ? buf : NULL;
        !           239:                                if (!silent)
        !           240:                                        printf("%s:\n", buf);
        !           241:                                if (stat(dp->d_name, &sc) < 0 && errno == ENOENT) {
        !           242:                                        if (mkdir(dp->d_name, 0777) < 0 ||
        !           243:                                            stat(dp->d_name, &sc) < 0) {
        !           244:                                                warn("%s", dp->d_name);
        !           245:                                                curdir = rcurdir = ocurdir;
        !           246:                                                continue;
        !           247:                                        }
        !           248:                                }
        !           249:                                if (readlink(dp->d_name, symbuf,
        !           250:                                    sizeof(symbuf) - 1) >= 0) {
        !           251:                                        fprintf(stderr,
        !           252:                                            "%s: is a link instead of a directory\n",
        !           253:                                            dp->d_name);
        !           254:                                        curdir = rcurdir = ocurdir;
        !           255:                                        continue;
        !           256:                                }
        !           257:                                if (chdir(dp->d_name) < 0) {
        !           258:                                        warn("%s", dp->d_name);
        !           259:                                        curdir = rcurdir = ocurdir;
        !           260:                                        continue;
        !           261:                                }
        !           262:                                dodir(buf, &sb, &sc, (buf[0] != '/'));
        !           263:                                if (chdir("..") < 0)
        !           264:                                        err(1, "..");
        !           265:                                curdir = rcurdir = ocurdir;
        !           266:                                continue;
        !           267:                        }
1.1       downsj    268:                }
1.10    ! deraadt   269:
        !           270:                /* non-directory */
        !           271:                symlen = readlink(dp->d_name, symbuf, sizeof(symbuf) - 1);
        !           272:                if (symlen >= 0)
        !           273:                        symbuf[symlen] = '\0';
        !           274:
        !           275:                /*
        !           276:                 * The option to ignore links exists mostly because
        !           277:                 * checking for them slows us down by 10-20%.
        !           278:                 * But it is off by default because this really is a useful check.
        !           279:                 */
        !           280:                if (!ignore_links) {
        !           281:                        /* see if the file in the base tree was a symlink */
        !           282:                        basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
        !           283:                        if (basesymlen >= 0)
        !           284:                                basesym[basesymlen] = '\0';
1.1       downsj    285:                }
                    286:
1.10    ! deraadt   287:                if (symlen >= 0) {
        !           288:                        /*
        !           289:                         * Link exists in new tree.  Print message if
        !           290:                         * it doesn't match.
        !           291:                         */
        !           292:                        if (!equivalent(basesymlen>=0 ? basesym : buf, symbuf))
        !           293:                                fprintf(stderr,"%s: %s\n", dp->d_name, symbuf);
        !           294:                } else {
        !           295:                        if (symlink(basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
        !           296:                                warn("%s", dp->d_name);
        !           297:                }
        !           298: next:
1.1       downsj    299:        }
                    300:
1.10    ! deraadt   301:        closedir(df);
        !           302:        return(0);
1.1       downsj    303: }
                    304:
1.5       ericj     305: void
1.10    ! deraadt   306: usage(void)
1.1       downsj    307: {
1.5       ericj     308:        (void)fprintf(stderr, "usage: %s [-e except] [-si] fromdir todir\n",
1.10    ! deraadt   309:            __progname);
1.5       ericj     310:        exit(1);
1.1       downsj    311: }