Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Implementation of basic procedures for the AFS user account | |
12 | * facility. | |
13 | */ | |
14 | ||
15 | /* | |
16 | * --------------------- Required definitions --------------------- | |
17 | */ | |
18 | #include <afsconfig.h> | |
19 | #include <afs/param.h> | |
20 | ||
21 | #include <roken.h> | |
22 | ||
23 | #include <afs/kautils.h> /*MAXKTCREALMLEN*/ | |
24 | ||
25 | #include "uss_procs.h" /*Module interface */ | |
26 | #include "uss_common.h" /*Common defs & operations */ | |
27 | #include "uss_acl.h" /*ACL-related operations */ | |
28 | ||
29 | #undef USS_PROCS_DB | |
30 | #undef USS_PROCS_DB_INSTANCE | |
31 | #undef USS_PROCS_DB_BUILDDIR | |
32 | #define uss_procs_MAX_SIZE 2048 | |
33 | char temp[1000]; | |
34 | extern int line; | |
35 | ||
36 | static int Copy(char *a_from, char *a_to, int a_mode); | |
37 | static int Echo(char *a_s, char *a_f, int a_mode); | |
38 | ||
39 | /*----------------------------------------------------------------------- | |
40 | * EXPORTED uss_procs_BuildDir | |
41 | * | |
42 | * Environment: | |
43 | * Called from the code generated by the uss grammar. | |
44 | * | |
45 | * Side Effects: | |
46 | * As advertised. | |
47 | *------------------------------------------------------------------------*/ | |
48 | ||
49 | afs_int32 | |
50 | uss_procs_BuildDir(char *a_path, char *a_mode, char *a_owner, char *a_access) | |
51 | { /*uss_procs_BuildDir */ | |
52 | ||
53 | int m, o; | |
54 | char buf[1000]; | |
55 | struct uss_subdir *new_dir; | |
56 | struct stat stbuf; | |
57 | ||
58 | /* | |
59 | * Don't do anything if there's already a problem. | |
60 | */ | |
61 | if (uss_syntax_err) | |
62 | return (1); | |
63 | ||
64 | if (uss_verbose) | |
65 | printf("Building directory '%s'; owner: '%s', ACL: '%s'\n", a_path, | |
66 | a_owner, a_access); | |
67 | ||
68 | /* | |
69 | * If we've not been given permission to overwrite things, make sure | |
70 | * the target doesn't exist before doing anything. | |
71 | */ | |
72 | if (!uss_OverwriteThisOne) { | |
73 | strcpy(temp, a_path); | |
74 | if (!stat(temp, &stbuf)) { | |
75 | if (uss_verbose) | |
76 | printf("\t[Directory exists, NOT overwriting it]\n"); | |
77 | return (0); | |
78 | } | |
79 | } | |
80 | ||
81 | sscanf(a_mode, "%o", &m); | |
82 | o = uss_procs_GetOwner(a_owner); | |
83 | #ifdef USS_PROCS_DB_BUILDDIR | |
84 | printf("DEBUGGING: Owner '%s' is uid %d\n", a_owner, o); | |
85 | #endif /* USS_PROCS_DB_BUILDDIR */ | |
86 | ||
87 | if (!uss_DryRun) { | |
88 | if (mkdir(a_path, m)) { | |
89 | /* | |
90 | * Can't make the directory. Complain if the directory doesn't | |
91 | * already exist. | |
92 | */ | |
93 | if (errno != EEXIST) { | |
94 | uss_procs_PrintErr(line, | |
95 | "Failed to create directory '%s': %s\n", | |
96 | a_path, strerror(errno)); | |
97 | return (1); | |
98 | } /*Directory didn't exist */ | |
99 | } /*Create the directory */ | |
100 | } /*Not a dry run */ | |
101 | else { | |
102 | if (uss_OverwriteThisOne) | |
103 | fprintf(stderr, "\t[Dry run: mkdir %s, mode %o]\n", a_path, m); | |
104 | } /*Dry run */ | |
105 | ||
106 | if (!uss_DryRun) { | |
107 | if (chmod(a_path, m)) { | |
108 | uss_procs_PrintErr(line, | |
109 | "Can't chmod() directory '%s' to be '%s' : %s\n", | |
110 | a_path, a_mode, strerror(errno)); | |
111 | return (1); | |
112 | } /* chmod the directory */ | |
113 | if (chown(a_path, o, -1)) { | |
114 | uss_procs_PrintErr(line, | |
115 | "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n", | |
116 | a_path, a_owner, o, strerror(errno)); | |
117 | return (1); | |
118 | } /*Couldn't chown */ | |
119 | } /*Not a dry run */ | |
120 | else { | |
121 | fprintf(stderr, | |
122 | "\t[Dry run: chown() directory '%s' to be owned by user]\n", | |
123 | a_path); | |
124 | } /*Dry run */ | |
125 | ||
126 | /* | |
127 | * Set the ACL for this new directory so that the uss_AccountCreator | |
128 | * is the only party that has rights. This will be corrected as the | |
129 | * final action performed on the account. | |
130 | */ | |
131 | sprintf(buf, "%s %s all", a_path, uss_AccountCreator); | |
132 | if (!uss_DryRun) { | |
133 | if (uss_verbose) | |
134 | fprintf(stderr, "Setting ACL: '%s'\n", buf); | |
135 | if (uss_acl_SetAccess(buf, 1, 0)) | |
136 | return (1); | |
137 | } /*Not a dry run */ | |
138 | else { | |
139 | fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n", buf, | |
140 | a_path); | |
141 | } /*Dry run */ | |
142 | ||
143 | /* | |
144 | * Use our linked list to remember this directory's true ACL setting so | |
145 | * we may set it correctly at the tail end of the account creation. | |
146 | */ | |
147 | new_dir = malloc(sizeof(struct uss_subdir)); | |
148 | new_dir->previous = uss_currentDir; | |
149 | new_dir->path = strdup(a_path); | |
150 | new_dir->finalACL = strdup(a_access); | |
151 | uss_currentDir = new_dir; | |
152 | ||
153 | /* | |
154 | * Return the happy news. | |
155 | */ | |
156 | return (0); | |
157 | ||
158 | } /*uss_procs_BuildDir */ | |
159 | ||
160 | ||
161 | /*----------------------------------------------------------------------- | |
162 | * EXPORTED uss_procs_CpFile | |
163 | * | |
164 | * Environment: | |
165 | * Called from the code generated by the uss grammar. | |
166 | * | |
167 | * Side Effects: | |
168 | * As advertised. | |
169 | *------------------------------------------------------------------------*/ | |
170 | ||
171 | afs_int32 | |
172 | uss_procs_CpFile(char *a_path, char *a_mode, char *a_owner, char *a_proto) | |
173 | { /*uss_procs_CpFile */ | |
174 | ||
175 | int m, o; | |
176 | struct stat stbuf; | |
177 | char *cp; | |
178 | ||
179 | /* | |
180 | * Don't do anything if something has already gone wrong. | |
181 | */ | |
182 | if (uss_syntax_err) | |
183 | return (1); | |
184 | ||
185 | if (uss_verbose) | |
186 | printf("Installing '%s'\n", a_path); | |
187 | ||
188 | /* | |
189 | * If we've not been given permission to overwrite things, make sure | |
190 | * the target doesn't exist before doing anything. | |
191 | */ | |
192 | if (!uss_OverwriteThisOne) { | |
193 | strcpy(temp, a_path); | |
194 | if (!stat(temp, &stbuf)) { | |
195 | if (uss_verbose) | |
196 | printf("\t[Entry exists, NOT overwriting it]\n"); | |
197 | return (0); | |
198 | } | |
199 | } | |
200 | ||
201 | sscanf(a_mode, "%o", &m); | |
202 | o = uss_procs_GetOwner(a_owner); | |
203 | ||
204 | strcpy(temp, a_proto); | |
205 | ||
206 | if (stat(temp, &stbuf)) { | |
207 | uss_procs_PrintErr(line, "Failed to stat '%s': %s\n", a_proto, | |
208 | strerror(errno)); | |
209 | return (1); | |
210 | } | |
211 | ||
212 | if (stbuf.st_mode & S_IFDIR) { | |
213 | if ((cp = strrchr(a_path, '/')) == NULL) { | |
214 | strcat(a_proto, "/"); | |
215 | strcat(a_proto, a_path); | |
216 | } else { | |
217 | /* | |
218 | * Append the last part (file name). | |
219 | */ | |
220 | strcat(a_proto, cp); | |
221 | } | |
222 | } | |
223 | /*Target is a directory */ | |
224 | if (!uss_DryRun) { | |
225 | if (Copy(a_proto, a_path, m)) { | |
226 | uss_procs_PrintErr(line, "Failed to copy '%s' to '%s'\n", a_proto, | |
227 | a_path); | |
228 | return (1); | |
229 | } /*Copy failed */ | |
230 | } /*Not a dry run */ | |
231 | else { | |
232 | fprintf(stderr, "\t[Dry run: Copying '%s' to '%s', mode %o]\n", | |
233 | a_proto, a_path, m); | |
234 | } | |
235 | ||
236 | if (!uss_DryRun) { | |
237 | if (chown(a_path, o, -1)) { | |
238 | uss_procs_PrintErr(line, | |
239 | "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n", | |
240 | a_path, a_owner, o, strerror(errno)); | |
241 | return (1); | |
242 | } /*chown failed */ | |
243 | } /*Not a dry run */ | |
244 | else { | |
245 | fprintf(stderr, | |
246 | "\t[Dry run: chown() file '%s' to be owned by user]\n", | |
247 | a_path); | |
248 | } /*Dry run */ | |
249 | ||
250 | /* | |
251 | * Return the happy news. | |
252 | */ | |
253 | return (0); | |
254 | ||
255 | } /*uss_procs_CpFile */ | |
256 | ||
257 | ||
258 | /*----------------------------------------------------------------------- | |
259 | * EXPORTED uss_procs_EchoToFile | |
260 | * | |
261 | * Environment: | |
262 | * Called from the code generated by the uss grammar. | |
263 | * | |
264 | * Side Effects: | |
265 | * As advertised. | |
266 | *------------------------------------------------------------------------*/ | |
267 | ||
268 | afs_int32 | |
269 | uss_procs_EchoToFile(char *a_path, char *a_mode, char *a_owner, | |
270 | char *a_content) | |
271 | { /*uss_procs_EchoToFile */ | |
272 | ||
273 | int m, o; | |
274 | struct stat stbuf; | |
275 | ||
276 | /* | |
277 | * Don't do anything if something has already gone wrong. | |
278 | */ | |
279 | if (uss_syntax_err) | |
280 | return (1); | |
281 | ||
282 | if (uss_verbose) | |
283 | printf("Echoing to '%s'\n", a_path); | |
284 | ||
285 | /* | |
286 | * If we've not been given permission to overwrite things, make sure | |
287 | * the target doesn't exist before doing anything. | |
288 | */ | |
289 | if (!uss_OverwriteThisOne) { | |
290 | strcpy(temp, a_path); | |
291 | if (!stat(temp, &stbuf)) { | |
292 | if (uss_verbose) | |
293 | printf("\t[Entry exists, NOT overwriting it]\n"); | |
294 | return (0); | |
295 | } | |
296 | } | |
297 | ||
298 | sscanf(a_mode, "%o", &m); | |
299 | o = uss_procs_GetOwner(a_owner); | |
300 | ||
301 | if (!uss_DryRun) { | |
302 | if (Echo(a_content, a_path, m)) { | |
303 | uss_procs_PrintErr(line, | |
304 | "Failed to echo string '%s' to file '%s'\n", | |
305 | a_content, a_path); | |
306 | return (1); | |
307 | } | |
308 | } /*Not a dry run */ | |
309 | else { | |
310 | fprintf(stderr, "\t[Dry run: Echoing '%s' into file '%s']\n", | |
311 | a_content, a_path); | |
312 | } /*Dry run */ | |
313 | ||
314 | if (!uss_DryRun) { | |
315 | if (chown(a_path, o, -1)) { | |
316 | uss_procs_PrintErr(line, | |
317 | "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n", | |
318 | a_path, a_owner, o, strerror(errno)); | |
319 | return (1); | |
320 | } | |
321 | } /*Not a dry run */ | |
322 | else { | |
323 | fprintf(stderr, | |
324 | "\t[Dry run: chown() file '%s' to be owned by user]\n", | |
325 | a_path); | |
326 | } /*Dry run */ | |
327 | ||
328 | /* | |
329 | * Return the happy news. | |
330 | */ | |
331 | return (0); | |
332 | ||
333 | } /*uss_procs_EchoToFile */ | |
334 | ||
335 | ||
336 | /*----------------------------------------------------------------------- | |
337 | * EXPORTED uss_procs_Exec | |
338 | * | |
339 | * Environment: | |
340 | * Called from the code generated by the uss grammar, as well as | |
341 | * from uss.c itself. | |
342 | * | |
343 | * Side Effects: | |
344 | * As advertised. | |
345 | *------------------------------------------------------------------------*/ | |
346 | ||
347 | afs_int32 | |
348 | uss_procs_Exec(char *a_command) | |
349 | { /*uss_procs_Exec */ | |
350 | ||
351 | if (uss_verbose) | |
352 | printf("Running '%s'\n", a_command); | |
353 | ||
354 | if (!uss_DryRun) { | |
355 | if (system(a_command)) { | |
356 | uss_procs_PrintErr(line, "Failed to run the '%s' command: %s\n", | |
357 | a_command, strerror(errno)); | |
358 | return (1); | |
359 | } | |
360 | } /*Not a dry run */ | |
361 | else { | |
362 | fprintf(stderr, "\t[Dry run: executing '%s']\n", a_command); | |
363 | } /*Dry run */ | |
364 | ||
365 | /* | |
366 | * Return the happy news. | |
367 | */ | |
368 | return (0); | |
369 | ||
370 | } /*uss_procs_Exec */ | |
371 | ||
372 | ||
373 | /*----------------------------------------------------------------------- | |
374 | * EXPORTED uss_procs_SetLink | |
375 | * | |
376 | * Environment: | |
377 | * Called from the code generated by the uss grammar. | |
378 | * | |
379 | * Side Effects: | |
380 | * As advertised. | |
381 | *------------------------------------------------------------------------*/ | |
382 | ||
383 | afs_int32 | |
384 | uss_procs_SetLink(char *a_path1, char *a_path2, char a_type) | |
385 | { /*uss_procs_SetLink */ | |
386 | ||
387 | struct stat stbuf; | |
388 | ||
389 | if (uss_verbose) | |
390 | printf("Setting link '%s' to '%s'\n", a_path1, a_path2); | |
391 | ||
392 | /* | |
393 | * If we've not been given permission to overwrite things, make sure | |
394 | * the target doesn't exist before doing anything. | |
395 | */ | |
396 | if (!uss_OverwriteThisOne) { | |
397 | strcpy(temp, a_path2); | |
398 | if (!stat(temp, &stbuf)) { | |
399 | if (uss_verbose) | |
400 | printf("\t[Entry exists, NOT overwriting it]\n"); | |
401 | return (0); | |
402 | } | |
403 | } | |
404 | ||
405 | if (a_type == 's') { | |
406 | /* | |
407 | * Symbolic link. | |
408 | */ | |
409 | if (!uss_DryRun) { | |
410 | if (symlink(a_path1, a_path2)) { | |
411 | uss_procs_PrintErr(line, | |
412 | "Failed to make symlink '%s' to '%s': %s\n", | |
413 | a_path1, a_path2, strerror(errno)); | |
414 | return (1); | |
415 | } | |
416 | } /*Dry run */ | |
417 | else { | |
418 | fprintf(stderr, "\t[Dry run: Making symlink '%s' to '%s']\n", | |
419 | a_path1, a_path2); | |
420 | } /*Not a dry run */ | |
421 | } /*Symbolic link */ | |
422 | else { | |
423 | /* | |
424 | * Hard link. | |
425 | */ | |
426 | if (!uss_DryRun) { | |
427 | if (link(a_path1, a_path2)) { | |
428 | uss_procs_PrintErr(line, | |
429 | "Failed to make hard link '%s' to '%s': %s\n", | |
430 | a_path1, a_path2, strerror(errno)); | |
431 | return (1); | |
432 | } | |
433 | } /*Dry run */ | |
434 | else { | |
435 | fprintf(stderr, "\t[Dry run: Making hard link '%s' to '%s']\n", | |
436 | a_path1, a_path2); | |
437 | } /*Not a dry run */ | |
438 | } /*Hard link */ | |
439 | ||
440 | /* | |
441 | * Return the happy news. | |
442 | */ | |
443 | return (0); | |
444 | ||
445 | } /*uss_procs_SetLink */ | |
446 | ||
447 | ||
448 | /*----------------------------------------------------------------------- | |
449 | * EXPORTED uss_procs_GetOwner | |
450 | * | |
451 | * Environment: | |
452 | * Nothing interesting. | |
453 | * | |
454 | * Side Effects: | |
455 | * As advertised. | |
456 | *------------------------------------------------------------------------*/ | |
457 | ||
458 | int | |
459 | uss_procs_GetOwner(char *a_ownerStr) | |
460 | { /*uss_procs_GetOwner */ | |
461 | ||
462 | struct passwd *pw; /*Ptr to password file entry */ | |
463 | int ownerID; /*Numerical owner */ | |
464 | ||
465 | ownerID = atoi(a_ownerStr); | |
466 | if ((ownerID == 0) && (a_ownerStr[0] != '0')) { | |
467 | /* | |
468 | * The owner is not in numerical format | |
469 | */ | |
470 | if ((pw = getpwnam(a_ownerStr)) == NULL) { | |
471 | uss_procs_PrintErr(line, "Owner '%s' is an unknown user\n", | |
472 | a_ownerStr); | |
473 | return (1); | |
474 | } | |
475 | return (pw->pw_uid); | |
476 | } else | |
477 | return (ownerID); | |
478 | ||
479 | } /*uss_procs_GetOwner */ | |
480 | ||
481 | /*----------------------------------------------------------------------- | |
482 | * static Copy | |
483 | * | |
484 | * Description: | |
485 | * Copies the "from" file to the "to" file and sets the mode. | |
486 | * | |
487 | * Arguments: | |
488 | * a_from : File to copy from. | |
489 | * a_to : File to copy to. | |
490 | * a_mode : New Unix mode to set. | |
491 | * | |
492 | * Returns: | |
493 | * 0 if everything went well, | |
494 | * if there was a problem. | |
495 | * | |
496 | * Environment: | |
497 | * Nothing interesting. | |
498 | * | |
499 | * Side Effects: | |
500 | * As advertised. | |
501 | *------------------------------------------------------------------------*/ | |
502 | ||
503 | static int | |
504 | Copy(char *a_from, char *a_to, int a_mode) | |
505 | { /*Copy */ | |
506 | ||
507 | int fd1, fd2; | |
508 | char buf[BUFSIZ]; | |
509 | int rcnt, wcnt = -1, rc; | |
510 | ||
511 | umask(0); | |
512 | fd1 = open(a_to, O_EXCL | O_CREAT | O_WRONLY, a_mode); | |
513 | if (fd1 < 0) { | |
514 | if (errno == EEXIST) { | |
515 | /* | |
516 | * The file exists. Since we can only be called when overwriting | |
517 | * has been enabled, we back off and open the file normally (not | |
518 | * supplying O_EXCL), then continue normally. | |
519 | */ | |
520 | fd1 = open(a_to, O_CREAT | O_WRONLY, a_mode); | |
521 | if (fd1 < 0) { | |
522 | uss_procs_PrintErr(line, | |
523 | "%s: Failed to open '%s' for overwrite: %s.\n", | |
524 | uss_whoami, a_to, strerror(errno)); | |
525 | return (1); | |
526 | } | |
527 | } else { | |
528 | uss_procs_PrintErr(line, "%s: Failed to open '%s': %s.\n", | |
529 | uss_whoami, a_to, strerror(errno)); | |
530 | return (1); | |
531 | } | |
532 | } | |
533 | ||
534 | if ((fd2 = open(a_from, O_RDONLY, 0)) < 0) { | |
535 | uss_procs_PrintErr(line, "%s: Error reading '%s': %s\n", uss_whoami, | |
536 | a_from, strerror(errno)); | |
537 | close(fd1); | |
538 | return (1); | |
539 | } | |
540 | do { | |
541 | rcnt = read(fd2, buf, BUFSIZ); | |
542 | if (rcnt == -1) | |
543 | break; | |
544 | wcnt = write(fd1, buf, rcnt); | |
545 | } while (rcnt == BUFSIZ && rcnt == wcnt); | |
546 | if (rcnt == -1 || wcnt != rcnt) { | |
547 | uss_procs_PrintErr(line, "read/write error to %s\n", a_to); | |
548 | close(fd1); | |
549 | close(fd2); | |
550 | return (1); | |
551 | } | |
552 | rc = close(fd1); | |
553 | if (rc) { | |
554 | uss_procs_PrintErr(line, "Failed to close '%s' %s\n", a_to, | |
555 | strerror(errno)); | |
556 | return (1); | |
557 | } | |
558 | if ((rc = close(fd2))) | |
559 | uss_procs_PrintErr(line, "Warning: Failed to close '%s': %s\n", | |
560 | a_from, strerror(errno)); | |
561 | return (0); | |
562 | ||
563 | } /*Copy */ | |
564 | ||
565 | /*----------------------------------------------------------------------- | |
566 | * static Echo | |
567 | * | |
568 | * Description: | |
569 | * Writes a string into a file and sets its mode. | |
570 | * | |
571 | * Arguments: | |
572 | * a_s : String to write. | |
573 | * a_f : Filename to write to. | |
574 | * a_mode : New Unix mode to set. | |
575 | * | |
576 | * Returns: | |
577 | * 0 if everything went well, | |
578 | * if there was a problem. | |
579 | * | |
580 | * Environment: | |
581 | * Nothing interesting. | |
582 | * | |
583 | * Side Effects: | |
584 | * As advertised. | |
585 | *------------------------------------------------------------------------*/ | |
586 | ||
587 | static int | |
588 | Echo(char *a_s, char *a_f, int a_mode) | |
589 | { /*Echo */ | |
590 | ||
591 | int fd; | |
592 | ||
593 | umask(0); | |
594 | fd = open(a_f, O_EXCL | O_CREAT | O_WRONLY, a_mode); | |
595 | if (fd < 0) { | |
596 | if (errno == EEXIST) { | |
597 | /* | |
598 | * The file exists. Since we can only be called when | |
599 | * overwriting has been enabled, we back off and open the | |
600 | * file normally (not supplying the O_EXCL), then continue | |
601 | * normally. Notice that we must truncate the file, since | |
602 | * if the original file is longer than the stuff we're about | |
603 | * to put in, all the old data past the current write will | |
604 | * still be there. | |
605 | */ | |
606 | fd = open(a_f, O_TRUNC | O_WRONLY, a_mode); | |
607 | if (fd < 0) { | |
608 | uss_procs_PrintErr(line, | |
609 | "%s: Failed to open '%s' for overwrite: %s.\n", | |
610 | uss_whoami, a_f, strerror(errno)); | |
611 | return (1); | |
612 | } | |
613 | } else { | |
614 | uss_procs_PrintErr(line, "%s: Failed to open '%s': %s. \n", | |
615 | uss_whoami, a_f, strerror(errno)); | |
616 | return (1); | |
617 | } | |
618 | } | |
619 | if (write(fd, a_s, strlen(a_s)) != strlen(a_s) || | |
620 | write(fd, "\n", 1) != 1) { | |
621 | uss_procs_PrintErr(line, "Short write to '%s'\n", a_f); | |
622 | close(fd); | |
623 | return (1); | |
624 | } | |
625 | if (close(fd)) { | |
626 | uss_procs_PrintErr(line, "Failed to close '%s': %s\n", a_f, | |
627 | strerror(errno)); | |
628 | return (1); | |
629 | } | |
630 | return (0); | |
631 | ||
632 | } /*Echo */ | |
633 | ||
634 | /*----------------------------------------------------------------------- | |
635 | * static uss_procs_PickADir | |
636 | * | |
637 | * Description: | |
638 | * Tries to replace $AUTO by a subdir. Subdirs are given by means | |
639 | * of "G" in the configuration file. Each of the directories is | |
640 | * examined, and the one with the inimum number of entries is | |
641 | * picked. | |
642 | * | |
643 | * Arguments: | |
644 | * a_path : ??? | |
645 | * a_cp : ??? | |
646 | * | |
647 | * Returns: | |
648 | * 0 if everything went well, | |
649 | * -1 if there was a problem. | |
650 | * | |
651 | * Environment: | |
652 | * Called with THREE parameters from lex.c! | |
653 | * | |
654 | * Side Effects: | |
655 | * As advertised. | |
656 | *------------------------------------------------------------------------*/ | |
657 | ||
658 | afs_int32 | |
659 | uss_procs_PickADir(char *path, char *cp) | |
660 | { /*uss_procs_PickADir */ | |
661 | ||
662 | char cd[300]; /*Current directory for search */ | |
663 | ||
664 | int i, count, MinIndex = 0, mina = 10000; | |
665 | struct dirent *dp; | |
666 | DIR *dirp; | |
667 | char dirname[300]; | |
668 | ||
669 | if (uss_NumGroups == 0) { | |
670 | fprintf(stderr, "%s: No choice yet given to replace $AUTO\n", | |
671 | uss_whoami); | |
672 | fprintf(stderr, "%s: Use the G command before $AUTO in config file\n", | |
673 | uss_whoami); | |
674 | return (-1); | |
675 | } | |
676 | ||
677 | if (uss_Auto[0] != '\0') | |
678 | return (0); /* we have already done this for this user */ | |
679 | ||
680 | if (*(cp - 1) == '/') { /*it's ..../$AUTO */ | |
681 | for (i = 0; &path[i] != cp; i++) | |
682 | cd[i] = path[i]; | |
683 | cd[i] = '\0'; | |
684 | } else { | |
685 | if (path != cp) { | |
686 | fprintf(stderr, | |
687 | "%s: $AUTO must be used to replace the whole path or the whole name of a subdirectory. Found: %s$AUTO\n", | |
688 | uss_whoami, path); | |
689 | return (-1); | |
690 | } | |
691 | cd[0] = '/'; | |
692 | cd[1] = '\0'; | |
693 | } | |
694 | ||
695 | /* | |
696 | * We now have the current dir (cd). Search all of the given | |
697 | * subdirs (by G in template), count the number of entries in | |
698 | * each and pick the minimum. | |
699 | */ | |
700 | for (i = 0; i < uss_NumGroups; i++) { | |
701 | sprintf(dirname, "%s/%s", cd, uss_DirPool[i]); | |
702 | if ((dirp = opendir(dirname)) == NULL) { | |
703 | if (errno != ENOTDIR) | |
704 | fprintf(stderr, | |
705 | "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n", | |
706 | uss_whoami, dirname, errno); | |
707 | continue; /*Skip and continue anyway */ | |
708 | } | |
709 | count = 0; | |
710 | for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) | |
711 | if (dp->d_name[0] != '.') | |
712 | count++; /* forget about files starting with . */ | |
713 | #ifdef USS_PROCS_DB | |
714 | printf("debug: Dir '%s' has %d entries\n", dirname, count); | |
715 | #endif /* USS_PROCS_DB */ | |
716 | if (count < mina) { | |
717 | mina = count; | |
718 | MinIndex = i; | |
719 | } | |
720 | closedir(dirp); | |
721 | } | |
722 | if (mina == 10000) { /* We found nothing */ | |
723 | fprintf(stderr, "%s: Warning: No valid choice to replace $AUTO\n", | |
724 | uss_whoami); | |
725 | uss_Auto[0] = '\0'; | |
726 | } else { | |
727 | strcpy(uss_Auto, uss_DirPool[MinIndex]); | |
728 | if (uss_verbose) | |
729 | printf("Picking dir w/minimum number of entries: '%s'\n", | |
730 | uss_Auto); | |
731 | } | |
732 | return (0); | |
733 | ||
734 | } /*uss_procs_PickADir */ | |
735 | ||
736 | /*----------------------------------------------------------------------- | |
737 | * EXPORTED uss_procs_AddToDirPool | |
738 | * | |
739 | * Environment: | |
740 | * Called from the code generated by the uss grammar. | |
741 | * | |
742 | * Side Effects: | |
743 | * As advertised. | |
744 | *------------------------------------------------------------------------*/ | |
745 | ||
746 | int | |
747 | uss_procs_AddToDirPool(char *a_dirToAdd) | |
748 | { | |
749 | if (uss_NumGroups > 99) { | |
750 | return (-1); | |
751 | } | |
752 | strcpy(uss_DirPool[uss_NumGroups++], a_dirToAdd); | |
753 | return 0; | |
754 | } | |
755 | ||
756 | /*----------------------------------------------------------------------- | |
757 | * EXPORTED uss_procs_FindAndOpen | |
758 | * | |
759 | * Environment: | |
760 | * Nothing interesting. | |
761 | * | |
762 | * Side Effects: | |
763 | * As advertised. | |
764 | *------------------------------------------------------------------------*/ | |
765 | ||
766 | FILE * | |
767 | uss_procs_FindAndOpen(char *a_fileToOpen) | |
768 | { /*uss_procs_FindAndOpen */ | |
769 | ||
770 | #define NUM_TPL_PATHS 3 | |
771 | ||
772 | FILE *rv; /*Template file descriptor */ | |
773 | int i; /*Loop counter */ | |
774 | char tmp_str[uss_MAX_SIZE]; /*Tmp string */ | |
775 | static char | |
776 | TemplatePath[NUM_TPL_PATHS][1024]; /*Template directories */ | |
777 | int cant_read; /*Can't read the file? */ | |
778 | ||
779 | /* | |
780 | * If a full pathname was given, just take it as is. | |
781 | */ | |
782 | if (strchr(a_fileToOpen, '/')) { | |
783 | strcpy(tmp_str, a_fileToOpen); | |
784 | rv = fopen(a_fileToOpen, "r"); | |
785 | } else { | |
786 | /* | |
787 | * A relative pathname was given. Try to find the file in each of | |
788 | * the default template directories. | |
789 | */ | |
790 | cant_read = 0; | |
791 | ||
792 | sprintf(TemplatePath[0], "%s", "."); | |
793 | sprintf(TemplatePath[1], "/afs/%s/common/uss", uss_Cell); | |
794 | sprintf(TemplatePath[2], "%s", "/etc"); | |
795 | ||
796 | for (i = 0; i < NUM_TPL_PATHS; i++) { | |
797 | sprintf(tmp_str, "%s/%s", TemplatePath[i], a_fileToOpen); | |
798 | if ((rv = fopen(tmp_str, "r")) != NULL) | |
799 | break; | |
800 | ||
801 | /* | |
802 | * If the file was there but couldn't be opened, we have | |
803 | * to report this. | |
804 | */ | |
805 | if (errno != ENOENT) { | |
806 | cant_read = 1; | |
807 | break; | |
808 | } | |
809 | } /*Look in template directories */ | |
810 | ||
811 | /* | |
812 | * If we found and opened the file, we're happy. Otherwise, | |
813 | * print out what went wrong. | |
814 | */ | |
815 | if (rv != NULL) { | |
816 | if (uss_verbose) | |
817 | fprintf(stderr, "Using template '%s'\n", tmp_str); | |
818 | } /*Got it */ | |
819 | else { | |
820 | /* | |
821 | * Check to see if we specifically found the file but | |
822 | * couldn't read it. | |
823 | */ | |
824 | if (cant_read) | |
825 | fprintf(stderr, "%s: Can't open template '%s': %s\n", | |
826 | uss_whoami, tmp_str, strerror(errno)); | |
827 | else { | |
828 | fprintf(stderr, "%s: Can't find template '%s' in searchlist", | |
829 | uss_whoami, a_fileToOpen); | |
830 | for (i = 0; i < NUM_TPL_PATHS; i++) | |
831 | fprintf(stderr, " '%s'", TemplatePath[i]); | |
832 | fprintf(stderr, "\n"); | |
833 | } /*Can't find template */ | |
834 | } /*Didn't get it */ | |
835 | } /*Relative pathname given */ | |
836 | ||
837 | /* | |
838 | * Whatever happened, return what we got. | |
839 | */ | |
840 | return (rv); | |
841 | ||
842 | } /*uss_procs_FindAndOpen */ | |
843 | ||
844 | ||
845 | /*----------------------------------------------------------------------- | |
846 | * EXPORTED uss_procs_PrintErr | |
847 | * | |
848 | * Environment: | |
849 | * Nothing interesting. | |
850 | * | |
851 | * Side Effects: | |
852 | * As advertised. | |
853 | *------------------------------------------------------------------------*/ | |
854 | ||
855 | void | |
856 | uss_procs_PrintErr(int a_lineNum, char *a_fmt, ... ) | |
857 | { /*uss_procs_PrintErr */ | |
858 | va_list ap; | |
859 | ||
860 | va_start(ap, a_fmt); | |
861 | uss_syntax_err++; | |
862 | fprintf(stderr, "%s: Template file, line %d: ", uss_whoami, a_lineNum); | |
863 | vfprintf(stderr, a_fmt, ap); | |
864 | va_end(ap); | |
865 | } /*uss_procs_PrintErr */ |