static bool clean_shutdown(void (*callback)(void *), void *parameter) { #ifdef SIMULATOR (void)callback; (void)parameter; bookmark_autobookmark(); call_storage_idle_notifys(true); exit(0); #else long msg_id = -1; int i; scrobbler_poweroff(); #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) if(!charger_inserted()) #endif { bool batt_safe = battery_level_safe(); int audio_stat = audio_status(); FOR_NB_SCREENS(i) { screens[i].clear_display(); screens[i].update(); } if (batt_safe) { #ifdef HAVE_TAGCACHE if (!tagcache_prepare_shutdown()) { cancel_shutdown(); splash(HZ, ID2P(LANG_TAGCACHE_BUSY)); return false; } #endif if (battery_level() > 10) splash(0, str(LANG_SHUTTINGDOWN)); else { msg_id = LANG_WARNING_BATTERY_LOW; splashf(0, "%s %s", str(LANG_WARNING_BATTERY_LOW), str(LANG_SHUTTINGDOWN)); } } else { msg_id = LANG_WARNING_BATTERY_EMPTY; splashf(0, "%s %s", str(LANG_WARNING_BATTERY_EMPTY), str(LANG_SHUTTINGDOWN)); } if (global_settings.fade_on_stop && (audio_stat & AUDIO_STATUS_PLAY)) { fade(false, false); } if (batt_safe) /* do not save on critical battery */ { #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC if (audio_stat & AUDIO_STATUS_RECORD) { rec_command(RECORDING_CMD_STOP); /* wait for stop to complete */ while (audio_status() & AUDIO_STATUS_RECORD) sleep(1); } #endif bookmark_autobookmark(); /* audio_stop_recording == audio_stop for HWCODEC */ audio_stop(); if (callback != NULL) callback(parameter); #if CONFIG_CODEC != SWCODEC /* wait for audio_stop or audio_stop_recording to complete */ while (audio_status()) sleep(1); #endif #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC audio_close_recording(); #endif if(global_settings.talk_menu) { bool enqueue = false; if(msg_id != -1) { talk_id(msg_id, enqueue); enqueue = true; } talk_id(LANG_SHUTTINGDOWN, enqueue); #if CONFIG_CODEC == SWCODEC voice_wait(); #endif } system_flush(); #ifdef HAVE_EEPROM_SETTINGS if (firmware_settings.initialized) { firmware_settings.disk_clean = true; firmware_settings.bl_version = 0; eeprom_settings_store(); } #endif } #ifdef HAVE_DIRCACHE else dircache_disable(); #endif shutdown_hw(); }
int main(int argc, char **argv) { char *ch = NULL; int opt; int cmd_count = 0; int hour = 0; int min = 0; int shutdown_delay = 0; struct sigaction sa; struct tm *lt; time_t tv; bool need_warning = false; char *msg = NULL; char *state = NULL; char *time_arg = NULL; FILE *fp; applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'c': do_cancel = true; cmd_count++; break; case 'd': do_wtmp = false; break; case 'D': do_dryrun = true; break; case 'H': do_halt = true; xasprintf(&state, "%s", "halt"); cmd_count++; break; case 'K': do_kexec = true; xasprintf(&state, "%s", "reboot"); cmd_count++; break; case 'p': do_poweroff = true; xasprintf(&state, "%s", "power off"); cmd_count++; break; case 'R': do_reexec = true; cmd_count++; break; case 'r': do_reboot = true; xasprintf(&state, "%s", "reboot"); cmd_count++; break; case 's': do_single = true; xasprintf(&state, "%s", "go down for maintenance"); cmd_count++; break; case 'w': do_wtmp_only = true; cmd_count++; break; case_RC_COMMON_GETOPT } } if (geteuid() != 0) eerrorx("%s: you must be root\n", applet); if (cmd_count != 1) { eerror("%s: %s\n", applet, exclusive); usage(EXIT_FAILURE); } if (do_cancel) { cancel_shutdown(); exit(EXIT_SUCCESS); } else if (do_reexec) { send_cmd("reexec"); exit(EXIT_SUCCESS); } else if (do_wtmp_only) { log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); exit(EXIT_SUCCESS); } if (optind >= argc) { eerror("%s: No shutdown time specified", applet); usage(EXIT_FAILURE); } time_arg = argv[optind]; if (*time_arg == '+') time_arg++; if (strcasecmp(time_arg, "now") == 0) strcpy(time_arg, "0"); for (ch=time_arg; *ch; ch++) if ((*ch < '0' || *ch > '9') && *ch != ':') { eerror("%s: invalid time %s", applet, time_arg); usage(EXIT_FAILURE); } if (strchr(time_arg, ':')) { if ((sscanf(time_arg, "%2d:%2d", &hour, &min) != 2) || (hour > 23) || (min > 59)) { eerror("%s: invalid time %s", applet, time_arg); usage(EXIT_FAILURE); } time(&tv); lt = localtime(&tv); shutdown_delay = (hour * 60 + min) - (lt->tm_hour * 60 + lt->tm_min); if (shutdown_delay < 0) shutdown_delay += 1440; } else { shutdown_delay = atoi(time_arg); } fp = fopen(shutdown_pid, "w"); if (!fp) eerrorx("%s: fopen `%s': %s", applet, shutdown_pid, strerror(errno)); fprintf(fp, "%d\n", getpid()); fclose(fp); openlog(applet, LOG_PID, LOG_DAEMON); memset(&sa, 0, sizeof(sa)); sa.sa_handler = stop_shutdown; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); while (shutdown_delay > 0) { need_warning = false; if (shutdown_delay > 180) need_warning = (shutdown_delay % 60 == 0); else if (shutdown_delay > 60) need_warning = (shutdown_delay % 30 == 0); else if (shutdown_delay > 10) need_warning = (shutdown_delay % 15 == 0); else need_warning = true; if (shutdown_delay <= 5) create_nologin(shutdown_delay); if (need_warning) { xasprintf(&msg, "\rThe system will %s in %d minutes\r\n", state, shutdown_delay); broadcast(msg); free(msg); } sleep_no_interrupt(60); shutdown_delay--; } xasprintf(&msg, "\rThe system will %s now\r\n", state); broadcast(msg); syslog(LOG_NOTICE, "The system will %s now", state); unlink(nologin_file); unlink(shutdown_pid); if (do_halt) send_cmd("halt"); else if (do_kexec) send_cmd("kexec"); else if (do_poweroff) send_cmd("poweroff"); else if (do_reboot) send_cmd("reboot"); else if (do_single) send_cmd("single"); return 0; }