/* * Source: copy of the udev package source file * * Copyrights of the source file apply * Copyright (c) 2004 Christophe Varoqui */ #include #include #include #include #include #include #include #include #include #include "checkers.h" #include "vector.h" #include "structs.h" #include "util.h" #include "callout.h" #include "debug.h" int execute_program(char *path, char *value, int len) { int retval; int count; int status; int fds[2], null_fd; pid_t pid; char *pos; char arg[CALLOUT_MAX_SIZE]; int argc = sizeof(arg) / 2; char *argv[argc + 1]; int i; i = 0; if (strchr(path, ' ')) { strlcpy(arg, path, sizeof(arg)); pos = arg; while (pos != NULL && i < argc) { if (pos[0] == '\'') { /* don't separate if in apostrophes */ pos++; argv[i] = strsep(&pos, "\'"); while (pos[0] == ' ') pos++; } else { argv[i] = strsep(&pos, " "); } i++; } } else { argv[i++] = path; } argv[i] = NULL; retval = pipe(fds); if (retval != 0) { condlog(0, "error creating pipe for callout: %s", strerror(errno)); return -1; } pid = fork(); switch(pid) { case 0: /* child */ /* dup write side of pipe to STDOUT */ if (dup2(fds[1], STDOUT_FILENO) < 0) { condlog(1, "failed to dup2 stdout: %m"); return -1; } close(fds[0]); close(fds[1]); /* Ignore writes to stderr */ null_fd = open("/dev/null", O_WRONLY); if (null_fd > 0) { if (dup2(null_fd, STDERR_FILENO) < 0) condlog(1, "failed to dup2 stderr: %m"); close(null_fd); } retval = execv(argv[0], argv); condlog(0, "error execing %s : %s", argv[0], strerror(errno)); exit(-1); case -1: condlog(0, "fork failed: %s", strerror(errno)); close(fds[0]); close(fds[1]); return -1; default: /* parent reads from fds[0] */ close(fds[1]); retval = 0; i = 0; while (1) { count = read(fds[0], value + i, len - i-1); if (count <= 0) break; i += count; if (i >= len-1) { condlog(0, "not enough space for response from %s", argv[0]); retval = -1; break; } } if (count < 0) { condlog(0, "no response from %s", argv[0]); retval = -1; } if (i > 0 && value[i-1] == '\n') i--; value[i] = '\0'; wait(&status); close(fds[0]); retval = -1; if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status == 0) retval = 0; else condlog(0, "%s exited with %d", argv[0], status); } else if (WIFSIGNALED(status)) condlog(0, "%s was terminated by signal %d", argv[0], WTERMSIG(status)); else condlog(0, "%s terminated abnormally", argv[0]); } return retval; } int apply_format(char * string, char * cmd, struct path * pp) { char * pos; char * dst; char * p; char * q; int len; int myfree; if (!string) return 1; if (!cmd) return 1; dst = cmd; p = dst; pos = strchr(string, '%'); myfree = CALLOUT_MAX_SIZE; if (!pos) { strcpy(dst, string); return 0; } len = (int) (pos - string) + 1; myfree -= len; if (myfree < 2) return 1; snprintf(p, len, "%s", string); p += len - 1; pos++; switch (*pos) { case 'n': len = strlen(pp->dev) + 1; myfree -= len; if (myfree < 2) return 1; snprintf(p, len, "%s", pp->dev); for (q = p; q < p + len; q++) { if (q && *q == '!') *q = '/'; } p += len - 1; break; case 'd': len = strlen(pp->dev_t) + 1; myfree -= len; if (myfree < 2) return 1; snprintf(p, len, "%s", pp->dev_t); p += len - 1; break; default: break; } pos++; if (!*pos) { condlog(3, "formatted callout = %s", dst); return 0; } len = strlen(pos) + 1; myfree -= len; if (myfree < 2) return 1; snprintf(p, len, "%s", pos); condlog(3, "reformatted callout = %s", dst); return 0; }