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

1.2     ! downsj      1: /*     $OpenBSD: lndir.c,v 1.1 1996/08/19 05:47:26 downsj Exp $        */
1.1       downsj      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:     if (!(S_ISDIR(ts.st_mode)))
                    323:        quit (2, "%s: Not a directory", tn);
                    324:     if (chdir (tn) < 0)
                    325:        quiterr (1, tn);
                    326:
                    327:     /* from directory */
                    328:     if (stat (fn, &fs) < 0)
                    329:        quiterr (1, fn);
                    330:     if (!(S_ISDIR(fs.st_mode)))
                    331:        quit (2, "%s: Not a directory", fn);
                    332:
                    333:     exit (dodir (fn, &fs, &ts, 0));
                    334: }