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