Annotation of src/distrib/utils/sysinst/util.c, Revision 1.56
1.55 fvdl 1: /* $NetBSD: util.c,v 1.51.2.2 2000/08/31 12:40:50 hubertf Exp $ */
1.1 phil 2:
3: /*
4: * Copyright 1997 Piermont Information Systems Inc.
5: * All rights reserved.
6: *
7: * Written by Philip A. Nelson for Piermont Information Systems Inc.
8: *
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:
1.42 cgd 19: * This product includes software developed for the NetBSD Project by
1.1 phil 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.
24: *
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.
36: *
37: */
38:
39: /* util.c -- routines that don't really fit anywhere else... */
40:
41: #include <stdio.h>
1.10 jonathan 42: #include <stdarg.h>
1.1 phil 43: #include <unistd.h>
1.5 phil 44: #include <sys/types.h>
1.4 phil 45: #include <sys/param.h>
46: #include <sys/sysctl.h>
1.5 phil 47: #include <sys/stat.h>
1.2 phil 48: #include <curses.h>
1.37 bouyer 49: #include <errno.h>
1.52 hubertf 50: #include <fts.h>
1.1 phil 51: #include "defs.h"
1.5 phil 52: #include "md.h"
1.1 phil 53: #include "msg_defs.h"
54: #include "menu_defs.h"
1.4 phil 55:
1.14 jonathan 56: /*
57: * local prototypes
58: */
1.29 mrg 59: struct tarstats {
1.22 jonathan 60: int nselected;
61: int nfound;
62: int nnotfound;
63: int nerror;
64: int nsuccess;
1.44 cgd 65: int nskipped;
1.22 jonathan 66: } tarstats;
67:
1.44 cgd 68: int extract_file __P((char *path));
1.22 jonathan 69: int extract_dist __P((void));
1.37 bouyer 70: int cleanup_dist __P((const char *path));
1.22 jonathan 71: int distribution_sets_exist_p __P((const char *path));
1.54 fvdl 72: static int check_for __P((unsigned int mode, const char *pathname));
1.4 phil 73:
1.29 mrg 74: int
75: dir_exists_p(path)
76: const char *path;
1.22 jonathan 77: {
1.54 fvdl 78: return file_mode_match(path, S_IFDIR);
79: }
1.29 mrg 80:
1.54 fvdl 81: int
82: file_exists_p(path)
83: const char *path;
84: {
85: return file_mode_match(path, S_IFREG);
1.22 jonathan 86: }
87:
1.29 mrg 88: int
1.54 fvdl 89: file_mode_match(path, mode)
1.29 mrg 90: const char *path;
1.54 fvdl 91: unsigned int mode;
1.22 jonathan 92: {
1.54 fvdl 93: struct stat st;
1.29 mrg 94:
1.54 fvdl 95: return (stat(path, &st) == 0 && (st.st_mode & mode) != 0);
1.22 jonathan 96: }
97:
1.29 mrg 98: int
99: distribution_sets_exist_p(path)
100: const char *path;
1.22 jonathan 101: {
102: char buf[STRSIZE];
103: int result;
104:
105: result = 1;
106: snprintf(buf, STRSIZE, "%s/%s", path, "kern.tgz");
107: result = result && file_exists_p(buf);
108:
109: snprintf(buf, STRSIZE, "%s/%s", path, "etc.tgz");
110: result = result && file_exists_p(buf);
111:
112: return(result);
113: }
114:
115:
1.29 mrg 116: void
117: get_ramsize()
1.4 phil 118: {
1.29 mrg 119: long len = sizeof(long);
1.4 phil 120: int mib[2] = {CTL_HW, HW_PHYSMEM};
121:
122: sysctl(mib, 2, (void *)&ramsize, (size_t *)&len, NULL, 0);
123:
124: /* Find out how many Megs ... round up. */
125: rammb = (ramsize + MEG - 1) / MEG;
126: }
127:
1.1 phil 128: static int asked = 0;
129:
1.29 mrg 130: void
1.50 fvdl 131: ask_sizemult(cylsize)
132: int cylsize;
1.1 phil 133: {
1.50 fvdl 134: current_cylsize = cylsize; /* XXX */
1.29 mrg 135:
1.1 phil 136: if (!asked) {
1.50 fvdl 137: msg_display(MSG_sizechoice);
1.29 mrg 138: process_menu(MENU_sizechoice);
1.1 phil 139: }
140: asked = 1;
1.9 phil 141: }
142:
1.29 mrg 143: void
1.50 fvdl 144: reask_sizemult(cylsize)
145: int cylsize;
1.9 phil 146: {
1.29 mrg 147:
1.9 phil 148: asked = 0;
1.50 fvdl 149: ask_sizemult(cylsize);
1.1 phil 150: }
151:
1.29 mrg 152: void
153: run_makedev()
1.3 phil 154: {
1.22 jonathan 155: char *owd;
156:
1.39 bouyer 157: wclear(stdscr);
158: wrefresh(stdscr);
1.29 mrg 159: msg_display(MSG_makedev);
1.5 phil 160: sleep (1);
1.14 jonathan 161:
1.29 mrg 162: owd = getcwd(NULL,0);
1.22 jonathan 163:
1.14 jonathan 164: /* make /dev, in case the user didn't extract it. */
165: make_target_dir("/dev");
1.10 jonathan 166: target_chdir_or_die("/dev");
1.56 ! fvdl 167: run_prog(0, NULL, "/bin/sh MAKEDEV all");
1.22 jonathan 168:
169: chdir(owd);
170: free(owd);
1.5 phil 171: }
172:
173:
1.29 mrg 174: /*
175: * Load files from floppy. Requires a /mnt2 directory for mounting them.
176: */
177: int
178: get_via_floppy()
1.5 phil 179: {
180: char distname[STRSIZE];
181: char fddev[STRSIZE] = "/dev/fd0a";
182: char fname[STRSIZE];
183: char fullname[STRSIZE];
1.34 garbled 184: char catcmd[STRSIZE];
1.7 phil 185: distinfo *list;
1.5 phil 186: char post[4];
187: int mounted = 0;
1.8 phil 188: int first;
1.5 phil 189: struct stat sb;
190:
1.29 mrg 191: cd_dist_dir("unloading from floppy");
1.7 phil 192:
1.29 mrg 193: msg_prompt_add(MSG_fddev, fddev, fddev, STRSIZE);
1.5 phil 194:
195: list = dist_list;
1.7 phil 196: while (list->name) {
1.29 mrg 197: strcpy(post, ".aa");
198: snprintf(distname, STRSIZE, "%s%s", list->name, dist_postfix);
1.8 phil 199: while (list->getit && strcmp(&post[1],list->fdlast) <= 0) {
1.29 mrg 200: snprintf(fname, STRSIZE, "%s%s", list->name, post);
201: snprintf(fullname, STRSIZE, "/mnt2/%s", fname);
1.8 phil 202: first = 1;
1.5 phil 203: while (!mounted || stat(fullname, &sb)) {
1.8 phil 204: if (mounted)
1.56 ! fvdl 205: run_prog(0, NULL, "/sbin/umount /mnt2");
1.8 phil 206: if (first)
1.29 mrg 207: msg_display(MSG_fdmount, fname);
1.8 phil 208: else
1.29 mrg 209: msg_display(MSG_fdnotfound, fname);
210: process_menu(MENU_fdok);
1.8 phil 211: if (!yesno)
212: return 0;
1.56 ! fvdl 213: while (run_prog(0, NULL,
1.35 bouyer 214: "/sbin/mount -r -t %s %s /mnt2",
1.29 mrg 215: fdtype, fddev)) {
216: msg_display(MSG_fdremount, fname);
217: process_menu(MENU_fdremount);
1.5 phil 218: if (!yesno)
219: return 0;
220: }
221: mounted = 1;
1.8 phil 222: first = 0;
1.5 phil 223: }
1.34 garbled 224: sprintf(catcmd, "/bin/cat %s >> %s",
225: fullname, distname);
226: if (logging)
227: (void)fprintf(log, "%s\n", catcmd);
228: if (scripting)
229: (void)fprintf(script, "%s\n", catcmd);
230: do_system(catcmd);
1.8 phil 231: if (post[2] < 'z')
232: post[2]++;
1.5 phil 233: else
1.29 mrg 234: post[2] = 'a', post[1]++;
1.5 phil 235: }
1.56 ! fvdl 236: run_prog(0, NULL, "/sbin/umount /mnt2");
1.5 phil 237: mounted = 0;
238: list++;
239: }
240: #ifndef DEBUG
1.10 jonathan 241: chdir("/"); /* back to current real root */
1.5 phil 242: #endif
1.6 phil 243: return 1;
244: }
245:
1.29 mrg 246: /*
247: * Get from a CDROM distribution.
248: */
1.6 phil 249: int
1.29 mrg 250: get_via_cdrom()
1.6 phil 251: {
1.22 jonathan 252: char tmpdir[STRSIZE];
253:
1.29 mrg 254: /*
255: * Fill in final default path, similar to ftp path
256: * because we expect the CDROM structure to be the
257: * same as the ftp site.
258: */
259: strncat(cdrom_dir, machine, STRSIZE - strlen(cdrom_dir));
260: strncat(cdrom_dir, ftp_prefix, STRSIZE - strlen(cdrom_dir));
1.28 fvdl 261:
262: /* Get CD-rom device name and path within CD-rom */
1.29 mrg 263: process_menu(MENU_cdromsource);
1.6 phil 264:
1.22 jonathan 265: again:
1.56 ! fvdl 266: run_prog(0, NULL, "/sbin/umount /mnt2");
1.22 jonathan 267:
1.6 phil 268: /* Mount it */
1.56 ! fvdl 269: if (run_prog(0, NULL,
1.35 bouyer 270: "/sbin/mount -rt cd9660 /dev/%sa /mnt2", cdrom_dev)) {
1.22 jonathan 271: msg_display(MSG_badsetdir, cdrom_dev);
1.29 mrg 272: process_menu(MENU_cdrombadmount);
1.6 phil 273: if (!yesno)
274: return 0;
1.22 jonathan 275: if (!ignorerror)
276: goto again;
277: }
278:
279: snprintf(tmpdir, STRSIZE, "%s/%s", "/mnt2", cdrom_dir);
280:
281: /* Verify distribution files exist. */
282: if (distribution_sets_exist_p(tmpdir) == 0) {
283: msg_display(MSG_badsetdir, tmpdir);
1.29 mrg 284: process_menu(MENU_cdrombadmount);
1.22 jonathan 285: if (!yesno)
286: return (0);
287: if (!ignorerror)
288: goto again;
1.6 phil 289: }
290:
291: /* return location, don't clean... */
1.22 jonathan 292: strncpy(ext_dir, tmpdir, STRSIZE);
1.6 phil 293: clean_dist_dir = 0;
294: mnt2_mounted = 1;
1.5 phil 295: return 1;
1.7 phil 296: }
297:
1.22 jonathan 298:
299: /*
300: * Get from a pathname inside an unmounted local filesystem
301: * (e.g., where sets were preloaded onto a local DOS partition)
302: */
1.29 mrg 303: int
304: get_via_localfs()
1.16 mhitch 305: {
1.22 jonathan 306: char tmpdir[STRSIZE];
307:
1.16 mhitch 308: /* Get device, filesystem, and filepath */
309: process_menu (MENU_localfssource);
310:
1.22 jonathan 311: again:
1.56 ! fvdl 312: run_prog(0, NULL, "/sbin/umount /mnt2");
1.22 jonathan 313:
1.16 mhitch 314: /* Mount it */
1.56 ! fvdl 315: if (run_prog(0, NULL, "/sbin/mount -rt %s /dev/%s /mnt2",
1.35 bouyer 316: localfs_fs, localfs_dev)) {
1.22 jonathan 317:
1.29 mrg 318: msg_display(MSG_localfsbadmount, localfs_dir, localfs_dev);
319: process_menu(MENU_localfsbadmount);
1.16 mhitch 320: if (!yesno)
321: return 0;
1.22 jonathan 322: if (!ignorerror)
1.29 mrg 323: goto again;
1.22 jonathan 324: }
325:
326: snprintf(tmpdir, STRSIZE, "%s/%s", "/mnt2", localfs_dir);
327:
328: /* Verify distribution files exist. */
329: if (distribution_sets_exist_p(tmpdir) == 0) {
330: msg_display(MSG_badsetdir, tmpdir);
1.29 mrg 331: process_menu(MENU_localfsbadmount);
1.22 jonathan 332: if (!yesno)
333: return 0;
334: if (!ignorerror)
335: goto again;
1.16 mhitch 336: }
337:
338: /* return location, don't clean... */
1.22 jonathan 339: strncpy(ext_dir, tmpdir, STRSIZE);
1.16 mhitch 340: clean_dist_dir = 0;
341: mnt2_mounted = 1;
342: return 1;
343: }
1.7 phil 344:
1.29 mrg 345: /*
346: * Get from an already-mounted pathname.
347: */
1.22 jonathan 348:
349: int get_via_localdir(void)
350: {
351:
352: /* Get device, filesystem, and filepath */
1.29 mrg 353: process_menu(MENU_localdirsource);
1.22 jonathan 354:
355: again:
356: /* Complain if not a directory */
357: if (dir_exists_p(localfs_dir) == 0) {
358:
1.29 mrg 359: msg_display(MSG_badlocalsetdir, localfs_dir);
360: process_menu(MENU_localdirbad);
1.22 jonathan 361: if (!yesno)
362: return (0);
363: if (!ignorerror)
364: goto again;
365: }
366:
367: /* Verify distribution files exist. */
368: if (distribution_sets_exist_p(localfs_dir) == 0) {
369: msg_display(MSG_badsetdir, localfs_dir);
1.29 mrg 370: process_menu(MENU_localdirbad);
1.22 jonathan 371: if (!yesno)
372: return (0);
373: if (!ignorerror)
374: goto again;
375: }
376:
377: /* return location, don't clean... */
1.29 mrg 378: strncpy(ext_dir, localfs_dir, STRSIZE);
1.22 jonathan 379: clean_dist_dir = 0;
380: mnt2_mounted = 0;
381: return 1;
382: }
383:
384:
1.29 mrg 385: void
386: cd_dist_dir(forwhat)
387: char *forwhat;
1.7 phil 388: {
1.19 phil 389: char *cwd;
390:
1.10 jonathan 391: /* ask user for the mountpoint. */
1.29 mrg 392: msg_prompt(MSG_distdir, dist_dir, dist_dir, STRSIZE, forwhat);
1.10 jonathan 393:
394: /* make sure the directory exists. */
395: make_target_dir(dist_dir);
1.7 phil 396:
397: clean_dist_dir = 1;
1.10 jonathan 398: target_chdir_or_die(dist_dir);
1.19 phil 399:
400: /* Set ext_dir for absolute path. */
1.29 mrg 401: cwd = getcwd(NULL,0);
402: strncpy(ext_dir, cwd, STRSIZE);
1.19 phil 403: free (cwd);
1.7 phil 404: }
405:
1.10 jonathan 406:
1.29 mrg 407: /*
408: * Support for custom distribution fetches / unpacks.
409: */
410: void
411: toggle_getit(num)
412: int num;
413: {
1.7 phil 414:
415: dist_list[num].getit ^= 1;
416: }
417:
1.29 mrg 418: void
419: show_cur_distsets()
1.7 phil 420: {
421: distinfo *list;
422:
1.29 mrg 423: msg_display(MSG_cur_distsets);
1.48 cgd 424: msg_table_add(MSG_cur_distsets_header);
1.7 phil 425: list = dist_list;
426: while (list->name) {
1.48 cgd 427: msg_table_add(MSG_cur_distsets_row, list->desc,
1.29 mrg 428: list->getit ? msg_string(MSG_yes) : msg_string(MSG_no));
1.7 phil 429: list++;
430: }
1.1 phil 431: }
1.10 jonathan 432:
1.12 phil 433: /* Do we want a verbose extract? */
434: static int verbose = -1;
435:
436: void
1.29 mrg 437: ask_verbose_dist()
1.12 phil 438: {
1.29 mrg 439:
1.12 phil 440: if (verbose < 0) {
1.29 mrg 441: msg_display(MSG_verboseextract);
442: process_menu(MENU_noyes);
1.12 phil 443: verbose = yesno;
1.36 bouyer 444: wclear(stdscr);
445: wrefresh(stdscr);
1.12 phil 446: }
447: }
448:
1.44 cgd 449: int
1.29 mrg 450: extract_file(path)
451: char *path;
1.12 phil 452: {
453: char *owd;
1.44 cgd 454: int tarexit, rv;
1.12 phil 455:
456: owd = getcwd (NULL,0);
457:
1.22 jonathan 458: /* check tarfile exists */
459: if (!file_exists_p(path)) {
460: tarstats.nnotfound++;
1.44 cgd 461:
462: msg_display(MSG_notarfile, path);
463: process_menu(MENU_noyes);
464: return (yesno == 0);
1.22 jonathan 465: }
466:
467: tarstats.nfound++;
1.14 jonathan 468: /* cd to the target root. */
1.12 phil 469: target_chdir_or_die("/");
470:
1.14 jonathan 471: /* now extract set files files into "./". */
1.56 ! fvdl 472: tarexit = run_prog(RUN_DISPLAY, NULL,
1.35 bouyer 473: "pax -zr%spe -f %s", verbose ? "v" : "", path);
1.22 jonathan 474:
1.17 phil 475: /* Check tarexit for errors and give warning. */
1.22 jonathan 476: if (tarexit) {
477: tarstats.nerror++;
1.44 cgd 478:
479: msg_display(MSG_tarerror, path);
480: process_menu(MENU_noyes);
481: rv = (yesno == 0);
1.22 jonathan 482: } else {
483: tarstats.nsuccess++;
1.44 cgd 484: rv = 0;
1.22 jonathan 485: }
486:
1.29 mrg 487: chdir(owd);
488: free(owd);
1.44 cgd 489:
490: return (rv);
1.12 phil 491: }
492:
1.19 phil 493:
1.29 mrg 494: /*
1.37 bouyer 495: * Extract_dist **REQUIRES** an absolute path in ext_dir. Any code
1.19 phil 496: * that sets up dist_dir for use by extract_dist needs to put in the
497: * full path name to the directory.
498: */
499:
1.22 jonathan 500: int
1.29 mrg 501: extract_dist()
1.12 phil 502: {
503: char distname[STRSIZE];
504: char fname[STRSIZE];
505: distinfo *list;
1.44 cgd 506: int punt;
1.12 phil 507:
1.22 jonathan 508: /* reset failure/success counters */
1.31 perry 509: memset(&tarstats, 0, sizeof(tarstats));
1.22 jonathan 510:
1.32 garbled 511: /*endwin();*/
1.44 cgd 512: for (punt = 0, list = dist_list; list->name != NULL; list++) {
1.15 phil 513: if (list->getit) {
1.22 jonathan 514: tarstats.nselected++;
1.44 cgd 515: if (punt) {
516: tarstats.nskipped++;
517: continue;
518: }
1.37 bouyer 519: if (cleanup_dist(list->name) == 0) {
520: msg_display(MSG_cleanup_warn);
521: process_menu(MENU_ok);
522: }
1.29 mrg 523: (void)snprintf(distname, STRSIZE, "%s%s", list->name,
524: dist_postfix);
525: (void)snprintf(fname, STRSIZE, "%s/%s", ext_dir,
526: distname);
1.44 cgd 527:
528: /* if extraction failed and user aborted, punt. */
529: punt = extract_file(fname);
1.15 phil 530: }
1.12 phil 531: }
1.22 jonathan 532:
1.43 cgd 533: puts(CL); /* XXX */
534: wclear(stdscr);
1.17 phil 535: wrefresh(stdscr);
1.22 jonathan 536:
537: if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) {
1.29 mrg 538: msg_display(MSG_endtarok);
539: process_menu(MENU_ok);
1.22 jonathan 540: return 0;
541: } else {
542: /* We encountered errors. Let the user know. */
543: msg_display(MSG_endtar,
1.44 cgd 544: tarstats.nselected, tarstats.nnotfound, tarstats.nskipped,
1.22 jonathan 545: tarstats.nfound, tarstats.nsuccess, tarstats.nerror);
1.29 mrg 546: process_menu(MENU_ok);
1.22 jonathan 547: return 1;
548: }
1.12 phil 549: }
550:
1.11 jonathan 551: /*
1.37 bouyer 552: * Do pre-extract cleanup for set 'name':
553: * open a file named '/dist/<name>_obsolete file', which contain a list of
554: * files to kill from the target. For each file, test if it is present on
555: * the target. Then display the list of files which will be removed,
556: * ask user for confirmation, and process.
557: * Non-empty directories will be renaned to <directory.old>.
558: */
559:
560: /* definition for a list of files. */
561: struct filelist {
562: struct filelist *next;
563: char name[MAXPATHLEN];
564: mode_t type;
565: };
566:
567: int
568: cleanup_dist(name)
569: const char *name;
570: {
571: char file_path[MAXPATHLEN];
572: char file_name[MAXPATHLEN];
573: FILE *list_file;
574: struct filelist *head = NULL;
575: struct filelist *current;
576: int saved_errno;
577: struct stat st;
578: int retval = 1;
579: int needok = 0;
580:
581: snprintf(file_path, MAXPATHLEN, "/dist/%s_obsolete", name);
582: list_file = fopen(file_path, "r");
583: if (list_file == NULL) {
584: saved_errno = errno;
585: if (logging)
586: fprintf(log, "Open of %s failed: %s\n", file_path,
587: strerror(saved_errno));
588: if (saved_errno == ENOENT)
589: return 1;
590: msg_display_add(MSG_openfail, name, strerror(saved_errno));
591: process_menu(MENU_ok);
592: return 0;
593: }
594: while (fgets(file_name, MAXPATHLEN, list_file)) {
595: /* ignore lines that don't begin with '/' */
596: if (file_name[0] != '/')
597: continue;
598: /* Remove trailing \n if any */
599: if (file_name[strlen(file_name)-1] == '\n')
600: file_name[strlen(file_name)-1] = '\0';
601: snprintf(file_path, MAXPATHLEN, "%s%s", target_prefix(),
602: file_name);
603: if (lstat(file_path, &st) != 0) {
604: saved_errno = errno;
605: if (logging)
606: fprintf(log, "stat() of %s failed: %s\n",
607: file_path, strerror(saved_errno));
608: if (saved_errno == ENOENT)
609: continue;
610: msg_display_add(MSG_statfail, file_path,
611: strerror(saved_errno));
612: process_menu(MENU_ok);
613: return 0;
614: }
615: if (head == NULL) {
616: head = current = malloc(sizeof(struct filelist));
617: if (head == NULL) {
618: fprintf(stderr, "out of memory\n");
619: exit(1);
620: }
621: } else {
622: current->next = malloc(sizeof(struct filelist));
623: if (head == NULL) {
624: fprintf(stderr, "out of memory\n");
625: exit(1);
626: }
627: current = current->next;
628: }
629: current->next = NULL;
630: snprintf(current->name, MAXPATHLEN, "%s", file_path);
631: current->type = st.st_mode & S_IFMT;
632: if (logging)
633: fprintf(log, "Adding file %s, type %d to list of "
634: "obsolete file\n", current->name, current->type);
635: }
636: if (head == NULL)
1.38 bouyer 637: return 1;
1.37 bouyer 638: #if 0
639: /* XXX doesn't work, too many files printed ! */
640: msg_display(MSG_deleting_files);
641: for (current = head; current != NULL; current = current->next) {
1.49 cgd 642: if (current->type != S_IFDIR) {
643: /* XXX msg_printf_add going/gone away */
1.37 bouyer 644: msg_printf_add("%s ", current->name);
1.49 cgd 645: }
1.37 bouyer 646: }
647: msg_display_add(MSG_deleting_dirs);
648: for (current = head; current != NULL; current = current->next) {
1.49 cgd 649: if (current->type == S_IFDIR) {
650: /* XXX msg_printf_add going/gone away */
1.37 bouyer 651: msg_printf_add("%s ", current->name);
1.49 cgd 652: }
1.37 bouyer 653: }
654: process_menu(MENU_ok);
655: #endif
656: /* first remove files */
657: for (current = head; current != NULL; current = current->next) {
658: if (current->type == S_IFDIR)
659: continue;
660: if (scripting)
661: (void)fprintf(script, "rm %s\n", current->name);
662: if (unlink(current->name) != 0) {
663: saved_errno = errno;
1.51 hubertf 664: if (saved_errno == ENOENT)
665: continue; /* don't worry about
666: non-existing files */
1.37 bouyer 667: if (logging)
668: fprintf(log, "rm %s failed: %s\n",
669: current->name, strerror(saved_errno));
670: msg_display_add(MSG_unlink_fail, current->name,
671: strerror(saved_errno));
672: retval = 0;
673: needok = 1;
674: }
675:
676: }
677: /* now dirs */
678: for (current = head; current != NULL; current = current->next) {
679: if (current->type != S_IFDIR)
680: continue;
681: if (rmdir(current->name) == 0) {
682: if (scripting)
683: (void)fprintf(script, "rmdir %s\n",
684: current->name);
685: continue;
686: }
687: saved_errno = errno;
688: if (saved_errno == ENOTEMPTY) {
689: if (logging)
690: fprintf(log, "dir %s not empty, "
691: "trying to rename to %s.old\n",
692: current->name, current->name);
693: snprintf(file_path, MAXPATHLEN,
694: "%s.old", current->name);
695: if (scripting)
696: (void)fprintf(script, "mv %s %s\n",
697: current->name, file_path);
698: needok = 1;
699: if (rename(current->name, file_path) != 0) {
700: saved_errno = errno;
701: if (logging)
702: fprintf(log, "mv %s %s failed: %s\n",
703: current->name, file_path,
704: strerror(saved_errno));
705: msg_display_add(MSG_rename_fail, current->name,
706: file_path, strerror(errno));
707: retval = 0;
708: }
709: msg_display_add(MSG_renamed_dir, current->name,
710: file_path);
711: } else { /* rmdir error */
1.55 fvdl 712: /*
713: * Don't worry about non-existing directories.
714: */
715: if (saved_errno == ENOENT)
716: continue;
1.37 bouyer 717: if (logging)
718: fprintf(log, "rm %s failed: %s\n",
719: current->name, strerror(saved_errno));
720: msg_display_add(MSG_unlink_fail, current->name,
721: strerror(saved_errno));
722: retval = 0;
723: needok = 1;
724: }
725: }
726: if (needok)
727: process_menu(MENU_ok);
728: return retval;
729: }
730:
731: /*
1.29 mrg 732: * Get and unpack the distribution.
733: * show success_msg if installation completes. Otherwise,,
734: * show failure_msg and wait for the user to ack it before continuing.
1.11 jonathan 735: * success_msg and failure_msg must both be 0-adic messages.
736: */
1.45 cgd 737: int
1.29 mrg 738: get_and_unpack_sets(success_msg, failure_msg)
1.47 cgd 739: msg success_msg;
740: msg failure_msg;
1.11 jonathan 741: {
1.29 mrg 742:
1.20 jonathan 743: /* Ensure mountpoint for distribution files exists in current root. */
1.32 garbled 744: (void) mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
745: if (scripting)
746: (void)fprintf(script, "mkdir /mnt2\nchmod 755 /mnt2\n");
1.20 jonathan 747:
1.26 phil 748: /* Find out which files to "get" if we get files. */
1.37 bouyer 749: wclear(stdscr);
750: wrefresh(stdscr);
1.29 mrg 751: process_menu(MENU_distset);
1.26 phil 752:
1.37 bouyer 753: /* ask user whether to do normal or verbose extraction */
754: ask_verbose_dist();
755:
1.11 jonathan 756: /* Get the distribution files */
1.46 cgd 757: do {
758: got_dist = 0;
759: process_menu(MENU_distmedium);
760: } while (got_dist == -1);
1.26 phil 761:
1.11 jonathan 762: if (nodist)
1.45 cgd 763: return 1;
1.20 jonathan 764:
1.22 jonathan 765: if (got_dist) {
1.11 jonathan 766:
1.22 jonathan 767: /* Extract the distribution, abort on errors. */
1.45 cgd 768: if (extract_dist())
769: return 1;
1.11 jonathan 770:
771: /* Configure the system */
1.29 mrg 772: run_makedev();
1.11 jonathan 773:
774: /* Other configuration. */
775: mnt_net_config();
776:
1.19 phil 777: /* Clean up dist dir (use absolute path name) */
1.11 jonathan 778: if (clean_dist_dir)
1.56 ! fvdl 779: run_prog(0, NULL, "/bin/rm -rf %s", ext_dir);
1.11 jonathan 780:
781: /* Mounted dist dir? */
782: if (mnt2_mounted)
1.56 ! fvdl 783: run_prog(0, NULL, "/sbin/umount /mnt2");
1.14 jonathan 784:
1.29 mrg 785: /* Install/Upgrade complete ... reboot or exit to script */
786: msg_display(success_msg);
787: process_menu(MENU_ok);
1.45 cgd 788: return 0;
1.22 jonathan 789: }
790:
1.29 mrg 791: msg_display(failure_msg);
792: process_menu(MENU_ok);
1.45 cgd 793: return 1;
1.14 jonathan 794: }
1.22 jonathan 795:
796:
1.14 jonathan 797:
798: /*
799: * Do a quick sanity check that the target can reboot.
800: * return 1 if everything OK, 0 if there is a problem.
801: * Uses a table of files we expect to find after a base install/upgrade.
802: */
803:
804: /* test flag and pathname to check for after unpacking. */
1.54 fvdl 805: struct check_table { unsigned int mode; const char *path;} checks[] = {
806: { S_IFREG, "/netbsd" },
807: { S_IFDIR, "/etc" },
808: { S_IFREG, "/etc/fstab" },
809: { S_IFREG, "/sbin/init" },
810: { S_IFREG, "/bin/sh" },
811: { S_IFREG, "/etc/rc" },
812: { S_IFREG, "/etc/rc.subr" },
813: { S_IFREG, "/etc/rc.conf" },
814: { S_IFDIR, "/dev" },
815: { S_IFCHR, "/dev/console" },
1.14 jonathan 816: /* XXX check for rootdev in target /dev? */
1.54 fvdl 817: { S_IFREG, "/etc/fstab" },
818: { S_IFREG, "/sbin/fsck" },
819: { S_IFREG, "/sbin/fsck_ffs" },
820: { S_IFREG, "/sbin/mount" },
821: { S_IFREG, "/sbin/mount_ffs" },
822: { S_IFREG, "/sbin/mount_nfs" },
1.20 jonathan 823: #if defined(DEBUG) || defined(DEBUG_CHECK)
1.54 fvdl 824: { S_IFREG, "/foo/bar" }, /* bad entry to exercise warning */
1.14 jonathan 825: #endif
826: { 0, 0 }
827:
828: };
829:
830: /*
831: * Check target for a single file.
832: */
1.29 mrg 833: static int
1.54 fvdl 834: check_for(mode, pathname)
835: unsigned int mode;
1.29 mrg 836: const char *pathname;
1.14 jonathan 837: {
1.18 jonathan 838: int found;
1.14 jonathan 839:
1.54 fvdl 840: found = (target_test(mode, pathname) == 0);
1.18 jonathan 841: if (found == 0)
1.14 jonathan 842: msg_display(MSG_rootmissing, pathname);
1.18 jonathan 843: return found;
1.14 jonathan 844: }
845:
1.25 jonathan 846: /*
847: * Check that all the files in check_table are present in the
848: * target root. Warn if not found.
849: */
1.14 jonathan 850: int
851: sanity_check()
852: {
853: int target_ok = 1;
854: struct check_table *p;
855:
856: for (p = checks; p->path; p++) {
1.54 fvdl 857: target_ok = target_ok && check_for(p->mode, p->path);
1.14 jonathan 858: }
859: if (target_ok)
860: return 0;
861:
862: /* Uh, oh. Something's missing. */
863: msg_display(MSG_badroot);
864: process_menu(MENU_ok);
865: return 1;
1.11 jonathan 866: }
1.32 garbled 867:
868: /* set reverse to 1 to default to no */
869: int askyesno(int reverse)
870: {
871: WINDOW *yesnowin;
872: int c, found;
873:
1.40 simonb 874: yesnowin = subwin(stdscr, 5, 20, getmaxy(stdscr)/2 - 2, getmaxx(stdscr)/2 - 10);
1.41 garbled 875: if (yesnowin == NULL) {
876: fprintf(stderr, "sysinst: failed to allocate yes/no box\n");
877: exit(1);
878: }
1.32 garbled 879: box(yesnowin, '*', '*');
880: wmove(yesnowin, 2,2);
881:
882: if (reverse)
883: waddstr(yesnowin, "Yes or No: [N]");
884: else
885: waddstr(yesnowin, "Yes or No: [Y]");
886:
887: wrefresh(yesnowin);
888: while ((c = getchar())) {
889: if (c == 'y' || c == 'Y') {
890: found = 1;
891: break;
892: } else if (c == 'n' || c == 'N' ) {
893: found = 0;
894: break;
895: } else if (c == '\n' || c == '\r') {
896: if (reverse)
897: found = 0;
898: else
899: found = 1;
900: break;
901: }
902: }
903: wclear(yesnowin);
904: wrefresh(yesnowin);
905: delwin(yesnowin);
906: refresh();
907: return(found);
1.52 hubertf 908: }
909:
910: /*
911: * Some globals to pass things back from callbacks
912: */
913: static char zoneinfo_dir[STRSIZE];
914: static char *tz_selected; /* timezonename (relative to share/zoneinfo */
915: static char *tz_default; /* UTC, or whatever /etc/localtime points to */
916: static char tz_env[STRSIZE];
917:
918: /*
919: * Callback from timezone menu
920: */
921: static int
922: set_timezone_select(menudesc *m)
923: {
924: time_t t;
925:
926: if (m)
927: tz_selected = m->opts[m->cursel].opt_name;
928: snprintf(tz_env, sizeof(tz_env), "%s/%s",
929: zoneinfo_dir, tz_selected);
930: setenv("TZ", tz_env, 1);
931: t = time(NULL);
932: msg_display(MSG_choose_timezone,
933: tz_default, tz_selected, ctime(&t), localtime(&t)->tm_zone);
934: return 0;
935: }
936:
937: /*
938: * Alarm-handler to update example-display
939: */
940: static void
941: timezone_sig(int sig)
942: {
943: set_timezone_select(NULL);
944: alarm(1);
945: }
946:
947: /*
948: * Choose from the files in usr/share/zoneinfo and set etc/localtime
949: */
950: int
951: set_timezone()
952: {
953: char localtime_link[STRSIZE];
954: char localtime_target[STRSIZE];
955: int rc;
956: time_t t;
957: sig_t oldalrm;
958: FTS *tree;
959: FTSENT *entry;
960: int rval;
961: char *argv[2];
962: int skip;
963: struct stat sb;
964: int nfiles, n;
965: int menu_no;
966: menu_ent *tz_menu;
967:
968: oldalrm=signal(SIGALRM, timezone_sig);
969: alarm(1);
970:
971: strncpy(zoneinfo_dir, target_expand("/usr/share/zoneinfo"), STRSIZE);
972: strncpy(localtime_link, target_expand("/etc/localtime"), STRSIZE);
973:
974: /* Add sanity check that /mnt/usr/share/zoneinfo contains
975: * something useful */
976:
977: rc = readlink(localtime_link, localtime_target,
978: sizeof(localtime_target));
979: if (rc < 0) {
1.53 hubertf 980: /* error, default to UTC */
981: tz_default = "UTC";
982: } else {
983: localtime_target[rc] = '\0';
984: tz_default = strchr(strstr(localtime_target, "zoneinfo"), '/')+1;
1.52 hubertf 985: }
986:
987: tz_selected=tz_default;
988: snprintf(tz_env, sizeof(tz_env), "%s/%s",
989: zoneinfo_dir, tz_selected);
990: setenv("TZ", tz_env, 1);
991: t = time(NULL);
992: msg_display(MSG_choose_timezone,
993: tz_default, tz_selected, ctime(&t), localtime(&t)->tm_zone);
994:
995: skip = strlen(zoneinfo_dir);
996: argv[0] = zoneinfo_dir;
997: argv[1] = NULL;
998: if (!(tree = fts_open(argv, FTS_LOGICAL, NULL))) {
1.53 hubertf 999: return 1; /* error - skip timezone setting */
1.52 hubertf 1000: }
1001: for (nfiles = 0; (entry = fts_read(tree)) != NULL;) {
1002: stat(entry->fts_accpath, &sb);
1003: if (S_ISREG(sb.st_mode))
1004: nfiles++;
1005: }
1006: if (errno) {
1.53 hubertf 1007: return 1; /* error - skip timezone setting */
1.52 hubertf 1008: }
1009: (void)fts_close(tree);
1010:
1011: tz_menu = malloc(nfiles * sizeof(struct menu_ent));
1012: if (tz_menu == NULL) {
1.53 hubertf 1013: return 1; /* error - skip timezone setting */
1.52 hubertf 1014: }
1015:
1016: if (!(tree = fts_open(argv, FTS_LOGICAL, NULL))) {
1.53 hubertf 1017: return 1; /* error - skip timezone setting */
1.52 hubertf 1018: }
1019: n=0;
1020: for (rval=0; (entry = fts_read(tree)) != NULL; ) {
1021:
1022: stat(entry->fts_accpath, &sb);
1023: if (S_ISREG(sb.st_mode)) {
1024: tz_menu[n].opt_name = strdup(entry->fts_accpath+skip+1);
1025: tz_menu[n].opt_menu = OPT_NOMENU;
1026: tz_menu[n].opt_flags = 0;
1027: tz_menu[n].opt_action = set_timezone_select;
1028:
1029: n++;
1030: }
1031: }
1032: if (errno) {
1.53 hubertf 1033: return 1; /* error - skip timezone setting */
1.52 hubertf 1034: }
1035: (void)fts_close(tree);
1036:
1037: menu_no = new_menu(NULL, tz_menu, nfiles, 23, 9,
1038: 12, 32, MC_SCROLL|MC_NOSHORTCUT, NULL, NULL,
1039: "\nPlease consult the install documents.");
1040: if (menu_no < 0) {
1.53 hubertf 1041: return 1; /* error - skip timezone setting */
1.52 hubertf 1042: }
1043: process_menu(menu_no);
1044:
1045: free_menu(menu_no);
1046: for(n=0; n < nfiles; n++)
1047: free(tz_menu[n].opt_name);
1048: free(tz_menu);
1049:
1050: signal(SIGALRM, SIG_IGN);
1051:
1052: snprintf(localtime_target, sizeof(localtime_target),
1053: "/usr/share/zoneinfo/%s", tz_selected);
1054: unlink(localtime_link);
1055: symlink(localtime_target, localtime_link);
1056:
1057: return 1;
1.56 ! fvdl 1058: }
! 1059:
! 1060: int
! 1061: set_root_password()
! 1062: {
! 1063: msg_display(MSG_rootpw);
! 1064: process_menu(MENU_yesno);
! 1065: if (yesno)
! 1066: run_prog(RUN_DISPLAY|RUN_CHROOT, NULL, "passwd -l root");
! 1067: return 0;
1.32 garbled 1068: }
CVSweb <webmaster@jp.NetBSD.org>