/* * state_create_subpartitions: let the user specify what subpartitions they * want on the disk, how large each should be, and where it should be mounted. */ void state_create_subpartitions(struct i_fn_args *a) { struct commands *cmds; if (measure_activated_swap_from_slice(a, storage_get_selected_disk(a->s), storage_get_selected_slice(a->s)) > 0) { if (swapoff_all(a) == NULL) { inform(a->c, _("Warning: swap could not be turned off.")); state = disk_get_formatted(storage_get_selected_disk(a->s)) ? state_select_disk : state_select_slice; return; } } cmds = commands_new(); /* * Auto-disklabel the slice. * NB: one cannot use "/dev/adXsY" here - * it must be in the form "adXsY". */ command_add(cmds, "%s%s -W %s", a->os_root, cmd_name(a, "DISKLABEL64"), slice_get_device_name(storage_get_selected_slice(a->s))); command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16", a->os_root, cmd_name(a, "DD"), slice_get_device_name(storage_get_selected_slice(a->s))); command_add(cmds, "%s%s -B -r -w %s auto", a->os_root, cmd_name(a, "DISKLABEL64"), slice_get_device_name(storage_get_selected_slice(a->s))); commands_execute(a, cmds); commands_free(cmds); if (use_hammer) fn_create_subpartitions_hammer(a); else fn_create_subpartitions_ufs(a); if (a->result) { state = state_install_os; } else { state = disk_get_formatted(storage_get_selected_disk(a->s)) ? state_select_disk : state_select_slice; } }
/* * state_format_disk: ask the user if they wish to format the disk they * selected. */ void state_format_disk(struct i_fn_args *a) { switch (dfui_be_present_dialog(a->c, _("How Much Disk?"), _("Use Entire Disk|Use Part of Disk|Return to Select Disk"), _("Select how much of this disk you want to use for %s.\n\n%s"), OPERATING_SYSTEM_NAME, disk_get_desc(storage_get_selected_disk(a->s)))) { case 1: /* Entire Disk */ if (measure_activated_swap_from_disk(a, storage_get_selected_disk(a->s)) > 0) { if (swapoff_all(a) == NULL) { inform(a->c, _("Warning: swap could not be turned off.")); state = state_select_disk; return; } } fn_format_disk(a); if (a->result) state = state_ask_fs; else state = state_format_disk; break; case 2: /* Part of Disk */ state = state_select_slice; break; case 3: /* Return */ state = state_select_disk; break; default: abort_backend(); break; } }
int main(int argc, char *argv[]) { bool need_umount, need_swapoff, need_loop_detach, need_dm_detach; bool in_container, use_watchdog = false; _cleanup_free_ char *cgroup = NULL; char *arguments[3]; unsigned retries; int cmd, r; static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL}; log_parse_environment(); r = parse_argv(argc, argv); if (r < 0) goto error; /* journald will die if not gone yet. The log target defaults * to console, but may have been changed by command line options. */ log_close_console(); /* force reopen of /dev/console */ log_open(); umask(0022); if (getpid() != 1) { log_error("Not executed by init (PID 1)."); r = -EPERM; goto error; } if (streq(arg_verb, "reboot")) cmd = RB_AUTOBOOT; else if (streq(arg_verb, "poweroff")) cmd = RB_POWER_OFF; else if (streq(arg_verb, "halt")) cmd = RB_HALT_SYSTEM; else if (streq(arg_verb, "kexec")) cmd = LINUX_REBOOT_CMD_KEXEC; else if (streq(arg_verb, "exit")) cmd = 0; /* ignored, just checking that arg_verb is valid */ else { r = -EINVAL; log_error("Unknown action '%s'.", arg_verb); goto error; } cg_get_root_path(&cgroup); use_watchdog = !!getenv("WATCHDOG_USEC"); /* lock us into memory */ mlockall(MCL_CURRENT|MCL_FUTURE); log_info("Sending SIGTERM to remaining processes..."); broadcast_signal(SIGTERM, true, true); log_info("Sending SIGKILL to remaining processes..."); broadcast_signal(SIGKILL, true, false); in_container = detect_container() > 0; need_umount = !in_container; need_swapoff = !in_container; need_loop_detach = !in_container; need_dm_detach = !in_container; /* Unmount all mountpoints, swaps, and loopback devices */ for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) { bool changed = false; if (use_watchdog) watchdog_ping(); /* Let's trim the cgroup tree on each iteration so that we leave an empty cgroup tree around, so that container managers get a nice notify event when we are down */ if (cgroup) cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false); if (need_umount) { log_info("Unmounting file systems."); r = umount_all(&changed); if (r == 0) { need_umount = false; log_info("All filesystems unmounted."); } else if (r > 0) log_info("Not all file systems unmounted, %d left.", r); else log_error_errno(r, "Failed to unmount file systems: %m"); } if (need_swapoff) { log_info("Deactivating swaps."); r = swapoff_all(&changed); if (r == 0) { need_swapoff = false; log_info("All swaps deactivated."); } else if (r > 0) log_info("Not all swaps deactivated, %d left.", r); else log_error_errno(r, "Failed to deactivate swaps: %m"); } if (need_loop_detach) { log_info("Detaching loop devices."); r = loopback_detach_all(&changed); if (r == 0) { need_loop_detach = false; log_info("All loop devices detached."); } else if (r > 0) log_info("Not all loop devices detached, %d left.", r); else log_error_errno(r, "Failed to detach loop devices: %m"); } if (need_dm_detach) { log_info("Detaching DM devices."); r = dm_detach_all(&changed); if (r == 0) { need_dm_detach = false; log_info("All DM devices detached."); } else if (r > 0) log_info("Not all DM devices detached, %d left.", r); else log_error_errno(r, "Failed to detach DM devices: %m"); } if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) { if (retries > 0) log_info("All filesystems, swaps, loop devices, DM devices detached."); /* Yay, done */ goto initrd_jump; } /* If in this iteration we didn't manage to * unmount/deactivate anything, we simply give up */ if (!changed) { log_info("Cannot finalize remaining%s%s%s%s continuing.", need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); goto initrd_jump; } log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.", retries + 1, need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); } log_error("Too many iterations, giving up."); initrd_jump: arguments[0] = NULL; arguments[1] = arg_verb; arguments[2] = NULL; execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments); if (!in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0) { r = switch_root_initramfs(); if (r >= 0) { argv[0] = (char*) "/shutdown"; setsid(); make_console_stdio(); log_info("Successfully changed into root pivot.\n" "Returning to initrd..."); execv("/shutdown", argv); log_error_errno(errno, "Failed to execute shutdown binary: %m"); } else log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m"); } if (need_umount || need_swapoff || need_loop_detach || need_dm_detach) log_error("Failed to finalize %s%s%s%s ignoring", need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); /* The kernel will automaticall flush ATA disks and suchlike * on reboot(), but the file systems need to be synce'd * explicitly in advance. So let's do this here, but not * needlessly slow down containers. */ if (!in_container) sync(); if (streq(arg_verb, "exit")) { if (in_container) exit(arg_exit_code); else { /* We cannot exit() on the host, fallback on another * method. */ cmd = RB_POWER_OFF; } } switch (cmd) { case LINUX_REBOOT_CMD_KEXEC: if (!in_container) { /* We cheat and exec kexec to avoid doing all its work */ pid_t pid; log_info("Rebooting with kexec."); pid = fork(); if (pid < 0) log_error_errno(errno, "Failed to fork: %m"); else if (pid == 0) { const char * const args[] = { KEXEC, "-e", NULL }; /* Child */ execv(args[0], (char * const *) args); _exit(EXIT_FAILURE); } else wait_for_terminate_and_warn("kexec", pid, true); } cmd = RB_AUTOBOOT; /* Fall through */ case RB_AUTOBOOT: if (!in_container) { _cleanup_free_ char *param = NULL; if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { log_info("Rebooting with argument '%s'.", param); syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); } } log_info("Rebooting."); break; case RB_POWER_OFF: log_info("Powering off."); break; case RB_HALT_SYSTEM: log_info("Halting system."); break; default: assert_not_reached("Unknown magic"); } reboot(cmd); if (errno == EPERM && in_container) { /* If we are in a container, and we lacked * CAP_SYS_BOOT just exit, this will kill our * container for good. */ log_info("Exiting container."); exit(0); } r = log_error_errno(errno, "Failed to invoke reboot(): %m"); error: log_emergency_errno(r, "Critical error while doing system shutdown: %m"); freeze(); }
int main(int argc, char *argv[]) { int cmd, r; unsigned retries; bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; bool in_container, use_watchdog = false; char *arguments[3]; log_parse_environment(); log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */ log_open(); umask(0022); if (getpid() != 1) { log_error("Not executed by init (pid 1)."); r = -EPERM; goto error; } if (argc != 2) { log_error("Invalid number of arguments."); r = -EINVAL; goto error; } in_container = detect_container(NULL) > 0; if (streq(argv[1], "reboot")) cmd = RB_AUTOBOOT; else if (streq(argv[1], "poweroff")) cmd = RB_POWER_OFF; else if (streq(argv[1], "halt")) cmd = RB_HALT_SYSTEM; else if (streq(argv[1], "kexec")) cmd = LINUX_REBOOT_CMD_KEXEC; else { log_error("Unknown action '%s'.", argv[1]); r = -EINVAL; goto error; } use_watchdog = !!getenv("WATCHDOG_USEC"); /* lock us into memory */ mlockall(MCL_CURRENT|MCL_FUTURE); log_info("Sending SIGTERM to remaining processes..."); broadcast_signal(SIGTERM, true); log_info("Sending SIGKILL to remaining processes..."); broadcast_signal(SIGKILL, true); if (in_container) { need_swapoff = false; need_dm_detach = false; need_loop_detach = false; } /* Unmount all mountpoints, swaps, and loopback devices */ for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) { bool changed = false; if (use_watchdog) watchdog_ping(); if (need_umount) { log_info("Unmounting file systems."); r = umount_all(&changed); if (r == 0) need_umount = false; else if (r > 0) log_info("Not all file systems unmounted, %d left.", r); else log_error("Failed to unmount file systems: %s", strerror(-r)); } if (need_swapoff) { log_info("Disabling swaps."); r = swapoff_all(&changed); if (r == 0) need_swapoff = false; else if (r > 0) log_info("Not all swaps are turned off, %d left.", r); else log_error("Failed to turn off swaps: %s", strerror(-r)); } if (need_loop_detach) { log_info("Detaching loop devices."); r = loopback_detach_all(&changed); if (r == 0) need_loop_detach = false; else if (r > 0) log_info("Not all loop devices detached, %d left.", r); else log_error("Failed to detach loop devices: %s", strerror(-r)); } if (need_dm_detach) { log_info("Detaching DM devices."); r = dm_detach_all(&changed); if (r == 0) need_dm_detach = false; else if (r > 0) log_warning("Not all DM devices detached, %d left.", r); else log_error("Failed to detach DM devices: %s", strerror(-r)); } if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) { if (retries > 0) log_info("All filesystems, swaps, loop devices, DM devices detached."); /* Yay, done */ break; } /* If in this iteration we didn't manage to * unmount/deactivate anything, we simply give up */ if (!changed) { log_error("Cannot finalize remaining file systems and devices, giving up."); break; } log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1); } if (retries >= FINALIZE_ATTEMPTS) log_error("Too many iterations, giving up."); arguments[0] = NULL; arguments[1] = argv[1]; arguments[2] = NULL; execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments); if (!in_container && access("/run/initramfs/shutdown", X_OK) == 0) { if (prepare_new_root() >= 0 && pivot_to_new_root() >= 0) { execv("/shutdown", argv); log_error("Failed to execute shutdown binary: %m"); } } if (cmd == LINUX_REBOOT_CMD_KEXEC) { if (!in_container) { /* We cheat and exec kexec to avoid doing all its work */ pid_t pid = fork(); if (pid < 0) log_error("Could not fork: %m. Falling back to normal reboot."); else if (pid > 0) { wait_for_terminate_and_warn("kexec", pid); log_warning("kexec failed. Falling back to normal reboot."); } else { /* Child */ const char *args[3] = { "/sbin/kexec", "-e", NULL }; execv(args[0], (char * const *) args); return EXIT_FAILURE; } } cmd = RB_AUTOBOOT; } reboot(cmd); if (errno == EPERM && in_container) { /* If we are in a container, and we lacked * CAP_SYS_BOOT just exit, this will kill our * container for good. */ log_error("Exiting container."); exit(0); } log_error("Failed to invoke reboot(): %m"); r = -errno; error: log_error("Critical error while doing system shutdown: %s", strerror(-r)); freeze(); return EXIT_FAILURE; }
int main(int argc, char *argv[]) { int status = 0, c; size_t i; static const struct option long_opts[] = { { "all", 0, 0, 'a' }, { "help", 0, 0, 'h' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { NULL, 0, 0, 0 } }; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); while ((c = getopt_long(argc, argv, "ahvVL:U:", long_opts, NULL)) != -1) { switch (c) { case 'a': /* all */ ++all; break; case 'h': /* help */ usage(stdout); break; case 'v': /* be chatty */ ++verbose; break; case 'V': /* version */ printf(UTIL_LINUX_VERSION); return EXIT_SUCCESS; case 'L': add_label(optarg); break; case 'U': add_uuid(optarg); break; case '?': default: usage(stderr); } } argv += optind; if (!all && !numof_labels() && !numof_uuids() && *argv == NULL) usage(stderr); mnt_init_debug(0); mntcache = mnt_new_cache(); for (i = 0; i < numof_labels(); i++) status |= swapoff_by("LABEL", get_label(i), !QUIET); for (i = 0; i < numof_uuids(); i++) status |= swapoff_by("UUID", get_uuid(i), !QUIET); while (*argv != NULL) status |= do_swapoff(*argv++, !QUIET, !CANONIC); if (all) status |= swapoff_all(); free_tables(); mnt_unref_cache(mntcache); return status; }
/* * state_select_slice: ask the user which slice they wish to install * DragonFly on. In order to avoid confusing them, refer to it as * a primary partition, but tell them what BSD has traditionally called * it, too. */ void state_select_slice(struct i_fn_args *a) { char msg_buf[1][1024]; snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Select the existing primary partition (also " "known as a `slice' in the BSD tradition) on " "which to install %s.\n\n" "Note that if you do not have any existing " "primary partitions on this disk, you must " "first create some. This installer does not " "currently have the ability to do this, so " "you will have to exit and run fdisk (in " "DOS or *BSD) or parted (in Linux) to do so."), OPERATING_SYSTEM_NAME); a->short_desc = msg_buf[0]; a->cancel_desc = _("Return to Select Disk"); fn_select_slice(a); if (!a->result || storage_get_selected_slice(a->s) == NULL) { state = state_select_disk; } else { if (measure_activated_swap_from_slice(a, storage_get_selected_disk(a->s), storage_get_selected_slice(a->s)) > 0) { if (swapoff_all(a) == NULL) { inform(a->c, _("Warning: swap could not be turned off.")); state = state_select_slice; return; } } if (slice_get_capacity(storage_get_selected_slice(a->s)) < DISK_MIN) { inform(a->c, _("WARNING: you should have a primary " "partition at least %dM in size, or " "you may encounter problems trying to " "install %s."), DISK_MIN, OPERATING_SYSTEM_NAME); } if (confirm_dangerous_action(a->c, _("WARNING! ALL data in primary partition #%d,\n\n%s\n\non the " "disk\n\n%s\n\n will be IRREVOCABLY ERASED!\n\nAre you " "ABSOLUTELY SURE you wish to take this action? This is " "your LAST CHANCE to cancel!"), slice_get_number(storage_get_selected_slice(a->s)), slice_get_desc(storage_get_selected_slice(a->s)), disk_get_desc(storage_get_selected_disk(a->s)))) { if (!format_slice(a)) { inform(a->c, _("Primary partition #%d was " "not correctly formatted, and may " "now be in an inconsistent state. " "We recommend re-formatting it " "before proceeding."), slice_get_number(storage_get_selected_slice(a->s))); } else { inform(a->c, _("Primary partition #%d was formatted."), slice_get_number(storage_get_selected_slice(a->s))); state = state_ask_fs; } } else { inform(a->c, _("Action cancelled - no primary partitions were formatted.")); state = state_select_slice; } } }
/* * Shutdown the system cleanly to prepare for reboot, halt, or power off. */ void kern_reboot(int howto) { static int first_buf_printf = 1; #if defined(SMP) /* * Bind us to CPU 0 so that all shutdown code runs there. Some * systems don't shutdown properly (i.e., ACPI power off) if we * run on another processor. */ if (!SCHEDULER_STOPPED()) { thread_lock(curthread); sched_bind(curthread, 0); thread_unlock(curthread); KASSERT(PCPU_GET(cpuid) == 0, ("boot: not running on cpu 0")); } #endif /* We're in the process of rebooting. */ rebooting = 1; /* collect extra flags that shutdown_nice might have set */ howto |= shutdown_howto; /* We are out of the debugger now. */ kdb_active = 0; /* * Do any callouts that should be done BEFORE syncing the filesystems. */ EVENTHANDLER_INVOKE(shutdown_pre_sync, howto); /* * Now sync filesystems */ if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) { register struct buf *bp; int iter, nbusy, pbusy; #ifndef PREEMPTION int subiter; #endif waittime = 0; wdog_kern_pat(WD_LASTVAL); sys_sync(curthread, NULL); /* * With soft updates, some buffers that are * written will be remarked as dirty until other * buffers are written. */ for (iter = pbusy = 0; iter < 20; iter++) { nbusy = 0; for (bp = &buf[nbuf]; --bp >= buf; ) if (isbufbusy(bp)) nbusy++; if (nbusy == 0) { if (first_buf_printf) printf("All buffers synced."); break; } if (first_buf_printf) { printf("Syncing disks, buffers remaining... "); first_buf_printf = 0; } printf("%d ", nbusy); if (nbusy < pbusy) iter = 0; pbusy = nbusy; wdog_kern_pat(WD_LASTVAL); sys_sync(curthread, NULL); #ifdef PREEMPTION /* * Drop Giant and spin for a while to allow * interrupt threads to run. */ DROP_GIANT(); DELAY(50000 * iter); PICKUP_GIANT(); #else /* * Drop Giant and context switch several times to * allow interrupt threads to run. */ DROP_GIANT(); for (subiter = 0; subiter < 50 * iter; subiter++) { thread_lock(curthread); mi_switch(SW_VOL, NULL); thread_unlock(curthread); DELAY(1000); } PICKUP_GIANT(); #endif } printf("\n"); /* * Count only busy local buffers to prevent forcing * a fsck if we're just a client of a wedged NFS server */ nbusy = 0; for (bp = &buf[nbuf]; --bp >= buf; ) { if (isbufbusy(bp)) { #if 0 /* XXX: This is bogus. We should probably have a BO_REMOTE flag instead */ if (bp->b_dev == NULL) { TAILQ_REMOVE(&mountlist, bp->b_vp->v_mount, mnt_list); continue; } #endif nbusy++; if (show_busybufs > 0) { printf( "%d: buf:%p, vnode:%p, flags:%0x, blkno:%jd, lblkno:%jd, buflock:", nbusy, bp, bp->b_vp, bp->b_flags, (intmax_t)bp->b_blkno, (intmax_t)bp->b_lblkno); BUF_LOCKPRINTINFO(bp); if (show_busybufs > 1) vn_printf(bp->b_vp, "vnode content: "); } } } if (nbusy) { /* * Failed to sync all blocks. Indicate this and don't * unmount filesystems (thus forcing an fsck on reboot). */ printf("Giving up on %d buffers\n", nbusy); DELAY(5000000); /* 5 seconds */ } else { if (!first_buf_printf) printf("Final sync complete\n"); /* * Unmount filesystems */ if (panicstr == 0) vfs_unmountall(); } swapoff_all(); DELAY(100000); /* wait for console output to finish */ } print_uptime(); cngrab(); /* * Ok, now do things that assume all filesystem activity has * been completed. */ EVENTHANDLER_INVOKE(shutdown_post_sync, howto); if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping) doadump(TRUE); /* Now that we're going to really halt the system... */ EVENTHANDLER_INVOKE(shutdown_final, howto); for(;;) ; /* safety against shutdown_reset not working */ /* NOTREACHED */ }
int main(int argc, char *argv[]) { bool need_umount, need_swapoff, need_loop_detach, need_dm_detach; bool in_container, use_watchdog = false, can_initrd; _cleanup_free_ char *cgroup = NULL; char *arguments[3]; int cmd, r, umount_log_level = LOG_INFO; static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL}; char *watchdog_device; /* The log target defaults to console, but the original systemd process will pass its log target in through a * command line argument, which will override this default. Also, ensure we'll never log to the journal or * syslog, as these logging daemons are either already dead or will die very soon. */ log_set_target(LOG_TARGET_CONSOLE); log_set_prohibit_ipc(true); log_parse_environment(); r = parse_argv(argc, argv); if (r < 0) goto error; log_open(); umask(0022); if (getpid_cached() != 1) { log_error("Not executed by init (PID 1)."); r = -EPERM; goto error; } if (streq(arg_verb, "reboot")) cmd = RB_AUTOBOOT; else if (streq(arg_verb, "poweroff")) cmd = RB_POWER_OFF; else if (streq(arg_verb, "halt")) cmd = RB_HALT_SYSTEM; else if (streq(arg_verb, "kexec")) cmd = LINUX_REBOOT_CMD_KEXEC; else if (streq(arg_verb, "exit")) cmd = 0; /* ignored, just checking that arg_verb is valid */ else { log_error("Unknown action '%s'.", arg_verb); r = -EINVAL; goto error; } (void) cg_get_root_path(&cgroup); in_container = detect_container() > 0; use_watchdog = getenv("WATCHDOG_USEC"); watchdog_device = getenv("WATCHDOG_DEVICE"); if (watchdog_device) { r = watchdog_set_device(watchdog_device); if (r < 0) log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", watchdog_device); } /* Lock us into memory */ (void) mlockall(MCL_CURRENT|MCL_FUTURE); /* Synchronize everything that is not written to disk yet at this point already. This is a good idea so that * slow IO is processed here already and the final process killing spree is not impacted by processes * desperately trying to sync IO to disk within their timeout. Do not remove this sync, data corruption will * result. */ if (!in_container) sync_with_progress(); disable_coredumps(); log_info("Sending SIGTERM to remaining processes..."); broadcast_signal(SIGTERM, true, true, arg_timeout); log_info("Sending SIGKILL to remaining processes..."); broadcast_signal(SIGKILL, true, false, arg_timeout); need_umount = !in_container; need_swapoff = !in_container; need_loop_detach = !in_container; need_dm_detach = !in_container; can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0; /* Unmount all mountpoints, swaps, and loopback devices */ for (;;) { bool changed = false; if (use_watchdog) watchdog_ping(); /* Let's trim the cgroup tree on each iteration so that we leave an empty cgroup tree around, so that container managers get a nice notify event when we are down */ if (cgroup) cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false); if (need_umount) { log_info("Unmounting file systems."); r = umount_all(&changed, umount_log_level); if (r == 0) { need_umount = false; log_info("All filesystems unmounted."); } else if (r > 0) log_info("Not all file systems unmounted, %d left.", r); else log_error_errno(r, "Failed to unmount file systems: %m"); } if (need_swapoff) { log_info("Deactivating swaps."); r = swapoff_all(&changed); if (r == 0) { need_swapoff = false; log_info("All swaps deactivated."); } else if (r > 0) log_info("Not all swaps deactivated, %d left.", r); else log_error_errno(r, "Failed to deactivate swaps: %m"); } if (need_loop_detach) { log_info("Detaching loop devices."); r = loopback_detach_all(&changed, umount_log_level); if (r == 0) { need_loop_detach = false; log_info("All loop devices detached."); } else if (r > 0) log_info("Not all loop devices detached, %d left.", r); else log_error_errno(r, "Failed to detach loop devices: %m"); } if (need_dm_detach) { log_info("Detaching DM devices."); r = dm_detach_all(&changed, umount_log_level); if (r == 0) { need_dm_detach = false; log_info("All DM devices detached."); } else if (r > 0) log_info("Not all DM devices detached, %d left.", r); else log_error_errno(r, "Failed to detach DM devices: %m"); } if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) { log_info("All filesystems, swaps, loop devices and DM devices detached."); /* Yay, done */ break; } if (!changed && umount_log_level == LOG_INFO && !can_initrd) { /* There are things we cannot get rid of. Loop one more time * with LOG_ERR to inform the user. Note that we don't need * to do this if there is a initrd to switch to, because that * one is likely to get rid of the remounting mounts. If not, * it will log about them. */ umount_log_level = LOG_ERR; continue; } /* If in this iteration we didn't manage to * unmount/deactivate anything, we simply give up */ if (!changed) { log_info("Cannot finalize remaining%s%s%s%s continuing.", need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); break; } log_debug("Couldn't finalize remaining %s%s%s%s trying again.", need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); } /* We're done with the watchdog. */ watchdog_free_device(); arguments[0] = NULL; arguments[1] = arg_verb; arguments[2] = NULL; execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL); (void) rlimit_nofile_safe(); if (can_initrd) { r = switch_root_initramfs(); if (r >= 0) { argv[0] = (char*) "/shutdown"; (void) setsid(); (void) make_console_stdio(); log_info("Successfully changed into root pivot.\n" "Returning to initrd..."); execv("/shutdown", argv); log_error_errno(errno, "Failed to execute shutdown binary: %m"); } else log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m"); } if (need_umount || need_swapoff || need_loop_detach || need_dm_detach) log_error("Failed to finalize %s%s%s%s ignoring", need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "", need_dm_detach ? " DM devices," : ""); /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we * sync'ed things already once above, but we did some more work since then which might have caused IO, hence * let's do it once more. Do not remove this sync, data corruption will result. */ if (!in_container) sync_with_progress(); if (streq(arg_verb, "exit")) { if (in_container) return arg_exit_code; cmd = RB_POWER_OFF; /* We cannot exit() on the host, fallback on another method. */ } switch (cmd) { case LINUX_REBOOT_CMD_KEXEC: if (!in_container) { /* We cheat and exec kexec to avoid doing all its work */ log_info("Rebooting with kexec."); r = safe_fork("(sd-kexec)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_WAIT, NULL); if (r == 0) { const char * const args[] = { KEXEC, "-e", NULL }; /* Child */ execv(args[0], (char * const *) args); _exit(EXIT_FAILURE); } /* If we are still running, then the kexec can't have worked, let's fall through */ } cmd = RB_AUTOBOOT; _fallthrough_; case RB_AUTOBOOT: (void) reboot_with_parameter(REBOOT_LOG); log_info("Rebooting."); break; case RB_POWER_OFF: log_info("Powering off."); break; case RB_HALT_SYSTEM: log_info("Halting system."); break; default: assert_not_reached("Unknown magic"); } (void) reboot(cmd); if (errno == EPERM && in_container) { /* If we are in a container, and we lacked * CAP_SYS_BOOT just exit, this will kill our * container for good. */ log_info("Exiting container."); return EXIT_SUCCESS; } r = log_error_errno(errno, "Failed to invoke reboot(): %m"); error: log_emergency_errno(r, "Critical error while doing system shutdown: %m"); freeze(); }
/* * fn_install_os: actually put DragonFly on a disk. */ void fn_install_os(struct i_fn_args *a) { struct subpartition *sp; struct commands *cmds; struct command *cmd; int i, seen_it, prefix, j, needcrypt; FILE *sources_conf; char line[256]; char cp_src[64][256]; char file_path[256]; char *string; int lines = 0; /* * Read SOURCES_CONF_FILE and populate our copy sources. */ snprintf(file_path, 256, "%s%s", a->os_root, SOURCES_CONF_FILE); sources_conf = fopen(file_path, "r"); i_log(a, "Reading %s", file_path); while(fgets(line, 256, sources_conf) != NULL && lines < 63) { if(strlen(line)>0) line[strlen(line)-1] = '\0'; strlcpy(cp_src[lines], line, 256); i_log(a,"Adding %s to copy source table.", cp_src[lines]); lines++; } i_log(a,"Added %i total items to copy source table.", lines); strcpy(cp_src[lines], ""); fclose(sources_conf); cmds = commands_new(); /* * If swap isn't mounted yet, mount it. */ if (measure_activated_swap(a) == 0) { for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); sp != NULL; sp = subpartition_next(sp)) { if (!subpartition_is_swap(sp)) continue; command_add(cmds, "%s%s %sdev/%s", a->os_root, cmd_name(a, "SWAPON"), a->os_root, subpartition_is_encrypted(sp) ? "mapper/swap" : subpartition_get_device_name(sp)); } } /* * Unmount anything already mounted on /mnt. */ unmount_all_under(a, cmds, "%smnt", a->os_root); /* Check if crypto support is needed */ needcrypt = 0; for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); sp != NULL; sp = subpartition_next(sp)) { if (subpartition_is_encrypted(sp)) { needcrypt = 1; break; } } for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); sp != NULL; sp = subpartition_next(sp)) { if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) { if (use_hammer == 1) { command_add(cmds, "%s%s %sdev/%s %smnt%s", a->os_root, cmd_name(a, "MOUNT_HAMMER"), a->os_root, subpartition_is_encrypted(sp) ? "mapper/root" : subpartition_get_device_name(sp), a->os_root, subpartition_get_mountpoint(sp)); } else { command_add(cmds, "%s%s %sdev/%s %smnt%s", a->os_root, cmd_name(a, "MOUNT"), a->os_root, subpartition_get_device_name(sp), a->os_root, subpartition_get_mountpoint(sp)); } } } /* * Create mount points and mount subpartitions on them. */ for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); sp != NULL; sp = subpartition_next(sp)) { if (subpartition_is_swap(sp)) { /* * Set this subpartition as the dump device. */ if (subpartition_get_capacity(sp) < storage_get_memsize(a->s)) continue; command_add(cmds, "%s%s -v %sdev/%s", a->os_root, cmd_name(a, "DUMPON"), a->os_root, subpartition_is_encrypted(sp) ? "mapper/swap" : subpartition_get_device_name(sp)); asprintf(&string, "/dev/%s", subpartition_is_encrypted(sp) ? "mapper/swap" : subpartition_get_device_name(sp)); config_var_set(rc_conf, "dumpdev", string); free(string); continue; } if (use_hammer == 0) { /* / is already mounted */ if (strcmp(subpartition_get_mountpoint(sp), "/") != 0) { command_add(cmds, "%s%s -p %smnt%s", a->os_root, cmd_name(a, "MKDIR"), a->os_root, subpartition_get_mountpoint(sp)); /* Don't mount it if it's TMPFS-backed. */ if (subpartition_is_tmpfsbacked(sp)) continue; if (subpartition_is_encrypted(sp)) { command_add(cmds, "%s%s %sdev/mapper/%s %smnt%s", a->os_root, cmd_name(a, "MOUNT"), a->os_root, subpartition_get_mountpoint(sp) + 1, a->os_root, subpartition_get_mountpoint(sp)); } else { command_add(cmds, "%s%s %sdev/%s %smnt%s", a->os_root, cmd_name(a, "MOUNT"), a->os_root, subpartition_get_device_name(sp), a->os_root, subpartition_get_mountpoint(sp)); } } } else if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) { command_add(cmds, "%s%s -p %smnt%s", a->os_root, cmd_name(a, "MKDIR"), a->os_root, subpartition_get_mountpoint(sp)); command_add(cmds, "%s%s %sdev/%s %smnt%s", a->os_root, cmd_name(a, "MOUNT"), a->os_root, subpartition_get_device_name(sp), a->os_root, subpartition_get_mountpoint(sp)); } } /* * Take care of HAMMER PFS. */ if (use_hammer == 1) handle_pfs(a, cmds); /* * Actually copy files now. */ for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) { char *src, *dest, *dn, *tmp_dest; dest = cp_src[i]; /* * If dest would be on an TMPFS-backed * mountpoint, don't bother copying it. */ sp = subpartition_of(storage_get_selected_slice(a->s), "%s%s", a->os_root, &dest[1]); if (sp != NULL && subpartition_is_tmpfsbacked(sp)) { continue; } /* * Create intermediate directories, if needed. */ tmp_dest = aura_strdup(dest); dn = dirname(tmp_dest); if (is_dir("%s%s", a->os_root, &dn[1]) && !is_dir("%smnt%s", a->os_root, dn)) { command_add(cmds, "%s%s -p %smnt%s", a->os_root, cmd_name(a, "MKDIR"), a->os_root, dn); } aura_free(tmp_dest, "directory name"); /* * If a directory by the same name but with the suffix * ".hdd" exists on the installation media, cpdup that * instead. This is particularly useful with /etc, which * may have significantly different behaviour on the * live CD compared to a standard HDD boot. */ if (is_dir("%s%s.hdd", a->os_root, &dest[1])) asprintf(&src, "%s.hdd", &dest[1]); else asprintf(&src, "%s", &dest[1]); if (is_dir("%s%s", a->os_root, src) || is_file("%s%s", a->os_root, src)) { /* * Cpdup the chosen file or directory onto the HDD. * if it exists on the source. */ cmd = command_add(cmds, "%s%s %s%s %smnt%s", a->os_root, cmd_name(a, "CPDUP"), a->os_root, src, a->os_root, dest); command_set_log_mode(cmd, COMMAND_LOG_QUIET); } } /* * Now, because cpdup does not cross mount points, * we must copy anything that the user might've made a * seperate mount point for (e.g. /usr/libdata/lint.) */ for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); sp != NULL; sp = subpartition_next(sp)) { /* * If the subpartition is a swap subpartition or an * TMPFS-backed mountpoint, don't try to copy anything * into it. */ if (subpartition_is_swap(sp) || subpartition_is_tmpfsbacked(sp)) continue; /* * If the mountpoint doesn't even exist on the installation * medium, don't try to copy anything from it! We assume * it's an empty subpartition for the user's needs. */ if (!is_dir("%s%s", a->os_root, &subpartition_get_mountpoint(sp)[1])) continue; /* * Don't bother copying the mountpoint IF: * - we've already said to copy it, or something besides it * (it's a prefix of something in cp_src); or * - we haven't said to copy it * (nothing in cp_src is a prefix of it.) */ seen_it = 0; prefix = 0; for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) { if (strncmp(subpartition_get_mountpoint(sp), cp_src[i], strlen(subpartition_get_mountpoint(sp))) == 0) { seen_it = 1; break; } if (strncmp(cp_src[i], subpartition_get_mountpoint(sp), strlen(cp_src[i])) == 0) { prefix = 1; } } if (seen_it || !prefix) continue; /* * Otherwise, cpdup the subpartition. * * XXX check for .hdd-extended source dirs here, too, * eventually - but for now, /etc.hdd will never be * the kind of tricky sub-mount-within-a-mount-point * that this part of the code is meant to handle. */ cmd = command_add(cmds, "%s%s %s%s %smnt%s", a->os_root, cmd_name(a, "CPDUP"), a->os_root, &subpartition_get_mountpoint(sp)[1], a->os_root, subpartition_get_mountpoint(sp)); command_set_log_mode(cmd, COMMAND_LOG_QUIET); } /* * Create symlinks. */ /* Take care of /sys. */ command_add(cmds, "%s%s -s usr/src/sys %smnt/sys", a->os_root, cmd_name(a, "LN"), a->os_root); /* * If the user has both /var and /tmp subpartitions, * symlink /var/tmp to /tmp. */ if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") != NULL && subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL) { command_add(cmds, "%s%s 1777 %smnt/tmp", a->os_root, cmd_name(a, "CHMOD"), a->os_root); command_add(cmds, "%s%s -rf %smnt/var/tmp", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s -s /tmp %smnt/var/tmp", a->os_root, cmd_name(a, "LN"), a->os_root); } /* * If the user has /var, but no /tmp, * symlink /tmp to /var/tmp. */ if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") == NULL && subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL) { command_add(cmds, "%s%s -rf %smnt/tmp", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s -s /var/tmp %smnt/tmp", a->os_root, cmd_name(a, "LN"), a->os_root); } /* * If the user has /usr, but no /home, * symlink /home to /usr/home. */ if (subpartition_find(storage_get_selected_slice(a->s), "/home") == NULL && subpartition_find(storage_get_selected_slice(a->s), "/usr") != NULL) { command_add(cmds, "%s%s -rf %smnt/home", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s %smnt/usr/home", a->os_root, cmd_name(a, "MKDIR"), a->os_root); command_add(cmds, "%s%s -s /usr/home %smnt/home", a->os_root, cmd_name(a, "LN"), a->os_root); } /* * XXX check for other possible combinations too? */ /* * Clean up. In case some file didn't make it, use rm -f */ command_add(cmds, "%s%s -f %smnt/boot/loader.conf", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s -f %smnt/tmp/install.log", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s -f %smnt/tmp/t[12]", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s -f %smnt/tmp/test_in", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s -f %smnt/tmp/test_out", a->os_root, cmd_name(a, "RM"), a->os_root); /* * Copy pristine versions over any files we might have installed. * This allows the resulting file tree to be customized. */ for (i = 0; cp_src[i] != NULL && cp_src[i][0] != '\0'; i++) { char *src, *dest, *dn, *tmp_dest; src = cp_src[i]; dest = cp_src[i]; /* * Get the directory that the desired thing to * copy resides in. */ tmp_dest = aura_strdup(dest); dn = dirname(tmp_dest); /* * If this dir doesn't exist in PRISTINE_DIR * on the install media, just skip it. */ if (!is_dir("%s%s%s", a->os_root, PRISTINE_DIR, dn)) { aura_free(tmp_dest, _("directory name")); continue; } /* * Create intermediate directories, if needed. */ if (!is_dir("%smnt%s", a->os_root, dn)) { command_add(cmds, "%s%s -p %smnt%s", a->os_root, cmd_name(a, "MKDIR"), a->os_root, dn); } aura_free(tmp_dest, "directory name"); /* * Cpdup the chosen file or directory onto the HDD. */ cmd = command_add(cmds, "%s%s %s%s %smnt%s", a->os_root, cmd_name(a, "CPDUP"), a->os_root, src, a->os_root, dest); cmd = command_add(cmds, "%s%s %s%s%s %smnt%s", a->os_root, cmd_name(a, "CPDUP"), a->os_root, PRISTINE_DIR, src, a->os_root, dest); command_set_log_mode(cmd, COMMAND_LOG_QUIET); } /* * Rebuild the user database, to get rid of any extra users * from the LiveCD that aren't supposed to be installed * (copying a pristine master.passwd isn't enough.) */ command_add(cmds, "%s%s -p -d %smnt/etc %smnt/etc/master.passwd", a->os_root, cmd_name(a, "PWD_MKDB"), a->os_root, a->os_root); /* Create missing directories. */ command_add(cmds, "%s%s %smnt/proc", a->os_root, cmd_name(a, "MKDIR"), a->os_root); command_add(cmds, "%s%s %smnt/mnt", a->os_root, cmd_name(a, "MKDIR"), a->os_root); /* Write new fstab. */ command_add(cmds, "%s%s '%s' >%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#", a->os_root); for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); sp != NULL; sp = subpartition_next(sp)) { if (strcmp(subpartition_get_mountpoint(sp), "swap") == 0) { command_add(cmds, "%s%s '/dev/%s\t\tnone\t\tswap\tsw\t\t0\t0' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_is_encrypted(sp) ? "mapper/swap" : subpartition_get_device_name(sp), a->os_root); if (subpartition_is_encrypted(sp)) { command_add(cmds, "%s%s 'swap\t/dev/%s\tnone\tnone' >>%smnt/etc/crypttab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), a->os_root); } } else if (use_hammer == 0) { if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) { command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), subpartition_get_mountpoint(sp), a->os_root); } else if (subpartition_is_tmpfsbacked(sp)) { command_add(cmds, "%s%s 'tmpfs\t\t\t%s\t\ttmpfs\trw,-s%luM\t1\t1' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_mountpoint(sp), subpartition_get_capacity(sp), a->os_root); } else if (subpartition_is_encrypted(sp)) { command_add(cmds, "%s%s '%s\t/dev/%s\tnone\tnone' >>%smnt/etc/crypttab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_mountpoint(sp) + 1, subpartition_get_device_name(sp), a->os_root); command_add(cmds, "%s%s '/dev/mapper/%s\t\t%s\t\tufs\trw\t\t2\t2' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_mountpoint(sp) + 1, subpartition_get_mountpoint(sp), a->os_root); } else { command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t2\t2' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), subpartition_get_mountpoint(sp), a->os_root); } } else { if (strcmp(subpartition_get_mountpoint(sp), "/") == 0) { command_add(cmds, "%s%s '/dev/%s\t\t%s\t\thammer\trw\t\t1\t1' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), subpartition_get_mountpoint(sp), a->os_root); if (subpartition_is_encrypted(sp)) { command_add(cmds, "%s%s 'vfs.root.mountfrom=\"ufs:md0s0\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), a->os_root); command_add(cmds, "%s%s 'vfs.root.realroot=\"crypt:hammer:%s:root\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), a->os_root); } else { command_add(cmds, "%s%s 'vfs.root.mountfrom=\"hammer:%s\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), a->os_root); } } else if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) { command_add(cmds, "%s%s '/dev/%s\t\t%s\t\tufs\trw\t\t1\t1' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), subpartition_get_device_name(sp), subpartition_get_mountpoint(sp), a->os_root); } } } /* * Take care of HAMMER PFS null mounts. */ if (use_hammer == 1) { for (j = 0; pfs_mountpt[j] != NULL; j++) { if (rindex(pfs_mountpt[j]+1, '/') != NULL) command_add(cmds, "%s%s '/pfs%s.%s\t%s\t\tnull\trw\t\t0\t0' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), dirname(pfs_mountpt[j]), basename(pfs_mountpt[j]), pfs_mountpt[j], a->os_root); else command_add(cmds, "%s%s '/pfs%s\t\t%s\t\tnull\trw\t\t0\t0' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), pfs_mountpt[j], pfs_mountpt[j], a->os_root); } } command_add(cmds, "%s%s '%s' >>%smnt/etc/fstab", a->os_root, cmd_name(a, "ECHO"), "proc\t\t\t/proc\t\tprocfs\trw\t\t0\t0", a->os_root); /* Backup the disklabel and the log. */ command_add(cmds, "%s%s %s > %smnt/etc/disklabel.%s", a->os_root, cmd_name(a, "DISKLABEL64"), slice_get_device_name(storage_get_selected_slice(a->s)), a->os_root, slice_get_device_name(storage_get_selected_slice(a->s))); /* 'chflags nohistory' as needed */ for (j = 0; pfs_mountpt[j] != NULL; j++) if (pfs_nohistory[j] == 1) command_add(cmds, "%s%s -R nohistory %smnt%s", a->os_root, cmd_name(a, "CHFLAGS"), a->os_root, pfs_mountpt[j]); command_add(cmds, "%s%s %sinstall.log %smnt/var/log/install.log", a->os_root, cmd_name(a, "CP"), a->tmp, a->os_root); command_add(cmds, "%s%s 600 %smnt/var/log/install.log", a->os_root, cmd_name(a, "CHMOD"), a->os_root); /* Do some preparation if encrypted partitions were configured */ if (needcrypt) { command_add(cmds, "%s%s 'dm_load=\"yes\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), a->os_root); command_add(cmds, "%s%s 'dm_target_crypt_load=\"yes\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), a->os_root); if (use_hammer) { command_add(cmds, "%s%s -b %smnt/boot -t %smnt/tmp", a->os_root, cmd_name(a, "MKINITRD"), a->os_root, a->os_root); command_add(cmds, "%s%s -rf %smnt/tmp/initrd", a->os_root, cmd_name(a, "RM"), a->os_root); command_add(cmds, "%s%s 'initrd.img_load=\"YES\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), a->os_root); command_add(cmds, "%s%s 'initrd.img_type=\"md_image\"' >>%smnt/boot/loader.conf", a->os_root, cmd_name(a, "ECHO"), a->os_root); } } /* Customize stuff here */ if(is_file("%susr/local/bin/after_installation_routines.sh", a->os_root)) { command_add(cmds, "%susr/local/bin/after_installation_routines.sh", a->os_root); } /* * Do it! */ /* commands_preview(a->c, cmds); */ if (!commands_execute(a, cmds)) { inform(a->c, _("%s was not fully installed."), OPERATING_SYSTEM_NAME); a->result = 0; } else { a->result = 1; } commands_free(cmds); cmds = commands_new(); if (a->result) { config_vars_write(rc_conf, CONFIG_TYPE_SH, "%smnt/etc/rc.conf", a->os_root); config_vars_free(rc_conf); rc_conf = config_vars_new(); } /* * Unmount everything we mounted on /mnt. This is done in a seperate * command chain, so that partitions are unmounted, even if an error * occurs in one of the preceding commands, or it is cancelled. */ unmount_all_under(a, cmds, "%smnt", a->os_root); /* * Once everything is unmounted, if the install went successfully, * make sure once and for all that the disklabel is bootable. */ if (a->result) command_add(cmds, "%s%s -B %s", a->os_root, cmd_name(a, "DISKLABEL64"), slice_get_device_name(storage_get_selected_slice(a->s))); if (!commands_execute(a, cmds)) inform(a->c, _("Warning: subpartitions were not correctly unmounted.")); commands_free(cmds); /* * Finally, remove all swap and any mappings. */ if (swapoff_all(a) == NULL) inform(a->c, _("Warning: swap could not be turned off.")); if (remove_all_mappings(a) == NULL) inform(a->c, _("Warning: mappings could not be removed.")); }
int main(int argc, char *argv[]) { int cmd, r; unsigned retries; bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; bool killed_everbody = false, in_container; log_parse_environment(); log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */ log_open(); if (getpid() != 1) { log_error("Not executed by init (pid 1)."); r = -EPERM; goto error; } if (argc != 2) { log_error("Invalid number of arguments."); r = -EINVAL; goto error; } in_container = detect_container(NULL) > 0; if (streq(argv[1], "reboot")) cmd = RB_AUTOBOOT; else if (streq(argv[1], "poweroff")) cmd = RB_POWER_OFF; else if (streq(argv[1], "halt")) cmd = RB_HALT_SYSTEM; else if (streq(argv[1], "kexec")) cmd = LINUX_REBOOT_CMD_KEXEC; else { log_error("Unknown action '%s'.", argv[1]); r = -EINVAL; goto error; } /* lock us into memory */ if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) log_warning("Cannot lock process memory: %m"); log_info("Sending SIGTERM to remaining processes..."); send_signal(SIGTERM); log_info("Sending SIGKILL to remaining processes..."); send_signal(SIGKILL); if (in_container) need_swapoff = false; /* Unmount all mountpoints, swaps, and loopback devices */ for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) { bool changed = false; if (need_umount) { log_info("Unmounting file systems."); r = umount_all(&changed); if (r == 0) need_umount = false; else if (r > 0) log_info("Not all file systems unmounted, %d left.", r); else log_error("Failed to unmount file systems: %s", strerror(-r)); } if (need_swapoff) { log_info("Disabling swaps."); r = swapoff_all(&changed); if (r == 0) need_swapoff = false; else if (r > 0) log_info("Not all swaps are turned off, %d left.", r); else log_error("Failed to turn off swaps: %s", strerror(-r)); } if (need_loop_detach) { log_info("Detaching loop devices."); r = loopback_detach_all(&changed); if (r == 0) need_loop_detach = false; else if (r > 0) log_info("Not all loop devices detached, %d left.", r); else log_error("Failed to detach loop devices: %s", strerror(-r)); } if (need_dm_detach) { log_info("Detaching DM devices."); r = dm_detach_all(&changed); if (r == 0) need_dm_detach = false; else if (r > 0) log_warning("Not all DM devices detached, %d left.", r); else log_error("Failed to detach DM devices: %s", strerror(-r)); } if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) /* Yay, done */ break; /* If in this iteration we didn't manage to * unmount/deactivate anything, we either kill more * processes, or simply give up */ if (!changed) { if (killed_everbody) { /* Hmm, we already killed everybody, * let's just give up */ log_error("Cannot finalize remaining file systems and devices, giving up."); break; } log_warning("Cannot finalize remaining file systems and devices, trying to kill remaining processes."); ultimate_send_signal(SIGTERM); ultimate_send_signal(SIGKILL); killed_everbody = true; } log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1); } if (retries >= FINALIZE_ATTEMPTS) log_error("Too many iterations, giving up."); execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL); /* If we are in a container, just exit, this will kill our * container for good. */ if (in_container) { log_error("Exiting container."); exit(0); } sync(); if (cmd == LINUX_REBOOT_CMD_KEXEC) { /* We cheat and exec kexec to avoid doing all its work */ pid_t pid = fork(); if (pid < 0) log_error("Could not fork: %m. Falling back to normal reboot."); else if (pid > 0) { wait_for_terminate_and_warn("kexec", pid); log_warning("kexec failed. Falling back to normal reboot."); } else { /* Child */ const char *args[3] = { "/sbin/kexec", "-e", NULL }; execv(args[0], (char * const *) args); return EXIT_FAILURE; } cmd = RB_AUTOBOOT; } reboot(cmd); log_error("Failed to invoke reboot(): %m"); r = -errno; error: log_error("Critical error while doing system shutdown: %s", strerror(-r)); freeze(); return EXIT_FAILURE; }