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
|
/*
* sysv-wrapper — translate traditional sysv-init commands to zygctl calls.
*
* Installed as multiple symlinks pointing at the same binary; we dispatch
* on argv[0] (basename) so each link behaves like the legacy tool.
*
* /sbin/init <runlevel> map runlevel char to a zygctl verb
* /sbin/telinit <runlevel> same; telinit is the historical client name
* /sbin/halt zygctl halt
* /sbin/reboot zygctl reboot
* /sbin/poweroff zygctl poweroff
*
* The wrapper itself does not connect to zyginit's socket — it just exec's
* /sbin/zygctl with the right verb. zygctl handles the socket protocol.
*
* Note: when /sbin/init is run by the kernel as PID 1, it is the zyginit
* daemon binary, NOT this wrapper. This wrapper lives at a different path
* (or replaces /sbin/init only on systems where zyginit is at /sbin/zyginit).
* On the current Hammerhead deploy /sbin/init IS zyginit; the wrapper
* is therefore meant for /sbin/halt, /sbin/reboot, /sbin/poweroff,
* /sbin/telinit. If you DO want /sbin/init to be this wrapper, install
* zyginit at /sbin/zyginit and point the kernel boot path there.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <errno.h>
#include "version.h"
#define ZYGCTL "/sbin/zygctl"
static int
run_zygctl(const char *verb)
{
execl(ZYGCTL, "zygctl", verb, (char *)NULL);
/* execl returns only on failure */
(void) fprintf(stderr, "%s: cannot exec %s: %s\n",
"sysv-wrapper", ZYGCTL, strerror(errno));
return (1);
}
static int
init_dispatch(int argc, char **argv)
{
if (argc < 2) {
(void) fprintf(stderr, "usage: %s <runlevel>\n", argv[0]);
return (1);
}
switch (argv[1][0]) {
case '0':
return (run_zygctl("halt"));
case '5':
return (run_zygctl("poweroff"));
case '6':
return (run_zygctl("reboot"));
case '1':
case 's':
case 'S':
return (run_zygctl("single"));
case '2':
case '3':
case '4':
return (run_zygctl("multi"));
case 'q':
case 'Q':
return (run_zygctl("reload"));
default:
(void) fprintf(stderr,
"%s: unknown runlevel '%s'\n", argv[0], argv[1]);
return (1);
}
}
int
main(int argc, char **argv)
{
const char *me;
char *argv0_copy;
/* basename(3) on illumos modifies its argument, so duplicate first */
argv0_copy = strdup(argv[0]);
if (argv0_copy == NULL) {
(void) fprintf(stderr, "out of memory\n");
return (1);
}
me = basename(argv0_copy);
if (argc >= 2 &&
(strcmp(argv[1], "--version") == 0 ||
strcmp(argv[1], "-V") == 0)) {
(void) printf("%s %s\n", me, ZYGINIT_VERSION);
free(argv0_copy);
return (0);
}
if (strcmp(me, "init") == 0 || strcmp(me, "telinit") == 0)
return (init_dispatch(argc, argv));
if (strcmp(me, "halt") == 0)
return (run_zygctl("halt"));
if (strcmp(me, "reboot") == 0)
return (run_zygctl("reboot"));
if (strcmp(me, "poweroff") == 0)
return (run_zygctl("poweroff"));
(void) fprintf(stderr, "sysv-wrapper: unknown invocation '%s'\n", me);
return (1);
}
|