convert-from-bsd-to-posix-string-and-memory-functions-20010807
[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
47 static int Copy();
48 static int Echo();
49
50 /*-----------------------------------------------------------------------
51  * EXPORTED uss_procs_BuildDir
52  *
53  * Environment:
54  *      Called from the code generated by the uss grammar.
55  *
56  * Side Effects:
57  *      As advertised.
58  *------------------------------------------------------------------------*/
59
60 afs_int32 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",
81                a_path, 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, sys_errlist[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",
119                     a_path, m);
120     } /*Dry run*/
121
122     if (!uss_DryRun) {
123         if (chmod(a_path, m)) {
124             uss_procs_PrintErr(line,
125                 "Can't chmod() directory '%s' to be '%s' : %s\n",
126                 a_path, a_mode, sys_errlist[errno]);
127                 return(1);
128         } /* chmod the directory */
129         if (chown(a_path, o, -1)) {
130             uss_procs_PrintErr(line,
131                                "Can't chown() directory '%s' to be owned by '%s' (uid %d): %s\n",
132                                a_path, a_owner, o, sys_errlist[errno]);
133             return(1);
134         } /*Couldn't chown*/
135     } /*Not a dry run*/
136     else {
137         fprintf(stderr,
138                 "\t[Dry run: chown() directory '%s' to be owned by user]\n",
139                 a_path);
140     } /*Dry run*/
141
142     /*
143       * Set the ACL for this new directory so that the uss_AccountCreator
144       * is the only party that has rights.  This will be corrected as the
145       * final action performed on the account.
146       */
147     sprintf(buf, "%s %s all", a_path, uss_AccountCreator);
148     if (!uss_DryRun) {
149         if (uss_verbose)
150             fprintf(stderr,
151                     "Setting ACL: '%s'\n", buf);
152         if (uss_acl_SetAccess(buf, 1, 0))
153             return(1);
154     } /*Not a dry run*/
155     else {
156         fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s) on '%s']\n",
157                 buf, a_path);
158     } /*Dry run*/
159
160     /*
161      * Use our linked list to remember this directory's true ACL setting so
162      * we may set it correctly at the tail end of the account creation.
163      */
164     new_dir = (struct uss_subdir *) malloc(sizeof(struct uss_subdir));
165     new_dir->previous = uss_currentDir;
166     new_dir->path = (char *) malloc(strlen(a_path)+1);
167     strcpy(new_dir->path, a_path);
168     new_dir->finalACL = (char *) malloc(strlen(a_access)+1);
169     strcpy(new_dir->finalACL, a_access);
170     uss_currentDir = new_dir;
171
172     /*
173      * Return the happy news.
174      */
175     return(0);
176
177 } /*uss_procs_BuildDir*/
178
179
180 /*-----------------------------------------------------------------------
181  * EXPORTED uss_procs_CpFile
182  *
183  * Environment:
184  *      Called from the code generated by the uss grammar.
185  *
186  * Side Effects:
187  *      As advertised.
188  *------------------------------------------------------------------------*/
189
190 afs_int32 uss_procs_CpFile(a_path, a_mode, a_owner, a_proto)
191     char *a_path;
192     char *a_mode;
193     char *a_owner;
194     char *a_proto;
195     
196 { /*uss_procs_CpFile*/
197     
198     int m, o;
199     struct stat stbuf;
200     char *cp;
201
202     /*
203      * Don't do anything if something has already gone wrong.
204      */
205     if (uss_syntax_err)
206         return(1);
207
208     if (uss_verbose)
209         printf("Installing '%s'\n", a_path);
210
211     /*
212      * If we've not been given permission to overwrite things, make sure
213      * the target doesn't exist before doing anything.
214      */
215     if (!uss_OverwriteThisOne) {
216         strcpy(temp, a_path);
217         if (!stat(temp, &stbuf)) {
218             if (uss_verbose)
219                 printf("\t[Entry exists, NOT overwriting it]\n");
220             return(0);
221         }
222     }
223
224     sscanf(a_mode, "%o", &m);
225     o = uss_procs_GetOwner(a_owner);
226
227     strcpy(temp, a_proto);
228
229     if (stat(temp, &stbuf)) {
230         uss_procs_PrintErr(line, "Failed to stat '%s': %s\n",
231                            a_proto, sys_errlist[errno]);
232         return(1);
233     }
234
235     if (stbuf.st_mode & S_IFDIR) {
236         if ((cp = strrchr(a_path, '/')) == NULL) {
237             strcat(a_proto, "/");
238             strcat(a_proto, a_path);
239         }
240         else {
241             /*
242              * Append the last part (file name).
243              */
244             strcat(a_proto, cp);
245         }
246     } /*Target is a directory*/
247
248     if (!uss_DryRun) {
249         if (Copy(a_proto, a_path, m)) {
250             uss_procs_PrintErr(line,
251                                "Failed to copy '%s' to '%s'\n",
252                                a_proto, a_path);
253             return(1);
254         } /*Copy failed*/
255     } /*Not a dry run*/
256     else {
257         fprintf(stderr, "\t[Dry run: Copying '%s' to '%s', mode %o]\n",
258                 a_proto, a_path, m);
259     }
260
261     if (!uss_DryRun) {
262         if (chown(a_path, o, -1)) {
263             uss_procs_PrintErr(line,
264                                "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
265                                a_path, a_owner, o, sys_errlist[errno]);
266             return(1);
267         } /*chown failed*/
268     } /*Not a dry run*/
269     else {
270         fprintf(stderr, "\t[Dry run: chown() file '%s' to be owned by user]\n",
271                 a_path);
272     } /*Dry run*/
273
274     /*
275      * Return the happy news.
276      */
277     return(0);
278     
279 } /*uss_procs_CpFile*/
280
281
282 /*-----------------------------------------------------------------------
283  * EXPORTED uss_procs_EchoToFile
284  *
285  * Environment:
286  *      Called from the code generated by the uss grammar.
287  *
288  * Side Effects:
289  *      As advertised.
290  *------------------------------------------------------------------------*/
291
292 afs_int32 uss_procs_EchoToFile(a_path, a_mode, a_owner, a_content)
293     char *a_path;
294     char *a_mode;
295     char *a_owner;
296     char *a_content;
297     
298 { /*uss_procs_EchoToFile*/
299     
300     int m, o;
301     struct stat stbuf;
302     
303     /*
304      * Don't do anything if something has already gone wrong.
305      */
306     if (uss_syntax_err)
307         return(1);
308     
309     if (uss_verbose)
310         printf("Echoing to '%s'\n", a_path);
311     
312     /*
313      * If we've not been given permission to overwrite things, make sure
314      * the target doesn't exist before doing anything.
315      */
316     if (!uss_OverwriteThisOne) {
317         strcpy(temp, a_path);
318         if (!stat(temp, &stbuf)) {
319             if (uss_verbose)
320                 printf("\t[Entry exists, NOT overwriting it]\n");
321             return(0);
322         }
323     }
324     
325     sscanf(a_mode, "%o", &m);
326     o = uss_procs_GetOwner(a_owner);
327     
328     if (!uss_DryRun) {
329         if (Echo(a_content, a_path, m)){
330             uss_procs_PrintErr(line,
331                                "Failed to echo string '%s' to file '%s'\n",
332                                a_content, a_path);
333             return(1);
334         }
335     } /*Not a dry run*/
336     else {
337         fprintf(stderr, "\t[Dry run: Echoing '%s' into file '%s']\n",
338                 a_content, a_path);
339     } /*Dry run*/
340     
341     if (!uss_DryRun) {
342         if (chown(a_path, o, -1)){
343             uss_procs_PrintErr(line,
344                                "Can't chown() file '%s' to be owned by '%s' (uid %d): %s\n",
345                                a_path, a_owner, o, sys_errlist[errno]);
346             return(1);
347         }
348     } /*Not a dry run*/
349     else {
350         fprintf(stderr,
351                 "\t[Dry run: chown() file '%s' to be owned by user]\n",
352                 a_path);
353     } /*Dry run*/
354     
355     /*
356      * Return the happy news.
357      */
358     return(0);
359     
360 } /*uss_procs_EchoToFile*/
361
362
363 /*-----------------------------------------------------------------------
364  * EXPORTED uss_procs_Exec
365  *
366  * Environment:
367  *      Called from the code generated by the uss grammar, as well as
368  *      from uss.c itself.
369  *
370  * Side Effects:
371  *      As advertised.
372  *------------------------------------------------------------------------*/
373
374 afs_int32 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,
385                            "Failed to run the '%s' command: %s\n",
386                            a_command, sys_errlist[errno]);
387         return(1);
388       }
389     } /*Not a dry run*/
390     else {
391       fprintf(stderr, "\t[Dry run: executing '%s']\n", a_command);
392     } /*Dry run*/
393
394     /*
395      * Return the happy news.
396      */
397     return(0);
398
399 } /*uss_procs_Exec*/
400
401
402 /*-----------------------------------------------------------------------
403  * EXPORTED uss_procs_SetLink
404  *
405  * Environment:
406  *      Called from the code generated by the uss grammar.
407  *
408  * Side Effects:
409  *      As advertised.
410  *------------------------------------------------------------------------*/
411
412 afs_int32 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, sys_errlist[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, sys_errlist[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 uss_procs_GetOwner(a_ownerStr)
491     char *a_ownerStr;
492
493 { /*uss_procs_GetOwner*/
494
495     struct passwd *pw;  /*Ptr to password file entry*/
496     int ownerID;        /*Numerical owner*/
497
498     ownerID = atoi(a_ownerStr);
499     if ((ownerID == 0) && (a_ownerStr[0] != '0')) {
500         /*
501          * The owner is not in numerical format
502          */
503         if ((pw = getpwnam(a_ownerStr)) == NULL) {
504             uss_procs_PrintErr(line,
505                                "Owner '%s' is an unknown user\n",
506                                a_ownerStr);
507             return(1);
508         }
509         return(pw->pw_uid);
510     }
511     else
512         return(ownerID);
513
514 } /*uss_procs_GetOwner*/
515
516 /*-----------------------------------------------------------------------
517  * static Copy
518  *
519  * Description:
520  *       Copies the "from" file to the "to" file and sets the mode. 
521  *
522  * Arguments:
523  *      a_from : File to copy from.
524  *      a_to   : File to copy to.
525  *      a_mode : New Unix mode to set.
526  *
527  * Returns:
528  *      0 if everything went well,
529  *      if there was a problem.
530  *
531  * Environment:
532  *      Nothing interesting.
533  *
534  * Side Effects:
535  *      As advertised.
536  *------------------------------------------------------------------------*/
537
538 static int 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, sys_errlist[errno]);
563                 return(1);
564             }
565         } else {
566             uss_procs_PrintErr(line, "%s: Failed to open '%s': %s.\n",
567                                uss_whoami, a_to, sys_errlist[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",
574                            uss_whoami, a_from, sys_errlist[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,
585                            "Failed to close '%s' %s\n",
586                            a_to, sys_errlist[errno]);
587         return(1);
588     }
589     if(rc = close(fd2))
590         uss_procs_PrintErr(line, "Warning: Failed to close '%s': %s\n",
591                            a_from, sys_errlist[errno]);
592     return(0);
593
594 } /*Copy*/
595
596 /*-----------------------------------------------------------------------
597  * static Echo
598  *
599  * Description:
600  *       Writes a string into a file and sets its mode.
601  *
602  * Arguments:
603  *      a_s    : String to write.
604  *      a_f    : Filename to write to.
605  *      a_mode : New Unix mode to set.
606  *
607  * Returns:
608  *      0 if everything went well,
609  *      if there was a problem.
610  *
611  * Environment:
612  *      Nothing interesting.
613  *
614  * Side Effects:
615  *      As advertised.
616  *------------------------------------------------------------------------*/
617
618 static int 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, sys_errlist[errno]);
645                 return(1);
646             }
647         } else {
648             uss_procs_PrintErr(line, "%s: Failed to open '%s': %s. \n",
649                                uss_whoami, a_f, sys_errlist[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",
657                            a_f, sys_errlist[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 uss_procs_PickADir(path, cp)
689     char *path;
690     char *cp;
691
692 { /*uss_procs_PickADir*/
693
694     char cd[300]; /*Current  directory for search*/
695
696     int i, count, MinIndex, mina = 10000;
697     struct dirent *dp;
698     DIR *dirp;
699     char dirname[300];
700
701     if (uss_NumGroups == 0){
702         fprintf(stderr,"%s: No choice yet given to replace $AUTO\n",
703                 uss_whoami);
704         fprintf(stderr,"%s: Use the G command before $AUTO in config file\n",
705                 uss_whoami);
706         return(-1);
707     }
708
709     if (uss_Auto[0] != '\0')
710         return(0); /* we have already done this for this user */
711
712     if (*(cp-1) == '/') { /*it's ..../$AUTO*/
713         for (i = 0; &path[i] != cp; i++)
714             cd[i] = path[i];
715         cd[i] = '\0';
716     }
717     else {
718         if (path != cp){ 
719             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);
720             return(-1);
721         }
722         cd[0] = '/'; cd[1] = '\0';
723     }
724
725     /* 
726      * We now have the current dir (cd).  Search all of the given
727      * subdirs (by G in template), count the number of entries in
728      * each and pick the minimum.
729      */
730     for (i=0; i < uss_NumGroups; i++) {
731         sprintf(dirname, "%s/%s", cd, uss_DirPool[i]);
732         if ((dirp = opendir(dirname)) == NULL) {
733             if (errno != ENOTDIR)
734                 fprintf(stderr,
735                         "%s: Warning: Can't open dir '%s' (errno=%d). Skipped.\n",
736                         uss_whoami, dirname, errno);
737             continue;   /*Skip and continue anyway*/
738         }
739         count = 0;
740         for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
741             if (dp->d_name[0] != '.')
742                 count++; /* forget about files starting with .*/
743 #ifdef USS_PROCS_DB
744         printf("debug: Dir '%s' has %d entries\n", dirname, count);
745 #endif /* USS_PROCS_DB */
746         if (count < mina) {
747             mina = count;
748             MinIndex = i;
749         }
750         closedir(dirp);
751     }
752     if (mina == 10000) { /* We found nothing */
753         fprintf(stderr,"%s: Warning: No valid choice to replace $AUTO\n",
754                 uss_whoami);
755         uss_Auto[0]= '\0';
756     }
757     else {
758         strcpy(uss_Auto, uss_DirPool[MinIndex]);
759         if (uss_verbose)
760             printf("Picking dir w/minimum number of entries: '%s'\n",
761                    uss_Auto);
762     }
763     return(0);
764
765 } /*uss_procs_PickADir*/
766
767 /*-----------------------------------------------------------------------
768  * EXPORTED uss_procs_AddToDirPool
769  *
770  * Environment:
771  *      Called from the code generated by the uss grammar.
772  *
773  * Side Effects:
774  *      As advertised.
775  *------------------------------------------------------------------------*/
776
777 int uss_procs_AddToDirPool(a_dirToAdd)
778     char *a_dirToAdd;
779 {
780     if (uss_NumGroups > 99) {
781        return(-1);
782     }
783     strcpy(uss_DirPool[uss_NumGroups++], a_dirToAdd);
784     return 0;
785 }
786
787 /*-----------------------------------------------------------------------
788  * EXPORTED uss_procs_FindAndOpen
789  *
790  * Environment:
791  *      Nothing interesting.
792  *
793  * Side Effects:
794  *      As advertised.
795  *------------------------------------------------------------------------*/
796
797 FILE *uss_procs_FindAndOpen(a_fileToOpen)
798     char *a_fileToOpen;
799
800 { /*uss_procs_FindAndOpen*/
801
802 #define NUM_TPL_PATHS 3
803
804     FILE *rv;                            /*Template file descriptor*/
805     int i;                               /*Loop counter*/
806     char tmp_str[uss_MAX_SIZE];          /*Tmp string*/
807     static char
808       TemplatePath[NUM_TPL_PATHS][1024]; /*Template directories*/
809     int cant_read;                       /*Can't read the file?*/
810
811     /*
812      * If a full pathname was given, just take it as is.
813      */
814     if (strchr(a_fileToOpen, '/')) {
815         strcpy(tmp_str, a_fileToOpen);
816         rv = fopen(a_fileToOpen, "r");
817     }
818     else {
819         /*
820          * A relative pathname was given.  Try to find the file in each of
821          * the default template directories.
822          */
823         cant_read = 0;
824         
825         sprintf(TemplatePath[0], "%s", ".");
826         sprintf(TemplatePath[1], "/afs/%s/common/uss", uss_Cell);
827         sprintf(TemplatePath[2], "%s", "/etc");
828         
829         for (i = 0; i < NUM_TPL_PATHS; i++) {
830             sprintf(tmp_str, "%s/%s", TemplatePath[i], a_fileToOpen);
831             if ((rv = fopen(tmp_str, "r")) != NULL)
832                 break;
833
834             /*
835              * If the file was there but couldn't be opened, we have
836              * to report this.
837              */
838             if (errno != ENOENT) {
839                 cant_read = 1;
840                 break;
841             }
842         } /*Look in template directories*/
843         
844         /*
845          * If we found and opened the file, we're happy.  Otherwise,
846          * print out what went wrong.
847          */
848         if (rv != NULL) {
849             if (uss_verbose)
850                 fprintf(stderr, "Using template '%s'\n", tmp_str);
851         } /*Got it*/
852         else {
853             /*
854              * Check to see if we specifically found the file but
855              * couldn't read it.
856              */
857             if (cant_read)
858                 fprintf(stderr,
859                         "%s: Can't open template '%s': %s\n",
860                         uss_whoami, tmp_str, sys_errlist[errno]);
861             else {
862                 fprintf(stderr,
863                         "%s: Can't find template '%s' in searchlist",
864                         uss_whoami, a_fileToOpen);
865                 for (i = 0; i < NUM_TPL_PATHS; i++)
866                     fprintf(stderr, " '%s'", TemplatePath[i]);
867                 fprintf(stderr, "\n");
868             } /*Can't find template*/
869         } /*Didn't get it*/
870     } /*Relative pathname given*/
871     
872     /*
873      * Whatever happened, return what we got.
874      */
875     return(rv);
876
877 } /*uss_procs_FindAndOpen*/
878
879
880 /*-----------------------------------------------------------------------
881  * EXPORTED uss_procs_PrintErr
882  *
883  * Environment:
884  *      Nothing interesting.
885  *
886  * Side Effects:
887  *      As advertised.
888  *------------------------------------------------------------------------*/
889
890 void uss_procs_PrintErr(a_lineNum, a_fmt, a_1, a_2, a_3, a_4, a_5)
891     int a_lineNum;
892     char *a_fmt;
893     char *a_1;
894     char *a_2;
895     char *a_3;
896     char *a_4;
897     char *a_5;
898
899 { /*uss_procs_PrintErr*/
900
901     uss_syntax_err++;
902     fprintf(stderr,"%s: Template file, line %d: ", uss_whoami, a_lineNum);
903     fprintf(stderr, a_fmt, a_1, a_2, a_3, a_4, a_5);
904
905 } /*uss_procs_PrintErr*/