File: file.c

package info (click to toggle)
gentoo 0.11.46-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 5,648 kB
  • ctags: 4,313
  • sloc: ansic: 33,912; sh: 3,903; makefile: 649; yacc: 316; sed: 16
file content (142 lines) | stat: -rw-r--r-- 3,967 bytes parent folder | download | duplicates (4)
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;
}