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

1.4     ! niklas      1: /*     $OpenBSD: lndir.c,v 1.3 1996/08/19 06:50:16 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>
1.4     ! niklas     48: #include <stdlib.h>
1.1       downsj     49: #include <sys/types.h>
                     50: #include <sys/stat.h>
                     51: #include <sys/param.h>
                     52: #include <errno.h>
                     53: #include <dirent.h>
                     54: #include <stdarg.h>
                     55: #include <string.h>
                     56:
                     57: int silent = 0;                        /* -silent */
                     58: int ignore_links = 0;          /* -ignorelinks */
                     59:
                     60: char *rcurdir;
                     61: char *curdir;
                     62:
                     63: struct except {
                     64:        char *name;
                     65:
                     66:        struct except *next;
                     67: };
                     68: struct except *exceptions = (struct except *)NULL;
                     69:
                     70: void
                     71: quit (int code, char * fmt, ...)
                     72: {
                     73:     va_list args;
                     74:     va_start(args, fmt);
                     75:     vfprintf (stderr, fmt, args);
                     76:     va_end(args);
                     77:     putc ('\n', stderr);
                     78:     exit (code);
                     79: }
                     80:
                     81: void
                     82: quiterr (code, s)
                     83:     char *s;
                     84: {
                     85:     perror (s);
                     86:     exit (code);
                     87: }
                     88:
                     89: void
                     90: msg (char * fmt, ...)
                     91: {
                     92:     va_list args;
                     93:     if (curdir) {
                     94:        fprintf (stderr, "%s:\n", curdir);
                     95:        curdir = 0;
                     96:     }
                     97:     va_start(args, fmt);
                     98:     vfprintf (stderr, fmt, args);
                     99:     va_end(args);
                    100:     putc ('\n', stderr);
                    101: }
                    102:
                    103: void
                    104: mperror (s)
                    105:     char *s;
                    106: {
                    107:     if (curdir) {
                    108:        fprintf (stderr, "%s:\n", curdir);
                    109:        curdir = 0;
                    110:     }
                    111:     perror (s);
                    112: }
                    113:
                    114:
                    115: int equivalent(lname, rname)
                    116:     char *lname;
                    117:     char *rname;
                    118: {
                    119:     char *s;
                    120:
                    121:     if (!strcmp(lname, rname))
                    122:        return 1;
                    123:     for (s = lname; *s && (s = strchr(s, '/')); s++) {
                    124:        while (s[1] == '/')
                    125:            strcpy(s+1, s+2);
                    126:     }
                    127:     return !strcmp(lname, rname);
                    128: }
                    129:
                    130:
                    131: addexcept(name)
                    132:     char *name;
                    133: {
                    134:     struct except *new;
                    135:
                    136:     new = (struct except *)malloc(sizeof(struct except));
                    137:     if (new == (struct except *)NULL)
                    138:         quiterr(1, "addexcept");
                    139:     new->name = strdup(name);
                    140:     if (new->name == (char *)NULL)
                    141:         quiterr(1, "addexcept");
                    142:
                    143:     new->next = exceptions;
                    144:     exceptions = new;
                    145: }
                    146:
                    147:
                    148: /* Recursively create symbolic links from the current directory to the "from"
                    149:    directory.  Assumes that files described by fs and ts are directories. */
                    150:
                    151: dodir (fn, fs, ts, rel)
                    152: char *fn;                      /* name of "from" directory, either absolute or
                    153:                                   relative to cwd */
                    154: struct stat *fs, *ts;          /* stats for the "from" directory and cwd */
                    155: int rel;                       /* if true, prepend "../" to fn before using */
                    156: {
                    157:     DIR *df;
                    158:     struct dirent *dp;
                    159:     char buf[MAXPATHLEN + 1], *p;
                    160:     char symbuf[MAXPATHLEN + 1];
                    161:     char basesym[MAXPATHLEN + 1];
                    162:     struct stat sb, sc;
                    163:     int n_dirs;
                    164:     int symlen;
                    165:     int basesymlen = -1;
                    166:     char *ocurdir;
                    167:     struct except *cur;
                    168:
                    169:     if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
                    170:        msg ("%s: From and to directories are identical!", fn);
                    171:        return 1;
                    172:     }
                    173:
                    174:     if (rel)
                    175:        strcpy (buf, "../");
                    176:     else
                    177:        buf[0] = '\0';
                    178:     strcat (buf, fn);
                    179:
                    180:     if (!(df = opendir (buf))) {
                    181:        msg ("%s: Cannot opendir", buf);
                    182:        return 1;
                    183:     }
                    184:
                    185:     p = buf + strlen (buf);
                    186:     *p++ = '/';
                    187:     n_dirs = fs->st_nlink;
                    188:     while (dp = readdir (df)) {
                    189:        if (dp->d_name[strlen(dp->d_name) - 1] == '~')
                    190:            continue;
1.3       downsj    191:        for (cur = exceptions; cur != (struct except *)NULL;
                    192:             cur = cur->next) {
                    193:            if (!strcmp (dp->d_name, cur->name))
                    194:                goto next;      /* can't continue */
                    195:        }
1.1       downsj    196:        strcpy (p, dp->d_name);
                    197:
                    198:        if (n_dirs > 0) {
                    199:            if (stat (buf, &sb) < 0) {
                    200:                mperror (buf);
                    201:                continue;
                    202:            }
                    203:
                    204:            if(S_ISDIR(sb.st_mode)) {
                    205:                /* directory */
                    206:                n_dirs--;
                    207:                if (dp->d_name[0] == '.' &&
                    208:                    (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
                    209:                                               dp->d_name[2] == '\0')))
                    210:                    continue;
                    211:                if (!strcmp (dp->d_name, "RCS"))
                    212:                    continue;
                    213:                if (!strcmp (dp->d_name, "SCCS"))
                    214:                    continue;
                    215:                if (!strcmp (dp->d_name, "CVS"))
                    216:                    continue;
                    217:                if (!strcmp (dp->d_name, "CVS.adm"))
                    218:                    continue;
                    219:                ocurdir = rcurdir;
                    220:                rcurdir = buf;
                    221:                curdir = silent ? buf : (char *)0;
                    222:                if (!silent)
                    223:                    printf ("%s:\n", buf);
                    224:                if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
                    225:                    if (mkdir (dp->d_name, 0777) < 0 ||
                    226:                        stat (dp->d_name, &sc) < 0) {
                    227:                        mperror (dp->d_name);
                    228:                        curdir = rcurdir = ocurdir;
                    229:                        continue;
                    230:                    }
                    231:                }
                    232:                if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
                    233:                    msg ("%s: is a link instead of a directory", dp->d_name);
                    234:                    curdir = rcurdir = ocurdir;
                    235:                    continue;
                    236:                }
                    237:                if (chdir (dp->d_name) < 0) {
                    238:                    mperror (dp->d_name);
                    239:                    curdir = rcurdir = ocurdir;
                    240:                    continue;
                    241:                }
                    242:                dodir (buf, &sb, &sc, (buf[0] != '/'));
                    243:                if (chdir ("..") < 0)
                    244:                    quiterr (1, "..");
                    245:                curdir = rcurdir = ocurdir;
                    246:                continue;
                    247:            }
                    248:        }
                    249:
                    250:        /* non-directory */
                    251:        symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
                    252:        if (symlen >= 0)
                    253:            symbuf[symlen] = '\0';
                    254:
                    255:        /* The option to ignore links exists mostly because
                    256:           checking for them slows us down by 10-20%.
                    257:           But it is off by default because this really is a useful check. */
                    258:        if (!ignore_links) {
                    259:            /* see if the file in the base tree was a symlink */
                    260:            basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
                    261:            if (basesymlen >= 0)
                    262:                basesym[basesymlen] = '\0';
                    263:        }
                    264:
                    265:        if (symlen >= 0) {
                    266:            /* Link exists in new tree.  Print message if it doesn't match. */
                    267:            if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf))
                    268:                msg ("%s: %s", dp->d_name, symbuf);
                    269:        } else {
                    270:            if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
                    271:                mperror (dp->d_name);
                    272:        }
                    273: next:
                    274:     }
                    275:
                    276:     closedir (df);
                    277:     return 0;
                    278: }
                    279:
                    280:
                    281: main (ac, av)
                    282: int ac;
                    283: char **av;
                    284: {
                    285:     char *prog_name = av[0];
                    286:     char *fn, *tn;
                    287:     struct stat fs, ts;
                    288:
                    289:     while (++av, --ac) {
                    290:        if ((strcmp(*av, "-silent") == 0) || (strcmp(*av, "-s") == 0))
                    291:            silent = 1;
                    292:        else if ((strcmp(*av, "-ignorelinks") == 0) || (strcmp(*av, "-i") == 0))
                    293:            ignore_links = 1;
                    294:        else if (strcmp(*av, "-e") == 0) {
                    295:            ++av, --ac;
                    296:
                    297:            if (ac < 2)
                    298:                quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
                    299:                      prog_name);
                    300:            addexcept(*av);
                    301:        }
                    302:        else if (strcmp(*av, "--") == 0) {
                    303:            ++av, --ac;
                    304:            break;
                    305:        }
                    306:        else
                    307:            break;
                    308:     }
                    309:
                    310:     if (ac < 1 || ac > 2)
                    311:        quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
                    312:              prog_name);
                    313:
                    314:     fn = av[0];
                    315:     if (ac == 2)
                    316:        tn = av[1];
                    317:     else
                    318:        tn = ".";
                    319:
                    320:     /* to directory */
                    321:     if (stat (tn, &ts) < 0)
                    322:        quiterr (1, tn);
                    323:     if (!(S_ISDIR(ts.st_mode)))
                    324:        quit (2, "%s: Not a directory", tn);
                    325:     if (chdir (tn) < 0)
                    326:        quiterr (1, tn);
                    327:
                    328:     /* from directory */
                    329:     if (stat (fn, &fs) < 0)
                    330:        quiterr (1, fn);
                    331:     if (!(S_ISDIR(fs.st_mode)))
                    332:        quit (2, "%s: Not a directory", fn);
                    333:
                    334:     exit (dodir (fn, &fs, &ts, 0));
                    335: }