2010-05-25 19:14:06 +08:00
|
|
|
/*
|
|
|
|
* commandhelper.c: Auxiliary program for commandtest
|
|
|
|
*
|
2014-03-18 16:13:43 +08:00
|
|
|
* Copyright (C) 2010-2014 Red Hat, Inc.
|
2010-05-25 19:14:06 +08:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-21 06:30:55 +08:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 18:06:23 +08:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-05-25 19:14:06 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2014-09-03 23:13:21 +08:00
|
|
|
#include <sys/stat.h>
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2020-01-27 20:52:23 +08:00
|
|
|
#define VIR_NO_GLIB_STDIO /* This file intentionally does not link to libvirt/glib */
|
2017-09-21 15:55:07 +08:00
|
|
|
#include "testutils.h"
|
2012-03-29 17:50:00 +08:00
|
|
|
|
|
|
|
#ifndef WIN32
|
2020-01-17 19:19:13 +08:00
|
|
|
# include <poll.h>
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2020-01-08 00:16:19 +08:00
|
|
|
/* Some UNIX lack it in headers & it doesn't hurt to redeclare */
|
|
|
|
extern char **environ;
|
|
|
|
|
2013-06-07 16:37:25 +08:00
|
|
|
# define VIR_FROM_THIS VIR_FROM_NONE
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
struct Arguments {
|
|
|
|
int readfds[3];
|
|
|
|
int numreadfds;
|
|
|
|
bool daemonize_check;
|
|
|
|
bool close_stdin;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct Arguments *parseArguments(int argc, char** argv)
|
|
|
|
{
|
|
|
|
struct Arguments* args = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!(args = calloc(1, sizeof(*args))))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
args->numreadfds = 1;
|
|
|
|
args->readfds[0] = STDIN_FILENO;
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
if (STREQ(argv[i - 1], "--readfd")) {
|
|
|
|
char c;
|
|
|
|
|
|
|
|
if (1 != sscanf(argv[i], "%u%c",
|
|
|
|
&args->readfds[args->numreadfds++], &c)) {
|
|
|
|
printf("Could not parse fd %s\n", argv[i]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (STREQ(argv[i], "--check-daemonize")) {
|
|
|
|
args->daemonize_check = true;
|
|
|
|
} else if (STREQ(argv[i], "--close-stdin")) {
|
|
|
|
args->close_stdin = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (ret == 0)
|
|
|
|
return args;
|
|
|
|
|
|
|
|
free(args);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-18 16:13:43 +08:00
|
|
|
static int envsort(const void *a, const void *b)
|
|
|
|
{
|
2021-02-01 19:27:47 +08:00
|
|
|
const char *astr = *(const char**)a;
|
|
|
|
const char *bstr = *(const char**)b;
|
2013-05-03 20:52:21 +08:00
|
|
|
|
2021-02-01 19:27:47 +08:00
|
|
|
while (true) {
|
|
|
|
char achar = (*astr == '=') ? '\0' : *astr;
|
|
|
|
char bchar = (*bstr == '=') ? '\0' : *bstr;
|
|
|
|
|
|
|
|
if ((achar == '\0') || (achar != bchar))
|
|
|
|
return achar - bchar;
|
|
|
|
|
|
|
|
astr++;
|
|
|
|
bstr++;
|
|
|
|
}
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
2021-02-01 19:27:51 +08:00
|
|
|
struct Arguments *args = parseArguments(argc, argv);
|
Convert 'int i' to 'size_t i' in tests/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 22:09:33 +08:00
|
|
|
size_t i, n;
|
2013-07-11 19:22:20 +08:00
|
|
|
int open_max;
|
2014-09-04 02:59:31 +08:00
|
|
|
char **newenv = NULL;
|
2011-04-30 01:14:23 +08:00
|
|
|
char *cwd;
|
2010-05-25 19:14:06 +08:00
|
|
|
FILE *log = fopen(abs_builddir "/commandhelper.log", "w");
|
2014-09-04 02:59:31 +08:00
|
|
|
int ret = EXIT_FAILURE;
|
2019-07-26 02:22:10 +08:00
|
|
|
struct pollfd fds[3];
|
|
|
|
char *buffers[3] = {NULL, NULL, NULL};
|
|
|
|
size_t buflen[3] = {0, 0, 0};
|
2020-07-21 18:32:10 +08:00
|
|
|
size_t daemonize_retries = 3;
|
2020-08-03 23:27:58 +08:00
|
|
|
char buf[1024];
|
|
|
|
ssize_t got;
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
if (!log || !args)
|
2021-02-01 19:27:48 +08:00
|
|
|
goto cleanup;
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2021-02-01 19:27:50 +08:00
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
fprintf(log, "ARG:%s\n", argv[i]);
|
|
|
|
}
|
|
|
|
|
2021-02-01 19:27:45 +08:00
|
|
|
for (n = 0; environ[n]; n++) {
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
|
|
|
|
2017-09-20 19:03:47 +08:00
|
|
|
if (!(newenv = malloc(sizeof(*newenv) * n)))
|
2021-02-01 19:27:48 +08:00
|
|
|
goto cleanup;
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2021-02-01 19:27:45 +08:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
newenv[i] = environ[i];
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
2021-02-01 19:27:45 +08:00
|
|
|
|
2010-05-25 19:14:06 +08:00
|
|
|
qsort(newenv, n, sizeof(newenv[0]), envsort);
|
|
|
|
|
2013-05-21 15:53:48 +08:00
|
|
|
for (i = 0; i < n; i++) {
|
2011-01-07 04:23:36 +08:00
|
|
|
/* Ignore the variables used to instruct the loader into
|
|
|
|
* behaving differently, as they could throw the tests off. */
|
|
|
|
if (!STRPREFIX(newenv[i], "LD_"))
|
|
|
|
fprintf(log, "ENV:%s\n", newenv[i]);
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
|
|
|
|
2013-07-11 19:22:20 +08:00
|
|
|
open_max = sysconf(_SC_OPEN_MAX);
|
|
|
|
if (open_max < 0)
|
2014-09-04 02:59:31 +08:00
|
|
|
goto cleanup;
|
2013-07-11 19:22:20 +08:00
|
|
|
for (i = 0; i < open_max; i++) {
|
2010-05-25 19:14:06 +08:00
|
|
|
int f;
|
|
|
|
int closed;
|
|
|
|
if (i == fileno(log))
|
|
|
|
continue;
|
|
|
|
closed = fcntl(i, F_GETFD, &f) == -1 &&
|
|
|
|
errno == EBADF;
|
|
|
|
if (!closed)
|
Convert 'int i' to 'size_t i' in tests/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 22:09:33 +08:00
|
|
|
fprintf(log, "FD:%zu\n", i);
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
|
|
|
|
2020-07-21 18:32:10 +08:00
|
|
|
while (true) {
|
|
|
|
bool daemonized = getpgrp() != getppid();
|
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
if (args->daemonize_check && !daemonized && daemonize_retries-- > 0) {
|
2020-07-21 18:32:10 +08:00
|
|
|
usleep(100*1000);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(log, "DAEMON:%s\n", daemonized ? "yes" : "no");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-04-30 01:14:23 +08:00
|
|
|
if (!(cwd = getcwd(NULL, 0)))
|
2014-09-04 02:59:31 +08:00
|
|
|
goto cleanup;
|
2011-04-30 01:14:23 +08:00
|
|
|
if (strlen(cwd) > strlen(".../commanddata") &&
|
2010-05-25 19:14:06 +08:00
|
|
|
STREQ(cwd + strlen(cwd) - strlen("/commanddata"), "/commanddata"))
|
|
|
|
strcpy(cwd, ".../commanddata");
|
2019-08-22 00:13:18 +08:00
|
|
|
# ifdef __APPLE__
|
|
|
|
char *noprivateprefix = NULL;
|
|
|
|
if (strstr(cwd, "/private"))
|
|
|
|
noprivateprefix = cwd + strlen("/private");
|
|
|
|
else
|
|
|
|
noprivateprefix = cwd;
|
|
|
|
fprintf(log, "CWD:%s\n", noprivateprefix);
|
|
|
|
# else
|
2010-05-25 19:14:06 +08:00
|
|
|
fprintf(log, "CWD:%s\n", cwd);
|
2019-08-22 00:13:18 +08:00
|
|
|
# endif
|
2017-09-20 19:03:47 +08:00
|
|
|
free(cwd);
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2014-09-03 23:13:21 +08:00
|
|
|
fprintf(log, "UMASK:%04o\n", umask(0));
|
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
if (args->close_stdin) {
|
2012-06-01 05:50:07 +08:00
|
|
|
if (freopen("/dev/null", "r", stdin) != stdin)
|
2014-09-04 02:59:31 +08:00
|
|
|
goto cleanup;
|
2012-06-01 05:50:07 +08:00
|
|
|
usleep(100*1000);
|
|
|
|
}
|
|
|
|
|
2010-05-25 19:14:06 +08:00
|
|
|
fprintf(stdout, "BEGIN STDOUT\n");
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, "BEGIN STDERR\n");
|
|
|
|
fflush(stderr);
|
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
for (i = 0; i < args->numreadfds; i++) {
|
|
|
|
fds[i].fd = args->readfds[i];
|
2021-02-01 19:27:46 +08:00
|
|
|
fds[i].events = POLLIN;
|
|
|
|
fds[i].revents = 0;
|
2019-07-26 02:22:10 +08:00
|
|
|
}
|
|
|
|
|
2010-05-25 19:14:06 +08:00
|
|
|
for (;;) {
|
2019-07-26 02:22:10 +08:00
|
|
|
unsigned ctr = 0;
|
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
if (poll(fds, args->numreadfds, -1) < 0) {
|
2019-07-26 02:22:10 +08:00
|
|
|
printf("poll failed: %s\n", strerror(errno));
|
2014-09-04 02:59:31 +08:00
|
|
|
goto cleanup;
|
2019-07-26 02:22:10 +08:00
|
|
|
}
|
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
for (i = 0; i < args->numreadfds; i++) {
|
2020-10-08 22:02:08 +08:00
|
|
|
short revents = POLLIN | POLLHUP | POLLERR;
|
|
|
|
|
|
|
|
# ifdef __APPLE__
|
|
|
|
/*
|
|
|
|
* poll() on /dev/null will return POLLNVAL
|
|
|
|
* Apple-Feedback: FB8785208
|
|
|
|
*/
|
|
|
|
revents |= POLLNVAL;
|
|
|
|
# endif
|
|
|
|
|
|
|
|
if (fds[i].revents & revents) {
|
2019-07-26 02:22:10 +08:00
|
|
|
fds[i].revents = 0;
|
|
|
|
|
|
|
|
got = read(fds[i].fd, buf, sizeof(buf));
|
|
|
|
if (got < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (got == 0) {
|
|
|
|
/* do not want to hear from this fd anymore */
|
|
|
|
fds[i].events = 0;
|
|
|
|
} else {
|
|
|
|
buffers[i] = realloc(buffers[i], buflen[i] + got);
|
|
|
|
if (!buf[i]) {
|
|
|
|
fprintf(stdout, "Out of memory!\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
memcpy(buffers[i] + buflen[i], buf, got);
|
|
|
|
buflen[i] += got;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-01 19:27:51 +08:00
|
|
|
for (i = 0; i < args->numreadfds; i++) {
|
2019-07-26 02:22:10 +08:00
|
|
|
if (fds[i].events) {
|
|
|
|
ctr++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ctr == 0)
|
2010-05-25 19:14:06 +08:00
|
|
|
break;
|
2019-07-26 02:22:10 +08:00
|
|
|
}
|
|
|
|
|
2021-02-01 19:27:51 +08:00
|
|
|
for (i = 0; i < args->numreadfds; i++) {
|
2020-09-22 01:32:29 +08:00
|
|
|
if (fwrite(buffers[i], 1, buflen[i], stdout) != buflen[i])
|
2014-09-04 02:59:31 +08:00
|
|
|
goto cleanup;
|
2020-09-22 01:32:29 +08:00
|
|
|
if (fwrite(buffers[i], 1, buflen[i], stderr) != buflen[i])
|
2014-09-04 02:59:31 +08:00
|
|
|
goto cleanup;
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stdout, "END STDOUT\n");
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, "END STDERR\n");
|
|
|
|
fflush(stderr);
|
|
|
|
|
2014-09-04 02:59:31 +08:00
|
|
|
ret = EXIT_SUCCESS;
|
2010-05-25 19:14:06 +08:00
|
|
|
|
2014-09-04 02:59:31 +08:00
|
|
|
cleanup:
|
2019-10-15 19:55:26 +08:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(buffers); i++)
|
2019-07-26 02:22:10 +08:00
|
|
|
free(buffers[i]);
|
2021-02-01 19:27:51 +08:00
|
|
|
if (args)
|
|
|
|
free(args);
|
2021-02-01 19:27:48 +08:00
|
|
|
if (newenv)
|
|
|
|
free(newenv);
|
|
|
|
if (log)
|
|
|
|
fclose(log);
|
2014-09-04 02:59:31 +08:00
|
|
|
return ret;
|
2010-05-25 19:14:06 +08:00
|
|
|
}
|
2012-03-29 17:50:00 +08:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int
|
|
|
|
main(void)
|
|
|
|
{
|
|
|
|
return EXIT_AM_SKIP;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|