Import hotplugd(8) from OpenBSD. hotplug2
authorAlexander Polakov <polachok@gmail.com>
Sun, 15 Nov 2009 22:51:29 +0000 (01:51 +0300)
committerAlexander Polakov <polachok@gmail.com>
Fri, 4 Dec 2009 22:01:36 +0000 (01:01 +0300)
sbin/hotplugd/Makefile [new file with mode: 0644]
sbin/hotplugd/compat.h [new file with mode: 0644]
sbin/hotplugd/hotplugd.8 [new file with mode: 0644]
sbin/hotplugd/hotplugd.c [new file with mode: 0644]

diff --git a/sbin/hotplugd/Makefile b/sbin/hotplugd/Makefile
new file mode 100644 (file)
index 0000000..a370ab6
--- /dev/null
@@ -0,0 +1,6 @@
+PROG=  hotplugd
+SRCS=  hotplugd.c
+MAN=   hotplugd.8
+
+WARNS= 1
+.include <bsd.prog.mk>
diff --git a/sbin/hotplugd/compat.h b/sbin/hotplugd/compat.h
new file mode 100644 (file)
index 0000000..a298ac8
--- /dev/null
@@ -0,0 +1,15 @@
+/* Used by reentrant functions */
+
+struct syslog_data {
+       int     log_file;
+       int     connected;
+       int     opened;
+       int     log_stat;
+       const char      *log_tag;
+       int     log_fac;
+       int     log_mask;
+};
+
+#define SYSLOG_DATA_INIT {-1, 0, 0, 0, (const char *)0, LOG_USER, 0xff}
+#define syslog_r(_a, _b, _c...) syslog(_a, _c)
+#define __dead
diff --git a/sbin/hotplugd/hotplugd.8 b/sbin/hotplugd/hotplugd.8
new file mode 100644 (file)
index 0000000..1a8ce3a
--- /dev/null
@@ -0,0 +1,127 @@
+.\"    $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 .
diff --git a/sbin/hotplugd/hotplugd.c b/sbin/hotplugd/hotplugd.c
new file mode 100644 (file)
index 0000000..a2dcdf7
--- /dev/null
@@ -0,0 +1,215 @@
+/*     $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);
+}