1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
/*
** 1998-09-18 - Maintain an instance of the 'file' external command as a child process, and
** feed it typing requests when necessary. We will only start 'file' ONCE per
** entire gentoo sessions (typically), thus amortizing its startup costs over
** a very long time. The aim of all this is hopefully to make typing using the
** file rules cheaper.
** BUG BUG BUG This module isn't used. It's just built and linked in... The reason is that
** no file command I'm aware of actually supports this. It's a one-line fix,
** but it's not my package. :(
*/
#include "gentoo.h"
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include "dialog.h"
#include "children.h"
#include "file.h"
/* ----------------------------------------------------------------------------------------- */
#define FD_INPUT (0)
#define FD_OUTPUT (1)
#define FD_ERROR (2)
static struct {
int file_in; /* Writing end of pipe connected to command's stdin. */
int file_out; /* Reading end of pipe connected to command's stdout. */
} file_info = { -1, -1 };
/* ----------------------------------------------------------------------------------------- */
static void start_file(MainInfo *min, char *cmd)
{
pid_t child;
int fd_in[2], fd_out[2];
if(pipe(fd_in) != 0)
return;
if(pipe(fd_out) != 0)
{
close(fd_in[FD_INPUT]);
close(fd_in[FD_OUTPUT]);
return;
}
child = fork();
if(child == 0) /* Now in child? */
{
assert(close(FD_INPUT) == 0); /* Connect stdin to pipe. */
assert(dup(fd_in[FD_INPUT]) == FD_INPUT);
assert(close(fd_in[FD_OUTPUT]) == 0);
assert(close(FD_OUTPUT) == 0); /* Connect stdout to pipe. */
assert(dup(fd_out[FD_OUTPUT]) == FD_OUTPUT);
assert(close(fd_out[FD_INPUT]) == 0);
execlp(cmd, cmd, "-f", "-", NULL);
fprintf(stderr, "FILE: execlp() of '%s' failed (code %d)\n", cmd, errno);
exit(EXIT_FAILURE);
}
else if(child > 0) /* In parent? */
{
chd_register(cmd, child, CGF_RUNINBG, FALSE);
file_info.file_in = fd_in[FD_OUTPUT];
file_info.file_out = fd_out[FD_INPUT];
assert(close(fd_in[FD_INPUT]) == 0);
assert(close(fd_out[FD_OUTPUT]) == 0);
if(fcntl(file_info.file_out, F_SETFL, O_NONBLOCK) != 0)
perror("**FILE: Couldn't make child's output non-blocking");
return;
}
close(fd_in[FD_INPUT]);
close(fd_in[FD_OUTPUT]);
close(fd_out[FD_INPUT]);
close(fd_out[FD_OUTPUT]);
dlg_dialog_async_new_error("Couldn't fork() to run\nthe 'file' command!");
}
/* ----------------------------------------------------------------------------------------- */
/* 1998-09-18 - Run 'file' on the supplied file name, and return a pointer to its result line.
** The returned string will be the result of 'file', minus the header and the
** trailing newline. The returned string is static, and only valid up until the
** next call to this function. If the execution fails, NULL is returned.
*/
char * fle_file(MainInfo *min, char *name)
{
char resp[PATH_MAX + 256], line[PATH_MAX + 32];
int len, got;
fd_set fds_read;
if(file_info.file_in < 0)
start_file(min, "file");
if(file_info.file_in > 0) /* File command running? */
{
len = sprintf(line, "%s\n", name);
write(file_info.file_in, line, len);
fprintf(stderr, "Wrote a %d-byte request ('%s'+LF)\n", len, name);
FD_ZERO(&fds_read);
FD_SET(file_info.file_out, &fds_read);
fprintf(stderr, "Entering select(), waiting for response\n");
if((select(file_info.file_out + 1, &fds_read, NULL, NULL, NULL)) > 0)
{
if(FD_ISSET(file_info.file_out, &fds_read))
{
while((got = read(file_info.file_out, resp, sizeof resp - 1)) > 0)
{
resp[got] = '\0';
fprintf(stderr, "Got %d bytes: '%s'", got, resp);
}
if(errno && errno != EAGAIN)
perror("Read from pipe");
}
fprintf(stderr, "file interaction done\n");
}
}
return NULL;
}
|