1/* vi: set sw=4 ts=4: */
2/*
3 * Poweroff reboot and halt, oh my.
4 *
5 * Copyright 2006 by Rob Landley <rob@landley.net>
6 *
7 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <sys/reboot.h>
12
13#if ENABLE_FEATURE_WTMP
14#include <sys/utsname.h>
15#include <utmp.h>
16
17static void write_wtmp(void)
18{
19	struct utmp utmp;
20	struct utsname uts;
21	/* "man utmp" says wtmp file should *not* be created automagically */
22	/*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
23		close(creat(bb_path_wtmp_file, 0664));
24	}*/
25	memset(&utmp, 0, sizeof(utmp));
26	utmp.ut_tv.tv_sec = time(NULL);
27	strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */
28	utmp.ut_type = RUN_LVL;
29	utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */
30	utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */
31	uname(&uts);
32	safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host));
33	updwtmp(bb_path_wtmp_file, &utmp);
34}
35#else
36#define write_wtmp() ((void)0)
37#endif
38
39#ifndef RB_HALT_SYSTEM
40#define RB_HALT_SYSTEM RB_HALT
41#endif
42
43#ifndef RB_POWERDOWN
44/* Stop system and switch power off if possible.  */
45# define RB_POWERDOWN   0x4321fedc
46#endif
47#ifndef RB_POWER_OFF
48# define RB_POWER_OFF RB_POWERDOWN
49#endif
50
51
52int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
53int halt_main(int argc UNUSED_PARAM, char **argv)
54{
55	static const int magic[] = {
56		RB_HALT_SYSTEM,
57		RB_POWER_OFF,
58		RB_AUTOBOOT
59	};
60	static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
61
62	int delay = 0;
63	int which, flags, rc;
64
65	/* Figure out which applet we're running */
66	for (which = 0; "hpr"[which] != applet_name[0]; which++)
67		continue;
68
69	/* Parse and handle arguments */
70	opt_complementary = "d+"; /* -d N */
71	/* We support -w even if !ENABLE_FEATURE_WTMP,
72	 * in order to not break scripts.
73	 * -i (shut down network interfaces) is ignored.
74	 */
75	flags = getopt32(argv, "d:nfwi", &delay);
76
77	sleep(delay);
78
79	write_wtmp();
80
81	if (flags & 8) /* -w */
82		return EXIT_SUCCESS;
83
84	if (!(flags & 2)) /* no -n */
85		sync();
86
87	/* Perform action. */
88	rc = 1;
89	if (!(flags & 4)) { /* no -f */
90//TODO: I tend to think that signalling linuxrc is wrong
91// pity original author didn't comment on it...
92		if (ENABLE_FEATURE_INITRD) {
93			/* talk to linuxrc */
94			/* bbox init/linuxrc assumed */
95			pid_t *pidlist = find_pid_by_name("linuxrc");
96			if (pidlist[0] > 0)
97				rc = kill(pidlist[0], signals[which]);
98			if (ENABLE_FEATURE_CLEAN_UP)
99				free(pidlist);
100		}
101		if (rc) {
102			/* talk to init */
103			if (!ENABLE_FEATURE_CALL_TELINIT) {
104				/* bbox init assumed */
105				rc = kill(1, signals[which]);
106			} else {
107				/* SysV style init assumed */
108				/* runlevels:
109				 * 0 == shutdown
110				 * 6 == reboot */
111				rc = execlp(CONFIG_TELINIT_PATH,
112						CONFIG_TELINIT_PATH,
113						which == 2 ? "6" : "0",
114						(char *)NULL
115				);
116			}
117		}
118	} else {
119		rc = reboot(magic[which]);
120	}
121
122	if (rc)
123		bb_perror_nomsg_and_die();
124	return rc;
125}
126