1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1995-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * module: 29 * debug.c 30 * 31 * purpose: 32 * utility routines for debugging filesync (tracing, diagnostics, 33 * and error simulation) 34 * 35 * contents: 36 * showflags display a word of flags symbolicly 37 * dbg_usage printout usage info for -D switch 38 * err_usage printout usage info for -E switch 39 * dbg_set_error enable an error simulation 40 * dbg_check_error check for error simulation 41 * 42 * 43 * note: 44 * there are numerous flag words and bit fields in this 45 * program, and it would be horrendous to just print them 46 * out in hex (in debugging output). These routines use 47 * a "flaglist" data structure to map between bits and 48 * character string names or descriptions. 49 * 50 * a flaglist is merely a list of paired bits and name strings. 51 */ 52 #pragma ident "%Z%%M% %I% %E% SMI" 53 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <ctype.h> 58 #include <errno.h> 59 60 #include "filesync.h" 61 #include "database.h" 62 #include "debug.h" 63 64 65 /* bits in opt_debug for usage message */ 66 static struct flaglist dbgflags[] = 67 { DBG_BASE, "BASE: base include building", 68 DBG_RULE, "RULE: rule tree building", 69 DBG_STAT, "STAT: file stats", 70 DBG_ANAL, "ANAL: difference analysis", 71 DBG_RECON, "RECO: reconciliation list processing", 72 DBG_VARS, "VARS: qualification and expansion", 73 DBG_FILES, "FILE: rule and baseline files", 74 DBG_LIST, "LIST: tree building", 75 DBG_EVAL, "EVAL: tree walking", 76 DBG_IGNORE, "IGNO: ignore list", 77 DBG_MISC, "MISC: everything else", 78 0, 0 79 }; 80 81 /* bits in opt_debug for dsiplay */ 82 struct flaglist dbgmap[] = 83 { DBG_BASE, "BASE", 84 DBG_RULE, "RULE", 85 DBG_STAT, "STAT", 86 DBG_ANAL, "ANAL", 87 DBG_RECON, "RECO", 88 DBG_VARS, "VARS", 89 DBG_FILES, "FILE", 90 DBG_LIST, "LIST", 91 DBG_EVAL, "EVAL", 92 DBG_IGNORE, "IGNO", 93 DBG_MISC, "MISC", 94 0, 0 95 }; 96 97 /* bits in the rules flag field */ 98 struct flaglist rflags[] = 99 { R_IGNORE, "IGNORE", 100 R_PROGRAM, "PROGRAM", 101 R_WILD, "WILD", 102 R_NEW, "NEW", 103 R_BOGUS, "BOGUS", 104 R_RESTRICT, "RESTRICT", 105 0, 0 106 }; 107 108 /* bits in the files flag field */ 109 struct flaglist fileflags[] = 110 { F_NEW, "new", 111 F_IN_BASELINE, "base", 112 F_IN_SOURCE, "srce", 113 F_IN_DEST, "dest", 114 F_EVALUATE, "eval", 115 F_SPARSE, "sparse", 116 F_REMOVE, "remove", 117 F_CONFLICT, "conflict", 118 F_LISTED, "listed", 119 F_STAT_ERROR, "statfail", 120 0, 0 121 }; 122 123 /* bits in the file src/dst difference mask */ 124 struct flaglist diffmap[] = { 125 D_CREATE, "create", 126 D_DELETE, "delete", 127 D_MTIME, "modtime", 128 D_SIZE, "size", 129 D_UID, "uid", 130 D_GID, "gid", 131 D_PROT, "modes", 132 D_LINKS, "links", 133 D_TYPE, "type", 134 D_FACLS, "facls", 135 D_RENAME_TO, "rename2", 136 D_RENAME_FROM, "renamed", 137 0, 0 138 }; 139 140 /* bits in the exit error code mask */ 141 struct flaglist errmap[] = { 142 ERR_RESOLVABLE, "resolvable", 143 ERR_UNRESOLVED, "unresolvable", 144 ERR_MISSING, "missing files", 145 ERR_PERM, "permissions", 146 ERR_FILES, "rule/base errors", 147 ERR_INVAL, "invalid arguments", 148 ERR_NOBASE, "bad base dir", 149 ERR_OTHER, "other", 150 0, 0 151 }; 152 153 /* 154 * routine: 155 * showflags 156 * 157 * purpose: 158 * format flags for printing 159 * 160 * parameters: 161 * pointer to map 162 * mask to be interpreted \ 163 * 164 * returns: 165 * pointer to a static buffer 166 */ 167 char * 168 showflags(struct flaglist *map, long mask) 169 { int i; 170 static char outbuf[MAX_NAME]; 171 172 outbuf[0] = 0; 173 for (i = 0; map[i].fl_mask; i++) 174 if (mask & map[i].fl_mask) { 175 if (outbuf[0]) 176 strcat(outbuf, "|"); 177 strcat(outbuf, map[i].fl_name); 178 } 179 180 return (outbuf); 181 } 182 183 /* 184 * routines: 185 * dbg_usage, err_usage 186 * 187 * purpose: 188 * to print out usage messages for the secret debugging flags 189 * 190 * returns: 191 * void 192 */ 193 void 194 dbg_usage(void) 195 { int i; 196 197 fprintf(stderr, "Usage:\tfilesync -Dmask ...\n"); 198 for (i = 0; dbgflags[i].fl_mask; i++) 199 fprintf(stderr, "\t0x%04lx .... %s\n", 200 dbgflags[i].fl_mask, dbgflags[i].fl_name); 201 fprintf(stderr, "\n"); 202 } 203 204 #ifdef DBG_ERRORS 205 /* 206 * The -E flag is a debugging feature that enables the user to request 207 * the simulation of difficult to trigger error conditions in order 208 * to test out the error handling code in filesync. We maintain a 209 * registry that specifies a file name and an operation, and an errno 210 * to be returned if the specified operation is attempted on the 211 * specified file. 212 */ 213 void 214 err_usage(void) 215 { 216 fprintf(stderr, "Usage:\tfilesync -E<errno>,<code>,<filename>\n"); 217 fprintf(stderr, "\ts ... eval stat source\n"); 218 fprintf(stderr, "\tS ... eval stat destination\n"); 219 fprintf(stderr, "\tn ... eval nftw source\n"); 220 fprintf(stderr, "\tN ... eval nftw destination\n"); 221 fprintf(stderr, "\tc ... reconcile copy create\n"); 222 fprintf(stderr, "\to ... reconcile copy open\n"); 223 fprintf(stderr, "\tr ... reconcile copy read/readlink\n"); 224 fprintf(stderr, "\tw ... reconcile copy write\n"); 225 fprintf(stderr, "\tl ... reconcile link/symlink\n"); 226 fprintf(stderr, "\tu ... reconcile unlink\n"); 227 fprintf(stderr, "\td ... reconcile mkdir/mknod\n"); 228 fprintf(stderr, "\tD ... reconcile rmdir\n"); 229 fprintf(stderr, "\tm ... reconcile rename\n"); 230 fprintf(stderr, "\tR ... reconcile restat\n"); 231 fprintf(stderr, "\tp ... reconcile protection (chmod)"); 232 fprintf(stderr, "\ta ... reconcile access control (setfacl)"); 233 fprintf(stderr, "\tO ... reconcile ownership (chown)"); 234 fprintf(stderr, "\tZ ... out of space on target\n"); 235 fprintf(stderr, "\n"); 236 } 237 238 /* 239 * this data structure us used to keep track of the error simulations 240 * that have been requested. 241 */ 242 static struct errsim { 243 int Errno; /* error number to return */ 244 char code; /* event triggering the error */ 245 char *file; /* file name triggering error */ 246 } errsim[ DBG_MAX_ERR ]; 247 248 static int num_errs; /* number of simulated errors */ 249 250 251 /* 252 * routine: 253 * dbg_set_error 254 * 255 * purpose: 256 * note that we have been requested to simulate file access errors 257 * 258 * parameters: 259 * argument string <errno>,<errcode>,<filename> 260 * 261 * returns: 262 * error mask 263 */ 264 int 265 dbg_set_error(char *arg) 266 { char *s; 267 char error_type; 268 int error_no; 269 270 if (num_errs >= DBG_MAX_ERR) { 271 fprintf(stderr, "ERROR: only %d -E specifications allowed\n", 272 DBG_MAX_ERR); 273 return (ERR_INVAL); 274 } 275 276 /* get the error number */ 277 if (!isdigit(arg[0])) 278 return (ERR_INVAL); 279 error_no = strtol(arg, &s, 0); 280 281 /* get the error condition */ 282 if (*s++ != ',' || !isalpha(*s)) 283 return (ERR_INVAL); 284 error_type = *s; 285 286 /* get the file name */ 287 while (*s && *s != ',') s++; 288 if (*s++ != ',' || *s == 0) 289 return (ERR_INVAL); 290 291 /* register the error simulation */ 292 errsim[num_errs].Errno = error_no; 293 errsim[num_errs].code = error_type; 294 errsim[num_errs].file = s; 295 296 if (opt_debug & DBG_MISC) 297 fprintf(stderr, "MISC: errsim[%d] %c(%s) -> %d\n", 298 num_errs, error_type, s, error_no); 299 300 num_errs++; 301 302 return (0); 303 } 304 305 /* 306 * routine: 307 * dbg_chk_error 308 * 309 * purpose: 310 * determine whether or not we have been asked to simulate an 311 * error for a specified file. 312 * 313 * parameters: 314 * file name 315 * 316 * returns: 317 * errno (or zero if no error) 318 */ 319 int 320 dbg_chk_error(const char *name, char code) 321 { int i; 322 323 for (i = 0; i < num_errs; i++) { 324 /* see if this code matches any registered condition */ 325 if (code != errsim[i].code) 326 continue; 327 328 /* see if this also matches the file name */ 329 if (!suffix(name, errsim[i].file)) 330 continue; 331 332 /* we have a winner */ 333 if (opt_debug & DBG_MISC) 334 fprintf(stderr, "MISC: trigger %d for file %c(%s)\n", 335 errsim[i].Errno, code, name); 336 return (errsim[i].Errno); 337 } 338 return (0); 339 } 340 341 #else /* ! DBG_ERRORS */ 342 void 343 err_usage(void) 344 { 345 fprintf(stderr, "ERROR: this filesync does not support -E\n"); 346 } 347 348 int 349 dbg_set_error(char *arg) 350 { 351 return (ERR_INVAL); 352 } 353 354 int 355 dbg_chk_error(const char *name, char code) 356 { 357 return (0); 358 } 359 #endif