Mon Oct 26 20:18:33 2020 UTC ()
PR 55752: relax an assertion, the first getvfsstat() call may overestimate
the file systems visible to us.


(martin)
diff -r1.50 -r1.51 src/usr.sbin/sysinst/util.c

cvs diff -r1.50 -r1.51 src/usr.sbin/sysinst/util.c (switch to unified diff)

--- src/usr.sbin/sysinst/util.c 2020/10/25 08:50:32 1.50
+++ src/usr.sbin/sysinst/util.c 2020/10/26 20:18:33 1.51
@@ -1,1528 +1,1528 @@ @@ -1,1528 +1,1528 @@
1/* $NetBSD: util.c,v 1.50 2020/10/25 08:50:32 martin Exp $ */ 1/* $NetBSD: util.c,v 1.51 2020/10/26 20:18:33 martin Exp $ */
2 2
3/* 3/*
4 * Copyright 1997 Piermont Information Systems Inc. 4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse
18 * or promote products derived from this software without specific prior 18 * or promote products derived from this software without specific prior
19 * written permission. 19 * written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE. 31 * THE POSSIBILITY OF SUCH DAMAGE.
32 * 32 *
33 */ 33 */
34 34
35/* util.c -- routines that don't really fit anywhere else... */ 35/* util.c -- routines that don't really fit anywhere else... */
36 36
37#include <assert.h> 37#include <assert.h>
38#include <inttypes.h> 38#include <inttypes.h>
39#include <stdio.h> 39#include <stdio.h>
40#include <stdarg.h> 40#include <stdarg.h>
41#include <string.h> 41#include <string.h>
42#include <unistd.h> 42#include <unistd.h>
43#include <sys/mount.h> 43#include <sys/mount.h>
44#include <sys/dkio.h> 44#include <sys/dkio.h>
45#include <sys/ioctl.h> 45#include <sys/ioctl.h>
46#include <sys/types.h> 46#include <sys/types.h>
47#include <sys/param.h> 47#include <sys/param.h>
48#include <sys/sysctl.h> 48#include <sys/sysctl.h>
49#include <sys/stat.h> 49#include <sys/stat.h>
50#include <sys/statvfs.h> 50#include <sys/statvfs.h>
51#include <isofs/cd9660/iso.h> 51#include <isofs/cd9660/iso.h>
52#include <curses.h> 52#include <curses.h>
53#include <err.h> 53#include <err.h>
54#include <errno.h> 54#include <errno.h>
55#include <dirent.h> 55#include <dirent.h>
56#include <util.h> 56#include <util.h>
57#include "defs.h" 57#include "defs.h"
58#include "md.h" 58#include "md.h"
59#include "defsizes.h" 59#include "defsizes.h"
60#include "msg_defs.h" 60#include "msg_defs.h"
61#include "menu_defs.h" 61#include "menu_defs.h"
62#ifdef MD_MAY_SWAP_TO 62#ifdef MD_MAY_SWAP_TO
63#include <sys/drvctlio.h> 63#include <sys/drvctlio.h>
64#endif 64#endif
65 65
66#define MAX_CD_DEVS 256 /* how many cd drives do we expect to attach */ 66#define MAX_CD_DEVS 256 /* how many cd drives do we expect to attach */
67#define ISO_BLKSIZE ISO_DEFAULT_BLOCK_SIZE 67#define ISO_BLKSIZE ISO_DEFAULT_BLOCK_SIZE
68 68
69static const char *msg_yes, *msg_no, *msg_all, *msg_some, *msg_none; 69static const char *msg_yes, *msg_no, *msg_all, *msg_some, *msg_none;
70static int select_menu_width; 70static int select_menu_width;
71 71
72static uint8_t set_status[SET_GROUP_END]; 72static uint8_t set_status[SET_GROUP_END];
73#define SET_VALID 0x01 73#define SET_VALID 0x01
74#define SET_SELECTED 0x02 74#define SET_SELECTED 0x02
75#define SET_SKIPPED 0x04 75#define SET_SKIPPED 0x04
76#define SET_INSTALLED 0x08 76#define SET_INSTALLED 0x08
77#define SET_NO_EXTRACT 0x10 77#define SET_NO_EXTRACT 0x10
78 78
79struct tarstats { 79struct tarstats {
80 int nselected; 80 int nselected;
81 int nfound; 81 int nfound;
82 int nnotfound; 82 int nnotfound;
83 int nerror; 83 int nerror;
84 int nsuccess; 84 int nsuccess;
85 int nskipped; 85 int nskipped;
86} tarstats; 86} tarstats;
87 87
88distinfo dist_list[] = { 88distinfo dist_list[] = {
89#ifdef SET_KERNEL_1_NAME 89#ifdef SET_KERNEL_1_NAME
90 {SET_KERNEL_1_NAME, SET_KERNEL_1, false, MSG_set_kernel_1, NULL}, 90 {SET_KERNEL_1_NAME, SET_KERNEL_1, false, MSG_set_kernel_1, NULL},
91#endif 91#endif
92#ifdef SET_KERNEL_2_NAME 92#ifdef SET_KERNEL_2_NAME
93 {SET_KERNEL_2_NAME, SET_KERNEL_2, false, MSG_set_kernel_2, NULL}, 93 {SET_KERNEL_2_NAME, SET_KERNEL_2, false, MSG_set_kernel_2, NULL},
94#endif 94#endif
95#ifdef SET_KERNEL_3_NAME 95#ifdef SET_KERNEL_3_NAME
96 {SET_KERNEL_3_NAME, SET_KERNEL_3, false, MSG_set_kernel_3, NULL}, 96 {SET_KERNEL_3_NAME, SET_KERNEL_3, false, MSG_set_kernel_3, NULL},
97#endif 97#endif
98#ifdef SET_KERNEL_4_NAME 98#ifdef SET_KERNEL_4_NAME
99 {SET_KERNEL_4_NAME, SET_KERNEL_4, false, MSG_set_kernel_4, NULL}, 99 {SET_KERNEL_4_NAME, SET_KERNEL_4, false, MSG_set_kernel_4, NULL},
100#endif 100#endif
101#ifdef SET_KERNEL_5_NAME 101#ifdef SET_KERNEL_5_NAME
102 {SET_KERNEL_5_NAME, SET_KERNEL_5, false, MSG_set_kernel_5, NULL}, 102 {SET_KERNEL_5_NAME, SET_KERNEL_5, false, MSG_set_kernel_5, NULL},
103#endif 103#endif
104#ifdef SET_KERNEL_6_NAME 104#ifdef SET_KERNEL_6_NAME
105 {SET_KERNEL_6_NAME, SET_KERNEL_6, false, MSG_set_kernel_6, NULL}, 105 {SET_KERNEL_6_NAME, SET_KERNEL_6, false, MSG_set_kernel_6, NULL},
106#endif 106#endif
107#ifdef SET_KERNEL_7_NAME 107#ifdef SET_KERNEL_7_NAME
108 {SET_KERNEL_7_NAME, SET_KERNEL_7, false, MSG_set_kernel_7, NULL}, 108 {SET_KERNEL_7_NAME, SET_KERNEL_7, false, MSG_set_kernel_7, NULL},
109#endif 109#endif
110#ifdef SET_KERNEL_8_NAME 110#ifdef SET_KERNEL_8_NAME
111 {SET_KERNEL_8_NAME, SET_KERNEL_8, false, MSG_set_kernel_8, NULL}, 111 {SET_KERNEL_8_NAME, SET_KERNEL_8, false, MSG_set_kernel_8, NULL},
112#endif 112#endif
113#ifdef SET_KERNEL_9_NAME 113#ifdef SET_KERNEL_9_NAME
114 {SET_KERNEL_9_NAME, SET_KERNEL_9, false, MSG_set_kernel_9, NULL}, 114 {SET_KERNEL_9_NAME, SET_KERNEL_9, false, MSG_set_kernel_9, NULL},
115#endif 115#endif
116 116
117 {"modules", SET_MODULES, false, MSG_set_modules, NULL}, 117 {"modules", SET_MODULES, false, MSG_set_modules, NULL},
118 {"base", SET_BASE, false, MSG_set_base, NULL}, 118 {"base", SET_BASE, false, MSG_set_base, NULL},
119#ifdef HAVE_DTB 119#ifdef HAVE_DTB
120 {"dtb", SET_DTB, false, MSG_set_dtb, NULL}, 120 {"dtb", SET_DTB, false, MSG_set_dtb, NULL},
121#endif 121#endif
122 {"etc", SET_ETC, false, MSG_set_system, NULL}, 122 {"etc", SET_ETC, false, MSG_set_system, NULL},
123 {"comp", SET_COMPILER, false, MSG_set_compiler, NULL}, 123 {"comp", SET_COMPILER, false, MSG_set_compiler, NULL},
124 {"games", SET_GAMES, false, MSG_set_games, NULL}, 124 {"games", SET_GAMES, false, MSG_set_games, NULL},
125 {"man", SET_MAN_PAGES, false, MSG_set_man_pages, NULL}, 125 {"man", SET_MAN_PAGES, false, MSG_set_man_pages, NULL},
126 {"misc", SET_MISC, false, MSG_set_misc, NULL}, 126 {"misc", SET_MISC, false, MSG_set_misc, NULL},
127 {"rescue", SET_RESCUE, false, MSG_set_rescue, NULL}, 127 {"rescue", SET_RESCUE, false, MSG_set_rescue, NULL},
128 {"tests", SET_TESTS, false, MSG_set_tests, NULL}, 128 {"tests", SET_TESTS, false, MSG_set_tests, NULL},
129 {"text", SET_TEXT_TOOLS, false, MSG_set_text_tools, NULL}, 129 {"text", SET_TEXT_TOOLS, false, MSG_set_text_tools, NULL},
130 130
131 {NULL, SET_GROUP, false, MSG_set_X11, NULL}, 131 {NULL, SET_GROUP, false, MSG_set_X11, NULL},
132 {"xbase", SET_X11_BASE, false, MSG_set_X11_base, NULL}, 132 {"xbase", SET_X11_BASE, false, MSG_set_X11_base, NULL},
133 {"xcomp", SET_X11_PROG, false, MSG_set_X11_prog, NULL}, 133 {"xcomp", SET_X11_PROG, false, MSG_set_X11_prog, NULL},
134 {"xetc", SET_X11_ETC, false, MSG_set_X11_etc, NULL}, 134 {"xetc", SET_X11_ETC, false, MSG_set_X11_etc, NULL},
135 {"xfont", SET_X11_FONTS, false, MSG_set_X11_fonts, NULL}, 135 {"xfont", SET_X11_FONTS, false, MSG_set_X11_fonts, NULL},
136 {"xserver", SET_X11_SERVERS, false, MSG_set_X11_servers, NULL}, 136 {"xserver", SET_X11_SERVERS, false, MSG_set_X11_servers, NULL},
137 {NULL, SET_GROUP_END, false, NULL, NULL}, 137 {NULL, SET_GROUP_END, false, NULL, NULL},
138 138
139#ifdef SET_MD_1_NAME 139#ifdef SET_MD_1_NAME
140 {SET_MD_1_NAME, SET_MD_1, false, MSG_set_md_1, NULL}, 140 {SET_MD_1_NAME, SET_MD_1, false, MSG_set_md_1, NULL},
141#endif 141#endif
142#ifdef SET_MD_2_NAME 142#ifdef SET_MD_2_NAME
143 {SET_MD_2_NAME, SET_MD_2, false, MSG_set_md_2, NULL}, 143 {SET_MD_2_NAME, SET_MD_2, false, MSG_set_md_2, NULL},
144#endif 144#endif
145#ifdef SET_MD_3_NAME 145#ifdef SET_MD_3_NAME
146 {SET_MD_3_NAME, SET_MD_3, false, MSG_set_md_3, NULL}, 146 {SET_MD_3_NAME, SET_MD_3, false, MSG_set_md_3, NULL},
147#endif 147#endif
148#ifdef SET_MD_4_NAME 148#ifdef SET_MD_4_NAME
149 {SET_MD_4_NAME, SET_MD_4, false, MSG_set_md_4, NULL}, 149 {SET_MD_4_NAME, SET_MD_4, false, MSG_set_md_4, NULL},
150#endif 150#endif
151 151
152 {NULL, SET_GROUP, true, MSG_set_source, NULL}, 152 {NULL, SET_GROUP, true, MSG_set_source, NULL},
153 {"syssrc", SET_SYSSRC, true, MSG_set_syssrc, NULL}, 153 {"syssrc", SET_SYSSRC, true, MSG_set_syssrc, NULL},
154 {"src", SET_SRC, true, MSG_set_src, NULL}, 154 {"src", SET_SRC, true, MSG_set_src, NULL},
155 {"sharesrc", SET_SHARESRC, true, MSG_set_sharesrc, NULL}, 155 {"sharesrc", SET_SHARESRC, true, MSG_set_sharesrc, NULL},
156 {"gnusrc", SET_GNUSRC, true, MSG_set_gnusrc, NULL}, 156 {"gnusrc", SET_GNUSRC, true, MSG_set_gnusrc, NULL},
157 {"xsrc", SET_XSRC, true, MSG_set_xsrc, NULL}, 157 {"xsrc", SET_XSRC, true, MSG_set_xsrc, NULL},
158 {"debug", SET_DEBUG, false, MSG_set_debug, NULL}, 158 {"debug", SET_DEBUG, false, MSG_set_debug, NULL},
159 {"xdebug", SET_X11_DEBUG, false, MSG_set_xdebug, NULL}, 159 {"xdebug", SET_X11_DEBUG, false, MSG_set_xdebug, NULL},
160 {NULL, SET_GROUP_END, false, NULL, NULL}, 160 {NULL, SET_GROUP_END, false, NULL, NULL},
161 161
162 {NULL, SET_LAST, false, NULL, NULL}, 162 {NULL, SET_LAST, false, NULL, NULL},
163}; 163};
164 164
165#define MAX_CD_INFOS 16 /* how many media can be found? */ 165#define MAX_CD_INFOS 16 /* how many media can be found? */
166struct cd_info { 166struct cd_info {
167 char device_name[16]; 167 char device_name[16];
168 char menu[100]; 168 char menu[100];
169}; 169};
170static struct cd_info cds[MAX_CD_INFOS]; 170static struct cd_info cds[MAX_CD_INFOS];
171 171
172/* flags whether to offer the respective options (depending on helper 172/* flags whether to offer the respective options (depending on helper
173 programs available on install media */ 173 programs available on install media */
174int have_raid, have_vnd, have_cgd, have_lvm, have_gpt, have_dk; 174int have_raid, have_vnd, have_cgd, have_lvm, have_gpt, have_dk;
175 175
176/* 176/*
177 * local prototypes 177 * local prototypes
178 */ 178 */
179 179
180static int check_for(unsigned int mode, const char *pathname); 180static int check_for(unsigned int mode, const char *pathname);
181static int get_iso9660_volname(int dev, int sess, char *volname, 181static int get_iso9660_volname(int dev, int sess, char *volname,
182 size_t volnamelen); 182 size_t volnamelen);
183static int get_available_cds(void); 183static int get_available_cds(void);
184static int binary_available(const char *prog); 184static int binary_available(const char *prog);
185 185
186void 186void
187init_set_status(int flags) 187init_set_status(int flags)
188{ 188{
189 static const uint8_t sets_valid[] = {MD_SETS_VALID}; 189 static const uint8_t sets_valid[] = {MD_SETS_VALID};
190 static const uint8_t sets_selected_full[] = {MD_SETS_SELECTED}; 190 static const uint8_t sets_selected_full[] = {MD_SETS_SELECTED};
191 static const uint8_t sets_selected_minimal[] = {MD_SETS_SELECTED_MINIMAL}; 191 static const uint8_t sets_selected_minimal[] = {MD_SETS_SELECTED_MINIMAL};
192 static const uint8_t sets_selected_nox[] = {MD_SETS_SELECTED_NOX}; 192 static const uint8_t sets_selected_nox[] = {MD_SETS_SELECTED_NOX};
193 static const uint8_t *sets_selected; 193 static const uint8_t *sets_selected;
194 unsigned int nelem_selected; 194 unsigned int nelem_selected;
195 unsigned int i, len; 195 unsigned int i, len;
196 const char *longest; 196 const char *longest;
197 197
198 if (flags & SFLAG_MINIMAL) { 198 if (flags & SFLAG_MINIMAL) {
199 sets_selected = sets_selected_minimal; 199 sets_selected = sets_selected_minimal;
200 nelem_selected = __arraycount(sets_selected_minimal); 200 nelem_selected = __arraycount(sets_selected_minimal);
201 } else if (flags & SFLAG_NOX) { 201 } else if (flags & SFLAG_NOX) {
202 sets_selected = sets_selected_nox; 202 sets_selected = sets_selected_nox;
203 nelem_selected = __arraycount(sets_selected_nox); 203 nelem_selected = __arraycount(sets_selected_nox);
204 } else { 204 } else {
205 sets_selected = sets_selected_full; 205 sets_selected = sets_selected_full;
206 nelem_selected = __arraycount(sets_selected_full); 206 nelem_selected = __arraycount(sets_selected_full);
207 } 207 }
208 208
209 for (i = 0; i < __arraycount(sets_valid); i++) 209 for (i = 0; i < __arraycount(sets_valid); i++)
210 set_status[sets_valid[i]] = SET_VALID; 210 set_status[sets_valid[i]] = SET_VALID;
211 for (i = 0; i < nelem_selected; i++) 211 for (i = 0; i < nelem_selected; i++)
212 set_status[sets_selected[i]] |= SET_SELECTED; 212 set_status[sets_selected[i]] |= SET_SELECTED;
213 213
214 set_status[SET_GROUP] = SET_VALID; 214 set_status[SET_GROUP] = SET_VALID;
215 215
216 /* Lookup some strings we need lots of times */ 216 /* Lookup some strings we need lots of times */
217 msg_yes = msg_string(MSG_Yes); 217 msg_yes = msg_string(MSG_Yes);
218 msg_no = msg_string(MSG_No); 218 msg_no = msg_string(MSG_No);
219 msg_all = msg_string(MSG_All); 219 msg_all = msg_string(MSG_All);
220 msg_some = msg_string(MSG_Some); 220 msg_some = msg_string(MSG_Some);
221 msg_none = msg_string(MSG_None); 221 msg_none = msg_string(MSG_None);
222 222
223 /* Find longest and use it to determine width of selection menu */ 223 /* Find longest and use it to determine width of selection menu */
224 len = strlen(msg_no); longest = msg_no; 224 len = strlen(msg_no); longest = msg_no;
225 i = strlen(msg_yes); if (i > len) {len = i; longest = msg_yes; } 225 i = strlen(msg_yes); if (i > len) {len = i; longest = msg_yes; }
226 i = strlen(msg_all); if (i > len) {len = i; longest = msg_all; } 226 i = strlen(msg_all); if (i > len) {len = i; longest = msg_all; }
227 i = strlen(msg_some); if (i > len) {len = i; longest = msg_some; } 227 i = strlen(msg_some); if (i > len) {len = i; longest = msg_some; }
228 i = strlen(msg_none); if (i > len) {len = i; longest = msg_none; } 228 i = strlen(msg_none); if (i > len) {len = i; longest = msg_none; }
229 select_menu_width = snprintf(NULL, 0, "%-30s %s", "", longest); 229 select_menu_width = snprintf(NULL, 0, "%-30s %s", "", longest);
230 230
231 /* Give the md code a chance to choose the right kernel, etc. */ 231 /* Give the md code a chance to choose the right kernel, etc. */
232 md_init_set_status(flags); 232 md_init_set_status(flags);
233} 233}
234 234
235int 235int
236dir_exists_p(const char *path) 236dir_exists_p(const char *path)
237{ 237{
238 238
239 return file_mode_match(path, S_IFDIR); 239 return file_mode_match(path, S_IFDIR);
240} 240}
241 241
242int 242int
243file_exists_p(const char *path) 243file_exists_p(const char *path)
244{ 244{
245 245
246 return file_mode_match(path, S_IFREG); 246 return file_mode_match(path, S_IFREG);
247} 247}
248 248
249int 249int
250file_mode_match(const char *path, unsigned int mode) 250file_mode_match(const char *path, unsigned int mode)
251{ 251{
252 struct stat st; 252 struct stat st;
253 253
254 return (stat(path, &st) == 0 && (st.st_mode & S_IFMT) == mode); 254 return (stat(path, &st) == 0 && (st.st_mode & S_IFMT) == mode);
255} 255}
256 256
257/* return ram size in MB */ 257/* return ram size in MB */
258uint64_t 258uint64_t
259get_ramsize(void) 259get_ramsize(void)
260{ 260{
261 uint64_t ramsize; 261 uint64_t ramsize;
262 size_t len = sizeof ramsize; 262 size_t len = sizeof ramsize;
263 int mib[2] = {CTL_HW, HW_PHYSMEM64}; 263 int mib[2] = {CTL_HW, HW_PHYSMEM64};
264 264
265 sysctl(mib, 2, &ramsize, &len, NULL, 0); 265 sysctl(mib, 2, &ramsize, &len, NULL, 0);
266 266
267 /* Find out how many Megs ... round up. */ 267 /* Find out how many Megs ... round up. */
268 return (ramsize + MEG - 1) / MEG; 268 return (ramsize + MEG - 1) / MEG;
269} 269}
270 270
271void 271void
272run_makedev(void) 272run_makedev(void)
273{ 273{
274 char *owd; 274 char *owd;
275 275
276 msg_display_add("\n\n"); 276 msg_display_add("\n\n");
277 msg_display_add(MSG_makedev); 277 msg_display_add(MSG_makedev);
278 278
279 owd = getcwd(NULL, 0); 279 owd = getcwd(NULL, 0);
280 280
281 /* make /dev, in case the user didn't extract it. */ 281 /* make /dev, in case the user didn't extract it. */
282 make_target_dir("/dev"); 282 make_target_dir("/dev");
283 target_chdir_or_die("/dev"); 283 target_chdir_or_die("/dev");
284 run_program(0, "/bin/sh MAKEDEV all"); 284 run_program(0, "/bin/sh MAKEDEV all");
285 285
286 chdir(owd); 286 chdir(owd);
287 free(owd); 287 free(owd);
288} 288}
289 289
290/* 290/*
291 * Performs in-place replacement of a set of patterns in a file that lives 291 * Performs in-place replacement of a set of patterns in a file that lives
292 * inside the installed system. The patterns must be separated by a semicolon. 292 * inside the installed system. The patterns must be separated by a semicolon.
293 * For example: 293 * For example:
294 * 294 *
295 * replace("/etc/some-file.conf", "s/prop1=NO/prop1=YES/;s/foo/bar/"); 295 * replace("/etc/some-file.conf", "s/prop1=NO/prop1=YES/;s/foo/bar/");
296 */ 296 */
297void 297void
298replace(const char *path, const char *patterns, ...) 298replace(const char *path, const char *patterns, ...)
299{ 299{
300 char *spatterns; 300 char *spatterns;
301 va_list ap; 301 va_list ap;
302 302
303 va_start(ap, patterns); 303 va_start(ap, patterns);
304 vasprintf(&spatterns, patterns, ap); 304 vasprintf(&spatterns, patterns, ap);
305 va_end(ap); 305 va_end(ap);
306 if (spatterns == NULL) 306 if (spatterns == NULL)
307 err(1, "vasprintf(&spatterns, \"%s\", ...)", patterns); 307 err(1, "vasprintf(&spatterns, \"%s\", ...)", patterns);
308 308
309 run_program(RUN_CHROOT, "sed -an -e '%s;H;$!d;g;w %s' %s", spatterns, 309 run_program(RUN_CHROOT, "sed -an -e '%s;H;$!d;g;w %s' %s", spatterns,
310 path, path); 310 path, path);
311 311
312 free(spatterns); 312 free(spatterns);
313} 313}
314 314
315static int 315static int
316floppy_fetch(const char *set_name) 316floppy_fetch(const char *set_name)
317{ 317{
318 char post[4]; 318 char post[4];
319 msg errmsg; 319 msg errmsg;
320 int menu; 320 int menu;
321 int status; 321 int status;
322 const char *write_mode = ">"; 322 const char *write_mode = ">";
323 323
324 strcpy(post, "aa"); 324 strcpy(post, "aa");
325 325
326 errmsg = ""; 326 errmsg = "";
327 menu = MENU_fdok; 327 menu = MENU_fdok;
328 for (;;) { 328 for (;;) {
329 umount_mnt2(); 329 umount_mnt2();
330 msg_display(errmsg); 330 msg_display(errmsg);
331 msg_fmt_display_add(MSG_fdmount, "%s%s", set_name, post); 331 msg_fmt_display_add(MSG_fdmount, "%s%s", set_name, post);
332 process_menu(menu, &status); 332 process_menu(menu, &status);
333 if (status != SET_CONTINUE) 333 if (status != SET_CONTINUE)
334 return status; 334 return status;
335 menu = MENU_fdremount; 335 menu = MENU_fdremount;
336 errmsg = MSG_fdremount; 336 errmsg = MSG_fdremount;
337 if (run_program(0, "/sbin/mount -r -t %s %s /mnt2", 337 if (run_program(0, "/sbin/mount -r -t %s %s /mnt2",
338 fd_type, fd_dev)) 338 fd_type, fd_dev))
339 continue; 339 continue;
340 mnt2_mounted = 1; 340 mnt2_mounted = 1;
341 errmsg = MSG_fdnotfound; 341 errmsg = MSG_fdnotfound;
342 342
343 /* Display this because it might take a while.... */ 343 /* Display this because it might take a while.... */
344 if (run_program(RUN_DISPLAY, 344 if (run_program(RUN_DISPLAY,
345 "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'", 345 "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'",
346 set_name, post, write_mode, 346 set_name, post, write_mode,
347 target_prefix(), xfer_dir, set_name, 347 target_prefix(), xfer_dir, set_name,
348 set_postfix(set_name))) 348 set_postfix(set_name)))
349 /* XXX: a read error will give a corrupt file! */ 349 /* XXX: a read error will give a corrupt file! */
350 continue; 350 continue;
351 351
352 /* We got that file, advance to next fragment */ 352 /* We got that file, advance to next fragment */
353 if (post[1] < 'z') 353 if (post[1] < 'z')
354 post[1]++; 354 post[1]++;
355 else 355 else
356 post[1] = 'a', post[0]++; 356 post[1] = 'a', post[0]++;
357 write_mode = ">>"; 357 write_mode = ">>";
358 errmsg = ""; 358 errmsg = "";
359 menu = MENU_fdok; 359 menu = MENU_fdok;
360 } 360 }
361} 361}
362 362
363/* 363/*
364 * Load files from floppy. Requires a /mnt2 directory for mounting them. 364 * Load files from floppy. Requires a /mnt2 directory for mounting them.
365 */ 365 */
366int 366int
367get_via_floppy(void) 367get_via_floppy(void)
368{ 368{
369 int rv = -1; 369 int rv = -1;
370 370
371 process_menu(MENU_floppysource, &rv); 371 process_menu(MENU_floppysource, &rv);
372 if (rv == SET_RETRY) 372 if (rv == SET_RETRY)
373 return SET_RETRY; 373 return SET_RETRY;
374 374
375 fetch_fn = floppy_fetch; 375 fetch_fn = floppy_fetch;
376 376
377 /* Set ext_dir for absolute path. */ 377 /* Set ext_dir for absolute path. */
378 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", target_prefix(), xfer_dir); 378 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", target_prefix(), xfer_dir);
379 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", target_prefix(), xfer_dir); 379 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", target_prefix(), xfer_dir);
380 380
381 return SET_OK; 381 return SET_OK;
382} 382}
383 383
384/* 384/*
385 * Get the volume name of a ISO9660 file system 385 * Get the volume name of a ISO9660 file system
386 */ 386 */
387static int 387static int
388get_iso9660_volname(int dev, int sess, char *volname, size_t volnamelen) 388get_iso9660_volname(int dev, int sess, char *volname, size_t volnamelen)
389{ 389{
390 int blkno, error, last; 390 int blkno, error, last;
391 char buf[ISO_BLKSIZE]; 391 char buf[ISO_BLKSIZE];
392 struct iso_volume_descriptor *vd = NULL; 392 struct iso_volume_descriptor *vd = NULL;
393 struct iso_primary_descriptor *pd = NULL; 393 struct iso_primary_descriptor *pd = NULL;
394 394
395 for (blkno = sess+16; blkno < sess+16+100; blkno++) { 395 for (blkno = sess+16; blkno < sess+16+100; blkno++) {
396 error = pread(dev, buf, ISO_BLKSIZE, blkno*ISO_BLKSIZE); 396 error = pread(dev, buf, ISO_BLKSIZE, blkno*ISO_BLKSIZE);
397 if (error == -1) 397 if (error == -1)
398 return -1; 398 return -1;
399 vd = (struct iso_volume_descriptor *)&buf; 399 vd = (struct iso_volume_descriptor *)&buf;
400 if (memcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0) 400 if (memcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0)
401 return -1; 401 return -1;
402 if (isonum_711((const unsigned char *)&vd->type) 402 if (isonum_711((const unsigned char *)&vd->type)
403 == ISO_VD_PRIMARY) { 403 == ISO_VD_PRIMARY) {
404 pd = (struct iso_primary_descriptor*)buf; 404 pd = (struct iso_primary_descriptor*)buf;
405 strncpy(volname, pd->volume_id, volnamelen - 1); 405 strncpy(volname, pd->volume_id, volnamelen - 1);
406 volname[volnamelen - 1] = '\0'; 406 volname[volnamelen - 1] = '\0';
407 last = volnamelen - 1; 407 last = volnamelen - 1;
408 while (last >= 0 408 while (last >= 0
409 && (volname[last] == ' ' || volname[last] == 0)) 409 && (volname[last] == ' ' || volname[last] == 0))
410 last--; 410 last--;
411 volname[last+1] = 0; 411 volname[last+1] = 0;
412 return 0; 412 return 0;
413 } 413 }
414 } 414 }
415 return -1; 415 return -1;
416} 416}
417 417
418/* 418/*
419 * Local state while iterating CDs and collecting volumes 419 * Local state while iterating CDs and collecting volumes
420 */ 420 */
421struct get_available_cds_state { 421struct get_available_cds_state {
422 size_t num_mounted; 422 size_t num_mounted;
423 struct statvfs *mounted; 423 struct statvfs *mounted;
424 struct cd_info *info; 424 struct cd_info *info;
425 size_t count; 425 size_t count;
426}; 426};
427 427
428/* 428/*
429 * Callback function: if this is a CD, enumerate all volumes on it 429 * Callback function: if this is a CD, enumerate all volumes on it
430 */ 430 */
431static bool 431static bool
432get_available_cds_helper(void *arg, const char *device) 432get_available_cds_helper(void *arg, const char *device)
433{ 433{
434 struct get_available_cds_state *state = arg; 434 struct get_available_cds_state *state = arg;
435 char dname[16], tname[16], volname[80], *t; 435 char dname[16], tname[16], volname[80], *t;
436 struct disklabel label; 436 struct disklabel label;
437 int part, dev, error, sess, ready, tlen; 437 int part, dev, error, sess, ready, tlen;
438 438
439 if (!is_cdrom_device(device, false)) 439 if (!is_cdrom_device(device, false))
440 return true; 440 return true;
441 441
442 sprintf(dname, "/dev/r%s%c", device, 'a'+RAW_PART); 442 sprintf(dname, "/dev/r%s%c", device, 'a'+RAW_PART);
443 tlen = sprintf(tname, "/dev/%s", device); 443 tlen = sprintf(tname, "/dev/%s", device);
444 444
445 /* check if this is mounted already */ 445 /* check if this is mounted already */
446 for (size_t i = 0; i < state->num_mounted; i++) { 446 for (size_t i = 0; i < state->num_mounted; i++) {
447 if (strncmp(state->mounted[i].f_mntfromname, tname, tlen) 447 if (strncmp(state->mounted[i].f_mntfromname, tname, tlen)
448 == 0) { 448 == 0) {
449 t = state->mounted[i].f_mntfromname + tlen; 449 t = state->mounted[i].f_mntfromname + tlen;
450 if (t[0] >= 'a' && t[0] <= 'z' && t[1] == 0) 450 if (t[0] >= 'a' && t[0] <= 'z' && t[1] == 0)
451 return true; 451 return true;
452 } 452 }
453 } 453 }
454 454
455 dev = open(dname, O_RDONLY, 0); 455 dev = open(dname, O_RDONLY, 0);
456 if (dev == -1) 456 if (dev == -1)
457 return true; 457 return true;
458 458
459 ready = 0; 459 ready = 0;
460 error = ioctl(dev, DIOCTUR, &ready); 460 error = ioctl(dev, DIOCTUR, &ready);
461 if (error != 0 || ready == 0) { 461 if (error != 0 || ready == 0) {
462 close(dev); 462 close(dev);
463 return true; 463 return true;
464 } 464 }
465 error = ioctl(dev, DIOCGDINFO, &label); 465 error = ioctl(dev, DIOCGDINFO, &label);
466 close(dev); 466 close(dev);
467 if (error != 0) 467 if (error != 0)
468 return true; 468 return true;
469 469
470 for (part = 0; part < label.d_npartitions; part++) { 470 for (part = 0; part < label.d_npartitions; part++) {
471 471
472 if (label.d_partitions[part].p_fstype == FS_UNUSED 472 if (label.d_partitions[part].p_fstype == FS_UNUSED
473 || label.d_partitions[part].p_size == 0) 473 || label.d_partitions[part].p_size == 0)
474 continue; 474 continue;
475 475
476 if (label.d_partitions[part].p_fstype == FS_ISO9660) { 476 if (label.d_partitions[part].p_fstype == FS_ISO9660) {
477 sess = label.d_partitions[part].p_cdsession; 477 sess = label.d_partitions[part].p_cdsession;
478 sprintf(dname, "/dev/r%s%c", device, 'a'+part); 478 sprintf(dname, "/dev/r%s%c", device, 'a'+part);
479 dev = open(dname, O_RDONLY, 0); 479 dev = open(dname, O_RDONLY, 0);
480 if (dev == -1) 480 if (dev == -1)
481 continue; 481 continue;
482 error = get_iso9660_volname(dev, sess, volname, 482 error = get_iso9660_volname(dev, sess, volname,
483 sizeof volname); 483 sizeof volname);
484 close(dev); 484 close(dev);
485 if (error) 485 if (error)
486 continue; 486 continue;
487 sprintf(state->info->device_name, 487 sprintf(state->info->device_name,
488 "%s%c", device, 'a'+part); 488 "%s%c", device, 'a'+part);
489 sprintf(state->info->menu, "%s (%s)", 489 sprintf(state->info->menu, "%s (%s)",
490 state->info->device_name, volname); 490 state->info->device_name, volname);
491 } else { 491 } else {
492 /* 492 /*
493 * All install CDs use partition 493 * All install CDs use partition
494 * a for the sets. 494 * a for the sets.
495 */ 495 */
496 if (part > 0) 496 if (part > 0)
497 continue; 497 continue;
498 sprintf(state->info->device_name, 498 sprintf(state->info->device_name,
499 "%s%c", device, 'a'+part); 499 "%s%c", device, 'a'+part);
500 strcpy(state->info->menu, state->info->device_name); 500 strcpy(state->info->menu, state->info->device_name);
501 } 501 }
502 state->info++; 502 state->info++;
503 if (++state->count >= MAX_CD_INFOS) 503 if (++state->count >= MAX_CD_INFOS)
504 return false; 504 return false;
505 } 505 }
506 506
507 return true; 507 return true;
508} 508}
509 509
510/* 510/*
511 * Get a list of all available CD media (not drives!), return 511 * Get a list of all available CD media (not drives!), return
512 * the number of entries collected. 512 * the number of entries collected.
513 */ 513 */
514static int 514static int
515get_available_cds(void) 515get_available_cds(void)
516{ 516{
517 struct get_available_cds_state data; 517 struct get_available_cds_state data;
518 int n, __diagused e; 518 int n, m;
519 519
520 memset(&data, 0, sizeof data); 520 memset(&data, 0, sizeof data);
521 data.info = cds; 521 data.info = cds;
522 522
523 n = getvfsstat(NULL, 0, ST_NOWAIT); 523 n = getvfsstat(NULL, 0, ST_NOWAIT);
524 if (n > 0) { 524 if (n > 0) {
525 data.mounted = calloc(n, sizeof(*data.mounted)); 525 data.mounted = calloc(n, sizeof(*data.mounted));
526 e = getvfsstat(data.mounted, n*sizeof(*data.mounted), 526 m = getvfsstat(data.mounted, n*sizeof(*data.mounted),
527 ST_NOWAIT); 527 ST_NOWAIT);
528 assert(e == n); 528 assert(m >= 0 && m <= n);
529 data.num_mounted = n; 529 data.num_mounted = m;
530 } 530 }
531 531
532 enumerate_disks(&data, get_available_cds_helper); 532 enumerate_disks(&data, get_available_cds_helper);
533 533
534 free(data.mounted); 534 free(data.mounted);
535 535
536 return data.count; 536 return data.count;
537} 537}
538 538
539static int 539static int
540cd_has_sets(void) 540cd_has_sets(void)
541{ 541{
542 /* Mount it */ 542 /* Mount it */
543 if (run_program(RUN_SILENT, "/sbin/mount -rt cd9660 /dev/%s /mnt2", 543 if (run_program(RUN_SILENT, "/sbin/mount -rt cd9660 /dev/%s /mnt2",
544 cdrom_dev) != 0) 544 cdrom_dev) != 0)
545 return 0; 545 return 0;
546 546
547 mnt2_mounted = 1; 547 mnt2_mounted = 1;
548 548
549 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", "/mnt2", set_dir_bin); 549 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", "/mnt2", set_dir_bin);
550 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", "/mnt2", set_dir_src); 550 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", "/mnt2", set_dir_src);
551 return dir_exists_p(ext_dir_bin); 551 return dir_exists_p(ext_dir_bin);
552} 552}
553 553
554/* 554/*
555 * Check whether we can remove the boot media. 555 * Check whether we can remove the boot media.
556 * If it is not a local filesystem, return -1. 556 * If it is not a local filesystem, return -1.
557 * If we can not decide for sure (can not tell MD content from plain ffs 557 * If we can not decide for sure (can not tell MD content from plain ffs
558 * on hard disk, for example), return 0. 558 * on hard disk, for example), return 0.
559 * If it is a CD/DVD, return 1. 559 * If it is a CD/DVD, return 1.
560 */ 560 */
561int 561int
562boot_media_still_needed(void) 562boot_media_still_needed(void)
563{ 563{
564 struct statvfs sb; 564 struct statvfs sb;
565 565
566 if (statvfs("/", &sb) == 0) { 566 if (statvfs("/", &sb) == 0) {
567 if (!(sb.f_flag & ST_LOCAL)) 567 if (!(sb.f_flag & ST_LOCAL))
568 return -1; 568 return -1;
569 if (strcmp(sb.f_fstypename, MOUNT_CD9660) == 0 569 if (strcmp(sb.f_fstypename, MOUNT_CD9660) == 0
570 || strcmp(sb.f_fstypename, MOUNT_UDF) == 0) 570 || strcmp(sb.f_fstypename, MOUNT_UDF) == 0)
571 return 1; 571 return 1;
572 } 572 }
573 573
574 return 0; 574 return 0;
575} 575}
576 576
577bool 577bool
578root_is_read_only(void) 578root_is_read_only(void)
579{ 579{
580 struct statvfs sb; 580 struct statvfs sb;
581 581
582 if (statvfs("/", &sb) == 0) 582 if (statvfs("/", &sb) == 0)
583 return sb.f_flag & ST_RDONLY; 583 return sb.f_flag & ST_RDONLY;
584 584
585 return false; 585 return false;
586} 586}
587 587
588/* 588/*
589 * Get from a CDROM distribution. 589 * Get from a CDROM distribution.
590 * Also used on "installation using bootable install media" 590 * Also used on "installation using bootable install media"
591 * as the default option in the "distmedium" menu. 591 * as the default option in the "distmedium" menu.
592 */ 592 */
593int 593int
594get_via_cdrom(void) 594get_via_cdrom(void)
595{ 595{
596 menu_ent cd_menu[MAX_CD_INFOS]; 596 menu_ent cd_menu[MAX_CD_INFOS];
597 struct stat sb; 597 struct stat sb;
598 int rv, num_cds, menu_cd, i, selected_cd = 0; 598 int rv, num_cds, menu_cd, i, selected_cd = 0;
599 bool silent = false; 599 bool silent = false;
600 int mib[2]; 600 int mib[2];
601 char rootdev[SSTRSIZE] = ""; 601 char rootdev[SSTRSIZE] = "";
602 size_t varlen; 602 size_t varlen;
603 603
604 /* If root is not md(4) and we have set dir, skip this step. */ 604 /* If root is not md(4) and we have set dir, skip this step. */
605 mib[0] = CTL_KERN; 605 mib[0] = CTL_KERN;
606 mib[1] = KERN_ROOT_DEVICE; 606 mib[1] = KERN_ROOT_DEVICE;
607 varlen = sizeof(rootdev); 607 varlen = sizeof(rootdev);
608 (void)sysctl(mib, 2, rootdev, &varlen, NULL, 0); 608 (void)sysctl(mib, 2, rootdev, &varlen, NULL, 0);
609 if (stat(set_dir_bin, &sb) == 0 && S_ISDIR(sb.st_mode) && 609 if (stat(set_dir_bin, &sb) == 0 && S_ISDIR(sb.st_mode) &&
610 strncmp("md", rootdev, 2) != 0) { 610 strncmp("md", rootdev, 2) != 0) {
611 strlcpy(ext_dir_bin, set_dir_bin, sizeof ext_dir_bin); 611 strlcpy(ext_dir_bin, set_dir_bin, sizeof ext_dir_bin);
612 strlcpy(ext_dir_src, set_dir_src, sizeof ext_dir_src); 612 strlcpy(ext_dir_src, set_dir_src, sizeof ext_dir_src);
613 return SET_OK; 613 return SET_OK;
614 } 614 }
615 615
616 memset(cd_menu, 0, sizeof(cd_menu)); 616 memset(cd_menu, 0, sizeof(cd_menu));
617 num_cds = get_available_cds(); 617 num_cds = get_available_cds();
618 if (num_cds <= 0) { 618 if (num_cds <= 0) {
619 hit_enter_to_continue(MSG_No_cd_found, NULL); 619 hit_enter_to_continue(MSG_No_cd_found, NULL);
620 return SET_RETRY; 620 return SET_RETRY;
621 } else if (num_cds == 1) { 621 } else if (num_cds == 1) {
622 /* single CD found, check for sets on it */ 622 /* single CD found, check for sets on it */
623 strcpy(cdrom_dev, cds[0].device_name); 623 strcpy(cdrom_dev, cds[0].device_name);
624 if (cd_has_sets()) 624 if (cd_has_sets())
625 return SET_OK; 625 return SET_OK;
626 } else { 626 } else {
627 for (i = 0; i< num_cds; i++) { 627 for (i = 0; i< num_cds; i++) {
628 cd_menu[i].opt_name = cds[i].menu; 628 cd_menu[i].opt_name = cds[i].menu;
629 cd_menu[i].opt_flags = OPT_EXIT; 629 cd_menu[i].opt_flags = OPT_EXIT;
630 cd_menu[i].opt_action = set_menu_select; 630 cd_menu[i].opt_action = set_menu_select;
631 } 631 }
632 /* create a menu offering available choices */ 632 /* create a menu offering available choices */
633 menu_cd = new_menu(MSG_Available_cds, 633 menu_cd = new_menu(MSG_Available_cds,
634 cd_menu, num_cds, -1, 4, 0, 0, 634 cd_menu, num_cds, -1, 4, 0, 0,
635 MC_SCROLL | MC_NOEXITOPT, 635 MC_SCROLL | MC_NOEXITOPT,
636 NULL, NULL, NULL, NULL, NULL); 636 NULL, NULL, NULL, NULL, NULL);
637 if (menu_cd == -1) 637 if (menu_cd == -1)
638 return SET_RETRY; 638 return SET_RETRY;
639 msg_display(MSG_ask_cd); 639 msg_display(MSG_ask_cd);
640 process_menu(menu_cd, &selected_cd); 640 process_menu(menu_cd, &selected_cd);
641 free_menu(menu_cd); 641 free_menu(menu_cd);
642 strcpy(cdrom_dev, cds[selected_cd].device_name); 642 strcpy(cdrom_dev, cds[selected_cd].device_name);
643 if (cd_has_sets()) 643 if (cd_has_sets())
644 return SET_OK; 644 return SET_OK;
645 } 645 }
646 646
647 if (silent) 647 if (silent)
648 msg_display(""); 648 msg_display("");
649 else { 649 else {
650 umount_mnt2(); 650 umount_mnt2();
651 hit_enter_to_continue(MSG_cd_path_not_found, NULL); 651 hit_enter_to_continue(MSG_cd_path_not_found, NULL);
652 } 652 }
653 653
654 /* ask for paths on the CD */ 654 /* ask for paths on the CD */
655 rv = -1; 655 rv = -1;
656 process_menu(MENU_cdromsource, &rv); 656 process_menu(MENU_cdromsource, &rv);
657 if (rv == SET_RETRY) 657 if (rv == SET_RETRY)
658 return SET_RETRY; 658 return SET_RETRY;
659 659
660 if (cd_has_sets()) 660 if (cd_has_sets())
661 return SET_OK; 661 return SET_OK;
662 662
663 return SET_RETRY; 663 return SET_RETRY;
664} 664}
665 665
666 666
667/* 667/*
668 * Get from a pathname inside an unmounted local filesystem 668 * Get from a pathname inside an unmounted local filesystem
669 * (e.g., where sets were preloaded onto a local DOS partition) 669 * (e.g., where sets were preloaded onto a local DOS partition)
670 */ 670 */
671int 671int
672get_via_localfs(void) 672get_via_localfs(void)
673{ 673{
674 int rv = -1; 674 int rv = -1;
675 675
676 /* Get device, filesystem, and filepath */ 676 /* Get device, filesystem, and filepath */
677 process_menu (MENU_localfssource, &rv); 677 process_menu (MENU_localfssource, &rv);
678 if (rv == SET_RETRY) 678 if (rv == SET_RETRY)
679 return SET_RETRY; 679 return SET_RETRY;
680 680
681 /* Mount it */ 681 /* Mount it */
682 if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2", 682 if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2",
683 localfs_fs, localfs_dev)) 683 localfs_fs, localfs_dev))
684 return SET_RETRY; 684 return SET_RETRY;
685 685
686 mnt2_mounted = 1; 686 mnt2_mounted = 1;
687 687
688 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s/%s", 688 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s/%s",
689 "/mnt2", localfs_dir, set_dir_bin); 689 "/mnt2", localfs_dir, set_dir_bin);
690 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s/%s", 690 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s/%s",
691 "/mnt2", localfs_dir, set_dir_src); 691 "/mnt2", localfs_dir, set_dir_src);
692 692
693 return SET_OK; 693 return SET_OK;
694} 694}
695 695
696/* 696/*
697 * Get from an already-mounted pathname. 697 * Get from an already-mounted pathname.
698 */ 698 */
699 699
700int 700int
701get_via_localdir(void) 701get_via_localdir(void)
702{ 702{
703 int rv = -1; 703 int rv = -1;
704 704
705 /* Get filepath */ 705 /* Get filepath */
706 process_menu(MENU_localdirsource, &rv); 706 process_menu(MENU_localdirsource, &rv);
707 if (rv == SET_RETRY) 707 if (rv == SET_RETRY)
708 return SET_RETRY; 708 return SET_RETRY;
709 709
710 /* 710 /*
711 * We have to have an absolute path ('cos pax runs in a 711 * We have to have an absolute path ('cos pax runs in a
712 * different directory), make it so. 712 * different directory), make it so.
713 */ 713 */
714 snprintf(ext_dir_bin, sizeof ext_dir_bin, "/%s/%s", localfs_dir, set_dir_bin); 714 snprintf(ext_dir_bin, sizeof ext_dir_bin, "/%s/%s", localfs_dir, set_dir_bin);
715 snprintf(ext_dir_src, sizeof ext_dir_src, "/%s/%s", localfs_dir, set_dir_src); 715 snprintf(ext_dir_src, sizeof ext_dir_src, "/%s/%s", localfs_dir, set_dir_src);
716 716
717 return SET_OK; 717 return SET_OK;
718} 718}
719 719
720 720
721/* 721/*
722 * Support for custom distribution fetches / unpacks. 722 * Support for custom distribution fetches / unpacks.
723 */ 723 */
724 724
725unsigned int 725unsigned int
726set_X11_selected(void) 726set_X11_selected(void)
727{ 727{
728 int i; 728 int i;
729 729
730 for (i = SET_X11_FIRST; ++i < SET_X11_LAST;) 730 for (i = SET_X11_FIRST; ++i < SET_X11_LAST;)
731 if (set_status[i] & SET_SELECTED) 731 if (set_status[i] & SET_SELECTED)
732 return 1; 732 return 1;
733 return 0; 733 return 0;
734} 734}
735 735
736unsigned int 736unsigned int
737get_kernel_set(void) 737get_kernel_set(void)
738{ 738{
739 int i; 739 int i;
740 740
741 for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;) 741 for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;)
742 if (set_status[i] & SET_SELECTED) 742 if (set_status[i] & SET_SELECTED)
743 return i; 743 return i;
744 return SET_NONE; 744 return SET_NONE;
745} 745}
746 746
747void 747void
748set_kernel_set(unsigned int kernel_set) 748set_kernel_set(unsigned int kernel_set)
749{ 749{
750 int i; 750 int i;
751 751
752 /* only one kernel set is allowed */ 752 /* only one kernel set is allowed */
753 for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;) 753 for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;)
754 set_status[i] &= ~SET_SELECTED; 754 set_status[i] &= ~SET_SELECTED;
755 set_status[kernel_set] |= SET_SELECTED; 755 set_status[kernel_set] |= SET_SELECTED;
756} 756}
757 757
758void 758void
759set_noextract_set(unsigned int set) 759set_noextract_set(unsigned int set)
760{ 760{
761 761
762 set_status[set] |= SET_NO_EXTRACT; 762 set_status[set] |= SET_NO_EXTRACT;
763} 763}
764 764
765static int 765static int
766set_toggle(menudesc *menu, void *arg) 766set_toggle(menudesc *menu, void *arg)
767{ 767{
768 distinfo **distp = arg; 768 distinfo **distp = arg;
769 int set = distp[menu->cursel]->set; 769 int set = distp[menu->cursel]->set;
770 770
771 if (set > SET_KERNEL_FIRST && set < SET_KERNEL_LAST && 771 if (set > SET_KERNEL_FIRST && set < SET_KERNEL_LAST &&
772 !(set_status[set] & SET_SELECTED)) 772 !(set_status[set] & SET_SELECTED))
773 set_kernel_set(set); 773 set_kernel_set(set);
774 else 774 else
775 set_status[set] ^= SET_SELECTED; 775 set_status[set] ^= SET_SELECTED;
776 return 0; 776 return 0;
777} 777}
778 778
779static int 779static int
780set_all_none(menudesc *menu, void *arg, int set, int clr) 780set_all_none(menudesc *menu, void *arg, int set, int clr)
781{ 781{
782 distinfo **distp = arg; 782 distinfo **distp = arg;
783 distinfo *dist = *distp; 783 distinfo *dist = *distp;
784 int nested; 784 int nested;
785 785
786 for (nested = 0; dist->set != SET_GROUP_END || nested--; dist++) { 786 for (nested = 0; dist->set != SET_GROUP_END || nested--; dist++) {
787 if (dist->set == SET_GROUP) { 787 if (dist->set == SET_GROUP) {
788 nested++; 788 nested++;
789 continue; 789 continue;
790 } 790 }
791 set_status[dist->set] = (set_status[dist->set] & ~clr) | set; 791 set_status[dist->set] = (set_status[dist->set] & ~clr) | set;
792 } 792 }
793 return 0; 793 return 0;
794} 794}
795 795
796static int 796static int
797set_all(menudesc *menu, void *arg) 797set_all(menudesc *menu, void *arg)
798{ 798{
799 return set_all_none(menu, arg, SET_SELECTED, 0); 799 return set_all_none(menu, arg, SET_SELECTED, 0);
800} 800}
801 801
802static int 802static int
803set_none(menudesc *menu, void *arg) 803set_none(menudesc *menu, void *arg)
804{ 804{
805 return set_all_none(menu, arg, 0, SET_SELECTED); 805 return set_all_none(menu, arg, 0, SET_SELECTED);
806} 806}
807 807
808static void 808static void
809set_label(menudesc *menu, int opt, void *arg) 809set_label(menudesc *menu, int opt, void *arg)
810{ 810{
811 distinfo **distp = arg; 811 distinfo **distp = arg;
812 distinfo *dist = distp[opt]; 812 distinfo *dist = distp[opt];
813 const char *selected; 813 const char *selected;
814 const char *desc; 814 const char *desc;
815 int nested; 815 int nested;
816 816
817 desc = dist->desc; 817 desc = dist->desc;
818 818
819 if (dist->set != SET_GROUP) 819 if (dist->set != SET_GROUP)
820 selected = set_status[dist->set] & SET_SELECTED ? msg_yes : msg_no; 820 selected = set_status[dist->set] & SET_SELECTED ? msg_yes : msg_no;
821 else { 821 else {
822 /* sub menu - display None/Some/All */ 822 /* sub menu - display None/Some/All */
823 nested = 0; 823 nested = 0;
824 selected = "unknown"; 824 selected = "unknown";
825 while ((++dist)->set != SET_GROUP_END || nested--) { 825 while ((++dist)->set != SET_GROUP_END || nested--) {
826 if (dist->set == SET_GROUP) { 826 if (dist->set == SET_GROUP) {
827 nested++; 827 nested++;
828 continue; 828 continue;
829 } 829 }
830 if (!(set_status[dist->set] & SET_VALID)) 830 if (!(set_status[dist->set] & SET_VALID))
831 continue; 831 continue;
832 if (set_status[dist->set] & SET_SELECTED) { 832 if (set_status[dist->set] & SET_SELECTED) {
833 if (selected == msg_none) { 833 if (selected == msg_none) {
834 selected = msg_some; 834 selected = msg_some;
835 break; 835 break;
836 } 836 }
837 selected = msg_all; 837 selected = msg_all;
838 } else { 838 } else {
839 if (selected == msg_all) { 839 if (selected == msg_all) {
840 selected = msg_some; 840 selected = msg_some;
841 break; 841 break;
842 } 842 }
843 selected = msg_none; 843 selected = msg_none;
844 } 844 }
845 } 845 }
846 } 846 }
847 847
848 wprintw(menu->mw, "%-30s %s", msg_string(desc), selected); 848 wprintw(menu->mw, "%-30s %s", msg_string(desc), selected);
849} 849}
850 850
851static int set_sublist(menudesc *menu, void *arg); 851static int set_sublist(menudesc *menu, void *arg);
852 852
853static int 853static int
854initialise_set_menu(distinfo *dist, menu_ent *me, distinfo **de, int all_none) 854initialise_set_menu(distinfo *dist, menu_ent *me, distinfo **de, int all_none)
855{ 855{
856 int set; 856 int set;
857 int sets; 857 int sets;
858 int nested; 858 int nested;
859 859
860 for (sets = 0; ; dist++) { 860 for (sets = 0; ; dist++) {
861 set = dist->set; 861 set = dist->set;
862 if (set == SET_LAST || set == SET_GROUP_END) 862 if (set == SET_LAST || set == SET_GROUP_END)
863 break; 863 break;
864 if (!(set_status[set] & SET_VALID)) 864 if (!(set_status[set] & SET_VALID))
865 continue; 865 continue;
866 *de = dist; 866 *de = dist;
867 memset(me, 0, sizeof(*me)); 867 memset(me, 0, sizeof(*me));
868 if (set != SET_GROUP) 868 if (set != SET_GROUP)
869 me->opt_action = set_toggle; 869 me->opt_action = set_toggle;
870 else { 870 else {
871 /* Collapse sublist */ 871 /* Collapse sublist */
872 nested = 0; 872 nested = 0;
873 while ((++dist)->set != SET_GROUP_END || nested--) { 873 while ((++dist)->set != SET_GROUP_END || nested--) {
874 if (dist->set == SET_GROUP) 874 if (dist->set == SET_GROUP)
875 nested++; 875 nested++;
876 } 876 }
877 me->opt_action = set_sublist; 877 me->opt_action = set_sublist;
878 } 878 }
879 sets++; 879 sets++;
880 de++; 880 de++;
881 me++; 881 me++;
882 } 882 }
883 883
884 if (all_none) { 884 if (all_none) {
885 me->opt_name = MSG_select_all; 885 me->opt_name = MSG_select_all;
886 me->opt_action = set_all; 886 me->opt_action = set_all;
887 me++; 887 me++;
888 me->opt_name = MSG_select_none; 888 me->opt_name = MSG_select_none;
889 me->opt_action = set_none; 889 me->opt_action = set_none;
890 sets += 2; 890 sets += 2;
891 } 891 }
892 892
893 return sets; 893 return sets;
894} 894}
895 895
896static int 896static int
897set_sublist(menudesc *menu, void *arg) 897set_sublist(menudesc *menu, void *arg)
898{ 898{
899 distinfo *de[SET_LAST]; 899 distinfo *de[SET_LAST];
900 menu_ent me[SET_LAST]; 900 menu_ent me[SET_LAST];
901 distinfo **dist = arg; 901 distinfo **dist = arg;
902 int menu_no; 902 int menu_no;
903 int sets; 903 int sets;
904 904
905 memset(me, 0, sizeof(me)); 905 memset(me, 0, sizeof(me));
906 sets = initialise_set_menu(dist[menu->cursel] + 1, me, de, 1); 906 sets = initialise_set_menu(dist[menu->cursel] + 1, me, de, 1);
907 907
908 menu_no = new_menu(NULL, me, sets, 20, 10, 0, select_menu_width, 908 menu_no = new_menu(NULL, me, sets, 20, 10, 0, select_menu_width,
909 MC_SUBMENU | MC_SCROLL | MC_DFLTEXIT, 909 MC_SUBMENU | MC_SCROLL | MC_DFLTEXIT,
910 NULL, set_label, NULL, NULL, 910 NULL, set_label, NULL, NULL,
911 MSG_install_selected_sets); 911 MSG_install_selected_sets);
912 912
913 process_menu(menu_no, de); 913 process_menu(menu_no, de);
914 free_menu(menu_no); 914 free_menu(menu_no);
915 915
916 return 0; 916 return 0;
917} 917}
918 918
919void 919void
920customise_sets(void) 920customise_sets(void)
921{ 921{
922 distinfo *de[SET_LAST]; 922 distinfo *de[SET_LAST];
923 menu_ent me[SET_LAST]; 923 menu_ent me[SET_LAST];
924 int sets; 924 int sets;
925 int menu_no; 925 int menu_no;
926 926
927 msg_display(MSG_cur_distsets); 927 msg_display(MSG_cur_distsets);
928 msg_table_add(MSG_cur_distsets_header); 928 msg_table_add(MSG_cur_distsets_header);
929 929
930 memset(me, 0, sizeof(me)); 930 memset(me, 0, sizeof(me));
931 sets = initialise_set_menu(dist_list, me, de, 0); 931 sets = initialise_set_menu(dist_list, me, de, 0);
932 932
933 menu_no = new_menu(NULL, me, sets, 0, 5, 0, select_menu_width, 933 menu_no = new_menu(NULL, me, sets, 0, 5, 0, select_menu_width,
934 MC_SCROLL | MC_NOBOX | MC_DFLTEXIT | MC_NOCLEAR, 934 MC_SCROLL | MC_NOBOX | MC_DFLTEXIT | MC_NOCLEAR,
935 NULL, set_label, NULL, NULL, 935 NULL, set_label, NULL, NULL,
936 MSG_install_selected_sets); 936 MSG_install_selected_sets);
937 937
938 process_menu(menu_no, de); 938 process_menu(menu_no, de);
939 free_menu(menu_no); 939 free_menu(menu_no);
940} 940}
941 941
942/* 942/*
943 * Extract_file **REQUIRES** an absolute path in ext_dir. Any code 943 * Extract_file **REQUIRES** an absolute path in ext_dir. Any code
944 * that sets up xfer_dir for use by extract_file needs to put in the 944 * that sets up xfer_dir for use by extract_file needs to put in the
945 * full path name to the directory. 945 * full path name to the directory.
946 */ 946 */
947 947
948int 948int
949extract_file(distinfo *dist, int update) 949extract_file(distinfo *dist, int update)
950{ 950{
951 const char *dest_dir = NULL; 951 const char *dest_dir = NULL;
952 952
953 if (update && (dist->set == SET_ETC || dist->set == SET_X11_ETC)) { 953 if (update && (dist->set == SET_ETC || dist->set == SET_X11_ETC)) {
954 dest_dir = "/.sysinst"; 954 dest_dir = "/.sysinst";
955 make_target_dir(dest_dir); 955 make_target_dir(dest_dir);
956 } else if (dist->set == SET_PKGSRC) 956 } else if (dist->set == SET_PKGSRC)
957 dest_dir = "/usr"; 957 dest_dir = "/usr";
958 else 958 else
959 dest_dir = "/"; 959 dest_dir = "/";
960 960
961 return extract_file_to(dist, update, dest_dir, NULL, true); 961 return extract_file_to(dist, update, dest_dir, NULL, true);
962} 962}
963 963
964int 964int
965extract_file_to(distinfo *dist, int update, const char *dest_dir, 965extract_file_to(distinfo *dist, int update, const char *dest_dir,
966 const char *extr_pattern, bool do_stats) 966 const char *extr_pattern, bool do_stats)
967{ 967{
968 char path[STRSIZE]; 968 char path[STRSIZE];
969 char *owd; 969 char *owd;
970 int rval; 970 int rval;
971 971
972 /* If we might need to tidy up, ensure directory exists */ 972 /* If we might need to tidy up, ensure directory exists */
973 if (fetch_fn != NULL) 973 if (fetch_fn != NULL)
974 make_target_dir(xfer_dir); 974 make_target_dir(xfer_dir);
975 975
976 (void)snprintf(path, sizeof path, "%s/%s%s", 976 (void)snprintf(path, sizeof path, "%s/%s%s",
977 ext_dir_for_set(dist->name), dist->name, set_postfix(dist->name)); 977 ext_dir_for_set(dist->name), dist->name, set_postfix(dist->name));
978 978
979 owd = getcwd(NULL, 0); 979 owd = getcwd(NULL, 0);
980 980
981 /* Do we need to fetch the file now? */ 981 /* Do we need to fetch the file now? */
982 if (fetch_fn != NULL) { 982 if (fetch_fn != NULL) {
983 rval = fetch_fn(dist->name); 983 rval = fetch_fn(dist->name);
984 if (rval != SET_OK) 984 if (rval != SET_OK)
985 return rval; 985 return rval;
986 } 986 }
987 987
988 /* check tarfile exists */ 988 /* check tarfile exists */
989 if (!file_exists_p(path)) { 989 if (!file_exists_p(path)) {
990 990
991#ifdef SUPPORT_8_3_SOURCE_FILESYSTEM 991#ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
992 /* 992 /*
993 * Update path to use dist->name truncated to the first eight 993 * Update path to use dist->name truncated to the first eight
994 * characters and check again 994 * characters and check again
995 */ 995 */
996 (void)snprintf(path, sizeof path, 996 (void)snprintf(path, sizeof path,
997 "%s/%.8s%.4s", /* 4 as includes '.' */ 997 "%s/%.8s%.4s", /* 4 as includes '.' */
998 ext_dir_for_set(dist->name), dist->name, 998 ext_dir_for_set(dist->name), dist->name,
999 set_postfix(dist->name)); 999 set_postfix(dist->name));
1000 1000
1001 if (!file_exists_p(path)) { 1001 if (!file_exists_p(path)) {
1002#endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */ 1002#endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
1003 if (do_stats) 1003 if (do_stats)
1004 tarstats.nnotfound++; 1004 tarstats.nnotfound++;
1005 1005
1006 char *err = str_arg_subst(msg_string(MSG_notarfile), 1006 char *err = str_arg_subst(msg_string(MSG_notarfile),
1007 1, &dist->name); 1007 1, &dist->name);
1008 hit_enter_to_continue(err, NULL); 1008 hit_enter_to_continue(err, NULL);
1009 free(err); 1009 free(err);
1010 free(owd); 1010 free(owd);
1011 return SET_RETRY; 1011 return SET_RETRY;
1012 } 1012 }
1013#ifdef SUPPORT_8_3_SOURCE_FILESYSTEM 1013#ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
1014 } 1014 }
1015#endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */ 1015#endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
1016 1016
1017 if (do_stats) 1017 if (do_stats)
1018 tarstats.nfound++; 1018 tarstats.nfound++;
1019 /* cd to the target root. */ 1019 /* cd to the target root. */
1020 target_chdir_or_die(dest_dir); 1020 target_chdir_or_die(dest_dir);
1021 1021
1022 /* 1022 /*
1023 * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0 1023 * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0
1024 * but is a file in 5.1 and beyond, so on upgrades we need to 1024 * but is a file in 5.1 and beyond, so on upgrades we need to
1025 * delete it before extracting the xbase set. 1025 * delete it before extracting the xbase set.
1026 */ 1026 */
1027 if (update && dist->set == SET_X11_BASE) 1027 if (update && dist->set == SET_X11_BASE)
1028 run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc"); 1028 run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc");
1029 1029
1030 /* now extract set files into "./". */ 1030 /* now extract set files into "./". */
1031 if (extr_pattern != NULL) { 1031 if (extr_pattern != NULL) {
1032 rval = run_program(RUN_DISPLAY | RUN_PROGRESS, 1032 rval = run_program(RUN_DISPLAY | RUN_PROGRESS,
1033 "progress -zf %s tar --chroot " 1033 "progress -zf %s tar --chroot "
1034 TAR_EXTRACT_FLAGS " - '%s'", 1034 TAR_EXTRACT_FLAGS " - '%s'",
1035 path, extr_pattern); 1035 path, extr_pattern);
1036 } else { 1036 } else {
1037 rval = run_program(RUN_DISPLAY | RUN_PROGRESS, 1037 rval = run_program(RUN_DISPLAY | RUN_PROGRESS,
1038 "progress -zf %s tar --chroot " 1038 "progress -zf %s tar --chroot "
1039 TAR_EXTRACT_FLAGS " -", path); 1039 TAR_EXTRACT_FLAGS " -", path);
1040 } 1040 }
1041 1041
1042 chdir(owd); 1042 chdir(owd);
1043 free(owd); 1043 free(owd);
1044 1044
1045 /* Check rval for errors and give warning. */ 1045 /* Check rval for errors and give warning. */
1046 if (rval != 0) { 1046 if (rval != 0) {
1047 if (do_stats) 1047 if (do_stats)
1048 tarstats.nerror++; 1048 tarstats.nerror++;
1049 msg_fmt_display(MSG_tarerror, "%s", path); 1049 msg_fmt_display(MSG_tarerror, "%s", path);
1050 hit_enter_to_continue(NULL, NULL); 1050 hit_enter_to_continue(NULL, NULL);
1051 return SET_RETRY; 1051 return SET_RETRY;
1052 } 1052 }
1053 1053
1054 if (fetch_fn != NULL && clean_xfer_dir) { 1054 if (fetch_fn != NULL && clean_xfer_dir) {
1055 run_program(0, "rm %s", path); 1055 run_program(0, "rm %s", path);
1056 /* Plausibly we should unlink an empty xfer_dir as well */ 1056 /* Plausibly we should unlink an empty xfer_dir as well */
1057 } 1057 }
1058 1058
1059 set_status[dist->set] |= SET_INSTALLED; 1059 set_status[dist->set] |= SET_INSTALLED;
1060 if (do_stats) 1060 if (do_stats)
1061 tarstats.nsuccess++; 1061 tarstats.nsuccess++;
1062 return SET_OK; 1062 return SET_OK;
1063} 1063}
1064 1064
1065static void 1065static void
1066skip_set(distinfo *dist, int skip_type) 1066skip_set(distinfo *dist, int skip_type)
1067{ 1067{
1068 int nested; 1068 int nested;
1069 int set; 1069 int set;
1070 1070
1071 nested = 0; 1071 nested = 0;
1072 while ((++dist)->set != SET_GROUP_END || nested--) { 1072 while ((++dist)->set != SET_GROUP_END || nested--) {
1073 set = dist->set; 1073 set = dist->set;
1074 if (set == SET_GROUP) { 1074 if (set == SET_GROUP) {
1075 nested++; 1075 nested++;
1076 continue; 1076 continue;
1077 } 1077 }
1078 if (set == SET_LAST) 1078 if (set == SET_LAST)
1079 break; 1079 break;
1080 if (set_status[set] == (SET_SELECTED | SET_VALID)) 1080 if (set_status[set] == (SET_SELECTED | SET_VALID))
1081 set_status[set] |= SET_SKIPPED; 1081 set_status[set] |= SET_SKIPPED;
1082 tarstats.nskipped++; 1082 tarstats.nskipped++;
1083 } 1083 }
1084} 1084}
1085 1085
1086distinfo* 1086distinfo*
1087get_set_distinfo(int opt) 1087get_set_distinfo(int opt)
1088{ 1088{
1089 distinfo *dist; 1089 distinfo *dist;
1090 int set; 1090 int set;
1091 1091
1092 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1092 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1093 if (set != opt) 1093 if (set != opt)
1094 continue; 1094 continue;
1095 if (dist->name == NULL) 1095 if (dist->name == NULL)
1096 continue; 1096 continue;
1097 if ((set_status[set] & (SET_VALID | SET_SELECTED)) 1097 if ((set_status[set] & (SET_VALID | SET_SELECTED))
1098 != (SET_VALID | SET_SELECTED)) 1098 != (SET_VALID | SET_SELECTED))
1099 continue; 1099 continue;
1100 return dist; 1100 return dist;
1101 } 1101 }
1102 1102
1103 return NULL; 1103 return NULL;
1104} 1104}
1105 1105
1106 1106
1107/* 1107/*
1108 * Get and unpack the distribution. 1108 * Get and unpack the distribution.
1109 * Show success_msg if installation completes. 1109 * Show success_msg if installation completes.
1110 * Otherwise show failure_msg and wait for the user to ack it before continuing. 1110 * Otherwise show failure_msg and wait for the user to ack it before continuing.
1111 * success_msg and failure_msg must both be 0-adic messages. 1111 * success_msg and failure_msg must both be 0-adic messages.
1112 */ 1112 */
1113int 1113int
1114get_and_unpack_sets(int update, msg setupdone_msg, msg success_msg, msg failure_msg) 1114get_and_unpack_sets(int update, msg setupdone_msg, msg success_msg, msg failure_msg)
1115{ 1115{
1116 distinfo *dist; 1116 distinfo *dist;
1117 int status; 1117 int status;
1118 int set, olderror, oldfound; 1118 int set, olderror, oldfound;
1119 bool entropy_loaded = false; 1119 bool entropy_loaded = false;
1120 1120
1121 /* Ensure mountpoint for distribution files exists in current root. */ 1121 /* Ensure mountpoint for distribution files exists in current root. */
1122 (void)mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); 1122 (void)mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
1123 if (script) 1123 if (script)
1124 (void)fprintf(script, "mkdir -m 755 /mnt2\n"); 1124 (void)fprintf(script, "mkdir -m 755 /mnt2\n");
1125 1125
1126 /* reset failure/success counters */ 1126 /* reset failure/success counters */
1127 memset(&tarstats, 0, sizeof(tarstats)); 1127 memset(&tarstats, 0, sizeof(tarstats));
1128 1128
1129 /* Find out which files to "get" if we get files. */ 1129 /* Find out which files to "get" if we get files. */
1130 1130
1131 /* Accurately count selected sets */ 1131 /* Accurately count selected sets */
1132 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1132 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1133 if (dist->name == NULL) 1133 if (dist->name == NULL)
1134 continue; 1134 continue;
1135 if (set_status[set] & SET_NO_EXTRACT) 1135 if (set_status[set] & SET_NO_EXTRACT)
1136 continue; 1136 continue;
1137 if ((set_status[set] & (SET_VALID | SET_SELECTED)) 1137 if ((set_status[set] & (SET_VALID | SET_SELECTED))
1138 == (SET_VALID | SET_SELECTED)) 1138 == (SET_VALID | SET_SELECTED))
1139 tarstats.nselected++; 1139 tarstats.nselected++;
1140 } 1140 }
1141 1141
1142 status = SET_RETRY; 1142 status = SET_RETRY;
1143 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1143 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1144 if (dist->name == NULL) 1144 if (dist->name == NULL)
1145 continue; 1145 continue;
1146 if (set_status[set] != (SET_VALID | SET_SELECTED)) 1146 if (set_status[set] != (SET_VALID | SET_SELECTED))
1147 continue; 1147 continue;
1148 1148
1149 /* save stats, in case we will retry */ 1149 /* save stats, in case we will retry */
1150 oldfound = tarstats.nfound; 1150 oldfound = tarstats.nfound;
1151 olderror = tarstats.nerror; 1151 olderror = tarstats.nerror;
1152 1152
1153 if (status != SET_OK) { 1153 if (status != SET_OK) {
1154 /* This might force a redraw.... */ 1154 /* This might force a redraw.... */
1155 clearok(curscr, 1); 1155 clearok(curscr, 1);
1156 touchwin(stdscr); 1156 touchwin(stdscr);
1157 wrefresh(stdscr); 1157 wrefresh(stdscr);
1158 /* Sort out the location of the set files */ 1158 /* Sort out the location of the set files */
1159 do { 1159 do {
1160 umount_mnt2(); 1160 umount_mnt2();
1161 msg_fmt_display(MSG_distmedium, "%d%d%s", 1161 msg_fmt_display(MSG_distmedium, "%d%d%s",
1162 tarstats.nselected, 1162 tarstats.nselected,
1163 tarstats.nsuccess + tarstats.nskipped, 1163 tarstats.nsuccess + tarstats.nskipped,
1164 dist->name); 1164 dist->name);
1165 fetch_fn = NULL; 1165 fetch_fn = NULL;
1166 process_menu(MENU_distmedium, &status); 1166 process_menu(MENU_distmedium, &status);
1167 } while (status == SET_RETRY); 1167 } while (status == SET_RETRY);
1168 1168
1169 if (status == SET_SKIP) { 1169 if (status == SET_SKIP) {
1170 set_status[set] |= SET_SKIPPED; 1170 set_status[set] |= SET_SKIPPED;
1171 tarstats.nskipped++; 1171 tarstats.nskipped++;
1172 continue; 1172 continue;
1173 } 1173 }
1174 if (status == SET_SKIP_GROUP) { 1174 if (status == SET_SKIP_GROUP) {
1175 skip_set(dist, status); 1175 skip_set(dist, status);
1176 continue; 1176 continue;
1177 } 1177 }
1178 if (status != SET_OK) { 1178 if (status != SET_OK) {
1179 hit_enter_to_continue(failure_msg, NULL); 1179 hit_enter_to_continue(failure_msg, NULL);
1180 return 1; 1180 return 1;
1181 } 1181 }
1182 } 1182 }
1183 1183
1184 if (set_status[set] & SET_NO_EXTRACT) 1184 if (set_status[set] & SET_NO_EXTRACT)
1185 continue; 1185 continue;
1186 1186
1187 /* Try to extract this set */ 1187 /* Try to extract this set */
1188 status = extract_file(dist, update); 1188 status = extract_file(dist, update);
1189 if (status == SET_RETRY) { 1189 if (status == SET_RETRY) {
1190 /* do this set again */ 1190 /* do this set again */
1191 dist--; 1191 dist--;
1192 /* and reset statistics to what we had before this 1192 /* and reset statistics to what we had before this
1193 * set */ 1193 * set */
1194 tarstats.nfound = oldfound; 1194 tarstats.nfound = oldfound;
1195 tarstats.nerror = olderror; 1195 tarstats.nerror = olderror;
1196 } 1196 }
1197 } 1197 }
1198 1198
1199#ifdef MD_SET_EXTRACT_FINALIZE 1199#ifdef MD_SET_EXTRACT_FINALIZE
1200 MD_SET_EXTRACT_FINALIZE(update); 1200 MD_SET_EXTRACT_FINALIZE(update);
1201#endif 1201#endif
1202 1202
1203 if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) { 1203 if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) {
1204 msg_display(MSG_endtarok); 1204 msg_display(MSG_endtarok);
1205 /* Give user a chance to see the success message */ 1205 /* Give user a chance to see the success message */
1206 sleep(1); 1206 sleep(1);
1207 } else { 1207 } else {
1208 /* We encountered errors. Let the user know. */ 1208 /* We encountered errors. Let the user know. */
1209 msg_fmt_display(MSG_endtar, "%d%d%d%d%d%d", 1209 msg_fmt_display(MSG_endtar, "%d%d%d%d%d%d",
1210 tarstats.nselected, tarstats.nnotfound, tarstats.nskipped, 1210 tarstats.nselected, tarstats.nnotfound, tarstats.nskipped,
1211 tarstats.nfound, tarstats.nsuccess, tarstats.nerror); 1211 tarstats.nfound, tarstats.nsuccess, tarstats.nerror);
1212 hit_enter_to_continue(NULL, NULL); 1212 hit_enter_to_continue(NULL, NULL);
1213 } 1213 }
1214 1214
1215 /* 1215 /*
1216 * postinstall needs to be run after extracting all sets, because 1216 * postinstall needs to be run after extracting all sets, because
1217 * otherwise /var/db/obsolete will only have current information 1217 * otherwise /var/db/obsolete will only have current information
1218 * from the base, comp, and etc sets. 1218 * from the base, comp, and etc sets.
1219 */ 1219 */
1220 if (update && (set_status[SET_ETC] & SET_INSTALLED)) { 1220 if (update && (set_status[SET_ETC] & SET_INSTALLED)) {
1221 int oldsendmail; 1221 int oldsendmail;
1222 oldsendmail = run_program(RUN_DISPLAY | RUN_CHROOT | 1222 oldsendmail = run_program(RUN_DISPLAY | RUN_CHROOT |
1223 RUN_ERROR_OK | RUN_PROGRESS, 1223 RUN_ERROR_OK | RUN_PROGRESS,
1224 "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf"); 1224 "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf");
1225 if (oldsendmail == 1) { 1225 if (oldsendmail == 1) {
1226 msg_display(MSG_oldsendmail); 1226 msg_display(MSG_oldsendmail);
1227 if (ask_yesno(NULL)) { 1227 if (ask_yesno(NULL)) {
1228 run_program(RUN_DISPLAY | RUN_CHROOT, 1228 run_program(RUN_DISPLAY | RUN_CHROOT,
1229 "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf"); 1229 "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf");
1230 } 1230 }
1231 } 1231 }
1232 run_program(RUN_DISPLAY | RUN_CHROOT, 1232 run_program(RUN_DISPLAY | RUN_CHROOT,
1233 "/usr/sbin/postinstall -s /.sysinst -d / fix"); 1233 "/usr/sbin/postinstall -s /.sysinst -d / fix");
1234 1234
1235 /* Don't discard the system's old entropy if any */ 1235 /* Don't discard the system's old entropy if any */
1236 run_program(RUN_CHROOT | RUN_SILENT, 1236 run_program(RUN_CHROOT | RUN_SILENT,
1237 "/etc/rc.d/random_seed start"); 1237 "/etc/rc.d/random_seed start");
1238 entropy_loaded = true; 1238 entropy_loaded = true;
1239 } 1239 }
1240 1240
1241 /* Configure the system */ 1241 /* Configure the system */
1242 if (set_status[SET_BASE] & SET_INSTALLED) 1242 if (set_status[SET_BASE] & SET_INSTALLED)
1243 run_makedev(); 1243 run_makedev();
1244 1244
1245 if (!update) { 1245 if (!update) {
1246 struct stat sb1, sb2; 1246 struct stat sb1, sb2;
1247 1247
1248 if (stat(target_expand("/"), &sb1) == 0 1248 if (stat(target_expand("/"), &sb1) == 0
1249 && stat(target_expand("/var"), &sb2) == 0 1249 && stat(target_expand("/var"), &sb2) == 0
1250 && sb1.st_dev != sb2.st_dev) { 1250 && sb1.st_dev != sb2.st_dev) {
1251 add_rc_conf("random_file=/etc/entropy-file\n"); 1251 add_rc_conf("random_file=/etc/entropy-file\n");
1252 if (target_file_exists_p("/boot.cfg")) { 1252 if (target_file_exists_p("/boot.cfg")) {
1253 run_program(RUN_CHROOT|RUN_FATAL, 1253 run_program(RUN_CHROOT|RUN_FATAL,
1254 "sh -c 'sed -e s./var/db/./etc/. " 1254 "sh -c 'sed -e s./var/db/./etc/. "
1255 "< /boot.cfg " 1255 "< /boot.cfg "
1256 "> /tmp/boot.cfg.tmp'"); 1256 "> /tmp/boot.cfg.tmp'");
1257 mv_within_target_or_die("/tmp/boot.cfg.tmp", 1257 mv_within_target_or_die("/tmp/boot.cfg.tmp",
1258 "/boot.cfg"); 1258 "/boot.cfg");
1259 1259
1260 } 1260 }
1261 } 1261 }
1262 1262
1263#ifdef MD_BOOT_CFG_FINALIZE 1263#ifdef MD_BOOT_CFG_FINALIZE
1264 if (target_file_exists_p("/boot.cfg")) { 1264 if (target_file_exists_p("/boot.cfg")) {
1265 MD_BOOT_CFG_FINALIZE("/boot.cfg"); 1265 MD_BOOT_CFG_FINALIZE("/boot.cfg");
1266 } 1266 }
1267#endif 1267#endif
1268 1268
1269 /* Save keyboard type */ 1269 /* Save keyboard type */
1270 save_kb_encoding(); 1270 save_kb_encoding();
1271 1271
1272 /* Other configuration. */ 1272 /* Other configuration. */
1273 mnt_net_config(); 1273 mnt_net_config();
1274 } 1274 }
1275 1275
1276 /* Mounted dist dir? */ 1276 /* Mounted dist dir? */
1277 umount_mnt2(); 1277 umount_mnt2();
1278 1278
1279 /* Save entropy -- on some systems it's ~all we'll ever get */ 1279 /* Save entropy -- on some systems it's ~all we'll ever get */
1280 if (!update || entropy_loaded) 1280 if (!update || entropy_loaded)
1281 run_program(RUN_SILENT | RUN_CHROOT | RUN_ERROR_OK, 1281 run_program(RUN_SILENT | RUN_CHROOT | RUN_ERROR_OK,
1282 "/etc/rc.d/random_seed stop"); 1282 "/etc/rc.d/random_seed stop");
1283 /* Install/Upgrade complete ... reboot or exit to script */ 1283 /* Install/Upgrade complete ... reboot or exit to script */
1284 hit_enter_to_continue(success_msg, NULL); 1284 hit_enter_to_continue(success_msg, NULL);
1285 return 0; 1285 return 0;
1286} 1286}
1287 1287
1288void 1288void
1289umount_mnt2(void) 1289umount_mnt2(void)
1290{ 1290{
1291 if (!mnt2_mounted) 1291 if (!mnt2_mounted)
1292 return; 1292 return;
1293 run_program(RUN_SILENT, "/sbin/umount /mnt2"); 1293 run_program(RUN_SILENT, "/sbin/umount /mnt2");
1294 mnt2_mounted = 0; 1294 mnt2_mounted = 0;
1295} 1295}
1296 1296
1297 1297
1298/* 1298/*
1299 * Do a quick sanity check that the target can reboot. 1299 * Do a quick sanity check that the target can reboot.
1300 * return 1 if everything OK, 0 if there is a problem. 1300 * return 1 if everything OK, 0 if there is a problem.
1301 * Uses a table of files we expect to find after a base install/upgrade. 1301 * Uses a table of files we expect to find after a base install/upgrade.
1302 */ 1302 */
1303 1303
1304/* test flag and pathname to check for after unpacking. */ 1304/* test flag and pathname to check for after unpacking. */
1305struct check_table { unsigned int mode; const char *path;} checks[] = { 1305struct check_table { unsigned int mode; const char *path;} checks[] = {
1306 { S_IFREG, "/netbsd" }, 1306 { S_IFREG, "/netbsd" },
1307 { S_IFDIR, "/etc" }, 1307 { S_IFDIR, "/etc" },
1308 { S_IFREG, "/etc/fstab" }, 1308 { S_IFREG, "/etc/fstab" },
1309 { S_IFREG, "/sbin/init" }, 1309 { S_IFREG, "/sbin/init" },
1310 { S_IFREG, "/bin/sh" }, 1310 { S_IFREG, "/bin/sh" },
1311 { S_IFREG, "/etc/rc" }, 1311 { S_IFREG, "/etc/rc" },
1312 { S_IFREG, "/etc/rc.subr" }, 1312 { S_IFREG, "/etc/rc.subr" },
1313 { S_IFREG, "/etc/rc.conf" }, 1313 { S_IFREG, "/etc/rc.conf" },
1314 { S_IFDIR, "/dev" }, 1314 { S_IFDIR, "/dev" },
1315 { S_IFCHR, "/dev/console" }, 1315 { S_IFCHR, "/dev/console" },
1316/* XXX check for rootdev in target /dev? */ 1316/* XXX check for rootdev in target /dev? */
1317 { S_IFREG, "/sbin/fsck" }, 1317 { S_IFREG, "/sbin/fsck" },
1318 { S_IFREG, "/sbin/fsck_ffs" }, 1318 { S_IFREG, "/sbin/fsck_ffs" },
1319 { S_IFREG, "/sbin/mount" }, 1319 { S_IFREG, "/sbin/mount" },
1320 { S_IFREG, "/sbin/mount_ffs" }, 1320 { S_IFREG, "/sbin/mount_ffs" },
1321 { S_IFREG, "/sbin/mount_nfs" }, 1321 { S_IFREG, "/sbin/mount_nfs" },
1322#if defined(DEBUG) || defined(DEBUG_CHECK) 1322#if defined(DEBUG) || defined(DEBUG_CHECK)
1323 { S_IFREG, "/foo/bar" }, /* bad entry to exercise warning */ 1323 { S_IFREG, "/foo/bar" }, /* bad entry to exercise warning */
1324#endif 1324#endif
1325 { 0, 0 } 1325 { 0, 0 }
1326 1326
1327}; 1327};
1328 1328
1329/* 1329/*
1330 * Check target for a single file. 1330 * Check target for a single file.
1331 */ 1331 */
1332static int 1332static int
1333check_for(unsigned int mode, const char *pathname) 1333check_for(unsigned int mode, const char *pathname)
1334{ 1334{
1335 int found; 1335 int found;
1336 1336
1337 found = (target_test(mode, pathname) == 0); 1337 found = (target_test(mode, pathname) == 0);
1338 if (found == 0) 1338 if (found == 0)
1339 msg_fmt_display(MSG_rootmissing, "%s", pathname); 1339 msg_fmt_display(MSG_rootmissing, "%s", pathname);
1340 return found; 1340 return found;
1341} 1341}
1342 1342
1343/* 1343/*
1344 * Check that all the files in check_table are present in the 1344 * Check that all the files in check_table are present in the
1345 * target root. Warn if not found. 1345 * target root. Warn if not found.
1346 */ 1346 */
1347int 1347int
1348sanity_check(void) 1348sanity_check(void)
1349{ 1349{
1350 int target_ok = 1; 1350 int target_ok = 1;
1351 struct check_table *p; 1351 struct check_table *p;
1352 1352
1353 for (p = checks; p->path; p++) { 1353 for (p = checks; p->path; p++) {
1354 target_ok = target_ok && check_for(p->mode, p->path); 1354 target_ok = target_ok && check_for(p->mode, p->path);
1355 } 1355 }
1356 if (target_ok) 1356 if (target_ok)
1357 return 0; 1357 return 0;
1358 1358
1359 /* Uh, oh. Something's missing. */ 1359 /* Uh, oh. Something's missing. */
1360 hit_enter_to_continue(MSG_badroot, NULL); 1360 hit_enter_to_continue(MSG_badroot, NULL);
1361 return 1; 1361 return 1;
1362} 1362}
1363 1363
1364/* 1364/*
1365 * Some globals to pass things back from callbacks 1365 * Some globals to pass things back from callbacks
1366 */ 1366 */
1367static char zoneinfo_dir[STRSIZE]; 1367static char zoneinfo_dir[STRSIZE];
1368static int zonerootlen; 1368static int zonerootlen;
1369static char *tz_selected; /* timezonename (relative to share/zoneinfo */ 1369static char *tz_selected; /* timezonename (relative to share/zoneinfo */
1370const char *tz_default; /* UTC, or whatever /etc/localtime points to */ 1370const char *tz_default; /* UTC, or whatever /etc/localtime points to */
1371static char tz_env[STRSIZE]; 1371static char tz_env[STRSIZE];
1372static int save_cursel, save_topline; 1372static int save_cursel, save_topline;
1373static int time_menu = -1; 1373static int time_menu = -1;
1374 1374
1375static void 1375static void
1376update_time_display(void) 1376update_time_display(void)
1377{ 1377{
1378 time_t t; 1378 time_t t;
1379 struct tm *tm; 1379 struct tm *tm;
1380 char cur_time[STRSIZE], *p; 1380 char cur_time[STRSIZE], *p;
1381 1381
1382 t = time(NULL); 1382 t = time(NULL);
1383 tm = localtime(&t); 1383 tm = localtime(&t);
1384 strlcpy(cur_time, safectime(&t), sizeof cur_time); 1384 strlcpy(cur_time, safectime(&t), sizeof cur_time);
1385 p = strchr(cur_time, '\n'); 1385 p = strchr(cur_time, '\n');
1386 if (p != NULL) 1386 if (p != NULL)
1387 *p = 0; 1387 *p = 0;
1388 1388
1389 msg_clear(); 1389 msg_clear();
1390 msg_fmt_table_add(MSG_choose_timezone, "%s%s%s%s", 1390 msg_fmt_table_add(MSG_choose_timezone, "%s%s%s%s",
1391 tz_default, tz_selected, cur_time, tm ? tm->tm_zone : "?"); 1391 tz_default, tz_selected, cur_time, tm ? tm->tm_zone : "?");
1392} 1392}
1393 1393
1394/* 1394/*
1395 * Callback from timezone menu 1395 * Callback from timezone menu
1396 */ 1396 */
1397static int 1397static int
1398set_tz_select(menudesc *m, void *arg) 1398set_tz_select(menudesc *m, void *arg)
1399{ 1399{
1400 char *new; 1400 char *new;
1401 1401
1402 if (m && strcmp(tz_selected, m->opts[m->cursel].opt_name) != 0) { 1402 if (m && strcmp(tz_selected, m->opts[m->cursel].opt_name) != 0) {
1403 /* Change the displayed timezone */ 1403 /* Change the displayed timezone */
1404 new = strdup(m->opts[m->cursel].opt_name); 1404 new = strdup(m->opts[m->cursel].opt_name);
1405 if (new == NULL) 1405 if (new == NULL)
1406 return 0; 1406 return 0;
1407 free(tz_selected); 1407 free(tz_selected);
1408 tz_selected = new; 1408 tz_selected = new;
1409 snprintf(tz_env, sizeof tz_env, "%.*s%s", 1409 snprintf(tz_env, sizeof tz_env, "%.*s%s",
1410 zonerootlen, zoneinfo_dir, tz_selected); 1410 zonerootlen, zoneinfo_dir, tz_selected);
1411 setenv("TZ", tz_env, 1); 1411 setenv("TZ", tz_env, 1);
1412 } 1412 }
1413 if (m) 1413 if (m)
1414 /* Warp curser to 'Exit' line on menu */ 1414 /* Warp curser to 'Exit' line on menu */
1415 m->cursel = -1; 1415 m->cursel = -1;
1416 1416
1417 update_time_display(); 1417 update_time_display();
1418 if (time_menu >= 1) { 1418 if (time_menu >= 1) {
1419 WINDOW *w = get_menudesc(time_menu)->mw; 1419 WINDOW *w = get_menudesc(time_menu)->mw;
1420 if (w != NULL) { 1420 if (w != NULL) {
1421 touchwin(w); 1421 touchwin(w);
1422 wrefresh(w); 1422 wrefresh(w);
1423 } 1423 }
1424 } 1424 }
1425 return 0; 1425 return 0;
1426} 1426}
1427 1427
1428static int 1428static int
1429set_tz_back(menudesc *m, void *arg) 1429set_tz_back(menudesc *m, void *arg)
1430{ 1430{
1431 1431
1432 zoneinfo_dir[zonerootlen] = 0; 1432 zoneinfo_dir[zonerootlen] = 0;
1433 m->cursel = save_cursel; 1433 m->cursel = save_cursel;
1434 m->topline = save_topline; 1434 m->topline = save_topline;
1435 return 0; 1435 return 0;
1436} 1436}
1437 1437
1438static int 1438static int
1439set_tz_dir(menudesc *m, void *arg) 1439set_tz_dir(menudesc *m, void *arg)
1440{ 1440{
1441 1441
1442 strlcpy(zoneinfo_dir + zonerootlen, m->opts[m->cursel].opt_name, 1442 strlcpy(zoneinfo_dir + zonerootlen, m->opts[m->cursel].opt_name,
1443 sizeof zoneinfo_dir - zonerootlen); 1443 sizeof zoneinfo_dir - zonerootlen);
1444 save_cursel = m->cursel; 1444 save_cursel = m->cursel;
1445 save_topline = m->topline; 1445 save_topline = m->topline;
1446 m->cursel = 0; 1446 m->cursel = 0;
1447 m->topline = 0; 1447 m->topline = 0;
1448 return 0; 1448 return 0;
1449} 1449}
1450 1450
1451/* 1451/*
1452 * Alarm-handler to update example-display 1452 * Alarm-handler to update example-display
1453 */ 1453 */
1454static void 1454static void
1455/*ARGSUSED*/ 1455/*ARGSUSED*/
1456timezone_sig(int sig) 1456timezone_sig(int sig)
1457{ 1457{
1458 1458
1459 set_tz_select(NULL, NULL); 1459 set_tz_select(NULL, NULL);
1460 alarm(60); 1460 alarm(60);
1461} 1461}
1462 1462
1463static int 1463static int
1464tz_sort(const void *a, const void *b) 1464tz_sort(const void *a, const void *b)
1465{ 1465{
1466 return strcmp(((const menu_ent *)a)->opt_name, ((const menu_ent *)b)->opt_name); 1466 return strcmp(((const menu_ent *)a)->opt_name, ((const menu_ent *)b)->opt_name);
1467} 1467}
1468 1468
1469static void 1469static void
1470tzm_set_names(menudesc *m, void *arg) 1470tzm_set_names(menudesc *m, void *arg)
1471{ 1471{
1472 DIR *dir; 1472 DIR *dir;
1473 struct dirent *dp; 1473 struct dirent *dp;
1474 static int nfiles; 1474 static int nfiles;
1475 static int maxfiles = 32; 1475 static int maxfiles = 32;
1476 static menu_ent *tz_menu; 1476 static menu_ent *tz_menu;
1477 static char **tz_names; 1477 static char **tz_names;
1478 void *p; 1478 void *p;
1479 int maxfname; 1479 int maxfname;
1480 char *fp; 1480 char *fp;
1481 struct stat sb; 1481 struct stat sb;
1482 1482
1483 if (tz_menu == NULL) 1483 if (tz_menu == NULL)
1484 tz_menu = calloc(maxfiles, sizeof *tz_menu); 1484 tz_menu = calloc(maxfiles, sizeof *tz_menu);
1485 if (tz_names == NULL) 1485 if (tz_names == NULL)
1486 tz_names = malloc(maxfiles * sizeof *tz_names); 1486 tz_names = malloc(maxfiles * sizeof *tz_names);
1487 if (tz_menu == NULL || tz_names == NULL) 1487 if (tz_menu == NULL || tz_names == NULL)
1488 return; /* error - skip timezone setting */ 1488 return; /* error - skip timezone setting */
1489 while (nfiles > 0) 1489 while (nfiles > 0)
1490 free(tz_names[--nfiles]); 1490 free(tz_names[--nfiles]);
1491 1491
1492 dir = opendir(zoneinfo_dir); 1492 dir = opendir(zoneinfo_dir);
1493 fp = strchr(zoneinfo_dir, 0); 1493 fp = strchr(zoneinfo_dir, 0);
1494 if (fp != zoneinfo_dir + zonerootlen) { 1494 if (fp != zoneinfo_dir + zonerootlen) {
1495 tz_names[0] = 0; 1495 tz_names[0] = 0;
1496 tz_menu[0].opt_name = msg_string(MSG_tz_back); 1496 tz_menu[0].opt_name = msg_string(MSG_tz_back);
1497 tz_menu[0].opt_action = set_tz_back; 1497 tz_menu[0].opt_action = set_tz_back;
1498 nfiles = 1; 1498 nfiles = 1;
1499 } 1499 }
1500 maxfname = zoneinfo_dir + sizeof zoneinfo_dir - fp - 1; 1500 maxfname = zoneinfo_dir + sizeof zoneinfo_dir - fp - 1;
1501 if (dir != NULL) { 1501 if (dir != NULL) {
1502 while ((dp = readdir(dir)) != NULL) { 1502 while ((dp = readdir(dir)) != NULL) {
1503 if (dp->d_namlen > maxfname || dp->d_name[0] == '.') 1503 if (dp->d_namlen > maxfname || dp->d_name[0] == '.')
1504 continue; 1504 continue;
1505 strlcpy(fp, dp->d_name, maxfname); 1505 strlcpy(fp, dp->d_name, maxfname);
1506 if (stat(zoneinfo_dir, &sb) == -1) 1506 if (stat(zoneinfo_dir, &sb) == -1)
1507 continue; 1507 continue;
1508 if (nfiles >= maxfiles) { 1508 if (nfiles >= maxfiles) {
1509 p = realloc(tz_menu, 1509 p = realloc(tz_menu,
1510 2 * maxfiles * sizeof *tz_menu); 1510 2 * maxfiles * sizeof *tz_menu);
1511 if (p == NULL) 1511 if (p == NULL)
1512 break; 1512 break;
1513 tz_menu = p; 1513 tz_menu = p;
1514 memset(tz_menu + maxfiles, 0, 1514 memset(tz_menu + maxfiles, 0,
1515 maxfiles * sizeof *tz_menu); 1515 maxfiles * sizeof *tz_menu);
1516 p = realloc(tz_names, 1516 p = realloc(tz_names,
1517 2 * maxfiles * sizeof *tz_names); 1517 2 * maxfiles * sizeof *tz_names);
1518 if (p == NULL) 1518 if (p == NULL)
1519 break; 1519 break;
1520 tz_names = p; 1520 tz_names = p;
1521 memset(tz_names + maxfiles, 0, 1521 memset(tz_names + maxfiles, 0,
1522 maxfiles * sizeof *tz_names); 1522 maxfiles * sizeof *tz_names);
1523 maxfiles *= 2; 1523 maxfiles *= 2;
1524 } 1524 }
1525 if (S_ISREG(sb.st_mode)) 1525 if (S_ISREG(sb.st_mode))
1526 tz_menu[nfiles].opt_action = set_tz_select; 1526 tz_menu[nfiles].opt_action = set_tz_select;
1527 else if (S_ISDIR(sb.st_mode)) { 1527 else if (S_ISDIR(sb.st_mode)) {
1528 tz_menu[nfiles].opt_action = set_tz_dir; 1528 tz_menu[nfiles].opt_action = set_tz_dir;