1 1.78 kim /* $NetBSD: util.c,v 1.78 2025/08/05 14:52:43 kim Exp $ */ 2 1.1 dholland 3 1.1 dholland /* 4 1.1 dholland * Copyright 1997 Piermont Information Systems Inc. 5 1.1 dholland * All rights reserved. 6 1.1 dholland * 7 1.1 dholland * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 1.1 dholland * 9 1.1 dholland * Redistribution and use in source and binary forms, with or without 10 1.1 dholland * modification, are permitted provided that the following conditions 11 1.1 dholland * are met: 12 1.1 dholland * 1. Redistributions of source code must retain the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer. 14 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer in the 16 1.1 dholland * documentation and/or other materials provided with the distribution. 17 1.1 dholland * 3. The name of Piermont Information Systems Inc. may not be used to endorse 18 1.1 dholland * or promote products derived from this software without specific prior 19 1.1 dholland * written permission. 20 1.1 dholland * 21 1.1 dholland * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 22 1.1 dholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 25 1.1 dholland * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 1.1 dholland * THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 dholland * 33 1.1 dholland */ 34 1.1 dholland 35 1.1 dholland /* util.c -- routines that don't really fit anywhere else... */ 36 1.1 dholland 37 1.17 martin #include <assert.h> 38 1.17 martin #include <inttypes.h> 39 1.1 dholland #include <stdio.h> 40 1.1 dholland #include <stdarg.h> 41 1.1 dholland #include <string.h> 42 1.1 dholland #include <unistd.h> 43 1.1 dholland #include <sys/mount.h> 44 1.1 dholland #include <sys/dkio.h> 45 1.1 dholland #include <sys/ioctl.h> 46 1.1 dholland #include <sys/types.h> 47 1.1 dholland #include <sys/param.h> 48 1.1 dholland #include <sys/sysctl.h> 49 1.1 dholland #include <sys/stat.h> 50 1.1 dholland #include <sys/statvfs.h> 51 1.1 dholland #include <isofs/cd9660/iso.h> 52 1.1 dholland #include <curses.h> 53 1.1 dholland #include <err.h> 54 1.1 dholland #include <errno.h> 55 1.1 dholland #include <dirent.h> 56 1.1 dholland #include <util.h> 57 1.1 dholland #include "defs.h" 58 1.1 dholland #include "md.h" 59 1.22 martin #include "defsizes.h" 60 1.1 dholland #include "msg_defs.h" 61 1.1 dholland #include "menu_defs.h" 62 1.41 martin #ifdef MD_MAY_SWAP_TO 63 1.41 martin #include <sys/drvctlio.h> 64 1.41 martin #endif 65 1.54 martin #ifdef CHECK_ENTROPY 66 1.54 martin #include <sha2.h> 67 1.54 martin #include <paths.h> 68 1.54 martin #endif 69 1.1 dholland 70 1.1 dholland #define MAX_CD_DEVS 256 /* how many cd drives do we expect to attach */ 71 1.1 dholland #define ISO_BLKSIZE ISO_DEFAULT_BLOCK_SIZE 72 1.1 dholland 73 1.1 dholland static const char *msg_yes, *msg_no, *msg_all, *msg_some, *msg_none; 74 1.1 dholland static int select_menu_width; 75 1.1 dholland 76 1.11 christos static uint8_t set_status[SET_GROUP_END]; 77 1.1 dholland #define SET_VALID 0x01 78 1.1 dholland #define SET_SELECTED 0x02 79 1.1 dholland #define SET_SKIPPED 0x04 80 1.1 dholland #define SET_INSTALLED 0x08 81 1.41 martin #define SET_NO_EXTRACT 0x10 82 1.1 dholland 83 1.1 dholland struct tarstats { 84 1.1 dholland int nselected; 85 1.1 dholland int nfound; 86 1.1 dholland int nnotfound; 87 1.1 dholland int nerror; 88 1.1 dholland int nsuccess; 89 1.1 dholland int nskipped; 90 1.1 dholland } tarstats; 91 1.1 dholland 92 1.1 dholland distinfo dist_list[] = { 93 1.1 dholland #ifdef SET_KERNEL_1_NAME 94 1.12 martin {SET_KERNEL_1_NAME, SET_KERNEL_1, false, MSG_set_kernel_1, NULL}, 95 1.1 dholland #endif 96 1.1 dholland #ifdef SET_KERNEL_2_NAME 97 1.12 martin {SET_KERNEL_2_NAME, SET_KERNEL_2, false, MSG_set_kernel_2, NULL}, 98 1.1 dholland #endif 99 1.1 dholland #ifdef SET_KERNEL_3_NAME 100 1.12 martin {SET_KERNEL_3_NAME, SET_KERNEL_3, false, MSG_set_kernel_3, NULL}, 101 1.1 dholland #endif 102 1.1 dholland #ifdef SET_KERNEL_4_NAME 103 1.12 martin {SET_KERNEL_4_NAME, SET_KERNEL_4, false, MSG_set_kernel_4, NULL}, 104 1.1 dholland #endif 105 1.1 dholland #ifdef SET_KERNEL_5_NAME 106 1.12 martin {SET_KERNEL_5_NAME, SET_KERNEL_5, false, MSG_set_kernel_5, NULL}, 107 1.1 dholland #endif 108 1.1 dholland #ifdef SET_KERNEL_6_NAME 109 1.12 martin {SET_KERNEL_6_NAME, SET_KERNEL_6, false, MSG_set_kernel_6, NULL}, 110 1.1 dholland #endif 111 1.1 dholland #ifdef SET_KERNEL_7_NAME 112 1.12 martin {SET_KERNEL_7_NAME, SET_KERNEL_7, false, MSG_set_kernel_7, NULL}, 113 1.1 dholland #endif 114 1.1 dholland #ifdef SET_KERNEL_8_NAME 115 1.12 martin {SET_KERNEL_8_NAME, SET_KERNEL_8, false, MSG_set_kernel_8, NULL}, 116 1.1 dholland #endif 117 1.1 dholland #ifdef SET_KERNEL_9_NAME 118 1.12 martin {SET_KERNEL_9_NAME, SET_KERNEL_9, false, MSG_set_kernel_9, NULL}, 119 1.1 dholland #endif 120 1.1 dholland 121 1.53 martin #ifdef HAVE_MODULES 122 1.12 martin {"modules", SET_MODULES, false, MSG_set_modules, NULL}, 123 1.53 martin #endif 124 1.12 martin {"base", SET_BASE, false, MSG_set_base, NULL}, 125 1.75 nia #ifdef HAVE_BASE32 126 1.75 nia {"base32", SET_BASE32, false, MSG_set_base32, NULL}, 127 1.75 nia #endif 128 1.76 nia #ifdef HAVE_BASE64 129 1.76 nia {"base64", SET_BASE64, false, MSG_set_base64, NULL}, 130 1.76 nia #endif 131 1.45 jmcneill #ifdef HAVE_DTB 132 1.45 jmcneill {"dtb", SET_DTB, false, MSG_set_dtb, NULL}, 133 1.45 jmcneill #endif 134 1.12 martin {"etc", SET_ETC, false, MSG_set_system, NULL}, 135 1.12 martin {"comp", SET_COMPILER, false, MSG_set_compiler, NULL}, 136 1.12 martin {"games", SET_GAMES, false, MSG_set_games, NULL}, 137 1.60 maya {"gpufw", SET_GPUFW, false, MSG_set_gpufw, NULL}, 138 1.12 martin {"man", SET_MAN_PAGES, false, MSG_set_man_pages, NULL}, 139 1.75 nia {"manhtml", SET_MAN_PAGES_HTML, false, MSG_set_man_pages_html, NULL}, 140 1.12 martin {"misc", SET_MISC, false, MSG_set_misc, NULL}, 141 1.33 maya {"rescue", SET_RESCUE, false, MSG_set_rescue, NULL}, 142 1.12 martin {"tests", SET_TESTS, false, MSG_set_tests, NULL}, 143 1.12 martin {"text", SET_TEXT_TOOLS, false, MSG_set_text_tools, NULL}, 144 1.12 martin 145 1.12 martin {NULL, SET_GROUP, false, MSG_set_X11, NULL}, 146 1.12 martin {"xbase", SET_X11_BASE, false, MSG_set_X11_base, NULL}, 147 1.12 martin {"xcomp", SET_X11_PROG, false, MSG_set_X11_prog, NULL}, 148 1.12 martin {"xetc", SET_X11_ETC, false, MSG_set_X11_etc, NULL}, 149 1.12 martin {"xfont", SET_X11_FONTS, false, MSG_set_X11_fonts, NULL}, 150 1.12 martin {"xserver", SET_X11_SERVERS, false, MSG_set_X11_servers, NULL}, 151 1.12 martin {NULL, SET_GROUP_END, false, NULL, NULL}, 152 1.1 dholland 153 1.1 dholland #ifdef SET_MD_1_NAME 154 1.12 martin {SET_MD_1_NAME, SET_MD_1, false, MSG_set_md_1, NULL}, 155 1.1 dholland #endif 156 1.1 dholland #ifdef SET_MD_2_NAME 157 1.12 martin {SET_MD_2_NAME, SET_MD_2, false, MSG_set_md_2, NULL}, 158 1.1 dholland #endif 159 1.1 dholland #ifdef SET_MD_3_NAME 160 1.12 martin {SET_MD_3_NAME, SET_MD_3, false, MSG_set_md_3, NULL}, 161 1.1 dholland #endif 162 1.1 dholland #ifdef SET_MD_4_NAME 163 1.12 martin {SET_MD_4_NAME, SET_MD_4, false, MSG_set_md_4, NULL}, 164 1.1 dholland #endif 165 1.1 dholland 166 1.12 martin {NULL, SET_GROUP, true, MSG_set_source, NULL}, 167 1.12 martin {"syssrc", SET_SYSSRC, true, MSG_set_syssrc, NULL}, 168 1.12 martin {"src", SET_SRC, true, MSG_set_src, NULL}, 169 1.12 martin {"sharesrc", SET_SHARESRC, true, MSG_set_sharesrc, NULL}, 170 1.12 martin {"gnusrc", SET_GNUSRC, true, MSG_set_gnusrc, NULL}, 171 1.12 martin {"xsrc", SET_XSRC, true, MSG_set_xsrc, NULL}, 172 1.12 martin {"debug", SET_DEBUG, false, MSG_set_debug, NULL}, 173 1.75 nia #ifdef HAVE_DEBUG32 174 1.75 nia {"debug32", SET_DEBUG32, false, MSG_set_debug32, NULL}, 175 1.75 nia #endif 176 1.76 nia #ifdef HAVE_DEBUG64 177 1.76 nia {"debug64", SET_DEBUG64, false, MSG_set_debug64, NULL}, 178 1.76 nia #endif 179 1.12 martin {"xdebug", SET_X11_DEBUG, false, MSG_set_xdebug, NULL}, 180 1.12 martin {NULL, SET_GROUP_END, false, NULL, NULL}, 181 1.1 dholland 182 1.12 martin {NULL, SET_LAST, false, NULL, NULL}, 183 1.1 dholland }; 184 1.1 dholland 185 1.1 dholland #define MAX_CD_INFOS 16 /* how many media can be found? */ 186 1.1 dholland struct cd_info { 187 1.1 dholland char device_name[16]; 188 1.1 dholland char menu[100]; 189 1.1 dholland }; 190 1.1 dholland static struct cd_info cds[MAX_CD_INFOS]; 191 1.1 dholland 192 1.22 martin /* flags whether to offer the respective options (depending on helper 193 1.22 martin programs available on install media */ 194 1.22 martin int have_raid, have_vnd, have_cgd, have_lvm, have_gpt, have_dk; 195 1.22 martin 196 1.1 dholland /* 197 1.1 dholland * local prototypes 198 1.1 dholland */ 199 1.1 dholland 200 1.1 dholland static int check_for(unsigned int mode, const char *pathname); 201 1.34 mrg static int get_iso9660_volname(int dev, int sess, char *volname, 202 1.34 mrg size_t volnamelen); 203 1.1 dholland static int get_available_cds(void); 204 1.22 martin static int binary_available(const char *prog); 205 1.1 dholland 206 1.1 dholland void 207 1.1 dholland init_set_status(int flags) 208 1.1 dholland { 209 1.1 dholland static const uint8_t sets_valid[] = {MD_SETS_VALID}; 210 1.1 dholland static const uint8_t sets_selected_full[] = {MD_SETS_SELECTED}; 211 1.1 dholland static const uint8_t sets_selected_minimal[] = {MD_SETS_SELECTED_MINIMAL}; 212 1.1 dholland static const uint8_t sets_selected_nox[] = {MD_SETS_SELECTED_NOX}; 213 1.1 dholland static const uint8_t *sets_selected; 214 1.1 dholland unsigned int nelem_selected; 215 1.1 dholland unsigned int i, len; 216 1.1 dholland const char *longest; 217 1.1 dholland 218 1.1 dholland if (flags & SFLAG_MINIMAL) { 219 1.1 dholland sets_selected = sets_selected_minimal; 220 1.22 martin nelem_selected = __arraycount(sets_selected_minimal); 221 1.1 dholland } else if (flags & SFLAG_NOX) { 222 1.1 dholland sets_selected = sets_selected_nox; 223 1.22 martin nelem_selected = __arraycount(sets_selected_nox); 224 1.1 dholland } else { 225 1.1 dholland sets_selected = sets_selected_full; 226 1.22 martin nelem_selected = __arraycount(sets_selected_full); 227 1.1 dholland } 228 1.1 dholland 229 1.22 martin for (i = 0; i < __arraycount(sets_valid); i++) 230 1.1 dholland set_status[sets_valid[i]] = SET_VALID; 231 1.1 dholland for (i = 0; i < nelem_selected; i++) 232 1.1 dholland set_status[sets_selected[i]] |= SET_SELECTED; 233 1.1 dholland 234 1.1 dholland set_status[SET_GROUP] = SET_VALID; 235 1.1 dholland 236 1.1 dholland /* Lookup some strings we need lots of times */ 237 1.1 dholland msg_yes = msg_string(MSG_Yes); 238 1.1 dholland msg_no = msg_string(MSG_No); 239 1.1 dholland msg_all = msg_string(MSG_All); 240 1.1 dholland msg_some = msg_string(MSG_Some); 241 1.1 dholland msg_none = msg_string(MSG_None); 242 1.1 dholland 243 1.1 dholland /* Find longest and use it to determine width of selection menu */ 244 1.1 dholland len = strlen(msg_no); longest = msg_no; 245 1.1 dholland i = strlen(msg_yes); if (i > len) {len = i; longest = msg_yes; } 246 1.1 dholland i = strlen(msg_all); if (i > len) {len = i; longest = msg_all; } 247 1.1 dholland i = strlen(msg_some); if (i > len) {len = i; longest = msg_some; } 248 1.1 dholland i = strlen(msg_none); if (i > len) {len = i; longest = msg_none; } 249 1.77 hannken select_menu_width = snprintf(NULL, 0, "%-40s %s", "", longest); 250 1.1 dholland 251 1.1 dholland /* Give the md code a chance to choose the right kernel, etc. */ 252 1.1 dholland md_init_set_status(flags); 253 1.1 dholland } 254 1.1 dholland 255 1.1 dholland int 256 1.1 dholland dir_exists_p(const char *path) 257 1.1 dholland { 258 1.1 dholland 259 1.1 dholland return file_mode_match(path, S_IFDIR); 260 1.1 dholland } 261 1.1 dholland 262 1.1 dholland int 263 1.1 dholland file_exists_p(const char *path) 264 1.1 dholland { 265 1.1 dholland 266 1.1 dholland return file_mode_match(path, S_IFREG); 267 1.1 dholland } 268 1.1 dholland 269 1.1 dholland int 270 1.1 dholland file_mode_match(const char *path, unsigned int mode) 271 1.1 dholland { 272 1.1 dholland struct stat st; 273 1.1 dholland 274 1.1 dholland return (stat(path, &st) == 0 && (st.st_mode & S_IFMT) == mode); 275 1.1 dholland } 276 1.1 dholland 277 1.22 martin /* return ram size in MB */ 278 1.22 martin uint64_t 279 1.1 dholland get_ramsize(void) 280 1.1 dholland { 281 1.58 martin static uint64_t ramsize; 282 1.1 dholland 283 1.58 martin if (ramsize == 0) { 284 1.58 martin size_t len = sizeof ramsize; 285 1.58 martin int mib[2] = {CTL_HW, HW_PHYSMEM64}; 286 1.58 martin 287 1.58 martin sysctl(mib, 2, &ramsize, &len, NULL, 0); 288 1.58 martin } 289 1.1 dholland 290 1.1 dholland /* Find out how many Megs ... round up. */ 291 1.1 dholland return (ramsize + MEG - 1) / MEG; 292 1.1 dholland } 293 1.1 dholland 294 1.1 dholland void 295 1.1 dholland run_makedev(void) 296 1.1 dholland { 297 1.1 dholland char *owd; 298 1.1 dholland 299 1.1 dholland msg_display_add("\n\n"); 300 1.1 dholland msg_display_add(MSG_makedev); 301 1.1 dholland 302 1.1 dholland owd = getcwd(NULL, 0); 303 1.1 dholland 304 1.1 dholland /* make /dev, in case the user didn't extract it. */ 305 1.1 dholland make_target_dir("/dev"); 306 1.1 dholland target_chdir_or_die("/dev"); 307 1.1 dholland run_program(0, "/bin/sh MAKEDEV all"); 308 1.1 dholland 309 1.1 dholland chdir(owd); 310 1.1 dholland free(owd); 311 1.1 dholland } 312 1.1 dholland 313 1.1 dholland /* 314 1.1 dholland * Performs in-place replacement of a set of patterns in a file that lives 315 1.1 dholland * inside the installed system. The patterns must be separated by a semicolon. 316 1.1 dholland * For example: 317 1.1 dholland * 318 1.1 dholland * replace("/etc/some-file.conf", "s/prop1=NO/prop1=YES/;s/foo/bar/"); 319 1.1 dholland */ 320 1.1 dholland void 321 1.1 dholland replace(const char *path, const char *patterns, ...) 322 1.1 dholland { 323 1.1 dholland char *spatterns; 324 1.1 dholland va_list ap; 325 1.1 dholland 326 1.1 dholland va_start(ap, patterns); 327 1.1 dholland vasprintf(&spatterns, patterns, ap); 328 1.1 dholland va_end(ap); 329 1.1 dholland if (spatterns == NULL) 330 1.1 dholland err(1, "vasprintf(&spatterns, \"%s\", ...)", patterns); 331 1.1 dholland 332 1.1 dholland run_program(RUN_CHROOT, "sed -an -e '%s;H;$!d;g;w %s' %s", spatterns, 333 1.1 dholland path, path); 334 1.1 dholland 335 1.1 dholland free(spatterns); 336 1.1 dholland } 337 1.1 dholland 338 1.1 dholland static int 339 1.1 dholland floppy_fetch(const char *set_name) 340 1.1 dholland { 341 1.1 dholland char post[4]; 342 1.1 dholland msg errmsg; 343 1.1 dholland int menu; 344 1.1 dholland int status; 345 1.1 dholland const char *write_mode = ">"; 346 1.1 dholland 347 1.1 dholland strcpy(post, "aa"); 348 1.1 dholland 349 1.1 dholland errmsg = ""; 350 1.1 dholland menu = MENU_fdok; 351 1.1 dholland for (;;) { 352 1.1 dholland umount_mnt2(); 353 1.1 dholland msg_display(errmsg); 354 1.24 christos msg_fmt_display_add(MSG_fdmount, "%s%s", set_name, post); 355 1.1 dholland process_menu(menu, &status); 356 1.1 dholland if (status != SET_CONTINUE) 357 1.1 dholland return status; 358 1.1 dholland menu = MENU_fdremount; 359 1.1 dholland errmsg = MSG_fdremount; 360 1.1 dholland if (run_program(0, "/sbin/mount -r -t %s %s /mnt2", 361 1.1 dholland fd_type, fd_dev)) 362 1.1 dholland continue; 363 1.1 dholland mnt2_mounted = 1; 364 1.1 dholland errmsg = MSG_fdnotfound; 365 1.1 dholland 366 1.1 dholland /* Display this because it might take a while.... */ 367 1.1 dholland if (run_program(RUN_DISPLAY, 368 1.1 dholland "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'", 369 1.1 dholland set_name, post, write_mode, 370 1.12 martin target_prefix(), xfer_dir, set_name, 371 1.12 martin set_postfix(set_name))) 372 1.1 dholland /* XXX: a read error will give a corrupt file! */ 373 1.1 dholland continue; 374 1.1 dholland 375 1.1 dholland /* We got that file, advance to next fragment */ 376 1.1 dholland if (post[1] < 'z') 377 1.1 dholland post[1]++; 378 1.1 dholland else 379 1.1 dholland post[1] = 'a', post[0]++; 380 1.1 dholland write_mode = ">>"; 381 1.1 dholland errmsg = ""; 382 1.1 dholland menu = MENU_fdok; 383 1.1 dholland } 384 1.1 dholland } 385 1.1 dholland 386 1.1 dholland /* 387 1.1 dholland * Load files from floppy. Requires a /mnt2 directory for mounting them. 388 1.1 dholland */ 389 1.1 dholland int 390 1.1 dholland get_via_floppy(void) 391 1.1 dholland { 392 1.6 martin int rv = -1; 393 1.6 martin 394 1.6 martin process_menu(MENU_floppysource, &rv); 395 1.6 martin if (rv == SET_RETRY) 396 1.2 martin return SET_RETRY; 397 1.1 dholland 398 1.1 dholland fetch_fn = floppy_fetch; 399 1.1 dholland 400 1.1 dholland /* Set ext_dir for absolute path. */ 401 1.1 dholland snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", target_prefix(), xfer_dir); 402 1.1 dholland snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", target_prefix(), xfer_dir); 403 1.1 dholland 404 1.1 dholland return SET_OK; 405 1.1 dholland } 406 1.1 dholland 407 1.1 dholland /* 408 1.1 dholland * Get the volume name of a ISO9660 file system 409 1.1 dholland */ 410 1.1 dholland static int 411 1.34 mrg get_iso9660_volname(int dev, int sess, char *volname, size_t volnamelen) 412 1.1 dholland { 413 1.1 dholland int blkno, error, last; 414 1.74 martin static char buf[ISO_BLKSIZE] __aligned(8); 415 1.1 dholland struct iso_volume_descriptor *vd = NULL; 416 1.1 dholland struct iso_primary_descriptor *pd = NULL; 417 1.1 dholland 418 1.1 dholland for (blkno = sess+16; blkno < sess+16+100; blkno++) { 419 1.1 dholland error = pread(dev, buf, ISO_BLKSIZE, blkno*ISO_BLKSIZE); 420 1.1 dholland if (error == -1) 421 1.1 dholland return -1; 422 1.1 dholland vd = (struct iso_volume_descriptor *)&buf; 423 1.1 dholland if (memcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0) 424 1.1 dholland return -1; 425 1.1 dholland if (isonum_711((const unsigned char *)&vd->type) 426 1.1 dholland == ISO_VD_PRIMARY) { 427 1.1 dholland pd = (struct iso_primary_descriptor*)buf; 428 1.34 mrg strncpy(volname, pd->volume_id, volnamelen - 1); 429 1.34 mrg volname[volnamelen - 1] = '\0'; 430 1.34 mrg last = volnamelen - 1; 431 1.1 dholland while (last >= 0 432 1.1 dholland && (volname[last] == ' ' || volname[last] == 0)) 433 1.1 dholland last--; 434 1.1 dholland volname[last+1] = 0; 435 1.1 dholland return 0; 436 1.1 dholland } 437 1.1 dholland } 438 1.1 dholland return -1; 439 1.1 dholland } 440 1.1 dholland 441 1.1 dholland /* 442 1.15 martin * Local state while iterating CDs and collecting volumes 443 1.15 martin */ 444 1.15 martin struct get_available_cds_state { 445 1.49 martin size_t num_mounted; 446 1.49 martin struct statvfs *mounted; 447 1.15 martin struct cd_info *info; 448 1.15 martin size_t count; 449 1.15 martin }; 450 1.15 martin 451 1.15 martin /* 452 1.15 martin * Callback function: if this is a CD, enumerate all volumes on it 453 1.1 dholland */ 454 1.15 martin static bool 455 1.15 martin get_available_cds_helper(void *arg, const char *device) 456 1.1 dholland { 457 1.15 martin struct get_available_cds_state *state = arg; 458 1.49 martin char dname[16], tname[16], volname[80], *t; 459 1.1 dholland struct disklabel label; 460 1.49 martin int part, dev, error, sess, ready, tlen; 461 1.15 martin 462 1.16 martin if (!is_cdrom_device(device, false)) 463 1.15 martin return true; 464 1.15 martin 465 1.15 martin sprintf(dname, "/dev/r%s%c", device, 'a'+RAW_PART); 466 1.49 martin tlen = sprintf(tname, "/dev/%s", device); 467 1.49 martin 468 1.49 martin /* check if this is mounted already */ 469 1.49 martin for (size_t i = 0; i < state->num_mounted; i++) { 470 1.49 martin if (strncmp(state->mounted[i].f_mntfromname, tname, tlen) 471 1.49 martin == 0) { 472 1.49 martin t = state->mounted[i].f_mntfromname + tlen; 473 1.49 martin if (t[0] >= 'a' && t[0] <= 'z' && t[1] == 0) 474 1.49 martin return true; 475 1.49 martin } 476 1.49 martin } 477 1.49 martin 478 1.15 martin dev = open(dname, O_RDONLY, 0); 479 1.15 martin if (dev == -1) 480 1.15 martin return true; 481 1.15 martin 482 1.15 martin ready = 0; 483 1.15 martin error = ioctl(dev, DIOCTUR, &ready); 484 1.15 martin if (error != 0 || ready == 0) { 485 1.15 martin close(dev); 486 1.15 martin return true; 487 1.15 martin } 488 1.15 martin error = ioctl(dev, DIOCGDINFO, &label); 489 1.15 martin close(dev); 490 1.15 martin if (error != 0) 491 1.15 martin return true; 492 1.1 dholland 493 1.15 martin for (part = 0; part < label.d_npartitions; part++) { 494 1.15 martin 495 1.15 martin if (label.d_partitions[part].p_fstype == FS_UNUSED 496 1.15 martin || label.d_partitions[part].p_size == 0) 497 1.15 martin continue; 498 1.15 martin 499 1.15 martin if (label.d_partitions[part].p_fstype == FS_ISO9660) { 500 1.15 martin sess = label.d_partitions[part].p_cdsession; 501 1.15 martin sprintf(dname, "/dev/r%s%c", device, 'a'+part); 502 1.14 martin dev = open(dname, O_RDONLY, 0); 503 1.14 martin if (dev == -1) 504 1.14 martin continue; 505 1.34 mrg error = get_iso9660_volname(dev, sess, volname, 506 1.34 mrg sizeof volname); 507 1.15 martin close(dev); 508 1.15 martin if (error) 509 1.15 martin continue; 510 1.15 martin sprintf(state->info->device_name, 511 1.15 martin "%s%c", device, 'a'+part); 512 1.15 martin sprintf(state->info->menu, "%s (%s)", 513 1.15 martin state->info->device_name, volname); 514 1.15 martin } else { 515 1.15 martin /* 516 1.15 martin * All install CDs use partition 517 1.15 martin * a for the sets. 518 1.15 martin */ 519 1.15 martin if (part > 0) 520 1.14 martin continue; 521 1.15 martin sprintf(state->info->device_name, 522 1.15 martin "%s%c", device, 'a'+part); 523 1.15 martin strcpy(state->info->menu, state->info->device_name); 524 1.1 dholland } 525 1.15 martin state->info++; 526 1.15 martin if (++state->count >= MAX_CD_INFOS) 527 1.15 martin return false; 528 1.1 dholland } 529 1.15 martin 530 1.15 martin return true; 531 1.15 martin } 532 1.15 martin 533 1.15 martin /* 534 1.15 martin * Get a list of all available CD media (not drives!), return 535 1.15 martin * the number of entries collected. 536 1.15 martin */ 537 1.15 martin static int 538 1.15 martin get_available_cds(void) 539 1.15 martin { 540 1.15 martin struct get_available_cds_state data; 541 1.51 martin int n, m; 542 1.15 martin 543 1.49 martin memset(&data, 0, sizeof data); 544 1.15 martin data.info = cds; 545 1.49 martin 546 1.49 martin n = getvfsstat(NULL, 0, ST_NOWAIT); 547 1.49 martin if (n > 0) { 548 1.49 martin data.mounted = calloc(n, sizeof(*data.mounted)); 549 1.51 martin m = getvfsstat(data.mounted, n*sizeof(*data.mounted), 550 1.49 martin ST_NOWAIT); 551 1.51 martin assert(m >= 0 && m <= n); 552 1.51 martin data.num_mounted = m; 553 1.49 martin } 554 1.15 martin 555 1.15 martin enumerate_disks(&data, get_available_cds_helper); 556 1.15 martin 557 1.49 martin free(data.mounted); 558 1.49 martin 559 1.15 martin return data.count; 560 1.1 dholland } 561 1.1 dholland 562 1.1 dholland static int 563 1.1 dholland cd_has_sets(void) 564 1.1 dholland { 565 1.52 martin 566 1.52 martin /* sanity check */ 567 1.52 martin if (cdrom_dev[0] == 0) 568 1.52 martin return 0; 569 1.52 martin 570 1.1 dholland /* Mount it */ 571 1.1 dholland if (run_program(RUN_SILENT, "/sbin/mount -rt cd9660 /dev/%s /mnt2", 572 1.1 dholland cdrom_dev) != 0) 573 1.1 dholland return 0; 574 1.1 dholland 575 1.1 dholland mnt2_mounted = 1; 576 1.1 dholland 577 1.1 dholland snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", "/mnt2", set_dir_bin); 578 1.1 dholland snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", "/mnt2", set_dir_src); 579 1.1 dholland return dir_exists_p(ext_dir_bin); 580 1.1 dholland } 581 1.1 dholland 582 1.1 dholland /* 583 1.1 dholland * Check whether we can remove the boot media. 584 1.1 dholland * If it is not a local filesystem, return -1. 585 1.1 dholland * If we can not decide for sure (can not tell MD content from plain ffs 586 1.1 dholland * on hard disk, for example), return 0. 587 1.1 dholland * If it is a CD/DVD, return 1. 588 1.1 dholland */ 589 1.1 dholland int 590 1.1 dholland boot_media_still_needed(void) 591 1.1 dholland { 592 1.1 dholland struct statvfs sb; 593 1.1 dholland 594 1.1 dholland if (statvfs("/", &sb) == 0) { 595 1.1 dholland if (!(sb.f_flag & ST_LOCAL)) 596 1.1 dholland return -1; 597 1.1 dholland if (strcmp(sb.f_fstypename, MOUNT_CD9660) == 0 598 1.1 dholland || strcmp(sb.f_fstypename, MOUNT_UDF) == 0) 599 1.1 dholland return 1; 600 1.1 dholland } 601 1.1 dholland 602 1.1 dholland return 0; 603 1.1 dholland } 604 1.1 dholland 605 1.32 martin bool 606 1.32 martin root_is_read_only(void) 607 1.32 martin { 608 1.32 martin struct statvfs sb; 609 1.32 martin 610 1.32 martin if (statvfs("/", &sb) == 0) 611 1.32 martin return sb.f_flag & ST_RDONLY; 612 1.32 martin 613 1.32 martin return false; 614 1.32 martin } 615 1.32 martin 616 1.1 dholland /* 617 1.1 dholland * Get from a CDROM distribution. 618 1.1 dholland * Also used on "installation using bootable install media" 619 1.1 dholland * as the default option in the "distmedium" menu. 620 1.1 dholland */ 621 1.1 dholland int 622 1.1 dholland get_via_cdrom(void) 623 1.1 dholland { 624 1.1 dholland menu_ent cd_menu[MAX_CD_INFOS]; 625 1.1 dholland struct stat sb; 626 1.6 martin int rv, num_cds, menu_cd, i, selected_cd = 0; 627 1.1 dholland int mib[2]; 628 1.1 dholland char rootdev[SSTRSIZE] = ""; 629 1.1 dholland size_t varlen; 630 1.1 dholland 631 1.1 dholland /* If root is not md(4) and we have set dir, skip this step. */ 632 1.1 dholland mib[0] = CTL_KERN; 633 1.1 dholland mib[1] = KERN_ROOT_DEVICE; 634 1.1 dholland varlen = sizeof(rootdev); 635 1.1 dholland (void)sysctl(mib, 2, rootdev, &varlen, NULL, 0); 636 1.1 dholland if (stat(set_dir_bin, &sb) == 0 && S_ISDIR(sb.st_mode) && 637 1.1 dholland strncmp("md", rootdev, 2) != 0) { 638 1.1 dholland strlcpy(ext_dir_bin, set_dir_bin, sizeof ext_dir_bin); 639 1.1 dholland strlcpy(ext_dir_src, set_dir_src, sizeof ext_dir_src); 640 1.1 dholland return SET_OK; 641 1.1 dholland } 642 1.1 dholland 643 1.25 christos memset(cd_menu, 0, sizeof(cd_menu)); 644 1.1 dholland num_cds = get_available_cds(); 645 1.1 dholland if (num_cds <= 0) { 646 1.52 martin msg_display(MSG_No_cd_found); 647 1.52 martin cdrom_dev[0] = 0; 648 1.1 dholland } else if (num_cds == 1) { 649 1.1 dholland /* single CD found, check for sets on it */ 650 1.1 dholland strcpy(cdrom_dev, cds[0].device_name); 651 1.1 dholland if (cd_has_sets()) 652 1.1 dholland return SET_OK; 653 1.1 dholland } else { 654 1.1 dholland for (i = 0; i< num_cds; i++) { 655 1.1 dholland cd_menu[i].opt_name = cds[i].menu; 656 1.1 dholland cd_menu[i].opt_flags = OPT_EXIT; 657 1.2 martin cd_menu[i].opt_action = set_menu_select; 658 1.1 dholland } 659 1.1 dholland /* create a menu offering available choices */ 660 1.1 dholland menu_cd = new_menu(MSG_Available_cds, 661 1.1 dholland cd_menu, num_cds, -1, 4, 0, 0, 662 1.1 dholland MC_SCROLL | MC_NOEXITOPT, 663 1.1 dholland NULL, NULL, NULL, NULL, NULL); 664 1.1 dholland if (menu_cd == -1) 665 1.1 dholland return SET_RETRY; 666 1.1 dholland msg_display(MSG_ask_cd); 667 1.1 dholland process_menu(menu_cd, &selected_cd); 668 1.1 dholland free_menu(menu_cd); 669 1.1 dholland strcpy(cdrom_dev, cds[selected_cd].device_name); 670 1.1 dholland if (cd_has_sets()) 671 1.1 dholland return SET_OK; 672 1.1 dholland } 673 1.1 dholland 674 1.52 martin if (num_cds >= 1 && mnt2_mounted) { 675 1.1 dholland umount_mnt2(); 676 1.22 martin hit_enter_to_continue(MSG_cd_path_not_found, NULL); 677 1.1 dholland } 678 1.1 dholland 679 1.1 dholland /* ask for paths on the CD */ 680 1.6 martin rv = -1; 681 1.6 martin process_menu(MENU_cdromsource, &rv); 682 1.52 martin if (rv == SET_RETRY || rv == SET_ABANDON) 683 1.52 martin return rv; 684 1.1 dholland 685 1.1 dholland if (cd_has_sets()) 686 1.1 dholland return SET_OK; 687 1.1 dholland 688 1.1 dholland return SET_RETRY; 689 1.1 dholland } 690 1.1 dholland 691 1.1 dholland 692 1.1 dholland /* 693 1.1 dholland * Get from a pathname inside an unmounted local filesystem 694 1.1 dholland * (e.g., where sets were preloaded onto a local DOS partition) 695 1.1 dholland */ 696 1.1 dholland int 697 1.1 dholland get_via_localfs(void) 698 1.1 dholland { 699 1.6 martin int rv = -1; 700 1.6 martin 701 1.1 dholland /* Get device, filesystem, and filepath */ 702 1.6 martin process_menu (MENU_localfssource, &rv); 703 1.6 martin if (rv == SET_RETRY) 704 1.2 martin return SET_RETRY; 705 1.1 dholland 706 1.1 dholland /* Mount it */ 707 1.1 dholland if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2", 708 1.1 dholland localfs_fs, localfs_dev)) 709 1.1 dholland return SET_RETRY; 710 1.1 dholland 711 1.1 dholland mnt2_mounted = 1; 712 1.1 dholland 713 1.1 dholland snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s/%s", 714 1.1 dholland "/mnt2", localfs_dir, set_dir_bin); 715 1.1 dholland snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s/%s", 716 1.1 dholland "/mnt2", localfs_dir, set_dir_src); 717 1.1 dholland 718 1.1 dholland return SET_OK; 719 1.1 dholland } 720 1.1 dholland 721 1.1 dholland /* 722 1.1 dholland * Get from an already-mounted pathname. 723 1.1 dholland */ 724 1.1 dholland 725 1.1 dholland int 726 1.1 dholland get_via_localdir(void) 727 1.1 dholland { 728 1.6 martin int rv = -1; 729 1.6 martin 730 1.1 dholland /* Get filepath */ 731 1.6 martin process_menu(MENU_localdirsource, &rv); 732 1.6 martin if (rv == SET_RETRY) 733 1.2 martin return SET_RETRY; 734 1.1 dholland 735 1.1 dholland /* 736 1.1 dholland * We have to have an absolute path ('cos pax runs in a 737 1.1 dholland * different directory), make it so. 738 1.1 dholland */ 739 1.1 dholland snprintf(ext_dir_bin, sizeof ext_dir_bin, "/%s/%s", localfs_dir, set_dir_bin); 740 1.1 dholland snprintf(ext_dir_src, sizeof ext_dir_src, "/%s/%s", localfs_dir, set_dir_src); 741 1.1 dholland 742 1.1 dholland return SET_OK; 743 1.1 dholland } 744 1.1 dholland 745 1.1 dholland 746 1.1 dholland /* 747 1.1 dholland * Support for custom distribution fetches / unpacks. 748 1.1 dholland */ 749 1.1 dholland 750 1.1 dholland unsigned int 751 1.1 dholland set_X11_selected(void) 752 1.1 dholland { 753 1.1 dholland int i; 754 1.1 dholland 755 1.1 dholland for (i = SET_X11_FIRST; ++i < SET_X11_LAST;) 756 1.1 dholland if (set_status[i] & SET_SELECTED) 757 1.1 dholland return 1; 758 1.1 dholland return 0; 759 1.1 dholland } 760 1.1 dholland 761 1.1 dholland unsigned int 762 1.1 dholland get_kernel_set(void) 763 1.1 dholland { 764 1.1 dholland int i; 765 1.1 dholland 766 1.1 dholland for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;) 767 1.1 dholland if (set_status[i] & SET_SELECTED) 768 1.1 dholland return i; 769 1.1 dholland return SET_NONE; 770 1.1 dholland } 771 1.1 dholland 772 1.1 dholland void 773 1.1 dholland set_kernel_set(unsigned int kernel_set) 774 1.1 dholland { 775 1.1 dholland int i; 776 1.1 dholland 777 1.1 dholland /* only one kernel set is allowed */ 778 1.1 dholland for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;) 779 1.1 dholland set_status[i] &= ~SET_SELECTED; 780 1.1 dholland set_status[kernel_set] |= SET_SELECTED; 781 1.1 dholland } 782 1.1 dholland 783 1.41 martin void 784 1.41 martin set_noextract_set(unsigned int set) 785 1.41 martin { 786 1.41 martin 787 1.41 martin set_status[set] |= SET_NO_EXTRACT; 788 1.41 martin } 789 1.41 martin 790 1.1 dholland static int 791 1.1 dholland set_toggle(menudesc *menu, void *arg) 792 1.1 dholland { 793 1.1 dholland distinfo **distp = arg; 794 1.1 dholland int set = distp[menu->cursel]->set; 795 1.1 dholland 796 1.1 dholland if (set > SET_KERNEL_FIRST && set < SET_KERNEL_LAST && 797 1.1 dholland !(set_status[set] & SET_SELECTED)) 798 1.1 dholland set_kernel_set(set); 799 1.1 dholland else 800 1.1 dholland set_status[set] ^= SET_SELECTED; 801 1.1 dholland return 0; 802 1.1 dholland } 803 1.1 dholland 804 1.1 dholland static int 805 1.1 dholland set_all_none(menudesc *menu, void *arg, int set, int clr) 806 1.1 dholland { 807 1.1 dholland distinfo **distp = arg; 808 1.1 dholland distinfo *dist = *distp; 809 1.1 dholland int nested; 810 1.1 dholland 811 1.1 dholland for (nested = 0; dist->set != SET_GROUP_END || nested--; dist++) { 812 1.1 dholland if (dist->set == SET_GROUP) { 813 1.1 dholland nested++; 814 1.1 dholland continue; 815 1.1 dholland } 816 1.1 dholland set_status[dist->set] = (set_status[dist->set] & ~clr) | set; 817 1.1 dholland } 818 1.1 dholland return 0; 819 1.1 dholland } 820 1.1 dholland 821 1.1 dholland static int 822 1.1 dholland set_all(menudesc *menu, void *arg) 823 1.1 dholland { 824 1.1 dholland return set_all_none(menu, arg, SET_SELECTED, 0); 825 1.1 dholland } 826 1.1 dholland 827 1.1 dholland static int 828 1.1 dholland set_none(menudesc *menu, void *arg) 829 1.1 dholland { 830 1.1 dholland return set_all_none(menu, arg, 0, SET_SELECTED); 831 1.1 dholland } 832 1.1 dholland 833 1.1 dholland static void 834 1.1 dholland set_label(menudesc *menu, int opt, void *arg) 835 1.1 dholland { 836 1.1 dholland distinfo **distp = arg; 837 1.1 dholland distinfo *dist = distp[opt]; 838 1.1 dholland const char *selected; 839 1.1 dholland const char *desc; 840 1.1 dholland int nested; 841 1.1 dholland 842 1.1 dholland desc = dist->desc; 843 1.1 dholland 844 1.1 dholland if (dist->set != SET_GROUP) 845 1.1 dholland selected = set_status[dist->set] & SET_SELECTED ? msg_yes : msg_no; 846 1.1 dholland else { 847 1.1 dholland /* sub menu - display None/Some/All */ 848 1.1 dholland nested = 0; 849 1.1 dholland selected = "unknown"; 850 1.1 dholland while ((++dist)->set != SET_GROUP_END || nested--) { 851 1.1 dholland if (dist->set == SET_GROUP) { 852 1.1 dholland nested++; 853 1.1 dholland continue; 854 1.1 dholland } 855 1.1 dholland if (!(set_status[dist->set] & SET_VALID)) 856 1.1 dholland continue; 857 1.1 dholland if (set_status[dist->set] & SET_SELECTED) { 858 1.1 dholland if (selected == msg_none) { 859 1.1 dholland selected = msg_some; 860 1.1 dholland break; 861 1.1 dholland } 862 1.1 dholland selected = msg_all; 863 1.1 dholland } else { 864 1.1 dholland if (selected == msg_all) { 865 1.1 dholland selected = msg_some; 866 1.1 dholland break; 867 1.1 dholland } 868 1.1 dholland selected = msg_none; 869 1.1 dholland } 870 1.1 dholland } 871 1.1 dholland } 872 1.1 dholland 873 1.77 hannken wprintw(menu->mw, "%-40s %s", msg_string(desc), selected); 874 1.1 dholland } 875 1.1 dholland 876 1.1 dholland static int set_sublist(menudesc *menu, void *arg); 877 1.1 dholland 878 1.1 dholland static int 879 1.1 dholland initialise_set_menu(distinfo *dist, menu_ent *me, distinfo **de, int all_none) 880 1.1 dholland { 881 1.1 dholland int set; 882 1.1 dholland int sets; 883 1.1 dholland int nested; 884 1.1 dholland 885 1.1 dholland for (sets = 0; ; dist++) { 886 1.1 dholland set = dist->set; 887 1.1 dholland if (set == SET_LAST || set == SET_GROUP_END) 888 1.1 dholland break; 889 1.1 dholland if (!(set_status[set] & SET_VALID)) 890 1.1 dholland continue; 891 1.1 dholland *de = dist; 892 1.25 christos memset(me, 0, sizeof(*me)); 893 1.1 dholland if (set != SET_GROUP) 894 1.1 dholland me->opt_action = set_toggle; 895 1.1 dholland else { 896 1.1 dholland /* Collapse sublist */ 897 1.1 dholland nested = 0; 898 1.1 dholland while ((++dist)->set != SET_GROUP_END || nested--) { 899 1.1 dholland if (dist->set == SET_GROUP) 900 1.1 dholland nested++; 901 1.1 dholland } 902 1.1 dholland me->opt_action = set_sublist; 903 1.1 dholland } 904 1.1 dholland sets++; 905 1.1 dholland de++; 906 1.1 dholland me++; 907 1.1 dholland } 908 1.1 dholland 909 1.1 dholland if (all_none) { 910 1.1 dholland me->opt_name = MSG_select_all; 911 1.1 dholland me->opt_action = set_all; 912 1.1 dholland me++; 913 1.1 dholland me->opt_name = MSG_select_none; 914 1.1 dholland me->opt_action = set_none; 915 1.1 dholland sets += 2; 916 1.1 dholland } 917 1.1 dholland 918 1.1 dholland return sets; 919 1.1 dholland } 920 1.1 dholland 921 1.1 dholland static int 922 1.1 dholland set_sublist(menudesc *menu, void *arg) 923 1.1 dholland { 924 1.1 dholland distinfo *de[SET_LAST]; 925 1.1 dholland menu_ent me[SET_LAST]; 926 1.1 dholland distinfo **dist = arg; 927 1.1 dholland int menu_no; 928 1.1 dholland int sets; 929 1.1 dholland 930 1.25 christos memset(me, 0, sizeof(me)); 931 1.1 dholland sets = initialise_set_menu(dist[menu->cursel] + 1, me, de, 1); 932 1.1 dholland 933 1.1 dholland menu_no = new_menu(NULL, me, sets, 20, 10, 0, select_menu_width, 934 1.1 dholland MC_SUBMENU | MC_SCROLL | MC_DFLTEXIT, 935 1.1 dholland NULL, set_label, NULL, NULL, 936 1.1 dholland MSG_install_selected_sets); 937 1.1 dholland 938 1.1 dholland process_menu(menu_no, de); 939 1.1 dholland free_menu(menu_no); 940 1.1 dholland 941 1.1 dholland return 0; 942 1.1 dholland } 943 1.1 dholland 944 1.1 dholland void 945 1.1 dholland customise_sets(void) 946 1.1 dholland { 947 1.1 dholland distinfo *de[SET_LAST]; 948 1.1 dholland menu_ent me[SET_LAST]; 949 1.1 dholland int sets; 950 1.1 dholland int menu_no; 951 1.1 dholland 952 1.1 dholland msg_display(MSG_cur_distsets); 953 1.1 dholland msg_table_add(MSG_cur_distsets_header); 954 1.1 dholland 955 1.25 christos memset(me, 0, sizeof(me)); 956 1.1 dholland sets = initialise_set_menu(dist_list, me, de, 0); 957 1.1 dholland 958 1.1 dholland menu_no = new_menu(NULL, me, sets, 0, 5, 0, select_menu_width, 959 1.1 dholland MC_SCROLL | MC_NOBOX | MC_DFLTEXIT | MC_NOCLEAR, 960 1.1 dholland NULL, set_label, NULL, NULL, 961 1.1 dholland MSG_install_selected_sets); 962 1.1 dholland 963 1.1 dholland process_menu(menu_no, de); 964 1.1 dholland free_menu(menu_no); 965 1.1 dholland } 966 1.1 dholland 967 1.1 dholland /* 968 1.1 dholland * Extract_file **REQUIRES** an absolute path in ext_dir. Any code 969 1.1 dholland * that sets up xfer_dir for use by extract_file needs to put in the 970 1.1 dholland * full path name to the directory. 971 1.1 dholland */ 972 1.1 dholland 973 1.1 dholland int 974 1.1 dholland extract_file(distinfo *dist, int update) 975 1.1 dholland { 976 1.41 martin const char *dest_dir = NULL; 977 1.41 martin 978 1.41 martin if (update && (dist->set == SET_ETC || dist->set == SET_X11_ETC)) { 979 1.41 martin dest_dir = "/.sysinst"; 980 1.41 martin make_target_dir(dest_dir); 981 1.41 martin } else if (dist->set == SET_PKGSRC) 982 1.41 martin dest_dir = "/usr"; 983 1.41 martin else 984 1.41 martin dest_dir = "/"; 985 1.41 martin 986 1.41 martin return extract_file_to(dist, update, dest_dir, NULL, true); 987 1.41 martin } 988 1.41 martin 989 1.41 martin int 990 1.41 martin extract_file_to(distinfo *dist, int update, const char *dest_dir, 991 1.41 martin const char *extr_pattern, bool do_stats) 992 1.41 martin { 993 1.1 dholland char path[STRSIZE]; 994 1.1 dholland char *owd; 995 1.1 dholland int rval; 996 1.1 dholland 997 1.1 dholland /* If we might need to tidy up, ensure directory exists */ 998 1.1 dholland if (fetch_fn != NULL) 999 1.1 dholland make_target_dir(xfer_dir); 1000 1.1 dholland 1001 1.1 dholland (void)snprintf(path, sizeof path, "%s/%s%s", 1002 1.12 martin ext_dir_for_set(dist->name), dist->name, set_postfix(dist->name)); 1003 1.1 dholland 1004 1.1 dholland owd = getcwd(NULL, 0); 1005 1.1 dholland 1006 1.1 dholland /* Do we need to fetch the file now? */ 1007 1.1 dholland if (fetch_fn != NULL) { 1008 1.1 dholland rval = fetch_fn(dist->name); 1009 1.1 dholland if (rval != SET_OK) 1010 1.1 dholland return rval; 1011 1.1 dholland } 1012 1.1 dholland 1013 1.1 dholland /* check tarfile exists */ 1014 1.1 dholland if (!file_exists_p(path)) { 1015 1.1 dholland 1016 1.1 dholland #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM 1017 1.30 martin /* 1018 1.30 martin * Update path to use dist->name truncated to the first eight 1019 1.30 martin * characters and check again 1020 1.30 martin */ 1021 1.30 martin (void)snprintf(path, sizeof path, 1022 1.30 martin "%s/%.8s%.4s", /* 4 as includes '.' */ 1023 1.30 martin ext_dir_for_set(dist->name), dist->name, 1024 1.30 martin set_postfix(dist->name)); 1025 1.30 martin 1026 1.1 dholland if (!file_exists_p(path)) { 1027 1.1 dholland #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */ 1028 1.41 martin if (do_stats) 1029 1.41 martin tarstats.nnotfound++; 1030 1.1 dholland 1031 1.30 martin char *err = str_arg_subst(msg_string(MSG_notarfile), 1032 1.30 martin 1, &dist->name); 1033 1.30 martin hit_enter_to_continue(err, NULL); 1034 1.30 martin free(err); 1035 1.31 martin free(owd); 1036 1.30 martin return SET_RETRY; 1037 1.30 martin } 1038 1.1 dholland #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM 1039 1.1 dholland } 1040 1.1 dholland #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */ 1041 1.1 dholland 1042 1.41 martin if (do_stats) 1043 1.41 martin tarstats.nfound++; 1044 1.1 dholland /* cd to the target root. */ 1045 1.41 martin target_chdir_or_die(dest_dir); 1046 1.1 dholland 1047 1.1 dholland /* 1048 1.1 dholland * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0 1049 1.1 dholland * but is a file in 5.1 and beyond, so on upgrades we need to 1050 1.1 dholland * delete it before extracting the xbase set. 1051 1.1 dholland */ 1052 1.1 dholland if (update && dist->set == SET_X11_BASE) 1053 1.1 dholland run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc"); 1054 1.1 dholland 1055 1.1 dholland /* now extract set files into "./". */ 1056 1.41 martin if (extr_pattern != NULL) { 1057 1.41 martin rval = run_program(RUN_DISPLAY | RUN_PROGRESS, 1058 1.41 martin "progress -zf %s tar --chroot " 1059 1.41 martin TAR_EXTRACT_FLAGS " - '%s'", 1060 1.41 martin path, extr_pattern); 1061 1.41 martin } else { 1062 1.41 martin rval = run_program(RUN_DISPLAY | RUN_PROGRESS, 1063 1.41 martin "progress -zf %s tar --chroot " 1064 1.41 martin TAR_EXTRACT_FLAGS " -", path); 1065 1.41 martin } 1066 1.1 dholland 1067 1.1 dholland chdir(owd); 1068 1.1 dholland free(owd); 1069 1.1 dholland 1070 1.1 dholland /* Check rval for errors and give warning. */ 1071 1.1 dholland if (rval != 0) { 1072 1.41 martin if (do_stats) 1073 1.41 martin tarstats.nerror++; 1074 1.24 christos msg_fmt_display(MSG_tarerror, "%s", path); 1075 1.22 martin hit_enter_to_continue(NULL, NULL); 1076 1.1 dholland return SET_RETRY; 1077 1.1 dholland } 1078 1.1 dholland 1079 1.1 dholland if (fetch_fn != NULL && clean_xfer_dir) { 1080 1.1 dholland run_program(0, "rm %s", path); 1081 1.1 dholland /* Plausibly we should unlink an empty xfer_dir as well */ 1082 1.1 dholland } 1083 1.1 dholland 1084 1.1 dholland set_status[dist->set] |= SET_INSTALLED; 1085 1.41 martin if (do_stats) 1086 1.41 martin tarstats.nsuccess++; 1087 1.1 dholland return SET_OK; 1088 1.1 dholland } 1089 1.1 dholland 1090 1.1 dholland static void 1091 1.1 dholland skip_set(distinfo *dist, int skip_type) 1092 1.1 dholland { 1093 1.1 dholland int nested; 1094 1.1 dholland int set; 1095 1.1 dholland 1096 1.1 dholland nested = 0; 1097 1.1 dholland while ((++dist)->set != SET_GROUP_END || nested--) { 1098 1.1 dholland set = dist->set; 1099 1.1 dholland if (set == SET_GROUP) { 1100 1.1 dholland nested++; 1101 1.1 dholland continue; 1102 1.1 dholland } 1103 1.1 dholland if (set == SET_LAST) 1104 1.1 dholland break; 1105 1.1 dholland if (set_status[set] == (SET_SELECTED | SET_VALID)) 1106 1.1 dholland set_status[set] |= SET_SKIPPED; 1107 1.1 dholland tarstats.nskipped++; 1108 1.1 dholland } 1109 1.1 dholland } 1110 1.1 dholland 1111 1.41 martin distinfo* 1112 1.41 martin get_set_distinfo(int opt) 1113 1.41 martin { 1114 1.41 martin distinfo *dist; 1115 1.41 martin int set; 1116 1.41 martin 1117 1.41 martin for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1118 1.41 martin if (set != opt) 1119 1.41 martin continue; 1120 1.41 martin if (dist->name == NULL) 1121 1.41 martin continue; 1122 1.41 martin if ((set_status[set] & (SET_VALID | SET_SELECTED)) 1123 1.41 martin != (SET_VALID | SET_SELECTED)) 1124 1.41 martin continue; 1125 1.41 martin return dist; 1126 1.41 martin } 1127 1.41 martin 1128 1.41 martin return NULL; 1129 1.41 martin } 1130 1.41 martin 1131 1.54 martin #ifdef CHECK_ENTROPY 1132 1.54 martin 1133 1.54 martin char entropy_file[PATH_MAX]; 1134 1.54 martin 1135 1.54 martin /* 1136 1.54 martin * Are we short of entropy? 1137 1.54 martin */ 1138 1.62 martin size_t 1139 1.54 martin entropy_needed(void) 1140 1.54 martin { 1141 1.54 martin int needed; 1142 1.54 martin size_t len; 1143 1.54 martin 1144 1.54 martin len = sizeof(needed); 1145 1.54 martin if (sysctlbyname("kern.entropy.needed", &needed, &len, NULL, 0)) 1146 1.54 martin return 0; 1147 1.54 martin 1148 1.54 martin if (needed < 0) 1149 1.54 martin return 0; 1150 1.54 martin 1151 1.54 martin return needed; 1152 1.54 martin } 1153 1.54 martin 1154 1.54 martin static void 1155 1.54 martin entropy_write_to_kernel(const uint8_t *data, size_t len) 1156 1.54 martin { 1157 1.54 martin int fd; 1158 1.54 martin 1159 1.54 martin fd = open(_PATH_RANDOM, O_RDWR, 0); 1160 1.54 martin if (fd >= 0) { 1161 1.54 martin write(fd, data, len); 1162 1.54 martin close(fd); 1163 1.54 martin } 1164 1.54 martin } 1165 1.54 martin 1166 1.54 martin static void 1167 1.54 martin entropy_add_manual(void) 1168 1.54 martin { 1169 1.54 martin SHA256_CTX ctx; 1170 1.62 martin char buf[256]; 1171 1.54 martin uint8_t digest[SHA256_DIGEST_LENGTH]; 1172 1.65 martin static const char prompt[] = "> "; 1173 1.62 martin size_t l; 1174 1.66 martin int txt_y; 1175 1.54 martin 1176 1.54 martin msg_display(MSG_entropy_enter_manual1); 1177 1.54 martin msg_printf("\n\n"); 1178 1.54 martin msg_display_add(MSG_entropy_enter_manual2); 1179 1.66 martin msg_printf("\n\n dd if=/dev/random bs=32 count=1 | openssl base64\n\n"); 1180 1.54 martin msg_display_add(MSG_entropy_enter_manual3); 1181 1.54 martin msg_printf("\n\n"); 1182 1.54 martin SHA256_Init(&ctx); 1183 1.66 martin txt_y = getcury(mainwin)+1; 1184 1.62 martin 1185 1.62 martin echo(); 1186 1.66 martin wmove(mainwin, txt_y, 0); 1187 1.66 martin msg_fmt_table_add(prompt, prompt); 1188 1.66 martin mvwgetnstr(mainwin, txt_y, 2, buf, sizeof buf); 1189 1.66 martin l = strlen(buf); 1190 1.66 martin if (l > 0) 1191 1.66 martin SHA256_Update(&ctx, (const uint8_t*)buf, l); 1192 1.62 martin noecho(); 1193 1.54 martin SHA256_Final(digest, &ctx); 1194 1.54 martin 1195 1.66 martin wmove(mainwin, txt_y-1, 0); 1196 1.62 martin wclrtobot(mainwin); 1197 1.62 martin wrefresh(mainwin); 1198 1.62 martin 1199 1.66 martin entropy_write_to_kernel(digest, sizeof digest); 1200 1.54 martin } 1201 1.54 martin 1202 1.54 martin /* 1203 1.56 gson * Get a file by some means and return a (potentially only 1204 1.54 martin * temporary valid) path to the local copy. 1205 1.56 gson * If mountpt is nonempty, the caller should unmount that 1206 1.54 martin * directory after processing the file. 1207 1.54 martin * Return success if the file is available, or failure if 1208 1.56 gson * the user cancelled the request or network transfer failed. 1209 1.54 martin */ 1210 1.54 martin static bool 1211 1.54 martin entropy_get_file(bool use_netbsd_seed, char *path) 1212 1.54 martin { 1213 1.54 martin static struct ftpinfo server = { .user = "ftp" }; 1214 1.55 martin char url[STRSIZE], tmpf[PATH_MAX], mountpt[PATH_MAX]; 1215 1.54 martin const char *ftp_opt; 1216 1.54 martin arg_rv arg; 1217 1.54 martin int rv = 0; 1218 1.54 martin const char *file_desc = msg_string(use_netbsd_seed ? 1219 1.54 martin MSG_entropy_seed : MSG_entropy_data); 1220 1.54 martin char *dir; 1221 1.54 martin 1222 1.54 martin path[0] = 0; 1223 1.54 martin mountpt[0] = 0; 1224 1.54 martin 1225 1.55 martin sprintf(tmpf, "/tmp/entr.%06x", getpid()); 1226 1.54 martin 1227 1.54 martin msg_display(use_netbsd_seed ? 1228 1.54 martin MSG_entropy_seed_hdr : MSG_entropy_data_hdr); 1229 1.54 martin msg_printf("\n\n %s\n\n", 1230 1.54 martin use_netbsd_seed ? 1231 1.54 martin "rndctl -S /tmp/entropy-file" : 1232 1.54 martin "dd if=/dev/random bs=32 count=1 of=/tmp/random.tmp"); 1233 1.54 martin strcpy(entropy_file, use_netbsd_seed ? 1234 1.54 martin "entropy-file" : "random.tmp"); 1235 1.54 martin process_menu(MENU_entropy_select_file, &rv); 1236 1.54 martin switch (rv) { 1237 1.54 martin case 1: 1238 1.54 martin case 2: 1239 1.54 martin #ifndef DEBUG 1240 1.54 martin if (!network_up) 1241 1.67 martin config_network(0); 1242 1.54 martin #endif 1243 1.54 martin server.xfer = rv == 1 ? XFER_HTTP : XFER_FTP; 1244 1.54 martin arg.arg = &server; 1245 1.54 martin arg.rv = -1; 1246 1.54 martin msg_display_add_subst(MSG_entropy_via_download, 1, file_desc); 1247 1.54 martin msg_printf("\n\n"); 1248 1.54 martin process_menu(MENU_entropy_ftpsource, &arg); 1249 1.54 martin if (arg.rv == SET_RETRY) 1250 1.54 martin return false; 1251 1.54 martin make_url(url, &server, entropy_file); 1252 1.54 martin if (server.xfer == XFER_FTP && 1253 1.54 martin strcmp("ftp", server.user) == 0 && server.pass[0] == 0) { 1254 1.54 martin /* do anon ftp */ 1255 1.54 martin ftp_opt = "-a "; 1256 1.54 martin } else { 1257 1.54 martin ftp_opt = ""; 1258 1.54 martin } 1259 1.54 martin rv = run_program(RUN_DISPLAY | RUN_PROGRESS, 1260 1.54 martin "/usr/bin/ftp %s -o %s %s", 1261 1.55 martin ftp_opt, tmpf, url); 1262 1.55 martin strcpy(path, tmpf); 1263 1.54 martin return rv == 0; 1264 1.54 martin case 3: 1265 1.54 martin #ifndef DEBUG 1266 1.54 martin if (!network_up) 1267 1.67 martin config_network(0); 1268 1.54 martin #endif 1269 1.54 martin rv = -1; 1270 1.54 martin msg_display_add_subst(MSG_entropy_via_nfs, 1, file_desc); 1271 1.54 martin msg_printf("\n\n"); 1272 1.54 martin process_menu(MENU_entropy_nfssource, &rv); 1273 1.54 martin if (rv == SET_RETRY) 1274 1.54 martin return false; 1275 1.54 martin if (nfs_host[0] != 0 && nfs_dir[0] != 0 && 1276 1.54 martin entropy_file[0] != 0) { 1277 1.54 martin strcpy(mountpt, "/tmp/ent-mnt.XXXXXX"); 1278 1.54 martin dir = mkdtemp(mountpt); 1279 1.54 martin if (dir == NULL) 1280 1.54 martin return false; 1281 1.54 martin sprintf(path, "%s/%s", mountpt, entropy_file); 1282 1.54 martin if (run_program(RUN_SILENT, 1283 1.54 martin "mount -t nfs -r %s:/%s %s", 1284 1.54 martin nfs_host, nfs_dir, mountpt) == 0) { 1285 1.54 martin run_program(RUN_SILENT, 1286 1.55 martin "cp %s %s", path, tmpf); 1287 1.54 martin run_program(RUN_SILENT, 1288 1.54 martin "umount %s", mountpt); 1289 1.54 martin rmdir(mountpt); 1290 1.55 martin strcpy(path, tmpf); 1291 1.54 martin } 1292 1.54 martin } 1293 1.54 martin break; 1294 1.54 martin case 4: 1295 1.54 martin rv = -1; 1296 1.54 martin /* Get device, filesystem, and filepath */ 1297 1.54 martin process_menu (MENU_entropy_localfs, &rv); 1298 1.54 martin if (rv == SET_RETRY) 1299 1.54 martin return false; 1300 1.54 martin if (localfs_dev[0] != 0 && localfs_fs[0] != 0 && 1301 1.54 martin entropy_file[0] != 0) { 1302 1.54 martin strcpy(mountpt, "/tmp/ent-mnt.XXXXXX"); 1303 1.54 martin dir = mkdtemp(mountpt); 1304 1.54 martin if (dir == NULL) 1305 1.54 martin return false; 1306 1.54 martin sprintf(path, "%s/%s", mountpt, entropy_file); 1307 1.54 martin if (run_program(RUN_SILENT, 1308 1.54 martin "mount -t %s -r /dev/%s %s", 1309 1.54 martin localfs_fs, localfs_dev, mountpt) == 0) { 1310 1.54 martin run_program(RUN_SILENT, 1311 1.55 martin "cp %s %s", path, tmpf); 1312 1.54 martin run_program(RUN_SILENT, 1313 1.54 martin "umount %s", mountpt); 1314 1.54 martin rmdir(mountpt); 1315 1.55 martin strcpy(path, tmpf); 1316 1.54 martin } 1317 1.54 martin } 1318 1.54 martin break; 1319 1.54 martin } 1320 1.54 martin return path[0] != 0; 1321 1.54 martin } 1322 1.54 martin 1323 1.54 martin static void 1324 1.54 martin entropy_add_bin_file(void) 1325 1.54 martin { 1326 1.54 martin char fname[PATH_MAX]; 1327 1.54 martin 1328 1.54 martin if (!entropy_get_file(false, fname)) 1329 1.54 martin return; 1330 1.54 martin if (access(fname, R_OK) == 0) 1331 1.54 martin run_program(RUN_SILENT, "dd if=%s of=" _PATH_RANDOM, 1332 1.54 martin fname); 1333 1.54 martin } 1334 1.54 martin 1335 1.54 martin static void 1336 1.54 martin entropy_add_seed(void) 1337 1.54 martin { 1338 1.54 martin char fname[PATH_MAX]; 1339 1.54 martin 1340 1.54 martin if (!entropy_get_file(true, fname)) 1341 1.54 martin return; 1342 1.54 martin if (access(fname, R_OK) == 0) 1343 1.54 martin run_program(RUN_SILENT, "rndctl -L %s", fname); 1344 1.54 martin } 1345 1.54 martin 1346 1.54 martin /* 1347 1.54 martin * return true if we have enough entropy 1348 1.54 martin */ 1349 1.54 martin bool 1350 1.62 martin do_add_entropy(void) 1351 1.54 martin { 1352 1.54 martin int rv; 1353 1.54 martin 1354 1.63 martin if (entropy_needed() == 0) 1355 1.63 martin return true; 1356 1.63 martin 1357 1.54 martin for (;;) { 1358 1.54 martin if (entropy_needed() == 0) 1359 1.63 martin break; 1360 1.54 martin 1361 1.54 martin msg_clear(); 1362 1.54 martin rv = 0; 1363 1.54 martin process_menu(MENU_not_enough_entropy, &rv); 1364 1.54 martin switch (rv) { 1365 1.54 martin case 0: 1366 1.54 martin return false; 1367 1.54 martin case 1: 1368 1.54 martin entropy_add_manual(); 1369 1.54 martin break; 1370 1.54 martin case 2: 1371 1.54 martin entropy_add_seed(); 1372 1.54 martin break; 1373 1.54 martin case 3: 1374 1.54 martin entropy_add_bin_file(); 1375 1.54 martin break; 1376 1.54 martin default: 1377 1.54 martin /* 1378 1.54 martin * retry after small delay to give a new USB device 1379 1.54 martin * a chance to attach and do deliver some 1380 1.54 martin * entropy 1381 1.54 martin */ 1382 1.54 martin msg_display("."); 1383 1.54 martin for (size_t i = 0; i < 10; i++) { 1384 1.54 martin if (entropy_needed() == 0) 1385 1.54 martin return true; 1386 1.54 martin sleep(1); 1387 1.54 martin msg_display_add("."); 1388 1.54 martin } 1389 1.54 martin } 1390 1.54 martin } 1391 1.63 martin 1392 1.63 martin /* 1393 1.63 martin * Save entropy (maybe again) to give the seed file a good 1394 1.63 martin * entropy estimate. 1395 1.63 martin */ 1396 1.63 martin run_program(RUN_SILENT | RUN_CHROOT | RUN_ERROR_OK, 1397 1.63 martin "/etc/rc.d/random_seed stop"); 1398 1.63 martin 1399 1.63 martin return true; 1400 1.54 martin } 1401 1.57 rillig #endif 1402 1.54 martin 1403 1.54 martin 1404 1.41 martin 1405 1.1 dholland /* 1406 1.1 dholland * Get and unpack the distribution. 1407 1.1 dholland * Show success_msg if installation completes. 1408 1.1 dholland * Otherwise show failure_msg and wait for the user to ack it before continuing. 1409 1.1 dholland * success_msg and failure_msg must both be 0-adic messages. 1410 1.1 dholland */ 1411 1.1 dholland int 1412 1.1 dholland get_and_unpack_sets(int update, msg setupdone_msg, msg success_msg, msg failure_msg) 1413 1.1 dholland { 1414 1.1 dholland distinfo *dist; 1415 1.1 dholland int status; 1416 1.42 martin int set, olderror, oldfound; 1417 1.44 martin bool entropy_loaded = false; 1418 1.1 dholland 1419 1.1 dholland /* Ensure mountpoint for distribution files exists in current root. */ 1420 1.1 dholland (void)mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); 1421 1.1 dholland if (script) 1422 1.1 dholland (void)fprintf(script, "mkdir -m 755 /mnt2\n"); 1423 1.1 dholland 1424 1.1 dholland /* reset failure/success counters */ 1425 1.1 dholland memset(&tarstats, 0, sizeof(tarstats)); 1426 1.1 dholland 1427 1.1 dholland /* Find out which files to "get" if we get files. */ 1428 1.1 dholland 1429 1.1 dholland /* Accurately count selected sets */ 1430 1.1 dholland for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1431 1.11 christos if (dist->name == NULL) 1432 1.11 christos continue; 1433 1.41 martin if (set_status[set] & SET_NO_EXTRACT) 1434 1.41 martin continue; 1435 1.1 dholland if ((set_status[set] & (SET_VALID | SET_SELECTED)) 1436 1.1 dholland == (SET_VALID | SET_SELECTED)) 1437 1.1 dholland tarstats.nselected++; 1438 1.1 dholland } 1439 1.1 dholland 1440 1.1 dholland status = SET_RETRY; 1441 1.11 christos for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1442 1.1 dholland if (dist->name == NULL) 1443 1.1 dholland continue; 1444 1.1 dholland if (set_status[set] != (SET_VALID | SET_SELECTED)) 1445 1.1 dholland continue; 1446 1.1 dholland 1447 1.42 martin /* save stats, in case we will retry */ 1448 1.42 martin oldfound = tarstats.nfound; 1449 1.42 martin olderror = tarstats.nerror; 1450 1.42 martin 1451 1.1 dholland if (status != SET_OK) { 1452 1.1 dholland /* This might force a redraw.... */ 1453 1.1 dholland clearok(curscr, 1); 1454 1.1 dholland touchwin(stdscr); 1455 1.1 dholland wrefresh(stdscr); 1456 1.1 dholland /* Sort out the location of the set files */ 1457 1.1 dholland do { 1458 1.1 dholland umount_mnt2(); 1459 1.24 christos msg_fmt_display(MSG_distmedium, "%d%d%s", 1460 1.24 christos tarstats.nselected, 1461 1.1 dholland tarstats.nsuccess + tarstats.nskipped, 1462 1.1 dholland dist->name); 1463 1.1 dholland fetch_fn = NULL; 1464 1.1 dholland process_menu(MENU_distmedium, &status); 1465 1.1 dholland } while (status == SET_RETRY); 1466 1.1 dholland 1467 1.1 dholland if (status == SET_SKIP) { 1468 1.1 dholland set_status[set] |= SET_SKIPPED; 1469 1.1 dholland tarstats.nskipped++; 1470 1.1 dholland continue; 1471 1.1 dholland } 1472 1.1 dholland if (status == SET_SKIP_GROUP) { 1473 1.1 dholland skip_set(dist, status); 1474 1.1 dholland continue; 1475 1.1 dholland } 1476 1.1 dholland if (status != SET_OK) { 1477 1.22 martin hit_enter_to_continue(failure_msg, NULL); 1478 1.1 dholland return 1; 1479 1.1 dholland } 1480 1.1 dholland } 1481 1.1 dholland 1482 1.41 martin if (set_status[set] & SET_NO_EXTRACT) 1483 1.41 martin continue; 1484 1.41 martin 1485 1.1 dholland /* Try to extract this set */ 1486 1.1 dholland status = extract_file(dist, update); 1487 1.42 martin if (status == SET_RETRY) { 1488 1.42 martin /* do this set again */ 1489 1.1 dholland dist--; 1490 1.42 martin /* and reset statistics to what we had before this 1491 1.42 martin * set */ 1492 1.42 martin tarstats.nfound = oldfound; 1493 1.42 martin tarstats.nerror = olderror; 1494 1.42 martin } 1495 1.1 dholland } 1496 1.1 dholland 1497 1.41 martin #ifdef MD_SET_EXTRACT_FINALIZE 1498 1.41 martin MD_SET_EXTRACT_FINALIZE(update); 1499 1.41 martin #endif 1500 1.41 martin 1501 1.1 dholland if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) { 1502 1.1 dholland msg_display(MSG_endtarok); 1503 1.1 dholland /* Give user a chance to see the success message */ 1504 1.1 dholland sleep(1); 1505 1.1 dholland } else { 1506 1.1 dholland /* We encountered errors. Let the user know. */ 1507 1.24 christos msg_fmt_display(MSG_endtar, "%d%d%d%d%d%d", 1508 1.1 dholland tarstats.nselected, tarstats.nnotfound, tarstats.nskipped, 1509 1.1 dholland tarstats.nfound, tarstats.nsuccess, tarstats.nerror); 1510 1.22 martin hit_enter_to_continue(NULL, NULL); 1511 1.1 dholland } 1512 1.1 dholland 1513 1.1 dholland /* 1514 1.1 dholland * postinstall needs to be run after extracting all sets, because 1515 1.1 dholland * otherwise /var/db/obsolete will only have current information 1516 1.1 dholland * from the base, comp, and etc sets. 1517 1.1 dholland */ 1518 1.1 dholland if (update && (set_status[SET_ETC] & SET_INSTALLED)) { 1519 1.1 dholland int oldsendmail; 1520 1.1 dholland oldsendmail = run_program(RUN_DISPLAY | RUN_CHROOT | 1521 1.1 dholland RUN_ERROR_OK | RUN_PROGRESS, 1522 1.1 dholland "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf"); 1523 1.1 dholland if (oldsendmail == 1) { 1524 1.1 dholland msg_display(MSG_oldsendmail); 1525 1.6 martin if (ask_yesno(NULL)) { 1526 1.1 dholland run_program(RUN_DISPLAY | RUN_CHROOT, 1527 1.1 dholland "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf"); 1528 1.1 dholland } 1529 1.1 dholland } 1530 1.1 dholland run_program(RUN_DISPLAY | RUN_CHROOT, 1531 1.1 dholland "/usr/sbin/postinstall -s /.sysinst -d / fix"); 1532 1.3 tls 1533 1.3 tls /* Don't discard the system's old entropy if any */ 1534 1.3 tls run_program(RUN_CHROOT | RUN_SILENT, 1535 1.44 martin "/etc/rc.d/random_seed start"); 1536 1.44 martin entropy_loaded = true; 1537 1.1 dholland } 1538 1.1 dholland 1539 1.1 dholland /* Configure the system */ 1540 1.73 riastrad if (set_status[SET_BASE] & SET_INSTALLED) { 1541 1.1 dholland run_makedev(); 1542 1.73 riastrad if (!update) { 1543 1.73 riastrad run_program(RUN_CHROOT|RUN_DISPLAY, 1544 1.73 riastrad "/usr/sbin/certctl rehash"); 1545 1.73 riastrad } 1546 1.73 riastrad } 1547 1.1 dholland 1548 1.62 martin if (!update) { 1549 1.3 tls struct stat sb1, sb2; 1550 1.3 tls 1551 1.4 martin if (stat(target_expand("/"), &sb1) == 0 1552 1.4 martin && stat(target_expand("/var"), &sb2) == 0 1553 1.4 martin && sb1.st_dev != sb2.st_dev) { 1554 1.3 tls add_rc_conf("random_file=/etc/entropy-file\n"); 1555 1.3 tls if (target_file_exists_p("/boot.cfg")) { 1556 1.3 tls run_program(RUN_CHROOT|RUN_FATAL, 1557 1.3 tls "sh -c 'sed -e s./var/db/./etc/. " 1558 1.3 tls "< /boot.cfg " 1559 1.3 tls "> /tmp/boot.cfg.tmp'"); 1560 1.3 tls mv_within_target_or_die("/tmp/boot.cfg.tmp", 1561 1.3 tls "/boot.cfg"); 1562 1.40 martin 1563 1.3 tls } 1564 1.3 tls } 1565 1.3 tls 1566 1.40 martin #ifdef MD_BOOT_CFG_FINALIZE 1567 1.40 martin if (target_file_exists_p("/boot.cfg")) { 1568 1.40 martin MD_BOOT_CFG_FINALIZE("/boot.cfg"); 1569 1.40 martin } 1570 1.40 martin #endif 1571 1.40 martin 1572 1.3 tls /* Save keyboard type */ 1573 1.1 dholland save_kb_encoding(); 1574 1.1 dholland 1575 1.1 dholland /* Other configuration. */ 1576 1.1 dholland mnt_net_config(); 1577 1.1 dholland } 1578 1.1 dholland 1579 1.1 dholland /* Mounted dist dir? */ 1580 1.1 dholland umount_mnt2(); 1581 1.1 dholland 1582 1.54 martin #ifdef CHECK_ENTROPY 1583 1.54 martin entropy_loaded |= entropy_needed() == 0; 1584 1.54 martin #endif 1585 1.54 martin 1586 1.3 tls /* Save entropy -- on some systems it's ~all we'll ever get */ 1587 1.44 martin if (!update || entropy_loaded) 1588 1.44 martin run_program(RUN_SILENT | RUN_CHROOT | RUN_ERROR_OK, 1589 1.3 tls "/etc/rc.d/random_seed stop"); 1590 1.1 dholland /* Install/Upgrade complete ... reboot or exit to script */ 1591 1.22 martin hit_enter_to_continue(success_msg, NULL); 1592 1.1 dholland return 0; 1593 1.1 dholland } 1594 1.1 dholland 1595 1.1 dholland void 1596 1.1 dholland umount_mnt2(void) 1597 1.1 dholland { 1598 1.1 dholland if (!mnt2_mounted) 1599 1.1 dholland return; 1600 1.1 dholland run_program(RUN_SILENT, "/sbin/umount /mnt2"); 1601 1.1 dholland mnt2_mounted = 0; 1602 1.1 dholland } 1603 1.1 dholland 1604 1.1 dholland 1605 1.1 dholland /* 1606 1.1 dholland * Do a quick sanity check that the target can reboot. 1607 1.1 dholland * return 1 if everything OK, 0 if there is a problem. 1608 1.1 dholland * Uses a table of files we expect to find after a base install/upgrade. 1609 1.1 dholland */ 1610 1.1 dholland 1611 1.1 dholland /* test flag and pathname to check for after unpacking. */ 1612 1.1 dholland struct check_table { unsigned int mode; const char *path;} checks[] = { 1613 1.1 dholland { S_IFREG, "/netbsd" }, 1614 1.1 dholland { S_IFDIR, "/etc" }, 1615 1.1 dholland { S_IFREG, "/etc/fstab" }, 1616 1.1 dholland { S_IFREG, "/sbin/init" }, 1617 1.1 dholland { S_IFREG, "/bin/sh" }, 1618 1.1 dholland { S_IFREG, "/etc/rc" }, 1619 1.1 dholland { S_IFREG, "/etc/rc.subr" }, 1620 1.1 dholland { S_IFREG, "/etc/rc.conf" }, 1621 1.1 dholland { S_IFDIR, "/dev" }, 1622 1.1 dholland { S_IFCHR, "/dev/console" }, 1623 1.1 dholland /* XXX check for rootdev in target /dev? */ 1624 1.1 dholland { S_IFREG, "/sbin/fsck" }, 1625 1.1 dholland { S_IFREG, "/sbin/fsck_ffs" }, 1626 1.1 dholland { S_IFREG, "/sbin/mount" }, 1627 1.1 dholland { S_IFREG, "/sbin/mount_ffs" }, 1628 1.1 dholland { S_IFREG, "/sbin/mount_nfs" }, 1629 1.1 dholland #if defined(DEBUG) || defined(DEBUG_CHECK) 1630 1.1 dholland { S_IFREG, "/foo/bar" }, /* bad entry to exercise warning */ 1631 1.1 dholland #endif 1632 1.1 dholland { 0, 0 } 1633 1.1 dholland 1634 1.1 dholland }; 1635 1.1 dholland 1636 1.1 dholland /* 1637 1.1 dholland * Check target for a single file. 1638 1.1 dholland */ 1639 1.1 dholland static int 1640 1.1 dholland check_for(unsigned int mode, const char *pathname) 1641 1.1 dholland { 1642 1.1 dholland int found; 1643 1.1 dholland 1644 1.1 dholland found = (target_test(mode, pathname) == 0); 1645 1.1 dholland if (found == 0) 1646 1.24 christos msg_fmt_display(MSG_rootmissing, "%s", pathname); 1647 1.1 dholland return found; 1648 1.1 dholland } 1649 1.1 dholland 1650 1.1 dholland /* 1651 1.1 dholland * Check that all the files in check_table are present in the 1652 1.1 dholland * target root. Warn if not found. 1653 1.1 dholland */ 1654 1.1 dholland int 1655 1.1 dholland sanity_check(void) 1656 1.1 dholland { 1657 1.1 dholland int target_ok = 1; 1658 1.1 dholland struct check_table *p; 1659 1.1 dholland 1660 1.1 dholland for (p = checks; p->path; p++) { 1661 1.1 dholland target_ok = target_ok && check_for(p->mode, p->path); 1662 1.1 dholland } 1663 1.1 dholland if (target_ok) 1664 1.1 dholland return 0; 1665 1.1 dholland 1666 1.1 dholland /* Uh, oh. Something's missing. */ 1667 1.22 martin hit_enter_to_continue(MSG_badroot, NULL); 1668 1.1 dholland return 1; 1669 1.1 dholland } 1670 1.1 dholland 1671 1.1 dholland /* 1672 1.1 dholland * Some globals to pass things back from callbacks 1673 1.1 dholland */ 1674 1.1 dholland static char zoneinfo_dir[STRSIZE]; 1675 1.1 dholland static int zonerootlen; 1676 1.1 dholland static char *tz_selected; /* timezonename (relative to share/zoneinfo */ 1677 1.1 dholland const char *tz_default; /* UTC, or whatever /etc/localtime points to */ 1678 1.1 dholland static char tz_env[STRSIZE]; 1679 1.1 dholland static int save_cursel, save_topline; 1680 1.47 martin static int time_menu = -1; 1681 1.47 martin 1682 1.47 martin static void 1683 1.47 martin update_time_display(void) 1684 1.47 martin { 1685 1.47 martin time_t t; 1686 1.47 martin struct tm *tm; 1687 1.47 martin char cur_time[STRSIZE], *p; 1688 1.47 martin 1689 1.47 martin t = time(NULL); 1690 1.47 martin tm = localtime(&t); 1691 1.47 martin strlcpy(cur_time, safectime(&t), sizeof cur_time); 1692 1.47 martin p = strchr(cur_time, '\n'); 1693 1.47 martin if (p != NULL) 1694 1.47 martin *p = 0; 1695 1.47 martin 1696 1.47 martin msg_clear(); 1697 1.47 martin msg_fmt_table_add(MSG_choose_timezone, "%s%s%s%s", 1698 1.47 martin tz_default, tz_selected, cur_time, tm ? tm->tm_zone : "?"); 1699 1.47 martin } 1700 1.1 dholland 1701 1.1 dholland /* 1702 1.1 dholland * Callback from timezone menu 1703 1.1 dholland */ 1704 1.1 dholland static int 1705 1.1 dholland set_tz_select(menudesc *m, void *arg) 1706 1.1 dholland { 1707 1.1 dholland char *new; 1708 1.1 dholland 1709 1.1 dholland if (m && strcmp(tz_selected, m->opts[m->cursel].opt_name) != 0) { 1710 1.1 dholland /* Change the displayed timezone */ 1711 1.1 dholland new = strdup(m->opts[m->cursel].opt_name); 1712 1.1 dholland if (new == NULL) 1713 1.1 dholland return 0; 1714 1.1 dholland free(tz_selected); 1715 1.1 dholland tz_selected = new; 1716 1.1 dholland snprintf(tz_env, sizeof tz_env, "%.*s%s", 1717 1.1 dholland zonerootlen, zoneinfo_dir, tz_selected); 1718 1.1 dholland setenv("TZ", tz_env, 1); 1719 1.1 dholland } 1720 1.1 dholland if (m) 1721 1.1 dholland /* Warp curser to 'Exit' line on menu */ 1722 1.1 dholland m->cursel = -1; 1723 1.1 dholland 1724 1.47 martin update_time_display(); 1725 1.47 martin if (time_menu >= 1) { 1726 1.47 martin WINDOW *w = get_menudesc(time_menu)->mw; 1727 1.47 martin if (w != NULL) { 1728 1.47 martin touchwin(w); 1729 1.47 martin wrefresh(w); 1730 1.47 martin } 1731 1.47 martin } 1732 1.1 dholland return 0; 1733 1.1 dholland } 1734 1.1 dholland 1735 1.1 dholland static int 1736 1.1 dholland set_tz_back(menudesc *m, void *arg) 1737 1.1 dholland { 1738 1.1 dholland 1739 1.1 dholland zoneinfo_dir[zonerootlen] = 0; 1740 1.1 dholland m->cursel = save_cursel; 1741 1.1 dholland m->topline = save_topline; 1742 1.1 dholland return 0; 1743 1.1 dholland } 1744 1.1 dholland 1745 1.1 dholland static int 1746 1.1 dholland set_tz_dir(menudesc *m, void *arg) 1747 1.1 dholland { 1748 1.1 dholland 1749 1.1 dholland strlcpy(zoneinfo_dir + zonerootlen, m->opts[m->cursel].opt_name, 1750 1.1 dholland sizeof zoneinfo_dir - zonerootlen); 1751 1.1 dholland save_cursel = m->cursel; 1752 1.1 dholland save_topline = m->topline; 1753 1.1 dholland m->cursel = 0; 1754 1.1 dholland m->topline = 0; 1755 1.1 dholland return 0; 1756 1.1 dholland } 1757 1.1 dholland 1758 1.1 dholland /* 1759 1.1 dholland * Alarm-handler to update example-display 1760 1.1 dholland */ 1761 1.1 dholland static void 1762 1.1 dholland /*ARGSUSED*/ 1763 1.1 dholland timezone_sig(int sig) 1764 1.1 dholland { 1765 1.1 dholland 1766 1.1 dholland set_tz_select(NULL, NULL); 1767 1.1 dholland alarm(60); 1768 1.1 dholland } 1769 1.1 dholland 1770 1.1 dholland static int 1771 1.1 dholland tz_sort(const void *a, const void *b) 1772 1.1 dholland { 1773 1.1 dholland return strcmp(((const menu_ent *)a)->opt_name, ((const menu_ent *)b)->opt_name); 1774 1.1 dholland } 1775 1.1 dholland 1776 1.1 dholland static void 1777 1.1 dholland tzm_set_names(menudesc *m, void *arg) 1778 1.1 dholland { 1779 1.1 dholland DIR *dir; 1780 1.1 dholland struct dirent *dp; 1781 1.1 dholland static int nfiles; 1782 1.1 dholland static int maxfiles = 32; 1783 1.1 dholland static menu_ent *tz_menu; 1784 1.1 dholland static char **tz_names; 1785 1.1 dholland void *p; 1786 1.1 dholland int maxfname; 1787 1.1 dholland char *fp; 1788 1.1 dholland struct stat sb; 1789 1.1 dholland 1790 1.1 dholland if (tz_menu == NULL) 1791 1.25 christos tz_menu = calloc(maxfiles, sizeof *tz_menu); 1792 1.1 dholland if (tz_names == NULL) 1793 1.1 dholland tz_names = malloc(maxfiles * sizeof *tz_names); 1794 1.1 dholland if (tz_menu == NULL || tz_names == NULL) 1795 1.1 dholland return; /* error - skip timezone setting */ 1796 1.1 dholland while (nfiles > 0) 1797 1.1 dholland free(tz_names[--nfiles]); 1798 1.1 dholland 1799 1.1 dholland dir = opendir(zoneinfo_dir); 1800 1.1 dholland fp = strchr(zoneinfo_dir, 0); 1801 1.1 dholland if (fp != zoneinfo_dir + zonerootlen) { 1802 1.1 dholland tz_names[0] = 0; 1803 1.1 dholland tz_menu[0].opt_name = msg_string(MSG_tz_back); 1804 1.1 dholland tz_menu[0].opt_action = set_tz_back; 1805 1.1 dholland nfiles = 1; 1806 1.1 dholland } 1807 1.1 dholland maxfname = zoneinfo_dir + sizeof zoneinfo_dir - fp - 1; 1808 1.1 dholland if (dir != NULL) { 1809 1.1 dholland while ((dp = readdir(dir)) != NULL) { 1810 1.1 dholland if (dp->d_namlen > maxfname || dp->d_name[0] == '.') 1811 1.1 dholland continue; 1812 1.1 dholland strlcpy(fp, dp->d_name, maxfname); 1813 1.1 dholland if (stat(zoneinfo_dir, &sb) == -1) 1814 1.1 dholland continue; 1815 1.1 dholland if (nfiles >= maxfiles) { 1816 1.26 martin p = realloc(tz_menu, 1817 1.26 martin 2 * maxfiles * sizeof *tz_menu); 1818 1.1 dholland if (p == NULL) 1819 1.1 dholland break; 1820 1.1 dholland tz_menu = p; 1821 1.26 martin memset(tz_menu + maxfiles, 0, 1822 1.26 martin maxfiles * sizeof *tz_menu); 1823 1.26 martin p = realloc(tz_names, 1824 1.26 martin 2 * maxfiles * sizeof *tz_names); 1825 1.1 dholland if (p == NULL) 1826 1.1 dholland break; 1827 1.1 dholland tz_names = p; 1828 1.26 martin memset(tz_names + maxfiles, 0, 1829 1.26 martin maxfiles * sizeof *tz_names); 1830 1.1 dholland maxfiles *= 2; 1831 1.1 dholland } 1832 1.1 dholland if (S_ISREG(sb.st_mode)) 1833 1.1 dholland tz_menu[nfiles].opt_action = set_tz_select; 1834 1.1 dholland else if (S_ISDIR(sb.st_mode)) { 1835 1.1 dholland tz_menu[nfiles].opt_action = set_tz_dir; 1836 1.1 dholland strlcat(fp, "/", 1837 1.1 dholland sizeof(zoneinfo_dir) - (fp - zoneinfo_dir)); 1838 1.1 dholland } else 1839 1.1 dholland continue; 1840 1.1 dholland tz_names[nfiles] = strdup(zoneinfo_dir + zonerootlen); 1841 1.1 dholland tz_menu[nfiles].opt_name = tz_names[nfiles]; 1842 1.1 dholland nfiles++; 1843 1.1 dholland } 1844 1.1 dholland closedir(dir); 1845 1.1 dholland } 1846 1.1 dholland *fp = 0; 1847 1.1 dholland 1848 1.1 dholland m->opts = tz_menu; 1849 1.1 dholland m->numopts = nfiles; 1850 1.1 dholland qsort(tz_menu, nfiles, sizeof *tz_menu, tz_sort); 1851 1.1 dholland } 1852 1.1 dholland 1853 1.1 dholland void 1854 1.1 dholland get_tz_default(void) 1855 1.1 dholland { 1856 1.1 dholland char localtime_link[STRSIZE]; 1857 1.1 dholland static char localtime_target[STRSIZE]; 1858 1.1 dholland int rc; 1859 1.1 dholland 1860 1.1 dholland strlcpy(localtime_link, target_expand("/etc/localtime"), 1861 1.1 dholland sizeof localtime_link); 1862 1.1 dholland 1863 1.1 dholland /* Add sanity check that /mnt/usr/share/zoneinfo contains 1864 1.1 dholland * something useful 1865 1.1 dholland */ 1866 1.1 dholland 1867 1.1 dholland rc = readlink(localtime_link, localtime_target, 1868 1.1 dholland sizeof(localtime_target) - 1); 1869 1.1 dholland if (rc < 0) { 1870 1.1 dholland /* error, default to UTC */ 1871 1.1 dholland tz_default = "UTC"; 1872 1.1 dholland } else { 1873 1.1 dholland localtime_target[rc] = '\0'; 1874 1.1 dholland tz_default = strchr(strstr(localtime_target, "zoneinfo"), '/') + 1; 1875 1.1 dholland } 1876 1.1 dholland } 1877 1.1 dholland 1878 1.1 dholland /* 1879 1.1 dholland * Choose from the files in usr/share/zoneinfo and set etc/localtime 1880 1.1 dholland */ 1881 1.1 dholland int 1882 1.1 dholland set_timezone(void) 1883 1.1 dholland { 1884 1.1 dholland char localtime_link[STRSIZE]; 1885 1.1 dholland char localtime_target[STRSIZE]; 1886 1.1 dholland int menu_no; 1887 1.1 dholland 1888 1.1 dholland strlcpy(zoneinfo_dir, target_expand("/usr/share/zoneinfo/"), 1889 1.1 dholland sizeof zoneinfo_dir - 1); 1890 1.1 dholland zonerootlen = strlen(zoneinfo_dir); 1891 1.1 dholland 1892 1.1 dholland get_tz_default(); 1893 1.1 dholland 1894 1.1 dholland tz_selected = strdup(tz_default); 1895 1.1 dholland snprintf(tz_env, sizeof(tz_env), "%s%s", zoneinfo_dir, tz_selected); 1896 1.1 dholland setenv("TZ", tz_env, 1); 1897 1.47 martin update_time_display(); 1898 1.1 dholland 1899 1.1 dholland signal(SIGALRM, timezone_sig); 1900 1.1 dholland alarm(60); 1901 1.1 dholland 1902 1.1 dholland menu_no = new_menu(NULL, NULL, 14, 23, 9, 1903 1.1 dholland 12, 32, MC_ALWAYS_SCROLL | MC_NOSHORTCUT, 1904 1.1 dholland tzm_set_names, NULL, NULL, 1905 1.39 martin "\nPlease consult the install documents.", 1906 1.39 martin MSG_exit_menu_generic); 1907 1.59 martin if (menu_no >= 0) { 1908 1.59 martin time_menu = menu_no; 1909 1.59 martin process_menu(menu_no, NULL); 1910 1.59 martin time_menu = -1; 1911 1.1 dholland 1912 1.59 martin free_menu(menu_no); 1913 1.59 martin } 1914 1.1 dholland 1915 1.59 martin alarm(0); 1916 1.1 dholland signal(SIGALRM, SIG_IGN); 1917 1.1 dholland 1918 1.59 martin if (menu_no >= 0) { 1919 1.59 martin snprintf(localtime_target, sizeof(localtime_target), 1920 1.59 martin "/usr/share/zoneinfo/%s", tz_selected); 1921 1.59 martin strlcpy(localtime_link, target_expand("/etc/localtime"), 1922 1.59 martin sizeof localtime_link); 1923 1.59 martin unlink(localtime_link); 1924 1.59 martin symlink(localtime_target, localtime_link); 1925 1.59 martin } 1926 1.1 dholland 1927 1.1 dholland return 1; 1928 1.1 dholland } 1929 1.1 dholland 1930 1.1 dholland void 1931 1.1 dholland scripting_vfprintf(FILE *f, const char *fmt, va_list ap) 1932 1.1 dholland { 1933 1.28 martin va_list ap2; 1934 1.1 dholland 1935 1.28 martin va_copy(ap2, ap); 1936 1.1 dholland if (f) 1937 1.1 dholland (void)vfprintf(f, fmt, ap); 1938 1.1 dholland if (script) 1939 1.28 martin (void)vfprintf(script, fmt, ap2); 1940 1.1 dholland } 1941 1.1 dholland 1942 1.1 dholland void 1943 1.1 dholland scripting_fprintf(FILE *f, const char *fmt, ...) 1944 1.1 dholland { 1945 1.1 dholland va_list ap; 1946 1.1 dholland 1947 1.1 dholland va_start(ap, fmt); 1948 1.1 dholland scripting_vfprintf(f, fmt, ap); 1949 1.1 dholland va_end(ap); 1950 1.1 dholland } 1951 1.1 dholland 1952 1.1 dholland void 1953 1.1 dholland add_rc_conf(const char *fmt, ...) 1954 1.1 dholland { 1955 1.1 dholland FILE *f; 1956 1.1 dholland va_list ap; 1957 1.1 dholland 1958 1.1 dholland va_start(ap, fmt); 1959 1.1 dholland f = target_fopen("/etc/rc.conf", "a"); 1960 1.1 dholland if (f != 0) { 1961 1.1 dholland scripting_fprintf(NULL, "cat <<EOF >>%s/etc/rc.conf\n", 1962 1.1 dholland target_prefix()); 1963 1.1 dholland scripting_vfprintf(f, fmt, ap); 1964 1.1 dholland fclose(f); 1965 1.1 dholland scripting_fprintf(NULL, "EOF\n"); 1966 1.1 dholland } 1967 1.1 dholland va_end(ap); 1968 1.1 dholland } 1969 1.1 dholland 1970 1.1 dholland int 1971 1.1 dholland del_rc_conf(const char *value) 1972 1.1 dholland { 1973 1.1 dholland FILE *fp, *nfp; 1974 1.1 dholland char buf[4096]; /* Ridiculously high, but should be enough in any way */ 1975 1.1 dholland char *rcconf, *tempname = NULL, *bakname = NULL; 1976 1.1 dholland char *cp; 1977 1.1 dholland int done = 0; 1978 1.1 dholland int fd; 1979 1.1 dholland int retval = 0; 1980 1.1 dholland 1981 1.57 rillig /* The paths might seem strange, but using /tmp would require copy instead 1982 1.1 dholland * of rename operations. */ 1983 1.1 dholland if (asprintf(&rcconf, "%s", target_expand("/etc/rc.conf")) < 0 1984 1.1 dholland || asprintf(&tempname, "%s", target_expand("/etc/rc.conf.tmp.XXXXXX")) < 0 1985 1.1 dholland || asprintf(&bakname, "%s", target_expand("/etc/rc.conf.bak.XXXXXX")) < 0) { 1986 1.1 dholland if (rcconf) 1987 1.1 dholland free(rcconf); 1988 1.1 dholland if (tempname) 1989 1.1 dholland free(tempname); 1990 1.24 christos msg_fmt_display(MSG_rcconf_delete_failed, "%s", value); 1991 1.22 martin hit_enter_to_continue(NULL, NULL); 1992 1.1 dholland return -1; 1993 1.1 dholland } 1994 1.1 dholland 1995 1.1 dholland if ((fd = mkstemp(bakname)) < 0) { 1996 1.24 christos msg_fmt_display(MSG_rcconf_delete_failed, "%s", value); 1997 1.22 martin hit_enter_to_continue(NULL, NULL); 1998 1.1 dholland return -1; 1999 1.1 dholland } 2000 1.1 dholland close(fd); 2001 1.1 dholland 2002 1.1 dholland if (!(fp = fopen(rcconf, "r+")) || (fd = mkstemp(tempname)) < 0) { 2003 1.1 dholland if (fp) 2004 1.1 dholland fclose(fp); 2005 1.24 christos msg_fmt_display(MSG_rcconf_delete_failed, "%s", value); 2006 1.22 martin hit_enter_to_continue(NULL, NULL); 2007 1.1 dholland return -1; 2008 1.1 dholland } 2009 1.1 dholland 2010 1.1 dholland nfp = fdopen(fd, "w"); 2011 1.1 dholland if (!nfp) { 2012 1.1 dholland fclose(fp); 2013 1.1 dholland close(fd); 2014 1.24 christos msg_fmt_display(MSG_rcconf_delete_failed, "%s", value); 2015 1.22 martin hit_enter_to_continue(NULL, NULL); 2016 1.1 dholland return -1; 2017 1.1 dholland } 2018 1.1 dholland 2019 1.1 dholland while (fgets(buf, sizeof buf, fp) != NULL) { 2020 1.1 dholland 2021 1.1 dholland cp = buf + strspn(buf, " \t"); /* Skip initial spaces */ 2022 1.1 dholland if (strncmp(cp, value, strlen(value)) == 0) { 2023 1.1 dholland cp += strlen(value); 2024 1.1 dholland if (*cp != '=') 2025 1.1 dholland scripting_fprintf(nfp, "%s", buf); 2026 1.1 dholland else 2027 1.1 dholland done = 1; 2028 1.1 dholland } else { 2029 1.1 dholland scripting_fprintf(nfp, "%s", buf); 2030 1.1 dholland } 2031 1.1 dholland } 2032 1.1 dholland fclose(fp); 2033 1.1 dholland fclose(nfp); 2034 1.57 rillig 2035 1.1 dholland if (done) { 2036 1.1 dholland if (rename(rcconf, bakname)) { 2037 1.1 dholland msg_display(MSG_rcconf_backup_failed); 2038 1.6 martin if (!ask_noyes(NULL)) { 2039 1.1 dholland retval = -1; 2040 1.1 dholland goto done; 2041 1.1 dholland } 2042 1.1 dholland } 2043 1.1 dholland 2044 1.1 dholland if (rename(tempname, rcconf)) { 2045 1.1 dholland if (rename(bakname, rcconf)) { 2046 1.22 martin hit_enter_to_continue(MSG_rcconf_restore_failed, 2047 1.22 martin NULL); 2048 1.1 dholland } else { 2049 1.22 martin hit_enter_to_continue(MSG_rcconf_delete_failed, 2050 1.22 martin NULL); 2051 1.1 dholland } 2052 1.1 dholland } 2053 1.1 dholland } 2054 1.1 dholland 2055 1.1 dholland done: 2056 1.78 kim (void)unlink(bakname); 2057 1.1 dholland (void)unlink(tempname); 2058 1.1 dholland free(rcconf); 2059 1.1 dholland free(tempname); 2060 1.1 dholland free(bakname); 2061 1.1 dholland return retval; 2062 1.1 dholland } 2063 1.1 dholland 2064 1.1 dholland void 2065 1.1 dholland add_sysctl_conf(const char *fmt, ...) 2066 1.1 dholland { 2067 1.1 dholland FILE *f; 2068 1.1 dholland va_list ap; 2069 1.1 dholland 2070 1.1 dholland va_start(ap, fmt); 2071 1.1 dholland f = target_fopen("/etc/sysctl.conf", "a"); 2072 1.1 dholland if (f != 0) { 2073 1.1 dholland scripting_fprintf(NULL, "cat <<EOF >>%s/etc/sysctl.conf\n", 2074 1.1 dholland target_prefix()); 2075 1.1 dholland scripting_vfprintf(f, fmt, ap); 2076 1.1 dholland fclose(f); 2077 1.1 dholland scripting_fprintf(NULL, "EOF\n"); 2078 1.1 dholland } 2079 1.1 dholland va_end(ap); 2080 1.1 dholland } 2081 1.1 dholland 2082 1.1 dholland void 2083 1.1 dholland enable_rc_conf(void) 2084 1.1 dholland { 2085 1.1 dholland 2086 1.1 dholland replace("/etc/rc.conf", "s/^rc_configured=NO/rc_configured=YES/"); 2087 1.1 dholland } 2088 1.1 dholland 2089 1.1 dholland int 2090 1.1 dholland check_lfs_progs(void) 2091 1.1 dholland { 2092 1.1 dholland 2093 1.1 dholland #ifndef NO_LFS 2094 1.2 martin return binary_available("fsck_lfs") && binary_available("mount_lfs") 2095 1.2 martin && binary_available("newfs_lfs"); 2096 1.1 dholland #else 2097 1.1 dholland return 0; 2098 1.1 dholland #endif 2099 1.1 dholland } 2100 1.1 dholland 2101 1.1 dholland int 2102 1.1 dholland set_is_source(const char *set_name) { 2103 1.1 dholland int len = strlen(set_name); 2104 1.1 dholland return len >= 3 && memcmp(set_name + len - 3, "src", 3) == 0; 2105 1.1 dholland } 2106 1.1 dholland 2107 1.1 dholland const char * 2108 1.1 dholland set_dir_for_set(const char *set_name) { 2109 1.1 dholland if (strcmp(set_name, "pkgsrc") == 0) 2110 1.1 dholland return pkgsrc_dir; 2111 1.1 dholland return set_is_source(set_name) ? set_dir_src : set_dir_bin; 2112 1.1 dholland } 2113 1.1 dholland 2114 1.1 dholland const char * 2115 1.1 dholland ext_dir_for_set(const char *set_name) { 2116 1.1 dholland if (strcmp(set_name, "pkgsrc") == 0) 2117 1.1 dholland return ext_dir_pkgsrc; 2118 1.1 dholland return set_is_source(set_name) ? ext_dir_src : ext_dir_bin; 2119 1.1 dholland } 2120 1.1 dholland 2121 1.2 martin void 2122 1.2 martin do_coloring(unsigned int fg, unsigned int bg) { 2123 1.2 martin if (bg > COLOR_WHITE) 2124 1.2 martin bg = COLOR_BLUE; 2125 1.2 martin if (fg > COLOR_WHITE) 2126 1.2 martin fg = COLOR_WHITE; 2127 1.2 martin if (fg != bg && has_colors()) { 2128 1.2 martin init_pair(1, fg, bg); 2129 1.2 martin wbkgd(stdscr, COLOR_PAIR(1)); 2130 1.2 martin wbkgd(mainwin, COLOR_PAIR(1)); 2131 1.2 martin wattrset(stdscr, COLOR_PAIR(1)); 2132 1.2 martin wattrset(mainwin, COLOR_PAIR(1)); 2133 1.2 martin } 2134 1.2 martin /* redraw screen */ 2135 1.2 martin touchwin(stdscr); 2136 1.2 martin touchwin(mainwin); 2137 1.2 martin wrefresh(stdscr); 2138 1.2 martin wrefresh(mainwin); 2139 1.2 martin return; 2140 1.2 martin } 2141 1.2 martin 2142 1.2 martin int 2143 1.2 martin set_menu_select(menudesc *m, void *arg) 2144 1.2 martin { 2145 1.2 martin *(int *)arg = m->cursel; 2146 1.2 martin return 1; 2147 1.2 martin } 2148 1.2 martin 2149 1.2 martin /* 2150 1.72 msaitoh * check whether a binary is available somewhere in PATH, 2151 1.2 martin * return 1 if found, 0 if not. 2152 1.2 martin */ 2153 1.22 martin static int 2154 1.2 martin binary_available(const char *prog) 2155 1.2 martin { 2156 1.9 kamil char *p, tmp[MAXPATHLEN], *path = getenv("PATH"), *opath; 2157 1.57 rillig 2158 1.2 martin if (path == NULL) 2159 1.2 martin return access(prog, X_OK) == 0; 2160 1.2 martin path = strdup(path); 2161 1.2 martin if (path == NULL) 2162 1.2 martin return 0; 2163 1.9 kamil 2164 1.9 kamil opath = path; 2165 1.9 kamil 2166 1.2 martin while ((p = strsep(&path, ":")) != NULL) { 2167 1.2 martin if (strlcpy(tmp, p, MAXPATHLEN) >= MAXPATHLEN) 2168 1.2 martin continue; 2169 1.2 martin if (strlcat(tmp, "/", MAXPATHLEN) >= MAXPATHLEN) 2170 1.2 martin continue; 2171 1.2 martin if (strlcat(tmp, prog, MAXPATHLEN) >= MAXPATHLEN) 2172 1.2 martin continue; 2173 1.2 martin if (access(tmp, X_OK) == 0) { 2174 1.9 kamil free(opath); 2175 1.2 martin return 1; 2176 1.2 martin } 2177 1.2 martin } 2178 1.9 kamil free(opath); 2179 1.2 martin return 0; 2180 1.2 martin } 2181 1.2 martin 2182 1.5 christos const char * 2183 1.5 christos safectime(time_t *t) 2184 1.5 christos { 2185 1.5 christos const char *s = ctime(t); 2186 1.5 christos if (s != NULL) 2187 1.5 christos return s; 2188 1.5 christos 2189 1.5 christos // Debugging. 2190 1.5 christos fprintf(stderr, "Can't convert to localtime 0x%jx (%s)\n", 2191 1.5 christos (intmax_t)*t, strerror(errno)); 2192 1.5 christos /*123456789012345678901234*/ 2193 1.5 christos return "preposterous clock time\n"; 2194 1.5 christos } 2195 1.6 martin 2196 1.6 martin int 2197 1.7 martin ask_yesno(const char* msgtxt) 2198 1.6 martin { 2199 1.6 martin arg_rv p; 2200 1.6 martin 2201 1.8 joerg p.arg = __UNCONST(msgtxt); 2202 1.6 martin p.rv = -1; 2203 1.6 martin 2204 1.6 martin process_menu(MENU_yesno, &p); 2205 1.6 martin return p.rv; 2206 1.6 martin } 2207 1.6 martin 2208 1.6 martin int 2209 1.7 martin ask_noyes(const char *msgtxt) 2210 1.6 martin { 2211 1.6 martin arg_rv p; 2212 1.6 martin 2213 1.8 joerg p.arg = __UNCONST(msgtxt); 2214 1.6 martin p.rv = -1; 2215 1.6 martin 2216 1.6 martin process_menu(MENU_noyes, &p); 2217 1.6 martin return p.rv; 2218 1.6 martin } 2219 1.12 martin 2220 1.22 martin int 2221 1.22 martin ask_reedit(const struct disk_partitions *parts) 2222 1.22 martin { 2223 1.22 martin const char *args[2]; 2224 1.22 martin arg_rep_int arg; 2225 1.22 martin 2226 1.22 martin args[0] = msg_string(parts->pscheme->name); 2227 1.22 martin args[1] = msg_string(parts->pscheme->short_name); 2228 1.22 martin arg.args.argv = args; 2229 1.22 martin arg.args.argc = 2; 2230 1.22 martin arg.rv = 0; 2231 1.22 martin process_menu(MENU_reedit, &arg); 2232 1.22 martin 2233 1.22 martin return arg.rv; 2234 1.22 martin } 2235 1.22 martin 2236 1.12 martin bool 2237 1.12 martin use_tgz_for_set(const char *set_name) 2238 1.12 martin { 2239 1.12 martin const struct distinfo *dist; 2240 1.57 rillig 2241 1.12 martin for (dist = dist_list; dist->set != SET_LAST; dist++) { 2242 1.12 martin if (dist->name == NULL) 2243 1.12 martin continue; 2244 1.12 martin if (strcmp(set_name, dist->name) == 0) 2245 1.12 martin return dist->force_tgz; 2246 1.12 martin } 2247 1.12 martin 2248 1.13 martin return true; 2249 1.12 martin } 2250 1.12 martin 2251 1.12 martin /* Return the postfix used for a given set */ 2252 1.13 martin const char * 2253 1.13 martin set_postfix(const char *set_name) 2254 1.12 martin { 2255 1.12 martin return use_tgz_for_set(set_name) ? dist_tgz_postfix : dist_postfix; 2256 1.12 martin } 2257 1.12 martin 2258 1.17 martin /* 2259 1.18 martin * Replace positional arguments (encoded as $0 .. $N) in the string 2260 1.18 martin * passed by the contents of the passed argument array. 2261 1.18 martin * Caller must free() the result string. 2262 1.17 martin */ 2263 1.18 martin char* 2264 1.18 martin str_arg_subst(const char *src, size_t argc, const char **argv) 2265 1.17 martin { 2266 1.18 martin const char *p, *last; 2267 1.17 martin char *out, *t; 2268 1.17 martin size_t len; 2269 1.17 martin 2270 1.17 martin len = strlen(src); 2271 1.17 martin for (p = strchr(src, '$'); p; p = strchr(p+1, '$')) { 2272 1.17 martin char *endp = NULL; 2273 1.17 martin size_t n; 2274 1.17 martin int e; 2275 1.17 martin 2276 1.17 martin /* $ followed by a correct numeric position? */ 2277 1.17 martin n = strtou(p+1, &endp, 10, 0, INT_MAX, &e); 2278 1.17 martin if ((e == 0 || e == ENOTSUP) && n < argc) { 2279 1.18 martin len += strlen(argv[n]); 2280 1.17 martin len -= endp-p; 2281 1.17 martin p = endp-1; 2282 1.17 martin } 2283 1.17 martin } 2284 1.17 martin 2285 1.17 martin out = malloc(len+1); 2286 1.18 martin if (out == NULL) 2287 1.18 martin return NULL; 2288 1.17 martin 2289 1.17 martin t = out; 2290 1.17 martin for (last = src, p = strchr(src, '$'); p; p = strchr(p+1, '$')) { 2291 1.17 martin char *endp = NULL; 2292 1.17 martin size_t n; 2293 1.17 martin int e; 2294 1.17 martin 2295 1.17 martin /* $ followed by a correct numeric position? */ 2296 1.17 martin n = strtou(p+1, &endp, 10, 0, INT_MAX, &e); 2297 1.17 martin if ((e == 0 || e == ENOTSUP) && n < argc) { 2298 1.17 martin size_t l = p-last; 2299 1.17 martin memcpy(t, last, l); 2300 1.17 martin t += l; 2301 1.18 martin strcpy(t, argv[n]); 2302 1.18 martin t += strlen(argv[n]); 2303 1.17 martin last = endp; 2304 1.17 martin } 2305 1.17 martin } 2306 1.17 martin if (*last) { 2307 1.17 martin strcpy(t, last); 2308 1.17 martin t += strlen(last); 2309 1.17 martin } else { 2310 1.17 martin *t = 0; 2311 1.17 martin } 2312 1.17 martin assert((size_t)(t-out) == len); 2313 1.17 martin 2314 1.18 martin return out; 2315 1.18 martin } 2316 1.18 martin 2317 1.18 martin /* 2318 1.22 martin * Does this string have any positional args that need expanding? 2319 1.22 martin */ 2320 1.22 martin bool 2321 1.22 martin needs_expanding(const char *src, size_t argc) 2322 1.22 martin { 2323 1.22 martin const char *p; 2324 1.22 martin 2325 1.22 martin for (p = strchr(src, '$'); p; p = strchr(p+1, '$')) { 2326 1.22 martin char *endp = NULL; 2327 1.22 martin size_t n; 2328 1.22 martin int e; 2329 1.22 martin 2330 1.22 martin /* $ followed by a correct numeric position? */ 2331 1.22 martin n = strtou(p+1, &endp, 10, 0, INT_MAX, &e); 2332 1.22 martin if ((e == 0 || e == ENOTSUP) && n < argc) 2333 1.22 martin return true; 2334 1.22 martin } 2335 1.22 martin return false; 2336 1.22 martin } 2337 1.22 martin 2338 1.22 martin /* 2339 1.18 martin * Replace positional arguments (encoded as $0 .. $N) in the 2340 1.22 martin * message by the strings passed as ... and call outfunc 2341 1.22 martin * with the result. 2342 1.18 martin */ 2343 1.22 martin static void 2344 1.24 christos msg_display_subst_internal(void (*outfunc)(msg), 2345 1.24 christos const char *master, size_t argc, va_list ap) 2346 1.18 martin { 2347 1.18 martin const char **args, **arg; 2348 1.18 martin char *out; 2349 1.18 martin 2350 1.24 christos args = calloc(argc, sizeof(*args)); 2351 1.18 martin if (args == NULL) 2352 1.18 martin return; 2353 1.18 martin 2354 1.18 martin arg = args; 2355 1.18 martin for (size_t i = 0; i < argc; i++) 2356 1.18 martin *arg++ = va_arg(ap, const char*); 2357 1.17 martin 2358 1.18 martin out = str_arg_subst(msg_string(master), argc, args); 2359 1.18 martin if (out != NULL) { 2360 1.22 martin outfunc(out); 2361 1.18 martin free(out); 2362 1.18 martin } 2363 1.17 martin free(args); 2364 1.17 martin } 2365 1.17 martin 2366 1.22 martin /* 2367 1.22 martin * Replace positional arguments (encoded as $0 .. $N) in the 2368 1.22 martin * message by the strings passed as ... 2369 1.22 martin */ 2370 1.22 martin void 2371 1.22 martin msg_display_subst(const char *master, size_t argc, ...) 2372 1.22 martin { 2373 1.22 martin va_list ap; 2374 1.22 martin 2375 1.22 martin va_start(ap, argc); 2376 1.22 martin msg_display_subst_internal(msg_display, master, argc, ap); 2377 1.22 martin va_end(ap); 2378 1.22 martin } 2379 1.22 martin 2380 1.22 martin /* 2381 1.22 martin * Same as above, but add to message instead of starting a new one 2382 1.22 martin */ 2383 1.22 martin void 2384 1.22 martin msg_display_add_subst(const char *master, size_t argc, ...) 2385 1.22 martin { 2386 1.22 martin va_list ap; 2387 1.22 martin 2388 1.22 martin va_start(ap, argc); 2389 1.22 martin msg_display_subst_internal(msg_display_add, master, argc, ap); 2390 1.22 martin va_end(ap); 2391 1.22 martin } 2392 1.22 martin 2393 1.22 martin /* initialize have_* variables */ 2394 1.22 martin void 2395 1.68 tsutsui check_available_binaries(void) 2396 1.22 martin { 2397 1.22 martin static int did_test = false; 2398 1.22 martin 2399 1.22 martin if (did_test) return; 2400 1.22 martin did_test = 1; 2401 1.22 martin 2402 1.22 martin have_raid = binary_available("raidctl"); 2403 1.22 martin have_vnd = binary_available("vndconfig"); 2404 1.22 martin have_cgd = binary_available("cgdconfig"); 2405 1.22 martin have_lvm = binary_available("lvm"); 2406 1.22 martin have_gpt = binary_available("gpt"); 2407 1.22 martin have_dk = binary_available("dkctl"); 2408 1.22 martin } 2409 1.22 martin 2410 1.22 martin /* 2411 1.22 martin * Wait for enter and immediately clear the screen after user response 2412 1.22 martin * (in case some longer action follows, so the user has instant feedback) 2413 1.22 martin */ 2414 1.22 martin void 2415 1.22 martin hit_enter_to_continue(const char *prompt, const char *title) 2416 1.22 martin { 2417 1.22 martin if (prompt != NULL) 2418 1.22 martin msg_display(prompt); 2419 1.22 martin process_menu(MENU_ok, __UNCONST(title)); 2420 1.22 martin msg_clear(); 2421 1.22 martin wrefresh(mainwin); 2422 1.22 martin } 2423 1.22 martin 2424 1.22 martin /* 2425 1.22 martin * On auto pilot: 2426 1.22 martin * convert an existing set of partitions ot a list of part_usage_info 2427 1.22 martin * so that we "want" exactly what is there already. 2428 1.22 martin */ 2429 1.22 martin static bool 2430 1.22 martin usage_info_list_from_parts(struct part_usage_info **list, size_t *count, 2431 1.22 martin struct disk_partitions *parts) 2432 1.22 martin { 2433 1.22 martin struct disk_part_info info; 2434 1.22 martin part_id pno; 2435 1.22 martin size_t no, num; 2436 1.22 martin 2437 1.22 martin num = 0; 2438 1.22 martin for (pno = 0; pno < parts->num_part; pno++) { 2439 1.22 martin if (!parts->pscheme->get_part_info(parts, pno, &info)) 2440 1.22 martin continue; 2441 1.22 martin num++; 2442 1.22 martin } 2443 1.22 martin 2444 1.22 martin *list = calloc(num, sizeof(**list)); 2445 1.22 martin if (*list == NULL) 2446 1.22 martin return false; 2447 1.22 martin 2448 1.22 martin *count = num; 2449 1.22 martin for (no = pno = 0; pno < parts->num_part && no < num; pno++) { 2450 1.22 martin if (!parts->pscheme->get_part_info(parts, pno, &info)) 2451 1.22 martin continue; 2452 1.22 martin (*list)[no].size = info.size; 2453 1.22 martin if (info.last_mounted != NULL && *info.last_mounted != 0) { 2454 1.22 martin strlcpy((*list)[no].mount, info.last_mounted, 2455 1.22 martin sizeof((*list)[no].mount)); 2456 1.22 martin (*list)[no].instflags |= PUIINST_MOUNT; 2457 1.22 martin } 2458 1.22 martin (*list)[no].parts = parts; 2459 1.22 martin (*list)[no].cur_part_id = pno; 2460 1.22 martin (*list)[no].cur_start = info.start; 2461 1.22 martin (*list)[no].cur_flags = info.flags; 2462 1.22 martin (*list)[no].type = info.nat_type->generic_ptype; 2463 1.22 martin if ((*list)[no].type == PT_swap) { 2464 1.22 martin (*list)[no].fs_type = FS_SWAP; 2465 1.22 martin (*list)[no].fs_version = 0; 2466 1.22 martin } else { 2467 1.22 martin (*list)[no].fs_type = info.fs_type; 2468 1.22 martin (*list)[no].fs_version = info.fs_sub_type; 2469 1.22 martin } 2470 1.48 martin (*list)[no].fs_opt1 = info.fs_opt1; 2471 1.48 martin (*list)[no].fs_opt2 = info.fs_opt2; 2472 1.48 martin (*list)[no].fs_opt3 = info.fs_opt3; 2473 1.22 martin no++; 2474 1.22 martin } 2475 1.22 martin return true; 2476 1.22 martin } 2477 1.22 martin 2478 1.22 martin bool 2479 1.70 martin empty_usage_set_from_parts(struct partition_usage_set *wanted, 2480 1.70 martin struct disk_partitions *parts) 2481 1.70 martin { 2482 1.71 martin usage_set_from_parts(wanted, parts); 2483 1.70 martin return true; 2484 1.70 martin } 2485 1.70 martin 2486 1.70 martin bool 2487 1.22 martin usage_set_from_parts(struct partition_usage_set *wanted, 2488 1.22 martin struct disk_partitions *parts) 2489 1.22 martin { 2490 1.22 martin memset(wanted, 0, sizeof(*wanted)); 2491 1.22 martin wanted->parts = parts; 2492 1.22 martin 2493 1.22 martin return usage_info_list_from_parts(&wanted->infos, &wanted->num, parts); 2494 1.22 martin } 2495 1.22 martin 2496 1.69 martin bool 2497 1.69 martin usage_set_from_install_desc(struct partition_usage_set *pset, 2498 1.69 martin const struct install_partition_desc *install, 2499 1.69 martin struct disk_partitions *parts) 2500 1.69 martin { 2501 1.69 martin size_t cnt, i; 2502 1.69 martin 2503 1.69 martin memset(pset, 0, sizeof(*pset)); 2504 1.69 martin pset->parts = parts; 2505 1.69 martin 2506 1.69 martin if (!install->infos || !install->num) 2507 1.69 martin return false; 2508 1.69 martin 2509 1.69 martin for (cnt = 0, i = 0; i < install->num; i++) { 2510 1.69 martin if (install->infos[i].parts != parts) 2511 1.69 martin continue; 2512 1.69 martin cnt++; 2513 1.69 martin } 2514 1.69 martin if (!cnt) 2515 1.69 martin return false; 2516 1.69 martin pset->num = cnt; 2517 1.69 martin pset->infos = calloc(cnt, sizeof(*pset->infos)); 2518 1.69 martin if (!pset->infos) 2519 1.69 martin return false; 2520 1.69 martin for (cnt = 0, i = 0; i < install->num; i++) { 2521 1.69 martin if (install->infos[i].parts != parts) 2522 1.69 martin continue; 2523 1.69 martin pset->infos[cnt] = install->infos[i]; 2524 1.69 martin cnt++; 2525 1.69 martin } 2526 1.69 martin return true; 2527 1.69 martin } 2528 1.69 martin 2529 1.69 martin bool 2530 1.69 martin merge_usage_set_into_install_desc(struct install_partition_desc *install, 2531 1.69 martin const struct partition_usage_set *pset) 2532 1.69 martin { 2533 1.69 martin // XXX 2534 1.69 martin return false; 2535 1.69 martin } 2536 1.69 martin 2537 1.35 martin struct disk_partitions * 2538 1.35 martin get_inner_parts(struct disk_partitions *parts) 2539 1.22 martin { 2540 1.23 martin daddr_t start, size; 2541 1.23 martin part_id pno; 2542 1.23 martin struct disk_part_info info; 2543 1.23 martin 2544 1.35 martin if (parts->pscheme->secondary_scheme == NULL) 2545 1.35 martin return NULL; 2546 1.22 martin 2547 1.35 martin start = -1; 2548 1.35 martin size = -1; 2549 1.35 martin if (parts->pscheme->guess_install_target == NULL || 2550 1.35 martin !parts->pscheme->guess_install_target(parts, &start, &size)) { 2551 1.35 martin for (pno = 0; pno < parts->num_part; pno++) { 2552 1.35 martin if (!parts->pscheme->get_part_info(parts, pno, &info)) 2553 1.35 martin continue; 2554 1.35 martin if (!(info.flags & PTI_SEC_CONTAINER)) 2555 1.35 martin continue; 2556 1.35 martin start = info.start; 2557 1.35 martin size = info.size; 2558 1.23 martin } 2559 1.23 martin } 2560 1.23 martin 2561 1.35 martin if (size > 0) 2562 1.35 martin return parts->pscheme->secondary_partitions(parts, start, 2563 1.35 martin false); 2564 1.35 martin 2565 1.35 martin return NULL; 2566 1.35 martin } 2567 1.35 martin 2568 1.35 martin bool 2569 1.35 martin install_desc_from_parts(struct install_partition_desc *install, 2570 1.35 martin struct disk_partitions *parts) 2571 1.35 martin { 2572 1.35 martin struct disk_partitions *inner_parts; 2573 1.35 martin 2574 1.35 martin memset(install, 0, sizeof(*install)); 2575 1.35 martin inner_parts = get_inner_parts(parts); 2576 1.35 martin if (inner_parts != NULL) 2577 1.35 martin parts = inner_parts; 2578 1.35 martin 2579 1.22 martin return usage_info_list_from_parts(&install->infos, &install->num, 2580 1.22 martin parts); 2581 1.22 martin } 2582 1.22 martin 2583 1.22 martin void 2584 1.22 martin free_usage_set(struct partition_usage_set *wanted) 2585 1.22 martin { 2586 1.35 martin /* XXX - free parts? free clone src? */ 2587 1.46 martin free(wanted->write_back); 2588 1.22 martin free(wanted->menu_opts); 2589 1.22 martin free(wanted->infos); 2590 1.22 martin } 2591 1.22 martin 2592 1.22 martin void 2593 1.22 martin free_install_desc(struct install_partition_desc *install) 2594 1.22 martin { 2595 1.35 martin size_t i, j; 2596 1.35 martin 2597 1.64 martin #ifndef NO_CLONES 2598 1.35 martin for (i = 0; i < install->num; i++) { 2599 1.35 martin struct selected_partitions *src = install->infos[i].clone_src; 2600 1.35 martin if (!(install->infos[i].flags & PUIFLG_CLONE_PARTS) || 2601 1.35 martin src == NULL) 2602 1.35 martin continue; 2603 1.35 martin free_selected_partitions(src); 2604 1.35 martin for (j = i+1; j < install->num; j++) 2605 1.35 martin if (install->infos[j].clone_src == src) 2606 1.57 rillig install->infos[j].clone_src = NULL; 2607 1.35 martin } 2608 1.37 martin #endif 2609 1.64 martin 2610 1.64 martin for (i = 0; i < install->num; i++) { 2611 1.64 martin struct disk_partitions * parts = install->infos[i].parts; 2612 1.64 martin 2613 1.64 martin if (parts == NULL) 2614 1.64 martin continue; 2615 1.64 martin 2616 1.64 martin if (parts->pscheme->free) 2617 1.64 martin parts->pscheme->free(parts); 2618 1.64 martin 2619 1.64 martin /* NULL all other references to this parts */ 2620 1.64 martin for (j = i+1; j < install->num; j++) 2621 1.64 martin if (install->infos[j].parts == parts) 2622 1.64 martin install->infos[j].parts = NULL; 2623 1.64 martin } 2624 1.64 martin 2625 1.46 martin free(install->write_back); 2626 1.22 martin free(install->infos); 2627 1.22 martin } 2628 1.22 martin 2629 1.41 martin #ifdef MD_MAY_SWAP_TO 2630 1.41 martin bool 2631 1.41 martin may_swap_if_not_sdmmc(const char *disk) 2632 1.41 martin { 2633 1.41 martin int fd, res; 2634 1.41 martin prop_dictionary_t command_dict, args_dict, results_dict, data_dict; 2635 1.41 martin prop_string_t string; 2636 1.41 martin prop_number_t number; 2637 1.41 martin const char *parent = ""; 2638 1.41 martin 2639 1.41 martin fd = open(DRVCTLDEV, O_RDONLY, 0); 2640 1.41 martin if (fd == -1) 2641 1.41 martin return true; 2642 1.41 martin 2643 1.41 martin command_dict = prop_dictionary_create(); 2644 1.41 martin args_dict = prop_dictionary_create(); 2645 1.41 martin 2646 1.55 martin string = prop_string_create_nocopy("get-properties"); 2647 1.41 martin prop_dictionary_set(command_dict, "drvctl-command", string); 2648 1.41 martin prop_object_release(string); 2649 1.41 martin 2650 1.55 martin string = prop_string_create_copy(disk); 2651 1.41 martin prop_dictionary_set(args_dict, "device-name", string); 2652 1.41 martin prop_object_release(string); 2653 1.41 martin 2654 1.41 martin prop_dictionary_set(command_dict, "drvctl-arguments", 2655 1.41 martin args_dict); 2656 1.41 martin prop_object_release(args_dict); 2657 1.41 martin 2658 1.41 martin res = prop_dictionary_sendrecv_ioctl(command_dict, fd, 2659 1.41 martin DRVCTLCOMMAND, &results_dict); 2660 1.41 martin prop_object_release(command_dict); 2661 1.41 martin close(fd); 2662 1.41 martin if (res) 2663 1.41 martin return true; 2664 1.41 martin 2665 1.41 martin number = prop_dictionary_get(results_dict, "drvctl-error"); 2666 1.55 martin if (prop_number_signed_value(number) == 0) { 2667 1.41 martin data_dict = prop_dictionary_get(results_dict, 2668 1.41 martin "drvctl-result-data"); 2669 1.41 martin if (data_dict != NULL) { 2670 1.41 martin string = prop_dictionary_get(data_dict, 2671 1.41 martin "device-parent"); 2672 1.41 martin if (string != NULL) 2673 1.55 martin parent = prop_string_value(string); 2674 1.41 martin } 2675 1.41 martin } 2676 1.41 martin 2677 1.41 martin prop_object_release(results_dict); 2678 1.41 martin 2679 1.41 martin if (parent == NULL) 2680 1.41 martin return true; 2681 1.41 martin 2682 1.41 martin return strncmp(parent, "sdmmc", 5) != 0; 2683 1.41 martin } 2684 1.41 martin #endif 2685