autofs-5.1.8 - add command pipe handling functions From: Ian Kent 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 --- CHANGELOG | 1 daemon/automount.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 86326a8d..09b5b157 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -66,6 +66,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. 19/10/2021 autofs-5.1.8 - add xdr_exports(). diff --git a/daemon/automount.c b/daemon/automount.c index 1164198e..33301121 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -70,6 +70,14 @@ unsigned int nfs_mount_uses_string_options = 0; 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" @@ -1687,6 +1695,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;