aboutsummaryrefslogtreecommitdiff
path: root/examples/shutdown-1.0/script/hardshutdown.c
blob: c21ddad58552fa1610b1b105e227781eeb81abf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* Including <unistd.h> makes sure that on a glibc system
 * <features.h> is included, which again defines __GLIBC__
 */

#include <unistd.h>
#include <stdio.h>	/* puts */
#include <time.h>	/* nanosleep */
#include <errno.h>
#include <stdlib.h>
#include <string.h>


/*
 * Magic values required to use _reboot() system call.
 */
#define	LINUX_REBOOT_MAGIC1	0xfee1dead
#define	LINUX_REBOOT_MAGIC2	672274793
#define	LINUX_REBOOT_MAGIC2A	85072278
#define	LINUX_REBOOT_MAGIC2B	369367448
/*
 * Commands accepted by the _reboot() system call.
 *
 * RESTART     Restart system using default command and mode.
 * HALT        Stop OS and give system control to ROM monitor, if any.
 * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
 * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
 * POWER_OFF   Stop OS and remove all power from system, if possible.
 * RESTART2    Restart system using given command string.
 */
#define	LINUX_REBOOT_CMD_RESTART	0x01234567
#define	LINUX_REBOOT_CMD_HALT		0xCDEF0123
#define	LINUX_REBOOT_CMD_CAD_ON		0x89ABCDEF
#define	LINUX_REBOOT_CMD_CAD_OFF	0x00000000
#define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
#define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4


#define USE_LIBC

#ifdef USE_LIBC

/* libc version */
#if defined __GLIBC__ && __GLIBC__ >= 2
#  include <sys/reboot.h>
#  define REBOOT(cmd) reboot(cmd)
#else
extern int reboot(int, int, int);
#  define REBOOT(cmd) reboot(LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,(cmd))
#endif

static int my_reboot(int cmd)
{
	return REBOOT(cmd);
}

#else /* no USE_LIBC */

/* direct syscall version */
#include <linux/unistd.h>

#ifdef _syscall3
_syscall3(int,  reboot,  int,  magic, int, magic_too, int, cmd);
#else
/* Let us hope we have a 3-argument reboot here */
extern int reboot(int, int, int);
#endif

static int my_reboot(int cmd)
{
	return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd);
}

#endif


static void do_reboot(void)
{
	my_reboot(LINUX_REBOOT_CMD_RESTART);
}
static void do_poweroff(void)
{
	my_reboot(LINUX_REBOOT_CMD_POWER_OFF);
}
static void do_halt(void)
{
	my_reboot(LINUX_REBOOT_CMD_HALT);
}

static void usage(void)
{
	puts(
	    "Usage: hardshutdown -h|-r|-p [NN]\n"
	    "	NN - seconds to sleep before requested action"
	);
	exit(1);
}

enum action_t {
	SHUTDOWN,	// do nothing
	HALT,
	POWEROFF,
	REBOOT
};

int main(int argc, char *argv[])
{
	struct timespec t = {0,0};
	enum action_t action = SHUTDOWN;
	int c, i;
	char *prog, *ptr;

	//if (*argv[0] == '-') argv[0]++; /* allow shutdown as login shell */
	prog = argv[0];
	ptr = strrchr(prog,'/');
	if (ptr)
		prog = ptr+1;

	for (c=1; c < argc; c++) {
		if (argv[c][0] >= '0' && argv[c][0] <= '9') {
			t.tv_sec = strtol(argv[c], NULL, 10);
			continue;
		}
		if (argv[c][0] != '-') {
			usage();
			return 1;
		}
		for (i=1; argv[c][i]; i++) {
			switch (argv[c][i]) {
			case 'h':
				action = HALT;
				break;
			case 'p':
				action = POWEROFF;
				break;
			case 'r':
				action = REBOOT;
				break;
			default:
				usage();
				return 1;
			}
		}
	}

	if (action==SHUTDOWN) {
		usage();
		return 1;
	}

	chdir("/");
	while (nanosleep(&t,&t)<0)
		if (errno!=EINTR) break;

	switch (action) {
	case HALT:
		do_halt();
		break;
	case POWEROFF:
		do_poweroff();
		break;
	case REBOOT:
		do_reboot();
		break;
	default: /* SHUTDOWN */
		break;
	}
	return 1;
}