1 /*
2 ** 1998-09-18 -	Maintain an instance of the 'file' external command as a child process, and
3 **		feed it typing requests when necessary. We will only start 'file' ONCE per
4 **		entire gentoo session (typically), thus amortizing its startup costs over
5 **		a very (?) long time. The aim of all this is hopefully to make typing using
6 **		the file rules cheaper.
7 ** 2002-01-03 -	It's a while later, the file command on your system might now have the -n
8 **		option which causes it to flush its output, and enables this module to do
9 **		it's thing in the way intended. Used by cmd_info.c.
10 */
11 
12 #include "gentoo.h"
13 
14 #include <fcntl.h>
15 #include <ctype.h>
16 #include <stdlib.h>
17 #include <signal.h>
18 #include <unistd.h>
19 
20 #include "dialog.h"
21 #include "errors.h"
22 #include "children.h"
23 #include "file.h"
24 
25 /* ----------------------------------------------------------------------------------------- */
26 
27 static struct {
28 	gint	file_in;		/* Writing end of pipe connected to command's stdin. */
29 	gint	file_out;		/* Reading end of pipe connected to command's stdout. */
30 } file_info = { -1, -1 };
31 
32 /* ----------------------------------------------------------------------------------------- */
33 
start_file(MainInfo * min,const gchar * cmd)34 static void start_file(MainInfo *min, const gchar *cmd)
35 {
36 	gchar	*argv[] = { "file", "file", "-n", "-f", "-", NULL };
37 	GPid	child;
38 	GError	*err = NULL;
39 
40 	if(g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child, &file_info.file_in, &file_info.file_out, NULL, &err))
41 	{
42 		chd_register("file", child, CGF_RUNINBG, 0);
43 	}
44 	else
45 	{
46 		gchar	buf[1024];
47 
48 		g_snprintf(buf, sizeof buf, "Couldn't run the 'file' command:\n%s", err->message);
49 		dlg_dialog_async_new_error(buf);
50 		g_error_free(err);
51 	}
52 }
53 
54 /* ----------------------------------------------------------------------------------------- */
55 
56 /* 1998-09-18 -	Run 'file' on the supplied file name, and return a pointer to its result line.
57 **		The returned string will be the result of 'file', minus the header and the
58 **		trailing newline. The returned string is static, and only valid up until the
59 **		next call to this function. If the execution fails, NULL is returned.
60 */
fle_file(MainInfo * min,const gchar * name)61 const gchar * fle_file(MainInfo *min, const gchar *name)
62 {
63 	if(file_info.file_in < 0)
64 		start_file(min, "file");
65 	if(file_info.file_in > 0)		/* File command running? */
66 	{
67 		static gchar	resp[PATH_MAX + 256];
68 		gchar		line[PATH_MAX + 32];
69 		gint		len, got;
70 		fd_set		fds_read;
71 		struct timeval	to;
72 
73 		len = g_snprintf(line, sizeof line, "%s\n", name);
74 		if(write(file_info.file_in, line, len) != len)
75 		{
76 			perror("Write to pipe");
77 			return NULL;
78 		}
79 		FD_ZERO(&fds_read);
80 		FD_SET(file_info.file_out, &fds_read);
81 		to.tv_sec  = 1U;
82 		to.tv_usec = 0U;
83 		if((select(file_info.file_out + 1, &fds_read, NULL, NULL, &to)) > 0)
84 		{
85 			if(FD_ISSET(file_info.file_out, &fds_read))
86 			{
87 				if((got = read(file_info.file_out, resp, sizeof resp - 1)) > 0)
88 				{
89 					const gchar	*cp;
90 
91 					resp[got - 1] = '\0';
92 					if((cp = strrchr(resp, ':')) != NULL)
93 					{
94 						cp++;
95 						while(*cp && isspace((guchar) *cp))
96 							cp++;
97 						return cp;
98 					}
99 				}
100 			}
101 		}
102 	}
103 	return NULL;
104 }
105