1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved 24*7c478bd9Sstevel@tonic-gate * 25*7c478bd9Sstevel@tonic-gate * module: 26*7c478bd9Sstevel@tonic-gate * base.c 27*7c478bd9Sstevel@tonic-gate * 28*7c478bd9Sstevel@tonic-gate * purpose: 29*7c478bd9Sstevel@tonic-gate * routines to create, traverse, read and write the baseline database 30*7c478bd9Sstevel@tonic-gate * 31*7c478bd9Sstevel@tonic-gate * contents: 32*7c478bd9Sstevel@tonic-gate * manipulation: 33*7c478bd9Sstevel@tonic-gate * add_base, add_file_to_base, add_file_to_dir 34*7c478bd9Sstevel@tonic-gate * (static) add_file_to_list 35*7c478bd9Sstevel@tonic-gate * reading baseline: 36*7c478bd9Sstevel@tonic-gate * read_baseline 37*7c478bd9Sstevel@tonic-gate * (static) gettype 38*7c478bd9Sstevel@tonic-gate * writing baseline: 39*7c478bd9Sstevel@tonic-gate * write_baseline 40*7c478bd9Sstevel@tonic-gate * (static) bw_header, bw_base, bw_file, showtype 41*7c478bd9Sstevel@tonic-gate */ 42*7c478bd9Sstevel@tonic-gate #ident "%W% %E% SMI" 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 45*7c478bd9Sstevel@tonic-gate #include <stdio.h> 46*7c478bd9Sstevel@tonic-gate #include <string.h> 47*7c478bd9Sstevel@tonic-gate #include <time.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #include "filesync.h" 50*7c478bd9Sstevel@tonic-gate #include "database.h" 51*7c478bd9Sstevel@tonic-gate #include "messages.h" 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #define BASE_MAJOR 1 /* base file format major rev */ 54*7c478bd9Sstevel@tonic-gate #define BASE_MINOR 2 /* base file format minor rev */ 55*7c478bd9Sstevel@tonic-gate #define BASE_TAG "filesync-BaseLine" 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate /* 58*7c478bd9Sstevel@tonic-gate * globals 59*7c478bd9Sstevel@tonic-gate */ 60*7c478bd9Sstevel@tonic-gate struct base omnibase; /* dummy to hold global rules */ 61*7c478bd9Sstevel@tonic-gate struct base *bases; /* pointer to the base list */ 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* 64*7c478bd9Sstevel@tonic-gate * locals 65*7c478bd9Sstevel@tonic-gate */ 66*7c478bd9Sstevel@tonic-gate static int num_bases; /* used to generate sequence #s */ 67*7c478bd9Sstevel@tonic-gate static errmask_t bw_header(FILE *); /* write out baseline header */ 68*7c478bd9Sstevel@tonic-gate static errmask_t bw_base(FILE *, struct base *); /* write out one base */ 69*7c478bd9Sstevel@tonic-gate static errmask_t bw_file(FILE *, struct file *, int); 70*7c478bd9Sstevel@tonic-gate static struct file *add_file_to_list(struct file **, const char *); 71*7c478bd9Sstevel@tonic-gate static char showtype(int); 72*7c478bd9Sstevel@tonic-gate static long gettype(int); 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * routine: 76*7c478bd9Sstevel@tonic-gate * add_base 77*7c478bd9Sstevel@tonic-gate * 78*7c478bd9Sstevel@tonic-gate * purpose: 79*7c478bd9Sstevel@tonic-gate * to find a base pair in the chain, adding it if necessary 80*7c478bd9Sstevel@tonic-gate * 81*7c478bd9Sstevel@tonic-gate * parameters: 82*7c478bd9Sstevel@tonic-gate * spec for source directory 83*7c478bd9Sstevel@tonic-gate * spec for dest directory 84*7c478bd9Sstevel@tonic-gate * 85*7c478bd9Sstevel@tonic-gate * returns: 86*7c478bd9Sstevel@tonic-gate * pointer to the base pair 87*7c478bd9Sstevel@tonic-gate * 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate struct base * 90*7c478bd9Sstevel@tonic-gate add_base(const char *src, const char *dst) 91*7c478bd9Sstevel@tonic-gate { struct base *bp, **bpp; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* first see if we already have it */ 94*7c478bd9Sstevel@tonic-gate for (bpp = &bases; (bp = *bpp) != 0; bpp = &bp->b_next) { 95*7c478bd9Sstevel@tonic-gate /* base must match on both src and dst */ 96*7c478bd9Sstevel@tonic-gate if (strcmp(src, bp->b_src_spec)) 97*7c478bd9Sstevel@tonic-gate continue; 98*7c478bd9Sstevel@tonic-gate if (strcmp(dst, bp->b_dst_spec)) 99*7c478bd9Sstevel@tonic-gate continue; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_BASE) 102*7c478bd9Sstevel@tonic-gate fprintf(stderr, "BASE: FOUND base=%d, src=%s, dst=%s\n", 103*7c478bd9Sstevel@tonic-gate bp->b_ident, src, dst); 104*7c478bd9Sstevel@tonic-gate return (bp); 105*7c478bd9Sstevel@tonic-gate } 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* no joy, so we have to allocate one */ 108*7c478bd9Sstevel@tonic-gate bp = malloc(sizeof (struct base)); 109*7c478bd9Sstevel@tonic-gate if (bp == 0) 110*7c478bd9Sstevel@tonic-gate nomem("base structure"); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* initialize the new base */ 113*7c478bd9Sstevel@tonic-gate memset((void *) bp, 0, sizeof (struct base)); 114*7c478bd9Sstevel@tonic-gate bp->b_ident = ++num_bases; 115*7c478bd9Sstevel@tonic-gate bp->b_src_spec = strdup(src); 116*7c478bd9Sstevel@tonic-gate bp->b_dst_spec = strdup(dst); 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* names are expanded at run-time, and this is run-time */ 119*7c478bd9Sstevel@tonic-gate if ((bp->b_src_name = expand(bp->b_src_spec)) == 0) { 120*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_badbase), bp->b_src_spec); 121*7c478bd9Sstevel@tonic-gate exit(ERR_FILES); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate if ((bp->b_dst_name = expand(bp->b_dst_spec)) == 0) { 125*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_badbase), bp->b_dst_spec); 126*7c478bd9Sstevel@tonic-gate exit(ERR_FILES); 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* chain it in */ 130*7c478bd9Sstevel@tonic-gate *bpp = bp; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_BASE) 133*7c478bd9Sstevel@tonic-gate fprintf(stderr, "BASE: ADDED base=%d, src=%s, dst=%s\n", 134*7c478bd9Sstevel@tonic-gate bp->b_ident, src, dst); 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate return (bp); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* 140*7c478bd9Sstevel@tonic-gate * routine: 141*7c478bd9Sstevel@tonic-gate * add_file_to_list 142*7c478bd9Sstevel@tonic-gate * 143*7c478bd9Sstevel@tonic-gate * purpose: 144*7c478bd9Sstevel@tonic-gate * to find a file on a list, or if necessary add it to the list 145*7c478bd9Sstevel@tonic-gate * 146*7c478bd9Sstevel@tonic-gate * this is an internal routine, used only by add_file_to_base 147*7c478bd9Sstevel@tonic-gate * and add_file_to_dir. 148*7c478bd9Sstevel@tonic-gate * 149*7c478bd9Sstevel@tonic-gate * parameters: 150*7c478bd9Sstevel@tonic-gate * pointer to the list head 151*7c478bd9Sstevel@tonic-gate * 152*7c478bd9Sstevel@tonic-gate * returns: 153*7c478bd9Sstevel@tonic-gate * pointer to a file structure 154*7c478bd9Sstevel@tonic-gate * 155*7c478bd9Sstevel@tonic-gate * notes: 156*7c478bd9Sstevel@tonic-gate * 157*7c478bd9Sstevel@tonic-gate * list is sorted to provide some search optimization 158*7c478bd9Sstevel@tonic-gate * 159*7c478bd9Sstevel@tonic-gate * most files are in the baseline, and so come in in alphabetical 160*7c478bd9Sstevel@tonic-gate * order. If we keep a guess pointer to the last file we added/found, 161*7c478bd9Sstevel@tonic-gate * there is a better than even chance that this one should be 162*7c478bd9Sstevel@tonic-gate * added immediately onto the end of it ... and in so doing we 163*7c478bd9Sstevel@tonic-gate * can save ourselves the trouble of searching the lists most 164*7c478bd9Sstevel@tonic-gate * of the time. 165*7c478bd9Sstevel@tonic-gate * 166*7c478bd9Sstevel@tonic-gate * this win would be even better if the FTW traversal was sorted, 167*7c478bd9Sstevel@tonic-gate * but building the baseline is enough of a win to justify the 168*7c478bd9Sstevel@tonic-gate * feature ... but even without this we run a 60%-70% hit rate. 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate static struct file * 171*7c478bd9Sstevel@tonic-gate add_file_to_list(struct file **pp, const char *name) 172*7c478bd9Sstevel@tonic-gate { struct file *fp, *new; 173*7c478bd9Sstevel@tonic-gate int rslt; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate static struct file **last_list; 176*7c478bd9Sstevel@tonic-gate static struct file *last_file; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* 179*7c478bd9Sstevel@tonic-gate * start with the guess pointer, we hope to find that 180*7c478bd9Sstevel@tonic-gate * this request will be satisfied by the next file in 181*7c478bd9Sstevel@tonic-gate * the list. The two cases we are trying to optimize 182*7c478bd9Sstevel@tonic-gate * are: 183*7c478bd9Sstevel@tonic-gate * appending to the list, with appends in alphabetical order 184*7c478bd9Sstevel@tonic-gate * searches of the list, with searches in alphabetical order 185*7c478bd9Sstevel@tonic-gate */ 186*7c478bd9Sstevel@tonic-gate if (last_list == pp && (new = last_file) != 0) { 187*7c478bd9Sstevel@tonic-gate /* we like to think we belong farther down-list */ 188*7c478bd9Sstevel@tonic-gate if (strcmp(name, new->f_name) > 0) { 189*7c478bd9Sstevel@tonic-gate fp = new->f_next; 190*7c478bd9Sstevel@tonic-gate /* if we're at the end, we just won */ 191*7c478bd9Sstevel@tonic-gate if (fp == 0) { 192*7c478bd9Sstevel@tonic-gate pp = &new->f_next; 193*7c478bd9Sstevel@tonic-gate goto makeit; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* or if the next one is what we want */ 197*7c478bd9Sstevel@tonic-gate if (strcmp(name, fp->f_name) == 0) { 198*7c478bd9Sstevel@tonic-gate fp->f_flags &= ~F_NEW; 199*7c478bd9Sstevel@tonic-gate new = fp; 200*7c478bd9Sstevel@tonic-gate goto gotit; 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate /* 206*7c478bd9Sstevel@tonic-gate * our guess pointer failed, so it is exhaustive search time 207*7c478bd9Sstevel@tonic-gate */ 208*7c478bd9Sstevel@tonic-gate last_list = pp; 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate for (fp = *pp; fp; pp = &fp->f_next, fp = *pp) { 211*7c478bd9Sstevel@tonic-gate rslt = strcmp(name, fp->f_name); 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate /* see if we got a match */ 214*7c478bd9Sstevel@tonic-gate if (rslt == 0) { 215*7c478bd9Sstevel@tonic-gate fp->f_flags &= ~F_NEW; 216*7c478bd9Sstevel@tonic-gate new = fp; 217*7c478bd9Sstevel@tonic-gate goto gotit; 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* see if we should go no farther */ 221*7c478bd9Sstevel@tonic-gate if (rslt < 0) 222*7c478bd9Sstevel@tonic-gate break; 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate makeit: 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * we didn't find it: 228*7c478bd9Sstevel@tonic-gate * pp points at where our pointer should go 229*7c478bd9Sstevel@tonic-gate * fp points at the node after ours 230*7c478bd9Sstevel@tonic-gate */ 231*7c478bd9Sstevel@tonic-gate new = (struct file *) malloc(sizeof (*new)); 232*7c478bd9Sstevel@tonic-gate if (new == 0) 233*7c478bd9Sstevel@tonic-gate nomem("file structure"); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate /* initialize the new node */ 236*7c478bd9Sstevel@tonic-gate memset((void *) new, 0, sizeof (struct file)); 237*7c478bd9Sstevel@tonic-gate new->f_name = strdup(name); 238*7c478bd9Sstevel@tonic-gate new->f_flags = F_NEW; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate /* chain it into the list */ 241*7c478bd9Sstevel@tonic-gate new->f_next = fp; 242*7c478bd9Sstevel@tonic-gate *pp = new; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate gotit: /* remember this as our next guess pointer */ 245*7c478bd9Sstevel@tonic-gate last_file = new; 246*7c478bd9Sstevel@tonic-gate return (new); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * routine: 251*7c478bd9Sstevel@tonic-gate * add_file_to_base 252*7c478bd9Sstevel@tonic-gate * 253*7c478bd9Sstevel@tonic-gate * purpose: 254*7c478bd9Sstevel@tonic-gate * to add a file-node to a baseline 255*7c478bd9Sstevel@tonic-gate * 256*7c478bd9Sstevel@tonic-gate * parameters: 257*7c478bd9Sstevel@tonic-gate * pointer to base 258*7c478bd9Sstevel@tonic-gate * name of file to be added 259*7c478bd9Sstevel@tonic-gate * 260*7c478bd9Sstevel@tonic-gate * returns: 261*7c478bd9Sstevel@tonic-gate * pointer to file structure 262*7c478bd9Sstevel@tonic-gate */ 263*7c478bd9Sstevel@tonic-gate struct file * 264*7c478bd9Sstevel@tonic-gate add_file_to_base(struct base *bp, const char *name) 265*7c478bd9Sstevel@tonic-gate { struct file *fp; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate fp = add_file_to_list(&bp->b_files, name); 268*7c478bd9Sstevel@tonic-gate fp->f_base = bp; 269*7c478bd9Sstevel@tonic-gate fp->f_depth = 0; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_LIST) 272*7c478bd9Sstevel@tonic-gate fprintf(stderr, "LIST: base=%d, %s file=%s\n", 273*7c478bd9Sstevel@tonic-gate bp->b_ident, (fp->f_flags&F_NEW) ? "NEW" : "FOUND", 274*7c478bd9Sstevel@tonic-gate name); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate return (fp); 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate /* 280*7c478bd9Sstevel@tonic-gate * routine: 281*7c478bd9Sstevel@tonic-gate * add_file_to_dir 282*7c478bd9Sstevel@tonic-gate * 283*7c478bd9Sstevel@tonic-gate * purpose: 284*7c478bd9Sstevel@tonic-gate * to add a file-node to a directory 285*7c478bd9Sstevel@tonic-gate * 286*7c478bd9Sstevel@tonic-gate * parameters: 287*7c478bd9Sstevel@tonic-gate * pointer to file entry for directory 288*7c478bd9Sstevel@tonic-gate * name of file to be added 289*7c478bd9Sstevel@tonic-gate * 290*7c478bd9Sstevel@tonic-gate * returns: 291*7c478bd9Sstevel@tonic-gate * pointer to file structure 292*7c478bd9Sstevel@tonic-gate */ 293*7c478bd9Sstevel@tonic-gate struct file * 294*7c478bd9Sstevel@tonic-gate add_file_to_dir(struct file *dp, const char *name) 295*7c478bd9Sstevel@tonic-gate { struct file *fp; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate fp = add_file_to_list(&dp->f_files, name); 298*7c478bd9Sstevel@tonic-gate fp->f_base = dp->f_base; 299*7c478bd9Sstevel@tonic-gate fp->f_depth = dp->f_depth + 1; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_LIST) 302*7c478bd9Sstevel@tonic-gate fprintf(stderr, "LIST: dir=%s, %s file=%s\n", 303*7c478bd9Sstevel@tonic-gate dp->f_name, (fp->f_flags&F_NEW) ? "NEW" : "FOUND", 304*7c478bd9Sstevel@tonic-gate name); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate return (fp); 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* 310*7c478bd9Sstevel@tonic-gate * routine: 311*7c478bd9Sstevel@tonic-gate * read_baseline 312*7c478bd9Sstevel@tonic-gate * 313*7c478bd9Sstevel@tonic-gate * purpose: 314*7c478bd9Sstevel@tonic-gate * to read in the baseline file 315*7c478bd9Sstevel@tonic-gate * 316*7c478bd9Sstevel@tonic-gate * parameters: 317*7c478bd9Sstevel@tonic-gate * name of baseline file 318*7c478bd9Sstevel@tonic-gate * 319*7c478bd9Sstevel@tonic-gate * returns: 320*7c478bd9Sstevel@tonic-gate * error mask 321*7c478bd9Sstevel@tonic-gate */ 322*7c478bd9Sstevel@tonic-gate errmask_t 323*7c478bd9Sstevel@tonic-gate read_baseline(char *name) 324*7c478bd9Sstevel@tonic-gate { FILE *file; 325*7c478bd9Sstevel@tonic-gate errmask_t errs = 0; 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate char *s; 328*7c478bd9Sstevel@tonic-gate char *s1 = 0; 329*7c478bd9Sstevel@tonic-gate char type; 330*7c478bd9Sstevel@tonic-gate char *field = "???"; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate unsigned long l; 333*7c478bd9Sstevel@tonic-gate unsigned long long ll; /* intermediate for 64 bit file support */ 334*7c478bd9Sstevel@tonic-gate int level; 335*7c478bd9Sstevel@tonic-gate int major, minor; 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate struct base *bp = 0; 338*7c478bd9Sstevel@tonic-gate struct file *fp; 339*7c478bd9Sstevel@tonic-gate struct fileinfo *ip; 340*7c478bd9Sstevel@tonic-gate aclent_t *ap; 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate struct file *dirstack[ MAX_DEPTH ]; 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate file = fopen(name, "r"); 345*7c478bd9Sstevel@tonic-gate if (file == NULL) { 346*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_open), gettext(TXT_base), 347*7c478bd9Sstevel@tonic-gate name); 348*7c478bd9Sstevel@tonic-gate return (ERR_FILES); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate lex_linenum = 0; 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_FILES) 353*7c478bd9Sstevel@tonic-gate fprintf(stderr, "FILE: READ BASELINE %s\n", name); 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate while (!feof(file)) { 356*7c478bd9Sstevel@tonic-gate /* find the first token on the line */ 357*7c478bd9Sstevel@tonic-gate s = lex(file); 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate /* skip blank lines and comments */ 360*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0 || *s == '#' || *s == '*') 361*7c478bd9Sstevel@tonic-gate continue; 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate field = "keyword"; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* see if the first token is a known keyword */ 366*7c478bd9Sstevel@tonic-gate if (strcmp(s, "VERSION") == 0 || strcmp(s, BASE_TAG) == 0) { 367*7c478bd9Sstevel@tonic-gate s = lex(0); 368*7c478bd9Sstevel@tonic-gate field = gettext(TXT_noargs); 369*7c478bd9Sstevel@tonic-gate if (s == 0) 370*7c478bd9Sstevel@tonic-gate goto bad; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate major = strtol(s, &s1, 10); 373*7c478bd9Sstevel@tonic-gate field = gettext(TXT_badver); 374*7c478bd9Sstevel@tonic-gate if (*s1 != '.') 375*7c478bd9Sstevel@tonic-gate goto bad; 376*7c478bd9Sstevel@tonic-gate minor = strtol(&s1[1], 0, 10); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate if (major != BASE_MAJOR || minor > BASE_MINOR) { 379*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_badver), 380*7c478bd9Sstevel@tonic-gate major, minor, gettext(TXT_base), name); 381*7c478bd9Sstevel@tonic-gate errs |= ERR_FILES; 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate s1 = 0; 384*7c478bd9Sstevel@tonic-gate continue; 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate if (strcmp(s, "BASE_SRC") == 0) { 388*7c478bd9Sstevel@tonic-gate s = lex(0); 389*7c478bd9Sstevel@tonic-gate field = "source directory"; 390*7c478bd9Sstevel@tonic-gate if (s == 0) 391*7c478bd9Sstevel@tonic-gate goto bad; 392*7c478bd9Sstevel@tonic-gate s1 = strdup(s); 393*7c478bd9Sstevel@tonic-gate bp = 0; 394*7c478bd9Sstevel@tonic-gate continue; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate if (strcmp(s, "BASE_DST") == 0) { 398*7c478bd9Sstevel@tonic-gate s = lex(0); 399*7c478bd9Sstevel@tonic-gate field = "destination directory"; 400*7c478bd9Sstevel@tonic-gate if (s == 0) 401*7c478bd9Sstevel@tonic-gate goto bad; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate /* make sure we have a source too */ 404*7c478bd9Sstevel@tonic-gate if (s1 == 0) { 405*7c478bd9Sstevel@tonic-gate field = "no source directory"; 406*7c478bd9Sstevel@tonic-gate goto bad; 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate bp = add_base(s1, s); 410*7c478bd9Sstevel@tonic-gate free(s1); 411*7c478bd9Sstevel@tonic-gate s1 = 0; 412*7c478bd9Sstevel@tonic-gate continue; 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate if (strcmp(s, "FILE") == 0) { 416*7c478bd9Sstevel@tonic-gate /* make sure we have a base to add to */ 417*7c478bd9Sstevel@tonic-gate if (bp == 0) { 418*7c478bd9Sstevel@tonic-gate field = "missing base"; 419*7c478bd9Sstevel@tonic-gate goto bad; 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate s = lex(0); /* level */ 423*7c478bd9Sstevel@tonic-gate field = "level"; 424*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 425*7c478bd9Sstevel@tonic-gate goto bad; 426*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 427*7c478bd9Sstevel@tonic-gate level = l; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate s = lex(0); /* type */ 430*7c478bd9Sstevel@tonic-gate field = "file type"; 431*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 432*7c478bd9Sstevel@tonic-gate goto bad; 433*7c478bd9Sstevel@tonic-gate type = *s; 434*7c478bd9Sstevel@tonic-gate if (gettype(type) < 0) 435*7c478bd9Sstevel@tonic-gate goto bad; 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate s = lex(0); /* name */ 438*7c478bd9Sstevel@tonic-gate field = "file name"; 439*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 440*7c478bd9Sstevel@tonic-gate goto bad; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate /* allocate a file structure for this entry */ 443*7c478bd9Sstevel@tonic-gate if (level == 0) 444*7c478bd9Sstevel@tonic-gate fp = add_file_to_base(bp, s); 445*7c478bd9Sstevel@tonic-gate else 446*7c478bd9Sstevel@tonic-gate fp = add_file_to_dir(dirstack[level-1], s); 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate fp->f_flags |= F_IN_BASELINE; 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* maintain the directory stack */ 451*7c478bd9Sstevel@tonic-gate if (level >= MAX_DEPTH) { 452*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_deep), s); 453*7c478bd9Sstevel@tonic-gate exit(ERR_OTHER); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate dirstack[ level ] = fp; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* get a pointer to the baseline file info structure */ 459*7c478bd9Sstevel@tonic-gate ip = &fp->f_info[ OPT_BASE ]; 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate ip->f_type = gettype(type); /* note file type */ 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate s = lex(0); /* modes */ 464*7c478bd9Sstevel@tonic-gate field = "file modes"; 465*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 466*7c478bd9Sstevel@tonic-gate goto bad; 467*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 468*7c478bd9Sstevel@tonic-gate ip->f_mode = l; 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate s = lex(0); /* uid */ 471*7c478bd9Sstevel@tonic-gate field = "file UID"; 472*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 473*7c478bd9Sstevel@tonic-gate goto bad; 474*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 475*7c478bd9Sstevel@tonic-gate ip->f_uid = l; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate s = lex(0); /* gid */ 478*7c478bd9Sstevel@tonic-gate field = "file GID"; 479*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 480*7c478bd9Sstevel@tonic-gate goto bad; 481*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 482*7c478bd9Sstevel@tonic-gate ip->f_gid = l; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate s = lex(0); /* source inode */ 485*7c478bd9Sstevel@tonic-gate field = "source i#"; 486*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 487*7c478bd9Sstevel@tonic-gate goto bad; 488*7c478bd9Sstevel@tonic-gate ll = strtoull(s, 0, 0); 489*7c478bd9Sstevel@tonic-gate fp->f_s_inum = (ino_t) ll; 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate s = lex(0); /* source major */ 492*7c478bd9Sstevel@tonic-gate field = "source major"; 493*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 494*7c478bd9Sstevel@tonic-gate goto bad; 495*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 496*7c478bd9Sstevel@tonic-gate fp->f_s_maj = l; 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate s = lex(0); /* source minor */ 499*7c478bd9Sstevel@tonic-gate field = "source minor"; 500*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 501*7c478bd9Sstevel@tonic-gate goto bad; 502*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 503*7c478bd9Sstevel@tonic-gate fp->f_s_min = l; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate s = lex(0); /* source nlink */ 506*7c478bd9Sstevel@tonic-gate field = "source nlink"; 507*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 508*7c478bd9Sstevel@tonic-gate goto bad; 509*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 510*7c478bd9Sstevel@tonic-gate fp->f_s_nlink = l; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate s = lex(0); /* source mod */ 513*7c478bd9Sstevel@tonic-gate field = "source modtime"; 514*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 515*7c478bd9Sstevel@tonic-gate goto bad; 516*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 517*7c478bd9Sstevel@tonic-gate fp->f_s_modtime = l; 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate s = lex(0); /* dest inode */ 520*7c478bd9Sstevel@tonic-gate field = "destination i#"; 521*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 522*7c478bd9Sstevel@tonic-gate goto bad; 523*7c478bd9Sstevel@tonic-gate ll = strtoull(s, 0, 0); 524*7c478bd9Sstevel@tonic-gate fp->f_d_inum = (ino_t) ll; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate s = lex(0); /* dest major */ 527*7c478bd9Sstevel@tonic-gate field = "destination major"; 528*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 529*7c478bd9Sstevel@tonic-gate goto bad; 530*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 531*7c478bd9Sstevel@tonic-gate fp->f_d_maj = l; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate s = lex(0); /* dest minor */ 534*7c478bd9Sstevel@tonic-gate field = "destination minor"; 535*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 536*7c478bd9Sstevel@tonic-gate goto bad; 537*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 538*7c478bd9Sstevel@tonic-gate fp->f_d_min = l; 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate s = lex(0); /* dest nlink */ 541*7c478bd9Sstevel@tonic-gate field = "dest nlink"; 542*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 543*7c478bd9Sstevel@tonic-gate goto bad; 544*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 545*7c478bd9Sstevel@tonic-gate fp->f_d_nlink = l; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate s = lex(0); /* dest mod */ 548*7c478bd9Sstevel@tonic-gate field = "dest modtime"; 549*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 550*7c478bd9Sstevel@tonic-gate goto bad; 551*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 552*7c478bd9Sstevel@tonic-gate fp->f_d_modtime = l; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate s = lex(0); /* major or size */ 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate if (type == 'C' || type == 'B') { 557*7c478bd9Sstevel@tonic-gate field = "rdev major"; 558*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 559*7c478bd9Sstevel@tonic-gate goto bad; 560*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 561*7c478bd9Sstevel@tonic-gate ip->f_rd_maj = l; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate s = lex(0); /* minor */ 564*7c478bd9Sstevel@tonic-gate field = "rdev minor"; 565*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 566*7c478bd9Sstevel@tonic-gate goto bad; 567*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 568*7c478bd9Sstevel@tonic-gate ip->f_rd_min = l; 569*7c478bd9Sstevel@tonic-gate } else { 570*7c478bd9Sstevel@tonic-gate field = "file size"; 571*7c478bd9Sstevel@tonic-gate if (s == 0 || *s == 0) 572*7c478bd9Sstevel@tonic-gate goto bad; 573*7c478bd9Sstevel@tonic-gate ll = strtoul(s, 0, 0); 574*7c478bd9Sstevel@tonic-gate ip->f_size = (off_t) ll; /* size */ 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate /* 578*7c478bd9Sstevel@tonic-gate * all fields after this point were added to the 579*7c478bd9Sstevel@tonic-gate * 1.0 format and so should be considered optional 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate s = lex(0); /* acl length ? */ 582*7c478bd9Sstevel@tonic-gate field = "acl count"; 583*7c478bd9Sstevel@tonic-gate if (s && *s) { 584*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 585*7c478bd9Sstevel@tonic-gate ip->f_numacls = l; 586*7c478bd9Sstevel@tonic-gate ip->f_acls = (aclent_t *) malloc(ip->f_numacls * 587*7c478bd9Sstevel@tonic-gate sizeof (aclent_t)); 588*7c478bd9Sstevel@tonic-gate if (ip->f_acls == 0) 589*7c478bd9Sstevel@tonic-gate nomem("Access Control List"); 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate continue; 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate if (strcmp(s, "ACL") == 0) { 596*7c478bd9Sstevel@tonic-gate /* make sure there is a place to put the ACL */ 597*7c478bd9Sstevel@tonic-gate if (ip == 0 || ip->f_acls == 0) { 598*7c478bd9Sstevel@tonic-gate field = "ACL w/o FILE/LIST"; 599*7c478bd9Sstevel@tonic-gate goto bad; 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate /* acl entry number */ 603*7c478bd9Sstevel@tonic-gate s = lex(0); 604*7c478bd9Sstevel@tonic-gate field = "acl index"; 605*7c478bd9Sstevel@tonic-gate if (s == 0) 606*7c478bd9Sstevel@tonic-gate goto bad; 607*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 608*7c478bd9Sstevel@tonic-gate if (l >= ip->f_numacls) 609*7c478bd9Sstevel@tonic-gate goto bad; 610*7c478bd9Sstevel@tonic-gate else 611*7c478bd9Sstevel@tonic-gate ap = &ip->f_acls[l]; 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate /* acl entry type */ 614*7c478bd9Sstevel@tonic-gate s = lex(0); 615*7c478bd9Sstevel@tonic-gate field = "acl type"; 616*7c478bd9Sstevel@tonic-gate if (s == 0) 617*7c478bd9Sstevel@tonic-gate goto bad; 618*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 619*7c478bd9Sstevel@tonic-gate ap->a_type = l; 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate /* acl entry ID */ 622*7c478bd9Sstevel@tonic-gate s = lex(0); 623*7c478bd9Sstevel@tonic-gate field = "acl id"; 624*7c478bd9Sstevel@tonic-gate if (s == 0) 625*7c478bd9Sstevel@tonic-gate goto bad; 626*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 627*7c478bd9Sstevel@tonic-gate ap->a_id = l; 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate /* acl entry perms */ 630*7c478bd9Sstevel@tonic-gate s = lex(0); 631*7c478bd9Sstevel@tonic-gate field = "acl perm"; 632*7c478bd9Sstevel@tonic-gate if (s == 0) 633*7c478bd9Sstevel@tonic-gate goto bad; 634*7c478bd9Sstevel@tonic-gate l = strtoul(s, 0, 0); 635*7c478bd9Sstevel@tonic-gate ap->a_perm = l; 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate continue; 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate bad: /* log the error and continue processing to find others */ 641*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_badinput), lex_linenum, 642*7c478bd9Sstevel@tonic-gate field, name); 643*7c478bd9Sstevel@tonic-gate errs |= ERR_FILES; 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate (void) fclose(file); 647*7c478bd9Sstevel@tonic-gate return (errs); 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate /* 651*7c478bd9Sstevel@tonic-gate * routine: 652*7c478bd9Sstevel@tonic-gate * write_baseline 653*7c478bd9Sstevel@tonic-gate * 654*7c478bd9Sstevel@tonic-gate * purpose: 655*7c478bd9Sstevel@tonic-gate * to rewrite the baseline file 656*7c478bd9Sstevel@tonic-gate * 657*7c478bd9Sstevel@tonic-gate * parameters: 658*7c478bd9Sstevel@tonic-gate * name of the new baseline file 659*7c478bd9Sstevel@tonic-gate * 660*7c478bd9Sstevel@tonic-gate * returns: 661*7c478bd9Sstevel@tonic-gate * error mask 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate errmask_t 664*7c478bd9Sstevel@tonic-gate write_baseline(char *name) 665*7c478bd9Sstevel@tonic-gate { FILE *newfile; 666*7c478bd9Sstevel@tonic-gate errmask_t errs = 0; 667*7c478bd9Sstevel@tonic-gate struct base *bp; 668*7c478bd9Sstevel@tonic-gate char tmpname[ MAX_PATH ]; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_FILES) 671*7c478bd9Sstevel@tonic-gate fprintf(stderr, "FILE: WRITE BASELINE %s\n", name); 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* if no-touch is specified, we don't update files */ 674*7c478bd9Sstevel@tonic-gate if (opt_notouch) 675*7c478bd9Sstevel@tonic-gate return (0); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* create a temporary output file */ 678*7c478bd9Sstevel@tonic-gate sprintf(tmpname, "%s-TMP", name); 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate /* create our output file */ 681*7c478bd9Sstevel@tonic-gate newfile = fopen(tmpname, "w+"); 682*7c478bd9Sstevel@tonic-gate if (newfile == NULL) { 683*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_creat), gettext(TXT_base), 684*7c478bd9Sstevel@tonic-gate tmpname); 685*7c478bd9Sstevel@tonic-gate return (ERR_FILES); 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate errs |= bw_header(newfile); 689*7c478bd9Sstevel@tonic-gate for (bp = bases; bp; bp = bp->b_next) 690*7c478bd9Sstevel@tonic-gate errs |= bw_base(newfile, bp); 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate if (ferror(newfile)) { 693*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_write), gettext(TXT_base), 694*7c478bd9Sstevel@tonic-gate tmpname); 695*7c478bd9Sstevel@tonic-gate errs |= ERR_FILES; 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate if (fclose(newfile)) { 699*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_fclose), gettext(TXT_base), 700*7c478bd9Sstevel@tonic-gate tmpname); 701*7c478bd9Sstevel@tonic-gate errs |= ERR_FILES; 702*7c478bd9Sstevel@tonic-gate } 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate /* now switch the new file for the old one */ 705*7c478bd9Sstevel@tonic-gate if (errs == 0) 706*7c478bd9Sstevel@tonic-gate if (rename(tmpname, name) != 0) { 707*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(ERR_rename), 708*7c478bd9Sstevel@tonic-gate gettext(TXT_base), tmpname, name); 709*7c478bd9Sstevel@tonic-gate errs |= ERR_FILES; 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate return (errs); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate /* 716*7c478bd9Sstevel@tonic-gate * routine: 717*7c478bd9Sstevel@tonic-gate * bw_header 718*7c478bd9Sstevel@tonic-gate * 719*7c478bd9Sstevel@tonic-gate * purpose: 720*7c478bd9Sstevel@tonic-gate * to write out a baseline header 721*7c478bd9Sstevel@tonic-gate * 722*7c478bd9Sstevel@tonic-gate * parameters: 723*7c478bd9Sstevel@tonic-gate * FILE* for the output file 724*7c478bd9Sstevel@tonic-gate * 725*7c478bd9Sstevel@tonic-gate * returns: 726*7c478bd9Sstevel@tonic-gate * error mask 727*7c478bd9Sstevel@tonic-gate * 728*7c478bd9Sstevel@tonic-gate * notes: 729*7c478bd9Sstevel@tonic-gate */ 730*7c478bd9Sstevel@tonic-gate static errmask_t 731*7c478bd9Sstevel@tonic-gate bw_header(FILE *file) 732*7c478bd9Sstevel@tonic-gate { time_t now; 733*7c478bd9Sstevel@tonic-gate struct tm *local; 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate /* figure out what time it is */ 736*7c478bd9Sstevel@tonic-gate (void) time(&now); 737*7c478bd9Sstevel@tonic-gate local = localtime(&now); 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate fprintf(file, "%s %d.%d\n", BASE_TAG, BASE_MAJOR, BASE_MINOR); 740*7c478bd9Sstevel@tonic-gate fprintf(file, "#\n"); 741*7c478bd9Sstevel@tonic-gate fprintf(file, "# filesync baseline, last written by %s, %s", 742*7c478bd9Sstevel@tonic-gate cuserid((char *) 0), asctime(local)); 743*7c478bd9Sstevel@tonic-gate fprintf(file, "#\n"); 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate return (0); 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate /* 749*7c478bd9Sstevel@tonic-gate * routine: 750*7c478bd9Sstevel@tonic-gate * bw_base 751*7c478bd9Sstevel@tonic-gate * 752*7c478bd9Sstevel@tonic-gate * purpose: 753*7c478bd9Sstevel@tonic-gate * to write out the summary for one base-pair 754*7c478bd9Sstevel@tonic-gate * 755*7c478bd9Sstevel@tonic-gate * parameters: 756*7c478bd9Sstevel@tonic-gate * FILE * for the output file 757*7c478bd9Sstevel@tonic-gate * 758*7c478bd9Sstevel@tonic-gate * returns: 759*7c478bd9Sstevel@tonic-gate * error mask 760*7c478bd9Sstevel@tonic-gate * 761*7c478bd9Sstevel@tonic-gate * notes: 762*7c478bd9Sstevel@tonic-gate */ 763*7c478bd9Sstevel@tonic-gate static errmask_t 764*7c478bd9Sstevel@tonic-gate bw_base(FILE *file, struct base *bp) 765*7c478bd9Sstevel@tonic-gate { struct file *fp; 766*7c478bd9Sstevel@tonic-gate errmask_t errs = 0; 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate /* see if this base is to be dropped from baseline */ 769*7c478bd9Sstevel@tonic-gate if (bp->b_flags & F_REMOVE) 770*7c478bd9Sstevel@tonic-gate return (0); 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate fprintf(file, "\n"); 773*7c478bd9Sstevel@tonic-gate fprintf(file, "BASE_SRC %s\n", noblanks(bp->b_src_spec)); 774*7c478bd9Sstevel@tonic-gate fprintf(file, "BASE_DST %s\n", noblanks(bp->b_dst_spec)); 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate for (fp = bp->b_files; fp; fp = fp->f_next) 777*7c478bd9Sstevel@tonic-gate errs |= bw_file(file, fp, 0); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate return (errs); 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate /* 783*7c478bd9Sstevel@tonic-gate * routine: 784*7c478bd9Sstevel@tonic-gate * bw_file 785*7c478bd9Sstevel@tonic-gate * 786*7c478bd9Sstevel@tonic-gate * purpose: 787*7c478bd9Sstevel@tonic-gate * to write a file description out to the baseline 788*7c478bd9Sstevel@tonic-gate * 789*7c478bd9Sstevel@tonic-gate * parameters: 790*7c478bd9Sstevel@tonic-gate * output FILE 791*7c478bd9Sstevel@tonic-gate * pointer to file description 792*7c478bd9Sstevel@tonic-gate * recursion depth 793*7c478bd9Sstevel@tonic-gate * 794*7c478bd9Sstevel@tonic-gate * returns: 795*7c478bd9Sstevel@tonic-gate * error mask 796*7c478bd9Sstevel@tonic-gate * 797*7c478bd9Sstevel@tonic-gate * notes: 798*7c478bd9Sstevel@tonic-gate * some of the information we write out is kept separately 799*7c478bd9Sstevel@tonic-gate * for source and destination files because the values should 800*7c478bd9Sstevel@tonic-gate * be expected to be different for different systems/copies. 801*7c478bd9Sstevel@tonic-gate * 802*7c478bd9Sstevel@tonic-gate * if a file has an unresolved conflict, we want to leave 803*7c478bd9Sstevel@tonic-gate * the old values in place so that we continue to compare 804*7c478bd9Sstevel@tonic-gate * files against the last time they agreed. 805*7c478bd9Sstevel@tonic-gate */ 806*7c478bd9Sstevel@tonic-gate static errmask_t 807*7c478bd9Sstevel@tonic-gate bw_file(FILE *file, struct file *fp, int depth) 808*7c478bd9Sstevel@tonic-gate { struct file *cp; 809*7c478bd9Sstevel@tonic-gate int i; 810*7c478bd9Sstevel@tonic-gate errmask_t errs = 0; 811*7c478bd9Sstevel@tonic-gate long long ll; /* intermediate for 64 bit file support */ 812*7c478bd9Sstevel@tonic-gate struct fileinfo *ip = &fp->f_info[OPT_BASE]; 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* if this file is to be removed from baseline, skip it */ 815*7c478bd9Sstevel@tonic-gate if (fp->f_flags & F_REMOVE) 816*7c478bd9Sstevel@tonic-gate return (0); 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate /* 819*7c478bd9Sstevel@tonic-gate * if this node is in conflict, or if it has not been 820*7c478bd9Sstevel@tonic-gate * evaluated this time around, we should just leave the 821*7c478bd9Sstevel@tonic-gate * baseline file the way it was before. If there is a 822*7c478bd9Sstevel@tonic-gate * conflict, let the baseline reflect the last agreement. 823*7c478bd9Sstevel@tonic-gate * If the node wasn't evaluated, let the baseline reflect 824*7c478bd9Sstevel@tonic-gate * our last knowledge. 825*7c478bd9Sstevel@tonic-gate */ 826*7c478bd9Sstevel@tonic-gate if (fp->f_flags & F_CONFLICT || (fp->f_flags&F_EVALUATE) == 0) { 827*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_ino = fp->f_s_inum; 828*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_nlink = fp->f_s_nlink; 829*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_d_maj = fp->f_s_maj; 830*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_d_min = fp->f_s_min; 831*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_modtime = fp->f_s_modtime; 832*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_ino = fp->f_d_inum; 833*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_nlink = fp->f_d_nlink; 834*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_d_maj = fp->f_d_maj; 835*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_d_min = fp->f_d_min; 836*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_modtime = fp->f_d_modtime; 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate /* write out the entry for this file */ 840*7c478bd9Sstevel@tonic-gate fprintf(file, "FILE %d %c %-20s 0%04o", depth, showtype(ip->f_type), 841*7c478bd9Sstevel@tonic-gate noblanks(fp->f_name), ip->f_mode); 842*7c478bd9Sstevel@tonic-gate fprintf(file, " %6ld %6ld", ip->f_uid, ip->f_gid); 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate ll = fp->f_info[OPT_SRC].f_ino; 845*7c478bd9Sstevel@tonic-gate fprintf(file, "\t%6lld %4ld %4ld %4d 0x%08lx", 846*7c478bd9Sstevel@tonic-gate ll, 847*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_d_maj, 848*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_d_min, 849*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_nlink, 850*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_SRC].f_modtime); 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate ll = fp->f_info[OPT_DST].f_ino; 853*7c478bd9Sstevel@tonic-gate fprintf(file, "\t%6lld %4ld %4ld %4d 0x%08lx", 854*7c478bd9Sstevel@tonic-gate ll, 855*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_d_maj, 856*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_d_min, 857*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_nlink, 858*7c478bd9Sstevel@tonic-gate fp->f_info[OPT_DST].f_modtime); 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* last fields are file type specific */ 861*7c478bd9Sstevel@tonic-gate if (S_ISBLK(ip->f_type) || S_ISCHR(ip->f_type)) 862*7c478bd9Sstevel@tonic-gate fprintf(file, "\t%4ld %4ld", ip->f_rd_maj, ip->f_rd_min); 863*7c478bd9Sstevel@tonic-gate else { 864*7c478bd9Sstevel@tonic-gate ll = ip->f_size; 865*7c478bd9Sstevel@tonic-gate fprintf(file, "\t%lld", ll); 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate /* ACL count goes at the end because it was added */ 869*7c478bd9Sstevel@tonic-gate fprintf(file, "\t%d", ip->f_numacls); 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate fprintf(file, "\n"); 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* if this file has ACLs, we have to write them out too */ 874*7c478bd9Sstevel@tonic-gate for (i = 0; i < ip->f_numacls; i++) 875*7c478bd9Sstevel@tonic-gate fprintf(file, "ACL %d %d %ld %o\n", i, ip->f_acls[i].a_type, 876*7c478bd9Sstevel@tonic-gate ip->f_acls[i].a_id, ip->f_acls[i].a_perm); 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate /* then enumerate all of the children (if any) */ 879*7c478bd9Sstevel@tonic-gate for (cp = fp->f_files; cp; cp = cp->f_next) 880*7c478bd9Sstevel@tonic-gate errs |= bw_file(file, cp, depth + 1); 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate return (errs); 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate /* 886*7c478bd9Sstevel@tonic-gate * routines: 887*7c478bd9Sstevel@tonic-gate * gettype/showtype 888*7c478bd9Sstevel@tonic-gate * 889*7c478bd9Sstevel@tonic-gate * purpose: 890*7c478bd9Sstevel@tonic-gate * to convert between a file type (as found in a mode word) 891*7c478bd9Sstevel@tonic-gate * and a single character representation 892*7c478bd9Sstevel@tonic-gate * 893*7c478bd9Sstevel@tonic-gate * parameters/return 894*7c478bd9Sstevel@tonic-gate * mode word -> character 895*7c478bd9Sstevel@tonic-gate * character -> mode word 896*7c478bd9Sstevel@tonic-gate */ 897*7c478bd9Sstevel@tonic-gate static char types[16] = "-PC?DNB?F?S?s???"; 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate static char showtype(int mode) 900*7c478bd9Sstevel@tonic-gate { 901*7c478bd9Sstevel@tonic-gate return (types[ (mode & S_IFMT) >> 12 ]); 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate static long gettype(int code) 905*7c478bd9Sstevel@tonic-gate { int i; 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) 908*7c478bd9Sstevel@tonic-gate if (types[i] == code) 909*7c478bd9Sstevel@tonic-gate return (i << 12); 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate return (-1); 912*7c478bd9Sstevel@tonic-gate } 913