message-view: bgo #727634 - Cannot copy build output
[anjuta.git] / libanjuta / anjuta-launcher.c
blobc2900f28725e04229d455c2e1ef3790cb8f39873
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-launcher.c
4 * Copyright (C) 2003 Naba Kumar <naba@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:anjuta-launcher
23 * @short_description: External process launcher with async input/output
24 * @see_also:
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-launcher.h
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
34 #include <errno.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <signal.h>
39 /* not sure if any platform has more than one of these, so play it
40 safe and use any-and-all-found rather than elif fallback */
41 #ifdef HAVE_LIBUTIL_H
42 # include <libutil.h>
43 #endif
44 #ifdef HAVE_UTIL_H
45 # include <util.h>
46 #endif
47 #ifdef HAVE_PTY_H
48 # include <pty.h>
49 #endif
51 #include "anjuta-utils-priv.h"
53 #include <assert.h>
54 #include <termios.h>
56 #include <string.h>
57 #include <time.h>
58 #include <glib/gi18n.h>
59 #include <glib.h>
61 #include "anjuta-utils.h"
62 #include "anjuta-marshal.h"
63 #include "resources.h"
64 #include "anjuta-launcher.h"
65 #include "anjuta-debug.h"
67 #define ANJUTA_PIXMAP_PASSWORD "password.png"
68 #define FILE_BUFFER_SIZE 1024
69 #define FILE_INPUT_BUFFER_SIZE (1024 * 1024 * 4)
70 #ifndef __MAX_BAUD
71 # if defined(B460800)
72 # define __MAX_BAUD B460800
73 # elif defined(B307200)
74 # define __MAX_BAUD B307200
75 # elif defined(B256000)
76 # define __MAX_BAUD B256000
77 # else
78 # define __MAX_BAUD B230400
79 # endif
80 #endif
83 static gboolean
84 anjuta_launcher_pty_check_child_exit_code (AnjutaLauncher *launcher,
85 const gchar* line);
87 struct _AnjutaLauncherPriv
90 * Busy flag is TRUE if the Launcher
91 * is currently executing a child.
93 gboolean busy;
95 /* These flags are used to synchronize the IO operations. */
96 gboolean stdout_is_done;
97 gboolean stderr_is_done;
99 /* GIO channels */
100 GIOChannel *stdout_channel;
101 GIOChannel *stderr_channel;
102 /*GIOChannel *stdin_channel;*/
103 GIOChannel *pty_channel;
105 /* GIO watch handles */
106 guint stdout_watch;
107 guint stderr_watch;
108 guint pty_watch;
110 /* Output line buffers */
111 gchar *stdout_buffer;
112 gchar *stderr_buffer;
114 /* Output of the pty is constantly stored here.*/
115 gchar *pty_output_buffer;
117 /* Terminal echo */
118 gboolean terminal_echo_on;
120 /* The child */
121 pid_t child_pid;
122 guint source;
123 gint child_status;
124 gboolean child_has_terminated;
126 /* Synchronization in progress */
127 guint completion_check_timeout;
129 /* Terminate child on child exit */
130 gboolean terminate_on_exit;
132 /* Start time of execution */
133 time_t start_time;
135 /* Should the outputs be buffered */
136 gboolean buffered_output;
138 /* Should we check for password prompts in stdout and pty */
139 gboolean check_for_passwd_prompt;
141 /* Output callback */
142 AnjutaLauncherOutputCallback output_callback;
144 /* Callback data */
145 gpointer callback_data;
147 /* Encondig */
148 gboolean custom_encoding;
149 gchar* encoding;
151 /* Env */
152 GHashTable* env;
155 enum
157 /* OUTPUT_ARRIVED_SIGNAL, */
158 CHILD_EXITED_SIGNAL,
159 BUSY_SIGNAL,
160 LAST_SIGNAL
163 static void anjuta_launcher_class_init (AnjutaLauncherClass * klass);
164 static void anjuta_launcher_init (AnjutaLauncher * obj);
165 static gboolean anjuta_launcher_call_execution_done (gpointer data);
166 static gboolean anjuta_launcher_check_for_execution_done (gpointer data);
167 static void anjuta_launcher_execution_done_cleanup (AnjutaLauncher *launcher,
168 gboolean emit_signal);
170 static gboolean is_password_prompt(const gchar* line);
172 static guint launcher_signals[LAST_SIGNAL] = { 0 };
173 static AnjutaLauncherClass *parent_class;
175 static void
176 anjuta_launcher_initialize (AnjutaLauncher *obj)
178 /* Busy flag */
179 obj->priv->busy = FALSE;
181 /* These flags are used to synchronize the IO operations. */
182 obj->priv->stdout_is_done = FALSE;
183 obj->priv->stderr_is_done = FALSE;
185 /* GIO channels */
186 obj->priv->stdout_channel = NULL;
187 obj->priv->stderr_channel = NULL;
188 obj->priv->pty_channel = NULL;
190 /* Output line buffers */
191 obj->priv->stdout_buffer = NULL;
192 obj->priv->stderr_buffer = NULL;
194 /* Pty buffer */
195 obj->priv->pty_output_buffer = NULL;
197 obj->priv->terminal_echo_on = TRUE;
199 /* The child */
200 obj->priv->child_pid = 0;
201 obj->priv->child_status = -1;
202 obj->priv->child_has_terminated = TRUE;
203 obj->priv->source = 0;
205 /* Synchronization in progress */
206 obj->priv->completion_check_timeout = 0;
208 /* Terminate child on child exit */
209 obj->priv->terminate_on_exit = FALSE;
211 /* Start time of execution */
212 obj->priv->start_time = 0;
214 obj->priv->buffered_output = TRUE;
215 obj->priv->check_for_passwd_prompt = TRUE;
217 /* Output callback */
218 obj->priv->output_callback = NULL;
219 obj->priv->callback_data = NULL;
221 /* Encoding */
222 obj->priv->custom_encoding = FALSE;
223 obj->priv->encoding = NULL;
225 /* Env */
226 obj->priv->env = g_hash_table_new_full (g_str_hash, g_str_equal,
227 g_free, g_free);
230 GType
231 anjuta_launcher_get_type ()
233 static GType obj_type = 0;
235 if (!obj_type)
237 static const GTypeInfo obj_info =
239 sizeof (AnjutaLauncherClass),
240 (GBaseInitFunc) NULL,
241 (GBaseFinalizeFunc) NULL,
242 (GClassInitFunc) anjuta_launcher_class_init,
243 (GClassFinalizeFunc) NULL,
244 NULL, /* class_data */
245 sizeof (AnjutaLauncher),
246 0, /* n_preallocs */
247 (GInstanceInitFunc) anjuta_launcher_init,
248 NULL /* value_table */
250 obj_type = g_type_register_static (G_TYPE_OBJECT,
251 "AnjutaLauncher", &obj_info, 0);
253 return obj_type;
256 static void
257 anjuta_launcher_dispose (GObject *obj)
259 AnjutaLauncher *launcher = ANJUTA_LAUNCHER (obj);
260 if (anjuta_launcher_is_busy (launcher))
262 g_source_remove (launcher->priv->source);
263 launcher->priv->source = 0;
265 anjuta_launcher_execution_done_cleanup (launcher, FALSE);
267 launcher->priv->busy = FALSE;
270 G_OBJECT_CLASS (parent_class)->dispose (obj);
273 static void
274 anjuta_launcher_finalize (GObject *obj)
276 AnjutaLauncher *launcher = ANJUTA_LAUNCHER (obj);
277 if (launcher->priv->custom_encoding && launcher->priv->encoding)
278 g_free (launcher->priv->encoding);
280 g_hash_table_destroy (launcher->priv->env);
282 g_free (launcher->priv);
283 G_OBJECT_CLASS (parent_class)->finalize (obj);
286 static void
287 anjuta_launcher_class_init (AnjutaLauncherClass * klass)
289 GObjectClass *object_class;
290 g_return_if_fail (klass != NULL);
291 object_class = (GObjectClass *) klass;
293 /* DEBUG_PRINT ("%s", "Initializing launcher class"); */
295 parent_class = g_type_class_peek_parent (klass);
298 * AnjutaLauncher::child-exited:
299 * @launcher: a #AnjutaLancher object.
300 * @child_pid: process ID of the child
301 * @status: status as returned by waitpid function
302 * @time: time in seconds taken by the child
304 * Emitted when the child has exited and all i/o channels have
305 * been closed. If the terminate on exit flag is set, the i/o
306 * channels are automatically closed when the child exit.
307 * You need to use WEXITSTATUS and friend to get the child exit
308 * code from the status returned.
310 launcher_signals[CHILD_EXITED_SIGNAL] =
311 g_signal_new ("child-exited",
312 G_TYPE_FROM_CLASS (object_class),
313 G_SIGNAL_RUN_FIRST,
314 G_STRUCT_OFFSET (AnjutaLauncherClass,
315 child_exited),
316 NULL, NULL,
317 anjuta_cclosure_marshal_VOID__INT_INT_ULONG,
318 G_TYPE_NONE, 3, G_TYPE_INT,
319 G_TYPE_INT, G_TYPE_ULONG);
322 * AnjutaLauncher::busy:
323 * @launcher: a #AnjutaLancher object.
324 * @busy: %TRUE is a child is currently running
326 * Emitted when a child starts after a call to one execute function
327 * (busy is %TRUE) or when a child exits and all i/o channels are
328 * closed (busy is %FALSE).
330 launcher_signals[BUSY_SIGNAL] =
331 g_signal_new ("busy",
332 G_TYPE_FROM_CLASS (object_class),
333 G_SIGNAL_RUN_FIRST,
334 G_STRUCT_OFFSET (AnjutaLauncherClass,
335 busy),
336 NULL, NULL,
337 anjuta_cclosure_marshal_VOID__BOOLEAN,
338 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
340 object_class->dispose = anjuta_launcher_dispose;
341 object_class->finalize = anjuta_launcher_finalize;
344 static void
345 anjuta_launcher_init (AnjutaLauncher * obj)
347 g_return_if_fail (obj != NULL);
348 obj->priv = g_new0 (AnjutaLauncherPriv, 1);
349 anjuta_launcher_initialize (obj);
353 * anjuta_launcher_is_busy:
354 * @launcher: a #AnjutaLancher object.
356 * Tells if the laucher is currently executing any command.
358 * Return value: %TRUE if launcher is busy, otherwise %FALSE.
360 gboolean
361 anjuta_launcher_is_busy (AnjutaLauncher *launcher)
363 return launcher->priv->busy;
366 static void
367 anjuta_launcher_set_busy (AnjutaLauncher *launcher, gboolean flag)
369 gboolean old_busy = launcher->priv->busy;
370 launcher->priv->busy = flag;
371 if (old_busy != flag)
372 g_signal_emit_by_name (G_OBJECT (launcher), "busy", flag);
376 * anjuta_launcher_send_stdin:
377 * @launcher: a #AnjutaLancher object.
378 * @input_str: The string to send to STDIN of the process.
380 * Sends a string to Standard input of the process currently being executed.
382 void
383 anjuta_launcher_send_stdin (AnjutaLauncher *launcher, const gchar * input_str)
385 g_return_if_fail (launcher);
386 g_return_if_fail (input_str);
388 anjuta_launcher_send_ptyin (launcher, input_str);
392 * anjuta_launcher_send_stdin_eof:
393 * @launcher: a #AnjutaLancher object.
395 * Sends a EOF to Standard input of the process currently being executed.
398 void
399 anjuta_launcher_send_stdin_eof (AnjutaLauncher *launcher)
401 GError* err = NULL;
402 g_io_channel_shutdown (launcher->priv->pty_channel, TRUE,
403 &err);
404 g_io_channel_unref (launcher->priv->pty_channel);
405 launcher->priv->pty_channel = NULL;
407 if (err)
409 g_warning ("g_io_channel_shutdown () failed: %s", err->message);
414 * anjuta_launcher_send_ptyin:
415 * @launcher: a #AnjutaLancher object.
416 * @input_str: The string to send to PTY of the process.
418 * Sends a string to TTY input of the process currently being executed.
419 * Mostly useful for entering passwords and other inputs which are directly
420 * read from TTY input of the process.
422 void
423 anjuta_launcher_send_ptyin (AnjutaLauncher *launcher, const gchar * input_str)
425 gsize bytes_written = 0;
426 GError *err = NULL;
428 g_return_if_fail (launcher);
429 g_return_if_fail (input_str);
430 g_return_if_fail (launcher->priv->pty_channel != NULL);
432 if (strlen (input_str) == 0)
433 return;
437 g_io_channel_write_chars (launcher->priv->pty_channel,
438 input_str, strlen (input_str),
439 &bytes_written, &err);
440 g_io_channel_flush (launcher->priv->pty_channel, NULL);
441 if (err)
443 g_warning ("Error encountered while writing to PTY!. %s",
444 err->message);
445 g_error_free (err);
447 return;
449 input_str += bytes_written;
451 while (*input_str);
455 * anjuta_launcher_reset:
456 * @launcher: a #AnjutaLancher object.
458 * Resets the launcher and kills (SIGTERM) current process, if it is still
459 * executing.
461 void
462 anjuta_launcher_reset (AnjutaLauncher *launcher)
464 if (anjuta_launcher_is_busy (launcher) &&
465 launcher->priv->child_pid)
466 kill (launcher->priv->child_pid, SIGTERM);
470 * anjuta_launcher_signal:
471 * @launcher: a #AnjutaLancher object.
472 * @sig: kernel signal ID (e.g. SIGTERM).
474 * Sends a kernel signal to the process that is being executed.
476 void
477 anjuta_launcher_signal (AnjutaLauncher *launcher, int sig)
479 if (launcher->priv->child_pid)
480 kill (launcher->priv->child_pid, sig);
484 * anjuta_launcher_get_child_pid:
485 * @launcher: a #AnjutaLancher object.
487 * Gets the Process ID of the child being executed.
489 * Return value: Process ID of the child.
491 pid_t
492 anjuta_launcher_get_child_pid (AnjutaLauncher *launcher)
494 if (anjuta_launcher_is_busy (launcher))
495 return launcher->priv->child_pid;
496 else
497 return -1;
500 static void
501 anjuta_launcher_synchronize (AnjutaLauncher *launcher)
503 if (launcher->priv->child_has_terminated &&
504 launcher->priv->stdout_is_done &&
505 launcher->priv->stderr_is_done)
507 if (launcher->priv->completion_check_timeout != 0)
508 g_source_remove (launcher->priv->completion_check_timeout);
509 launcher->priv->completion_check_timeout =
510 /* Use a low priority timer to make sure all pending I/O are flushed out */
511 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 50, anjuta_launcher_check_for_execution_done,
512 launcher, NULL);
515 /* This case is not very good, but it blocks the whole IDE
516 because we never new if the child has finished */
517 else if (launcher->priv->stdout_is_done &&
518 launcher->priv->stderr_is_done)
520 /* DEBUG_PRINT ("%s", "Child has't exited yet waiting for 200ms"); */
521 if (launcher->priv->completion_check_timeout != 0)
522 g_source_remove (launcher->priv->completion_check_timeout);
523 launcher->priv->completion_check_timeout =
524 /* Use a low priority timer to make sure all pending I/O are flushed out */
525 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 200, anjuta_launcher_check_for_execution_done,
526 launcher, NULL);
528 /* Add this case for gdb. It creates child inheriting gdb
529 * pipes which are not closed if gdb crashes */
530 else if (launcher->priv->child_has_terminated &&
531 launcher->priv->terminate_on_exit)
533 if (launcher->priv->completion_check_timeout != 0)
534 g_source_remove (launcher->priv->completion_check_timeout);
535 launcher->priv->completion_check_timeout =
536 /* Use a low priority timer to make sure all pending I/O are flushed out */
537 g_idle_add ( anjuta_launcher_call_execution_done,
538 launcher);
542 /* Password dialog */
543 static GtkWidget*
544 create_password_dialog (const gchar* prompt)
546 GtkWidget *dialog;
547 GtkWidget *hbox;
548 GtkWidget *box;
549 GtkWidget *icon;
550 GtkWidget *label;
551 GtkWidget *entry;
553 g_return_val_if_fail (prompt, NULL);
555 dialog = gtk_dialog_new_with_buttons (prompt,
556 NULL, //FIXME: Pass the parent window here
557 // for transient purpose.
558 GTK_DIALOG_DESTROY_WITH_PARENT,
559 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
560 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
561 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
563 gtk_window_set_wmclass (GTK_WINDOW (dialog), "launcher-password-prompt",
564 "anjuta");
565 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
566 gtk_widget_show (hbox);
567 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG(dialog))), hbox);
569 icon = anjuta_res_get_image (ANJUTA_PIXMAP_PASSWORD);
570 gtk_widget_show (icon);
571 gtk_box_pack_start (GTK_BOX(hbox), icon, TRUE, TRUE, 0);
573 if (strlen (prompt) < 20) {
574 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
575 } else {
576 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
578 gtk_widget_show (box);
579 gtk_box_pack_start (GTK_BOX (hbox), box, TRUE, TRUE, 0);
581 label = gtk_label_new (_(prompt));
582 gtk_widget_show (label);
583 gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
585 entry = gtk_entry_new ();
586 gtk_widget_show (entry);
587 gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
588 gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 0);
590 g_object_ref (entry);
591 g_object_set_data_full (G_OBJECT (dialog), "password_entry",
592 g_object_ref (entry),
593 g_object_unref);
594 gtk_widget_grab_focus (entry);
595 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
597 return dialog;
600 /* pty buffer check for password authentication */
601 static void
602 anjuta_launcher_check_password_real (AnjutaLauncher *launcher,
603 const gchar* last_line)
605 if (anjuta_launcher_is_busy (launcher) == FALSE)
606 return;
608 if (last_line) {
610 /* DEBUG_PRINT ("(In password) Last line = %s", last_line); */
611 if (is_password_prompt(last_line)) {
612 /* Password prompt detected */
613 GtkWidget* dialog;
614 gint button;
615 const gchar* passwd;
616 gchar* line;
618 dialog = create_password_dialog (last_line);
619 button = gtk_dialog_run (GTK_DIALOG(dialog));
620 switch (button) {
621 case GTK_RESPONSE_OK:
622 passwd = gtk_entry_get_text (
623 GTK_ENTRY (g_object_get_data (G_OBJECT (dialog),
624 "password_entry")));
625 line = g_strconcat (passwd, "\n", NULL);
626 anjuta_launcher_send_ptyin (launcher, line);
627 g_free (line);
628 break;
629 case GTK_RESPONSE_CANCEL:
630 anjuta_launcher_reset (launcher);
631 break;
632 default:
633 break;
635 gtk_widget_destroy (dialog);
640 static void
641 anjuta_launcher_check_password (AnjutaLauncher *launcher, const gchar *chars)
643 glong start, end;
644 gchar *last_line;
646 if (!chars || strlen(chars) <= 0)
647 return;
649 /* DEBUG_PRINT ("Chars buffer = %s", chars); */
650 start = end = strlen (chars);
651 while (start > 0 && chars[start-1] != '\n') start--;
653 if (end > start)
655 last_line = g_strndup (&chars[start], end - start + 1);
657 /* DEBUG_PRINT ("Last line = %s", last_line); */
658 /* Checks for password, again */
659 anjuta_launcher_check_password_real (launcher, last_line);
660 g_free (last_line);
664 static gboolean
665 is_password_prompt (const gchar* line)
667 const gchar* regex = "[Pp]assword.*:";
669 * Translators: This regex should match the password prompts of
670 * at least the "su" and the "sudo" command line utility in your
671 * language and possible other things like "ssh".
672 * More information on the regular expression syntax can be
673 * found at http://library.gnome.org/devel/glib/unstable/glib-regex-syntax.html
675 const gchar* i18n_regex = _("[Pp]assword.*:");
676 if (g_regex_match_simple (regex, line, 0, 0))
677 return TRUE;
678 else if (g_regex_match_simple (i18n_regex, line, 0, 0))
679 return TRUE;
681 return FALSE;
684 static void
685 anjuta_launcher_buffered_output (AnjutaLauncher *launcher,
686 AnjutaLauncherOutputType output_type,
687 const gchar *chars)
689 gchar *all_lines;
690 gchar *incomplete_line;
691 gchar **buffer;
693 g_return_if_fail (chars != NULL);
694 g_return_if_fail (strlen (chars) > 0);
696 if (launcher->priv->output_callback == NULL)
697 return;
698 if (launcher->priv->buffered_output == FALSE)
700 (launcher->priv->output_callback)(launcher, output_type, chars,
701 launcher->priv->callback_data);
702 return;
704 switch (output_type)
706 case ANJUTA_LAUNCHER_OUTPUT_STDOUT:
707 buffer = &launcher->priv->stdout_buffer;
708 break;
709 case ANJUTA_LAUNCHER_OUTPUT_STDERR:
710 buffer = &launcher->priv->stderr_buffer;
711 break;
712 default:
713 g_warning ("Should not reach here");
714 return;
716 if (*buffer)
717 all_lines = g_strconcat (*buffer, chars, NULL);
718 else
719 all_lines = g_strdup (chars);
721 /* Buffer the last incomplete line */
722 incomplete_line = all_lines + strlen (all_lines);
723 while (incomplete_line > all_lines &&
724 *incomplete_line != '\n')
726 incomplete_line = g_utf8_prev_char (incomplete_line);
728 if (*incomplete_line == '\n')
729 incomplete_line++;
731 /* Update line buffer */
732 g_free(*buffer);
733 *buffer = NULL;
734 if (strlen(incomplete_line))
736 *buffer = g_strdup (incomplete_line);
737 /* DEBUG_PRINT ("Line buffer for %d: %s", output_type, incomplete_line); */
739 /* Check for password prompt */
740 if (launcher->priv->check_for_passwd_prompt)
741 anjuta_launcher_check_password (launcher, incomplete_line);
743 /* Deliver complete lines */
744 *incomplete_line = '\0';
745 if (strlen (all_lines) > 0)
746 (launcher->priv->output_callback)(launcher, output_type, all_lines,
747 launcher->priv->callback_data);
748 g_free (all_lines);
751 static gboolean
752 anjuta_launcher_scan_output (GIOChannel *channel, GIOCondition condition,
753 AnjutaLauncher *launcher)
755 gsize n;
756 gchar buffer[FILE_BUFFER_SIZE];
757 gboolean ret = TRUE;
759 if (condition & G_IO_IN)
761 GError *err = NULL;
764 g_io_channel_read_chars (channel, buffer, FILE_BUFFER_SIZE-1, &n, &err);
765 if (n > 0) /* There is output */
767 gchar *utf8_chars = NULL;
768 buffer[n] = '\0';
769 if (!launcher->priv->custom_encoding)
770 utf8_chars = anjuta_util_convert_to_utf8 (buffer);
771 else
772 utf8_chars = g_strdup(buffer);
773 anjuta_launcher_buffered_output (launcher,
774 ANJUTA_LAUNCHER_OUTPUT_STDOUT,
775 utf8_chars);
776 g_free (utf8_chars);
778 /* Ignore illegal characters */
779 if (err && err->domain == G_CONVERT_ERROR)
781 g_error_free (err);
782 err = NULL;
784 /* The pipe is closed on the other side */
785 /* if not related to non blocking read or interrupted syscall */
786 else if (err && errno != EAGAIN && errno != EINTR)
788 launcher->priv->stdout_is_done = TRUE;
789 anjuta_launcher_synchronize (launcher);
790 ret = FALSE;
792 /* Read next chars if buffer was too small
793 * (the maximum length of one character is 6 bytes) */
794 } while (!err && (n > FILE_BUFFER_SIZE - 7));
795 if (err)
796 g_error_free (err);
798 if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
800 DEBUG_PRINT ("%s", "launcher.c: STDOUT pipe closed");
801 launcher->priv->stdout_is_done = TRUE;
802 anjuta_launcher_synchronize (launcher);
803 ret = FALSE;
805 return ret;
808 static gboolean
809 anjuta_launcher_scan_error (GIOChannel *channel, GIOCondition condition,
810 AnjutaLauncher *launcher)
812 gsize n;
813 gchar buffer[FILE_BUFFER_SIZE];
814 gboolean ret = TRUE;
816 if (condition & G_IO_IN)
818 GError *err = NULL;
821 g_io_channel_read_chars (channel, buffer, FILE_BUFFER_SIZE-1, &n, &err);
822 if (n > 0) /* There is stderr output */
824 gchar *utf8_chars;
825 buffer[n] = '\0';
826 utf8_chars = anjuta_util_convert_to_utf8 (buffer);
827 anjuta_launcher_buffered_output (launcher,
828 ANJUTA_LAUNCHER_OUTPUT_STDERR,
829 utf8_chars);
830 g_free (utf8_chars);
832 /* Ignore illegal characters */
833 if (err && err->domain == G_CONVERT_ERROR)
835 g_error_free (err);
836 err = NULL;
838 /* The pipe is closed on the other side */
839 /* if not related to non blocking read or interrupted syscall */
840 else if (err && errno != EAGAIN && errno != EINTR)
843 launcher->priv->stderr_is_done = TRUE;
844 anjuta_launcher_synchronize (launcher);
845 ret = FALSE;
847 /* Read next chars if buffer was too small
848 * (the maximum length of one character is 6 bytes) */
849 } while (!err && (n > FILE_BUFFER_SIZE - 7));
850 if (err)
851 g_error_free (err);
853 if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
855 DEBUG_PRINT ("%s", "launcher.c: STDERR pipe closed");
856 launcher->priv->stderr_is_done = TRUE;
857 anjuta_launcher_synchronize (launcher);
858 ret = FALSE;
860 return ret;
863 static gboolean
864 anjuta_launcher_scan_pty (GIOChannel *channel, GIOCondition condition,
865 AnjutaLauncher *launcher)
867 gsize n;
868 gchar buffer[FILE_BUFFER_SIZE];
869 gboolean ret = TRUE;
871 if (condition & G_IO_IN)
873 GError *err = NULL;
876 g_io_channel_read_chars (channel, buffer, FILE_BUFFER_SIZE-1, &n, &err);
877 if (n > 0) /* There is stderr output */
879 gchar *utf8_chars;
880 gchar *old_str = launcher->priv->pty_output_buffer;
881 buffer[n] = '\0';
882 utf8_chars = anjuta_util_convert_to_utf8 (buffer);
883 if (old_str)
885 gchar *str = g_strconcat (old_str, utf8_chars, NULL);
886 launcher->priv->pty_output_buffer = str;
887 g_free (old_str);
889 else
890 launcher->priv->pty_output_buffer = g_strdup (utf8_chars);
891 g_free (utf8_chars);
893 /* Ignore illegal characters */
894 if (err && err->domain == G_CONVERT_ERROR)
896 g_error_free (err);
897 err = NULL;
899 /* The pipe is closed on the other side */
900 /* if not related to non blocking read or interrupted syscall */
901 else if (err && errno != EAGAIN && errno != EINTR)
903 ret = FALSE;
905 /* Read next chars if buffer was too small
906 * (the maximum length of one character is 6 bytes) */
907 } while (!err && (n > FILE_BUFFER_SIZE - 7));
908 if (err)
909 g_error_free (err);
910 if (launcher->priv->check_for_passwd_prompt
911 && launcher->priv->pty_output_buffer
912 && strlen (launcher->priv->pty_output_buffer) > 0)
914 anjuta_launcher_check_password (launcher,
915 launcher->priv->pty_output_buffer);
918 /* In pty case, we handle the cases in different invocations */
919 /* Do not hook up for G_IO_HUP */
920 if (condition & G_IO_ERR)
922 DEBUG_PRINT ("%s", "launcher.c: PTY pipe error!");
923 ret = FALSE;
925 return ret;
928 static void
929 anjuta_launcher_execution_done_cleanup (AnjutaLauncher *launcher,
930 gboolean emit_signal)
932 gint child_status, child_pid;
933 time_t start_time;
935 /* Remove pending timeout */
936 if (launcher->priv->completion_check_timeout != 0)
937 g_source_remove (launcher->priv->completion_check_timeout);
939 if (launcher->priv->stdout_channel)
941 g_io_channel_shutdown (launcher->priv->stdout_channel, emit_signal, NULL);
942 g_io_channel_unref (launcher->priv->stdout_channel);
943 if (!launcher->priv->stdout_is_done)
944 g_source_remove (launcher->priv->stdout_watch);
947 if (launcher->priv->stderr_channel)
949 g_io_channel_shutdown (launcher->priv->stderr_channel, emit_signal, NULL);
950 g_io_channel_unref (launcher->priv->stderr_channel);
951 if (!launcher->priv->stderr_is_done)
952 g_source_remove (launcher->priv->stderr_watch);
955 if (launcher->priv->pty_channel)
957 g_io_channel_shutdown (launcher->priv->pty_channel, emit_signal, NULL);
958 g_io_channel_unref (launcher->priv->pty_channel);
960 g_source_remove (launcher->priv->pty_watch);
963 if (launcher->priv->pty_output_buffer)
964 g_free (launcher->priv->pty_output_buffer);
965 if (launcher->priv->stdout_buffer)
967 /* Send remaining data if last line is not terminated with EOL */
968 (launcher->priv->output_callback)(launcher,
969 ANJUTA_LAUNCHER_OUTPUT_STDOUT,
970 launcher->priv->stdout_buffer,
971 launcher->priv->callback_data);
972 g_free (launcher->priv->stdout_buffer);
974 if (launcher->priv->stderr_buffer)
976 /* Send remaining data if last line is not terminated with EOL */
977 (launcher->priv->output_callback)(launcher,
978 ANJUTA_LAUNCHER_OUTPUT_STDERR,
979 launcher->priv->stderr_buffer,
980 launcher->priv->callback_data);
981 g_free (launcher->priv->stdout_buffer);
984 /* Save them before we re-initialize */
985 child_status = launcher->priv->child_status;
986 child_pid = launcher->priv->child_pid;
987 start_time = launcher->priv->start_time;
989 if (emit_signal)
990 anjuta_launcher_set_busy (launcher, FALSE);
992 anjuta_launcher_initialize (launcher);
995 /* Call this here, after set_busy (FALSE) so we are able to
996 launch a new child from the terminate function.
997 (by clubfan 2002-04-07)
999 /* DEBUG_PRINT ("Exit status: %d", child_status); */
1000 if (emit_signal)
1001 g_signal_emit_by_name (launcher, "child-exited", child_pid,
1002 child_status,
1003 time (NULL) - start_time);
1006 /* Using this function is necessary because
1007 * anjuta_launcher_execution_done_cleanup needs to be called in the same
1008 * thread than the gtk main loop */
1009 static gboolean
1010 anjuta_launcher_call_execution_done (gpointer data)
1012 AnjutaLauncher *launcher = data;
1014 launcher->priv->completion_check_timeout = 0;
1015 anjuta_launcher_execution_done_cleanup (launcher, TRUE);
1016 return FALSE;
1019 /* monitors closure of stdout stderr and pty through a gtk_timeout_add setup */
1020 static gboolean
1021 anjuta_launcher_check_for_execution_done (gpointer data)
1023 AnjutaLauncher *launcher = data;
1025 DEBUG_PRINT ("launcher_execution_done STDOUT:%d, STDERR:%d",
1026 launcher->priv->stdout_is_done ? 1 : 0,
1027 launcher->priv->stderr_is_done ? 1 : 0);
1029 if (launcher->priv->stdout_is_done == FALSE ||
1030 launcher->priv->stderr_is_done == FALSE)
1031 return TRUE;
1032 if (launcher->priv->child_has_terminated == FALSE)
1034 /* DEBUG_PRINT ("%s", "launcher: We missed the exit of the child"); */
1036 launcher->priv->completion_check_timeout = 0;
1037 anjuta_launcher_execution_done_cleanup (launcher, TRUE);
1038 return FALSE;
1041 static void
1042 anjuta_launcher_child_terminated (GPid pid, gint status, gpointer data)
1044 AnjutaLauncher *launcher = data;
1046 g_return_if_fail(ANJUTA_IS_LAUNCHER(launcher));
1048 /* Save child exit code */
1049 launcher->priv->child_status = status;
1050 launcher->priv->child_has_terminated = TRUE;
1051 anjuta_launcher_synchronize (launcher);
1055 static gboolean
1056 anjuta_launcher_set_encoding_real (AnjutaLauncher *launcher, const gchar *charset)
1058 GIOStatus s;
1059 gboolean r = TRUE;
1061 g_return_val_if_fail (launcher != NULL, FALSE);
1062 // charset can be NULL
1064 s = g_io_channel_set_encoding (launcher->priv->stderr_channel, charset, NULL);
1065 if (s != G_IO_STATUS_NORMAL) r = FALSE;
1066 s = g_io_channel_set_encoding (launcher->priv->stdout_channel, charset, NULL);
1067 if (s != G_IO_STATUS_NORMAL) r = FALSE;
1068 s = g_io_channel_set_encoding (launcher->priv->pty_channel, charset, NULL);
1069 if (s != G_IO_STATUS_NORMAL) r = FALSE;
1071 if (! r)
1073 g_warning ("launcher.c: Failed to set channel encoding!");
1075 return r;
1080 * anjuta_launcher_set_encoding:
1081 * @launcher: a #AnjutaLancher object.
1082 * @charset: Character set to use for Input/Output with the process.
1084 * Sets the character set to use for Input/Output with the process.
1087 void
1088 anjuta_launcher_set_encoding (AnjutaLauncher *launcher, const gchar *charset)
1090 if (launcher->priv->custom_encoding)
1091 g_free (launcher->priv->encoding);
1093 launcher->priv->custom_encoding = TRUE;
1094 if (charset)
1095 launcher->priv->encoding = g_strdup(charset);
1096 else
1097 launcher->priv->encoding = NULL;
1100 static pid_t
1101 anjuta_launcher_fork (AnjutaLauncher *launcher, const gchar *dir, gchar *const args[], gchar *const envp[])
1103 int pty_master_fd, md;
1104 int stdout_pipe[2], stderr_pipe[2];
1105 pid_t child_pid;
1106 struct termios termios_flags;
1107 gchar * const *env;
1109 /* The pipes */
1110 pipe (stderr_pipe);
1111 pipe (stdout_pipe);
1113 /* Fork the command */
1114 child_pid = forkpty (&pty_master_fd, NULL, NULL, NULL);
1115 if (child_pid == 0)
1117 close (2);
1118 dup (stderr_pipe[1]);
1119 close (1);
1120 dup (stdout_pipe[1]);
1122 /* Close unnecessary pipes */
1123 close (stderr_pipe[0]);
1124 close (stdout_pipe[0]);
1127 if ((ioctl(pty_slave_fd, TIOCSCTTY, NULL))
1128 perror ("Could not set new controlling tty");
1130 /* Set no delays for the write pipes (non_buffered) so
1131 that we get all the outputs immidiately */
1132 if ((md = fcntl (stdout_pipe[1], F_GETFL)) != -1)
1133 fcntl (stdout_pipe[1], F_SETFL, O_SYNC | md);
1134 if ((md = fcntl (stderr_pipe[1], F_GETFL)) != -1)
1135 fcntl (stderr_pipe[1], F_SETFL, O_SYNC | md);
1137 /* Set working directory */
1138 if (dir != NULL)
1140 /* Exit if working directory doesn't exist */
1141 if (chdir (dir) != 0) _exit(-1);
1144 /* Set up environment */
1145 if (envp != NULL)
1147 GString *variable = g_string_new (NULL);
1148 for (env = envp; *env != NULL; env++)
1150 gchar *value = strchr (*env, '=');
1152 if (value == NULL)
1154 g_setenv (*env, NULL, TRUE);
1156 else
1158 g_string_truncate (variable, 0);
1159 g_string_append_len (variable, *env, value - *env);
1160 g_setenv (variable->str, value + 1, TRUE);
1163 g_string_free (variable, TRUE);
1166 execvp (args[0], args);
1167 g_warning (_("Cannot execute command: \"%s\""), args[0]);
1168 perror(_("execvp failed"));
1169 _exit(-1);
1172 /* Close parent's side pipes */
1173 close (stderr_pipe[1]);
1174 close (stdout_pipe[1]);
1176 if (child_pid < 0)
1178 g_warning ("launcher.c: Fork failed!");
1179 /* Close parent's side pipes */
1180 close (stderr_pipe[0]);
1181 close (stdout_pipe[0]);
1182 return child_pid;
1186 * Set pipes none blocking, so we can read big buffers
1187 * in the callback without having to use FIONREAD
1188 * to make sure the callback doesn't block.
1190 if ((md = fcntl (stdout_pipe[0], F_GETFL)) != -1)
1191 fcntl (stdout_pipe[0], F_SETFL, O_NONBLOCK | md);
1192 if ((md = fcntl (stderr_pipe[0], F_GETFL)) != -1)
1193 fcntl (stderr_pipe[0], F_SETFL, O_NONBLOCK | md);
1194 if ((md = fcntl (pty_master_fd, F_GETFL)) != -1)
1195 fcntl (pty_master_fd, F_SETFL, O_NONBLOCK | md);
1197 launcher->priv->child_pid = child_pid;
1198 launcher->priv->stderr_channel = g_io_channel_unix_new (stderr_pipe[0]);
1199 launcher->priv->stdout_channel = g_io_channel_unix_new (stdout_pipe[0]);
1200 launcher->priv->pty_channel = g_io_channel_unix_new (pty_master_fd);
1202 g_io_channel_set_buffer_size (launcher->priv->pty_channel, FILE_INPUT_BUFFER_SIZE);
1204 if (!launcher->priv->custom_encoding)
1205 g_get_charset ((const gchar**)&launcher->priv->encoding);
1206 anjuta_launcher_set_encoding_real (launcher, launcher->priv->encoding);
1208 tcgetattr(pty_master_fd, &termios_flags);
1209 termios_flags.c_iflag &= ~(IGNPAR | INPCK | INLCR | IGNCR | ICRNL | IXON |
1210 IXOFF | ISTRIP);
1211 termios_flags.c_iflag |= IGNBRK | BRKINT | IMAXBEL | IXANY;
1212 termios_flags.c_oflag &= ~OPOST;
1213 // termios_flags.c_oflag |= 0;
1214 termios_flags.c_cflag &= ~(CSTOPB | PARENB | HUPCL);
1215 termios_flags.c_cflag |= CS8 | CLOCAL;
1217 if (!launcher->priv->terminal_echo_on)
1219 termios_flags.c_lflag &= ~(ECHOKE | ECHOE | ECHO | ECHONL |
1220 #ifdef ECHOPRT
1221 ECHOPRT |
1222 #endif
1223 ECHOCTL | ISIG | ICANON | IEXTEN | NOFLSH | TOSTOP);
1225 // termios_flags.c_lflag |= 0;
1226 termios_flags.c_cc[VMIN] = 0;
1227 cfsetospeed(&termios_flags, __MAX_BAUD);
1228 tcsetattr(pty_master_fd, TCSANOW, &termios_flags);
1230 launcher->priv->stderr_watch =
1231 g_io_add_watch (launcher->priv->stderr_channel,
1232 G_IO_IN | G_IO_ERR | G_IO_HUP,
1233 (GIOFunc)anjuta_launcher_scan_error, launcher);
1234 launcher->priv->stdout_watch =
1235 g_io_add_watch (launcher->priv->stdout_channel,
1236 G_IO_IN | G_IO_ERR | G_IO_HUP,
1237 (GIOFunc)anjuta_launcher_scan_output, launcher);
1238 launcher->priv->pty_watch =
1239 g_io_add_watch (launcher->priv->pty_channel,
1240 G_IO_IN | G_IO_ERR, /* Do not hook up for G_IO_HUP */
1241 (GIOFunc)anjuta_launcher_scan_pty, launcher);
1243 /* DEBUG_PRINT ("Terminal child forked: %d", launcher->priv->child_pid); */
1244 launcher->priv->source = g_child_watch_add (launcher->priv->child_pid,
1245 anjuta_launcher_child_terminated, launcher);
1246 return child_pid;
1250 * anjuta_launcher_execute_v:
1251 * @launcher: a #AnjutaLancher object.
1252 * @dir: Working directory or %NULL.
1253 * @argv: Command args.
1254 * @envp: Additional environment variable.
1255 * @callback: The callback for delivering output from the process.
1256 * @callback_data: Callback data for the above callback.
1258 * The first of the @args is the command itself. The rest are sent to the
1259 * as it's arguments. This function works similar to anjuta_launcher_execute().
1261 * Return value: %TRUE if successfully launched, otherwise %FALSE.
1263 gboolean
1264 anjuta_launcher_execute_v (AnjutaLauncher *launcher, gchar *const dir,
1265 gchar *const argv[],
1266 gchar *const envp[],
1267 AnjutaLauncherOutputCallback callback,
1268 gpointer callback_data)
1270 if (anjuta_launcher_is_busy (launcher))
1271 return FALSE;
1273 anjuta_launcher_set_busy (launcher, TRUE);
1275 launcher->priv->start_time = time (NULL);
1276 launcher->priv->child_status = 0;
1277 launcher->priv->stdout_is_done = FALSE;
1278 launcher->priv->stderr_is_done = FALSE;
1279 launcher->priv->child_has_terminated = FALSE;
1280 launcher->priv->output_callback = callback;
1281 launcher->priv->callback_data = callback_data;
1283 /* On a fork error perform a cleanup and return */
1284 if (anjuta_launcher_fork (launcher, dir, argv, envp) < 0)
1286 anjuta_launcher_initialize (launcher);
1287 return FALSE;
1289 return TRUE;
1293 * anjuta_launcher_execute:
1294 * @launcher: a #AnjutaLancher object.
1295 * @command_str: The command to execute.
1296 * @callback: The callback for delivering output from the process.
1297 * @callback_data: Callback data for the above callback.
1299 * Executes a command in the launcher. Both outputs (STDOUT and STDERR) are
1300 * delivered to the above callback. The data are delivered as they arrive
1301 * from the process and could be of any lenght. If the process asks for
1302 * passwords, the user will be automatically prompted with a dialog to enter
1303 * it. Please note that not all formats of the password are recognized. Those
1304 * with the standard 'assword:' substring in the prompt should work well.
1306 * Return value: %TRUE if successfully launched, otherwise %FALSE.
1308 gboolean
1309 anjuta_launcher_execute (AnjutaLauncher *launcher, const gchar *command_str,
1310 AnjutaLauncherOutputCallback callback,
1311 gpointer callback_data)
1313 GList *args_list, *args_list_ptr;
1314 gchar **args, **args_ptr;
1315 gboolean ret;
1317 /* Prepare command args */
1318 args_list = anjuta_util_parse_args_from_string (command_str);
1319 args = g_new (char*, g_list_length (args_list) + 1);
1320 args_list_ptr = args_list;
1321 args_ptr = args;
1322 while (args_list_ptr)
1324 *args_ptr = (char*) args_list_ptr->data;
1325 args_list_ptr = g_list_next (args_list_ptr);
1326 args_ptr++;
1328 *args_ptr = NULL;
1330 ret = anjuta_launcher_execute_v (launcher, NULL, args, NULL,
1331 callback, callback_data);
1332 g_free (args);
1333 anjuta_util_glist_strings_free (args_list);
1334 return ret;
1338 * anjuta_launcher_set_buffered_output:
1339 * @launcher: a #AnjutaLancher object.
1340 * @buffered: buffer output.
1342 * Sets if output should buffered or not. By default, it is buffered.
1344 * Return value: Previous flag value
1346 gboolean
1347 anjuta_launcher_set_buffered_output (AnjutaLauncher *launcher, gboolean buffered)
1349 gboolean past_value = launcher->priv->buffered_output;
1350 launcher->priv->buffered_output = buffered;
1351 return past_value;
1355 * anjuta_launcher_set_check_passwd_prompt:
1356 * @launcher: a #AnjutaLancher object.
1357 * @check_passwd: check for password.
1359 * Set if output is checked for a password prompti. A special dialog box
1360 * is use to enter it in this case. By default, this behavior is enabled.
1362 * Return value: Previous flag value
1364 gboolean
1365 anjuta_launcher_set_check_passwd_prompt (AnjutaLauncher *launcher, gboolean check_passwd)
1367 gboolean past_value = launcher->priv->check_for_passwd_prompt;
1368 launcher->priv->check_for_passwd_prompt = check_passwd;
1369 return past_value;
1373 * anjuta_launcher_set_terminal_echo:
1374 * @launcher: a #AnjutaLancher object.
1375 * @echo_on: Echo ON flag.
1377 * Sets if input (those given in STDIN) should enabled or disabled. By default,
1378 * it is disabled.
1380 * Return value: Previous flag value
1382 gboolean
1383 anjuta_launcher_set_terminal_echo (AnjutaLauncher *launcher,
1384 gboolean echo_on)
1386 gboolean past_value = launcher->priv->terminal_echo_on;
1387 launcher->priv->terminal_echo_on = echo_on;
1388 return past_value;
1392 * anjuta_launcher_set_terminate_on_exit:
1393 * @launcher: a #AnjutaLancher object.
1394 * @terminate_on_exit: terminate on exit flag
1396 * When this flag is set, al i/o channels are closed and the child-exit
1397 * signal is emitted as soon as the child exit. By default, or when this
1398 * flag is clear, the launcher object wait until the i/o channels are
1399 * closed.
1401 * Return value: Previous flag value
1403 gboolean
1404 anjuta_launcher_set_terminate_on_exit (AnjutaLauncher *launcher,
1405 gboolean terminate_on_exit)
1407 gboolean past_value = launcher->priv->terminate_on_exit;
1408 launcher->priv->terminate_on_exit = terminate_on_exit;
1409 return past_value;
1413 * anjuta_launcher_new:
1415 * Sets if input (those given in STDIN) should enabled or disabled. By default,
1416 * it is disabled.
1418 * Return value: a new instance of #AnjutaLancher class.
1420 AnjutaLauncher*
1421 anjuta_launcher_new ()
1423 return g_object_new (ANJUTA_TYPE_LAUNCHER, NULL);