311 lines
7.3 KiB
Diff
311 lines
7.3 KiB
Diff
autofs-5.1.8 - add command pipe handling functions
|
|
|
|
From: Ian Kent <raven@themaw.net>
|
|
|
|
In order to use a single file handle for a command pipe the pipe needs
|
|
to be independent of the kernel message packet handling function.
|
|
|
|
Add most of the functions needed for this as preperation.
|
|
|
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
|
---
|
|
CHANGELOG | 1
|
|
daemon/automount.c | 269 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 270 insertions(+)
|
|
|
|
--- autofs-5.1.7.orig/CHANGELOG
|
|
+++ autofs-5.1.7/CHANGELOG
|
|
@@ -126,6 +126,7 @@
|
|
- eliminate last remaining state_pipe usage.
|
|
- add function master_find_mapent_by_devid().
|
|
- use device id to locate autofs_point when setting log priotity.
|
|
+- add command pipe handling functions.
|
|
|
|
25/01/2021 autofs-5.1.7
|
|
- make bind mounts propagation slave by default.
|
|
--- autofs-5.1.7.orig/daemon/automount.c
|
|
+++ autofs-5.1.7/daemon/automount.c
|
|
@@ -60,6 +60,14 @@ unsigned int nfs_mount_uses_string_optio
|
|
static struct nfs_mount_vers vers, check = {1, 1, 1};
|
|
|
|
#define FIFO_BUF_SIZE 25
|
|
+static int cmd_pipe_fifo = -1;
|
|
+
|
|
+/* autofs cmd fifo name */
|
|
+#define FIFO_NAME "autofs.cmd.fifo"
|
|
+const char *cmd_pipe_name = AUTOFS_FIFO_DIR "/" FIFO_NAME;
|
|
+
|
|
+int start_cmd_pipe_handler(void);
|
|
+void finish_cmd_pipe_handler(void);
|
|
|
|
/* autofs fifo name prefix */
|
|
#define FIFO_NAME_PREFIX "autofs.fifo"
|
|
@@ -1654,6 +1662,267 @@ static void *signal_handler(void *arg)
|
|
}
|
|
}
|
|
|
|
+static pthread_mutex_t cmd_pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
+static unsigned int done = 0;
|
|
+static pthread_t cmd_pipe_thid;
|
|
+
|
|
+void cmd_pipe_mutex_lock(void)
|
|
+{
|
|
+ int status = pthread_mutex_lock(&cmd_pipe_mutex);
|
|
+ if (status)
|
|
+ fatal(status);
|
|
+}
|
|
+
|
|
+void cmd_pipe_mutex_unlock(void)
|
|
+{
|
|
+ int status = pthread_mutex_unlock(&cmd_pipe_mutex);
|
|
+ if (status)
|
|
+ fatal(status);
|
|
+}
|
|
+
|
|
+static int create_cmd_pipe_fifo(void)
|
|
+{
|
|
+ char buf[MAX_ERR_BUF];
|
|
+ int ret = -1;
|
|
+ int fd;
|
|
+
|
|
+ if (cmd_pipe_fifo != -1)
|
|
+ return 0;
|
|
+
|
|
+ ret = unlink(cmd_pipe_name);
|
|
+ if (ret != 0 && errno != ENOENT) {
|
|
+ fprintf(stderr,
|
|
+ "%s: failed to unlink command pipe. Is the "
|
|
+ "automount daemon already running?", program);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = mkfifo(cmd_pipe_name, S_IRUSR|S_IWUSR);
|
|
+ if (ret != 0 && errno != EEXIST) {
|
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ fprintf(stderr, "%s: mkfifo for %s failed: %s",
|
|
+ program, cmd_pipe_name, estr);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ fd = open_fd(cmd_pipe_name, O_RDWR|O_NONBLOCK);
|
|
+ if (fd < 0) {
|
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ unlink(cmd_pipe_name);
|
|
+ fprintf(stderr, "%s: failed to open cwcommand pipe %s: %s",
|
|
+ program, cmd_pipe_name, estr);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cmd_pipe_fifo = fd;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int destroy_cmd_pipe_fifo(void)
|
|
+{
|
|
+ char buf[MAX_ERR_BUF];
|
|
+ int ret = -1;
|
|
+
|
|
+ if (cmd_pipe_fifo == -1)
|
|
+ return 0;
|
|
+
|
|
+ ret = close(cmd_pipe_fifo);
|
|
+ if (ret != 0) {
|
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ warn(LOGOPT_ANY,
|
|
+ "close for command pipe %s: %s", cmd_pipe_name, estr);
|
|
+ }
|
|
+
|
|
+ cmd_pipe_fifo = -1;
|
|
+
|
|
+ ret = unlink(cmd_pipe_name);
|
|
+ if (ret != 0) {
|
|
+ warn(LOGOPT_ANY,
|
|
+ "failed to unlink FIFO. Was the fifo created OK?");
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void handle_cmd_pipe_fifo_message(int fd)
|
|
+{
|
|
+ struct autofs_point *ap;
|
|
+ char buffer[PIPE_BUF];
|
|
+ char *end, *sep;
|
|
+ char buf[MAX_ERR_BUF];
|
|
+ dev_t devid;
|
|
+ int ret;
|
|
+ long pri;
|
|
+
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ ret = read(fd, &buffer, sizeof(buffer));
|
|
+ if (ret < 0) {
|
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ warn(LOGOPT_ANY,
|
|
+ "read on command pipe returned error: %s", estr);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sep = strrchr(buffer, ' ');
|
|
+ if (!sep) {
|
|
+ error(LOGOPT_ANY,
|
|
+ "incorrect command pipe message format %s.", buffer);
|
|
+ return;
|
|
+ }
|
|
+ sep++;
|
|
+
|
|
+ errno = 0;
|
|
+ devid = strtol(buffer, &end, 10);
|
|
+ if ((devid == LONG_MIN || devid == LONG_MAX) && errno == ERANGE) {
|
|
+ debug(LOGOPT_ANY, "strtol reported a range error.");
|
|
+ error(LOGOPT_ANY, "invalid command pipe message format %s.", buffer);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((devid == 0 && errno == EINVAL) || end == buffer) {
|
|
+ debug(LOGOPT_ANY, "devid id is expected to be a integer.");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ap = master_find_mapent_by_devid(master_list, devid);
|
|
+ if (!ap) {
|
|
+ error(LOGOPT_ANY, "can't locate autofs_point for device id %ld.", devid);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ errno = 0;
|
|
+ pri = strtol(sep, &end, 10);
|
|
+ if ((pri == LONG_MIN || pri == LONG_MAX) && errno == ERANGE) {
|
|
+ error(ap->logopt, "failed to set log priority.");
|
|
+ error(ap->logopt, "strtol reported an %s.",
|
|
+ pri == LONG_MIN ? "underflow" : "overflow");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((pri == 0 && errno == EINVAL) || end == sep) {
|
|
+ debug(ap->logopt, "priority is expected to be an integer "
|
|
+ "in the range 0-7 inclusive.");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (pri > LOG_DEBUG || pri < LOG_EMERG) {
|
|
+ debug(ap->logopt,
|
|
+ "invalid log priority (%ld) received on fifo", pri);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * OK, the message passed all of the sanity checks. The
|
|
+ * automounter actually only supports three log priorities.
|
|
+ * Everything is logged at log level debug, deamon messages
|
|
+ * and everything except debug messages are logged with the
|
|
+ * verbose setting and only error and critical messages are
|
|
+ * logged when debugging isn't enabled.
|
|
+ */
|
|
+ if (pri >= LOG_WARNING) {
|
|
+ if (pri == LOG_DEBUG) {
|
|
+ set_log_debug_ap(ap);
|
|
+ info(ap->logopt, "debug logging set for %s", ap->path);
|
|
+ } else {
|
|
+ set_log_verbose_ap(ap);
|
|
+ info(ap->logopt, "verbose logging set for %s", ap->path);
|
|
+ }
|
|
+ } else {
|
|
+ if (ap->logopt & LOGOPT_ANY)
|
|
+ info(ap->logopt, "basic logging set for %s", ap->path);
|
|
+ set_log_norm_ap(ap);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void cmd_pipe_dummy(int sig)
|
|
+{
|
|
+}
|
|
+
|
|
+static void *cmd_pipe_handler(void *arg)
|
|
+{
|
|
+ struct sigaction sa;
|
|
+ sigset_t signalset;
|
|
+ struct pollfd fds[1];
|
|
+ int pollfds = 1;
|
|
+ char buf[MAX_ERR_BUF];
|
|
+ char *estr;
|
|
+
|
|
+ if (create_cmd_pipe_fifo())
|
|
+ return NULL;
|
|
+
|
|
+ fds[0].fd = cmd_pipe_fifo;
|
|
+ fds[0].events = POLLIN;
|
|
+
|
|
+ sa.sa_handler = cmd_pipe_dummy;
|
|
+ sigemptyset(&sa.sa_mask);
|
|
+ sa.sa_flags = 0;
|
|
+ if (sigaction(SIGPIPE, &sa, NULL) == -1) {
|
|
+ error(LOGOPT_ANY, "failed to set signal handler %d", errno);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ sigfillset(&signalset);
|
|
+ sigdelset(&signalset, SIGPIPE);
|
|
+
|
|
+ while (1) {
|
|
+ cmd_pipe_mutex_lock();
|
|
+ if (done) {
|
|
+ cmd_pipe_mutex_unlock();
|
|
+ break;
|
|
+ }
|
|
+ cmd_pipe_mutex_unlock();
|
|
+
|
|
+ errno = 0;
|
|
+ if (ppoll(fds, pollfds, NULL, &signalset) == -1) {
|
|
+ if (errno == EINTR)
|
|
+ continue;
|
|
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
+ logerr("poll failed: %s", estr);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (fds[0].revents & POLLIN) {
|
|
+ debug(LOGOPT_ANY, "message pending on control fifo.");
|
|
+ handle_cmd_pipe_fifo_message(fds[0].fd);
|
|
+ }
|
|
+ }
|
|
+ destroy_cmd_pipe_fifo();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+int start_cmd_pipe_handler(void)
|
|
+{
|
|
+ pthread_t thid;
|
|
+ pthread_attr_t attrs;
|
|
+ pthread_attr_t *pattrs = &attrs;
|
|
+ int status;
|
|
+
|
|
+ status = pthread_attr_init(pattrs);
|
|
+ if (status)
|
|
+ pattrs = NULL;
|
|
+ else
|
|
+ pthread_attr_setdetachstate(pattrs, PTHREAD_CREATE_DETACHED);
|
|
+
|
|
+ status = pthread_create(&thid, pattrs, cmd_pipe_handler, NULL);
|
|
+
|
|
+ if (pattrs)
|
|
+ pthread_attr_destroy(pattrs);
|
|
+
|
|
+ if (!status)
|
|
+ cmd_pipe_thid = thid;
|
|
+
|
|
+ return !status;
|
|
+}
|
|
+
|
|
+void finish_cmd_pipe_handler(void)
|
|
+{
|
|
+ cmd_pipe_mutex_lock();
|
|
+ done = 1;
|
|
+ pthread_kill(cmd_pipe_thid, SIGPIPE);
|
|
+ cmd_pipe_mutex_unlock();
|
|
+}
|
|
+
|
|
static void return_start_status(void *arg)
|
|
{
|
|
struct startup_cond *sc;
|