create.c revision 8857
1/*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 36#endif /* not lint */ 37 38#include <sys/param.h> 39#include <sys/stat.h> 40#include <time.h> 41#include <fcntl.h> 42#include <fts.h> 43#include <dirent.h> 44#include <grp.h> 45#include <pwd.h> 46#include <errno.h> 47#include <unistd.h> 48#include <stdio.h> 49#include <md5.h> 50#include "mtree.h" 51#include "extern.h" 52 53#define INDENTNAMELEN 15 54#define MAXLINELEN 80 55 56extern long int crc_total; 57extern int ftsoptions; 58extern int dflag, iflag, nflag, sflag; 59extern u_short keys; 60extern char fullpath[MAXPATHLEN]; 61 62static gid_t gid; 63static uid_t uid; 64static mode_t mode; 65 66static int dsort __P((const FTSENT **, const FTSENT **)); 67static void output __P((int, int *, const char *, ...)); 68static int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *)); 69static void statf __P((int, FTSENT *)); 70 71void 72cwalk() 73{ 74 register FTS *t; 75 register FTSENT *p; 76 time_t clock; 77 char *argv[2], host[MAXHOSTNAMELEN]; 78 int indent = 0; 79 80 (void)time(&clock); 81 (void)gethostname(host, sizeof(host)); 82 (void)printf( 83 "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", 84 getlogin(), host, fullpath, ctime(&clock)); 85 86 argv[0] = "."; 87 argv[1] = NULL; 88 if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) 89 err("fts_open: %s", strerror(errno)); 90 while ((p = fts_read(t))) { 91 if (iflag) 92 indent = p->fts_level * 4; 93 switch(p->fts_info) { 94 case FTS_D: 95 if (!dflag) 96 (void)printf("\n"); 97 if (!nflag) 98 (void)printf("# %s\n", p->fts_path); 99 statd(t, p, &uid, &gid, &mode); 100 statf(indent, p); 101 break; 102 case FTS_DP: 103 if (!nflag && (p->fts_level > 0)) 104 (void)printf("%*s# %s\n", indent, "", p->fts_path); 105 (void)printf("%*s..\n", indent, ""); 106 if (!dflag) 107 (void)printf("\n"); 108 break; 109 case FTS_DNR: 110 case FTS_ERR: 111 case FTS_NS: 112 (void)fprintf(stderr, 113 "mtree: %s: %s\n", p->fts_path, strerror(errno)); 114 break; 115 default: 116 if (!dflag) 117 statf(indent, p); 118 break; 119 120 } 121 } 122 (void)fts_close(t); 123 if (sflag && keys & F_CKSUM) 124 (void)fprintf(stderr, 125 "mtree: %s checksum: %lu\n", fullpath, crc_total); 126} 127 128static void 129statf(indent, p) 130 int indent; 131 FTSENT *p; 132{ 133 struct group *gr; 134 struct passwd *pw; 135 u_long len, val; 136 int fd, offset; 137 138 if (iflag || S_ISDIR(p->fts_statp->st_mode)) 139 offset = printf("%*s%s", indent, "", p->fts_name); 140 else 141 offset = printf("%*s %s", indent, "", p->fts_name); 142 143 if (offset > (INDENTNAMELEN + indent)) 144 offset = MAXLINELEN; 145 else 146 offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); 147 148 if (!S_ISREG(p->fts_statp->st_mode) && !dflag) 149 output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); 150 if (p->fts_statp->st_uid != uid) { 151 if (keys & F_UNAME) { 152 if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) { 153 output(indent, &offset, "uname=%s", pw->pw_name); 154 } else { 155 err("could not get uname for uid=%u", 156 p->fts_statp->st_uid); 157 } 158 } 159 if (keys & F_UID) 160 output(indent, &offset, "uid=%u", p->fts_statp->st_uid); 161 } 162 if (p->fts_statp->st_gid != gid) { 163 if (keys & F_GNAME) { 164 if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) { 165 output(indent, &offset, "gname=%s", gr->gr_name); 166 } else { 167 err("could not get gname for gid=%u", 168 p->fts_statp->st_gid); 169 } 170 } 171 if (keys & F_GID) 172 output(indent, &offset, "gid=%u", p->fts_statp->st_gid); 173 } 174 if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 175 output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS); 176 if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 177 output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); 178 if (keys & F_SIZE) 179 output(indent, &offset, "size=%qd", p->fts_statp->st_size); 180 if (keys & F_TIME) 181 output(indent, &offset, "time=%ld.%ld", 182 p->fts_statp->st_mtimespec.ts_sec, 183 p->fts_statp->st_mtimespec.ts_nsec); 184 if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 185 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 186 crc(fd, &val, &len)) 187 err("%s: %s", p->fts_accpath, strerror(errno)); 188 (void)close(fd); 189 output(indent, &offset, "cksum=%lu", val); 190 } 191 if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 192 char *md5digest = MD5File(p->fts_accpath); 193 194 if (!md5digest) { 195 err("%s: %s", p->fts_accpath, strerror(errno)); 196 } else { 197 output(indent, &offset, "md5digest=%s", md5digest); 198 free(md5digest); 199 } 200 } 201 if (keys & F_SLINK && 202 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 203 output(indent, &offset, "link=%s", rlink(p->fts_accpath)); 204 (void)putchar('\n'); 205} 206 207#define MAXGID 5000 208#define MAXUID 5000 209#define MAXMODE MBITS + 1 210 211static int 212statd(t, parent, puid, pgid, pmode) 213 FTS *t; 214 FTSENT *parent; 215 uid_t *puid; 216 gid_t *pgid; 217 mode_t *pmode; 218{ 219 register FTSENT *p; 220 register gid_t sgid; 221 register uid_t suid; 222 register mode_t smode; 223 struct group *gr; 224 struct passwd *pw; 225 gid_t savegid = *pgid; 226 uid_t saveuid = *puid; 227 mode_t savemode = *pmode; 228 u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE]; 229 static int first = 1; 230 231 if ((p = fts_children(t, 0)) == NULL) { 232 if (errno) 233 err("%s: %s", RP(parent), strerror(errno)); 234 return (1); 235 } 236 237 bzero(g, sizeof(g)); 238 bzero(u, sizeof(u)); 239 bzero(m, sizeof(m)); 240 241 maxuid = maxgid = maxmode = 0; 242 for (; p; p = p->fts_link) { 243 if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) { 244 smode = p->fts_statp->st_mode & MBITS; 245 if (smode < MAXMODE && ++m[smode] > maxmode) { 246 savemode = smode; 247 maxmode = m[smode]; 248 } 249 sgid = p->fts_statp->st_gid; 250 if (sgid < MAXGID && ++g[sgid] > maxgid) { 251 savegid = sgid; 252 maxgid = g[sgid]; 253 } 254 suid = p->fts_statp->st_uid; 255 if (suid < MAXUID && ++u[suid] > maxuid) { 256 saveuid = suid; 257 maxuid = u[suid]; 258 } 259 } 260 } 261 /* 262 * If the /set record is the same as the last one we do not need to output 263 * a new one. So first we check to see if anything changed. Note that we 264 * always output a /set record for the first directory. 265 */ 266 if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) || 267 (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) || 268 ((keys & F_MODE) && (*pmode != savemode)) || (first)) { 269 first = 0; 270 if (dflag) 271 (void)printf("/set type=dir"); 272 else 273 (void)printf("/set type=file"); 274 if (keys & F_UNAME) 275 if ((pw = getpwuid(saveuid)) != NULL) 276 (void)printf(" uname=%s", pw->pw_name); 277 else 278 err("could not get uname for uid=%u", saveuid); 279 if (keys & F_UID) 280 (void)printf(" uid=%lu", saveuid); 281 if (keys & F_GNAME) 282 if ((gr = getgrgid(savegid)) != NULL) 283 (void)printf(" gname=%s", gr->gr_name); 284 else 285 err("could not get gname for gid=%u", savegid); 286 if (keys & F_GID) 287 (void)printf(" gid=%lu", savegid); 288 if (keys & F_MODE) 289 (void)printf(" mode=%#o", savemode); 290 if (keys & F_NLINK) 291 (void)printf(" nlink=1"); 292 (void)printf("\n"); 293 *puid = saveuid; 294 *pgid = savegid; 295 *pmode = savemode; 296 } 297 return (0); 298} 299 300static int 301dsort(a, b) 302 const FTSENT **a, **b; 303{ 304 if (S_ISDIR((*a)->fts_statp->st_mode)) { 305 if (!S_ISDIR((*b)->fts_statp->st_mode)) 306 return (1); 307 } else if (S_ISDIR((*b)->fts_statp->st_mode)) 308 return (-1); 309 return (strcmp((*a)->fts_name, (*b)->fts_name)); 310} 311 312#if __STDC__ 313#include <stdarg.h> 314#else 315#include <varargs.h> 316#endif 317 318void 319#if __STDC__ 320output(int indent, int *offset, const char *fmt, ...) 321#else 322output(indent, offset, fmt, va_alist) 323 int indent; 324 int *offset; 325 char *fmt; 326 va_dcl 327#endif 328{ 329 va_list ap; 330 char buf[1024]; 331#if __STDC__ 332 va_start(ap, fmt); 333#else 334 va_start(ap); 335#endif 336 (void)vsnprintf(buf, sizeof(buf), fmt, ap); 337 va_end(ap); 338 339 if (*offset + strlen(buf) > MAXLINELEN - 3) { 340 (void)printf(" \\\n%*s", INDENTNAMELEN + indent, ""); 341 *offset = INDENTNAMELEN + indent; 342 } 343 *offset += printf(" %s", buf) + 1; 344} 345