--- /dev/null
+.\" $OpenBSD: hotplugd.8,v 1.10 2009/03/20 17:53:14 jasper Exp $
+.\"
+.\" Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: December 7 2008 $
+.Dt HOTPLUGD 8
+.Os
+.Sh NAME
+.Nm hotplugd
+.Nd devices hot plugging monitor daemon
+.Sh SYNOPSIS
+.Nm hotplugd
+.Op Fl d Ar device
+.Sh DESCRIPTION
+The
+.Nm
+daemon monitors the
+.Xr hotplug 4
+pseudo-device, acting on signaled events by executing the scripts in the
+.Pa /etc/hotplug
+directory.
+By default it uses the
+.Pa /dev/hotplug
+device for reading events from, but an alternative device can be
+specified with the
+.Fl d
+option.
+.Pp
+Actions can be configured either for device attachment or detachment.
+On device attachment the
+.Pa attach
+script is executed if it exists.
+On device detachment the
+.Pa detach
+script is executed if it exists.
+In both cases two parameters are passed to the scripts: the class and name
+of the attached or detached device.
+The device class corresponds to the classes described in the
+.Aq Pa sys/device.h
+header file and can be one of the following:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It 0
+generic, no special info
+.It 1
+CPU (carries resource utilization)
+.It 2
+disk drive
+.It 3
+network interface
+.It 4
+tape device
+.It 5
+serial line interface
+.El
+.Pp
+Not all classes are really usable.
+For example, it's unlikely that a CPU will be hotplugged.
+.Pp
+The device name is the usual name,
+as listed in
+.Xr MAKEDEV 8 ,
+and the unit number, e.g.\&
+.Pa sd1 .
+.Sh FILES
+.Bl -tag -width "/dev/hotplug/attach" -compact
+.It /dev/hotplug
+Pseudo-device file.
+.It /etc/hotplug
+Directory where the scripts to execute are located.
+.It /etc/hotplug/attach
+Script to execute on device attachment.
+.It /etc/hotplug/detach
+Script to execute on device detachment.
+.El
+.Sh EXAMPLES
+Sample
+.Pa attach
+script:
+.Bd -literal -offset indent
+#!/bin/sh
+
+DEVCLASS=$1
+DEVNAME=$2
+
+case $DEVCLASS in
+2)
+ # disk devices
+ disklabel=`/sbin/disklabel $DEVNAME 2\*(Gt&1 | \e
+ sed -n '/^label: /s/^label: //p'`
+ case $disklabel in
+ Sony*DSC*)
+ # Sony DSC camera
+ mount -o nodev,nosuid /dev/"$DEVNAME"i /mnt/camera
+ ;;
+ esac
+ ;;
+3)
+ # network devices; requires hostname.$DEVNAME
+ sh /etc/netstart $DEVNAME
+ ;;
+esac
+.Ed
+.Sh SEE ALSO
+.Xr hotplug 4
+.Sh HISTORY
+The
+.Nm
+program first appeared in
+.Ox 3.6 .
+.Sh AUTHORS
+The
+.Nm
+program was written by
+.An Alexander Yurchenko Aq grange@openbsd.org .
--- /dev/null
+/* $OpenBSD: hotplugd.c,v 1.11 2009/06/26 01:06:04 kurt Exp $ */
+/*
+ * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Devices hot plugging daemon.
+ */
+
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/hotplug.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "compat.h"
+
+#define _PATH_DEV_HOTPLUG "/dev/hotplug"
+#define _PATH_ETC_HOTPLUG "/etc/hotplug"
+#define _PATH_ETC_HOTPLUG_ATTACH _PATH_ETC_HOTPLUG "/attach"
+#define _PATH_ETC_HOTPLUG_DETACH _PATH_ETC_HOTPLUG "/detach"
+#define _LOG_TAG "hotplugd"
+#define _LOG_FACILITY LOG_DAEMON
+#define _LOG_OPT (LOG_NDELAY | LOG_PID)
+
+volatile sig_atomic_t quit = 0;
+char *device = _PATH_DEV_HOTPLUG;
+int devfd = -1;
+
+void exec_script(const char *, int, char *);
+void sigchild(int);
+void sigquit(int);
+__dead void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ struct sigaction sact;
+ struct hotplug_event he;
+
+ while ((ch = getopt(argc, argv, "d:")) != -1)
+ switch (ch) {
+ case 'd':
+ device = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc > 0)
+ usage();
+
+ if ((devfd = open(device, O_RDONLY)) == -1)
+ err(1, "%s", device);
+
+ bzero(&sact, sizeof(sact));
+ sigemptyset(&sact.sa_mask);
+ sact.sa_flags = 0;
+ sact.sa_handler = sigquit;
+ sigaction(SIGINT, &sact, NULL);
+ sigaction(SIGQUIT, &sact, NULL);
+ sigaction(SIGTERM, &sact, NULL);
+ sact.sa_handler = SIG_IGN;
+ sigaction(SIGHUP, &sact, NULL);
+ sact.sa_handler = sigchild;
+ sact.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &sact, NULL);
+
+ openlog(_LOG_TAG, _LOG_OPT, _LOG_FACILITY);
+ if (daemon(0, 0) == -1)
+ err(1, "daemon");
+
+ syslog(LOG_INFO, "started");
+
+ while (!quit) {
+ if (read(devfd, &he, sizeof(he)) == -1) {
+ if (errno == EINTR)
+ /* ignore */
+ continue;
+ syslog(LOG_ERR, "read: %m");
+ exit(1);
+ }
+
+ switch (he.he_type) {
+ case HOTPLUG_DEVAT:
+ syslog(LOG_INFO, "%s attached, class %d",
+ he.he_devname, he.he_devclass);
+ exec_script(_PATH_ETC_HOTPLUG_ATTACH, he.he_devclass,
+ he.he_devname);
+ break;
+ case HOTPLUG_DEVDT:
+ syslog(LOG_INFO, "%s detached, class %d",
+ he.he_devname, he.he_devclass);
+ exec_script(_PATH_ETC_HOTPLUG_DETACH, he.he_devclass,
+ he.he_devname);
+ break;
+ default:
+ syslog(LOG_NOTICE, "unknown event (0x%x)", he.he_type);
+ }
+ }
+
+ syslog(LOG_INFO, "terminated");
+
+ closelog();
+ close(devfd);
+
+ return (0);
+}
+
+void
+exec_script(const char *file, int class, char *name)
+{
+ char strclass[8];
+ pid_t pid;
+
+ snprintf(strclass, sizeof(strclass), "%d", class);
+
+ if (access(file, X_OK | R_OK)) {
+ syslog(LOG_ERR, "could not access %s", file);
+ return;
+ }
+
+ if ((pid = fork()) == -1) {
+ syslog(LOG_ERR, "fork: %m");
+ return;
+ }
+ if (pid == 0) {
+ /* child process */
+ execl(file, basename(file), strclass, name, (char *)NULL);
+ syslog(LOG_ERR, "execl %s: %m", file);
+ _exit(1);
+ /* NOTREACHED */
+ }
+}
+
+/* ARGSUSED */
+void
+sigchild(int signum)
+{
+ struct syslog_data sdata = SYSLOG_DATA_INIT;
+ int saved_errno, status;
+ pid_t pid;
+
+ saved_errno = errno;
+
+ sdata.log_tag = _LOG_TAG;
+ sdata.log_fac = _LOG_FACILITY;
+ sdata.log_stat = _LOG_OPT;
+
+ while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) {
+ if (pid == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno != ECHILD)
+ syslog_r(LOG_ERR, &sdata, "waitpid: %m");
+ break;
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ syslog_r(LOG_NOTICE, &sdata,
+ "child exit status: %d",
+ WEXITSTATUS(status));
+ }
+ } else {
+ syslog_r(LOG_NOTICE, &sdata,
+ "child is terminated abnormally");
+ }
+ }
+
+ errno = saved_errno;
+}
+
+/* ARGSUSED */
+void
+sigquit(int signum)
+{
+ quit = 1;
+}
+
+__dead void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-d device]\n", __progname);
+ exit(1);
+}