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