Expand PMF_FN_* macros.
[netbsd-mini2440.git] / distrib / utils / sysinst / main.c
blobc443c8bf3def3e3093daf42f1cd3aba5bc8e59d9
1 /* $NetBSD: main.c,v 1.53 2008/12/21 11:02:41 martin Exp $ */
3 /*
4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved.
7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Piermont Information Systems Inc.
21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
39 /* main sysinst program. */
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/uio.h>
44 #include <stdio.h>
45 #include <signal.h>
46 #include <curses.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49 #include <dirent.h>
50 #include <locale.h>
52 #include "defs.h"
53 #include "md.h"
54 #include "msg_defs.h"
55 #include "menu_defs.h"
56 #include "txtwalk.h"
58 int main(int, char **);
59 static void select_language(void);
60 static void usage(void);
61 static void miscsighandler(int);
62 static void ttysighandler(int);
63 static void cleanup(void);
64 static void process_f_flag(char *);
66 static int exit_cleanly = 0; /* Did we finish nicely? */
67 int logging; /* are we logging everything? */
68 int scripting; /* are we building a script? */
69 FILE *logfp; /* log file */
70 FILE *script; /* script file */
72 #ifdef DEBUG
73 extern int log_flip(void);
74 #endif
76 /* String defaults and stuff for processing the -f file argument. */
78 struct f_arg {
79 const char *name;
80 const char *dflt;
81 char *var;
82 int size;
85 static const struct f_arg fflagopts[] = {
86 {"release", REL, rel, sizeof rel},
87 {"machine", MACH, machine, sizeof machine},
88 {"xfer dir", "/usr/INSTALL", xfer_dir, sizeof xfer_dir},
89 {"ext dir", "", ext_dir, sizeof ext_dir},
90 {"ftp host", SYSINST_FTP_HOST, ftp.host, sizeof ftp.host},
91 {"ftp dir", SYSINST_FTP_DIR, ftp.dir, sizeof ftp.dir},
92 {"ftp prefix", "/" MACH "/binary/sets", set_dir, sizeof set_dir},
93 {"ftp user", "ftp", ftp.user, sizeof ftp.user},
94 {"ftp pass", "", ftp.pass, sizeof ftp.pass},
95 {"ftp proxy", "", ftp.proxy, sizeof ftp.proxy},
96 {"nfs host", "", nfs_host, sizeof nfs_host},
97 {"nfs dir", "/bsd/release", nfs_dir, sizeof nfs_dir},
98 {"cd dev", "cd0a", cdrom_dev, sizeof cdrom_dev},
99 {"fd dev", "/dev/fd0a", fd_dev, sizeof fd_dev},
100 {"local dev", "", localfs_dev, sizeof localfs_dev},
101 {"local fs", "ffs", localfs_fs, sizeof localfs_fs},
102 {"local dir", "release", localfs_dir, sizeof localfs_dir},
103 {"targetroot mount", "/targetroot", targetroot_mnt, sizeof targetroot_mnt},
104 {"dist postfix", ".tgz", dist_postfix, sizeof dist_postfix},
105 {"diskname", "mydisk", bsddiskname, sizeof bsddiskname},
107 {NULL, NULL, NULL, 0}
110 static void
111 init(void)
113 const struct f_arg *arg;
115 sizemult = 1;
116 disktype = "unknown";
117 tmp_ramdisk_size = 0;
118 doessf = "";
119 clean_xfer_dir = 0;
120 mnt2_mounted = 0;
121 fd_type = "msdos";
123 for (arg = fflagopts; arg->name != NULL; arg++)
124 strlcpy(arg->var, arg->dflt, arg->size);
128 main(int argc, char **argv)
130 WINDOW *win;
131 int ch;
133 logging = 0; /* shut them off unless turned on by the user */
134 init();
135 #ifdef DEBUG
136 log_flip();
137 #endif
138 scripting = 0;
140 /* Check for TERM ... */
141 if (!getenv("TERM")) {
142 (void)fprintf(stderr,
143 "sysinst: environment variable TERM not set.\n");
144 exit(1);
147 /* argv processing */
148 while ((ch = getopt(argc, argv, "Dr:f:")) != -1)
149 switch(ch) {
150 case 'D': /* set to get past certain errors in testing */
151 debug = 1;
152 break;
153 case 'r':
154 /* Release name other than compiled in release. */
155 strncpy(rel, optarg, sizeof rel);
156 break;
157 case 'f':
158 /* Definition file to read. */
159 process_f_flag(optarg);
160 break;
161 case '?':
162 default:
163 usage();
166 md_init();
168 /* initialize message window */
169 if (menu_init()) {
170 __menu_initerror();
171 exit(1);
175 * Put 'messages' in a window that has a one-character border
176 * on the real screen.
178 win = newwin(getmaxy(stdscr) - 2, getmaxx(stdscr) - 2, 1, 1);
179 if (win == NULL) {
180 (void)fprintf(stderr,
181 "sysinst: screen too small\n");
182 exit(1);
184 if (has_colors()) {
186 * XXX This color trick should be done so much better,
187 * but is it worth it?
189 wbkgd(win, COLOR_PAIR(1));
190 wattrset(win, COLOR_PAIR(1));
192 msg_window(win);
194 /* Watch for signals and clean up */
195 (void)atexit(cleanup);
196 (void)signal(SIGINT, ttysighandler);
197 (void)signal(SIGQUIT, ttysighandler);
198 (void)signal(SIGHUP, miscsighandler);
200 /* redraw screen */
201 touchwin(stdscr);
202 refresh();
204 /* Ensure we have mountpoint for target filesystems */
205 mkdir(targetroot_mnt, S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
207 select_language();
208 get_kb_encoding();
210 /* Menu processing */
211 process_menu(MENU_netbsd, NULL);
213 exit_cleanly = 1;
214 return 0;
217 static int
218 set_language(menudesc *m, void *arg)
220 char **fnames = arg;
222 msg_file(fnames[m->cursel]);
223 return 1;
226 static void
227 select_language(void)
229 DIR *dir;
230 struct dirent *dirent;
231 char **lang_msg, **fnames;
232 int max_lang = 16, num_lang = 0;
233 const char *cp;
234 menu_ent *opt = 0;
235 int lang_menu = -1;
236 int lang;
238 dir = opendir(".");
239 if (!dir)
240 return;
242 lang_msg = malloc(max_lang * sizeof *lang_msg);
243 fnames = malloc(max_lang * sizeof *fnames);
244 if (!lang_msg || !fnames)
245 goto done;
247 lang_msg[0] = strdup(msg_string(MSG_sysinst_message_language));
248 fnames[0] = 0;
249 num_lang = 1;
251 while ((dirent = readdir(dir)) != 0) {
252 if (memcmp(dirent->d_name, "sysinstmsgs.", 12))
253 continue;
254 if (msg_file(dirent->d_name))
255 continue;
256 cp = msg_string(MSG_sysinst_message_language);
257 if (!strcmp(cp, lang_msg[0]))
258 continue;
259 if (num_lang == max_lang) {
260 char **new;
261 max_lang *= 2;
262 new = realloc(lang_msg, max_lang * sizeof *lang_msg);
263 if (!new)
264 break;
265 lang_msg = new;
266 new = realloc(fnames, max_lang * sizeof *fnames);
267 if (!new)
268 break;
269 fnames = new;
271 fnames[num_lang] = strdup(dirent->d_name);
272 lang_msg[num_lang++] = strdup(cp);
274 msg_file(0);
275 closedir(dir);
276 dir = 0;
278 if (num_lang == 1)
279 goto done;
281 opt = calloc(num_lang, sizeof *opt);
282 if (!opt)
283 goto done;
285 for (lang = 0; lang < num_lang; lang++) {
286 opt[lang].opt_name = lang_msg[lang];
287 opt[lang].opt_menu = OPT_NOMENU;
288 opt[lang].opt_action = set_language;
291 lang_menu = new_menu(NULL, opt, num_lang, -1, 12, 0, 0, MC_NOEXITOPT,
292 NULL, NULL, NULL, NULL, NULL);
294 if (lang_menu != -1) {
295 msg_display(MSG_hello);
296 process_menu(lang_menu, fnames);
299 done:
300 if (dir)
301 closedir(dir);
302 if (lang_menu != -1)
303 free_menu(lang_menu);
304 free(opt);
305 while (num_lang) {
306 free(lang_msg[--num_lang]);
307 free(fnames[num_lang]);
309 free(lang_msg);
310 free(fnames);
312 /* set locale according to selected language */
313 cp = msg_string(MSG_sysinst_message_locale);
314 if (cp) {
315 setlocale(LC_CTYPE, cp);
316 setenv("LC_CTYPE", cp, 1);
320 /* toplevel menu handler ... */
321 void
322 toplevel(void)
325 /* Display banner message in (english, francais, deutsch..) */
326 msg_display(MSG_hello);
327 msg_display_add(MSG_md_hello);
328 msg_display_add(MSG_thanks);
331 * Undo any stateful side-effects of previous menu choices.
332 * XXX must be idempotent, since we get run each time the main
333 * menu is displayed.
335 unwind_mounts();
336 /* ... */
340 /* The usage ... */
342 static void
343 usage(void)
346 (void)fprintf(stderr, msg_string(MSG_usage));
347 exit(1);
350 /* ARGSUSED */
351 static void
352 miscsighandler(int signo)
356 * we need to cleanup(), but it was already scheduled with atexit(),
357 * so it'll be invoked on exit().
359 exit(1);
362 static void
363 ttysighandler(int signo)
367 * if we want to ignore a TTY signal (SIGINT or SIGQUIT), then we
368 * just return. If we want to forward a TTY signal, we forward it
369 * to the specified process group.
371 * This functionality is used when setting up and displaying child
372 * output so that the child gets the signal and presumably dies,
373 * but sysinst continues. We use this rather than actually ignoring
374 * the signals, because that will be be passed on to a child
375 * through fork/exec, whereas special handlers get reset on exec..
377 if (ttysig_ignore)
378 return;
379 if (ttysig_forward) {
380 killpg(ttysig_forward, signo);
381 return;
385 * we need to cleanup(), but it was already scheduled with atexit(),
386 * so it'll be invoked on exit().
388 exit(1);
391 static void
392 cleanup(void)
394 time_t tloc;
396 (void)time(&tloc);
398 #if 0
399 restore_etc();
400 #endif
401 /* Ensure we aren't inside the target tree */
402 chdir(getenv("HOME"));
403 unwind_mounts();
404 umount_mnt2();
406 endwin();
408 if (logging) {
409 fprintf(logfp, "Log ended at: %s\n", asctime(localtime(&tloc)));
410 fflush(logfp);
411 fclose(logfp);
413 if (scripting) {
414 fprintf(script, "# Script ended at: %s\n",
415 asctime(localtime(&tloc)));
416 fflush(script);
417 fclose(script);
420 if (!exit_cleanly)
421 fprintf(stderr, "\n\nsysinst terminated.\n");
425 /* process function ... */
427 void
428 process_f_flag(char *f_name)
430 char buffer[STRSIZE];
431 int len;
432 const struct f_arg *arg;
433 FILE *fp;
434 char *cp, *cp1;
436 /* open the file */
437 fp = fopen(f_name, "r");
438 if (fp == NULL) {
439 fprintf(stderr, msg_string(MSG_config_open_error), f_name);
440 exit(1);
443 while (fgets(buffer, sizeof buffer, fp) != NULL) {
444 cp = buffer + strspn(buffer, " \t");
445 if (strchr("#\r\n", *cp) != NULL)
446 continue;
447 for (arg = fflagopts; arg->name != NULL; arg++) {
448 len = strlen(arg->name);
449 if (memcmp(cp, arg->name, len) != 0)
450 continue;
451 cp1 = cp + len;
452 cp1 += strspn(cp1, " \t");
453 if (*cp1++ != '=')
454 continue;
455 cp1 += strspn(cp1, " \t");
456 len = strcspn(cp1, " \n\r\t");
457 cp1[len] = 0;
458 strlcpy(arg->var, cp1, arg->size);
459 break;
463 fclose(fp);