|
root / tools / sysv-wrapper / wrapper.c
wrapper.c C 112 lines 3.0 KB
  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);
}