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>
5  *
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.
10  *
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.
15  *
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.
19  */
20 
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
27  *
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #  include <config.h>
32 #endif
33 
34 #include <errno.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 
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
50 
51 #include "anjuta-utils-priv.h"
52 
53 #include <assert.h>
54 #include <termios.h>
55 
56 #include <string.h>
57 #include <time.h>
58 #include <glib/gi18n.h>
59 #include <glib.h>
60 
61 #include "anjuta-utils.h"
62 #include "anjuta-marshal.h"
63 #include "resources.h"
64 #include "anjuta-launcher.h"
65 #include "anjuta-debug.h"
66 
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
81 
82 /*
83 static gboolean
84 anjuta_launcher_pty_check_child_exit_code (AnjutaLauncher *launcher,
85 										   const gchar* line);
86 */
87 struct _AnjutaLauncherPriv
88 {
89 	/*
90 	*  Busy flag is TRUE if the Launcher
91 	*  is currently executing a child.
92 	*/
93 	gboolean busy;
94 
95 	/* These flags are used to synchronize the IO operations. */
96 	gboolean stdout_is_done;
97 	gboolean stderr_is_done;
98 
99 	/* GIO channels */
100 	GIOChannel *stdout_channel;
101 	GIOChannel *stderr_channel;
102 	/*GIOChannel *stdin_channel;*/
103 	GIOChannel *pty_channel;
104 
105 	/* GIO watch handles */
106 	guint stdout_watch;
107 	guint stderr_watch;
108 	guint pty_watch;
109 
110 	/* Output line buffers */
111 	gchar *stdout_buffer;
112 	gchar *stderr_buffer;
113 
114 	/* Output of the pty is constantly stored here.*/
115 	gchar *pty_output_buffer;
116 
117 	/* Terminal echo */
118 	gboolean terminal_echo_on;
119 
120 	/* The child */
121 	pid_t child_pid;
122 	guint source;
123 	gint child_status;
124 	gboolean child_has_terminated;
125 
126 	/* Synchronization in progress */
127 	guint completion_check_timeout;
128 
129 	/* Terminate child on child exit */
130 	gboolean terminate_on_exit;
131 
132 	/* Start time of execution */
133 	time_t start_time;
134 
135 	/* Should the outputs be buffered */
136 	gboolean buffered_output;
137 
138 	/* Should we check for password prompts in stdout and pty */
139 	gboolean check_for_passwd_prompt;
140 
141 	/* Output callback */
142 	AnjutaLauncherOutputCallback output_callback;
143 
144 	/* Callback data */
145 	gpointer callback_data;
146 
147 	/* Encondig */
148 	gboolean custom_encoding;
149 	gchar* encoding;
150 
151 	/* Env */
152 	GHashTable* env;
153 };
154 
155 enum
156 {
157 	/* OUTPUT_ARRIVED_SIGNAL, */
158 	CHILD_EXITED_SIGNAL,
159 	BUSY_SIGNAL,
160 	LAST_SIGNAL
161 };
162 
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);
169 
170 static gboolean is_password_prompt(const gchar* line);
171 
172 static guint launcher_signals[LAST_SIGNAL] = { 0 };
173 static AnjutaLauncherClass *parent_class;
174 
175 static void
anjuta_launcher_initialize(AnjutaLauncher * obj)176 anjuta_launcher_initialize (AnjutaLauncher *obj)
177 {
178 	/* Busy flag */
179 	obj->priv->busy = FALSE;
180 
181 	/* These flags are used to synchronize the IO operations. */
182 	obj->priv->stdout_is_done = FALSE;
183 	obj->priv->stderr_is_done = FALSE;
184 
185 	/* GIO channels */
186 	obj->priv->stdout_channel = NULL;
187 	obj->priv->stderr_channel = NULL;
188 	obj->priv->pty_channel = NULL;
189 
190 	/* Output line buffers */
191 	obj->priv->stdout_buffer = NULL;
192 	obj->priv->stderr_buffer = NULL;
193 
194 	/* Pty buffer */
195 	obj->priv->pty_output_buffer = NULL;
196 
197 	obj->priv->terminal_echo_on = TRUE;
198 
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;
204 
205 	/* Synchronization in progress */
206 	obj->priv->completion_check_timeout = 0;
207 
208 	/* Terminate child on child exit */
209 	obj->priv->terminate_on_exit = FALSE;
210 
211 	/* Start time of execution */
212 	obj->priv->start_time = 0;
213 
214 	obj->priv->buffered_output = TRUE;
215 	obj->priv->check_for_passwd_prompt = TRUE;
216 
217 	/* Output callback */
218 	obj->priv->output_callback = NULL;
219 	obj->priv->callback_data = NULL;
220 
221 	/* Encoding */
222 	obj->priv->custom_encoding = FALSE;
223 	obj->priv->encoding = NULL;
224 
225 	/* Env */
226 	obj->priv->env = g_hash_table_new_full (g_str_hash, g_str_equal,
227 											g_free, g_free);
228 }
229 
230 GType
anjuta_launcher_get_type()231 anjuta_launcher_get_type ()
232 {
233 	static GType obj_type = 0;
234 
235 	if (!obj_type)
236 	{
237 		static const GTypeInfo obj_info =
238 		{
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 */
249 		};
250 		obj_type = g_type_register_static (G_TYPE_OBJECT,
251 		                                   "AnjutaLauncher", &obj_info, 0);
252 	}
253 	return obj_type;
254 }
255 
256 static void
anjuta_launcher_dispose(GObject * obj)257 anjuta_launcher_dispose (GObject *obj)
258 {
259 	AnjutaLauncher *launcher = ANJUTA_LAUNCHER (obj);
260 	if (anjuta_launcher_is_busy (launcher))
261 	{
262 		g_source_remove (launcher->priv->source);
263 		launcher->priv->source = 0;
264 
265 		anjuta_launcher_execution_done_cleanup (launcher, FALSE);
266 
267 		launcher->priv->busy = FALSE;
268 
269 	}
270 	G_OBJECT_CLASS (parent_class)->dispose (obj);
271 }
272 
273 static void
anjuta_launcher_finalize(GObject * obj)274 anjuta_launcher_finalize (GObject *obj)
275 {
276 	AnjutaLauncher *launcher = ANJUTA_LAUNCHER (obj);
277 	if (launcher->priv->custom_encoding && launcher->priv->encoding)
278 		g_free (launcher->priv->encoding);
279 
280 	g_hash_table_destroy (launcher->priv->env);
281 
282 	g_free (launcher->priv);
283 	G_OBJECT_CLASS (parent_class)->finalize (obj);
284 }
285 
286 static void
anjuta_launcher_class_init(AnjutaLauncherClass * klass)287 anjuta_launcher_class_init (AnjutaLauncherClass * klass)
288 {
289 	GObjectClass *object_class;
290 	g_return_if_fail (klass != NULL);
291 	object_class = (GObjectClass *) klass;
292 
293 	/* DEBUG_PRINT ("%s", "Initializing launcher class"); */
294 
295 	parent_class = g_type_class_peek_parent (klass);
296 
297 	/**
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
303 	 *
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.
309 	 **/
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);
320 
321 	/**
322 	 * AnjutaLauncher::busy:
323  	 * @launcher: a #AnjutaLancher object.
324 	 * @busy: %TRUE is a child is currently running
325 	 *
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).
329 	 **/
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);
339 
340 	object_class->dispose = anjuta_launcher_dispose;
341 	object_class->finalize = anjuta_launcher_finalize;
342 }
343 
344 static void
anjuta_launcher_init(AnjutaLauncher * obj)345 anjuta_launcher_init (AnjutaLauncher * obj)
346 {
347 	g_return_if_fail (obj != NULL);
348 	obj->priv = g_new0 (AnjutaLauncherPriv, 1);
349 	anjuta_launcher_initialize (obj);
350 }
351 
352 /**
353  * anjuta_launcher_is_busy:
354  * @launcher: a #AnjutaLancher object.
355  *
356  * Tells if the laucher is currently executing any command.
357  *
358  * Return value: %TRUE if launcher is busy, otherwise %FALSE.
359  */
360 gboolean
anjuta_launcher_is_busy(AnjutaLauncher * launcher)361 anjuta_launcher_is_busy (AnjutaLauncher *launcher)
362 {
363 	return launcher->priv->busy;
364 }
365 
366 static void
anjuta_launcher_set_busy(AnjutaLauncher * launcher,gboolean flag)367 anjuta_launcher_set_busy (AnjutaLauncher *launcher, gboolean flag)
368 {
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);
373 }
374 
375 /**
376  * anjuta_launcher_send_stdin:
377  * @launcher: a #AnjutaLancher object.
378  * @input_str: The string to send to STDIN of the process.
379  *
380  * Sends a string to Standard input of the process currently being executed.
381  */
382 void
anjuta_launcher_send_stdin(AnjutaLauncher * launcher,const gchar * input_str)383 anjuta_launcher_send_stdin (AnjutaLauncher *launcher, const gchar * input_str)
384 {
385 	g_return_if_fail (launcher);
386 	g_return_if_fail (input_str);
387 
388 	anjuta_launcher_send_ptyin (launcher, input_str);
389 }
390 
391 /**
392  * anjuta_launcher_send_stdin_eof:
393  * @launcher: a #AnjutaLancher object.
394  *
395  * Sends a EOF to Standard input of the process currently being executed.
396  */
397 
398 void
anjuta_launcher_send_stdin_eof(AnjutaLauncher * launcher)399 anjuta_launcher_send_stdin_eof (AnjutaLauncher *launcher)
400 {
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;
406 
407 	if (err)
408 	{
409 		g_warning ("g_io_channel_shutdown () failed: %s", err->message);
410 	}
411 }
412 
413 /**
414  * anjuta_launcher_send_ptyin:
415  * @launcher: a #AnjutaLancher object.
416  * @input_str: The string to send to PTY of the process.
417  *
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.
421  */
422 void
anjuta_launcher_send_ptyin(AnjutaLauncher * launcher,const gchar * input_str)423 anjuta_launcher_send_ptyin (AnjutaLauncher *launcher, const gchar * input_str)
424 {
425 	gsize bytes_written = 0;
426 	GError *err = NULL;
427 
428 	g_return_if_fail (launcher);
429 	g_return_if_fail (input_str);
430 	g_return_if_fail (launcher->priv->pty_channel != NULL);
431 
432 	if (strlen (input_str) == 0)
433 		return;
434 
435 	do
436 	{
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)
442 		{
443 			g_warning ("Error encountered while writing to PTY!. %s",
444 					   err->message);
445 			g_error_free (err);
446 
447 			return;
448 		}
449 		input_str += bytes_written;
450 	}
451 	while (*input_str);
452 }
453 
454 /**
455  * anjuta_launcher_reset:
456  * @launcher: a #AnjutaLancher object.
457  *
458  * Resets the launcher and kills (SIGTERM) current process, if it is still
459  * executing.
460  */
461 void
anjuta_launcher_reset(AnjutaLauncher * launcher)462 anjuta_launcher_reset (AnjutaLauncher *launcher)
463 {
464 	if (anjuta_launcher_is_busy (launcher) &&
465 	    launcher->priv->child_pid)
466 		kill (launcher->priv->child_pid, SIGTERM);
467 }
468 
469 /**
470  * anjuta_launcher_signal:
471  * @launcher: a #AnjutaLancher object.
472  * @sig: kernel signal ID (e.g. SIGTERM).
473  *
474  * Sends a kernel signal to the process that is being executed.
475  */
476 void
anjuta_launcher_signal(AnjutaLauncher * launcher,int sig)477 anjuta_launcher_signal (AnjutaLauncher *launcher, int sig)
478 {
479 	if (launcher->priv->child_pid)
480 		kill (launcher->priv->child_pid, sig);
481 }
482 
483 /**
484  * anjuta_launcher_get_child_pid:
485  * @launcher: a #AnjutaLancher object.
486  *
487  * Gets the Process ID of the child being executed.
488  *
489  * Return value: Process ID of the child.
490  */
491 pid_t
anjuta_launcher_get_child_pid(AnjutaLauncher * launcher)492 anjuta_launcher_get_child_pid (AnjutaLauncher *launcher)
493 {
494   if (anjuta_launcher_is_busy (launcher))
495     return launcher->priv->child_pid;
496   else
497     return -1;
498 }
499 
500 static void
anjuta_launcher_synchronize(AnjutaLauncher * launcher)501 anjuta_launcher_synchronize (AnjutaLauncher *launcher)
502 {
503 	if (launcher->priv->child_has_terminated &&
504 		launcher->priv->stdout_is_done &&
505 		launcher->priv->stderr_is_done)
506 	{
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);
513 	}
514 
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)
519 	{
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);
527 	}
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)
532 	{
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);
539 	}
540 }
541 
542 /* Password dialog */
543 static GtkWidget*
create_password_dialog(const gchar * prompt)544 create_password_dialog (const gchar* prompt)
545 {
546 	GtkWidget *dialog;
547 	GtkWidget *hbox;
548 	GtkWidget *box;
549 	GtkWidget *icon;
550 	GtkWidget *label;
551 	GtkWidget *entry;
552 
553 	g_return_val_if_fail (prompt, NULL);
554 
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);
562 
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);
568 
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);
572 
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);
577 	}
578 	gtk_widget_show (box);
579 	gtk_box_pack_start (GTK_BOX (hbox), box, TRUE, TRUE, 0);
580 
581 	label = gtk_label_new (_(prompt));
582 	gtk_widget_show (label);
583 	gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
584 
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);
589 
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);
596 
597 	return dialog;
598 }
599 
600 /* pty buffer check for password authentication */
601 static void
anjuta_launcher_check_password_real(AnjutaLauncher * launcher,const gchar * last_line)602 anjuta_launcher_check_password_real (AnjutaLauncher *launcher,
603 									 const gchar* last_line)
604 {
605 	if (anjuta_launcher_is_busy (launcher) == FALSE)
606 		return;
607 
608 	if (last_line) {
609 
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;
617 
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;
634 			}
635 			gtk_widget_destroy (dialog);
636 		}
637 	}
638 }
639 
640 static void
anjuta_launcher_check_password(AnjutaLauncher * launcher,const gchar * chars)641 anjuta_launcher_check_password (AnjutaLauncher *launcher, const gchar *chars)
642 {
643 	glong start, end;
644 	gchar *last_line;
645 
646 	if (!chars || strlen(chars) <= 0)
647 		return;
648 
649 	/* DEBUG_PRINT ("Chars buffer = %s", chars); */
650 	start = end = strlen (chars);
651 	while (start > 0 && chars[start-1] != '\n') start--;
652 
653 	if (end > start)
654 	{
655 		last_line = g_strndup (&chars[start], end - start + 1);
656 
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);
661 	}
662 }
663 
664 static gboolean
is_password_prompt(const gchar * line)665 is_password_prompt (const gchar* line)
666 {
667 	const gchar* regex = "[Pp]assword.*:";
668 	/*
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
674 	 */
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;
680 
681 	return FALSE;
682 }
683 
684 static void
anjuta_launcher_buffered_output(AnjutaLauncher * launcher,AnjutaLauncherOutputType output_type,const gchar * chars)685 anjuta_launcher_buffered_output (AnjutaLauncher *launcher,
686 								 AnjutaLauncherOutputType output_type,
687 								 const gchar *chars)
688 {
689 	gchar *all_lines;
690 	gchar *incomplete_line;
691 	gchar **buffer;
692 
693 	g_return_if_fail (chars != NULL);
694 	g_return_if_fail (strlen (chars) > 0);
695 
696 	if (launcher->priv->output_callback == NULL)
697 		return;
698 	if (launcher->priv->buffered_output == FALSE)
699 	{
700 		(launcher->priv->output_callback)(launcher, output_type, chars,
701 										  launcher->priv->callback_data);
702 		return;
703 	}
704 	switch (output_type)
705 	{
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;
715 	}
716 	if (*buffer)
717 		all_lines = g_strconcat (*buffer, chars, NULL);
718 	else
719 		all_lines = g_strdup (chars);
720 
721 	/* Buffer the last incomplete line */
722 	incomplete_line = all_lines + strlen (all_lines);
723 	while (incomplete_line > all_lines &&
724 		   *incomplete_line != '\n')
725 	{
726 		incomplete_line = g_utf8_prev_char (incomplete_line);
727 	}
728 	if (*incomplete_line == '\n')
729 		incomplete_line++;
730 
731 	/* Update line buffer */
732 	g_free(*buffer);
733 	*buffer = NULL;
734 	if (strlen(incomplete_line))
735 	{
736 		*buffer = g_strdup (incomplete_line);
737 		/* DEBUG_PRINT ("Line buffer for %d: %s", output_type, incomplete_line); */
738 	}
739 	/* Check for password prompt */
740 	if (launcher->priv->check_for_passwd_prompt)
741 		anjuta_launcher_check_password (launcher, incomplete_line);
742 
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);
749 }
750 
751 static gboolean
anjuta_launcher_scan_output(GIOChannel * channel,GIOCondition condition,AnjutaLauncher * launcher)752 anjuta_launcher_scan_output (GIOChannel *channel, GIOCondition condition,
753 							 AnjutaLauncher *launcher)
754 {
755 	gsize n;
756 	gchar buffer[FILE_BUFFER_SIZE];
757 	gboolean ret = TRUE;
758 
759 	if (condition & G_IO_IN)
760 	{
761 		GError *err = NULL;
762 		do
763 		{
764 			GIOStatus status;
765 			status = g_io_channel_read_chars (channel, buffer, FILE_BUFFER_SIZE-1, &n, &err);
766 			if (n > 0) /* There is output */
767 			{
768 				gchar *utf8_chars = NULL;
769 				buffer[n] = '\0';
770 				if (!launcher->priv->custom_encoding)
771 					utf8_chars = anjuta_util_convert_to_utf8 (buffer);
772 				else
773 					utf8_chars = g_strdup(buffer);
774 				anjuta_launcher_buffered_output (launcher,
775 												 ANJUTA_LAUNCHER_OUTPUT_STDOUT,
776 												 utf8_chars);
777 				g_free (utf8_chars);
778 			}
779 			/* Ignore illegal characters */
780 			if (err && err->domain == G_CONVERT_ERROR)
781 			{
782 				g_error_free (err);
783 				err = NULL;
784 			}
785 			/* The pipe is closed on the other side */
786 			/* if not related to non blocking read or interrupted syscall */
787 			else if (err && errno != EAGAIN && errno != EINTR)
788 			{
789 				launcher->priv->stdout_is_done = TRUE;
790 				anjuta_launcher_synchronize (launcher);
791 				ret = FALSE;
792 			}
793 			else if (status == G_IO_STATUS_EOF)
794 			{
795 				launcher->priv->stdout_is_done = TRUE;
796 				anjuta_launcher_synchronize (launcher);
797 				if (err)
798 					g_error_free (err);
799 				return FALSE;
800 			}
801 		/* Read next chars if buffer was too small
802 		 * (the maximum length of one character is 6 bytes) */
803 		} while (!err && (n > FILE_BUFFER_SIZE - 7));
804 		if (err)
805 			g_error_free (err);
806 	}
807 	if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
808 	{
809 		DEBUG_PRINT ("%s", "launcher.c: STDOUT pipe closed");
810 		launcher->priv->stdout_is_done = TRUE;
811 		anjuta_launcher_synchronize (launcher);
812 		ret = FALSE;
813 	}
814 	return ret;
815 }
816 
817 static gboolean
anjuta_launcher_scan_error(GIOChannel * channel,GIOCondition condition,AnjutaLauncher * launcher)818 anjuta_launcher_scan_error (GIOChannel *channel, GIOCondition condition,
819 							AnjutaLauncher *launcher)
820 {
821 	gsize n;
822 	gchar buffer[FILE_BUFFER_SIZE];
823 	gboolean ret = TRUE;
824 
825 	if (condition & G_IO_IN)
826 	{
827 		GError *err = NULL;
828 		do
829 		{
830 			GIOStatus status;
831 			status = g_io_channel_read_chars (channel, buffer, FILE_BUFFER_SIZE-1, &n, &err);
832 			if (n > 0) /* There is stderr output */
833 			{
834 				gchar *utf8_chars;
835 				buffer[n] = '\0';
836 				utf8_chars = anjuta_util_convert_to_utf8 (buffer);
837 				anjuta_launcher_buffered_output (launcher,
838 												 ANJUTA_LAUNCHER_OUTPUT_STDERR,
839 												 utf8_chars);
840 				g_free (utf8_chars);
841 			}
842 			/* Ignore illegal characters */
843 			if (err && err->domain == G_CONVERT_ERROR)
844 			{
845 				g_error_free (err);
846 				err = NULL;
847 			}
848 			/* The pipe is closed on the other side */
849 			/* if not related to non blocking read or interrupted syscall */
850 			else if (err && errno != EAGAIN && errno != EINTR)
851 			{
852 
853 				launcher->priv->stderr_is_done = TRUE;
854 				anjuta_launcher_synchronize (launcher);
855 				ret = FALSE;
856 			}
857 			else if (status == G_IO_STATUS_EOF)
858 			{
859 				launcher->priv->stderr_is_done = TRUE;
860 				anjuta_launcher_synchronize (launcher);
861 				if (err)
862 					g_error_free (err);
863 				return FALSE;
864 			}
865 		/* Read next chars if buffer was too small
866 		 * (the maximum length of one character is 6 bytes) */
867 		} while (!err && (n > FILE_BUFFER_SIZE - 7));
868 		if (err)
869 			g_error_free (err);
870 	}
871 	if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
872 	{
873 		DEBUG_PRINT ("%s", "launcher.c: STDERR pipe closed");
874 		launcher->priv->stderr_is_done = TRUE;
875 		anjuta_launcher_synchronize (launcher);
876 		ret = FALSE;
877 	}
878 	return ret;
879 }
880 
881 static gboolean
anjuta_launcher_scan_pty(GIOChannel * channel,GIOCondition condition,AnjutaLauncher * launcher)882 anjuta_launcher_scan_pty (GIOChannel *channel, GIOCondition condition,
883 						  AnjutaLauncher *launcher)
884 {
885 	gsize n;
886 	gchar buffer[FILE_BUFFER_SIZE];
887 	gboolean ret = TRUE;
888 
889 	if (condition & G_IO_IN)
890 	{
891 		GError *err = NULL;
892 		do
893 		{
894 			GIOStatus status;
895 			status = g_io_channel_read_chars (channel, buffer, FILE_BUFFER_SIZE-1, &n, &err);
896 			if (n > 0) /* There is stderr output */
897 			{
898 				gchar *utf8_chars;
899 				gchar *old_str = launcher->priv->pty_output_buffer;
900 				buffer[n] = '\0';
901 				utf8_chars = anjuta_util_convert_to_utf8 (buffer);
902 				if (old_str)
903 				{
904 					gchar *str = g_strconcat (old_str, utf8_chars, NULL);
905 					launcher->priv->pty_output_buffer = str;
906 					g_free (old_str);
907 				}
908 				else
909 					launcher->priv->pty_output_buffer = g_strdup (utf8_chars);
910 				g_free (utf8_chars);
911 			}
912 			/* Ignore illegal characters */
913 			if (err && err->domain == G_CONVERT_ERROR)
914 			{
915 				g_error_free (err);
916 				err = NULL;
917 			}
918 			/* The pipe is closed on the other side */
919 			/* if not related to non blocking read or interrupted syscall */
920 			else if (err && errno != EAGAIN && errno != EINTR)
921 			{
922 				ret = FALSE;
923 			}
924 			else if (status == G_IO_STATUS_EOF)
925 			{
926 				ret = FALSE;
927 				break;
928 			}
929 		/* Read next chars if buffer was too small
930 		 * (the maximum length of one character is 6 bytes) */
931 		} while (!err && (n > FILE_BUFFER_SIZE - 7));
932 		if (err)
933 			g_error_free (err);
934 		if (launcher->priv->check_for_passwd_prompt
935 			&& launcher->priv->pty_output_buffer
936 			&& strlen (launcher->priv->pty_output_buffer) > 0)
937 		{
938 			anjuta_launcher_check_password (launcher,
939 											launcher->priv->pty_output_buffer);
940 		}
941 	}
942 	/* In pty case, we handle the cases in different invocations */
943 	/* Do not hook up for G_IO_HUP */
944 	if (condition & G_IO_ERR)
945 	{
946 		DEBUG_PRINT ("%s", "launcher.c: PTY pipe error!");
947 		ret = FALSE;
948 	}
949 	return ret;
950 }
951 
952 static void
anjuta_launcher_execution_done_cleanup(AnjutaLauncher * launcher,gboolean emit_signal)953 anjuta_launcher_execution_done_cleanup (AnjutaLauncher *launcher,
954 										gboolean emit_signal)
955 {
956 	gint child_status, child_pid;
957 	time_t start_time;
958 
959 	/* Remove pending timeout */
960 	if (launcher->priv->completion_check_timeout != 0)
961 		g_source_remove (launcher->priv->completion_check_timeout);
962 
963 	if (launcher->priv->stdout_channel)
964 	{
965 		g_io_channel_shutdown (launcher->priv->stdout_channel, emit_signal, NULL);
966 		g_io_channel_unref (launcher->priv->stdout_channel);
967 		if (!launcher->priv->stdout_is_done)
968 			g_source_remove (launcher->priv->stdout_watch);
969 	}
970 
971 	if (launcher->priv->stderr_channel)
972 	{
973 		g_io_channel_shutdown (launcher->priv->stderr_channel, emit_signal, NULL);
974 		g_io_channel_unref (launcher->priv->stderr_channel);
975 		if (!launcher->priv->stderr_is_done)
976 			g_source_remove (launcher->priv->stderr_watch);
977 	}
978 
979 	if (launcher->priv->pty_channel)
980 	{
981 		g_io_channel_shutdown (launcher->priv->pty_channel, emit_signal, NULL);
982 		g_io_channel_unref (launcher->priv->pty_channel);
983 
984 		g_source_remove (launcher->priv->pty_watch);
985 	}
986 
987 	if (launcher->priv->pty_output_buffer)
988 		g_free (launcher->priv->pty_output_buffer);
989 	if (launcher->priv->stdout_buffer)
990 	{
991 		/* Send remaining data if last line is not terminated with EOL */
992 		(launcher->priv->output_callback)(launcher,
993 			       ANJUTA_LAUNCHER_OUTPUT_STDOUT,
994 			       launcher->priv->stdout_buffer,
995 			       launcher->priv->callback_data);
996 		g_free (launcher->priv->stdout_buffer);
997 	}
998 	if (launcher->priv->stderr_buffer)
999 	{
1000 		/* Send remaining data if last line is not terminated with EOL */
1001 		(launcher->priv->output_callback)(launcher,
1002 			       ANJUTA_LAUNCHER_OUTPUT_STDERR,
1003 			       launcher->priv->stderr_buffer,
1004 			       launcher->priv->callback_data);
1005 		g_free (launcher->priv->stdout_buffer);
1006 	}
1007 
1008 	/* Save them before we re-initialize */
1009 	child_status = launcher->priv->child_status;
1010 	child_pid = launcher->priv->child_pid;
1011 	start_time = launcher->priv->start_time;
1012 
1013 	if (emit_signal)
1014 		anjuta_launcher_set_busy (launcher, FALSE);
1015 
1016 	anjuta_launcher_initialize (launcher);
1017 
1018 
1019 	/* Call this here, after set_busy (FALSE) so we are able to
1020 	   launch a new child from the terminate function.
1021 	   (by clubfan 2002-04-07)
1022 	*/
1023 	/* DEBUG_PRINT ("Exit status: %d", child_status); */
1024 	if (emit_signal)
1025 		g_signal_emit_by_name (launcher, "child-exited", child_pid,
1026 							   child_status,
1027 							   time (NULL) - start_time);
1028 }
1029 
1030 /* Using this function is necessary because
1031  * anjuta_launcher_execution_done_cleanup needs to be called in the same
1032  * thread than the gtk main loop */
1033 static gboolean
anjuta_launcher_call_execution_done(gpointer data)1034 anjuta_launcher_call_execution_done (gpointer data)
1035 {
1036 	AnjutaLauncher *launcher = data;
1037 
1038 	launcher->priv->completion_check_timeout = 0;
1039 	anjuta_launcher_execution_done_cleanup (launcher, TRUE);
1040 	return FALSE;
1041 }
1042 
1043 /* monitors closure of stdout stderr and pty through a gtk_timeout_add setup */
1044 static gboolean
anjuta_launcher_check_for_execution_done(gpointer data)1045 anjuta_launcher_check_for_execution_done (gpointer data)
1046 {
1047 	AnjutaLauncher *launcher = data;
1048 	/*
1049 	DEBUG_PRINT ("launcher_execution_done STDOUT:%d, STDERR:%d",
1050 				 launcher->priv->stdout_is_done ? 1 : 0,
1051 				 launcher->priv->stderr_is_done ? 1 : 0);
1052 	*/
1053 	if (launcher->priv->stdout_is_done == FALSE ||
1054 	    launcher->priv->stderr_is_done == FALSE)
1055 		return TRUE;
1056 	if (launcher->priv->child_has_terminated == FALSE)
1057 	{
1058 		/* DEBUG_PRINT ("%s", "launcher: We missed the exit of the child"); */
1059 	}
1060 	launcher->priv->completion_check_timeout = 0;
1061 	anjuta_launcher_execution_done_cleanup (launcher, TRUE);
1062 	return FALSE;
1063 }
1064 
1065 static void
anjuta_launcher_child_terminated(GPid pid,gint status,gpointer data)1066 anjuta_launcher_child_terminated (GPid pid, gint status, gpointer data)
1067 {
1068 	AnjutaLauncher *launcher = data;
1069 
1070 	g_return_if_fail(ANJUTA_IS_LAUNCHER(launcher));
1071 
1072 	/* Save child exit code */
1073 	launcher->priv->child_status = status;
1074 	launcher->priv->child_has_terminated = TRUE;
1075 	anjuta_launcher_synchronize (launcher);
1076 }
1077 
1078 
1079 static gboolean
anjuta_launcher_set_encoding_real(AnjutaLauncher * launcher,const gchar * charset)1080 anjuta_launcher_set_encoding_real (AnjutaLauncher *launcher, const gchar *charset)
1081 {
1082 	GIOStatus s;
1083 	gboolean r = TRUE;
1084 
1085 	g_return_val_if_fail (launcher != NULL, FALSE);
1086 	// charset can be NULL
1087 
1088 	s = g_io_channel_set_encoding (launcher->priv->stderr_channel, charset, NULL);
1089 	if (s != G_IO_STATUS_NORMAL) r = FALSE;
1090 	s = g_io_channel_set_encoding (launcher->priv->stdout_channel, charset, NULL);
1091 	if (s != G_IO_STATUS_NORMAL) r = FALSE;
1092 	s = g_io_channel_set_encoding (launcher->priv->pty_channel, charset, NULL);
1093 	if (s != G_IO_STATUS_NORMAL) r = FALSE;
1094 
1095 	if (! r)
1096 	{
1097 		g_warning ("launcher.c: Failed to set channel encoding!");
1098 	}
1099 	return r;
1100 }
1101 
1102 
1103 /**
1104  * anjuta_launcher_set_encoding:
1105  * @launcher: a #AnjutaLancher object.
1106  * @charset: Character set to use for Input/Output with the process.
1107  *
1108  * Sets the character set to use for Input/Output with the process.
1109  *
1110  */
1111 void
anjuta_launcher_set_encoding(AnjutaLauncher * launcher,const gchar * charset)1112 anjuta_launcher_set_encoding (AnjutaLauncher *launcher, const gchar *charset)
1113 {
1114 	if (launcher->priv->custom_encoding)
1115 		g_free (launcher->priv->encoding);
1116 
1117 	launcher->priv->custom_encoding = TRUE;
1118 	if (charset)
1119 	  launcher->priv->encoding = g_strdup(charset);
1120 	else
1121 	  launcher->priv->encoding = NULL;
1122 }
1123 
1124 static pid_t
anjuta_launcher_fork(AnjutaLauncher * launcher,const gchar * dir,gchar * const args[],gchar * const envp[])1125 anjuta_launcher_fork (AnjutaLauncher *launcher, const gchar *dir, gchar *const args[], gchar *const envp[])
1126 {
1127 	int pty_master_fd, md;
1128 	int stdout_pipe[2], stderr_pipe[2];
1129 	pid_t child_pid;
1130 	struct termios termios_flags;
1131 	gchar * const *env;
1132 
1133 	/* The pipes */
1134 	pipe (stderr_pipe);
1135 	pipe (stdout_pipe);
1136 
1137 	/* Fork the command */
1138 	child_pid = forkpty (&pty_master_fd, NULL, NULL, NULL);
1139 	if (child_pid == 0)
1140 	{
1141 		close (2);
1142 		dup (stderr_pipe[1]);
1143 		close (1);
1144 		dup (stdout_pipe[1]);
1145 
1146 		/* Close unnecessary pipes */
1147 		close (stderr_pipe[0]);
1148 		close (stdout_pipe[0]);
1149 
1150 		/*
1151 		if ((ioctl(pty_slave_fd, TIOCSCTTY, NULL))
1152 			perror ("Could not set new controlling tty");
1153 		*/
1154 		/* Set no delays for the write pipes (non_buffered) so
1155 		that we get all the outputs immidiately */
1156 		if ((md = fcntl (stdout_pipe[1], F_GETFL)) != -1)
1157 			fcntl (stdout_pipe[1], F_SETFL, O_SYNC | md);
1158 		if ((md = fcntl (stderr_pipe[1], F_GETFL)) != -1)
1159 			fcntl (stderr_pipe[1], F_SETFL, O_SYNC | md);
1160 
1161 		/* Set working directory */
1162 		if (dir != NULL)
1163 		{
1164 			/* Exit if working directory doesn't exist */
1165 			if (chdir (dir) != 0) _exit(-1);
1166 		}
1167 
1168 		/* Set up environment */
1169 		if (envp != NULL)
1170 		{
1171 			GString *variable = g_string_new (NULL);
1172 			for (env = envp; *env != NULL; env++)
1173 			{
1174 				gchar *value = strchr (*env, '=');
1175 
1176 				if (value == NULL)
1177 				{
1178 					g_setenv (*env, NULL, TRUE);
1179 				}
1180 				else
1181 				{
1182 					g_string_truncate (variable, 0);
1183 					g_string_append_len (variable, *env, value - *env);
1184 					g_setenv (variable->str, value + 1, TRUE);
1185 				}
1186 			}
1187 			g_string_free (variable, TRUE);
1188 		}
1189 
1190 		execvp (args[0], args);
1191 		g_warning (_("Cannot execute command: \"%s\""), args[0]);
1192 		perror(_("execvp failed"));
1193 		_exit(-1);
1194 	}
1195 
1196 	/* Close parent's side pipes */
1197 	close (stderr_pipe[1]);
1198 	close (stdout_pipe[1]);
1199 
1200 	if (child_pid < 0)
1201 	{
1202 		g_warning ("launcher.c: Fork failed!");
1203 		/* Close parent's side pipes */
1204 		close (stderr_pipe[0]);
1205 		close (stdout_pipe[0]);
1206 		return child_pid;
1207 	}
1208 
1209 	/*
1210 	*  Set pipes none blocking, so we can read big buffers
1211 	*  in the callback without having to use FIONREAD
1212 	*  to make sure the callback doesn't block.
1213 	*/
1214 	if ((md = fcntl (stdout_pipe[0], F_GETFL)) != -1)
1215 		fcntl (stdout_pipe[0], F_SETFL, O_NONBLOCK | md);
1216 	if ((md = fcntl (stderr_pipe[0], F_GETFL)) != -1)
1217 		fcntl (stderr_pipe[0], F_SETFL, O_NONBLOCK | md);
1218 	if ((md = fcntl (pty_master_fd, F_GETFL)) != -1)
1219 		fcntl (pty_master_fd, F_SETFL, O_NONBLOCK | md);
1220 
1221 	launcher->priv->child_pid = child_pid;
1222 	launcher->priv->stderr_channel = g_io_channel_unix_new (stderr_pipe[0]);
1223 	launcher->priv->stdout_channel = g_io_channel_unix_new (stdout_pipe[0]);
1224 	launcher->priv->pty_channel = g_io_channel_unix_new (pty_master_fd);
1225 
1226 	g_io_channel_set_buffer_size (launcher->priv->pty_channel, FILE_INPUT_BUFFER_SIZE);
1227 
1228 	if (!launcher->priv->custom_encoding)
1229 	  g_get_charset ((const gchar**)&launcher->priv->encoding);
1230 	anjuta_launcher_set_encoding_real (launcher, launcher->priv->encoding);
1231 
1232 	tcgetattr(pty_master_fd, &termios_flags);
1233 	termios_flags.c_iflag &= ~(IGNPAR | INPCK | INLCR | IGNCR | ICRNL | IXON |
1234 					IXOFF | ISTRIP);
1235 	termios_flags.c_iflag |= IGNBRK | BRKINT | IMAXBEL | IXANY;
1236 	termios_flags.c_oflag &= ~OPOST;
1237 //	termios_flags.c_oflag |= 0;
1238 	termios_flags.c_cflag &= ~(CSTOPB | PARENB | HUPCL);
1239 	termios_flags.c_cflag |= CS8 | CLOCAL;
1240 
1241 	if (!launcher->priv->terminal_echo_on)
1242 	{
1243 		termios_flags.c_lflag &= ~(ECHOKE | ECHOE | ECHO | ECHONL |
1244 #ifdef ECHOPRT
1245 						ECHOPRT |
1246 #endif
1247 						ECHOCTL | ISIG | ICANON | IEXTEN | NOFLSH | TOSTOP);
1248 	}
1249 //	termios_flags.c_lflag |= 0;
1250 	termios_flags.c_cc[VMIN] = 0;
1251 	cfsetospeed(&termios_flags, __MAX_BAUD);
1252 	tcsetattr(pty_master_fd, TCSANOW, &termios_flags);
1253 
1254 	launcher->priv->stderr_watch =
1255 		g_io_add_watch (launcher->priv->stderr_channel,
1256 						G_IO_IN | G_IO_ERR | G_IO_HUP,
1257 						(GIOFunc)anjuta_launcher_scan_error, launcher);
1258 	launcher->priv->stdout_watch =
1259 		g_io_add_watch (launcher->priv->stdout_channel,
1260 						G_IO_IN | G_IO_ERR | G_IO_HUP,
1261 						(GIOFunc)anjuta_launcher_scan_output, launcher);
1262 	launcher->priv->pty_watch =
1263 		g_io_add_watch (launcher->priv->pty_channel,
1264 						G_IO_IN | G_IO_ERR, /* Do not hook up for G_IO_HUP */
1265 						(GIOFunc)anjuta_launcher_scan_pty, launcher);
1266 
1267 	/* DEBUG_PRINT ("Terminal child forked: %d", launcher->priv->child_pid); */
1268 	launcher->priv->source = g_child_watch_add (launcher->priv->child_pid,
1269 			anjuta_launcher_child_terminated, launcher);
1270 	return child_pid;
1271 }
1272 
1273 /**
1274  * anjuta_launcher_execute_v:
1275  * @launcher: a #AnjutaLancher object.
1276  * @dir: Working directory or %NULL.
1277  * @argv: Command args.
1278  * @envp: Additional environment variable.
1279  * @callback: The callback for delivering output from the process.
1280  * @callback_data: Callback data for the above callback.
1281  *
1282  * The first of the @args is the command itself. The rest are sent to the
1283  * as it's arguments. This function works similar to anjuta_launcher_execute().
1284  *
1285  * Return value: %TRUE if successfully launched, otherwise %FALSE.
1286  */
1287 gboolean
anjuta_launcher_execute_v(AnjutaLauncher * launcher,gchar * const dir,gchar * const argv[],gchar * const envp[],AnjutaLauncherOutputCallback callback,gpointer callback_data)1288 anjuta_launcher_execute_v (AnjutaLauncher *launcher, gchar *const dir,
1289 	       	gchar *const argv[],
1290 	       	gchar *const envp[],
1291 	       	AnjutaLauncherOutputCallback callback,
1292 	       	gpointer callback_data)
1293 {
1294 	if (anjuta_launcher_is_busy (launcher))
1295 		return FALSE;
1296 
1297 	anjuta_launcher_set_busy (launcher, TRUE);
1298 
1299 	launcher->priv->start_time = time (NULL);
1300 	launcher->priv->child_status = 0;
1301 	launcher->priv->stdout_is_done = FALSE;
1302 	launcher->priv->stderr_is_done = FALSE;
1303 	launcher->priv->child_has_terminated = FALSE;
1304 	launcher->priv->output_callback = callback;
1305 	launcher->priv->callback_data = callback_data;
1306 
1307 	/* On a fork error perform a cleanup and return */
1308 	if (anjuta_launcher_fork (launcher, dir, argv, envp) < 0)
1309 	{
1310 		anjuta_launcher_initialize (launcher);
1311 		return FALSE;
1312 	}
1313 	return TRUE;
1314 }
1315 
1316 /**
1317  * anjuta_launcher_execute:
1318  * @launcher: a #AnjutaLancher object.
1319  * @command_str: The command to execute.
1320  * @callback: The callback for delivering output from the process.
1321  * @callback_data: Callback data for the above callback.
1322  *
1323  * Executes a command in the launcher. Both outputs (STDOUT and STDERR) are
1324  * delivered to the above callback. The data are delivered as they arrive
1325  * from the process and could be of any lenght. If the process asks for
1326  * passwords, the user will be automatically prompted with a dialog to enter
1327  * it. Please note that not all formats of the password are recognized. Those
1328  * with the standard 'assword:' substring in the prompt should work well.
1329  *
1330  * Return value: %TRUE if successfully launched, otherwise %FALSE.
1331  */
1332 gboolean
anjuta_launcher_execute(AnjutaLauncher * launcher,const gchar * command_str,AnjutaLauncherOutputCallback callback,gpointer callback_data)1333 anjuta_launcher_execute (AnjutaLauncher *launcher, const gchar *command_str,
1334 						 AnjutaLauncherOutputCallback callback,
1335 						 gpointer callback_data)
1336 {
1337 	GList *args_list, *args_list_ptr;
1338 	gchar **args, **args_ptr;
1339 	gboolean ret;
1340 
1341 	/* Prepare command args */
1342 	args_list = anjuta_util_parse_args_from_string (command_str);
1343 	args = g_new (char*, g_list_length (args_list) + 1);
1344 	args_list_ptr = args_list;
1345 	args_ptr = args;
1346 	while (args_list_ptr)
1347 	{
1348 		*args_ptr = (char*) args_list_ptr->data;
1349 		args_list_ptr = g_list_next (args_list_ptr);
1350 		args_ptr++;
1351 	}
1352 	*args_ptr = NULL;
1353 
1354 	ret = anjuta_launcher_execute_v (launcher, NULL, args, NULL,
1355 		callback, callback_data);
1356 	g_free (args);
1357 	anjuta_util_glist_strings_free (args_list);
1358 	return ret;
1359 }
1360 
1361 /**
1362  * anjuta_launcher_set_buffered_output:
1363  * @launcher: a #AnjutaLancher object.
1364  * @buffered: buffer output.
1365  *
1366  * Sets if output should buffered or not. By default, it is buffered.
1367  *
1368  * Return value: Previous flag value
1369  */
1370 gboolean
anjuta_launcher_set_buffered_output(AnjutaLauncher * launcher,gboolean buffered)1371 anjuta_launcher_set_buffered_output (AnjutaLauncher *launcher, gboolean buffered)
1372 {
1373 	gboolean past_value = launcher->priv->buffered_output;
1374 	launcher->priv->buffered_output = buffered;
1375 	return past_value;
1376 }
1377 
1378 /**
1379  * anjuta_launcher_set_check_passwd_prompt:
1380  * @launcher: a #AnjutaLancher object.
1381  * @check_passwd: check for password.
1382  *
1383  * Set if output is checked for a password prompti. A special dialog box
1384  * is use to enter it in this case. By default, this behavior is enabled.
1385  *
1386  * Return value: Previous flag value
1387  */
1388 gboolean
anjuta_launcher_set_check_passwd_prompt(AnjutaLauncher * launcher,gboolean check_passwd)1389 anjuta_launcher_set_check_passwd_prompt (AnjutaLauncher *launcher, gboolean check_passwd)
1390 {
1391 	gboolean past_value = launcher->priv->check_for_passwd_prompt;
1392 	launcher->priv->check_for_passwd_prompt = check_passwd;
1393 	return past_value;
1394 }
1395 
1396 /**
1397  * anjuta_launcher_set_terminal_echo:
1398  * @launcher: a #AnjutaLancher object.
1399  * @echo_on: Echo ON flag.
1400  *
1401  * Sets if input (those given in STDIN) should enabled or disabled. By default,
1402  * it is disabled.
1403  *
1404  * Return value: Previous flag value
1405  */
1406 gboolean
anjuta_launcher_set_terminal_echo(AnjutaLauncher * launcher,gboolean echo_on)1407 anjuta_launcher_set_terminal_echo (AnjutaLauncher *launcher,
1408 								   gboolean echo_on)
1409 {
1410 	gboolean past_value = launcher->priv->terminal_echo_on;
1411 	launcher->priv->terminal_echo_on = echo_on;
1412 	return past_value;
1413 }
1414 
1415 /**
1416  * anjuta_launcher_set_terminate_on_exit:
1417  * @launcher: a #AnjutaLancher object.
1418  * @terminate_on_exit: terminate on exit flag
1419  *
1420  * When this flag is set, al i/o channels are closed and the child-exit
1421  * signal is emitted as soon as the child exit. By default, or when this
1422  * flag is clear, the launcher object wait until the i/o channels are
1423  * closed.
1424  *
1425  * Return value: Previous flag value
1426  */
1427 gboolean
anjuta_launcher_set_terminate_on_exit(AnjutaLauncher * launcher,gboolean terminate_on_exit)1428 anjuta_launcher_set_terminate_on_exit (AnjutaLauncher *launcher,
1429 						gboolean terminate_on_exit)
1430 {
1431 	gboolean past_value = launcher->priv->terminate_on_exit;
1432 	launcher->priv->terminate_on_exit = terminate_on_exit;
1433 	return past_value;
1434 }
1435 
1436 /**
1437  * anjuta_launcher_new:
1438  *
1439  * Sets if input (those given in STDIN) should enabled or disabled. By default,
1440  * it is disabled.
1441  *
1442  * Return value: a new instance of #AnjutaLancher class.
1443  */
1444 AnjutaLauncher*
anjuta_launcher_new()1445 anjuta_launcher_new ()
1446 {
1447 	return g_object_new (ANJUTA_TYPE_LAUNCHER, NULL);
1448 }
1449