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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
/*
** 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 session (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.
** 2002-01-03 - It's a while later, the file command on your system might now have the -n
** option which causes it to flush its output, and enables this module to do
** it's thing in the way intended. Used by cmd_info.c.
*/
#include "gentoo.h"
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include "dialog.h"
#include "children.h"
#include "file.h"
/* ----------------------------------------------------------------------------------------- */
static struct {
gint file_in; /* Writing end of pipe connected to command's stdin. */
gint file_out; /* Reading end of pipe connected to command's stdout. */
} file_info = { -1, -1 };
/* ----------------------------------------------------------------------------------------- */
static void start_file(MainInfo *min, const gchar *cmd)
{
pid_t child;
gint fd_in[2], fd_out[2];
if(pipe(fd_in) != 0)
return;
if(pipe(fd_out) != 0)
{
close(fd_in[STDIN_FILENO]);
close(fd_in[STDOUT_FILENO]);
return;
}
child = fork();
if(child == 0) /* Now in child? */
{
guint bits = 0U;
if(close(STDIN_FILENO) == 0)
{
if(dup(fd_in[STDIN_FILENO]) == STDIN_FILENO)
bits |= (close(fd_in[STDOUT_FILENO]) == 0);
}
if(close(STDOUT_FILENO) == 0)
{
if(dup(fd_out[STDOUT_FILENO]) == STDOUT_FILENO)
bits |= (close(fd_out[STDIN_FILENO]) == 0) << 1;
}
if(bits == 3U)
execlp(cmd, cmd, "-n", "-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[STDOUT_FILENO];
file_info.file_out = fd_out[STDIN_FILENO];
if(close(fd_in[STDIN_FILENO]) == 0)
{
if(close(fd_out[STDOUT_FILENO]) == 0)
{
if(fcntl(file_info.file_out, F_SETFL, O_NONBLOCK) == 0)
return;
}
}
}
close(fd_in[STDIN_FILENO]);
close(fd_in[STDOUT_FILENO]);
close(fd_out[STDIN_FILENO]);
close(fd_out[STDOUT_FILENO]);
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.
*/
const gchar * fle_file(MainInfo *min, const gchar *name)
{
if(file_info.file_in < 0)
start_file(min, "file");
if(file_info.file_in > 0) /* File command running? */
{
static gchar resp[PATH_MAX + 256];
gchar line[PATH_MAX + 32];
gint len, got;
fd_set fds_read;
struct timeval to;
len = g_snprintf(line, sizeof line, "%s\n", name);
if(write(file_info.file_in, line, len) != len)
{
perror("Write to pipe");
return NULL;
}
FD_ZERO(&fds_read);
FD_SET(file_info.file_out, &fds_read);
to.tv_sec = 1U;
to.tv_usec = 0U;
if((select(file_info.file_out + 1, &fds_read, NULL, NULL, &to)) > 0)
{
if(FD_ISSET(file_info.file_out, &fds_read))
{
errno = 0;
if((got = read(file_info.file_out, resp, sizeof resp - 1)) > 0)
{
const gchar *cp;
resp[got - 1] = '\0';
if((cp = strchr(resp, ':')) != NULL)
{
cp++;
while(*cp && isspace((guchar) *cp))
cp++;
return cp;
}
}
if(errno && errno != EAGAIN)
perror("Read from pipe");
}
}
else
perror("select");
}
return NULL;
}
|