1/*
2 * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 *	This program is free software; you can redistribute it and/or modify it
5 *	under the terms of the GNU General Public License as published by the
6 *	Free Software Foundation version 2 of the License.
7 *
8 *	This program is distributed in the hope that it will be useful, but
9 *	WITHOUT ANY WARRANTY; without even the implied warranty of
10 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 *	General Public License for more details.
12 *
13 *	You should have received a copy of the GNU General Public License along
14 *	with this program; if not, write to the Free Software Foundation, Inc.,
15 *	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 *
17 */
18
19#include <time.h>
20#include <errno.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <stddef.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <sys/wait.h>
29#include <sys/un.h>
30
31#include "udev.h"
32#include "udevd.h"
33
34static int sock = -1;
35static int udev_log = 0;
36
37#ifdef USE_LOG
38void log_message (int priority, const char *format, ...)
39{
40	va_list	args;
41
42	if (priority > udev_log)
43		return;
44
45	va_start(args, format);
46	vsyslog(priority, format, args);
47	va_end(args);
48}
49#endif
50
51int main(int argc, char *argv[], char *envp[])
52{
53	static struct udevd_ctrl_msg ctrl_msg;
54	struct sockaddr_un saddr;
55	socklen_t addrlen;
56	const char *env;
57	const char *arg;
58	const char *val;
59	int *intval;
60	int retval = 1;
61
62	env = getenv("UDEV_LOG");
63	if (env)
64		udev_log = log_priority(env);
65
66	logging_init("udevcontrol");
67	dbg("version %s", UDEV_VERSION);
68
69	if (argc < 2) {
70		fprintf(stderr, "missing command\n\n");
71		goto exit;
72	}
73	memset(&ctrl_msg, 0x00, sizeof(struct udevd_ctrl_msg));
74	strcpy(ctrl_msg.magic, UDEVD_CTRL_MAGIC);
75	arg = argv[1];
76
77	if (!strcmp(arg, "stop_exec_queue"))
78		ctrl_msg.type = UDEVD_CTRL_STOP_EXEC_QUEUE;
79	else if (!strcmp(arg, "start_exec_queue"))
80		ctrl_msg.type = UDEVD_CTRL_START_EXEC_QUEUE;
81	else if (!strcmp(arg, "reload_rules"))
82		ctrl_msg.type = UDEVD_CTRL_RELOAD_RULES;
83	else if (!strncmp(arg, "log_priority=", strlen("log_priority="))) {
84		intval = (int *) ctrl_msg.buf;
85		val = &arg[strlen("log_priority=")];
86		ctrl_msg.type = UDEVD_CTRL_SET_LOG_LEVEL;
87		*intval = log_priority(val);
88		info("send log_priority=%i", *intval);
89	} else if (!strncmp(arg, "max_childs=", strlen("max_childs="))) {
90		char *endp;
91		int count;
92
93		intval = (int *) ctrl_msg.buf;
94		val = &arg[strlen("max_childs=")];
95		ctrl_msg.type = UDEVD_CTRL_SET_MAX_CHILDS;
96		count = strtoul(val, &endp, 0);
97		if (endp[0] != '\0' || count < 1) {
98			fprintf(stderr, "invalid number\n");
99			goto exit;
100		}
101		*intval = count;
102		info("send max_childs=%i", *intval);
103	} else if (!strncmp(arg, "max_childs_running=", strlen("max_childs_running="))) {
104		char *endp;
105		int count;
106
107		intval = (int *) ctrl_msg.buf;
108		val = &arg[strlen("max_childs_running=")];
109		ctrl_msg.type = UDEVD_CTRL_SET_MAX_CHILDS_RUNNING;
110		count = strtoul(val, &endp, 0);
111		if (endp[0] != '\0' || count < 1) {
112			fprintf(stderr, "invalid number\n");
113			goto exit;
114		}
115		*intval = count;
116		info("send max_childs_running=%i", *intval);
117	} else if (!strncmp(arg, "env", strlen("env"))) {
118		val = argv[2];
119		if (val == NULL) {
120			fprintf(stderr, "missing key\n");
121			goto exit;
122		}
123		ctrl_msg.type = UDEVD_CTRL_ENV;
124		strlcpy(ctrl_msg.buf, val, sizeof(ctrl_msg.buf));
125		info("send env '%s'", val);
126	} else if (strcmp(arg, "help") == 0  || strcmp(arg, "--help") == 0  || strcmp(arg, "-h") == 0) {
127		printf("Usage: udevcontrol COMMAND\n"
128			"  log_priority=<level>   set the udev log level for the daemon\n"
129			"  stop_exec_queue        keep udevd from executing events, queue only\n"
130			"  start_exec_queue       execute events, flush queue\n"
131			"  reload_rules           reloads the rules files\n"
132			"  env <var>=<value>      set a global environment variable\n"
133			"  max_childs=<N>         maximum number of childs\n"
134			"  max_childs_running=<N> maximum number of childs running at the same time\n"
135			"  help                   print this help text\n\n");
136		goto exit;
137	} else {
138		fprintf(stderr, "unrecognized command '%s'\n", arg);
139		goto exit;
140	}
141
142	if (getuid() != 0) {
143		fprintf(stderr, "root privileges required\n");
144		goto exit;
145	}
146
147	sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
148	if (sock == -1) {
149		err("error getting socket: %s", strerror(errno));
150		goto exit;
151	}
152
153	memset(&saddr, 0x00, sizeof(struct sockaddr_un));
154	saddr.sun_family = AF_LOCAL;
155	/* use abstract namespace for socket path */
156	strcpy(&saddr.sun_path[1], UDEVD_CTRL_SOCK_PATH);
157	addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
158
159	retval = sendto(sock, &ctrl_msg, sizeof(ctrl_msg), 0, (struct sockaddr *)&saddr, addrlen);
160	if (retval == -1) {
161		err("error sending message: %s", strerror(errno));
162		retval = 1;
163	} else {
164		dbg("sent message type=0x%02x, %u bytes sent", ctrl_msg.type, retval);
165		retval = 0;
166	}
167
168	close(sock);
169exit:
170	logging_close();
171	return retval;
172}
173