comerr-behave-like-the-rest-of-the-world-20010918
[openafs.git] / src / package / package.c
1 /*
2  * (C) Copyright Transarc Corporation 1989
3  * Licensed Materials - Property of Transarc
4  * All Rights Reserved.
5  */
6
7 /*------------------------------------------------------------------------
8  * package.c
9  *
10  * Description:
11  *      AFS workstation configuration tool.
12  *
13  * Author:
14  *      Transarc Corporation & Carnegie Mellon University
15  *------------------------------------------------------------------------*/
16 #include <afs/param.h>
17 #include <stdio.h>              /*I/O stuff*/
18 #ifdef  AFS_AIX32_ENV
19 #include <signal.h>
20 #endif
21 #include <sys/types.h>          /*Low-level type definitions*/
22 #include <sys/stat.h>           /*Stat buffer defs*/
23 #include <sys/param.h>          /*Machine-type dependent params*/
24 #if     defined(AFS_SUN_ENV)
25 #include <sys/ioccom.h>         /* for _IOW macro */
26 #endif
27 #include <afs/com_err.h>        /*Error compiler package*/
28 #include <afs/cmd.h>            /*Command interpretation library*/
29
30 #include <netinet/in.h>
31 #include <afs/vice.h>
32 #include <afs/venus.h>
33
34 #include "globals.h"            /*Our own set of global defs*/
35 #include "package.h"            /*Generally-used definitions*/
36 #include "systype.h"            /*Systype string*/
37
38 /*
39  * Command line parameter indices.
40  */
41 #define P_CONFIG        0
42 #define P_FULLCONFIG    1
43 #define P_OVERWRITE     2
44 #define P_NOACTION      3
45 #define P_VERBOSE       4
46 #define P_SILENT        5
47 #define P_REBOOTFILES   6
48 #define P_DEBUG         7
49
50 extern int test_linecounter;    /*Line number currently being parsed*/
51 char *emalloc();
52 int check();
53 int update();
54
55 /*
56  * Set up default configuration: Perform all actions, moderate output
57  * level, handle files causing reboot, don't overwrite protected files,
58  * and turn debugging output off.
59  */
60 int     status = status_noerror;        /*Start off with no errors*/
61
62 int     opt_lazy     = FALSE;   /*Perform all actions*/
63 int     opt_silent   = FALSE;   /*Don't be overly silent*/
64 int     opt_verbose  = FALSE;   /*Don't be overly verbose*/
65 int     opt_stdin    = FALSE;   /*Read configuration from stdin*/
66 int     opt_reboot   = TRUE;    /*Update boot-critical files (e.g., vmunix)*/
67 #ifdef KFLAG
68 int     opt_kflag = TRUE;       /*Why was this KFLAG stuff ifdefed?*/
69 #endif /* KFLAG */
70 int     opt_debug = FALSE;      /*Turn off debugging output*/
71
72 CTREEPTR config_root;           /*Top of the config tree*/
73
74 char *conffile = "/etc/package";        /*Base configuration file*/
75 char filename[MAXPATHLEN];              /*Chosen configuration file name*/
76
77 /*------------------------------------------------------------------------
78  * PRIVATE packageExecute
79  *
80  * Description:
81  *      Actually perform that for which the program was invoked,
82  *      namely bringing the machine's local disk into agreement
83  *      with the given goal.
84  *
85  * Arguments:
86  *      None.
87  *
88  * Returns:
89  *      Nothing.
90  *
91  * Environment:
92  *      Everything we need to know is in globals.
93  *
94  * Side Effects:
95  *      As described.
96  *------------------------------------------------------------------------*/
97
98 static void packageExecute()
99
100 { /*packageExecute*/
101
102     FILE *fp;                   /*Descriptor for configuration filename*/
103     int code;                   /*Return value from functions*/
104     static char parse_err[80];  /*Parsing error string*/
105
106     /*
107      * If we're getting our configuration info from stdin, go straight
108      * for it.  Otherwise, open the config file, build the tree, and
109      * then close the config file.
110      */
111     if (opt_stdin) {
112         code = BuildConfigTree(stdin);
113         if (code) {
114             sprintf(parse_err,
115                     "** Lexical error in configuration file, line %d",
116                     test_linecounter);
117             fatal(parse_err);
118         }
119     }
120     else {
121         verbose_message("Loading configuration file '%s'", filename);
122         fp = efopen(filename, "r");
123         verbose_message("Building configuration tree");
124         code = BuildConfigTree(fp);
125         if (code) {
126             sprintf(parse_err,
127                     "** Lexical error in configuration file, line %d",
128                     test_linecounter);
129             fatal(parse_err);
130         }
131         (void) fclose(fp);
132     }
133
134     /*
135      * Now that the configuration tree is built, ``apply'' the check
136      * function on that tree.
137      */
138     verbose_message("Checking integrity of configuration tree");
139     ApplyConfigTree(check);
140
141     /*
142      * The config tree seems fine, so ``apply'' the update function
143      * on the tree.
144      */
145     verbose_message("Updating local disk to match configuration tree");
146     ApplyConfigTree(update);
147
148     loudonly_message("Sync");
149     if (!opt_lazy && (sync() < 0))
150         message("Sync; %m");
151
152     /*
153      * We're all done!  Print out a parting message (if we've been asked
154      * to be verbose) and return to our caller.  The overall status has
155      * been recorded in the global status variable.
156      */
157     verbose_message("Done");
158
159 } /*packageExecute*/
160
161 #define MAXSIZE 2048
162 struct output {
163   afs_int32 found;
164   char  name[MAXSIZE];
165 } sysoutput;
166
167 char *getsystype()
168 {
169   afs_int32            code;
170   struct ViceIoctl data;
171   
172   data.in       = (char *)&sysoutput;
173   data.out      = (char *)&sysoutput;
174   data.out_size = MAXSIZE;
175   data.in_size  = sizeof(afs_int32);
176
177   code = pioctl(0, VIOC_AFS_SYSNAME, &data, 1);
178   if (!code && sysoutput.found) 
179       return(sysoutput.name);
180   return(SYS_NAME);
181 }
182
183 /*------------------------------------------------------------------------
184  * PRIVATE packageInit
185  *
186  * Description:
187  *      Routine called when package is invoked, responsible for basic
188  *      initialization, command line parsing, and calling the
189  *      routine that does all the work.
190  *
191  * Arguments:
192  *      as      : Command syntax descriptor.
193  *      arock   : Associated rock (not used here).
194  *
195  * Returns:
196  *      Zero (but may exit the entire program on error!)
197  *
198  * Environment:
199  *      Puts everything it finds into global variables.
200  *
201  * Side Effects:
202  *      Initializes this program.
203  *------------------------------------------------------------------------*/
204
205 static int packageInit(as, arock)
206     struct cmd_syndesc *as;
207     char *arock;
208
209 { /*packageInit*/
210
211     systype = getsystype();
212
213     /*
214      * Set up the default configuration file to use.
215      */
216     sprintf(filename, "%s.%s", conffile, systype);
217
218     if (as->parms[P_DEBUG].items != 0) {
219         opt_debug = TRUE;
220         debug_message("Debugging output enabled");
221     }
222
223     if (as->parms[P_CONFIG].items != 0) {
224         /*
225          * Pull out the configuration file name, tack on the sysname.
226          */
227         sprintf(filename,"%s.%s", as->parms[P_CONFIG].items->data, systype);
228     }
229
230     if (as->parms[P_FULLCONFIG].items != 0) {
231         /*
232          * Make sure we use only one of -config and -fullconfig.
233          */
234         if (as->parms[P_CONFIG].items != 0) {
235             message("Can't use the -config and -fullconfig switches together");
236             status = -1;
237             exit(status);
238         } /*Switch conflict*/
239
240         /*
241          * If ``stdin'' is the configuration file to use, make sure we
242          * remember that fact.
243          */
244         if (strcmp(as->parms[P_FULLCONFIG].items->data, "stdin") == 0) {
245             opt_stdin = TRUE;
246             filename[0] = '\0';
247         }
248         else
249             sprintf(filename, "%s", as->parms[P_FULLCONFIG].items->data);
250     } /*Full config file name given*/
251
252     if (as->parms[P_OVERWRITE].items != 0)
253         opt_kflag = FALSE;
254     else
255         opt_kflag = TRUE;
256
257     if (as->parms[P_NOACTION].items != 0)
258         opt_lazy = TRUE;
259
260     if (as->parms[P_VERBOSE].items != 0)
261         opt_verbose = TRUE;
262
263     if (as->parms[P_SILENT].items != 0) {
264         if (opt_verbose) {
265             message("Can't use the -silent and -verbose flags together");
266             status = -1;
267             exit(status);
268         }
269         else
270             opt_silent = TRUE;
271     }
272
273     if (as->parms[P_REBOOTFILES].items != 0)
274         opt_reboot = FALSE;
275
276     /*
277      * Now that we've finished parsing, execute the package function.
278      * This sets the global status variable, so we simply exit with
279      * its value.
280      */
281     packageExecute();
282     exit(status);
283
284 } /*packageInit*/
285
286 #include "AFS_component_version_number.c"
287
288 main(argc, argv)
289     int argc;
290     char **argv;
291
292 { /*main*/
293
294     register afs_int32 code;                    /*Return code*/
295     register struct cmd_syndesc *ts;    /*Ptr to cmd line syntax descriptor*/
296
297 #ifdef  AFS_AIX32_ENV
298     /*
299      * The following signal action for AIX is necessary so that in case of a 
300      * crash (i.e. core is generated) we can include the user's data section 
301      * in the core dump. Unfortunately, by default, only a partial core is
302      * generated which, in many cases, isn't too useful.
303      */
304     struct sigaction nsa;
305     
306     sigemptyset(&nsa.sa_mask);
307     nsa.sa_handler = SIG_DFL;
308     nsa.sa_flags = SA_FULLDUMP;
309     sigaction(SIGSEGV, &nsa, NULL);
310 #endif
311     /*
312       * Set file mode creation mask.
313       */
314     (void)umask(0);
315
316     /*
317      * Set up to parse the command line.
318      */
319     ts = cmd_CreateSyntax("initcmd", packageInit, 0,
320                           "initialize the program");
321     cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
322                 "base name of configuration file");
323     cmd_AddParm(ts, "-fullconfig", CMD_SINGLE, CMD_OPTIONAL,
324                 "full name of configuration file, or stdin for standard input");
325     cmd_AddParm(ts, "-overwrite", CMD_FLAG, CMD_OPTIONAL,
326                 "overwrite write-protected files");
327     cmd_AddParm(ts, "-noaction", CMD_FLAG, CMD_OPTIONAL,
328                 "show what would be done, but don't do it");
329     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
330                 "give more details about what's happening");
331     cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL,
332                 "supress all output");
333     cmd_AddParm(ts, "-rebootfiles", CMD_FLAG, CMD_OPTIONAL,
334                 "don't handle boot-critical files");
335     cmd_AddParm(ts, "-debug", CMD_FLAG, CMD_OPTIONAL,
336                 "enable debugging input");
337
338     /*
339      * Set up the appropriate error tables.
340      */
341     initialize_CMD_error_table();
342
343     /*
344      * Parse command line switches & execute the command, then get the
345      * heck out of here.
346      */
347     code = cmd_Dispatch(argc, argv);
348     if (code) {
349       com_err(argv[0], code, "while dispatching command line");
350       exit(-1);
351     }
352
353 } /*main*/