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