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