Print this page
Bump Apache dependency to Apache 2
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/logadm/glob.c
+++ new/usr/src/cmd/logadm/glob.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
23 23 * Use is subject to license terms.
24 24 *
25 25 * logadm/glob.c -- globbing routines
26 26 *
27 27 * these routines support two kinds of globs. first, the
28 28 * usual kind of filename globbing, like:
29 29 *
30 30 * *.c
31 31 * /var/log/syslog.?
32 32 * log[0-9]*file
33 - * /var/apache/logs/x*{access,error}_log
33 + * /var/apache2/2.2/logs/x*{access,error}_log
34 34 *
35 35 * this is basically the same syntax that csh supports for globs and
36 36 * is provided by the routine glob_glob() which takes a filename and
37 37 * returns a list of filenames that match the glob.
38 38 *
39 39 * the second type is something called a "reglob" which is a pathname
40 40 * where the components are regular expressions as described in regex(3c).
41 41 * some examples:
42 42 *
43 43 * .*\.c
44 44 * /var/log/syslog\..
45 45 * log[0-9].*file
46 46 * /var/log/syslog\.([0-9]+)$0
47 47 *
48 48 * the last example uses the ()$n form to assign a numeric extension
49 49 * on a filename to the "n" value kept by the fn routines with each
50 50 * filename (see fn_setn() in fn.c). logadm uses this mechanism to
51 51 * correctly sort lognames when templates containing $n are used.
52 52 *
53 53 * the routine glob_reglob() is used to expand reglobs. glob_glob()
54 54 * is implemented by expanding the curly braces, converting the globs
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
55 55 * to reglobs, and then passing the work to glob_reglob().
56 56 *
57 57 * finally, since expanding globs and reglobs requires doing a stat(2)
58 58 * on the files, we store the resulting stat information in the filename
59 59 * struct (see fn_setstat() in fn.c).
60 60 *
61 61 * the glob(3c) routines are not used here since they don't support
62 62 * braces, and don't support the more powerful reglobs required by logadm.
63 63 */
64 64
65 -#pragma ident "%Z%%M% %I% %E% SMI"
66 -
67 65 #include <stdio.h>
68 66 #include <libintl.h>
69 67 #include <stdlib.h>
70 68 #include <libgen.h>
71 69 #include <strings.h>
72 70 #include <sys/types.h>
73 71 #include <sys/param.h>
74 72 #include <sys/stat.h>
75 73 #include <dirent.h>
76 74 #include "err.h"
77 75 #include "fn.h"
78 76 #include "glob.h"
79 77
80 78 /* forward declarations for functions used internally by this module */
81 79 static struct fn_list *glob_debrace(struct fn *fnp);
82 80 static struct fn_list *glob_reglob_list(struct fn_list *fnlp);
83 81 static boolean_t glob_magic(struct fn *fnp);
84 82
85 83 /* expand curly braces (like file{one,two,three}name) */
86 84 static struct fn_list *
87 85 glob_debrace(struct fn *fnp)
88 86 {
89 87 struct fn_list *ret = fn_list_new(NULL);
90 88 struct fn_list *newret;
91 89 char *sp = fn_s(fnp);
92 90 char *left;
93 91 char *right;
94 92 char *comma;
95 93
96 94 /* start with an empty string in the list */
97 95 fn_list_adds(ret, "");
98 96
99 97 /* while braces remain... */
100 98 while (sp != NULL && (left = strchr(sp, '{')) != NULL)
101 99 if ((right = strchr(left, '}')) == NULL) {
102 100 err(EF_FILE|EF_JMP, "Missing }");
103 101 fn_list_free(ret);
104 102 return (NULL);
105 103 } else {
106 104 /* stuff before "left" is finished */
107 105 fn_list_appendrange(ret, sp, left);
108 106
109 107 /* stuff after "right" still need processing */
110 108 sp = right + 1;
111 109
112 110 if (left + 1 == right)
113 111 continue; /* just an empty {} */
114 112
115 113 /* stuff between "left" and "right" is comma-sep list */
116 114 left++;
117 115 newret = fn_list_new(NULL);
118 116 while ((comma = strchr(left, ',')) != NULL) {
119 117 struct fn_list *dup = fn_list_dup(ret);
120 118
121 119 /* stuff from left to comma is one variant */
122 120 fn_list_appendrange(dup, left, comma);
123 121 fn_list_addfn_list(newret, dup);
124 122 left = comma + 1;
125 123 }
126 124 /* what's left is the last item in the list */
127 125 fn_list_appendrange(ret, left, right);
128 126 fn_list_addfn_list(newret, ret);
129 127 ret = newret;
130 128 }
131 129
132 130 /* anything remaining in "s" is finished */
133 131 fn_list_appendrange(ret, sp, &sp[strlen(sp)]);
134 132 return (ret);
135 133 }
136 134
137 135 /* return true if filename contains any "magic" characters (*,?,[) */
138 136 static boolean_t
139 137 glob_magic(struct fn *fnp)
140 138 {
141 139 char *s = fn_s(fnp);
142 140
143 141 for (; s != NULL && *s; s++)
144 142 if (*s == '*' ||
145 143 *s == '?' ||
146 144 *s == '[')
147 145 return (B_TRUE);
148 146
149 147 return (B_FALSE);
150 148 }
151 149
152 150 /*
153 151 * glob_glob -- given a filename glob, return the list of matching filenames
154 152 *
155 153 * fn_setn() and fn_setstat() are called to set the "n" and stat information
156 154 * for the resulting filenames.
157 155 */
158 156 struct fn_list *
159 157 glob_glob(struct fn *fnp)
160 158 {
161 159 struct fn_list *tmplist = glob_debrace(fnp);
162 160 struct fn_list *ret;
163 161 struct fn *nextfnp;
164 162 struct fn *newfnp;
165 163 int magic = 0;
166 164
167 165 /* debracing produced NULL list? */
168 166 if (tmplist == NULL)
169 167 return (NULL);
170 168
171 169 /* see if anything in list contains magic characters */
172 170 fn_list_rewind(tmplist);
173 171 while ((nextfnp = fn_list_next(tmplist)) != NULL)
174 172 if (glob_magic(nextfnp)) {
175 173 magic = 1;
176 174 break;
177 175 }
178 176
179 177 if (!magic)
180 178 return (tmplist); /* no globs to expand */
181 179
182 180 /* foreach name in the list, call glob_glob() to expand it */
183 181 fn_list_rewind(tmplist);
184 182 ret = fn_list_new(NULL);
185 183 while ((nextfnp = fn_list_next(tmplist)) != NULL) {
186 184 newfnp = glob_to_reglob(nextfnp);
187 185 fn_list_addfn(ret, newfnp);
188 186 }
189 187 fn_list_free(tmplist);
190 188 tmplist = ret;
191 189 ret = glob_reglob_list(tmplist);
192 190 fn_list_free(tmplist);
193 191
194 192 return (ret);
195 193 }
196 194
197 195 /*
198 196 * glob_glob_list -- given a list of filename globs, return all matches
199 197 */
200 198 struct fn_list *
201 199 glob_glob_list(struct fn_list *fnlp)
202 200 {
203 201 struct fn_list *ret = fn_list_new(NULL);
204 202 struct fn *fnp;
205 203
206 204 fn_list_rewind(fnlp);
207 205 while ((fnp = fn_list_next(fnlp)) != NULL)
208 206 fn_list_addfn_list(ret, glob_glob(fnp));
209 207 return (ret);
210 208 }
211 209
212 210 /*
213 211 * glob_reglob -- given a filename reglob, return a list of matching filenames
214 212 *
215 213 * this routine does all the hard work in this module.
216 214 */
217 215 struct fn_list *
218 216 glob_reglob(struct fn *fnp)
219 217 {
220 218 struct fn_list *ret = fn_list_new(NULL);
221 219 struct fn_list *newret;
222 220 struct fn *nextfnp;
223 221 char *mys = STRDUP(fn_s(fnp));
224 222 char *sp = mys;
225 223 char *slash;
226 224 int skipdotfiles;
227 225 char *re;
228 226 char ret0[MAXPATHLEN];
229 227
230 228
231 229 /* start with the initial directory in the list */
232 230 if (*sp == '/') {
233 231 fn_list_adds(ret, "/");
234 232 while (*sp == '/')
235 233 sp++;
236 234 } else
237 235 fn_list_adds(ret, "./");
238 236
239 237 /* while components remain... */
240 238 do {
241 239 if ((slash = strchr(sp, '/')) != NULL) {
242 240 *slash++ = '\0';
243 241 /* skip superfluous slashes */
244 242 while (*slash == '/')
245 243 slash++;
246 244 }
247 245
248 246 /* dot files are skipped unless a dot was specifically given */
249 247 if (sp[0] == '\\' && sp[1] == '.')
250 248 skipdotfiles = 0;
251 249 else
252 250 skipdotfiles = 1;
253 251
254 252 /* compile the regex */
255 253 if ((re = regcmp("^", sp, "$", (char *)0)) == NULL)
256 254 err(EF_FILE|EF_JMP, "regcmp failed on <%s>", sp);
257 255
258 256 /* apply regex to every filename we've matched so far */
259 257 newret = fn_list_new(NULL);
260 258 fn_list_rewind(ret);
261 259 while ((nextfnp = fn_list_next(ret)) != NULL) {
262 260 DIR *dirp;
263 261 struct dirent *dp;
264 262
265 263 /* go through directory looking for matches */
266 264 if ((dirp = opendir(fn_s(nextfnp))) == NULL)
267 265 continue;
268 266
269 267 while ((dp = readdir(dirp)) != NULL) {
270 268 if (skipdotfiles && dp->d_name[0] == '.')
271 269 continue;
272 270 *ret0 = '\0';
273 271 if (regex(re, dp->d_name, ret0)) {
274 272 struct fn *matchfnp = fn_dup(nextfnp);
275 273 struct stat stbuf;
276 274 int n;
277 275
278 276 fn_puts(matchfnp, dp->d_name);
279 277
280 278 if (stat(fn_s(matchfnp), &stbuf) < 0) {
281 279 fn_free(matchfnp);
282 280 continue;
283 281 }
284 282
285 283 /* skip non-dirs if more components */
286 284 if (slash &&
287 285 (stbuf.st_mode & S_IFMT) !=
288 286 S_IFDIR) {
289 287 fn_free(matchfnp);
290 288 continue;
291 289 }
292 290
293 291 /*
294 292 * component matched, fill in "n"
295 293 * value, stat information, and
296 294 * append component to directory
297 295 * name just searched.
298 296 */
299 297
300 298 if (*ret0)
301 299 n = atoi(ret0);
302 300 else
303 301 n = -1;
304 302 fn_setn(matchfnp, n);
305 303 fn_setstat(matchfnp, &stbuf);
306 304
307 305 if (slash)
308 306 fn_putc(matchfnp, '/');
309 307
310 308 fn_list_addfn(newret, matchfnp);
311 309 }
312 310 }
313 311 (void) closedir(dirp);
314 312 }
315 313 fn_list_free(ret);
316 314 ret = newret;
317 315 sp = slash;
318 316 } while (slash);
319 317
320 318 FREE(mys);
321 319
322 320 return (ret);
323 321 }
324 322
325 323 /* reglob a list of filenames */
326 324 static struct fn_list *
327 325 glob_reglob_list(struct fn_list *fnlp)
328 326 {
329 327 struct fn_list *ret = fn_list_new(NULL);
330 328 struct fn *fnp;
331 329
332 330 fn_list_rewind(fnlp);
333 331 while ((fnp = fn_list_next(fnlp)) != NULL)
334 332 fn_list_addfn_list(ret, glob_reglob(fnp));
335 333 return (ret);
336 334 }
337 335
338 336 /*
339 337 * glob_to_reglob -- convert a glob (*, ?, etc) to a reglob (.*, ., etc.)
340 338 */
341 339 struct fn *
342 340 glob_to_reglob(struct fn *fnp)
343 341 {
344 342 int c;
345 343 struct fn *ret = fn_new(NULL);
346 344
347 345 fn_rewind(fnp);
348 346 while ((c = fn_getc(fnp)) != '\0')
349 347 switch (c) {
350 348 case '.':
351 349 case '(':
352 350 case ')':
353 351 case '^':
354 352 case '+':
355 353 case '{':
356 354 case '}':
357 355 case '$':
358 356 /* magic characters need backslash */
359 357 fn_putc(ret, '\\');
360 358 fn_putc(ret, c);
361 359 break;
362 360 case '?':
363 361 /* change '?' to a single dot */
364 362 fn_putc(ret, '.');
365 363 break;
366 364 case '*':
367 365 /* change '*' to ".*" */
368 366 fn_putc(ret, '.');
369 367 fn_putc(ret, '*');
370 368 break;
371 369 default:
372 370 fn_putc(ret, c);
373 371 }
374 372
375 373 return (ret);
376 374 }
377 375
378 376 #ifdef TESTMODULE
379 377
380 378 /*
381 379 * test main for glob module, usage: a.out [-r] [pattern...]
382 380 * -r means the patterns are reglobs instead of globs
383 381 */
384 382 int
385 383 main(int argc, char *argv[])
386 384 {
387 385 int i;
388 386 int reglobs = 0;
389 387 struct fn *argfnp = fn_new(NULL);
390 388 struct fn *fnp;
391 389 struct fn_list *fnlp;
392 390
393 391 err_init(argv[0]);
394 392 setbuf(stdout, NULL);
395 393
396 394 for (i = 1; i < argc; i++) {
397 395 if (strcmp(argv[i], "-r") == 0) {
398 396 reglobs = 1;
399 397 continue;
400 398 }
401 399
402 400 if (SETJMP) {
403 401 printf(" skipped due to errors\n");
404 402 continue;
405 403 } else {
406 404 printf("<%s>:\n", argv[i]);
407 405 fn_renew(argfnp, argv[i]);
408 406 if (reglobs)
409 407 fnlp = glob_reglob(argfnp);
410 408 else
411 409 fnlp = glob_glob(argfnp);
412 410 }
413 411
414 412 fn_list_rewind(fnlp);
415 413 while ((fnp = fn_list_next(fnlp)) != NULL)
416 414 printf(" <%s>\n", fn_s(fnp));
417 415
418 416 printf("total size: %lld\n", fn_list_totalsize(fnlp));
419 417
420 418 while ((fnp = fn_list_popoldest(fnlp)) != NULL) {
421 419 printf(" oldest <%s>\n", fn_s(fnp));
422 420 fn_free(fnp);
423 421 }
424 422
425 423 fn_list_free(fnlp);
426 424 }
427 425 fn_free(argfnp);
428 426
429 427 err_done(0);
430 428 /* NOTREACHED */
431 429 return (0);
432 430 }
433 431
434 432 #endif /* TESTMODULE */
↓ open down ↓ |
358 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX