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