This source file includes following definitions.
- write_all
- init_subshell_child
- init_raw_mode
- synchronize
- read_command_line_buffer
- clear_subshell_prompt_string
- parse_subshell_prompt_string
- set_prompt_string
- feed_subshell
- pty_open_master
- pty_open_slave
- pty_open_master
- pty_open_slave
- init_subshell_precmd
- subshell_name_quote
- clear_cwd_pipe
- init_subshell
- invoke_subshell
- flush_subshell
- read_subshell_prompt
- do_update_prompt
- exit_subshell
- do_subshell_chdir
- subshell_get_console_attributes
- sigchld_handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 #include <config.h>
56
57 #ifndef _GNU_SOURCE
58 #define _GNU_SOURCE 1
59 #endif
60
61 #include <ctype.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <errno.h>
65 #include <string.h>
66 #include <signal.h>
67 #ifdef HAVE_SYS_SELECT_H
68 #include <sys/select.h>
69 #else
70 #include <sys/time.h>
71 #include <unistd.h>
72 #endif
73 #include <sys/types.h>
74 #include <sys/wait.h>
75 #ifdef HAVE_SYS_IOCTL_H
76 #include <sys/ioctl.h>
77 #endif
78 #include <termios.h>
79
80 #ifdef HAVE_STROPTS_H
81 #include <stropts.h>
82 #endif
83
84 #ifdef HAVE_OPENPTY
85
86 #ifdef HAVE_PTY_H
87 #include <pty.h>
88 #endif
89 #ifdef HAVE_UTIL_H
90 #include <util.h>
91 #endif
92
93 #ifdef HAVE_LIBUTIL_H
94 #include <libutil.h>
95 #endif
96 #endif
97
98 #include "lib/global.h"
99
100 #include "lib/fileloc.h"
101 #include "lib/unixcompat.h"
102 #include "lib/tty/tty.h"
103 #include "lib/tty/key.h"
104 #include "lib/vfs/vfs.h"
105 #include "lib/strutil.h"
106 #include "lib/mcconfig.h"
107 #include "lib/util.h"
108 #include "lib/widget.h"
109
110 #include "src/filemanager/layout.h"
111 #include "src/filemanager/command.h"
112
113 #include "subshell.h"
114 #include "internal.h"
115
116
117
118
119
120
121
122 enum subshell_state_enum subshell_state;
123
124
125 GString *subshell_prompt = NULL;
126
127
128
129 gboolean update_subshell_prompt = FALSE;
130
131
132
133 gboolean should_read_new_subshell_prompt;
134
135
136
137 #ifndef WEXITSTATUS
138 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
139 #endif
140
141 #ifndef WIFEXITED
142 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
143 #endif
144
145
146 #define INITIAL_PROMPT_SIZE 10
147
148
149 #define FORK_FAILURE 69
150
151
152 #define PTY_BUFFER_SIZE BUF_SMALL
153
154
155
156
157 enum
158 {
159 READ = 0,
160 WRITE = 1
161 };
162
163
164
165 #define SHELL_BUFFER_KEYBINDING "_"
166
167
168
169 #define SHELL_CURSOR_KEYBINDING "+"
170
171
172
173
174 static char tcsh_fifo[128];
175
176 static int subshell_pty_slave = -1;
177
178
179
180 static const char subshell_switch_key = XCTRL ('o') & 255;
181
182
183
184 static char pty_buffer[PTY_BUFFER_SIZE] = "\0";
185
186
187 static int subshell_pipe[2];
188
189
190 static int command_buffer_pipe[2];
191
192
193 static pid_t subshell_pid = 1;
194
195
196 static char subshell_cwd[MC_MAXPATHLEN + 1];
197
198
199 static int subshell_ready;
200
201
202 static gboolean use_persistent_buffer = FALSE;
203
204
205 static GString *subshell_prompt_temp_buffer = NULL;
206
207
208
209 static volatile int subshell_alive, subshell_stopped;
210
211
212
213
214 static struct termios shell_mode;
215
216
217
218
219 static struct termios raw_mode;
220
221
222
223
224
225
226
227
228 static ssize_t
229 write_all (int fd, const void *buf, size_t count)
230 {
231 ssize_t written = 0;
232
233 while (count > 0)
234 {
235 ssize_t ret;
236
237 ret = write (fd, (const unsigned char *) buf + written, count);
238 if (ret < 0)
239 {
240 if (errno == EINTR)
241 {
242 if (tty_got_winch ())
243 tty_change_screen_size ();
244
245 continue;
246 }
247
248 return written > 0 ? written : ret;
249 }
250 count -= ret;
251 written += ret;
252 }
253 return written;
254 }
255
256
257
258
259
260
261
262
263
264
265
266 static void
267 init_subshell_child (const char *pty_name)
268 {
269 char *init_file = NULL;
270 pid_t mc_sid;
271
272 (void) pty_name;
273 setsid ();
274
275
276
277
278
279 #ifdef TIOCSCTTY
280 ioctl (subshell_pty_slave, TIOCSCTTY, 0);
281 #endif
282
283
284
285
286 if (tcsetattr (subshell_pty_slave, TCSANOW, &shell_mode))
287 {
288 fprintf (stderr, "Cannot set pty terminal modes: %s\r\n", unix_error_string (errno));
289 my_exit (FORK_FAILURE);
290 }
291
292
293
294 tty_resize (subshell_pty_slave);
295
296
297
298
299
300 {
301 int ret;
302
303 ret = chdir (mc_config_get_home_dir ());
304 (void) ret;
305 }
306
307
308 mc_sid = getsid (0);
309 if (mc_sid != -1)
310 {
311 char sid_str[BUF_SMALL];
312
313 g_snprintf (sid_str, sizeof (sid_str), "MC_SID=%ld", (long) mc_sid);
314 putenv (g_strdup (sid_str));
315 }
316
317 switch (mc_global.shell->type)
318 {
319 case SHELL_BASH:
320
321 init_file = mc_config_get_full_path (MC_BASHRC_FILE);
322
323
324 if (!exist_file (init_file))
325 {
326 g_free (init_file);
327 init_file = g_strdup (".bashrc");
328 }
329
330
331
332 putenv ((char *) "HISTCONTROL=ignoreboth");
333
334
335 {
336 char *input_file;
337
338 input_file = mc_config_get_full_path (MC_INPUTRC_FILE);
339 if (exist_file (input_file))
340 g_setenv ("INPUTRC", input_file, TRUE);
341 g_free (input_file);
342 }
343
344 break;
345
346 case SHELL_ASH_BUSYBOX:
347 case SHELL_DASH:
348
349 init_file = mc_config_get_full_path (MC_ASHRC_FILE);
350
351
352 if (!exist_file (init_file))
353 {
354 g_free (init_file);
355 init_file = g_strdup (".profile");
356 }
357
358
359 g_setenv ("ENV", init_file, TRUE);
360
361 break;
362
363 case SHELL_ZSH:
364
365
366
367
368 if (g_getenv ("ZDOTDIR") != NULL)
369 {
370
371
372 init_file = mc_config_get_full_path (MC_ZSHRC_FILE);
373 if (exist_file (init_file))
374 {
375
376 g_setenv ("ZDOTDIR", mc_config_get_data_path (), TRUE);
377 }
378 }
379 break;
380
381
382 case SHELL_TCSH:
383 case SHELL_FISH:
384 break;
385
386 default:
387 fprintf (stderr, __FILE__ ": unimplemented subshell type %u\r\n", mc_global.shell->type);
388 my_exit (FORK_FAILURE);
389 }
390
391
392
393
394
395
396
397 dup2 (subshell_pty_slave, STDIN_FILENO);
398 dup2 (subshell_pty_slave, STDOUT_FILENO);
399 dup2 (subshell_pty_slave, STDERR_FILENO);
400
401 close (subshell_pipe[READ]);
402
403 if (use_persistent_buffer)
404 close (command_buffer_pipe[READ]);
405
406 close (subshell_pty_slave);
407
408
409
410
411
412 close (mc_global.tty.subshell_pty);
413
414
415
416 switch (mc_global.shell->type)
417 {
418 case SHELL_BASH:
419 execl (mc_global.shell->path, "bash", "-rcfile", init_file, (char *) NULL);
420 break;
421
422 case SHELL_ZSH:
423
424
425 execl (mc_global.shell->path, "zsh", "-Z", "-g", (char *) NULL);
426 break;
427
428 case SHELL_ASH_BUSYBOX:
429 case SHELL_DASH:
430 case SHELL_TCSH:
431 case SHELL_FISH:
432 execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL);
433 break;
434
435 default:
436 break;
437 }
438
439
440 g_free (init_file);
441 my_exit (FORK_FAILURE);
442 }
443
444
445
446 static void
447 init_raw_mode (void)
448 {
449 static gboolean initialized = FALSE;
450
451
452
453
454
455
456
457 if (!initialized)
458 {
459 tcgetattr (STDOUT_FILENO, &raw_mode);
460 raw_mode.c_lflag &= ~ICANON;
461 raw_mode.c_lflag &= ~ISIG;
462 raw_mode.c_lflag &= ~ECHO;
463 raw_mode.c_iflag &= ~IXON;
464 raw_mode.c_iflag &= ~ICRNL;
465 raw_mode.c_oflag &= ~OPOST;
466 raw_mode.c_cc[VTIME] = 0;
467 raw_mode.c_cc[VMIN] = 1;
468 initialized = TRUE;
469 }
470 }
471
472
473
474
475
476
477
478 static void
479 synchronize (void)
480 {
481 sigset_t sigchld_mask, old_mask;
482
483 sigemptyset (&sigchld_mask);
484 sigaddset (&sigchld_mask, SIGCHLD);
485 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
486
487
488
489
490
491 sigdelset (&old_mask, SIGCHLD);
492
493
494 while (subshell_alive && !subshell_stopped)
495 sigsuspend (&old_mask);
496
497 if (subshell_state != ACTIVE)
498 {
499
500 tcflush (subshell_pty_slave, TCIFLUSH);
501 }
502
503 subshell_stopped = FALSE;
504 kill (subshell_pid, SIGCONT);
505
506 sigprocmask (SIG_SETMASK, &old_mask, NULL);
507
508 }
509
510
511
512
513
514 static gboolean
515 read_command_line_buffer (gboolean test_mode)
516 {
517 char subshell_command_buffer[BUF_LARGE];
518 char subshell_cursor_buffer[BUF_SMALL];
519
520 fd_set read_set;
521 int i;
522 ssize_t bytes;
523 struct timeval subshell_prompt_timer = { 0, 0 };
524 int command_buffer_length;
525 int command_buffer_char_length;
526 int bash_version;
527 int cursor_position;
528 int maxfdp;
529 int rc;
530
531 if (!use_persistent_buffer)
532 return TRUE;
533
534 FD_ZERO (&read_set);
535 FD_SET (command_buffer_pipe[READ], &read_set);
536 maxfdp = command_buffer_pipe[READ];
537
538
539
540
541
542 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0)
543 {
544 if (rc == -1)
545 {
546 if (errno == EINTR)
547 continue;
548
549 return FALSE;
550 }
551
552 if (rc == 1)
553 {
554 bytes = read (command_buffer_pipe[READ], subshell_command_buffer,
555 sizeof (subshell_command_buffer));
556 (void) bytes;
557 }
558 }
559
560
561 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING,
562 sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
563
564 subshell_prompt_timer.tv_sec = 1;
565 FD_ZERO (&read_set);
566 FD_SET (command_buffer_pipe[READ], &read_set);
567
568 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1)
569 {
570 if (rc == -1)
571 {
572 if (errno == EINTR)
573 continue;
574
575 return FALSE;
576 }
577
578 if (rc == 0)
579 return FALSE;
580 }
581
582 bytes =
583 read (command_buffer_pipe[READ], subshell_command_buffer, sizeof (subshell_command_buffer));
584 if (bytes == 0 || bytes == sizeof (subshell_command_buffer))
585 return FALSE;
586
587 command_buffer_char_length = bytes - 1;
588 subshell_command_buffer[command_buffer_char_length] = '\0';
589 command_buffer_length = str_length (subshell_command_buffer);
590
591
592 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING,
593 sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
594
595 subshell_prompt_timer.tv_sec = 1;
596 subshell_prompt_timer.tv_usec = 0;
597 FD_ZERO (&read_set);
598 FD_SET (command_buffer_pipe[READ], &read_set);
599
600 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1)
601 {
602 if (rc == -1)
603 {
604 if (errno == EINTR)
605 continue;
606
607 return FALSE;
608 }
609
610 if (rc == 0)
611 return FALSE;
612 }
613
614 bytes =
615 read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof (subshell_cursor_buffer));
616 if (bytes == 0)
617 return FALSE;
618
619 subshell_cursor_buffer[bytes - 1] = '\0';
620 if (mc_global.shell->type == SHELL_BASH)
621 {
622 if (sscanf (subshell_cursor_buffer, "%d:%d", &bash_version, &cursor_position) != 2)
623 return FALSE;
624 }
625 else
626 {
627 if (sscanf (subshell_cursor_buffer, "%d", &cursor_position) != 1)
628 return FALSE;
629 bash_version = 1000;
630 }
631
632 if (test_mode)
633 return TRUE;
634
635
636
637 for (i = 0; i < command_buffer_char_length; i++)
638 if ((unsigned char) subshell_command_buffer[i] < 32
639 || (unsigned char) subshell_command_buffer[i] == 127)
640 subshell_command_buffer[i] = ' ';
641
642 input_assign_text (cmdline, "");
643 input_insert (cmdline, subshell_command_buffer, FALSE);
644
645 if (bash_version < 5)
646 {
647
648
649 char *curr, *stop;
650
651 curr = subshell_command_buffer;
652 stop = curr + cursor_position;
653
654 for (cursor_position = 0; curr < stop; cursor_position++)
655 str_next_char_safe (&curr);
656 }
657 if (cursor_position > command_buffer_length)
658 cursor_position = command_buffer_length;
659 cmdline->point = cursor_position;
660
661 flush_subshell (0, VISIBLY);
662
663
664 if (mc_global.shell->type != SHELL_ZSH)
665 {
666
667
668
669
670 if (cursor_position != command_buffer_length)
671 {
672 write_all (mc_global.tty.subshell_pty, "\005", 1);
673 if (flush_subshell (1, VISIBLY) != 1)
674 return FALSE;
675 }
676 }
677
678 if (command_buffer_length > 0)
679 {
680
681 write_all (mc_global.tty.subshell_pty, "\025", 1);
682 if (flush_subshell (1, VISIBLY) != 1)
683 return FALSE;
684 }
685
686 return TRUE;
687 }
688
689
690
691 static void
692 clear_subshell_prompt_string (void)
693 {
694 if (subshell_prompt_temp_buffer != NULL)
695 g_string_set_size (subshell_prompt_temp_buffer, 0);
696 }
697
698
699
700 static void
701 parse_subshell_prompt_string (const char *buffer, int bytes)
702 {
703 int i;
704
705 if (mc_global.mc_run_mode != MC_RUN_FULL)
706 return;
707
708
709 if (subshell_prompt == NULL)
710 subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE);
711 if (subshell_prompt_temp_buffer == NULL)
712 subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE);
713
714
715 for (i = 0; i < bytes; i++)
716 if (buffer[i] == '\n' || buffer[i] == '\r')
717 g_string_set_size (subshell_prompt_temp_buffer, 0);
718 else if (buffer[i] != '\0')
719 g_string_append_c (subshell_prompt_temp_buffer, buffer[i]);
720 }
721
722
723
724 static void
725 set_prompt_string (void)
726 {
727 if (mc_global.mc_run_mode != MC_RUN_FULL)
728 return;
729
730 if (subshell_prompt_temp_buffer->len != 0)
731 mc_g_string_copy (subshell_prompt, subshell_prompt_temp_buffer);
732
733 setup_cmdline ();
734 }
735
736
737
738
739 static gboolean
740 feed_subshell (int how, gboolean fail_on_error)
741 {
742 fd_set read_set;
743 int bytes;
744 int i;
745
746 struct timeval wtime;
747 struct timeval *wptr;
748
749 should_read_new_subshell_prompt = FALSE;
750
751
752 wtime.tv_sec = 1;
753 wtime.tv_usec = 0;
754 wptr = fail_on_error ? &wtime : NULL;
755
756 while (TRUE)
757 {
758 int maxfdp;
759
760 if (!subshell_alive)
761 return FALSE;
762
763
764
765 FD_ZERO (&read_set);
766 FD_SET (mc_global.tty.subshell_pty, &read_set);
767 FD_SET (subshell_pipe[READ], &read_set);
768 maxfdp = MAX (mc_global.tty.subshell_pty, subshell_pipe[READ]);
769 if (how == VISIBLY)
770 {
771 FD_SET (STDIN_FILENO, &read_set);
772 maxfdp = MAX (maxfdp, STDIN_FILENO);
773 }
774
775 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1)
776 {
777
778 if (errno == EINTR)
779 {
780 if (tty_got_winch ())
781 tty_change_screen_size ();
782
783 continue;
784 }
785 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
786 fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
787 unix_error_string (errno));
788 exit (EXIT_FAILURE);
789 }
790
791 if (FD_ISSET (mc_global.tty.subshell_pty, &read_set))
792
793
794
795
796
797
798 {
799 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
800
801
802 if (bytes == -1 && errno == EIO && !subshell_alive)
803 return FALSE;
804
805 if (bytes <= 0)
806 {
807 #ifdef PTY_ZEROREAD
808
809 continue;
810 #else
811 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
812 fprintf (stderr, "read (subshell_pty...): %s\r\n", unix_error_string (errno));
813 exit (EXIT_FAILURE);
814 #endif
815 }
816
817 if (how == VISIBLY)
818 write_all (STDOUT_FILENO, pty_buffer, bytes);
819
820 if (should_read_new_subshell_prompt)
821 parse_subshell_prompt_string (pty_buffer, bytes);
822 }
823
824 else if (FD_ISSET (subshell_pipe[READ], &read_set))
825
826 {
827 bytes = read (subshell_pipe[READ], subshell_cwd, sizeof (subshell_cwd));
828 if (bytes <= 0)
829 {
830 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
831 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
832 unix_error_string (errno));
833 exit (EXIT_FAILURE);
834 }
835
836 subshell_cwd[bytes - 1] = '\0';
837
838 synchronize ();
839
840 clear_subshell_prompt_string ();
841 should_read_new_subshell_prompt = TRUE;
842 subshell_ready = TRUE;
843 if (subshell_state == RUNNING_COMMAND)
844 {
845 subshell_state = INACTIVE;
846 return TRUE;
847 }
848 }
849
850 else if (FD_ISSET (STDIN_FILENO, &read_set))
851
852 {
853 should_read_new_subshell_prompt = FALSE;
854 bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer));
855 if (bytes <= 0)
856 {
857 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
858 fprintf (stderr,
859 "read (STDIN_FILENO, pty_buffer...): %s\r\n", unix_error_string (errno));
860 exit (EXIT_FAILURE);
861 }
862
863 for (i = 0; i < bytes; ++i)
864 if (pty_buffer[i] == subshell_switch_key)
865 {
866 write_all (mc_global.tty.subshell_pty, pty_buffer, i);
867
868 if (subshell_ready)
869 {
870 subshell_state = INACTIVE;
871 set_prompt_string ();
872 if (subshell_ready && !read_command_line_buffer (FALSE))
873 {
874
875 if (mc_global.shell->type != SHELL_FISH)
876 {
877 write_all (mc_global.tty.subshell_pty, "\003", 1);
878 subshell_state = RUNNING_COMMAND;
879 if (feed_subshell (QUIETLY, TRUE))
880 if (read_command_line_buffer (FALSE))
881 return TRUE;
882 }
883 subshell_state = ACTIVE;
884 flush_subshell (0, VISIBLY);
885 input_assign_text (cmdline, "");
886 }
887 }
888
889 return TRUE;
890 }
891
892 write_all (mc_global.tty.subshell_pty, pty_buffer, bytes);
893
894 if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r')
895 {
896
897
898 if (use_persistent_buffer)
899 input_assign_text (cmdline, "");
900 subshell_ready = FALSE;
901 }
902 }
903 else
904 return FALSE;
905 }
906 }
907
908
909
910
911 #ifndef HAVE_OPENPTY
912
913 #ifdef HAVE_GRANTPT
914
915
916
917 static int
918 pty_open_master (char *pty_name)
919 {
920 char *slave_name;
921 int pty_master;
922
923 #ifdef HAVE_POSIX_OPENPT
924 pty_master = posix_openpt (O_RDWR);
925 #elif defined HAVE_GETPT
926
927 pty_master = getpt ();
928 #elif defined IS_AIX
929 strcpy (pty_name, "/dev/ptc");
930 pty_master = open (pty_name, O_RDWR);
931 #else
932 strcpy (pty_name, "/dev/ptmx");
933 pty_master = open (pty_name, O_RDWR);
934 #endif
935
936 if (pty_master == -1)
937 return -1;
938
939 if (grantpt (pty_master) == -1
940 || unlockpt (pty_master) == -1
941 || !(slave_name = ptsname (pty_master)))
942 {
943 close (pty_master);
944 return -1;
945 }
946 strcpy (pty_name, slave_name);
947 return pty_master;
948 }
949
950
951
952
953 static int
954 pty_open_slave (const char *pty_name)
955 {
956 int pty_slave;
957
958 pty_slave = open (pty_name, O_RDWR);
959 if (pty_slave == -1)
960 {
961 fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name, unix_error_string (errno));
962 return -1;
963 }
964 #if !defined(__osf__) && !defined(__linux__)
965 #if defined (I_FIND) && defined (I_PUSH)
966 if (ioctl (pty_slave, I_FIND, "ptem") == 0)
967 if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
968 {
969 fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
970 pty_slave, unix_error_string (errno));
971 close (pty_slave);
972 return -1;
973 }
974
975 if (ioctl (pty_slave, I_FIND, "ldterm") == 0)
976 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
977 {
978 fprintf (stderr,
979 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
980 pty_slave, unix_error_string (errno));
981 close (pty_slave);
982 return -1;
983 }
984 #if !defined(sgi) && !defined(__sgi)
985 if (ioctl (pty_slave, I_FIND, "ttcompat") == 0)
986 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
987 {
988 fprintf (stderr,
989 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
990 pty_slave, unix_error_string (errno));
991 close (pty_slave);
992 return -1;
993 }
994 #endif
995 #endif
996 #endif
997
998 fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
999 return pty_slave;
1000 }
1001
1002 #else
1003
1004
1005
1006 static int
1007 pty_open_master (char *pty_name)
1008 {
1009 int pty_master;
1010 const char *ptr1, *ptr2;
1011
1012 strcpy (pty_name, "/dev/ptyXX");
1013 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1014 {
1015 pty_name[8] = *ptr1;
1016 for (ptr2 = "0123456789abcdef"; *ptr2 != '\0'; ++ptr2)
1017 {
1018 pty_name[9] = *ptr2;
1019
1020
1021 pty_master = open (pty_name, O_RDWR);
1022 if (pty_master == -1)
1023 {
1024 if (errno == ENOENT)
1025 return -1;
1026 continue;
1027 }
1028 pty_name[5] = 't';
1029 if (access (pty_name, 6) != 0)
1030 {
1031 close (pty_master);
1032 pty_name[5] = 'p';
1033 continue;
1034 }
1035 return pty_master;
1036 }
1037 }
1038 return -1;
1039 }
1040
1041
1042
1043
1044 static int
1045 pty_open_slave (const char *pty_name)
1046 {
1047 int pty_slave;
1048 struct group *group_info;
1049
1050 group_info = getgrnam ("tty");
1051 if (group_info != NULL)
1052 {
1053
1054
1055
1056
1057 }
1058 pty_slave = open (pty_name, O_RDWR);
1059 if (pty_slave == -1)
1060 fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1061 fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
1062 return pty_slave;
1063 }
1064 #endif
1065
1066 #endif
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079 static void
1080 init_subshell_precmd (char *precmd, size_t buff_size)
1081 {
1082 switch (mc_global.shell->type)
1083 {
1084 case SHELL_BASH:
1085 g_snprintf (precmd, buff_size,
1086 " mc_print_command_buffer () { printf \"%%s\\\\n\" \"$READLINE_LINE\" >&%d; }\n"
1087 " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"mc_print_command_buffer\"'\n"
1088 " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING
1089 "\":\"echo $BASH_VERSINFO:$READLINE_POINT >&%d\"'\n"
1090 " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n"
1091 "PS1='\\u@\\h:\\w\\$ '\n", command_buffer_pipe[WRITE],
1092 command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1093 break;
1094
1095 case SHELL_ASH_BUSYBOX:
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 case SHELL_DASH:
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136 g_snprintf (precmd, buff_size,
1137 "precmd() { "
1138 "if [ ! \"${PWD##$HOME}\" ]; then "
1139 "MC_PWD=\"~\"; "
1140 "else "
1141 "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; "
1142 "fi; "
1143 "echo \"$USER@$(hostname -s):$MC_PWD\"; "
1144 "pwd>&%d; "
1145 "kill -STOP $$; "
1146 "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
1147 break;
1148
1149 case SHELL_ZSH:
1150 g_snprintf (precmd, buff_size,
1151 " mc_print_command_buffer () { printf \"%%s\\\\n\" \"$BUFFER\" >&%d; }\n"
1152 " zle -N mc_print_command_buffer\n"
1153 " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n"
1154 " mc_print_cursor_position () { echo $CURSOR >&%d}\n"
1155 " zle -N mc_print_cursor_position\n"
1156 " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n"
1157 " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n"
1158 "PS1='%%n@%%m:%%~%%# '\n",
1159 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1160 break;
1161
1162 case SHELL_TCSH:
1163 g_snprintf (precmd, buff_size,
1164 "set echo_style=both; "
1165 "set prompt='%%n@%%m:%%~%%# '; "
1166 "alias precmd 'echo -n;echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
1167 break;
1168 case SHELL_FISH:
1169 g_snprintf (precmd, buff_size,
1170 " bind \\e" SHELL_BUFFER_KEYBINDING " 'commandline >&%d';"
1171 "bind \\e" SHELL_CURSOR_KEYBINDING " 'commandline -C >&%d';"
1172 "if not functions -q fish_prompt_mc;"
1173 "functions -e fish_right_prompt;"
1174 "functions -c fish_prompt fish_prompt_mc; end;"
1175 "function fish_prompt;"
1176 "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n",
1177 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1178 break;
1179
1180 default:
1181 break;
1182 }
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205 static GString *
1206 subshell_name_quote (const char *s)
1207 {
1208 GString *ret;
1209 const char *su, *n;
1210 const char *quote_cmd_start, *quote_cmd_end;
1211
1212 if (mc_global.shell->type == SHELL_FISH)
1213 {
1214 quote_cmd_start = "(printf '%b' '";
1215 quote_cmd_end = "')";
1216 }
1217
1218
1219
1220
1221
1222
1223
1224 else
1225 {
1226 quote_cmd_start = "\"`printf '%b' '";
1227 quote_cmd_end = "'`\"";
1228 }
1229
1230 ret = g_string_sized_new (64);
1231
1232
1233 if (s[0] == '-')
1234 g_string_append (ret, "./");
1235
1236
1237 g_string_append (ret, quote_cmd_start);
1238
1239
1240
1241
1242
1243
1244 for (su = s; su[0] != '\0'; su = n)
1245 {
1246 n = str_cget_next_char_safe (su);
1247
1248 if (str_isalnum (su))
1249 g_string_append_len (ret, su, n - su);
1250 else
1251 {
1252 int c;
1253
1254 for (c = 0; c < n - su; c++)
1255 g_string_append_printf (ret, "\\0%03o", (unsigned char) su[c]);
1256 }
1257 }
1258
1259 g_string_append (ret, quote_cmd_end);
1260
1261 return ret;
1262 }
1263
1264
1265
1266
1267
1268
1269
1270 static void
1271 clear_cwd_pipe (void)
1272 {
1273 fd_set read_set;
1274 struct timeval wtime = { 0, 0 };
1275 int maxfdp;
1276
1277 FD_ZERO (&read_set);
1278 FD_SET (subshell_pipe[READ], &read_set);
1279 maxfdp = subshell_pipe[READ];
1280
1281 if (select (maxfdp + 1, &read_set, NULL, NULL, &wtime) > 0
1282 && FD_ISSET (subshell_pipe[READ], &read_set))
1283 {
1284 if (read (subshell_pipe[READ], subshell_cwd, sizeof (subshell_cwd)) <= 0)
1285 {
1286 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1287 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n", unix_error_string (errno));
1288 exit (EXIT_FAILURE);
1289 }
1290
1291 synchronize ();
1292 }
1293 }
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309 void
1310 init_subshell (void)
1311 {
1312
1313 static char pty_name[BUF_SMALL];
1314
1315 char precmd[BUF_MEDIUM];
1316
1317
1318
1319 init_raw_mode ();
1320
1321 if (mc_global.tty.subshell_pty == 0)
1322 {
1323 if (mc_global.shell->type == SHELL_NONE)
1324 return;
1325
1326
1327
1328
1329
1330 #ifdef HAVE_OPENPTY
1331 if (openpty (&mc_global.tty.subshell_pty, &subshell_pty_slave, NULL, NULL, NULL))
1332 {
1333 fprintf (stderr, "Cannot open master and slave sides of pty: %s\n",
1334 unix_error_string (errno));
1335 mc_global.tty.use_subshell = FALSE;
1336 return;
1337 }
1338 #else
1339 mc_global.tty.subshell_pty = pty_open_master (pty_name);
1340 if (mc_global.tty.subshell_pty == -1)
1341 {
1342 fprintf (stderr, "Cannot open master side of pty: %s\r\n", unix_error_string (errno));
1343 mc_global.tty.use_subshell = FALSE;
1344 return;
1345 }
1346 subshell_pty_slave = pty_open_slave (pty_name);
1347 if (subshell_pty_slave == -1)
1348 {
1349 fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
1350 pty_name, unix_error_string (errno));
1351 mc_global.tty.use_subshell = FALSE;
1352 return;
1353 }
1354 #endif
1355
1356
1357
1358 if (mc_global.shell->type == SHELL_TCSH)
1359 {
1360 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
1361 mc_tmpdir (), (int) getpid ());
1362 if (mkfifo (tcsh_fifo, 0600) == -1)
1363 {
1364 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo, unix_error_string (errno));
1365 mc_global.tty.use_subshell = FALSE;
1366 return;
1367 }
1368
1369
1370
1371 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
1372 || (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
1373 {
1374 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
1375 perror (__FILE__ ": open");
1376 mc_global.tty.use_subshell = FALSE;
1377 return;
1378 }
1379 }
1380 else if (pipe (subshell_pipe) != 0)
1381 {
1382 perror (__FILE__ ": couldn't create pipe");
1383 mc_global.tty.use_subshell = FALSE;
1384 return;
1385 }
1386
1387 if (mc_global.mc_run_mode == MC_RUN_FULL &&
1388 (mc_global.shell->type == SHELL_BASH || mc_global.shell->type == SHELL_ZSH
1389 || mc_global.shell->type == SHELL_FISH))
1390 use_persistent_buffer = TRUE;
1391 if (use_persistent_buffer && pipe (command_buffer_pipe) != 0)
1392 {
1393 perror (__FILE__ ": couldn't create pipe");
1394 mc_global.tty.use_subshell = FALSE;
1395 return;
1396 }
1397 }
1398
1399
1400
1401 subshell_alive = TRUE;
1402 subshell_stopped = FALSE;
1403 subshell_pid = fork ();
1404
1405 if (subshell_pid == -1)
1406 {
1407 fprintf (stderr, "Cannot spawn the subshell process: %s\r\n", unix_error_string (errno));
1408
1409
1410 exit (EXIT_FAILURE);
1411 }
1412
1413 if (subshell_pid == 0)
1414 {
1415
1416 init_subshell_child (pty_name);
1417 }
1418
1419 init_subshell_precmd (precmd, BUF_MEDIUM);
1420
1421 write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd));
1422
1423
1424
1425 subshell_state = RUNNING_COMMAND;
1426 tty_enable_interrupt_key ();
1427 if (!feed_subshell (QUIETLY, TRUE))
1428 mc_global.tty.use_subshell = FALSE;
1429 tty_disable_interrupt_key ();
1430 if (!subshell_alive)
1431 mc_global.tty.use_subshell = FALSE;
1432
1433
1434
1435
1436
1437 if (use_persistent_buffer && !read_command_line_buffer (TRUE))
1438 use_persistent_buffer = FALSE;
1439 }
1440
1441
1442
1443 int
1444 invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath)
1445 {
1446
1447 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
1448
1449
1450 if (new_dir_vpath != NULL)
1451 do_subshell_chdir (subshell_get_cwd (), TRUE);
1452
1453 if (command == NULL)
1454 {
1455 if (subshell_state == INACTIVE)
1456 {
1457 subshell_state = ACTIVE;
1458
1459
1460 if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL)
1461 write_all (mc_global.tty.subshell_pty, " \b", 2);
1462
1463 if (use_persistent_buffer)
1464 {
1465 size_t i;
1466 int pos;
1467
1468
1469
1470 for (i = 0; i < cmdline->buffer->len; i++)
1471 if ((unsigned char) cmdline->buffer->str[i] < 32
1472 || (unsigned char) cmdline->buffer->str[i] == 127)
1473 g_string_overwrite_len (cmdline->buffer, i, " ", 1);
1474
1475
1476 write_all (mc_global.tty.subshell_pty, cmdline->buffer->str, cmdline->buffer->len);
1477
1478
1479 pos = str_length (cmdline->buffer->str) - cmdline->point;
1480 for (i = 0; i < (size_t) pos; i++)
1481 write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3);
1482 }
1483 }
1484 }
1485 else
1486 {
1487
1488
1489
1490
1491 if (use_persistent_buffer)
1492 clear_cwd_pipe ();
1493 else
1494 {
1495
1496
1497 if (mc_global.shell->type != SHELL_FISH)
1498 {
1499 write_all (mc_global.tty.subshell_pty, "\003", 1);
1500 subshell_state = RUNNING_COMMAND;
1501 feed_subshell (QUIETLY, FALSE);
1502 }
1503 }
1504
1505 if (how == QUIETLY)
1506 write_all (mc_global.tty.subshell_pty, " ", 1);
1507
1508 write_all (mc_global.tty.subshell_pty, command, strlen (command));
1509 write_all (mc_global.tty.subshell_pty, "\n", 1);
1510 subshell_state = RUNNING_COMMAND;
1511 subshell_ready = FALSE;
1512 }
1513
1514 feed_subshell (how, FALSE);
1515
1516 if (new_dir_vpath != NULL && subshell_alive)
1517 {
1518 const char *pcwd;
1519
1520 pcwd = vfs_translate_path (vfs_path_as_str (subshell_get_cwd ()));
1521 if (strcmp (subshell_cwd, pcwd) != 0)
1522 *new_dir_vpath = vfs_path_from_str (subshell_cwd);
1523 }
1524
1525
1526 while (!subshell_alive && subshell_get_mainloop_quit () == 0 && mc_global.tty.use_subshell)
1527 init_subshell ();
1528
1529 return subshell_get_mainloop_quit ();
1530 }
1531
1532
1533
1534 gboolean
1535 flush_subshell (int max_wait_length, int how)
1536 {
1537 int rc = 0;
1538 ssize_t bytes = 0;
1539 struct timeval timeleft = { 0, 0 };
1540 gboolean return_value = FALSE;
1541 fd_set tmp;
1542
1543 timeleft.tv_sec = max_wait_length;
1544 FD_ZERO (&tmp);
1545 FD_SET (mc_global.tty.subshell_pty, &tmp);
1546
1547 while (subshell_alive
1548 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0)
1549 {
1550
1551 if (rc == -1)
1552 {
1553 if (errno == EINTR)
1554 {
1555 if (tty_got_winch ())
1556 tty_change_screen_size ();
1557
1558 continue;
1559 }
1560
1561 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno));
1562 exit (EXIT_FAILURE);
1563 }
1564
1565 return_value = TRUE;
1566 timeleft.tv_sec = 0;
1567 timeleft.tv_usec = 0;
1568
1569 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
1570 if (how == VISIBLY)
1571 write_all (STDOUT_FILENO, pty_buffer, bytes);
1572 }
1573
1574 return return_value;
1575 }
1576
1577
1578
1579 gboolean
1580 read_subshell_prompt (void)
1581 {
1582 int rc = 0;
1583 ssize_t bytes = 0;
1584 struct timeval timeleft = { 0, 0 };
1585 gboolean should_reset_prompt = TRUE;
1586 gboolean got_new_prompt = FALSE;
1587
1588 fd_set tmp;
1589 FD_ZERO (&tmp);
1590 FD_SET (mc_global.tty.subshell_pty, &tmp);
1591
1592 while (subshell_alive
1593 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0)
1594 {
1595
1596 if (rc == -1)
1597 {
1598 if (errno == EINTR)
1599 {
1600 if (tty_got_winch ())
1601 tty_change_screen_size ();
1602
1603 continue;
1604 }
1605
1606 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno));
1607 exit (EXIT_FAILURE);
1608 }
1609
1610 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
1611 if (should_reset_prompt)
1612 {
1613 should_reset_prompt = FALSE;
1614 clear_subshell_prompt_string ();
1615 }
1616
1617 parse_subshell_prompt_string (pty_buffer, bytes);
1618 got_new_prompt = TRUE;
1619 }
1620
1621 if (got_new_prompt)
1622 set_prompt_string ();
1623
1624 return (rc != 0 || bytes != 0);
1625 }
1626
1627
1628
1629 void
1630 do_update_prompt (void)
1631 {
1632 if (update_subshell_prompt)
1633 {
1634 if (subshell_prompt != NULL)
1635 {
1636 printf ("\r\n%s", subshell_prompt->str);
1637 fflush (stdout);
1638 }
1639 update_subshell_prompt = FALSE;
1640 }
1641 }
1642
1643
1644
1645 gboolean
1646 exit_subshell (void)
1647 {
1648 gboolean subshell_quit = TRUE;
1649
1650 if (subshell_state != INACTIVE && subshell_alive)
1651 subshell_quit =
1652 query_dialog (_("Warning"),
1653 _("The shell is still active. Quit anyway?"),
1654 D_NORMAL, 2, _("&Yes"), _("&No")) == 0;
1655
1656 if (subshell_quit)
1657 {
1658 if (mc_global.shell->type == SHELL_TCSH)
1659 {
1660 if (unlink (tcsh_fifo) == -1)
1661 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
1662 tcsh_fifo, unix_error_string (errno));
1663 }
1664
1665 if (subshell_prompt != NULL)
1666 {
1667 g_string_free (subshell_prompt, TRUE);
1668 subshell_prompt = NULL;
1669 }
1670
1671 if (subshell_prompt_temp_buffer != NULL)
1672 {
1673 g_string_free (subshell_prompt_temp_buffer, TRUE);
1674 subshell_prompt_temp_buffer = NULL;
1675 }
1676
1677 pty_buffer[0] = '\0';
1678 }
1679
1680 return subshell_quit;
1681 }
1682
1683
1684
1685
1686 void
1687 do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt)
1688 {
1689 char *pcwd;
1690
1691 pcwd = vfs_path_to_str_flags (subshell_get_cwd (), 0, VPF_RECODE);
1692
1693 if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, pcwd) != 0))
1694 {
1695
1696
1697
1698
1699 if (update_prompt)
1700 do_update_prompt ();
1701 g_free (pcwd);
1702 return;
1703 }
1704
1705
1706
1707 if (!use_persistent_buffer)
1708 {
1709 write_all (mc_global.tty.subshell_pty, "\003", 1);
1710 subshell_state = RUNNING_COMMAND;
1711 if (mc_global.shell->type != SHELL_FISH)
1712 if (!feed_subshell (QUIETLY, TRUE))
1713 {
1714 subshell_state = ACTIVE;
1715 return;
1716 }
1717 }
1718
1719
1720 write_all (mc_global.tty.subshell_pty, " cd ", 4);
1721
1722 if (vpath != NULL)
1723 {
1724 const char *translate;
1725
1726 translate = vfs_translate_path (vfs_path_as_str (vpath));
1727 if (translate != NULL)
1728 {
1729 GString *temp;
1730
1731 temp = subshell_name_quote (translate);
1732 write_all (mc_global.tty.subshell_pty, temp->str, temp->len);
1733 g_string_free (temp, TRUE);
1734 }
1735 else
1736 {
1737 write_all (mc_global.tty.subshell_pty, ".", 1);
1738 }
1739 }
1740 else
1741 {
1742 write_all (mc_global.tty.subshell_pty, "/", 1);
1743 }
1744 write_all (mc_global.tty.subshell_pty, "\n", 1);
1745
1746 subshell_state = RUNNING_COMMAND;
1747 if (!feed_subshell (QUIETLY, TRUE))
1748 {
1749 subshell_state = ACTIVE;
1750 return;
1751 }
1752
1753 if (subshell_alive)
1754 {
1755 gboolean bPathNotEq;
1756
1757 bPathNotEq = strcmp (subshell_cwd, pcwd) != 0;
1758
1759 if (bPathNotEq && mc_global.shell->type == SHELL_TCSH)
1760 {
1761 char rp_subshell_cwd[PATH_MAX];
1762 char rp_current_panel_cwd[PATH_MAX];
1763 char *p_subshell_cwd, *p_current_panel_cwd;
1764
1765 p_subshell_cwd = mc_realpath (subshell_cwd, rp_subshell_cwd);
1766 p_current_panel_cwd = mc_realpath (pcwd, rp_current_panel_cwd);
1767
1768 if (p_subshell_cwd == NULL)
1769 p_subshell_cwd = subshell_cwd;
1770 if (p_current_panel_cwd == NULL)
1771 p_current_panel_cwd = pcwd;
1772 bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd) != 0;
1773 }
1774
1775 if (bPathNotEq && !DIR_IS_DOT (pcwd))
1776 {
1777 char *cwd;
1778
1779 cwd = vfs_path_to_str_flags (subshell_get_cwd (), 0, VPF_STRIP_PASSWORD);
1780 vfs_print_message (_("Warning: Cannot change to %s.\n"), cwd);
1781 g_free (cwd);
1782 }
1783 }
1784
1785
1786 if (mc_global.shell->type == SHELL_ZSH)
1787 {
1788
1789
1790
1791 write_all (mc_global.tty.subshell_pty, " \n", 2);
1792 subshell_state = RUNNING_COMMAND;
1793 feed_subshell (QUIETLY, TRUE);
1794 }
1795
1796 update_subshell_prompt = FALSE;
1797
1798 g_free (pcwd);
1799
1800
1801 }
1802
1803
1804
1805 void
1806 subshell_get_console_attributes (void)
1807 {
1808
1809
1810 if (tcgetattr (STDOUT_FILENO, &shell_mode))
1811 {
1812 fprintf (stderr, "Cannot get terminal settings: %s\r\n", unix_error_string (errno));
1813 mc_global.tty.use_subshell = FALSE;
1814 }
1815 }
1816
1817
1818
1819
1820
1821
1822 void
1823 sigchld_handler (int sig)
1824 {
1825 int status;
1826 pid_t pid;
1827
1828 (void) sig;
1829
1830 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
1831
1832 if (pid == subshell_pid)
1833 {
1834
1835
1836 if (WIFSTOPPED (status))
1837 {
1838 if (WSTOPSIG (status) == SIGSTOP)
1839 {
1840
1841 subshell_stopped = TRUE;
1842 }
1843 else
1844 {
1845
1846 kill (subshell_pid, SIGCONT);
1847 }
1848 }
1849 else
1850 {
1851
1852 subshell_alive = FALSE;
1853 delete_select_channel (mc_global.tty.subshell_pty);
1854 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
1855 {
1856 int subshell_quit;
1857 subshell_quit = subshell_get_mainloop_quit () | SUBSHELL_EXIT;
1858 subshell_set_mainloop_quit (subshell_quit);
1859 }
1860 }
1861 }
1862 subshell_handle_cons_saver ();
1863
1864
1865 }
1866
1867