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