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 (c) 1996, by Sun Microsystems, Inc.
24 * All Rights Reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <locale.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <sys/param.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #include <stdlib.h>
39
40 #include "rules.h"
41
42 char * lex(FILE *);
43
44 extern char *mstrdup(const char *);
45 extern void *mmalloc(size_t size);
46
47 void
read_rules(FILE * file,int (* rulefunc)())48 read_rules(FILE *file, int (*rulefunc)())
49 {
50 char *s;
51 int base_active = 0;
52 int list_ent_cnt = 0;
53 int gign_ent_cnt = 0;
54 int lign_ent_cnt = 0;
55 struct item *add_item();
56 struct item *fitem, *sitem;
57 char version[20];
58
59 last_gign = &gign_hd;
60 gign_hd.i_next = (struct item *)0;
61 gign_hd.i_str = (char *)0;
62 list_hd.i_next = (struct item *)0;
63 list_hd.i_str = (char *)0;
64 while (s = lex(file)) {
65 if (s == (char *)0)
66 break;
67 if (*s == '#')
68 continue;
69 if (*s == '*')
70 continue;
71 if (strcmp(s, BASE) == 0) {
72 #ifdef DEBUG
73 printf("BASE base_active = %d\n", base_active);
74 #endif /* DEBUG */
75 if (base_active) {
76 /*
77 * Tack local IGNORE strings to end of globals
78 */
79 if (lign_hd.i_next != (struct item *)0) {
80 last_gign->i_next = &lign_hd;
81 }
82 /*
83 * Process directives for previous BASE command
84 * if there was one. Also free up LIST items
85 * and local IGNORE items.
86 */
87 do_base_dir(basedir, &list_hd, &gign_hd,
88 rulefunc);
89 /*
90 * Free up space from LIST item list
91 */
92 fitem = list_hd.i_next;
93 if (fitem != (struct item *)0) {
94 while (fitem != (struct item *)0) {
95 free(fitem->i_str);
96 sitem = fitem->i_next;
97 free(fitem);
98 fitem = sitem;
99 }
100 }
101 /*
102 * Free up space from local IGNORE item list
103 */
104 fitem = lign_hd.i_next;
105 if (fitem != (struct item *)0) {
106 while (fitem != (struct item *)0) {
107 free(fitem->i_str);
108 sitem = fitem->i_next;
109 free(fitem);
110 fitem = sitem;
111 }
112 }
113 last_gign->i_next = (struct item *)0;
114 }
115 base_active = 1;
116 /*
117 * Reset LIST item list and local IGNORE item
118 * list to be empty.
119 */
120 last_list = &list_hd;
121 list_hd.i_next = (struct item *)0;
122 list_hd.i_str = (char *)0;
123 last_lign = &lign_hd;
124 lign_hd.i_next = (struct item *)0;
125 lign_hd.i_str = (char *)0;
126 /*
127 * Get BASE directory specified
128 */
129 s = lex(0);
130 if (s == (char *)0) {
131 fprintf(stderr, gettext("cachefspack: "));
132 fprintf(stderr, gettext(
133 "illegal BASE command\n"));
134 return;
135 }
136
137 if (*s == '$') {
138 /*
139 * String starts with a '$', it must be an
140 * environment variable
141 */
142 s = getenv(&s[1]);
143 if (s == (char *)NULL) {
144 fprintf(stderr,
145 gettext("cachefspack: "));
146 fprintf(stderr,
147 gettext("Can't find "
148 "environment variable\n"));
149 exit(1);
150 }
151 }
152 basedir = mstrdup(s);
153 #ifdef DEBUG
154 printf("basedir = %s\n", basedir);
155 #endif /* DEBUG */
156 continue;
157 }
158 if (strcmp(s, IGNORE) == 0) {
159 #ifdef DEBUG
160 printf("IGNORE - base_active = %d\n", base_active);
161 #endif /* DEBUG */
162 if (base_active) {
163 /*
164 * Local IGNORE rule
165 */
166 while ((s = lex(0))
167 != 0) {
168 last_lign = add_item(last_lign, s,
169 def_lign_flags);
170 }
171 } else {
172 /*
173 * Global IGNORE rule
174 */
175 while ((s = lex(0)) != 0) {
176 last_gign = add_item(last_gign, s,
177 def_gign_flags);
178 }
179 }
180 continue;
181 }
182 if (strcmp(s, LIST) == 0) {
183 #ifdef DEBUG
184 printf("LIST\n");
185 #endif /* DEBUG */
186 if (!base_active) {
187 fprintf(stderr,
188 gettext(
189 "cachefspack: skipping LIST command - "));
190 fprintf(stderr,
191 gettext(" no active base\n"));
192 continue;
193 }
194 while ((s = lex(0)) != 0) {
195 last_list = add_item(last_list, s,
196 def_list_flags);
197 }
198 continue;
199 }
200 if (strcmp(s, VERSION) == 0) {
201 sprintf(version, "%d.%d", VERMAJOR, VERMINOR);
202 s = lex(0);
203 if (s == (char *)0) {
204 fprintf(stderr, gettext("cachefspack: "));
205 fprintf(stderr, gettext("missing version\n"));
206 fprintf(stderr, gettext("cachefspack: "));
207 fprintf(stderr, gettext(
208 "version = %d.%d\n"), VERMAJOR, VERMINOR);
209 exit(1);
210 }
211 if (strcmp(version, s) != 0) {
212 fprintf(stderr, gettext(
213 "cachefspack: "));
214 fprintf(stderr, gettext(
215 "WARNING - version of packing rules "));
216 fprintf(stderr, gettext(
217 "does not match cachefspack version\n"));
218 fprintf(stderr, gettext(
219 "version = %d.%d\n"), VERMAJOR, VERMINOR);
220 }
221 }
222 }
223 /*
224 * Tack local IGNORE strings to end of globals
225 */
226 if (lign_hd.i_next != (struct item *)0) {
227 last_gign->i_next = &lign_hd;
228 }
229 do_base_dir(basedir, &list_hd, &gign_hd, rulefunc);
230 }
231
232 struct item *
add_item(struct item * last_item,char * str,int flags)233 add_item(struct item *last_item, char *str, int flags)
234 {
235 struct item * add_cmd_items();
236
237 if (*str == CMDCHAR) {
238 last_item = add_cmd_items(last_item, &str[1], bang_list_flags);
239 } else {
240 last_item->i_next = (struct item *)mmalloc(
241 sizeof (struct item));
242 last_item = last_item->i_next;
243 last_item->i_str = mstrdup(str);
244 last_item->i_flag = flags;
245 last_item->i_next = (struct item *)0;
246 }
247 return (last_item);
248 }
249
250 struct item *
add_cmd_items(struct item * last_item,char * str,int flags)251 add_cmd_items(struct item *last_item, char *str, int flags)
252 {
253 FILE *fd;
254 char inbuf[MAX_RULE_SZ];
255 char *olddir = NULL;
256 char *s;
257 void getcmd(char *, char *);
258
259 if ((basedir != NULL) && (basedir[0] != '\0')) {
260 olddir = getcwd(NULL, MAXPATHLEN + 1);
261 if (olddir == NULL) {
262 fprintf(stderr, gettext("cannot malloc buffer\n"));
263 exit(1);
264 }
265
266 if (chdir(basedir) != 0) {
267 fprintf(stderr, gettext("cannot chdir to %s: %s\n"),
268 basedir, strerror(errno));
269 exit(1);
270 }
271 }
272
273 getcmd(str, inbuf);
274 fd = popen(inbuf, "r");
275 if (fd == NULL) {
276 fprintf(stderr, gettext("cachefspack: LIST can't execute - "));
277 fprintf(stderr, "%s\n", inbuf);
278 exit(1);
279 }
280
281 while (s = lex(fd)) {
282 last_item = add_item(last_item, s, flags);
283 while (s = lex(0)) {
284 last_item = add_item(last_item, s, flags);
285 }
286 }
287 if (pclose(fd) < 0) {
288 fprintf(stderr, gettext("cachefspack: can't close pipe\n"));
289 }
290
291 if (olddir != NULL) {
292 if (chdir(olddir) != 0) {
293 fprintf(stderr, gettext("cannot return to %s: %s\n"),
294 olddir, strerror(errno));
295 exit(1);
296 }
297 free(olddir);
298 }
299
300 return (last_item);
301 }
302
303 void
getcmd(char * str,char * buf)304 getcmd(char *str, char *buf)
305 {
306 char *s;
307
308 strcpy(buf, str);
309 strcat(buf, " ");
310 while (s = lex(0)) {
311 strcat(buf, s);
312 strcat(buf, " ");
313 }
314 #ifdef DEBUG
315 printf("getcmd: cmd = %s\n", buf);
316 #endif /* DEBUG */
317 }
318
319 /*
320 * routine:
321 * lex
322 *
323 * purpose:
324 * my own version of strtok that handles quoting and escaping
325 *
326 * parameters:
327 * string to be lexed (or 0 for same string)
328 *
329 * returns:
330 * pointer to next token
331 *
332 * notes:
333 * this routine makes no changes to the string it is passed,
334 * copying tokens into a static buffer.
335 */
336 char *
lex(FILE * fd)337 lex(FILE *fd)
338 { char c, delim;
339 char *p;
340 const char *s;
341 static const char *savep = 0;
342 static char namebuf[MAX_RULE_SZ];
343 static char inbuf[MAX_RULE_SZ];
344 int len, space_left;
345 char *err;
346
347 /*
348 * if the file descriptor is non-zero read a new command. Otherwise
349 * get fields from current line.
350 */
351 if (fd != 0) {
352 len = 0;
353 space_left = sizeof (inbuf);
354 while ((err = fgets(&inbuf[len], space_left, fd)) != NULL) {
355 len = strlen(inbuf);
356 if (len == 1) {
357 /*
358 * must be a blank line starting command.
359 * If a blank line occurs after the start of
360 * a command, blanks will be included in the
361 * command.
362 */
363 len = 0;
364 continue;
365 }
366 len -= 2;
367 space_left -= len;
368 s = (char *)((int)inbuf + len);
369 /*
370 * Continuation character
371 */
372 if (strcmp(s, "\\\n") == 0) {
373 continue;
374 }
375 break;
376 }
377 if (err == NULL) {
378 return (err);
379 }
380 s = inbuf;
381 } else {
382 if (savep == 0)
383 return (0);
384 s = savep;
385 }
386 savep = 0;
387
388 /* skip over leading white space */
389 while (isspace(*s))
390 s++;
391 if (*s == 0) {
392 return (0);
393 }
394
395 /* see if this is a quoted string */
396 c = *s;
397 if (c == '\'' || c == '"') {
398 delim = c;
399 s++;
400 } else
401 delim = 0;
402
403 /* copy the token into the buffer */
404 for (p = namebuf; (c = *s) != 0; s++) {
405 if ((p - namebuf) >= sizeof (namebuf)) {
406 savep = 0;
407 return (0);
408 }
409 /* literal escape */
410 if (c == '\\') {
411 s++;
412 *p++ = *s;
413 continue;
414 }
415
416 /* closing delimiter */
417 if (c == delim) {
418 s++;
419 break;
420 }
421
422 /* delimiting white space */
423 if (delim == 0 && isspace(c))
424 break;
425
426 /* ordinary characters */
427 *p++ = *s;
428 }
429
430
431 /* remember where we left off */
432 savep = *s ? s : 0;
433
434 /* null terminate and return the buffer */
435 *p = 0;
436 return (namebuf);
437 }
438
439 char *
mk_base_dir(char * path,char * linkpath)440 mk_base_dir(char *path, char *linkpath)
441 {
442 static char pathb[MAXPATHLEN];
443 char *dnam;
444 char *get_dirname(char *);
445 int len;
446
447 /*
448 * absolute path name
449 */
450 if (*linkpath == '/') {
451 strcpy(pathb, linkpath);
452 } else {
453 /*
454 * relative path
455 */
456 dnam = get_dirname(path);
457 if (dnam == (char *)0) {
458 return ((char *) 0);
459 }
460 strcpy(pathb, dnam);
461 len = strlen(pathb);
462 if (len == 0)
463 return (pathb);
464 if (pathb[len-1] != '/')
465 strcat(pathb, "/");
466 if (strncmp(linkpath, "../", 3) == 0) {
467 /*
468 * path is relative to directory containing sym link
469 * remove "../" from beginning of linkpath
470 */
471 strcat(pathb, &linkpath[3]);
472 } else {
473 /*
474 * path is relative to directory containing sym link
475 */
476 strcat(pathb, linkpath);
477 }
478 }
479 return (pathb);
480 }
481