fix silly indirect-through-zero bug
[unix-history] / usr / src / usr.sbin / mtree / create.c
index fe8ed52..7c5243a 100644 (file)
-/*
+/*-
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)create.c   5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)create.c   5.16 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <time.h>
+#include <fts.h>
 #include <dirent.h>
 #include <dirent.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <strings.h>
 #include "mtree.h"
 
 #include "mtree.h"
 
-cwalk(parent, tail)
-       ENTRY *parent;
-       register char *tail;
+#define        LABEL \
+       if (label++) \
+               (void)putchar(' '); \
+
+int ftsoptions = FTS_PHYSICAL;
+
+cwalk()
 {
 {
-       extern ENTRY *root;
-       extern dev_t device;
-       extern int dflag, xflag, errno, alphasort();
-       extern char path[];
-       register ENTRY *centry, *level;
-       struct dirent *dp, **dir_list;
-       struct stat sbuf;
-       int cnt, dir_cnt;
-       char *emalloc(), *rlink();
+       extern int dflag;
+       register FTS *t;
+       register FTSENT *p;
+       register int cnt, label, notset;
+       time_t clock;
+       uid_t uid;
+       gid_t gid;
+       mode_t mode;
+       int tabs, dsort();
+       char *argv[2];
+       char curp[MAXPATHLEN], *inotype(), *getlogin(), *rlink();
 
 
-       *tail++ = '/';
-       dir_cnt = scandir(".", &dir_list, NULL, alphasort);
-       if (dir_cnt == -1 || xflag && lstat(".", &sbuf)) {
-               (void)fprintf(stderr, "mtree: %s: %s\n", path + 2,
-                   strerror(errno));
-                       exit(1);
+       if (!getwd(curp)) {
+               (void)fprintf(stderr, "mtree: %s\n", curp);
+               exit(1);
        }
        }
-       device = sbuf.st_dev;
-       for (cnt = 0; cnt < dir_cnt; ++cnt) {
-               dp = dir_list[cnt];
-               if (dp->d_name[0] == '.' &&
-                   (!dp->d_name[1] || dp->d_name[1] == '.' && !dp->d_name[2]))
-                       continue;
-               bcopy(dp->d_name, tail, dp->d_namlen + 1);
-               if (lstat(dp->d_name, &sbuf)) {
-                       (void)fprintf(stderr, "mtree: %s: %s\n",
-                           path + 2, strerror(errno));
-                       exit(1);
-               }
-               if (dflag && !S_ISDIR(sbuf.st_mode))
-                       continue;
-
-               centry = (ENTRY *)emalloc(sizeof(ENTRY));
-               if (!(centry->name = strdup(dp->d_name)))
-                       nomem();
-               centry->nlen = dp->d_namlen;
+       (void)time(&clock);
+       (void)printf("#\t  fs: %s\n#\t  by: %s\n#\tdate: %s\n",
+           curp, getlogin(), ctime(&clock));
 
 
-               switch(sbuf.st_mode&S_IFMT) {
-               case S_IFDIR:
-                       centry->info.type = F_DIR;
-                       break;
-               case S_IFCHR:
-                       centry->info.type = F_CHAR;
-                       break;
-               case S_IFBLK:
-                       centry->info.type = F_BLOCK;
-                       break;
-               case S_IFREG:
-                       centry->info.type = F_FILE;
-                       break;
-               case S_IFLNK:
-                       centry->info.type = F_LINK;
-                       centry->info.slink = strdup(rlink(dp->d_name));
-                       break;
-               case S_IFSOCK:
-                       centry->info.type = F_SOCK;
+       argv[0] = ".";
+       argv[1] = (char *)NULL;
+       if (!(t = fts_open(argv, ftsoptions, dsort))) {
+               (void)fprintf(stderr,
+                   "mtree: fts_open: %s.\n", strerror(errno));
+               exit(1);
+       }
+       while (p = fts_read(t)) {
+               switch(p->fts_info) {
+               case FTS_D:
+                       if (dflag)
+                               notset = 1;
+                       else
+                               notset =
+                                   statdir(t, p, &uid, &gid, &mode, &tabs);
+                       if (!strcmp(p->fts_name, "."))
+                               continue;
                        break;
                        break;
+               case FTS_DP:
+                       if (p->fts_level <= 0)
+                               continue;
+                       for (cnt = p->fts_level - 1; cnt-- > 0; )
+                               (void)putchar('\t');
+                       (void)printf("..\n");
+                       continue;
+               case FTS_DNR:
+               case FTS_ERR:
+               case FTS_NS:
+                       (void)fprintf(stderr, "mtree: %s: %s.\n",
+                           p->fts_path, strerror(errno));
+                       continue;
                default:
                default:
-                       (void)fprintf(stderr, "mtree: unknown file type %s.\n",
-                           path + 2);
-                       exit(1);
+                       if (dflag)
+                               continue;
                }
                }
-               centry->info.st_uid = sbuf.st_uid;
-               centry->info.st_gid = sbuf.st_gid;
-               centry->info.st_size = sbuf.st_size;
-               centry->info.st_mode = sbuf.st_mode&07777;
-               centry->info.st_nlink = sbuf.st_nlink;
-               centry->info.st_uid = sbuf.st_uid;
 
 
-               if (!root) {
-                       level = root = centry;
-                       root->parent = root->child = NULL;
-               }
-               else if (parent) {
-                       centry->parent = parent;
-                       parent->child = centry;
-                       level = centry;
-                       parent = NULL;
-               }
+               for (cnt = p->fts_level - 1; cnt-- > 0; )
+                       (void)putchar('\t');
+               (void)printf("%s", p->fts_name);
+               if (p->fts_info == FTS_D)
+                       (void)putchar('\t');
                else {
                else {
-                       centry->parent = level->parent;
-                       level = level->next = centry;
-               }
-               stats(&centry->info);
-               if (!S_ISDIR(sbuf.st_mode) || xflag && device != sbuf.st_dev)
-                       continue;
-               if (chdir(dp->d_name)) {
-                       (void)fprintf(stderr, "mtree: %s: %s\n", path + 2,
-                           strerror(errno));
-                       exit(1);
-               }
-               cwalk(level, tail + dp->d_namlen);
-               if (chdir("..")) {
-                       (void)fprintf(stderr, "mtree: ..: %s\n",
-                           strerror(errno));
-                       exit(1);
+                       if (tabs > 1 && p->fts_namelen < 8)
+                               (void)putchar('\t');
+                       (void)putchar('\t');
                }
                }
-       }
-}
 
 
-#define        LABEL { \
-       if (!label++) \
-               (void)printf("%s", level->nlen > 7 ? "\t" : "\t\t"); \
-       else \
-               (void)putchar(' '); \
-}
-
-extern mode_t dmode;                           /* default directory mode */
-extern mode_t fmode;                           /* default file mode */
-uid_t uid, gid;                                        /* default owner, group */
-u_int type;
-pwalk(level, tabs)
-       ENTRY *level;
-       int tabs;
-{
-       INFO *ip;
-       register int cnt;
-       int label;
-       char *ftype();
-
-       for (; level; level = level->next) {
-               for (cnt = tabs; cnt--; )
-                       (void)putchar('\t');
-               (void)printf("%s", level->name);
                label = 0;
                label = 0;
-               if ((ip = &level->info)->type != type) {
+               if (!S_ISREG(p->fts_statb.st_mode) || notset) {
+                       LABEL;
+                       (void)printf("type=%s", inotype(p->fts_statb.st_mode));
+               }
+               if (p->fts_statb.st_uid != uid || notset) {
                        LABEL;
                        LABEL;
-                       (void)printf("type=%s", ftype(ip->type));
+                       (void)printf("owner=%u", p->fts_statb.st_uid);
                }
                }
-               if (ip->st_uid != uid) {
+               if (p->fts_statb.st_gid != gid || notset) {
                        LABEL;
                        LABEL;
-                       (void)printf("owner=%u", ip->st_uid);
+                       (void)printf("group=%u", p->fts_statb.st_gid);
                }
                }
-               if (ip->st_gid != gid) {
+               if ((p->fts_statb.st_mode & MBITS) != mode || notset) {
                        LABEL;
                        LABEL;
-                       (void)printf("group=%u", ip->st_gid);
+                       (void)printf("mode=%#o", p->fts_statb.st_mode & MBITS);
                }
                }
-               if (ip->type == F_DIR) {
-                       if (ip->st_mode != dmode) {
-                               LABEL;
-                               (void)printf("mode=%o", ip->st_mode);
-                       }
-               } else {
-                       if (ip->st_mode != fmode) {
-                               LABEL;
-                               (void)printf("mode=%o", ip->st_mode);
-                       }
-                       if (ip->st_nlink != 1) {
-                               LABEL;
-                               (void)printf("nlink=%u", ip->st_nlink);
-                       }
+               if (p->fts_statb.st_nlink != 1 || notset) {
+                       LABEL;
+                       (void)printf("nlink=%u", p->fts_statb.st_nlink);
                }
                LABEL;
                }
                LABEL;
-               (void)printf("size=%ld", ip->st_size);
-               if (ip->slink)
-                       (void)printf(" link=%s", ip->slink);
-               (void)putchar('\n');
-               if (level->child)
-                       pwalk(level->child, tabs + 1);
-               if (ip->type == F_DIR) {
-                       for (cnt = tabs; cnt--; )
-                               (void)putchar('\t');
-                       (void)printf("..\n");
+               (void)printf("size=%ld", p->fts_statb.st_size);
+               LABEL;
+               (void)printf("time=%ld", p->fts_statb.st_mtime);
+
+               if (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE) {
+                       LABEL;
+                       (void)printf("link=%s", rlink(p->fts_accpath));
                }
                }
+               (void)putchar('\n');
        }
        }
+       (void)fts_close(t);
 }
 
 }
 
-ID *uhead;
-ID *ghead;
-u_long dmodes[0777 + 1];
-u_long fmodes[0777 + 1];
+#define        MAXGID  5000
+#define        MAXUID  5000
+#define        MAXMODE MBITS + 1
 
 
-stats(ip)
-       INFO *ip;
+statdir(t, parent, puid, pgid, pmode, tabs)
+       FTS *t;
+       FTSENT *parent;
+       uid_t *puid;
+       gid_t *pgid;
+       mode_t *pmode;
+       int *tabs;
 {
 {
-       register ID *p;
+       register FTSENT *p;
+       register gid_t gid;
+       register uid_t uid;
+       register mode_t mode;
+       gid_t savegid;
+       uid_t saveuid;
+       mode_t savemode;
+       u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
 
 
-       if (ip->type == F_DIR)
-               ++dmodes[ip->st_mode&0777];
-       else
-               ++fmodes[ip->st_mode&0777];
-       for (p = uhead;; p = p->next)
-               if (!p) {
-                       p = (ID *)emalloc(sizeof(ID));
-                       p->id = ip->st_uid;
-                       p->next = uhead;
-                       uhead = p;
-                       break;
-               } else if (p->id == ip->st_uid) {
-                       ++p->cnt;
-                       break;
-               }
-       for (p = ghead;; p = p->next)
-               if (!p) {
-                       p = (ID *)emalloc(sizeof(ID));
-                       p->id = ip->st_gid;
-                       p->next = ghead;
-                       ghead = p;
-                       break;
-               } else if (p->id == ip->st_gid) {
-                       ++p->cnt;
-                       break;
+       if (!(p = fts_children(t))) {
+               if (errno) {
+                       (void)fprintf(stderr, "mtree: %s: %s.\n",
+                           RP(parent), strerror(errno));
+                       exit(1);
                }
                }
+               return(1);
+       }
+
+       bzero(g, sizeof(g));
+       bzero(u, sizeof(u));
+       bzero(m, sizeof(m));
+
+       *tabs = 1;
+       maxuid = maxgid = maxmode = 0;
+       for (; p; p = p->fts_link) {
+               mode = p->fts_statb.st_mode & MBITS;
+               if (mode < MAXMODE && ++m[mode] > maxmode) {
+                       savemode = mode;
+                       maxmode = m[mode];
+               }
+               gid = p->fts_statb.st_gid;
+               if (gid < MAXGID && ++g[gid] > maxgid) {
+                       savegid = gid;
+                       maxgid = g[gid];
+               }
+               uid = p->fts_statb.st_uid;
+               if (uid < MAXUID && ++u[uid] > maxuid) {
+                       saveuid = uid;
+                       maxuid = u[uid];
+               }
+               if (p->fts_namelen > 7)
+                       *tabs = 2;
+       }
+       (void)printf("\n/set group=%u mode=%#o nlink=1 owner=%u type=file\n",
+           savegid, savemode, saveuid);
+       *puid = saveuid;
+       *pgid = savegid;
+       *pmode = savemode;
+       return(0);
 }
 
 }
 
-shostats()
+dsort(p1, p2)
+       FTSENT **p1, **p2;
 {
 {
-       register ID *p;
-       register mode_t cnt;
-       register u_long max;
+       register FTSENT *a, *b;
 
 
-       for (max = 0, cnt = 0777; cnt; --cnt)
-               if (dmodes[cnt] > max) {
-                       max = dmodes[cnt];
-                       dmode = cnt;
-               }
-       (void)printf("/set dmode=%o\n", dmode);
-       for (max = 0, cnt = 0777; cnt; --cnt)
-               if (fmodes[cnt] > max) {
-                       max = dmodes[cnt];
-                       fmode = cnt;
-               }
-       (void)printf("/set fmode=%o\n", fmode);
-       for (max = 0, p = uhead; p; p = p->next)
-               if (p->cnt > max) {
-                       max = p->cnt;
-                       uid = p->id;
-               }
-       (void)printf("/set owner=%u\n", uid);
-       for (max = 0, p = ghead; p; p = p->next)
-               if (p->cnt > max) {
-                       max = p->cnt;
-                       gid = p->id;
-               }
-       (void)printf("/set group=%u\n", gid);
-       (void)printf("/set nlink=1\n");
-       if (dflag) {
-               type = F_DIR;
-               (void)printf("/set type=dir\n\n");
-       } else {
-               type = F_FILE;
-               (void)printf("/set type=file\n\n");
-       }
+       a = *p1;
+       b = *p2;
+
+       if (S_ISDIR(a->fts_statb.st_mode)) {
+               if (!S_ISDIR(b->fts_statb.st_mode))
+                       return(1);
+       } else if (S_ISDIR(b->fts_statb.st_mode))
+               return(-1);
+       return(strcmp(a->fts_name, b->fts_name));
 }
 }