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