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