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