xref: /illumos-gate/usr/src/cmd/filesync/debug.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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
360