3 #define INCL_DOSFILEMGR
6 /* These 3 are needed for compile if os2.h includes os2tk.h, not os2emx.h */
7 #define INCL_DOSPROCESS
8 #define SPU_DISABLESUPPRESSION 0
9 #define SPU_ENABLESUPPRESSION 1
12 #include <sys/uflags.h>
15 * Various Unix compatibility functions for OS/2
24 #define PERLIO_NOT_STDIO 0
30 typedef void (*emx_startroutine)(void *);
31 typedef void* (*pthreads_startroutine)(void *);
40 const char *pthreads_states[] = {
51 enum pthreads_state state;
54 thread_join_t *thread_join_data;
55 int thread_join_count;
56 perl_mutex start_thread_mutex;
59 pthread_join(perl_os_thread tid, void **status)
61 MUTEX_LOCK(&start_thread_mutex);
62 switch (thread_join_data[tid].state) {
63 case pthreads_st_exited:
64 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
65 MUTEX_UNLOCK(&start_thread_mutex);
66 *status = thread_join_data[tid].status;
68 case pthreads_st_waited:
69 MUTEX_UNLOCK(&start_thread_mutex);
70 Perl_croak_nocontext("join with a thread with a waiter");
73 thread_join_data[tid].state = pthreads_st_waited;
74 COND_INIT(&thread_join_data[tid].cond);
75 MUTEX_UNLOCK(&start_thread_mutex);
76 COND_WAIT(&thread_join_data[tid].cond, NULL);
77 COND_DESTROY(&thread_join_data[tid].cond);
78 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
79 *status = thread_join_data[tid].status;
82 MUTEX_UNLOCK(&start_thread_mutex);
83 Perl_croak_nocontext("join: unknown thread state: '%s'",
84 pthreads_states[thread_join_data[tid].state]);
91 pthread_startit(void *arg)
93 /* Thread is already started, we need to transfer control only */
94 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
95 int tid = pthread_self();
98 arg = ((void**)arg)[1];
99 if (tid >= thread_join_count) {
100 int oc = thread_join_count;
102 thread_join_count = tid + 5 + tid/5;
103 if (thread_join_data) {
104 Renew(thread_join_data, thread_join_count, thread_join_t);
105 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
107 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
110 if (thread_join_data[tid].state != pthreads_st_none)
111 Perl_croak_nocontext("attempt to reuse thread id %i", tid);
112 thread_join_data[tid].state = pthreads_st_run;
113 /* Now that we copied/updated the guys, we may release the caller... */
114 MUTEX_UNLOCK(&start_thread_mutex);
115 thread_join_data[tid].status = (*start_routine)(arg);
116 switch (thread_join_data[tid].state) {
117 case pthreads_st_waited:
118 COND_SIGNAL(&thread_join_data[tid].cond);
121 thread_join_data[tid].state = pthreads_st_exited;
127 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
128 void *(*start_routine)(void*), void *arg)
132 args[0] = (void*)start_routine;
135 MUTEX_LOCK(&start_thread_mutex);
136 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
137 /*stacksize*/ 10*1024*1024, (void*)args);
138 MUTEX_LOCK(&start_thread_mutex);
139 MUTEX_UNLOCK(&start_thread_mutex);
140 return *tid ? 0 : EINVAL;
144 pthread_detach(perl_os_thread tid)
146 MUTEX_LOCK(&start_thread_mutex);
147 switch (thread_join_data[tid].state) {
148 case pthreads_st_waited:
149 MUTEX_UNLOCK(&start_thread_mutex);
150 Perl_croak_nocontext("detach on a thread with a waiter");
152 case pthreads_st_run:
153 thread_join_data[tid].state = pthreads_st_detached;
154 MUTEX_UNLOCK(&start_thread_mutex);
157 MUTEX_UNLOCK(&start_thread_mutex);
158 Perl_croak_nocontext("detach: unknown thread state: '%s'",
159 pthreads_states[thread_join_data[tid].state]);
165 /* This is a very bastardized version: */
167 os2_cond_wait(perl_cond *c, perl_mutex *m)
171 if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET))
172 Perl_croak_nocontext("panic: COND_WAIT-reset: rc=%i", rc);
173 if (m) MUTEX_UNLOCK(m);
174 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
175 && (rc != ERROR_INTERRUPT))
176 Perl_croak_nocontext("panic: COND_WAIT: rc=%i", rc);
177 if (rc == ERROR_INTERRUPT)
179 if (m) MUTEX_LOCK(m);
183 /*****************************************************************************/
184 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
185 static PFN ExtFCN[2]; /* Labeled by ord below. */
186 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
187 #define ORD_QUERY_ELP 0
188 #define ORD_SET_ELP 1
189 struct PMWIN_entries_t PMWIN_entries;
192 loadByOrd(char *modname, ULONG ord)
194 if (ExtFCN[ord] == NULL) {
195 static HMODULE hdosc = 0;
200 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
202 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
203 Perl_croak_nocontext("This version of OS/2 does not support %s.%i",
204 modname, loadOrd[ord]);
207 if ((long)ExtFCN[ord] == -1)
208 Perl_croak_nocontext("panic queryaddr");
212 init_PMWIN_entries(void)
214 static HMODULE hpmwin = 0;
215 static const int ords[] = {
216 763, /* Initialize */
217 716, /* CreateMsgQueue */
218 726, /* DestroyMsgQueue */
221 912, /* DispatchMsg */
230 if (CheckOSError(DosLoadModule(buf, sizeof buf, "pmwin", &hpmwin)))
231 Perl_croak_nocontext("This version of OS/2 does not support pmwin: error in %s", buf);
233 if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL,
234 ((PFN*)&PMWIN_entries)+i)))
235 Perl_croak_nocontext("This version of OS/2 does not support pmwin.%d", ords[i]);
242 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
244 #define QSS_INI_BUFFER 1024
247 get_sysinfo(ULONG pid, ULONG flags)
250 ULONG rc, buf_len = QSS_INI_BUFFER;
252 New(1322, pbuffer, buf_len, char);
253 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
254 rc = QuerySysState(flags, pid, pbuffer, buf_len);
255 while (rc == ERROR_BUFFER_OVERFLOW) {
256 Renew(pbuffer, buf_len *= 2, char);
257 rc = QuerySysState(flags, pid, pbuffer, buf_len);
264 return (PQTOPLEVEL)pbuffer;
267 #define PRIO_ERR 0x1111
275 psi = get_sysinfo(pid, QSS_PROCESS);
279 if (pid != psi->procdata->pid) {
281 Perl_croak_nocontext("panic: wrong pid in sysinfo");
283 prio = psi->procdata->threads->priority;
289 setpriority(int which, int pid, int val)
294 prio = sys_prio(pid);
296 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
297 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
298 /* Do not change class. */
299 return CheckOSError(DosSetPriority((pid < 0)
300 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
302 (32 - val) % 32 - (prio & 0xFF),
305 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
306 /* Documentation claims one can change both class and basevalue,
307 * but I find it wrong. */
308 /* Change class, but since delta == 0 denotes absolute 0, correct. */
309 if (CheckOSError(DosSetPriority((pid < 0)
310 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
311 priors[(32 - val) >> 5] + 1,
315 if ( ((32 - val) % 32) == 0 ) return 0;
316 return CheckOSError(DosSetPriority((pid < 0)
317 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
323 /* else return CheckOSError(DosSetPriority((pid < 0) */
324 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
325 /* priors[(32 - val) >> 5] + 1, */
326 /* (32 - val) % 32 - (prio & 0xFF), */
332 getpriority(int which /* ignored */, int pid)
338 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
339 /* DosGetInfoBlocks has old priority! */
340 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
341 /* if (pid != pib->pib_ulpid) { */
343 if (ret == PRIO_ERR) {
347 /* ret = tib->tib_ptib2->tib2_ulpri; */
348 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
351 /*****************************************************************************/
354 /* There is no big sense to make it thread-specific, since signals
355 are delivered to thread 1 only. XXXX Maybe make it into an array? */
356 static int spawn_pid;
357 static int spawn_killed;
360 spawn_sighandler(int sig)
362 /* Some programs do not arrange for the keyboard signals to be
363 delivered to them. We need to deliver the signal manually. */
364 /* We may get a signal only if
365 a) kid does not receive keyboard signal: deliver it;
366 b) kid already died, and we get a signal. We may only hope
367 that the pid number was not reused.
371 sig = SIGKILL; /* Try harder. */
372 kill(spawn_pid, sig);
377 result(pTHX_ int flag, int pid)
381 Signal_t (*ihand)(); /* place to save signal during system() */
382 Signal_t (*qhand)(); /* place to save signal during system() */
388 if (pid < 0 || flag != 0)
394 ihand = rsignal(SIGINT, &spawn_sighandler);
395 qhand = rsignal(SIGQUIT, &spawn_sighandler);
397 r = wait4pid(pid, &status, 0);
398 } while (r == -1 && errno == EINTR);
399 rsignal(SIGINT, ihand);
400 rsignal(SIGQUIT, qhand);
402 PL_statusvalue = (U16)status;
405 return status & 0xFFFF;
407 ihand = rsignal(SIGINT, SIG_IGN);
408 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
409 rsignal(SIGINT, ihand);
410 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
413 return PL_statusvalue;
417 #define EXECF_SPAWN 0
419 #define EXECF_TRUEEXEC 2
420 #define EXECF_SPAWN_NOWAIT 3
421 #define EXECF_SPAWN_BYFLAG 4
423 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
432 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
433 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
436 return (pib->pib_ultype);
440 file_type(char *path)
445 if (!(_emx_env & 0x200))
446 Perl_croak_nocontext("file_type not implemented on DOS"); /* not OS/2. */
447 if (CheckOSError(DosQueryAppType(path, &apptype))) {
449 case ERROR_FILE_NOT_FOUND:
450 case ERROR_PATH_NOT_FOUND:
452 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
454 default: /* Found, but not an
455 executable, or some other
463 static ULONG os2_mytype;
465 /* Spawn/exec a program, revert to shell if needed. */
466 /* global PL_Argv[] contains arguments. */
469 do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
475 char buf[256], *s = 0, scrbuf[280];
477 static char * fargs[4]
478 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
479 char **argsp = fargs;
482 int new_stderr = -1, nostderr = 0, fl_stderr;
489 if (strEQ(PL_Argv[0],"/bin/sh"))
490 PL_Argv[0] = PL_sh_path;
492 if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\'
493 && !(PL_Argv[0][0] && PL_Argv[0][1] == ':'
494 && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\'))
495 ) /* will spawnvp use PATH? */
496 TAINT_ENV(); /* testing IFS here is overkill, probably */
497 /* We should check PERL_SH* and PERLLIB_* as well? */
498 if (!really || !*(tmps = SvPV(really, n_a)))
503 if (_emx_env & 0x200) { /* OS/2. */
504 int type = file_type(tmps);
506 if (type == -1) { /* Not found */
511 else if (type == -2) { /* Not an EXE */
516 else if (type == -3) { /* Is a directory? */
517 /* Special-case this */
519 int l = strlen(tmps);
521 if (l + 5 <= sizeof tbuf) {
523 strcpy(tbuf + l, ".exe");
524 type = file_type(tbuf);
534 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
535 case FAPPTYP_WINDOWAPI:
537 if (os2_mytype != 3) { /* not PM */
538 if (flag == P_NOWAIT)
540 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
541 Perl_warner(aTHX_ WARN_EXEC, "Starting PM process with flag=%d, mytype=%d",
546 case FAPPTYP_NOTWINDOWCOMPAT:
548 if (os2_mytype != 0) { /* not full screen */
549 if (flag == P_NOWAIT)
551 else if ((flag & 7) != P_SESSION)
552 Perl_warner(aTHX_ WARN_EXEC, "Starting Full Screen process with flag=%d, mytype=%d",
557 case FAPPTYP_NOTSPEC:
558 /* Let the shell handle this... */
567 new_stderr = dup(2); /* Preserve stderr */
568 if (new_stderr == -1) {
576 fl_stderr = fcntl(2, F_GETFD);
580 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
584 rc = result(aTHX_ trueflag, spawnvp(flag,tmps,PL_Argv));
586 if (execf == EXECF_TRUEEXEC)
587 rc = execvp(tmps,PL_Argv);
588 else if (execf == EXECF_EXEC)
589 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
590 else if (execf == EXECF_SPAWN_NOWAIT)
591 rc = spawnvp(flag,tmps,PL_Argv);
592 else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
593 rc = result(aTHX_ trueflag,
594 spawnvp(flag,tmps,PL_Argv));
596 if (rc < 0 && pass == 1
597 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
602 if (err == ENOENT || err == ENOEXEC) {
603 /* No such file, or is a script. */
604 /* Try adding script extensions to the file name, and
606 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
611 char *s = 0, *s1, *s2;
616 if (l >= sizeof scrbuf) {
619 Perl_warner(aTHX_ WARN_EXEC, "Size of scriptname too big: %d", l);
627 file = PerlIO_open(scr, "r");
632 rd = PerlIO_read(file, buf, sizeof buf-1);
634 if ((s2 = strchr(buf, '\n')) != NULL) *++s2 = '\0';
636 if (!rd) { /* Empty... */
639 /* Special case: maybe from -Zexe build, so
640 there is an executable around (contrary to
641 documentation, DosQueryAppType sometimes (?)
642 does not append ".exe", so we could have
643 reached this place). */
644 if (l + 5 < sizeof scrbuf) {
645 strcpy(scrbuf + l, ".exe");
646 if (PerlLIO_stat(scrbuf,&PL_statbuf) >= 0
647 && !S_ISDIR(PL_statbuf.st_mode)) {
657 if (PerlIO_close(file) != 0) { /* Failure */
659 Perl_warner(aTHX_ WARN_EXEC, "Error reading \"%s\": %s",
660 scr, Strerror(errno));
661 buf[0] = 0; /* Not #! */
667 } else if (buf[0] == 'e') {
668 if (strnEQ(buf, "extproc", 7)
671 } else if (buf[0] == 'E') {
672 if (strnEQ(buf, "EXTPROC", 7)
677 buf[0] = 0; /* Not #! */
685 /* Do better than pdksh: allow a few args,
686 strip trailing whitespace. */
696 while (*s && !isSPACE(*s))
703 Perl_warner(aTHX_ WARN_EXEC, "Too many args on %.*s line of \"%s\"",
714 || (!buf[0] && file)) { /* File without magic */
715 /* In fact we tried all what pdksh would
716 try. There is no point in calling
717 pdksh, we may just emulate its logic. */
718 char *shell = getenv("EXECSHELL");
719 char *shell_opt = NULL;
725 shell = getenv("OS2_SHELL");
726 if (inicmd) { /* No spaces at start! */
728 while (*s && !isSPACE(*s)) {
730 inicmd = NULL; /* Cannot use */
738 /* Dosish shells will choke on slashes
739 in paths, fortunately, this is
740 important for zeroth arg only. */
747 /* If EXECSHELL is set, we do not set */
750 shell = ((_emx_env & 0x200)
753 nargs = shell_opt ? 2 : 1; /* shell file args */
754 exec_args[0] = shell;
755 exec_args[1] = shell_opt;
757 if (nargs == 2 && inicmd) {
758 /* Use the original cmd line */
759 /* XXXX This is good only until we refuse
760 quoted arguments... */
764 } else if (!buf[0] && inicmd) { /* No file */
765 /* Start with the original cmdline. */
766 /* XXXX This is good only until we refuse
767 quoted arguments... */
771 nargs = 2; /* shell -c */
774 while (a[1]) /* Get to the end */
776 a++; /* Copy finil NULL too */
777 while (a >= PL_Argv) {
778 *(a + nargs) = *a; /* PL_Argv was preallocated to be
783 PL_Argv[nargs] = argsp[nargs];
784 /* Enable pathless exec if #! (as pdksh). */
785 pass = (buf[0] == '#' ? 2 : 3);
789 /* Not found: restore errno */
793 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
794 char *no_dir = strrchr(PL_Argv[0], '/');
796 /* Do as pdksh port does: if not found with /, try without
799 PL_Argv[0] = no_dir + 1;
804 if (rc < 0 && ckWARN(WARN_EXEC))
805 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s\n",
806 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
808 PL_Argv[0], Strerror(errno));
809 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
810 && ((trueflag & 0xFF) == P_WAIT))
814 if (new_stderr != -1) { /* How can we use error codes? */
817 fcntl(2, F_SETFD, fl_stderr);
823 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
825 do_spawn3(pTHX_ char *cmd, int execf, int flag)
831 char *shell, *copt, *news = NULL;
832 int rc, err, seenspace = 0, mergestderr = 0;
833 char fullcmd[MAXNAMLEN + 1];
836 if ((shell = getenv("EMXSHELL")) != NULL)
838 else if ((shell = getenv("SHELL")) != NULL)
840 else if ((shell = getenv("COMSPEC")) != NULL)
845 /* Consensus on perl5-porters is that it is _very_ important to
846 have a shell which will not change between computers with the
847 same architecture, to avoid "action on a distance".
848 And to have simple build, this shell should be sh. */
853 while (*cmd && isSPACE(*cmd))
856 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
857 STRLEN l = strlen(PL_sh_path);
859 New(1302, news, strlen(cmd) - 7 + l + 1, char);
860 strcpy(news, PL_sh_path);
861 strcpy(news + l, cmd + 7);
865 /* save an extra exec if possible */
866 /* see if there are shell metacharacters in it */
868 if (*cmd == '.' && isSPACE(cmd[1]))
871 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
874 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
878 for (s = cmd; *s; s++) {
879 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
880 if (*s == '\n' && s[1] == '\0') {
883 } else if (*s == '\\' && !seenspace) {
884 continue; /* Allow backslashes in names */
885 } else if (*s == '>' && s >= cmd + 3
886 && s[-1] == '2' && s[1] == '&' && s[2] == '1'
887 && isSPACE(s[-2]) ) {
890 while (*t && isSPACE(*t))
895 break; /* Allow 2>&1 as the last thing */
898 /* We do not convert this to do_spawn_ve since shell
899 should be smart enough to start itself gloriously. */
901 if (execf == EXECF_TRUEEXEC)
902 rc = execl(shell,shell,copt,cmd,(char*)0);
903 else if (execf == EXECF_EXEC)
904 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
905 else if (execf == EXECF_SPAWN_NOWAIT)
906 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
907 else if (execf == EXECF_SPAWN_BYFLAG)
908 rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
910 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
911 rc = result(aTHX_ P_WAIT,
912 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
913 if (rc < 0 && ckWARN(WARN_EXEC))
914 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
915 (execf == EXECF_SPAWN ? "spawn" : "exec"),
916 shell, Strerror(errno));
923 } else if (*s == ' ' || *s == '\t') {
928 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
929 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
930 PL_Cmd = savepvn(cmd, s-cmd);
932 for (s = PL_Cmd; *s;) {
933 while (*s && isSPACE(*s)) s++;
936 while (*s && !isSPACE(*s)) s++;
942 rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
953 os2_do_aspawn(pTHX_ SV *really, register SV **mark, register SV **sp)
958 int flag = P_WAIT, flag_set = 0;
962 New(1301,PL_Argv, sp - mark + 3, char*);
965 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
972 while (++mark <= sp) {
974 *a++ = SvPVx(*mark, n_a);
980 if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
981 rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
983 rc = do_spawn_ve(aTHX_ really, flag, EXECF_SPAWN, NULL, 0);
991 os2_do_spawn(pTHX_ char *cmd)
994 return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
998 do_spawn_nowait(pTHX_ char *cmd)
1001 return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
1005 Perl_do_exec(pTHX_ char *cmd)
1008 do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
1013 os2exec(pTHX_ char *cmd)
1016 return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
1020 my_syspopen(pTHX_ char *cmd, char *mode)
1025 register I32 this, that, newfd;
1026 register I32 pid, rc;
1031 /* `this' is what we use in the parent, `that' in the child. */
1032 this = (*mode == 'w');
1036 taint_proper("Insecure %s%s", "EXEC");
1040 /* Now we need to spawn the child. */
1041 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1042 int new = dup(p[this]);
1049 newfd = dup(*mode == 'r'); /* Preserve std* */
1051 /* This cannot happen due to fh being bad after pipe(), since
1052 pipe() should have created fh 0 and 1 even if they were
1053 initially closed. But we closed p[this] before. */
1054 if (errno != EBADF) {
1061 fh_fl = fcntl(*mode == 'r', F_GETFD);
1062 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1063 dup2(p[that], *mode == 'r');
1066 /* Where is `this' and newfd now? */
1067 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1069 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1070 pid = do_spawn_nowait(aTHX_ cmd);
1072 close(*mode == 'r'); /* It was closed initially */
1073 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1074 dup2(newfd, *mode == 'r'); /* Return std* back. */
1076 fcntl(*mode == 'r', F_SETFD, fh_fl);
1078 fcntl(*mode == 'r', F_SETFD, fh_fl);
1079 if (p[that] == (*mode == 'r'))
1085 if (p[that] < p[this]) { /* Make fh as small as possible */
1086 dup2(p[this], p[that]);
1090 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1091 (void)SvUPGRADE(sv,SVt_IV);
1093 PL_forkprocess = pid;
1094 return PerlIO_fdopen(p[this], mode);
1096 #else /* USE_POPEN */
1102 res = popen(cmd, mode);
1104 char *shell = getenv("EMXSHELL");
1106 my_setenv("EMXSHELL", PL_sh_path);
1107 res = popen(cmd, mode);
1108 my_setenv("EMXSHELL", shell);
1110 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1111 (void)SvUPGRADE(sv,SVt_IV);
1112 SvIVX(sv) = -1; /* A cooky. */
1115 #endif /* USE_POPEN */
1119 /******************************************************************/
1125 Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
1131 /*******************************************************************/
1132 /* not implemented in EMX 0.9d */
1134 char * ctermid(char *s) { return 0; }
1136 #ifdef MYTTYNAME /* was not in emx0.9a */
1137 void * ttyname(x) { return 0; }
1140 /******************************************************************/
1141 /* my socket forwarders - EMX lib only provides static forwarders */
1143 static HMODULE htcp = 0;
1148 static BYTE buf[20];
1151 if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */
1153 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1154 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1155 return (void *) ((void * (*)(void)) fcn) ();
1160 tcp1(char *name, int arg)
1162 static BYTE buf[20];
1165 if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */
1167 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1168 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1169 ((void (*)(int)) fcn) (arg);
1172 void * gethostent() { return tcp0("GETHOSTENT"); }
1173 void * getnetent() { return tcp0("GETNETENT"); }
1174 void * getprotoent() { return tcp0("GETPROTOENT"); }
1175 void * getservent() { return tcp0("GETSERVENT"); }
1176 void sethostent(x) { tcp1("SETHOSTENT", x); }
1177 void setnetent(x) { tcp1("SETNETENT", x); }
1178 void setprotoent(x) { tcp1("SETPROTOENT", x); }
1179 void setservent(x) { tcp1("SETSERVENT", x); }
1180 void endhostent() { tcp0("ENDHOSTENT"); }
1181 void endnetent() { tcp0("ENDNETENT"); }
1182 void endprotoent() { tcp0("ENDPROTOENT"); }
1183 void endservent() { tcp0("ENDSERVENT"); }
1185 /*****************************************************************************/
1186 /* not implemented in C Set++ */
1189 int setuid(x) { errno = EINVAL; return -1; }
1190 int setgid(x) { errno = EINVAL; return -1; }
1193 /*****************************************************************************/
1194 /* stat() hack for char/block device */
1198 /* First attempt used DosQueryFSAttach which crashed the system when
1199 used with 5.001. Now just look for /dev/. */
1202 os2_stat(char *name, struct stat *st)
1204 static int ino = SHRT_MAX;
1206 if (stricmp(name, "/dev/con") != 0
1207 && stricmp(name, "/dev/tty") != 0)
1208 return stat(name, st);
1210 memset(st, 0, sizeof *st);
1211 st->st_mode = S_IFCHR|0666;
1212 st->st_ino = (ino-- & 0x7FFF);
1219 #ifdef USE_PERL_SBRK
1221 /* SBRK() emulation, mostly moved to malloc.c. */
1224 sys_alloc(int size) {
1226 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1228 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1231 Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
1235 #endif /* USE_PERL_SBRK */
1239 char *tmppath = TMPPATH1;
1244 char *p = getenv("TMP"), *tpath;
1247 if (!p) p = getenv("TEMP");
1250 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1254 strcpy(tpath + len + 1, TMPPATH1);
1261 XS(XS_File__Copy_syscopy)
1264 if (items < 2 || items > 3)
1265 Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
1268 char * src = (char *)SvPV(ST(0),n_a);
1269 char * dst = (char *)SvPV(ST(1),n_a);
1276 flag = (unsigned long)SvIV(ST(2));
1279 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1280 ST(0) = sv_newmortal();
1281 sv_setiv(ST(0), (IV)RETVAL);
1286 #include "patchlevel.h"
1289 mod2fname(pTHX_ SV *sv)
1291 static char fname[9];
1292 int pos = 6, len, avlen;
1293 unsigned int sum = 0;
1299 if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
1301 if (SvTYPE(sv) != SVt_PVAV)
1302 Perl_croak_nocontext("Not array reference given to mod2fname");
1304 avlen = av_len((AV*)sv);
1306 Perl_croak_nocontext("Empty array reference given to mod2fname");
1308 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1309 strncpy(fname, s, 8);
1311 if (len < 6) pos = len;
1313 sum = 33 * sum + *(s++); /* Checksumming first chars to
1314 * get the capitalization into c.s. */
1317 while (avlen >= 0) {
1318 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1320 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1325 sum++; /* Avoid conflict of DLLs in memory. */
1327 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* */
1328 fname[pos] = 'A' + (sum % 26);
1329 fname[pos + 1] = 'A' + (sum / 26 % 26);
1330 fname[pos + 2] = '\0';
1331 return (char *)fname;
1334 XS(XS_DynaLoader_mod2fname)
1338 Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
1343 RETVAL = mod2fname(aTHX_ sv);
1344 ST(0) = sv_newmortal();
1345 sv_setpv((SV*)ST(0), RETVAL);
1353 static char buf[300];
1356 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1359 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
1360 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
1363 if (len && buf[len - 1] == '\n')
1365 if (len && buf[len - 1] == '\r')
1367 if (len && buf[len - 1] == '.')
1379 if (_execname(buf, sizeof buf) != 0)
1380 return PL_origargv[0];
1393 perllib_mangle(char *s, unsigned int l)
1395 static char *newp, *oldp;
1396 static int newl, oldl, notfound;
1397 static char ret[STATIC_FILE_LENGTH+1];
1399 if (!newp && !notfound) {
1400 newp = getenv("PERLLIB_PREFIX");
1405 while (*newp && !isSPACE(*newp) && *newp != ';') {
1406 newp++; oldl++; /* Skip digits. */
1408 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1409 newp++; /* Skip whitespace. */
1411 newl = strlen(newp);
1412 if (newl == 0 || oldl == 0) {
1413 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1418 if (*s == '\\') *s = '/';
1431 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1434 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1435 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1437 strcpy(ret + newl, s + oldl);
1442 Perl_hab_GET() /* Needed if perl.h cannot be included */
1444 return perl_hab_GET();
1448 Perl_Register_MQ(int serve)
1453 if (Perl_os2_initial_mode++)
1455 DosGetInfoBlocks(&tib, &pib);
1456 Perl_os2_initial_mode = pib->pib_ultype;
1457 Perl_hmq_refcnt = 1;
1458 /* Try morphing into a PM application. */
1459 if (pib->pib_ultype != 3) /* 2 is VIO */
1460 pib->pib_ultype = 3; /* 3 is PM */
1461 init_PMWIN_entries();
1462 /* 64 messages if before OS/2 3.0, ignored otherwise */
1463 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1467 _exit(188); /* Panic can try to create a window. */
1468 Perl_croak_nocontext("Cannot create a message queue, or morph to a PM application");
1474 Perl_Serve_Messages(int force)
1479 if (Perl_hmq_servers && !force)
1481 if (!Perl_hmq_refcnt)
1482 Perl_croak_nocontext("No message queue");
1483 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1485 if (msg.msg == WM_QUIT)
1486 Perl_croak_nocontext("QUITing...");
1487 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1493 Perl_Process_Messages(int force, I32 *cntp)
1497 if (Perl_hmq_servers && !force)
1499 if (!Perl_hmq_refcnt)
1500 Perl_croak_nocontext("No message queue");
1501 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1504 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1505 if (msg.msg == WM_DESTROY)
1507 if (msg.msg == WM_CREATE)
1510 Perl_croak_nocontext("QUITing...");
1514 Perl_Deregister_MQ(int serve)
1519 if (--Perl_hmq_refcnt == 0) {
1520 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1522 /* Try morphing back from a PM application. */
1523 if (pib->pib_ultype == 3) /* 3 is PM */
1524 pib->pib_ultype = Perl_os2_initial_mode;
1526 Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
1531 extern void dlopen();
1532 void *fakedl = &dlopen; /* Pull in dynaloading part. */
1534 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1535 && ((path)[2] == '/' || (path)[2] == '\\'))
1536 #define sys_is_rooted _fnisabs
1537 #define sys_is_relative _fnisrel
1538 #define current_drive _getdrive
1540 #undef chdir /* Was _chdir2. */
1541 #define sys_chdir(p) (chdir(p) == 0)
1542 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1544 static int DOS_harderr_state = -1;
1550 Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
1552 int arg1 = SvIV(ST(0));
1553 int arg2 = SvIV(ST(1));
1554 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1555 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1556 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1559 if (CheckOSError(DosError(a)))
1560 Perl_croak_nocontext("DosError(%d) failed", a);
1561 ST(0) = sv_newmortal();
1562 if (DOS_harderr_state >= 0)
1563 sv_setiv(ST(0), DOS_harderr_state);
1564 DOS_harderr_state = RETVAL;
1569 static signed char DOS_suppression_state = -1;
1571 XS(XS_OS2_Errors2Drive)
1575 Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
1579 int suppress = SvOK(sv);
1580 char *s = suppress ? SvPV(sv, n_a) : NULL;
1581 char drive = (s ? *s : 0);
1584 if (suppress && !isALPHA(drive))
1585 Perl_croak_nocontext("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1586 if (CheckOSError(DosSuppressPopUps((suppress
1587 ? SPU_ENABLESUPPRESSION
1588 : SPU_DISABLESUPPRESSION),
1590 Perl_croak_nocontext("DosSuppressPopUps(%c) failed", drive);
1591 ST(0) = sv_newmortal();
1592 if (DOS_suppression_state > 0)
1593 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1594 else if (DOS_suppression_state == 0)
1595 sv_setpvn(ST(0), "", 0);
1596 DOS_suppression_state = drive;
1601 static const char * const si_fields[QSV_MAX] = {
1603 "MAX_TEXT_SESSIONS",
1607 "DYN_PRI_VARIATION",
1625 "FOREGROUND_FS_SESSION",
1626 "FOREGROUND_PROCESS"
1633 Perl_croak_nocontext("Usage: OS2::SysInfo()");
1635 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1636 APIRET rc = NO_ERROR; /* Return code */
1639 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1640 QSV_MAX, /* information */
1643 Perl_croak_nocontext("DosQuerySysInfo() failed");
1644 EXTEND(SP,2*QSV_MAX);
1645 while (i < QSV_MAX) {
1646 ST(j) = sv_newmortal();
1647 sv_setpv(ST(j++), si_fields[i]);
1648 ST(j) = sv_newmortal();
1649 sv_setiv(ST(j++), si[i]);
1653 XSRETURN(2 * QSV_MAX);
1656 XS(XS_OS2_BootDrive)
1660 Perl_croak_nocontext("Usage: OS2::BootDrive()");
1662 ULONG si[1] = {0}; /* System Information Data Buffer */
1663 APIRET rc = NO_ERROR; /* Return code */
1666 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1667 (PVOID)si, sizeof(si))))
1668 Perl_croak_nocontext("DosQuerySysInfo() failed");
1669 ST(0) = sv_newmortal();
1670 c = 'a' - 1 + si[0];
1671 sv_setpvn(ST(0), &c, 1);
1680 Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
1682 bool serve = SvOK(ST(0));
1683 unsigned long pmq = perl_hmq_GET(serve);
1685 ST(0) = sv_newmortal();
1686 sv_setiv(ST(0), pmq);
1691 XS(XS_OS2_UnMorphPM)
1695 Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
1697 bool serve = SvOK(ST(0));
1699 perl_hmq_UNSET(serve);
1704 XS(XS_OS2_Serve_Messages)
1708 Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
1710 bool force = SvOK(ST(0));
1711 unsigned long cnt = Perl_Serve_Messages(force);
1713 ST(0) = sv_newmortal();
1714 sv_setiv(ST(0), cnt);
1719 XS(XS_OS2_Process_Messages)
1722 if (items < 1 || items > 2)
1723 Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
1725 bool force = SvOK(ST(0));
1731 int fake = SvIV(sv); /* Force SvIVX */
1734 Perl_croak_nocontext("Can't upgrade count to IV");
1736 cnt = Perl_Process_Messages(force, &cntr);
1739 cnt = Perl_Process_Messages(force, NULL);
1741 ST(0) = sv_newmortal();
1742 sv_setiv(ST(0), cnt);
1747 XS(XS_Cwd_current_drive)
1751 Perl_croak_nocontext("Usage: Cwd::current_drive()");
1755 RETVAL = current_drive();
1756 ST(0) = sv_newmortal();
1757 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1762 XS(XS_Cwd_sys_chdir)
1766 Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
1769 char * path = (char *)SvPV(ST(0),n_a);
1772 RETVAL = sys_chdir(path);
1773 ST(0) = boolSV(RETVAL);
1774 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1779 XS(XS_Cwd_change_drive)
1783 Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
1786 char d = (char)*SvPV(ST(0),n_a);
1789 RETVAL = change_drive(d);
1790 ST(0) = boolSV(RETVAL);
1791 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1796 XS(XS_Cwd_sys_is_absolute)
1800 Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
1803 char * path = (char *)SvPV(ST(0),n_a);
1806 RETVAL = sys_is_absolute(path);
1807 ST(0) = boolSV(RETVAL);
1808 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1813 XS(XS_Cwd_sys_is_rooted)
1817 Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
1820 char * path = (char *)SvPV(ST(0),n_a);
1823 RETVAL = sys_is_rooted(path);
1824 ST(0) = boolSV(RETVAL);
1825 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1830 XS(XS_Cwd_sys_is_relative)
1834 Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
1837 char * path = (char *)SvPV(ST(0),n_a);
1840 RETVAL = sys_is_relative(path);
1841 ST(0) = boolSV(RETVAL);
1842 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1851 Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
1855 RETVAL = _getcwd2(p, MAXPATHLEN);
1856 ST(0) = sv_newmortal();
1857 sv_setpv((SV*)ST(0), RETVAL);
1862 XS(XS_Cwd_sys_abspath)
1865 if (items < 1 || items > 2)
1866 Perl_croak_nocontext("Usage: Cwd::sys_abspath(path, dir = NULL)");
1869 char * path = (char *)SvPV(ST(0),n_a);
1877 dir = (char *)SvPV(ST(1),n_a);
1879 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1883 if (_abspath(p, path, MAXPATHLEN) == 0) {
1889 /* Absolute with drive: */
1890 if ( sys_is_absolute(path) ) {
1891 if (_abspath(p, path, MAXPATHLEN) == 0) {
1896 } else if (path[0] == '/' || path[0] == '\\') {
1897 /* Rooted, but maybe on different drive. */
1898 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1899 char p1[MAXPATHLEN];
1901 /* Need to prepend the drive. */
1904 Copy(path, p1 + 2, strlen(path) + 1, char);
1906 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1911 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1917 /* Either path is relative, or starts with a drive letter. */
1918 /* If the path starts with a drive letter, then dir is
1920 a/b) it is absolute/x:relative on the same drive.
1921 c) path is on current drive, and dir is rooted
1922 In all the cases it is safe to drop the drive part
1924 if ( !sys_is_relative(path) ) {
1927 if ( ( ( sys_is_absolute(dir)
1928 || (isALPHA(dir[0]) && dir[1] == ':'
1929 && strnicmp(dir, path,1) == 0))
1930 && strnicmp(dir, path,1) == 0)
1931 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1932 && toupper(path[0]) == current_drive())) {
1934 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1935 RETVAL = p; goto done;
1937 RETVAL = NULL; goto done;
1941 /* Need to prepend the absolute path of dir. */
1942 char p1[MAXPATHLEN];
1944 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1947 if (p1[ l - 1 ] != '/') {
1951 Copy(path, p1 + l, strlen(path) + 1, char);
1952 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1964 ST(0) = sv_newmortal();
1965 sv_setpv((SV*)ST(0), RETVAL);
1969 typedef APIRET (*PELP)(PSZ path, ULONG type);
1972 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1974 loadByOrd("doscalls",ord); /* Guarantied to load or die! */
1975 return (*(PELP)ExtFCN[ord])(path, type);
1978 #define extLibpath(type) \
1979 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1980 : BEGIN_LIBPATH))) \
1983 #define extLibpath_set(p,type) \
1984 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1987 XS(XS_Cwd_extLibpath)
1990 if (items < 0 || items > 1)
1991 Perl_croak_nocontext("Usage: Cwd::extLibpath(type = 0)");
2001 type = (int)SvIV(ST(0));
2004 RETVAL = extLibpath(type);
2005 ST(0) = sv_newmortal();
2006 sv_setpv((SV*)ST(0), RETVAL);
2011 XS(XS_Cwd_extLibpath_set)
2014 if (items < 1 || items > 2)
2015 Perl_croak_nocontext("Usage: Cwd::extLibpath_set(s, type = 0)");
2018 char * s = (char *)SvPV(ST(0),n_a);
2026 type = (int)SvIV(ST(1));
2029 RETVAL = extLibpath_set(s, type);
2030 ST(0) = boolSV(RETVAL);
2031 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
2039 char *file = __FILE__;
2043 if (_emx_env & 0x200) { /* OS/2 */
2044 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
2045 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
2046 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
2048 newXS("OS2::Error", XS_OS2_Error, file);
2049 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
2050 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
2051 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
2052 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
2053 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
2054 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
2055 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
2056 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
2057 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
2058 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
2059 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
2060 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
2061 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
2062 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
2063 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
2064 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
2065 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
2068 sv_setiv(GvSV(gv), 1);
2070 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
2072 sv_setiv(GvSV(gv), _emx_rev);
2073 sv_setpv(GvSV(gv), _emx_vprt);
2075 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
2077 sv_setiv(GvSV(gv), _emx_env);
2078 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
2080 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
2084 OS2_Perl_data_t OS2_Perl_data;
2087 Perl_OS2_init(char **env)
2093 OS2_Perl_data.xs_init = &Xs_OS2_init;
2094 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
2095 if (environ == NULL && env) {
2098 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
2099 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
2100 strcpy(PL_sh_path, SH_PATH);
2101 PL_sh_path[0] = shell[0];
2102 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
2103 int l = strlen(shell), i;
2104 if (shell[l-1] == '/' || shell[l-1] == '\\') {
2107 New(1304, PL_sh_path, l + 8, char);
2108 strncpy(PL_sh_path, shell, l);
2109 strcpy(PL_sh_path + l, "/sh.exe");
2110 for (i = 0; i < l; i++) {
2111 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
2114 MUTEX_INIT(&start_thread_mutex);
2115 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2122 my_tmpnam (char *str)
2124 char *p = getenv("TMP"), *tpath;
2127 if (!p) p = getenv("TEMP");
2128 tpath = tempnam(p, "pltmp");
2142 if (s.st_mode & S_IWOTH) {
2145 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2151 /* This code was contributed by Rocco Caputo. */
2153 my_flock(int handle, int o)
2155 FILELOCK rNull, rFull;
2156 ULONG timeout, handle_type, flag_word;
2158 int blocking, shared;
2159 static int use_my = -1;
2162 char *s = getenv("USE_PERL_FLOCK");
2168 if (!(_emx_env & 0x200) || !use_my)
2169 return flock(handle, o); /* Delegate to EMX. */
2172 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2173 (handle_type & 0xFF))
2178 // set lock/unlock ranges
2179 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2180 rFull.lRange = 0x7FFFFFFF;
2181 // set timeout for blocking
2182 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2183 // shared or exclusive?
2184 shared = (o & LOCK_SH) ? 1 : 0;
2185 // do not block the unlock
2186 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2187 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2192 case ERROR_INVALID_HANDLE:
2195 case ERROR_SHARING_BUFFER_EXCEEDED:
2198 case ERROR_LOCK_VIOLATION:
2199 break; // not an error
2200 case ERROR_INVALID_PARAMETER:
2201 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2202 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2205 case ERROR_INTERRUPT:
2214 if (o & (LOCK_SH | LOCK_EX)) {
2215 // for blocking operations
2229 case ERROR_INVALID_HANDLE:
2232 case ERROR_SHARING_BUFFER_EXCEEDED:
2235 case ERROR_LOCK_VIOLATION:
2237 errno = EWOULDBLOCK;
2241 case ERROR_INVALID_PARAMETER:
2242 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2243 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2246 case ERROR_INTERRUPT:
2253 // give away timeslice