Branch data Line data Source code
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 : : #else
9 : : #include <io.h>
10 : : #endif
11 : :
12 : : static GOptionEntry options[] = {
13 : : G_OPTION_ENTRY_NULL
14 : : };
15 : :
16 : : static void
17 : 12 : write_all (int fd,
18 : : const guint8* buf,
19 : : gsize len)
20 : : {
21 : 24 : while (len > 0)
22 : : {
23 : 12 : gssize bytes_written = write (fd, buf, len);
24 : 12 : int errsv = errno;
25 : 12 : if (bytes_written < 0)
26 : 0 : g_error ("Failed to write to fd %d: %s",
27 : : fd, g_strerror (errsv));
28 : 12 : buf += bytes_written;
29 : 12 : len -= bytes_written;
30 : : }
31 : 12 : }
32 : :
33 : : static int
34 : 1 : echo_mode (int argc,
35 : : char **argv)
36 : : {
37 : : int i;
38 : :
39 : 3 : for (i = 2; i < argc; i++)
40 : : {
41 : 2 : write_all (1, (guint8*)argv[i], strlen (argv[i]));
42 : 2 : write_all (1, (guint8*)"\n", 1);
43 : : }
44 : :
45 : 1 : return 0;
46 : : }
47 : :
48 : : static int
49 : 1 : echo_stdout_and_stderr_mode (int argc,
50 : : char **argv)
51 : : {
52 : : int i;
53 : :
54 : 3 : for (i = 2; i < argc; i++)
55 : : {
56 : 2 : write_all (1, (guint8*)argv[i], strlen (argv[i]));
57 : 2 : write_all (1, (guint8*)"\n", 1);
58 : 2 : write_all (2, (guint8*)argv[i], strlen (argv[i]));
59 : 2 : write_all (2, (guint8*)"\n", 1);
60 : : }
61 : :
62 : 1 : return 0;
63 : : }
64 : :
65 : : static int
66 : 58 : cat_mode (int argc,
67 : : char **argv)
68 : : {
69 : : GIOChannel *chan_stdin;
70 : : GIOChannel *chan_stdout;
71 : : GIOStatus status;
72 : : char buf[1024];
73 : : gsize bytes_read, bytes_written;
74 : 58 : GError *local_error = NULL;
75 : 58 : GError **error = &local_error;
76 : :
77 : 58 : chan_stdin = g_io_channel_unix_new (0);
78 : 58 : g_io_channel_set_encoding (chan_stdin, NULL, error);
79 : 58 : g_assert_no_error (local_error);
80 : 58 : chan_stdout = g_io_channel_unix_new (1);
81 : 58 : g_io_channel_set_encoding (chan_stdout, NULL, error);
82 : 58 : g_assert_no_error (local_error);
83 : :
84 : 108 : while (TRUE)
85 : : {
86 : : do
87 : 166 : status = g_io_channel_read_chars (chan_stdin, buf, sizeof (buf),
88 : : &bytes_read, error);
89 : 166 : while (status == G_IO_STATUS_AGAIN);
90 : :
91 : 166 : if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
92 : : break;
93 : :
94 : : do
95 : 108 : status = g_io_channel_write_chars (chan_stdout, buf, bytes_read,
96 : : &bytes_written, error);
97 : 108 : while (status == G_IO_STATUS_AGAIN);
98 : :
99 : 108 : if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
100 : : break;
101 : : }
102 : :
103 : 58 : g_io_channel_unref (chan_stdin);
104 : 58 : g_io_channel_unref (chan_stdout);
105 : :
106 : 58 : if (local_error)
107 : : {
108 : 0 : g_printerr ("I/O error: %s\n", local_error->message);
109 : 0 : g_clear_error (&local_error);
110 : 0 : return 1;
111 : : }
112 : 58 : return 0;
113 : : }
114 : :
115 : : static gint
116 : 0 : sleep_forever_mode (int argc,
117 : : char **argv)
118 : : {
119 : : GMainLoop *loop;
120 : :
121 : 0 : loop = g_main_loop_new (NULL, TRUE);
122 : 0 : g_main_loop_run (loop);
123 : :
124 : 0 : return 0;
125 : : }
126 : :
127 : : static int
128 : 3 : write_to_fds (int argc, char **argv)
129 : : {
130 : : int i;
131 : :
132 : 9 : for (i = 2; i < argc; i++)
133 : : {
134 : 6 : int fd = atoi (argv[i]);
135 : 6 : FILE *f = fdopen (fd, "w");
136 : 6 : const char buf[] = "hello world\n";
137 : : size_t bytes_written;
138 : :
139 : 6 : g_assert (f != NULL);
140 : :
141 : 6 : bytes_written = fwrite (buf, 1, sizeof (buf), f);
142 : 6 : g_assert (bytes_written == sizeof (buf));
143 : :
144 : 6 : if (fclose (f) == -1)
145 : : g_assert_not_reached ();
146 : : }
147 : :
148 : 3 : return 0;
149 : : }
150 : :
151 : : static int
152 : 4 : read_from_fd (int argc, char **argv)
153 : : {
154 : : int fd;
155 : 4 : const char expected_result[] = "Yay success!";
156 : : guint8 buf[sizeof (expected_result) + 1];
157 : : gsize bytes_read;
158 : : FILE *f;
159 : :
160 : 4 : if (argc != 3)
161 : : {
162 : 0 : g_print ("Usage: %s read-from-fd FD\n", argv[0]);
163 : 0 : return 1;
164 : : }
165 : :
166 : 4 : fd = atoi (argv[2]);
167 : 4 : if (fd == 0)
168 : : {
169 : 0 : g_warning ("Argument \"%s\" does not look like a valid nonzero file descriptor", argv[2]);
170 : 0 : return 1;
171 : : }
172 : :
173 : 4 : f = fdopen (fd, "r");
174 : 4 : if (f == NULL)
175 : : {
176 : 0 : g_warning ("Failed to open fd %d: %s", fd, g_strerror (errno));
177 : 0 : return 1;
178 : : }
179 : :
180 : 4 : bytes_read = fread (buf, 1, sizeof (buf), f);
181 : 4 : if (bytes_read != sizeof (expected_result))
182 : : {
183 : 0 : g_warning ("Read %zu bytes, but expected %zu", bytes_read, sizeof (expected_result));
184 : 0 : return 1;
185 : : }
186 : :
187 : 4 : if (memcmp (expected_result, buf, sizeof (expected_result)) != 0)
188 : : {
189 : 0 : buf[sizeof (expected_result)] = '\0';
190 : 0 : g_warning ("Expected \"%s\" but read \"%s\"", expected_result, (char *)buf);
191 : 0 : return 1;
192 : : }
193 : :
194 : 4 : if (fclose (f) == -1)
195 : : g_assert_not_reached ();
196 : :
197 : 4 : return 0;
198 : : }
199 : :
200 : : static int
201 : 2 : env_mode (int argc, char **argv)
202 : : {
203 : : char **env;
204 : : int i;
205 : :
206 : 2 : env = g_get_environ ();
207 : :
208 : 183 : for (i = 0; env[i]; i++)
209 : 181 : g_print ("%s\n", env[i]);
210 : :
211 : 2 : g_strfreev (env);
212 : :
213 : 2 : return 0;
214 : : }
215 : :
216 : : static int
217 : 1 : cwd_mode (int argc, char **argv)
218 : : {
219 : : char *cwd;
220 : :
221 : 1 : cwd = g_get_current_dir ();
222 : 1 : g_print ("%s\n", cwd);
223 : 1 : g_free (cwd);
224 : :
225 : 1 : return 0;
226 : : }
227 : :
228 : : static int
229 : 1 : printenv_mode (int argc, char **argv)
230 : : {
231 : : gint i;
232 : :
233 : 4 : for (i = 2; i < argc; i++)
234 : : {
235 : 3 : const gchar *value = g_getenv (argv[i]);
236 : :
237 : 3 : if (value != NULL)
238 : 2 : g_print ("%s=%s\n", argv[i], value);
239 : : }
240 : :
241 : 1 : return 0;
242 : : }
243 : :
244 : : #ifdef G_OS_UNIX
245 : : static void
246 : 1 : on_sleep_exited (GObject *object,
247 : : GAsyncResult *result,
248 : : gpointer user_data)
249 : : {
250 : 1 : GSubprocess *subprocess = G_SUBPROCESS (object);
251 : 1 : gboolean *done = user_data;
252 : 1 : GError *local_error = NULL;
253 : : gboolean ret;
254 : :
255 : 1 : ret = g_subprocess_wait_finish (subprocess, result, &local_error);
256 : 1 : g_assert_no_error (local_error);
257 : 1 : g_assert_true (ret);
258 : :
259 : 1 : *done = TRUE;
260 : 1 : g_main_context_wakeup (NULL);
261 : 1 : }
262 : :
263 : : static int
264 : 1 : sleep_and_kill (int argc, char **argv)
265 : : {
266 : 1 : GPtrArray *args = NULL;
267 : 1 : GSubprocessLauncher *launcher = NULL;
268 : 1 : GSubprocess *proc = NULL;
269 : 1 : GError *local_error = NULL;
270 : : pid_t sleep_pid;
271 : 1 : gboolean done = FALSE;
272 : :
273 : 1 : args = g_ptr_array_new_with_free_func (g_free);
274 : :
275 : : /* Run sleep "forever" in a shell; this will trigger PTRACE_EVENT_EXEC */
276 : 1 : g_ptr_array_add (args, g_strdup ("sh"));
277 : 1 : g_ptr_array_add (args, g_strdup ("-c"));
278 : 1 : g_ptr_array_add (args, g_strdup ("exec sleep infinity"));
279 : 1 : g_ptr_array_add (args, NULL);
280 : 1 : launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
281 : 1 : proc = g_subprocess_launcher_spawnv (launcher, (const gchar **) args->pdata, &local_error);
282 : 1 : g_assert_no_error (local_error);
283 : 1 : g_assert_nonnull (proc);
284 : :
285 : 1 : sleep_pid = atoi (g_subprocess_get_identifier (proc));
286 : :
287 : 1 : g_subprocess_wait_async (proc, NULL, on_sleep_exited, &done);
288 : :
289 : 1 : kill (sleep_pid, SIGKILL);
290 : :
291 : 2 : while (!done)
292 : 1 : g_main_context_iteration (NULL, TRUE);
293 : :
294 : 1 : g_assert_false (g_subprocess_get_successful (proc));
295 : :
296 : 1 : g_clear_pointer (&args, g_ptr_array_unref);
297 : 1 : g_clear_object (&launcher);
298 : 1 : g_clear_object (&proc);
299 : :
300 : 1 : return EXIT_SUCCESS;
301 : : }
302 : : #endif
303 : :
304 : : int
305 : 80 : main (int argc, char **argv)
306 : : {
307 : : GOptionContext *context;
308 : 80 : GError *error = NULL;
309 : : const char *mode;
310 : : gboolean ret;
311 : :
312 : 80 : context = g_option_context_new ("MODE - Test GSubprocess stuff");
313 : 80 : g_option_context_add_main_entries (context, options, NULL);
314 : 80 : ret = g_option_context_parse (context, &argc, &argv, &error);
315 : 80 : g_option_context_free (context);
316 : :
317 : 80 : if (!ret)
318 : : {
319 : 0 : g_printerr ("%s: %s\n", argv[0], error->message);
320 : 0 : g_error_free (error);
321 : 0 : return 1;
322 : : }
323 : :
324 : 80 : if (argc < 2)
325 : : {
326 : 0 : g_printerr ("MODE argument required\n");
327 : 0 : return 1;
328 : : }
329 : :
330 : 80 : g_log_writer_default_set_use_stderr (TRUE);
331 : :
332 : 80 : mode = argv[1];
333 : 80 : if (strcmp (mode, "noop") == 0)
334 : 4 : return 0;
335 : 76 : else if (strcmp (mode, "exit1") == 0)
336 : 4 : return 1;
337 : 72 : else if (strcmp (mode, "assert-argv0") == 0)
338 : : {
339 : 0 : if (strcmp (argv[0], "moocow") == 0)
340 : 0 : return 0;
341 : 0 : g_printerr ("argv0=%s != moocow\n", argv[0]);
342 : 0 : return 1;
343 : : }
344 : 72 : else if (strcmp (mode, "echo") == 0)
345 : 1 : return echo_mode (argc, argv);
346 : 71 : else if (strcmp (mode, "echo-stdout-and-stderr") == 0)
347 : 1 : return echo_stdout_and_stderr_mode (argc, argv);
348 : 70 : else if (strcmp (mode, "cat") == 0)
349 : 58 : return cat_mode (argc, argv);
350 : 12 : else if (strcmp (mode, "sleep-forever") == 0)
351 : 0 : return sleep_forever_mode (argc, argv);
352 : 12 : else if (strcmp (mode, "write-to-fds") == 0)
353 : 3 : return write_to_fds (argc, argv);
354 : 9 : else if (strcmp (mode, "read-from-fd") == 0)
355 : 4 : return read_from_fd (argc, argv);
356 : 5 : else if (strcmp (mode, "env") == 0)
357 : 2 : return env_mode (argc, argv);
358 : 3 : else if (strcmp (mode, "cwd") == 0)
359 : 1 : return cwd_mode (argc, argv);
360 : 2 : else if (strcmp (mode, "printenv") == 0)
361 : 1 : return printenv_mode (argc, argv);
362 : : #ifdef G_OS_UNIX
363 : 1 : else if (strcmp (mode, "sleep-and-kill") == 0)
364 : 1 : return sleep_and_kill (argc, argv);
365 : : #endif
366 : : else
367 : : {
368 : 0 : g_printerr ("Unknown MODE %s\n", argv[1]);
369 : 0 : return 1;
370 : : }
371 : :
372 : : return TRUE;
373 : : }
|