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