1 | #include <gio/gio.h> |
2 | #include <string.h> |
3 | #include <stdio.h> |
4 | #include <stdlib.h> |
5 | #include <errno.h> |
6 | #ifdef G_OS_UNIX |
7 | #include <unistd.h> |
8 | #include <gio/gunixinputstream.h> |
9 | #include <gio/gunixoutputstream.h> |
10 | #else |
11 | #include <io.h> |
12 | #endif |
13 | |
14 | static GOptionEntry options[] = { |
15 | {NULL} |
16 | }; |
17 | |
18 | static void |
19 | write_all (int fd, |
20 | const guint8* buf, |
21 | gsize len) |
22 | { |
23 | while (len > 0) |
24 | { |
25 | gssize bytes_written = write (fd: fd, buf: buf, n: len); |
26 | int errsv = errno; |
27 | if (bytes_written < 0) |
28 | g_error ("Failed to write to fd %d: %s" , |
29 | fd, g_strerror (errsv)); |
30 | buf += bytes_written; |
31 | len -= bytes_written; |
32 | } |
33 | } |
34 | |
35 | static int |
36 | echo_mode (int argc, |
37 | char **argv) |
38 | { |
39 | int i; |
40 | |
41 | for (i = 2; i < argc; i++) |
42 | { |
43 | write_all (fd: 1, buf: (guint8*)argv[i], len: strlen (s: argv[i])); |
44 | write_all (fd: 1, buf: (guint8*)"\n" , len: 1); |
45 | } |
46 | |
47 | return 0; |
48 | } |
49 | |
50 | static int |
51 | echo_stdout_and_stderr_mode (int argc, |
52 | char **argv) |
53 | { |
54 | int i; |
55 | |
56 | for (i = 2; i < argc; i++) |
57 | { |
58 | write_all (fd: 1, buf: (guint8*)argv[i], len: strlen (s: argv[i])); |
59 | write_all (fd: 1, buf: (guint8*)"\n" , len: 1); |
60 | write_all (fd: 2, buf: (guint8*)argv[i], len: strlen (s: argv[i])); |
61 | write_all (fd: 2, buf: (guint8*)"\n" , len: 1); |
62 | } |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | static int |
68 | cat_mode (int argc, |
69 | char **argv) |
70 | { |
71 | GIOChannel *chan_stdin; |
72 | GIOChannel *chan_stdout; |
73 | GIOStatus status; |
74 | char buf[1024]; |
75 | gsize bytes_read, bytes_written; |
76 | GError *local_error = NULL; |
77 | GError **error = &local_error; |
78 | |
79 | chan_stdin = g_io_channel_unix_new (fd: 0); |
80 | g_io_channel_set_encoding (channel: chan_stdin, NULL, error); |
81 | g_assert_no_error (local_error); |
82 | chan_stdout = g_io_channel_unix_new (fd: 1); |
83 | g_io_channel_set_encoding (channel: chan_stdout, NULL, error); |
84 | g_assert_no_error (local_error); |
85 | |
86 | while (TRUE) |
87 | { |
88 | do |
89 | status = g_io_channel_read_chars (channel: chan_stdin, buf, count: sizeof (buf), |
90 | bytes_read: &bytes_read, error); |
91 | while (status == G_IO_STATUS_AGAIN); |
92 | |
93 | if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR) |
94 | break; |
95 | |
96 | do |
97 | status = g_io_channel_write_chars (channel: chan_stdout, buf, count: bytes_read, |
98 | bytes_written: &bytes_written, error); |
99 | while (status == G_IO_STATUS_AGAIN); |
100 | |
101 | if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR) |
102 | break; |
103 | } |
104 | |
105 | g_io_channel_unref (channel: chan_stdin); |
106 | g_io_channel_unref (channel: chan_stdout); |
107 | |
108 | if (local_error) |
109 | { |
110 | g_printerr (format: "I/O error: %s\n" , local_error->message); |
111 | g_clear_error (err: &local_error); |
112 | return 1; |
113 | } |
114 | return 0; |
115 | } |
116 | |
117 | static gint |
118 | sleep_forever_mode (int argc, |
119 | char **argv) |
120 | { |
121 | GMainLoop *loop; |
122 | |
123 | loop = g_main_loop_new (NULL, TRUE); |
124 | g_main_loop_run (loop); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | static int |
130 | write_to_fds (int argc, char **argv) |
131 | { |
132 | int i; |
133 | |
134 | for (i = 2; i < argc; i++) |
135 | { |
136 | int fd = atoi (nptr: argv[i]); |
137 | FILE *f = fdopen (fd: fd, modes: "w" ); |
138 | const char buf[] = "hello world\n" ; |
139 | size_t bytes_written; |
140 | |
141 | g_assert (f != NULL); |
142 | |
143 | bytes_written = fwrite (ptr: buf, size: 1, n: sizeof (buf), s: f); |
144 | g_assert (bytes_written == sizeof (buf)); |
145 | |
146 | if (fclose (stream: f) == -1) |
147 | g_assert_not_reached (); |
148 | } |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | static int |
154 | env_mode (int argc, char **argv) |
155 | { |
156 | char **env; |
157 | int i; |
158 | |
159 | env = g_get_environ (); |
160 | |
161 | for (i = 0; env[i]; i++) |
162 | g_print (format: "%s\n" , env[i]); |
163 | |
164 | g_strfreev (str_array: env); |
165 | |
166 | return 0; |
167 | } |
168 | |
169 | static int |
170 | cwd_mode (int argc, char **argv) |
171 | { |
172 | char *cwd; |
173 | |
174 | cwd = g_get_current_dir (); |
175 | g_print (format: "%s\n" , cwd); |
176 | g_free (mem: cwd); |
177 | |
178 | return 0; |
179 | } |
180 | |
181 | static int |
182 | printenv_mode (int argc, char **argv) |
183 | { |
184 | gint i; |
185 | |
186 | for (i = 2; i < argc; i++) |
187 | { |
188 | const gchar *value = g_getenv (variable: argv[i]); |
189 | |
190 | if (value != NULL) |
191 | g_print (format: "%s=%s\n" , argv[i], value); |
192 | } |
193 | |
194 | return 0; |
195 | } |
196 | |
197 | int |
198 | main (int argc, char **argv) |
199 | { |
200 | GOptionContext *context; |
201 | GError *error = NULL; |
202 | const char *mode; |
203 | gboolean ret; |
204 | |
205 | context = g_option_context_new (parameter_string: "MODE - Test GSubprocess stuff" ); |
206 | g_option_context_add_main_entries (context, entries: options, NULL); |
207 | ret = g_option_context_parse (context, argc: &argc, argv: &argv, error: &error); |
208 | g_option_context_free (context); |
209 | |
210 | if (!ret) |
211 | { |
212 | g_printerr (format: "%s: %s\n" , argv[0], error->message); |
213 | g_error_free (error); |
214 | return 1; |
215 | } |
216 | |
217 | if (argc < 2) |
218 | { |
219 | g_printerr (format: "MODE argument required\n" ); |
220 | return 1; |
221 | } |
222 | |
223 | mode = argv[1]; |
224 | if (strcmp (s1: mode, s2: "noop" ) == 0) |
225 | return 0; |
226 | else if (strcmp (s1: mode, s2: "exit1" ) == 0) |
227 | return 1; |
228 | else if (strcmp (s1: mode, s2: "assert-argv0" ) == 0) |
229 | { |
230 | if (strcmp (s1: argv[0], s2: "moocow" ) == 0) |
231 | return 0; |
232 | g_printerr (format: "argv0=%s != moocow\n" , argv[0]); |
233 | return 1; |
234 | } |
235 | else if (strcmp (s1: mode, s2: "echo" ) == 0) |
236 | return echo_mode (argc, argv); |
237 | else if (strcmp (s1: mode, s2: "echo-stdout-and-stderr" ) == 0) |
238 | return echo_stdout_and_stderr_mode (argc, argv); |
239 | else if (strcmp (s1: mode, s2: "cat" ) == 0) |
240 | return cat_mode (argc, argv); |
241 | else if (strcmp (s1: mode, s2: "sleep-forever" ) == 0) |
242 | return sleep_forever_mode (argc, argv); |
243 | else if (strcmp (s1: mode, s2: "write-to-fds" ) == 0) |
244 | return write_to_fds (argc, argv); |
245 | else if (strcmp (s1: mode, s2: "env" ) == 0) |
246 | return env_mode (argc, argv); |
247 | else if (strcmp (s1: mode, s2: "cwd" ) == 0) |
248 | return cwd_mode (argc, argv); |
249 | else if (strcmp (s1: mode, s2: "printenv" ) == 0) |
250 | return printenv_mode (argc, argv); |
251 | else |
252 | { |
253 | g_printerr (format: "Unknown MODE %s\n" , argv[1]); |
254 | return 1; |
255 | } |
256 | |
257 | return TRUE; |
258 | } |
259 | |