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 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #include <signal.h> 29*7c478bd9Sstevel@tonic-gate #include <unistd.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 33*7c478bd9Sstevel@tonic-gate #include "bart.h" 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate static int sanitize_reloc_root(char *root, size_t bufsize); 36*7c478bd9Sstevel@tonic-gate static int create_manifest_filelist(char **argv, char *reloc_root); 37*7c478bd9Sstevel@tonic-gate static int create_manifest_rule(char *reloc_root, FILE *rule_fp); 38*7c478bd9Sstevel@tonic-gate static void output_manifest(void); 39*7c478bd9Sstevel@tonic-gate static int eval_file(const char *fname, const struct stat64 *statb); 40*7c478bd9Sstevel@tonic-gate static char *sanitized_fname(const char *, boolean_t); 41*7c478bd9Sstevel@tonic-gate static char *get_acl_string(const char *fname, const struct stat64 *statb, 42*7c478bd9Sstevel@tonic-gate int *err_code); 43*7c478bd9Sstevel@tonic-gate static int generate_hash(int fdin, char *hash_str); 44*7c478bd9Sstevel@tonic-gate static int read_filelist(char *reloc_root, char **argv, char *buf, 45*7c478bd9Sstevel@tonic-gate size_t bufsize); 46*7c478bd9Sstevel@tonic-gate static int walker(const char *name, const struct stat64 *sp, 47*7c478bd9Sstevel@tonic-gate int type, struct FTW *ftwx); 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * The following globals are necessary due to the "walker" function 51*7c478bd9Sstevel@tonic-gate * provided by nftw(). Since there is no way to pass them through to the 52*7c478bd9Sstevel@tonic-gate * walker function, they must be global. 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate static int compute_chksum = 1, eval_err = 0; 55*7c478bd9Sstevel@tonic-gate static struct rule *subtree_root; 56*7c478bd9Sstevel@tonic-gate static char reloc_root[PATH_MAX]; 57*7c478bd9Sstevel@tonic-gate static struct statvfs parent_vfs; 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate int 60*7c478bd9Sstevel@tonic-gate bart_create(int argc, char **argv) 61*7c478bd9Sstevel@tonic-gate { 62*7c478bd9Sstevel@tonic-gate boolean_t filelist_input; 63*7c478bd9Sstevel@tonic-gate int ret, c, output_pipe[2]; 64*7c478bd9Sstevel@tonic-gate FILE *rules_fd = NULL; 65*7c478bd9Sstevel@tonic-gate pid_t pid; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate filelist_input = B_FALSE; 68*7c478bd9Sstevel@tonic-gate reloc_root[0] = '\0'; 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "Inr:R:")) != EOF) { 71*7c478bd9Sstevel@tonic-gate switch (c) { 72*7c478bd9Sstevel@tonic-gate case 'I': 73*7c478bd9Sstevel@tonic-gate if (rules_fd != NULL) { 74*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s", INPUT_ERR); 75*7c478bd9Sstevel@tonic-gate usage(); 76*7c478bd9Sstevel@tonic-gate } 77*7c478bd9Sstevel@tonic-gate filelist_input = B_TRUE; 78*7c478bd9Sstevel@tonic-gate break; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate case 'n': 81*7c478bd9Sstevel@tonic-gate compute_chksum = 0; 82*7c478bd9Sstevel@tonic-gate break; 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate case 'r': 85*7c478bd9Sstevel@tonic-gate if (strcmp(optarg, "-") == 0) 86*7c478bd9Sstevel@tonic-gate rules_fd = stdin; 87*7c478bd9Sstevel@tonic-gate else 88*7c478bd9Sstevel@tonic-gate rules_fd = fopen(optarg, "r"); 89*7c478bd9Sstevel@tonic-gate if (rules_fd == NULL) { 90*7c478bd9Sstevel@tonic-gate perror(optarg); 91*7c478bd9Sstevel@tonic-gate usage(); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate break; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate case 'R': 96*7c478bd9Sstevel@tonic-gate (void) strlcpy(reloc_root, optarg, sizeof (reloc_root)); 97*7c478bd9Sstevel@tonic-gate ret = sanitize_reloc_root(reloc_root, 98*7c478bd9Sstevel@tonic-gate sizeof (reloc_root)); 99*7c478bd9Sstevel@tonic-gate if (ret == 0) 100*7c478bd9Sstevel@tonic-gate usage(); 101*7c478bd9Sstevel@tonic-gate break; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate case '?': 104*7c478bd9Sstevel@tonic-gate default : 105*7c478bd9Sstevel@tonic-gate usage(); 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate argv += optind; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate if (pipe(output_pipe) < 0) { 111*7c478bd9Sstevel@tonic-gate perror(""); 112*7c478bd9Sstevel@tonic-gate exit(FATAL_EXIT); 113*7c478bd9Sstevel@tonic-gate } 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate pid = fork(); 116*7c478bd9Sstevel@tonic-gate if (pid < 0) { 117*7c478bd9Sstevel@tonic-gate perror(NULL); 118*7c478bd9Sstevel@tonic-gate exit(FATAL_EXIT); 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* 122*7c478bd9Sstevel@tonic-gate * Break the creation of a manifest into two parts: the parent process 123*7c478bd9Sstevel@tonic-gate * generated the data whereas the child process sorts the data. 124*7c478bd9Sstevel@tonic-gate * 125*7c478bd9Sstevel@tonic-gate * The processes communicate through the pipe. 126*7c478bd9Sstevel@tonic-gate */ 127*7c478bd9Sstevel@tonic-gate if (pid > 0) { 128*7c478bd9Sstevel@tonic-gate /* 129*7c478bd9Sstevel@tonic-gate * Redirect the stdout of this process so it goes into 130*7c478bd9Sstevel@tonic-gate * output_pipe[0]. The output of this process will be read 131*7c478bd9Sstevel@tonic-gate * by the child, which will sort the output. 132*7c478bd9Sstevel@tonic-gate */ 133*7c478bd9Sstevel@tonic-gate if (dup2(output_pipe[0], STDOUT_FILENO) != STDOUT_FILENO) { 134*7c478bd9Sstevel@tonic-gate perror(NULL); 135*7c478bd9Sstevel@tonic-gate exit(FATAL_EXIT); 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate (void) close(output_pipe[0]); 138*7c478bd9Sstevel@tonic-gate (void) close(output_pipe[1]); 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate if (filelist_input == B_TRUE) { 141*7c478bd9Sstevel@tonic-gate ret = create_manifest_filelist(argv, reloc_root); 142*7c478bd9Sstevel@tonic-gate } else { 143*7c478bd9Sstevel@tonic-gate ret = create_manifest_rule(reloc_root, rules_fd); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* Close stdout so the sort in the child proc will complete */ 147*7c478bd9Sstevel@tonic-gate (void) fclose(stdout); 148*7c478bd9Sstevel@tonic-gate } else { 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * Redirect the stdin of this process so its read in from 151*7c478bd9Sstevel@tonic-gate * the pipe, which is the parent process in this case. 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate if (dup2(output_pipe[1], STDIN_FILENO) != STDIN_FILENO) { 154*7c478bd9Sstevel@tonic-gate perror(NULL); 155*7c478bd9Sstevel@tonic-gate exit(FATAL_EXIT); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate (void) close(output_pipe[0]); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate output_manifest(); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* Wait for the child proc (the sort) to complete */ 163*7c478bd9Sstevel@tonic-gate (void) wait(0); 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate return (ret); 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * Handle the -R option and sets 'root' to be the absolute path of the 170*7c478bd9Sstevel@tonic-gate * relocatable root. This is useful when the user specifies '-R ../../foo'. 171*7c478bd9Sstevel@tonic-gate * 172*7c478bd9Sstevel@tonic-gate * Return code is whether or not the location spec'd by the -R flag is a 173*7c478bd9Sstevel@tonic-gate * directory or not. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate static int 176*7c478bd9Sstevel@tonic-gate sanitize_reloc_root(char *root, size_t bufsize) 177*7c478bd9Sstevel@tonic-gate { 178*7c478bd9Sstevel@tonic-gate char pwd[PATH_MAX]; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* 181*7c478bd9Sstevel@tonic-gate * First, save the current directory and go to the location 182*7c478bd9Sstevel@tonic-gate * specified with the -R option. 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate (void) getcwd(pwd, sizeof (pwd)); 185*7c478bd9Sstevel@tonic-gate if (chdir(root) < 0) { 186*7c478bd9Sstevel@tonic-gate /* Failed to change directory, something is wrong.... */ 187*7c478bd9Sstevel@tonic-gate perror(root); 188*7c478bd9Sstevel@tonic-gate return (0); 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate /* 192*7c478bd9Sstevel@tonic-gate * Save the absolute path of the relocatable root directory. 193*7c478bd9Sstevel@tonic-gate */ 194*7c478bd9Sstevel@tonic-gate (void) getcwd(root, bufsize); 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * Now, go back to where we started, necessary for picking up a rules 198*7c478bd9Sstevel@tonic-gate * file. 199*7c478bd9Sstevel@tonic-gate */ 200*7c478bd9Sstevel@tonic-gate if (chdir(pwd) < 0) { 201*7c478bd9Sstevel@tonic-gate /* Failed to change directory, something is wrong.... */ 202*7c478bd9Sstevel@tonic-gate perror(root); 203*7c478bd9Sstevel@tonic-gate return (0); 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * Make sure the path returned does not have a trailing /. This 208*7c478bd9Sstevel@tonic-gate * can only happen when the entire pathname is "/". 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate if (strcmp(root, "/") == 0) 211*7c478bd9Sstevel@tonic-gate root[0] = '\0'; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate /* 214*7c478bd9Sstevel@tonic-gate * Since the earlier chdir() succeeded, return success. 215*7c478bd9Sstevel@tonic-gate */ 216*7c478bd9Sstevel@tonic-gate return (1); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * This is the worker bee which creates the manifest based upon the command 221*7c478bd9Sstevel@tonic-gate * line options supplied by the user. 222*7c478bd9Sstevel@tonic-gate * 223*7c478bd9Sstevel@tonic-gate * NOTE: create_manifest() eventually outputs data to a pipe, which is read in 224*7c478bd9Sstevel@tonic-gate * by the child process. The child process is running output_manifest(), which 225*7c478bd9Sstevel@tonic-gate * is responsible for generating sorted output. 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate static int 228*7c478bd9Sstevel@tonic-gate create_manifest_rule(char *reloc_root, FILE *rule_fp) 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate struct rule *root; 231*7c478bd9Sstevel@tonic-gate int ret_status = EXIT; 232*7c478bd9Sstevel@tonic-gate uint_t flags; 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate if (compute_chksum) 235*7c478bd9Sstevel@tonic-gate flags = ATTR_CONTENTS; 236*7c478bd9Sstevel@tonic-gate else 237*7c478bd9Sstevel@tonic-gate flags = 0; 238*7c478bd9Sstevel@tonic-gate ret_status = read_rules(rule_fp, reloc_root, flags, 1); 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate /* Loop through every single subtree */ 241*7c478bd9Sstevel@tonic-gate for (root = get_first_subtree(); root != NULL; 242*7c478bd9Sstevel@tonic-gate root = get_next_subtree(root)) { 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * This subtree has already been traversed by a 246*7c478bd9Sstevel@tonic-gate * previous stanza, i.e. this rule is a subset of a 247*7c478bd9Sstevel@tonic-gate * previous rule. 248*7c478bd9Sstevel@tonic-gate * 249*7c478bd9Sstevel@tonic-gate * Subtree has already been handled so move on! 250*7c478bd9Sstevel@tonic-gate */ 251*7c478bd9Sstevel@tonic-gate if (root->traversed) 252*7c478bd9Sstevel@tonic-gate continue; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* 255*7c478bd9Sstevel@tonic-gate * Check to see if this subtree should have contents 256*7c478bd9Sstevel@tonic-gate * checking turned on or off. 257*7c478bd9Sstevel@tonic-gate * 258*7c478bd9Sstevel@tonic-gate * NOTE: The 'compute_chksum' and 'parent_vfs' 259*7c478bd9Sstevel@tonic-gate * are a necessary hack: the variables are used in 260*7c478bd9Sstevel@tonic-gate * walker(), both directly and indirectly. Since 261*7c478bd9Sstevel@tonic-gate * the parameters to walker() are defined by nftw(), 262*7c478bd9Sstevel@tonic-gate * the globals are really a backdoor mechanism. 263*7c478bd9Sstevel@tonic-gate */ 264*7c478bd9Sstevel@tonic-gate ret_status = statvfs(root->subtree, &parent_vfs); 265*7c478bd9Sstevel@tonic-gate if (ret_status < 0) { 266*7c478bd9Sstevel@tonic-gate perror(root->subtree); 267*7c478bd9Sstevel@tonic-gate continue; 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate /* 271*7c478bd9Sstevel@tonic-gate * Walk the subtree and invoke the callback function 272*7c478bd9Sstevel@tonic-gate * walker() 273*7c478bd9Sstevel@tonic-gate */ 274*7c478bd9Sstevel@tonic-gate subtree_root = root; 275*7c478bd9Sstevel@tonic-gate (void) nftw64(root->subtree, &walker, 20, FTW_PHYS); 276*7c478bd9Sstevel@tonic-gate root->traversed = B_TRUE; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate /* 279*7c478bd9Sstevel@tonic-gate * Ugly but necessary: 280*7c478bd9Sstevel@tonic-gate * 281*7c478bd9Sstevel@tonic-gate * walker() must return 0, or the tree walk will stop, 282*7c478bd9Sstevel@tonic-gate * so warning flags must be set through a global. 283*7c478bd9Sstevel@tonic-gate */ 284*7c478bd9Sstevel@tonic-gate if (eval_err == WARNING_EXIT) 285*7c478bd9Sstevel@tonic-gate ret_status = WARNING_EXIT; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate return (ret_status); 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate static int 292*7c478bd9Sstevel@tonic-gate create_manifest_filelist(char **argv, char *reloc_root) 293*7c478bd9Sstevel@tonic-gate { 294*7c478bd9Sstevel@tonic-gate int ret_status = EXIT; 295*7c478bd9Sstevel@tonic-gate char input_fname[PATH_MAX]; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate while (read_filelist(reloc_root, argv, 298*7c478bd9Sstevel@tonic-gate input_fname, sizeof (input_fname)) != -1) { 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate struct stat64 stat_buf; 301*7c478bd9Sstevel@tonic-gate int ret; 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate ret = lstat64(input_fname, &stat_buf); 304*7c478bd9Sstevel@tonic-gate if (ret < 0) { 305*7c478bd9Sstevel@tonic-gate ret_status = WARNING_EXIT; 306*7c478bd9Sstevel@tonic-gate perror(input_fname); 307*7c478bd9Sstevel@tonic-gate } else { 308*7c478bd9Sstevel@tonic-gate ret = eval_file(input_fname, &stat_buf); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if (ret == WARNING_EXIT) 311*7c478bd9Sstevel@tonic-gate ret_status = WARNING_EXIT; 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate return (ret_status); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate /* 319*7c478bd9Sstevel@tonic-gate * output_manifest() the child process. It reads in the output from 320*7c478bd9Sstevel@tonic-gate * create_manifest() and sorts it. 321*7c478bd9Sstevel@tonic-gate */ 322*7c478bd9Sstevel@tonic-gate static void 323*7c478bd9Sstevel@tonic-gate output_manifest(void) 324*7c478bd9Sstevel@tonic-gate { 325*7c478bd9Sstevel@tonic-gate char *env[] = {"LC_CTYPE=C", "LC_COLLATE=C", "LC_NUMERIC=C", NULL}; 326*7c478bd9Sstevel@tonic-gate time_t time_val; 327*7c478bd9Sstevel@tonic-gate struct tm *tm; 328*7c478bd9Sstevel@tonic-gate char time_buf[1024]; 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate (void) printf("%s", MANIFEST_VER); 331*7c478bd9Sstevel@tonic-gate time_val = time((time_t)0); 332*7c478bd9Sstevel@tonic-gate tm = localtime(&time_val); 333*7c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), "%A, %B %d, %Y (%T)", tm); 334*7c478bd9Sstevel@tonic-gate (void) printf("! %s\n", time_buf); 335*7c478bd9Sstevel@tonic-gate (void) printf("%s", FORMAT_STR); 336*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate * Simply run sort and read from the the current stdin, which is really 339*7c478bd9Sstevel@tonic-gate * the output of create_manifest(). 340*7c478bd9Sstevel@tonic-gate * Also, make sure the output is unique, since a given file may be 341*7c478bd9Sstevel@tonic-gate * included by several stanzas. 342*7c478bd9Sstevel@tonic-gate */ 343*7c478bd9Sstevel@tonic-gate if (execle("/usr/bin/sort", "sort", NULL, env) < 0) { 344*7c478bd9Sstevel@tonic-gate perror(""); 345*7c478bd9Sstevel@tonic-gate exit(FATAL_EXIT); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * Callback function for nftw() 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate static int 355*7c478bd9Sstevel@tonic-gate walker(const char *name, const struct stat64 *sp, int type, struct FTW *ftwx) 356*7c478bd9Sstevel@tonic-gate { 357*7c478bd9Sstevel@tonic-gate int ret; 358*7c478bd9Sstevel@tonic-gate struct statvfs path_vfs; 359*7c478bd9Sstevel@tonic-gate boolean_t dir_flag = B_FALSE; 360*7c478bd9Sstevel@tonic-gate struct rule *rule; 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate switch (type) { 363*7c478bd9Sstevel@tonic-gate case FTW_F: /* file */ 364*7c478bd9Sstevel@tonic-gate rule = check_rules(name, 'F'); 365*7c478bd9Sstevel@tonic-gate if (rule != NULL) { 366*7c478bd9Sstevel@tonic-gate if (rule->attr_list & ATTR_CONTENTS) 367*7c478bd9Sstevel@tonic-gate compute_chksum = 1; 368*7c478bd9Sstevel@tonic-gate else 369*7c478bd9Sstevel@tonic-gate compute_chksum = 0; 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate break; 372*7c478bd9Sstevel@tonic-gate case FTW_SL: /* symbolic link */ 373*7c478bd9Sstevel@tonic-gate case FTW_DP: /* end of directory */ 374*7c478bd9Sstevel@tonic-gate case FTW_DNR: /* unreadable directory */ 375*7c478bd9Sstevel@tonic-gate case FTW_NS: /* unstatable file */ 376*7c478bd9Sstevel@tonic-gate break; 377*7c478bd9Sstevel@tonic-gate case FTW_D: /* enter directory */ 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /* 380*7c478bd9Sstevel@tonic-gate * Check to see if any subsequent rules are a subset 381*7c478bd9Sstevel@tonic-gate * of this rule; if they are, then mark them as 382*7c478bd9Sstevel@tonic-gate * "traversed". 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate rule = subtree_root->next; 385*7c478bd9Sstevel@tonic-gate while (rule != NULL) { 386*7c478bd9Sstevel@tonic-gate if (strcmp(name, rule->subtree) == 0) 387*7c478bd9Sstevel@tonic-gate rule->traversed = B_TRUE; 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate rule = rule->next; 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate dir_flag = B_TRUE; 392*7c478bd9Sstevel@tonic-gate ret = statvfs(name, &path_vfs); 393*7c478bd9Sstevel@tonic-gate if (ret < 0) 394*7c478bd9Sstevel@tonic-gate eval_err = WARNING_EXIT; 395*7c478bd9Sstevel@tonic-gate break; 396*7c478bd9Sstevel@tonic-gate default: 397*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, INVALID_FILE, name); 398*7c478bd9Sstevel@tonic-gate eval_err = WARNING_EXIT; 399*7c478bd9Sstevel@tonic-gate break; 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* This is the function which really processes the file */ 403*7c478bd9Sstevel@tonic-gate ret = eval_file(name, sp); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate /* 406*7c478bd9Sstevel@tonic-gate * Since the parameters to walker() are constrained by nftw(), 407*7c478bd9Sstevel@tonic-gate * need to use a global to reflect a WARNING. Sigh. 408*7c478bd9Sstevel@tonic-gate */ 409*7c478bd9Sstevel@tonic-gate if (ret == WARNING_EXIT) 410*7c478bd9Sstevel@tonic-gate eval_err = WARNING_EXIT; 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * This is a case of a directory which crosses into a mounted 414*7c478bd9Sstevel@tonic-gate * filesystem of a different type, e.g., UFS -> NFS. 415*7c478bd9Sstevel@tonic-gate * BART should not walk the new filesystem (by specification), so 416*7c478bd9Sstevel@tonic-gate * set this consolidation-private flag so the rest of the subtree 417*7c478bd9Sstevel@tonic-gate * under this directory is not waled. 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate if (dir_flag && 420*7c478bd9Sstevel@tonic-gate (strcmp(parent_vfs.f_basetype, path_vfs.f_basetype) != 0)) 421*7c478bd9Sstevel@tonic-gate ftwx->quit = FTW_PRUNE; 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate return (0); 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* 427*7c478bd9Sstevel@tonic-gate * This file does the per-file evaluation and is run to generate every entry 428*7c478bd9Sstevel@tonic-gate * in the manifest. 429*7c478bd9Sstevel@tonic-gate * 430*7c478bd9Sstevel@tonic-gate * All output is written to a pipe which is read by the child process, 431*7c478bd9Sstevel@tonic-gate * which is running output_manifest(). 432*7c478bd9Sstevel@tonic-gate */ 433*7c478bd9Sstevel@tonic-gate static int 434*7c478bd9Sstevel@tonic-gate eval_file(const char *fname, const struct stat64 *statb) 435*7c478bd9Sstevel@tonic-gate { 436*7c478bd9Sstevel@tonic-gate int fd, ret, err_code, i; 437*7c478bd9Sstevel@tonic-gate char last_field[PATH_MAX], ftype, *acl_str, 438*7c478bd9Sstevel@tonic-gate *quoted_name; 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate err_code = EXIT; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate switch (statb->st_mode & S_IFMT) { 443*7c478bd9Sstevel@tonic-gate /* Regular file */ 444*7c478bd9Sstevel@tonic-gate case S_IFREG: ftype = 'F'; break; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate /* Directory */ 447*7c478bd9Sstevel@tonic-gate case S_IFDIR: ftype = 'D'; break; 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate /* Block Device */ 450*7c478bd9Sstevel@tonic-gate case S_IFBLK: ftype = 'B'; break; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate /* Character Device */ 453*7c478bd9Sstevel@tonic-gate case S_IFCHR: ftype = 'C'; break; 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate /* Named Pipe */ 456*7c478bd9Sstevel@tonic-gate case S_IFIFO: ftype = 'P'; break; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* Socket */ 459*7c478bd9Sstevel@tonic-gate case S_IFSOCK: ftype = 'S'; break; 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate /* Door */ 462*7c478bd9Sstevel@tonic-gate case S_IFDOOR: ftype = 'O'; break; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* Symbolic link */ 465*7c478bd9Sstevel@tonic-gate case S_IFLNK: ftype = 'L'; break; 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate default: ftype = '-'; break; 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* First, make sure this file should be cataloged */ 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate if ((subtree_root != NULL) && 473*7c478bd9Sstevel@tonic-gate (exclude_fname(fname, ftype, subtree_root))) 474*7c478bd9Sstevel@tonic-gate return (err_code); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate for (i = 0; i < PATH_MAX; i++) 477*7c478bd9Sstevel@tonic-gate last_field[i] = '\0'; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * Regular files, compute the MD5 checksum and put it into 'last_field' 481*7c478bd9Sstevel@tonic-gate * UNLESS instructed to ignore the checksums. 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate if (ftype == 'F') { 484*7c478bd9Sstevel@tonic-gate if (compute_chksum) { 485*7c478bd9Sstevel@tonic-gate fd = open(fname, O_RDONLY|O_LARGEFILE); 486*7c478bd9Sstevel@tonic-gate if (fd < 0) { 487*7c478bd9Sstevel@tonic-gate err_code = WARNING_EXIT; 488*7c478bd9Sstevel@tonic-gate perror(fname); 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate /* default value since the computution failed */ 491*7c478bd9Sstevel@tonic-gate (void) strcpy(last_field, "-"); 492*7c478bd9Sstevel@tonic-gate } else { 493*7c478bd9Sstevel@tonic-gate if (generate_hash(fd, last_field) != 0) { 494*7c478bd9Sstevel@tonic-gate err_code = WARNING_EXIT; 495*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, CONTENTS_WARN, 496*7c478bd9Sstevel@tonic-gate fname); 497*7c478bd9Sstevel@tonic-gate (void) strcpy(last_field, "-"); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate (void) close(fd); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate /* Instructed to ignore checksums, just put in a '-' */ 503*7c478bd9Sstevel@tonic-gate else 504*7c478bd9Sstevel@tonic-gate (void) strcpy(last_field, "-"); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * For symbolic links, put the destination of the symbolic link into 509*7c478bd9Sstevel@tonic-gate * 'last_field' 510*7c478bd9Sstevel@tonic-gate */ 511*7c478bd9Sstevel@tonic-gate if (ftype == 'L') { 512*7c478bd9Sstevel@tonic-gate ret = readlink(fname, last_field, sizeof (last_field)); 513*7c478bd9Sstevel@tonic-gate if (ret < 0) { 514*7c478bd9Sstevel@tonic-gate err_code = WARNING_EXIT; 515*7c478bd9Sstevel@tonic-gate perror(fname); 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate /* default value since the computation failed */ 518*7c478bd9Sstevel@tonic-gate (void) strcpy(last_field, "-"); 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate else 521*7c478bd9Sstevel@tonic-gate (void) strlcpy(last_field, 522*7c478bd9Sstevel@tonic-gate sanitized_fname(last_field, B_FALSE), 523*7c478bd9Sstevel@tonic-gate sizeof (last_field)); 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * Boundary condition: possible for a symlink to point to 527*7c478bd9Sstevel@tonic-gate * nothing [ ln -s '' link_name ]. For this case, set the 528*7c478bd9Sstevel@tonic-gate * destination to "\000". 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate if (strlen(last_field) == 0) 531*7c478bd9Sstevel@tonic-gate (void) strcpy(last_field, "\\000"); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate acl_str = get_acl_string(fname, statb, &err_code); 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate /* Sanitize 'fname', so its in the proper format for the manifest */ 537*7c478bd9Sstevel@tonic-gate quoted_name = sanitized_fname(fname, B_TRUE); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate /* Start to build the entry.... */ 540*7c478bd9Sstevel@tonic-gate (void) printf("%s %c %d %o %s %x %d %d", quoted_name, ftype, 541*7c478bd9Sstevel@tonic-gate (int)statb->st_size, (int)statb->st_mode, acl_str, 542*7c478bd9Sstevel@tonic-gate (int)statb->st_mtime, (int)statb->st_uid, (int)statb->st_gid); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* Finish it off based upon whether or not it's a device node */ 545*7c478bd9Sstevel@tonic-gate if ((ftype == 'B') && (ftype == 'C')) 546*7c478bd9Sstevel@tonic-gate (void) printf(" %x\n", (int)statb->st_rdev); 547*7c478bd9Sstevel@tonic-gate else if (strlen(last_field) > 0) 548*7c478bd9Sstevel@tonic-gate (void) printf(" %s\n", last_field); 549*7c478bd9Sstevel@tonic-gate else 550*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate /* free the memory consumed */ 553*7c478bd9Sstevel@tonic-gate free(acl_str); 554*7c478bd9Sstevel@tonic-gate free(quoted_name); 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate return (err_code); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate /* 560*7c478bd9Sstevel@tonic-gate * When creating a manifest, make sure all '?', tabs, space, newline, '/' 561*7c478bd9Sstevel@tonic-gate * and '[' are all properly quoted. Convert them to a "\ooo" where the 'ooo' 562*7c478bd9Sstevel@tonic-gate * represents their octal value. For filesystem objects, as opposed to symlink 563*7c478bd9Sstevel@tonic-gate * targets, also canonicalize the pathname. 564*7c478bd9Sstevel@tonic-gate */ 565*7c478bd9Sstevel@tonic-gate static char * 566*7c478bd9Sstevel@tonic-gate sanitized_fname(const char *fname, boolean_t canon_path) 567*7c478bd9Sstevel@tonic-gate { 568*7c478bd9Sstevel@tonic-gate const char *ip; 569*7c478bd9Sstevel@tonic-gate unsigned char ch; 570*7c478bd9Sstevel@tonic-gate char *op, *quoted_name; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate /* Initialize everything */ 573*7c478bd9Sstevel@tonic-gate quoted_name = safe_calloc((4 * PATH_MAX) + 1); 574*7c478bd9Sstevel@tonic-gate ip = fname; 575*7c478bd9Sstevel@tonic-gate op = quoted_name; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate if (canon_path) { 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * In the case when a relocatable root was used, the relocatable 580*7c478bd9Sstevel@tonic-gate * root should *not* be part of the manifest. 581*7c478bd9Sstevel@tonic-gate */ 582*7c478bd9Sstevel@tonic-gate ip += strlen(reloc_root); 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate /* 585*7c478bd9Sstevel@tonic-gate * In the case when the '-I' option was used, make sure 586*7c478bd9Sstevel@tonic-gate * the quoted_name starts with a '/'. 587*7c478bd9Sstevel@tonic-gate */ 588*7c478bd9Sstevel@tonic-gate if (*ip != '/') 589*7c478bd9Sstevel@tonic-gate *op++ = '/'; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* Now walk through 'fname' and build the quoted string */ 593*7c478bd9Sstevel@tonic-gate while ((ch = *ip++) != 0) { 594*7c478bd9Sstevel@tonic-gate switch (ch) { 595*7c478bd9Sstevel@tonic-gate /* Quote the following characters */ 596*7c478bd9Sstevel@tonic-gate case ' ': 597*7c478bd9Sstevel@tonic-gate case '*': 598*7c478bd9Sstevel@tonic-gate case '\n': 599*7c478bd9Sstevel@tonic-gate case '?': 600*7c478bd9Sstevel@tonic-gate case '[': 601*7c478bd9Sstevel@tonic-gate case '\\': 602*7c478bd9Sstevel@tonic-gate case '\t': 603*7c478bd9Sstevel@tonic-gate op += sprintf(op, "\\%.3o", (unsigned char)ch); 604*7c478bd9Sstevel@tonic-gate break; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate /* Otherwise, simply append them */ 607*7c478bd9Sstevel@tonic-gate default: 608*7c478bd9Sstevel@tonic-gate *op++ = ch; 609*7c478bd9Sstevel@tonic-gate break; 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate *op = 0; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate return (quoted_name); 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* 619*7c478bd9Sstevel@tonic-gate * Function responsible for generating the ACL information for a given 620*7c478bd9Sstevel@tonic-gate * file. Note, the string is put into buffer malloc'd by this function. 621*7c478bd9Sstevel@tonic-gate * Its the responsibility of the caller to free the buffer. 622*7c478bd9Sstevel@tonic-gate */ 623*7c478bd9Sstevel@tonic-gate static char * 624*7c478bd9Sstevel@tonic-gate get_acl_string(const char *fname, const struct stat64 *statb, int *err_code) 625*7c478bd9Sstevel@tonic-gate { 626*7c478bd9Sstevel@tonic-gate aclent_t *aclbuf; 627*7c478bd9Sstevel@tonic-gate int num_acls, ret; 628*7c478bd9Sstevel@tonic-gate char *acl_info; 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate if (S_ISLNK(statb->st_mode)) { 631*7c478bd9Sstevel@tonic-gate return (safe_strdup("-")); 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* First, figure out how many ACL entries this file has */ 635*7c478bd9Sstevel@tonic-gate num_acls = acl(fname, GETACLCNT, 0, NULL); 636*7c478bd9Sstevel@tonic-gate if (num_acls < 0) { 637*7c478bd9Sstevel@tonic-gate *err_code = WARNING_EXIT; 638*7c478bd9Sstevel@tonic-gate perror(fname); 639*7c478bd9Sstevel@tonic-gate return (safe_strdup("-")); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate /* 643*7c478bd9Sstevel@tonic-gate * Next, create a buffer which is big enough for all the ACL entries. 644*7c478bd9Sstevel@tonic-gate * Then go get the raw data. 645*7c478bd9Sstevel@tonic-gate */ 646*7c478bd9Sstevel@tonic-gate aclbuf = (aclent_t *)safe_calloc(sizeof (aclent_t) * num_acls); 647*7c478bd9Sstevel@tonic-gate ret = acl(fname, GETACL, num_acls, aclbuf); 648*7c478bd9Sstevel@tonic-gate if (ret < 0) { 649*7c478bd9Sstevel@tonic-gate *err_code = WARNING_EXIT; 650*7c478bd9Sstevel@tonic-gate perror(fname); 651*7c478bd9Sstevel@tonic-gate return (safe_strdup("-")); 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate /* Convert the raw entries to text */ 655*7c478bd9Sstevel@tonic-gate acl_info = acltotext(aclbuf, num_acls); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate /* Free up the buffer which held the raw ACL entries */ 658*7c478bd9Sstevel@tonic-gate free(aclbuf); 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate if (acl_info == NULL) { 661*7c478bd9Sstevel@tonic-gate *err_code = WARNING_EXIT; 662*7c478bd9Sstevel@tonic-gate perror(fname); 663*7c478bd9Sstevel@tonic-gate return (safe_strdup("-")); 664*7c478bd9Sstevel@tonic-gate } else 665*7c478bd9Sstevel@tonic-gate return (acl_info); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate /* 670*7c478bd9Sstevel@tonic-gate * 671*7c478bd9Sstevel@tonic-gate * description: This routine reads stdin in BUF_SIZE chunks, uses the bits 672*7c478bd9Sstevel@tonic-gate * to update the md5 hash buffer, and outputs the chunks 673*7c478bd9Sstevel@tonic-gate * to stdout. When stdin is exhausted, the hash is computed, 674*7c478bd9Sstevel@tonic-gate * converted to a hexadecimal string, and returned. 675*7c478bd9Sstevel@tonic-gate * 676*7c478bd9Sstevel@tonic-gate * returns: The md5 hash of stdin, or NULL if unsuccessful for any reason. 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate static int 679*7c478bd9Sstevel@tonic-gate generate_hash(int fdin, char *hash_str) 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate unsigned char buf[BUF_SIZE]; 682*7c478bd9Sstevel@tonic-gate unsigned char hash[MD5_DIGEST_LENGTH]; 683*7c478bd9Sstevel@tonic-gate int i, amtread; 684*7c478bd9Sstevel@tonic-gate MD5_CTX ctx; 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate MD5Init(&ctx); 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate for (;;) { 689*7c478bd9Sstevel@tonic-gate amtread = read(fdin, buf, sizeof (buf)); 690*7c478bd9Sstevel@tonic-gate if (amtread == 0) 691*7c478bd9Sstevel@tonic-gate break; 692*7c478bd9Sstevel@tonic-gate if (amtread < 0) 693*7c478bd9Sstevel@tonic-gate return (1); 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate /* got some data. Now update hash */ 696*7c478bd9Sstevel@tonic-gate MD5Update(&ctx, buf, amtread); 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* done passing through data, calculate hash */ 700*7c478bd9Sstevel@tonic-gate MD5Final(hash, &ctx); 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate for (i = 0; i < MD5_DIGEST_LENGTH; i++) 703*7c478bd9Sstevel@tonic-gate (void) sprintf(hash_str + (i*2), "%2.2x", hash[i]); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate return (0); 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * Used by 'bart create' with the '-I' option. Return each entry into a 'buf' 710*7c478bd9Sstevel@tonic-gate * with the appropriate exit code: '0' for success and '-1' for failure. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate static int 713*7c478bd9Sstevel@tonic-gate read_filelist(char *reloc_root, char **argv, char *buf, size_t bufsize) 714*7c478bd9Sstevel@tonic-gate { 715*7c478bd9Sstevel@tonic-gate static int argv_index = -1; 716*7c478bd9Sstevel@tonic-gate static boolean_t read_stdinput = B_FALSE; 717*7c478bd9Sstevel@tonic-gate char temp_buf[PATH_MAX]; 718*7c478bd9Sstevel@tonic-gate char *cp; 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate /* 721*7c478bd9Sstevel@tonic-gate * INITIALIZATION: 722*7c478bd9Sstevel@tonic-gate * Setup this code so it knows whether or not to read sdtin. 723*7c478bd9Sstevel@tonic-gate * Also, if reading from argv, setup the index, "argv_index" 724*7c478bd9Sstevel@tonic-gate */ 725*7c478bd9Sstevel@tonic-gate if (argv_index == -1) { 726*7c478bd9Sstevel@tonic-gate argv_index = 0; 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate /* In this case, no args after '-I', so read stdin */ 729*7c478bd9Sstevel@tonic-gate if (argv[0] == NULL) 730*7c478bd9Sstevel@tonic-gate read_stdinput = B_TRUE; 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate buf[0] = '\0'; 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate if (read_stdinput) { 736*7c478bd9Sstevel@tonic-gate if (fgets(temp_buf, PATH_MAX, stdin) == NULL) 737*7c478bd9Sstevel@tonic-gate return (-1); 738*7c478bd9Sstevel@tonic-gate cp = strtok(temp_buf, "\n"); 739*7c478bd9Sstevel@tonic-gate } else { 740*7c478bd9Sstevel@tonic-gate cp = argv[argv_index++]; 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate if (cp == NULL) 744*7c478bd9Sstevel@tonic-gate return (-1); 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate /* 747*7c478bd9Sstevel@tonic-gate * Unlike similar code elsewhere, avoid adding a leading 748*7c478bd9Sstevel@tonic-gate * slash for relative pathnames. 749*7c478bd9Sstevel@tonic-gate */ 750*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, bufsize, 751*7c478bd9Sstevel@tonic-gate (reloc_root[0] == '\0' || cp[0] == '/') ? "%s%s" : "%s/%s", 752*7c478bd9Sstevel@tonic-gate reloc_root, cp); 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate return (0); 755*7c478bd9Sstevel@tonic-gate } 756