#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
+#include <ctype.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <unistd.h>
+#include <sys/wait.h>
static int quit = 0;
static int info = 0;
return rv;
}
+static int _reopen_fd_to_null(int fd)
+{
+ int null_fd;
+ int r = 0;
+
+ if ((null_fd = open("/dev/null", O_RDWR)) == -1) {
+ log_error("open error /dev/null %d", errno);
+ return 0;
+ }
+
+ if (close(fd)) {
+ log_error("close error fd %d %d", fd, errno);
+ goto out;
+ }
+
+ if (dup2(null_fd, fd) == -1) {
+ log_error("dup2 error %d", errno);
+ goto out;
+ }
+
+ r = 1;
+out:
+ if (close(null_fd)) {
+ log_error("close error fd %d %d", null_fd, errno);
+ return 0;
+ }
+
+ return r;
+}
+
+#define MAX_AV_COUNT 32
+#define ONE_ARG_LEN 1024
+
+static void _run_command_pipe(const char *cmd_str, pid_t *pid_out, FILE **fp_out)
+{
+ char arg[ONE_ARG_LEN];
+ char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
+ char *arg_dup;
+ int av_count = 0;
+ int cmd_len;
+ int arg_len;
+ pid_t pid = 0;
+ FILE *fp = NULL;
+ int pipefd[2];
+ int i;
+
+ for (i = 0; i < MAX_AV_COUNT + 1; i++)
+ av[i] = NULL;
+
+ cmd_len = strlen(cmd_str);
+
+ memset(&arg, 0, sizeof(arg));
+ arg_len = 0;
+
+ for (i = 0; i < cmd_len; i++) {
+ if (!cmd_str[i])
+ break;
+
+ if (av_count == MAX_AV_COUNT)
+ goto out;
+
+ if (cmd_str[i] == '\\') {
+ if (i == (cmd_len - 1))
+ break;
+ i++;
+
+ if (cmd_str[i] == '\\') {
+ arg[arg_len++] = cmd_str[i];
+ continue;
+ }
+ if (isspace(cmd_str[i])) {
+ arg[arg_len++] = cmd_str[i];
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
+ arg[arg_len++] = cmd_str[i];
+ } else if (isspace(cmd_str[i])) {
+ if (arg_len) {
+ if (!(arg_dup = strdup(arg)))
+ goto out;
+ av[av_count++] = arg_dup;
+ }
+
+ memset(arg, 0, sizeof(arg));
+ arg_len = 0;
+ } else {
+ break;
+ }
+ }
+
+ if (arg_len) {
+ if (av_count >= MAX_AV_COUNT)
+ goto out;
+ if (!(arg_dup = strdup(arg)))
+ goto out;
+ av[av_count++] = arg_dup;
+ }
+
+ if (pipe(pipefd)) {
+ log_error("pipe error %d", errno);
+ goto out;
+ }
+
+ pid = fork();
+
+ if (pid < 0) {
+ log_error("fork error %d", errno);
+ pid = 0;
+ goto out;
+ }
+
+ if (pid == 0) {
+ /* Child -> writer, convert pipe[0] to STDOUT */
+ if (!_reopen_fd_to_null(STDIN_FILENO))
+ log_error("reopen STDIN error");
+ else if (close(pipefd[0 /*read*/]))
+ log_error("close error pipe[0] %d", errno);
+ else if (close(STDOUT_FILENO))
+ log_error("close error STDOUT %d", errno);
+ else if (dup2(pipefd[1 /*write*/], STDOUT_FILENO) == -1)
+ log_error("dup2 error STDOUT %d", errno);
+ else if (close(pipefd[1]))
+ log_error("close error pipe[1] %d", errno);
+ else {
+ execvp(av[0], av);
+ log_error("execvp error %d", errno);
+ }
+ _exit(errno);
+ }
+
+ /* Parent -> reader */
+ if (close(pipefd[1 /*write*/]))
+ log_error("close error STDOUT %d", errno);
+
+ if (!(fp = fdopen(pipefd[0 /*read*/], "r"))) {
+ log_error("fdopen STDIN error %d", errno);
+ if (close(pipefd[0]))
+ log_error("close error STDIN %d", errno);
+ }
+
+ out:
+ for (i = 0; i < MAX_AV_COUNT + 1; i++)
+ free(av[i]);
+
+ *pid_out = pid;
+ *fp_out = fp;
+}
+
+/* Returns -1 on error, 0 on success. */
+
+static int _close_command_pipe(pid_t pid, FILE *fp)
+{
+ int status, estatus;
+ int ret = -1;
+
+ if (waitpid(pid, &status, 0) != pid) {
+ log_error("waitpid error pid %d %d", pid, errno);
+ goto out;
+ }
+
+ if (WIFEXITED(status)) {
+ /* pid exited with an exit code */
+ estatus = WEXITSTATUS(status);
+
+ /* exit status 0: child success */
+ if (!estatus) {
+ ret = 0;
+ goto out;
+ }
+
+ /* exit status not zero: child error */
+ log_error("child exit error %d", estatus);
+ goto out;
+ }
+
+ if (WIFSIGNALED(status)) {
+ /* pid terminated due to a signal */
+ log_error("child exit from signal");
+ goto out;
+ }
+
+ log_error("child exit problem");
+
+out:
+ if (fp && fclose(fp))
+ log_error("fclose error STDIN %d", errno);
+ return ret;
+}
+
/* Returns -1 on error, 0 on success. */
static int _get_kill_command(char *kill_cmd)
{
- char config_cmd[PATH_MAX] = { 0 };
+ char config_cmd[PATH_MAX + 128] = { 0 };
char config_val[1024] = { 0 };
char line[PATH_MAX] = { 0 };
- char type[4] = { 0 };
- FILE *fp;
+ pid_t pid = 0;
+ FILE *fp = NULL;
- snprintf(config_cmd, PATH_MAX, "%s/lvmconfig --typeconfig full global/lvmlockctl_kill_command", LVM_DIR);
- type[0] = 'r';
+ snprintf(config_cmd, PATH_MAX, "%s config --typeconfig full global/lvmlockctl_kill_command", LVM_PATH);
- if (!(fp = popen(config_cmd, type))) {
+ _run_command_pipe(config_cmd, &pid, &fp);
+
+ if (!pid) {
log_error("failed to run %s", config_cmd);
return -1;
}
+ if (!fp) {
+ log_error("failed to get output %s", config_cmd);
+ _close_command_pipe(pid, fp);
+ return -1;
+ }
+
if (!fgets(line, sizeof(line), fp)) {
log_error("no output from %s", config_cmd);
goto bad;
goto bad;
}
+ if (config_val[0] != '/') {
+ log_error("lvmlockctl_kill_command must be full path");
+ goto bad;
+ }
+
printf("Found lvmlockctl_kill_command: %s\n", config_val);
snprintf(kill_cmd, PATH_MAX, "%s %s", config_val, arg_vg_name);
+ kill_cmd[PATH_MAX-1] = '\0';
- pclose(fp);
+ _close_command_pipe(pid, fp);
return 0;
bad:
- pclose(fp);
+ _close_command_pipe(pid, fp);
return -1;
}
static int _run_kill_command(char *kill_cmd)
{
- int status;
+ pid_t pid = 0;
+ FILE *fp = NULL;
+ int rv;
- status = system(kill_cmd);
+ _run_command_pipe(kill_cmd, &pid, &fp);
+ rv = _close_command_pipe(pid, fp);
- if (!WEXITSTATUS(status))
- return 0;
+ if (!pid)
+ return -1;
- return -1;
+ if (rv < 0)
+ return -1;
+
+ return 0;
}
static int do_drop(void)