GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/hotplugd/hotplugd.c Lines: 0 81 0.0 %
Date: 2017-11-07 Branches: 0 41 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: hotplugd.c,v 1.14 2016/07/31 20:13:12 natano Exp $	*/
2
/*
3
 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/*
19
 * Devices hot plugging daemon.
20
 */
21
22
#include <sys/types.h>
23
#include <sys/device.h>
24
#include <sys/hotplug.h>
25
#include <sys/wait.h>
26
27
#include <err.h>
28
#include <errno.h>
29
#include <fcntl.h>
30
#include <libgen.h>
31
#include <signal.h>
32
#include <stdarg.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <syslog.h>
37
#include <unistd.h>
38
39
#define _PATH_DEV_HOTPLUG		"/dev/hotplug"
40
#define _PATH_ETC_HOTPLUG		"/etc/hotplug"
41
#define _PATH_ETC_HOTPLUG_ATTACH	_PATH_ETC_HOTPLUG "/attach"
42
#define _PATH_ETC_HOTPLUG_DETACH	_PATH_ETC_HOTPLUG "/detach"
43
#define _LOG_TAG			"hotplugd"
44
#define _LOG_FACILITY			LOG_DAEMON
45
#define _LOG_OPT			(LOG_NDELAY | LOG_PID)
46
47
volatile sig_atomic_t quit = 0;
48
char *device = _PATH_DEV_HOTPLUG;
49
int devfd = -1;
50
51
void exec_script(const char *, int, char *);
52
53
void sigchild(int);
54
void sigquit(int);
55
__dead void usage(void);
56
57
int
58
main(int argc, char *argv[])
59
{
60
	int ch;
61
	struct sigaction sact;
62
	struct hotplug_event he;
63
64
	if (pledge("stdio rpath proc exec flock cpath wpath", NULL) == -1)
65
		err(1, "pledge");
66
67
	while ((ch = getopt(argc, argv, "d:")) != -1)
68
		switch (ch) {
69
		case 'd':
70
			device = optarg;
71
			break;
72
		case '?':
73
		default:
74
			usage();
75
			/* NOTREACHED */
76
		}
77
78
	argc -= optind;
79
	argv += optind;
80
	if (argc > 0)
81
		usage();
82
83
	if ((devfd = open(device, O_RDONLY | O_CLOEXEC)) == -1)
84
		err(1, "%s", device);
85
86
	bzero(&sact, sizeof(sact));
87
	sigemptyset(&sact.sa_mask);
88
	sact.sa_flags = 0;
89
	sact.sa_handler = sigquit;
90
	sigaction(SIGINT, &sact, NULL);
91
	sigaction(SIGQUIT, &sact, NULL);
92
	sigaction(SIGTERM, &sact, NULL);
93
	sact.sa_handler = SIG_IGN;
94
	sigaction(SIGHUP, &sact, NULL);
95
	sact.sa_handler = sigchild;
96
	sact.sa_flags = SA_NOCLDSTOP;
97
	sigaction(SIGCHLD, &sact, NULL);
98
99
	openlog(_LOG_TAG, _LOG_OPT, _LOG_FACILITY);
100
	if (daemon(0, 0) == -1)
101
		err(1, "daemon");
102
103
	syslog(LOG_INFO, "started");
104
105
	while (!quit) {
106
		if (read(devfd, &he, sizeof(he)) == -1) {
107
			if (errno == EINTR)
108
				/* ignore */
109
				continue;
110
			syslog(LOG_ERR, "read: %m");
111
			exit(1);
112
		}
113
114
		switch (he.he_type) {
115
		case HOTPLUG_DEVAT:
116
			syslog(LOG_INFO, "%s attached, class %d",
117
			    he.he_devname, he.he_devclass);
118
			exec_script(_PATH_ETC_HOTPLUG_ATTACH, he.he_devclass,
119
			    he.he_devname);
120
			break;
121
		case HOTPLUG_DEVDT:
122
			syslog(LOG_INFO, "%s detached, class %d",
123
			    he.he_devname, he.he_devclass);
124
			exec_script(_PATH_ETC_HOTPLUG_DETACH, he.he_devclass,
125
			    he.he_devname);
126
			break;
127
		default:
128
			syslog(LOG_NOTICE, "unknown event (0x%x)", he.he_type);
129
		}
130
	}
131
132
	syslog(LOG_INFO, "terminated");
133
134
	closelog();
135
	close(devfd);
136
137
	return (0);
138
}
139
140
void
141
exec_script(const char *file, int class, char *name)
142
{
143
	char strclass[8];
144
	pid_t pid;
145
146
	snprintf(strclass, sizeof(strclass), "%d", class);
147
148
	if (access(file, X_OK | R_OK) == -1) {
149
		if (errno != ENOENT)
150
			syslog(LOG_ERR, "%s: %m", file);
151
		return;
152
	}
153
154
	if ((pid = fork()) == -1) {
155
		syslog(LOG_ERR, "fork: %m");
156
		return;
157
	}
158
	if (pid == 0) {
159
		/* child process */
160
		execl(file, basename(file), strclass, name, (char *)NULL);
161
		syslog(LOG_ERR, "execl %s: %m", file);
162
		_exit(1);
163
		/* NOTREACHED */
164
	}
165
}
166
167
/* ARGSUSED */
168
void
169
sigchild(int signum)
170
{
171
	struct syslog_data sdata = SYSLOG_DATA_INIT;
172
	int saved_errno, status;
173
	pid_t pid;
174
175
	saved_errno = errno;
176
177
	sdata.log_tag = _LOG_TAG;
178
	sdata.log_fac = _LOG_FACILITY;
179
	sdata.log_stat = _LOG_OPT;
180
181
	while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) {
182
		if (pid == -1) {
183
			if (errno == EINTR)
184
				continue;
185
			if (errno != ECHILD)
186
				syslog_r(LOG_ERR, &sdata, "waitpid: %m");
187
			break;
188
		}
189
190
		if (WIFEXITED(status)) {
191
			if (WEXITSTATUS(status) != 0) {
192
				syslog_r(LOG_NOTICE, &sdata,
193
				    "child exit status: %d",
194
				    WEXITSTATUS(status));
195
			}
196
		} else {
197
			syslog_r(LOG_NOTICE, &sdata,
198
			    "child is terminated abnormally");
199
		}
200
	}
201
202
	errno = saved_errno;
203
}
204
205
/* ARGSUSED */
206
void
207
sigquit(int signum)
208
{
209
	quit = 1;
210
}
211
212
__dead void
213
usage(void)
214
{
215
	extern char *__progname;
216
217
	fprintf(stderr, "usage: %s [-d device]\n", __progname);
218
	exit(1);
219
}