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