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