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