diff options
Diffstat (limited to 'lib/utils_cmd.c')
| -rw-r--r-- | lib/utils_cmd.c | 107 |
1 files changed, 49 insertions, 58 deletions
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c index d1feaa33..35b83297 100644 --- a/lib/utils_cmd.c +++ b/lib/utils_cmd.c | |||
| @@ -40,7 +40,6 @@ | |||
| 40 | 40 | ||
| 41 | /** includes **/ | 41 | /** includes **/ |
| 42 | #include "common.h" | 42 | #include "common.h" |
| 43 | #include "utils.h" | ||
| 44 | #include "utils_cmd.h" | 43 | #include "utils_cmd.h" |
| 45 | /* This variable must be global, since there's no way the caller | 44 | /* This variable must be global, since there's no way the caller |
| 46 | * can forcibly slay a dead or ungainly running program otherwise. | 45 | * can forcibly slay a dead or ungainly running program otherwise. |
| @@ -62,9 +61,6 @@ static pid_t *_cmd_pids = NULL; | |||
| 62 | # include <sys/wait.h> | 61 | # include <sys/wait.h> |
| 63 | #endif | 62 | #endif |
| 64 | 63 | ||
| 65 | /* used in _cmd_open to pass the environment to commands */ | ||
| 66 | extern char **environ; | ||
| 67 | |||
| 68 | /** macros **/ | 64 | /** macros **/ |
| 69 | #ifndef WEXITSTATUS | 65 | #ifndef WEXITSTATUS |
| 70 | # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) | 66 | # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) |
| @@ -80,14 +76,12 @@ extern char **environ; | |||
| 80 | #endif | 76 | #endif |
| 81 | 77 | ||
| 82 | /** prototypes **/ | 78 | /** prototypes **/ |
| 83 | static int _cmd_open(char *const *, int *, int *) __attribute__((__nonnull__(1, 2, 3))); | 79 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) |
| 84 | 80 | __attribute__((__nonnull__(1, 2, 3))); | |
| 85 | static int _cmd_fetch_output(int, output *, int) __attribute__((__nonnull__(2))); | ||
| 86 | 81 | ||
| 87 | static int _cmd_close(int); | 82 | static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) __attribute__((__nonnull__(2))); |
| 88 | 83 | ||
| 89 | /* prototype imported from utils.h */ | 84 | static int _cmd_close(int fileDescriptor); |
| 90 | extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3))); | ||
| 91 | 85 | ||
| 92 | /* this function is NOT async-safe. It is exported so multithreaded | 86 | /* this function is NOT async-safe. It is exported so multithreaded |
| 93 | * plugins (or other apps) can call it prior to running any commands | 87 | * plugins (or other apps) can call it prior to running any commands |
| @@ -110,7 +104,6 @@ void cmd_init(void) { | |||
| 110 | 104 | ||
| 111 | /* Start running a command, array style */ | 105 | /* Start running a command, array style */ |
| 112 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { | 106 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { |
| 113 | pid_t pid; | ||
| 114 | #ifdef RLIMIT_CORE | 107 | #ifdef RLIMIT_CORE |
| 115 | struct rlimit limit; | 108 | struct rlimit limit; |
| 116 | #endif | 109 | #endif |
| @@ -123,6 +116,7 @@ static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { | |||
| 123 | 116 | ||
| 124 | setenv("LC_ALL", "C", 1); | 117 | setenv("LC_ALL", "C", 1); |
| 125 | 118 | ||
| 119 | pid_t pid; | ||
| 126 | if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) { | 120 | if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) { |
| 127 | return -1; /* errno set by the failing function */ | 121 | return -1; /* errno set by the failing function */ |
| 128 | } | 122 | } |
| @@ -171,22 +165,23 @@ static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { | |||
| 171 | return pfd[0]; | 165 | return pfd[0]; |
| 172 | } | 166 | } |
| 173 | 167 | ||
| 174 | static int _cmd_close(int fd) { | 168 | static int _cmd_close(int fileDescriptor) { |
| 175 | int status; | ||
| 176 | pid_t pid; | 169 | pid_t pid; |
| 177 | 170 | ||
| 178 | /* make sure the provided fd was opened */ | 171 | /* make sure the provided fd was opened */ |
| 179 | long maxfd = mp_open_max(); | 172 | long maxfd = mp_open_max(); |
| 180 | if (fd < 0 || fd > maxfd || !_cmd_pids || (pid = _cmd_pids[fd]) == 0) { | 173 | if (fileDescriptor < 0 || fileDescriptor > maxfd || !_cmd_pids || |
| 174 | (pid = _cmd_pids[fileDescriptor]) == 0) { | ||
| 181 | return -1; | 175 | return -1; |
| 182 | } | 176 | } |
| 183 | 177 | ||
| 184 | _cmd_pids[fd] = 0; | 178 | _cmd_pids[fileDescriptor] = 0; |
| 185 | if (close(fd) == -1) { | 179 | if (close(fileDescriptor) == -1) { |
| 186 | return -1; | 180 | return -1; |
| 187 | } | 181 | } |
| 188 | 182 | ||
| 189 | /* EINTR is ok (sort of), everything else is bad */ | 183 | /* EINTR is ok (sort of), everything else is bad */ |
| 184 | int status; | ||
| 190 | while (waitpid(pid, &status, 0) < 0) { | 185 | while (waitpid(pid, &status, 0) < 0) { |
| 191 | if (errno != EINTR) { | 186 | if (errno != EINTR) { |
| 192 | return -1; | 187 | return -1; |
| @@ -197,68 +192,67 @@ static int _cmd_close(int fd) { | |||
| 197 | return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; | 192 | return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; |
| 198 | } | 193 | } |
| 199 | 194 | ||
| 200 | static int _cmd_fetch_output(int fd, output *op, int flags) { | 195 | static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) { |
| 201 | size_t len = 0, i = 0, lineno = 0; | ||
| 202 | size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ | ||
| 203 | char *buf = NULL; | ||
| 204 | int ret; | ||
| 205 | char tmpbuf[4096]; | 196 | char tmpbuf[4096]; |
| 206 | 197 | cmd_output->buf = NULL; | |
| 207 | op->buf = NULL; | 198 | cmd_output->buflen = 0; |
| 208 | op->buflen = 0; | 199 | ssize_t ret; |
| 209 | while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) { | 200 | while ((ret = read(fileDescriptor, tmpbuf, sizeof(tmpbuf))) > 0) { |
| 210 | len = (size_t)ret; | 201 | size_t len = (size_t)ret; |
| 211 | op->buf = realloc(op->buf, op->buflen + len + 1); | 202 | cmd_output->buf = realloc(cmd_output->buf, cmd_output->buflen + len + 1); |
| 212 | memcpy(op->buf + op->buflen, tmpbuf, len); | 203 | memcpy(cmd_output->buf + cmd_output->buflen, tmpbuf, len); |
| 213 | op->buflen += len; | 204 | cmd_output->buflen += len; |
| 214 | i++; | ||
| 215 | } | 205 | } |
| 216 | 206 | ||
| 217 | if (ret < 0) { | 207 | if (ret < 0) { |
| 218 | printf("read() returned %d: %s\n", ret, strerror(errno)); | 208 | printf("read() returned %zd: %s\n", ret, strerror(errno)); |
| 219 | return ret; | 209 | return ret; |
| 220 | } | 210 | } |
| 221 | 211 | ||
| 222 | /* some plugins may want to keep output unbroken, and some commands | 212 | /* some plugins may want to keep output unbroken, and some commands |
| 223 | * will yield no output, so return here for those */ | 213 | * will yield no output, so return here for those */ |
| 224 | if (flags & CMD_NO_ARRAYS || !op->buf || !op->buflen) { | 214 | if (flags & CMD_NO_ARRAYS || !cmd_output->buf || !cmd_output->buflen) { |
| 225 | return op->buflen; | 215 | return cmd_output->buflen; |
| 226 | } | 216 | } |
| 227 | 217 | ||
| 228 | /* and some may want both */ | 218 | /* and some may want both */ |
| 219 | char *buf = NULL; | ||
| 229 | if (flags & CMD_NO_ASSOC) { | 220 | if (flags & CMD_NO_ASSOC) { |
| 230 | buf = malloc(op->buflen); | 221 | buf = malloc(cmd_output->buflen); |
| 231 | memcpy(buf, op->buf, op->buflen); | 222 | memcpy(buf, cmd_output->buf, cmd_output->buflen); |
| 232 | } else { | 223 | } else { |
| 233 | buf = op->buf; | 224 | buf = cmd_output->buf; |
| 234 | } | 225 | } |
| 235 | 226 | ||
| 236 | op->line = NULL; | 227 | cmd_output->line = NULL; |
| 237 | op->lens = NULL; | 228 | cmd_output->lens = NULL; |
| 238 | i = 0; | 229 | size_t i = 0; |
| 239 | while (i < op->buflen) { | 230 | size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ |
| 231 | size_t rsf = 6; | ||
| 232 | size_t lineno = 0; | ||
| 233 | while (i < cmd_output->buflen) { | ||
| 240 | /* make sure we have enough memory */ | 234 | /* make sure we have enough memory */ |
| 241 | if (lineno >= ary_size) { | 235 | if (lineno >= ary_size) { |
| 242 | /* ary_size must never be zero */ | 236 | /* ary_size must never be zero */ |
| 243 | do { | 237 | do { |
| 244 | ary_size = op->buflen >> --rsf; | 238 | ary_size = cmd_output->buflen >> --rsf; |
| 245 | } while (!ary_size); | 239 | } while (!ary_size); |
| 246 | 240 | ||
| 247 | op->line = realloc(op->line, ary_size * sizeof(char *)); | 241 | cmd_output->line = realloc(cmd_output->line, ary_size * sizeof(char *)); |
| 248 | op->lens = realloc(op->lens, ary_size * sizeof(size_t)); | 242 | cmd_output->lens = realloc(cmd_output->lens, ary_size * sizeof(size_t)); |
| 249 | } | 243 | } |
| 250 | 244 | ||
| 251 | /* set the pointer to the string */ | 245 | /* set the pointer to the string */ |
| 252 | op->line[lineno] = &buf[i]; | 246 | cmd_output->line[lineno] = &buf[i]; |
| 253 | 247 | ||
| 254 | /* hop to next newline or end of buffer */ | 248 | /* hop to next newline or end of buffer */ |
| 255 | while (buf[i] != '\n' && i < op->buflen) { | 249 | while (buf[i] != '\n' && i < cmd_output->buflen) { |
| 256 | i++; | 250 | i++; |
| 257 | } | 251 | } |
| 258 | buf[i] = '\0'; | 252 | buf[i] = '\0'; |
| 259 | 253 | ||
| 260 | /* calculate the string length using pointer difference */ | 254 | /* calculate the string length using pointer difference */ |
| 261 | op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno]; | 255 | cmd_output->lens[lineno] = (size_t)&buf[i] - (size_t)cmd_output->line[lineno]; |
| 262 | 256 | ||
| 263 | lineno++; | 257 | lineno++; |
| 264 | i++; | 258 | i++; |
| @@ -268,12 +262,6 @@ static int _cmd_fetch_output(int fd, output *op, int flags) { | |||
| 268 | } | 262 | } |
| 269 | 263 | ||
| 270 | int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | 264 | int cmd_run(const char *cmdstring, output *out, output *err, int flags) { |
| 271 | int i = 0, argc; | ||
| 272 | size_t cmdlen; | ||
| 273 | char **argv = NULL; | ||
| 274 | char *cmd = NULL; | ||
| 275 | char *str = NULL; | ||
| 276 | |||
| 277 | if (cmdstring == NULL) { | 265 | if (cmdstring == NULL) { |
| 278 | return -1; | 266 | return -1; |
| 279 | } | 267 | } |
| @@ -288,7 +276,8 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | |||
| 288 | 276 | ||
| 289 | /* make copy of command string so strtok() doesn't silently modify it */ | 277 | /* make copy of command string so strtok() doesn't silently modify it */ |
| 290 | /* (the calling program may want to access it later) */ | 278 | /* (the calling program may want to access it later) */ |
| 291 | cmdlen = strlen(cmdstring); | 279 | size_t cmdlen = strlen(cmdstring); |
| 280 | char *cmd = NULL; | ||
| 292 | if ((cmd = malloc(cmdlen + 1)) == NULL) { | 281 | if ((cmd = malloc(cmdlen + 1)) == NULL) { |
| 293 | return -1; | 282 | return -1; |
| 294 | } | 283 | } |
| @@ -307,8 +296,8 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | |||
| 307 | 296 | ||
| 308 | /* each arg must be whitespace-separated, so args can be a maximum | 297 | /* each arg must be whitespace-separated, so args can be a maximum |
| 309 | * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ | 298 | * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ |
| 310 | argc = (cmdlen >> 1) + 2; | 299 | int argc = (cmdlen >> 1) + 2; |
| 311 | argv = calloc((size_t)argc, sizeof(char *)); | 300 | char **argv = calloc((size_t)argc, sizeof(char *)); |
| 312 | 301 | ||
| 313 | if (argv == NULL) { | 302 | if (argv == NULL) { |
| 314 | printf("%s\n", _("Could not malloc argv array in popen()")); | 303 | printf("%s\n", _("Could not malloc argv array in popen()")); |
| @@ -316,8 +305,9 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | |||
| 316 | } | 305 | } |
| 317 | 306 | ||
| 318 | /* get command arguments (stupidly, but fairly quickly) */ | 307 | /* get command arguments (stupidly, but fairly quickly) */ |
| 308 | int i = 0; | ||
| 319 | while (cmd) { | 309 | while (cmd) { |
| 320 | str = cmd; | 310 | char *str = cmd; |
| 321 | str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ | 311 | str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ |
| 322 | 312 | ||
| 323 | if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ | 313 | if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ |
| @@ -347,8 +337,6 @@ int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | |||
| 347 | } | 337 | } |
| 348 | 338 | ||
| 349 | int cmd_run_array(char *const *argv, output *out, output *err, int flags) { | 339 | int cmd_run_array(char *const *argv, output *out, output *err, int flags) { |
| 350 | int fd, pfd_out[2], pfd_err[2]; | ||
| 351 | |||
| 352 | /* initialize the structs */ | 340 | /* initialize the structs */ |
| 353 | if (out) { | 341 | if (out) { |
| 354 | memset(out, 0, sizeof(output)); | 342 | memset(out, 0, sizeof(output)); |
| @@ -357,6 +345,9 @@ int cmd_run_array(char *const *argv, output *out, output *err, int flags) { | |||
| 357 | memset(err, 0, sizeof(output)); | 345 | memset(err, 0, sizeof(output)); |
| 358 | } | 346 | } |
| 359 | 347 | ||
| 348 | int fd; | ||
| 349 | int pfd_out[2]; | ||
| 350 | int pfd_err[2]; | ||
| 360 | if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) { | 351 | if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) { |
| 361 | die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); | 352 | die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); |
| 362 | } | 353 | } |
