Files
libvirt/tests/commandhelper.c
T

264 lines
6.7 KiB
C
Raw Normal View History

2010-05-25 12:14:06 +01:00
/*
* commandhelper.c: Auxiliary program for commandtest
*
2014-03-18 09:13:43 +01:00
* Copyright (C) 2010-2014 Red Hat, Inc.
2010-05-25 12:14:06 +01: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
* License along with this library. If not, see
2012-07-21 18:06:23 +08:00
* <http://www.gnu.org/licenses/>.
2010-05-25 12:14:06 +01:00
*/
#include <config.h>
#include <unistd.h>
#include <fcntl.h>
2014-09-03 09:13:21 -06:00
#include <sys/stat.h>
2010-05-25 12:14:06 +01:00
#define VIR_NO_GLIB_STDIO /* This file intentionally does not link to libvirt/glib */
2017-09-21 08:55:07 +01:00
#include "testutils.h"
#ifndef WIN32
2020-01-17 11:19:13 +00:00
# include <poll.h>
2010-05-25 12:14:06 +01:00
2020-01-07 16:16:19 +00:00
/* Some UNIX lack it in headers & it doesn't hurt to redeclare */
extern char **environ;
2013-06-07 10:37:25 +02:00
# define VIR_FROM_THIS VIR_FROM_NONE
2010-05-25 12:14:06 +01:00
2014-03-18 09:13:43 +01:00
static int envsort(const void *a, const void *b)
{
2010-05-25 12:14:06 +01:00
const char *const*astrptr = a;
const char *const*bstrptr = b;
const char *astr = *astrptr;
const char *bstr = *bstrptr;
char *aeq = strchr(astr, '=');
char *beq = strchr(bstr, '=');
char *akey;
char *bkey;
int ret;
if (!(akey = strndup(astr, aeq - astr)))
abort();
if (!(bkey = strndup(bstr, beq - bstr)))
abort();
ret = strcmp(akey, bkey);
free(akey);
free(bkey);
2010-05-25 12:14:06 +01:00
return ret;
}
int main(int argc, char **argv) {
size_t i, n;
2013-07-11 07:22:20 -04:00
int open_max;
2010-05-25 12:14:06 +01:00
char **origenv;
char **newenv = NULL;
2011-04-29 11:14:23 -06:00
char *cwd;
2010-05-25 12:14:06 +01:00
FILE *log = fopen(abs_builddir "/commandhelper.log", "w");
int ret = EXIT_FAILURE;
int readfds[3] = { STDIN_FILENO, };
int numreadfds = 1;
struct pollfd fds[3];
int numpollfds = 0;
char *buffers[3] = {NULL, NULL, NULL};
size_t buflen[3] = {0, 0, 0};
char c;
bool daemonize_check = false;
size_t daemonize_retries = 3;
2020-08-03 17:27:58 +02:00
char buf[1024];
ssize_t got;
2010-05-25 12:14:06 +01:00
if (!log)
2018-04-02 07:13:33 -04:00
return ret;
2010-05-25 12:14:06 +01:00
for (i = 1; i < argc; i++) {
2010-05-25 12:14:06 +01:00
fprintf(log, "ARG:%s\n", argv[i]);
if (STREQ(argv[i - 1], "--readfd") &&
sscanf(argv[i], "%u%c", &readfds[numreadfds++], &c) != 1) {
printf("Could not parse fd %s\n", argv[i]);
goto cleanup;
} else if (STREQ(argv[i], "--check-daemonize")) {
daemonize_check = true;
}
}
2010-05-25 12:14:06 +01:00
origenv = environ;
n = 0;
while (*origenv != NULL) {
n++;
origenv++;
}
if (!(newenv = malloc(sizeof(*newenv) * n)))
abort();
2010-05-25 12:14:06 +01:00
origenv = environ;
n = i = 0;
while (*origenv != NULL) {
newenv[i++] = *origenv;
n++;
origenv++;
}
qsort(newenv, n, sizeof(newenv[0]), envsort);
2013-05-21 15:53:48 +08:00
for (i = 0; i < n; i++) {
/* 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 12:14:06 +01:00
}
2013-07-11 07:22:20 -04:00
open_max = sysconf(_SC_OPEN_MAX);
if (open_max < 0)
goto cleanup;
2013-07-11 07:22:20 -04:00
for (i = 0; i < open_max; i++) {
2010-05-25 12:14:06 +01:00
int f;
int closed;
if (i == fileno(log))
continue;
closed = fcntl(i, F_GETFD, &f) == -1 &&
errno == EBADF;
if (!closed)
fprintf(log, "FD:%zu\n", i);
2010-05-25 12:14:06 +01:00
}
while (true) {
bool daemonized = getpgrp() != getppid();
if (daemonize_check && !daemonized && daemonize_retries-- > 0) {
usleep(100*1000);
continue;
}
fprintf(log, "DAEMON:%s\n", daemonized ? "yes" : "no");
break;
}
2011-04-29 11:14:23 -06:00
if (!(cwd = getcwd(NULL, 0)))
goto cleanup;
2011-04-29 11:14:23 -06:00
if (strlen(cwd) > strlen(".../commanddata") &&
2010-05-25 12:14:06 +01:00
STREQ(cwd + strlen(cwd) - strlen("/commanddata"), "/commanddata"))
strcpy(cwd, ".../commanddata");
# 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 12:14:06 +01:00
fprintf(log, "CWD:%s\n", cwd);
# endif
free(cwd);
2010-05-25 12:14:06 +01:00
2014-09-03 09:13:21 -06:00
fprintf(log, "UMASK:%04o\n", umask(0));
2012-05-31 15:50:07 -06:00
if (argc > 1 && STREQ(argv[1], "--close-stdin")) {
if (freopen("/dev/null", "r", stdin) != stdin)
goto cleanup;
2012-05-31 15:50:07 -06:00
usleep(100*1000);
}
2010-05-25 12:14:06 +01:00
fprintf(stdout, "BEGIN STDOUT\n");
fflush(stdout);
fprintf(stderr, "BEGIN STDERR\n");
fflush(stderr);
for (i = 0; i < numreadfds; i++) {
fds[numpollfds].fd = readfds[i];
fds[numpollfds].events = POLLIN;
fds[numpollfds].revents = 0;
numpollfds++;
}
2010-05-25 12:14:06 +01:00
for (;;) {
unsigned ctr = 0;
if (poll(fds, numpollfds, -1) < 0) {
printf("poll failed: %s\n", strerror(errno));
goto cleanup;
}
for (i = 0; i < numpollfds; i++) {
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) {
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;
}
}
}
for (i = 0; i < numpollfds; i++) {
if (fds[i].events) {
ctr++;
break;
}
}
if (ctr == 0)
2010-05-25 12:14:06 +01:00
break;
}
for (i = 0; i < numpollfds; i++) {
if (fwrite(buffers[i], 1, buflen[i], stdout) != buflen[i])
goto cleanup;
if (fwrite(buffers[i], 1, buflen[i], stderr) != buflen[i])
goto cleanup;
2010-05-25 12:14:06 +01:00
}
fprintf(stdout, "END STDOUT\n");
fflush(stdout);
fprintf(stderr, "END STDERR\n");
fflush(stderr);
ret = EXIT_SUCCESS;
2010-05-25 12:14:06 +01:00
cleanup:
for (i = 0; i < G_N_ELEMENTS(buffers); i++)
free(buffers[i]);
fclose(log);
free(newenv);
return ret;
2010-05-25 12:14:06 +01:00
}
#else
int
main(void)
{
return EXIT_AM_SKIP;
}
#endif