@@ -6,6 +6,8 @@ BEGIN_OPS_PREAMBLE
6
6
#include "parrot/parrot.h"
7
7
#include "parrot/extend.h"
8
8
#include "parrot/dynext.h"
9
+ #include "parrot/io.h"
10
+ #include "pmc/pmc_filehandle.h"
9
11
10
12
/* 6modely includes. */
11
13
#include "../6model/sixmodelobject.h"
@@ -563,6 +565,97 @@ static char *create_command_line(const char *const *args) {
563
565
return cmd;
564
566
}
565
567
568
+ static PIOHANDLE Run_OS_Command_Piped(PARROT_INTERP, PMC *command, PMC *env_hash, INTVAL flags,
569
+ INTVAL *pid, INTVAL *status) {
570
+ HANDLE current = GetCurrentProcess();
571
+ HANDLE hnull = INVALID_HANDLE_VALUE;
572
+ HANDLE hread = INVALID_HANDLE_VALUE;
573
+ HANDLE hwrite = INVALID_HANDLE_VALUE;
574
+ HANDLE hchild = INVALID_HANDLE_VALUE;
575
+ STARTUPINFO si;
576
+ PROCESS_INFORMATION pi;
577
+ SECURITY_ATTRIBUTES sec;
578
+ const char *env = pack_env_hash(interp, env_hash);
579
+ const char *const *argv = pack_arg_array(interp, command);
580
+ const char *cmd = create_command_line(argv);
581
+ PIOHANDLE os_handle;
582
+
583
+ pi.hThread = INVALID_HANDLE_VALUE;
584
+ pi.hProcess = INVALID_HANDLE_VALUE;
585
+ sec.nLength = sizeof sec;
586
+ sec.lpSecurityDescriptor = NULL;
587
+ sec.bInheritHandle = TRUE;
588
+
589
+ si.cb = sizeof si;
590
+ GetStartupInfo(&si);
591
+ si.dwFlags = STARTF_USESTDHANDLES;
592
+ if (CreatePipe(&hread, &hwrite, NULL, 0) == 0)
593
+ goto fail;
594
+ if (DuplicateHandle(current, flags & PARROT_EXEC_STDOUT ? hwrite : hread,
595
+ current, &hchild,
596
+ 0, TRUE,
597
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)
598
+ == 0)
599
+ goto fail;
600
+ if (hchild == INVALID_HANDLE_VALUE)
601
+ goto fail;
602
+
603
+ if (flags & PARROT_EXEC_STDOUT) {
604
+ /* Redirect input to NULL. This is to avoid
605
+ * interferences in case both the child and
606
+ * the parent tries to read from stdin.
607
+ * May be unnecessary or even interfere
608
+ * with valid usages, need more feedback. */
609
+ hnull = CreateFile("NUL", GENERIC_READ|GENERIC_WRITE,
610
+ 0, &sec, OPEN_EXISTING,
611
+ FILE_ATTRIBUTE_NORMAL, NULL);
612
+ if (hnull == INVALID_HANDLE_VALUE)
613
+ goto fail;
614
+ si.hStdInput = hnull;
615
+ si.hStdOutput = hchild;
616
+ si.hStdError = hchild;
617
+ }
618
+ else {
619
+ si.hStdInput = hchild;
620
+ }
621
+
622
+ if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, env, NULL, &si, &pi) == 0)
623
+ goto fail;
624
+
625
+ if (flags & PARROT_EXEC_STDOUT) {
626
+ os_handle = hread;
627
+ CloseHandle(hwrite);
628
+ }
629
+ else {
630
+ os_handle = hwrite;
631
+ CloseHandle(hread);
632
+ }
633
+
634
+ Parrot_str_free_cstring(cmd);
635
+ CloseHandle(pi.hThread);
636
+
637
+ *pid = (INTVAL)pi.hProcess;
638
+
639
+ return os_handle;
640
+
641
+ fail:
642
+ if (cmd != NULL)
643
+ Parrot_str_free_cstring(cmd);
644
+ if (hnull != INVALID_HANDLE_VALUE)
645
+ CloseHandle(hnull);
646
+ if (hread != INVALID_HANDLE_VALUE)
647
+ CloseHandle(hread);
648
+ if (hwrite != INVALID_HANDLE_VALUE)
649
+ CloseHandle(hwrite);
650
+ if (hchild != INVALID_HANDLE_VALUE)
651
+ CloseHandle(hchild);
652
+ if (pi.hThread != INVALID_HANDLE_VALUE)
653
+ CloseHandle(pi.hThread);
654
+ if (pi.hProcess != INVALID_HANDLE_VALUE)
655
+ CloseHandle(pi.hProcess);
656
+ Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_UNIMPLEMENTED,
657
+ "pipe open error");
658
+ }
566
659
static INTVAL Run_OS_Command(PARROT_INTERP, PMC *command, PMC *env_hash)
567
660
{
568
661
DWORD status = 0;
@@ -667,6 +760,129 @@ static INTVAL Run_OS_Command(PARROT_INTERP, PMC *command, PMC *env_hash)
667
760
/* make gcc happy */
668
761
return 1;
669
762
}
763
+ static PIOHANDLE Run_OS_Command_Piped(PARROT_INTERP, PMC *command, PMC *env_hash, INTVAL flags,
764
+ INTVAL *pid, INTVAL *status) {
765
+ char **saved = environ;
766
+ char **cmd = pack_arg_array(interp, command);
767
+ char **env = pack_env_hash(interp, env_hash);
768
+ char *prog = cmd[0];
769
+ PIOHANDLE handles[3];
770
+ int in_fds[2];
771
+ int out_fds[2];
772
+ int err_fds[2];
773
+
774
+ if (flags & PARROT_EXEC_STDIN
775
+ && pipe(in_fds) < 0)
776
+ goto error_pipe_in;
777
+
778
+ if (flags & PARROT_EXEC_STDOUT
779
+ && pipe(out_fds) < 0)
780
+ goto error_pipe_out;
781
+
782
+ if (flags & PARROT_EXEC_STDERR
783
+ && pipe(err_fds) < 0)
784
+ goto error_pipe_err;
785
+
786
+ *pid = fork();
787
+
788
+ if (*pid < 0)
789
+ goto error_fork;
790
+
791
+ if (*pid > 0) {
792
+ if (flags & PARROT_EXEC_STDIN) {
793
+ /* close fd for reading */
794
+ close(in_fds[0]);
795
+ handles[0] = in_fds[1];
796
+ }
797
+
798
+ if (flags & PARROT_EXEC_STDOUT) {
799
+ /* close fd for writing */
800
+ close(out_fds[1]);
801
+ handles[1] = out_fds[0];
802
+ }
803
+
804
+ if (flags & PARROT_EXEC_STDERR) {
805
+ /* close fd for writing */
806
+ close(err_fds[1]);
807
+ handles[2] = err_fds[0];
808
+ }
809
+ }
810
+ else /* (pid == 0) */ {
811
+ /* Child - exec process */
812
+
813
+ if (flags & PARROT_EXEC_STDIN) {
814
+ /* redirect stdin to pipe */
815
+ close(in_fds[1]);
816
+ close(STDIN_FILENO);
817
+
818
+ if (dup(in_fds[0]) != STDIN_FILENO)
819
+ PARROT_FORCE_EXIT(EXIT_FAILURE);
820
+ }
821
+
822
+ if (flags & PARROT_EXEC_STDOUT) {
823
+ /* redirect stdout to pipe */
824
+ close(out_fds[0]);
825
+ close(STDOUT_FILENO);
826
+
827
+ if (dup(out_fds[1]) != STDOUT_FILENO)
828
+ PARROT_FORCE_EXIT(EXIT_FAILURE);
829
+
830
+ if (!(flags & PARROT_EXEC_STDERR)) {
831
+ close(STDERR_FILENO);
832
+
833
+ if (dup(out_fds[1]) != STDERR_FILENO)
834
+ PARROT_FORCE_EXIT(EXIT_FAILURE);
835
+ }
836
+ }
837
+
838
+ if (flags & PARROT_EXEC_STDERR) {
839
+ /* redirect stderr to pipe */
840
+ close(err_fds[0]);
841
+ close(STDERR_FILENO);
842
+
843
+ if (dup(err_fds[1]) != STDERR_FILENO)
844
+ PARROT_FORCE_EXIT(EXIT_FAILURE);
845
+ }
846
+
847
+ environ = env;
848
+
849
+ *status = execvp(prog, cmd);
850
+
851
+ /* if we get here, something's horribly wrong, but free anyway... */
852
+ free_packed(env);
853
+ free_packed(cmd);
854
+ environ = saved;
855
+
856
+ /* Will never reach this unless exec fails.
857
+ * No need to clean up, we're just going to exit */
858
+ perror("execvp");
859
+ PARROT_FORCE_EXIT(EXIT_FAILURE);
860
+ }
861
+
862
+ return handles[1];
863
+
864
+ error_fork:
865
+ if (flags & PARROT_EXEC_STDERR) {
866
+ close(err_fds[0]);
867
+ close(err_fds[1]);
868
+ }
869
+
870
+ error_pipe_err:
871
+ if (flags & PARROT_EXEC_STDOUT) {
872
+ close(out_fds[0]);
873
+ close(out_fds[1]);
874
+ }
875
+
876
+ error_pipe_out:
877
+ if (flags & PARROT_EXEC_STDIN) {
878
+ close(in_fds[0]);
879
+ close(in_fds[1]);
880
+ }
881
+
882
+ error_pipe_in:
883
+ Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
884
+ "Error executing process: %s", strerror(errno));
885
+ }
670
886
#endif
671
887
672
888
/*
@@ -3787,6 +4003,58 @@ inline op nqp_delete_f(out INT, in STR) :base_core {
3787
4003
#endif
3788
4004
}
3789
4005
4006
+ inline op nqp_openpipe(out PMC, in STR, in STR, in PMC, in STR) {
4007
+ STRING *dir = $3;
4008
+ PMC *env = $4;
4009
+ STRING * const old_cwd = Parrot_file_getcwd(interp);
4010
+ INTVAL status = 0;
4011
+ const INTVAL typenum = Parrot_hll_get_ctx_HLL_type(interp, enum_class_FileHandle);
4012
+ PMC *handle = Parrot_pmc_new(interp, typenum);
4013
+ IO_BUFFER * read_buffer = IO_GET_READ_BUFFER(interp, handle);
4014
+ PMC * command = Parrot_pmc_new(interp, enum_class_ResizableStringArray);
4015
+ const VTABLE * vtable = Parrot_io_get_vtable(interp, IO_VTABLE_PIPE, NULL);
4016
+ PIOHANDLE os_handle;
4017
+ INTVAL pid;
4018
+ #ifdef WIN32
4019
+ const STRING *comspec = Parrot_str_new(interp, "ComSpec", 0);
4020
+ VTABLE_push_string(interp, command, Parrot_getenv(interp, comspec));
4021
+ VTABLE_push_string(interp, command, Parrot_str_new_constant(interp, "/c"));
4022
+ #else
4023
+ VTABLE_push_string(interp, command, Parrot_str_new_constant(interp, "sh"));
4024
+ VTABLE_push_string(interp, command, Parrot_str_new_constant(interp, "-c"));
4025
+ #endif
4026
+ VTABLE_push_string(interp, command, $2);
4027
+
4028
+ Parrot_file_chdir(interp, dir);
4029
+ os_handle = Run_OS_Command_Piped(interp, command, env, PARROT_EXEC_STDOUT, &pid, &status);
4030
+ Parrot_file_chdir(interp, old_cwd);
4031
+
4032
+ SETATTR_FileHandle_io_vtable(interp, handle, vtable);
4033
+ SETATTR_FileHandle_process_id(interp, handle, pid);
4034
+ SETATTR_FileHandle_exit_status(interp, handle, status);
4035
+ SETATTR_FileHandle_os_handle(interp, handle, os_handle);
4036
+ SETATTR_FileHandle_flags(interp, handle, PIO_F_PIPE | PIO_F_READ);
4037
+ SETATTR_FileHandle_mode(interp, handle, Parrot_str_new_constant(interp, "rp"));
4038
+ SETATTR_FileHandle_file_pos(interp, handle, 0);
4039
+
4040
+ if (!read_buffer) {
4041
+ read_buffer = (IO_BUFFER *)Parrot_gc_allocate_fixed_size_storage(interp,
4042
+ sizeof(IO_BUFFER));
4043
+ read_buffer->encoding = NULL;
4044
+ read_buffer->buffer_size = 2048; /* PIO_BUFFER_MIN_SIZE */
4045
+ read_buffer->buffer_ptr = (char *)mem_sys_allocate(2048);
4046
+ read_buffer->buffer_start = read_buffer->buffer_ptr;
4047
+ read_buffer->buffer_end = read_buffer->buffer_ptr;
4048
+ PARROT_ASSERT(BUFFER_IS_EMPTY(read_buffer));
4049
+ read_buffer->raw_reads = 0;
4050
+ read_buffer->flags |= PIO_BF_MALLOC;
4051
+
4052
+ SETATTR_FileHandle_read_buffer(interp, handle, read_buffer);
4053
+ }
4054
+
4055
+ $1 = handle;
4056
+ }
4057
+
3790
4058
inline op nqp_spawn(out INT, in PMC, in STR, in PMC) {
3791
4059
STRING *dir = $3;
3792
4060
PMC *env = $4;
0 commit comments