1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)mtree.c 5.3 (Berkeley) 09/06/89"; 26 #endif /* not lint */ 27 28 #include <sys/param.h> 29 #include <sys/stat.h> 30 #include <dirent.h> 31 #include <stdio.h> 32 #include <strings.h> 33 #include "mtree.h" 34 35 extern int errno; 36 ENTRY *root; 37 dev_t device; 38 int cflag, dflag, eflag, rflag, uflag, xflag, exitval; 39 char path[MAXPATHLEN]; 40 41 main(argc, argv) 42 int argc; 43 char **argv; 44 { 45 extern char *optarg; 46 struct stat sbuf; 47 int ch; 48 char *p; 49 50 p = NULL; 51 while ((ch = getopt(argc, argv, "cdef:p:rux")) != EOF) 52 switch((char)ch) { 53 case 'c': 54 cflag = 1; 55 break; 56 case 'd': 57 dflag = 1; 58 break; 59 case 'e': 60 eflag = 1; 61 break; 62 case 'f': 63 if (!(freopen(optarg, "r", stdin))) { 64 (void)fprintf(stderr, 65 "mtree: can't read %s.\n", optarg); 66 exit(1); 67 } 68 break; 69 case 'p': 70 p = optarg; 71 break; 72 case 'r': 73 rflag = 1; 74 break; 75 case 'u': 76 uflag = 1; 77 break; 78 case 'x': 79 xflag = 1; 80 break; 81 case '?': 82 default: 83 (void)fprintf(stderr, 84 "usage: mtree [-cderux] [-p path] [-f spec]\n"); 85 exit(1); 86 } 87 if (!cflag) 88 spec(); 89 if (p && chdir(p)) { 90 (void)fprintf(stderr, 91 "mtree: %s: %s\n", p, strerror(errno)); 92 exit(1); 93 } 94 path[0] = '.'; 95 if (cflag) { 96 headers(); 97 cwalk((ENTRY *)NULL, path + 1); 98 shostats(); 99 pwalk(root, 0); 100 } else { 101 if (xflag) { 102 if (lstat(".", &sbuf)) { 103 (void)fprintf(stderr, "mtree: root: %s\n", 104 strerror(errno)); 105 exit(1); 106 } 107 device = sbuf.st_dev; 108 } 109 vwalk(root, path + 1); 110 miss(root, path + 1); 111 } 112 exit(exitval); 113 } 114 115 vwalk(level, tail) 116 register ENTRY *level; 117 register char *tail; 118 { 119 register ENTRY *ep; 120 register DIR *dirp; 121 register struct dirent *dp; 122 struct stat sbuf; 123 124 if (!(dirp = opendir("."))) { 125 (void)fprintf(stderr, "mtree: %s: %s\n", 126 level == root ? "root" : path, strerror(errno)); 127 exit(1); 128 } 129 *tail++ = '/'; 130 while ((dp = readdir(dirp))) { 131 if (dp->d_name[0] == '.' && 132 (!dp->d_name[1] || dp->d_name[1] == '.' && !dp->d_name[2])) 133 continue; 134 bcopy(dp->d_name, tail, dp->d_namlen + 1); 135 for (ep = level; ep; ep = ep->next) 136 if (!strcmp(ep->name, dp->d_name)) 137 break; 138 if (ep && ep->flags&F_IGN) { 139 ep->flags |= F_VISIT; 140 continue; 141 } 142 if (lstat(dp->d_name, &sbuf)) { 143 (void)fprintf(stderr, "mtree: %s: %s\n", 144 path + 2, strerror(errno)); 145 exit(1); 146 } 147 if (!dflag || S_ISDIR(sbuf.st_mode)) 148 if (ep) { 149 compare(ep->name, &ep->info, &sbuf); 150 ep->flags |= F_VISIT; 151 } else if (!eflag) { 152 (void)printf("extra: %s%s", 153 path + 2, rflag ? "" : "\n"); 154 if (rflag) 155 if (unlink(path)) 156 (void)printf(", not removed: %s\n", 157 strerror(errno)); 158 else 159 (void)printf(", removed\n"); 160 } 161 if (S_ISDIR(sbuf.st_mode) && 162 (!xflag || device == sbuf.st_dev)) { 163 if (chdir(dp->d_name)) { 164 (void)fprintf(stderr, "mtree: %s: %s\n", 165 path + 2, strerror(errno)); 166 exit(1); 167 } 168 vwalk(ep ? ep->child : ep, tail + dp->d_namlen); 169 if (chdir("..")) { 170 (void)fprintf(stderr, "mtree: ..: %s\n", 171 strerror(errno)); 172 exit(1); 173 } 174 } 175 } 176 (void)closedir(dirp); 177 } 178 179 miss(level, tail) 180 register ENTRY *level; 181 register char *tail; 182 { 183 register int create; 184 register char *p; 185 186 for (*tail++ = '/'; level; level = level->next) { 187 if (level->info.type != F_DIR && 188 (dflag || level->flags&F_VISIT)) 189 continue; 190 (void)strcpy(tail, level->name); 191 if (!(level->flags&F_VISIT)) 192 (void)printf("missing: %s%s", path + 2, 193 uflag ? "" : "\n"); 194 if (level->info.type != F_DIR) 195 continue; 196 create = 0; 197 if (uflag) 198 if (mkdir(path, 0777)) 199 (void)printf(" (not created: %s)\n", 200 strerror(errno)); 201 else { 202 create = 1; 203 (void)printf(" (created)\n"); 204 } 205 for (p = tail; *p; ++p); 206 miss(level->child, p); 207 if (create) { 208 *p = '\0'; 209 dirset(&level->info); 210 } 211 } 212 } 213 214 dirset(s1) 215 register INFO *s1; 216 { 217 extern int errno; 218 register struct stat *s2; 219 struct stat sbuf; 220 221 if (stat(path, &sbuf)) { 222 (void)fprintf(stderr, 223 "mtree: %s: %s\n", path, strerror(errno)); 224 return; 225 } 226 s2 = &sbuf; 227 228 if (s1->flags&F_MODE && s1->st_mode != (s2->st_mode&07777) && 229 chmod(path, s1->st_mode)) 230 (void)printf("%s: permissions not set: %s\n", 231 path + 2, strerror(errno)); 232 if (s1->flags&F_OWNER && s1->st_uid != s2->st_uid && 233 chown(path, s1->st_uid, -1)) 234 (void)printf("%s: owner not modified: %s\n", 235 path + 2, strerror(errno)); 236 if (s1->flags&F_GROUP && s1->st_gid != s2->st_gid && 237 chown(path, -1, s1->st_gid)) 238 (void)printf("%s: group not modified: %s\n", 239 path + 2, strerror(errno)); 240 } 241