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 *
showflags(struct flaglist * map,long mask)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
dbg_usage(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
err_usage(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
dbg_set_error(char * arg)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
dbg_chk_error(const char * name,char code)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
err_usage(void)342 err_usage(void)
343 {
344 fprintf(stderr, "ERROR: this filesync does not support -E\n");
345 }
346
347 int
dbg_set_error(char * arg)348 dbg_set_error(char *arg)
349 {
350 return (ERR_INVAL);
351 }
352
353 int
dbg_chk_error(const char * name,char code)354 dbg_chk_error(const char *name, char code)
355 {
356 return (0);
357 }
358 #endif
359