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
13 #include <sys/uflags.h>
16 * Various Unix compatibility functions for OS/2
27 #define PERLIO_NOT_STDIO 0
34 typedef void (*emx_startroutine)(void *);
35 typedef void* (*pthreads_startroutine)(void *);
44 const char *pthreads_states[] = {
55 enum pthreads_state state;
58 thread_join_t *thread_join_data;
59 int thread_join_count;
60 perl_mutex start_thread_mutex;
63 pthread_join(perl_os_thread tid, void **status)
65 MUTEX_LOCK(&start_thread_mutex);
66 switch (thread_join_data[tid].state) {
67 case pthreads_st_exited:
68 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
69 MUTEX_UNLOCK(&start_thread_mutex);
70 *status = thread_join_data[tid].status;
72 case pthreads_st_waited:
73 MUTEX_UNLOCK(&start_thread_mutex);
74 Perl_croak_nocontext("join with a thread with a waiter");
77 thread_join_data[tid].state = pthreads_st_waited;
78 COND_INIT(&thread_join_data[tid].cond);
79 MUTEX_UNLOCK(&start_thread_mutex);
80 COND_WAIT(&thread_join_data[tid].cond, NULL);
81 COND_DESTROY(&thread_join_data[tid].cond);
82 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
83 *status = thread_join_data[tid].status;
86 MUTEX_UNLOCK(&start_thread_mutex);
87 Perl_croak_nocontext("join: unknown thread state: '%s'",
88 pthreads_states[thread_join_data[tid].state]);
95 pthread_startit(void *arg)
97 /* Thread is already started, we need to transfer control only */
98 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
99 int tid = pthread_self();
102 arg = ((void**)arg)[1];
103 if (tid >= thread_join_count) {
104 int oc = thread_join_count;
106 thread_join_count = tid + 5 + tid/5;
107 if (thread_join_data) {
108 Renew(thread_join_data, thread_join_count, thread_join_t);
109 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
111 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
114 if (thread_join_data[tid].state != pthreads_st_none)
115 Perl_croak_nocontext("attempt to reuse thread id %i", tid);
116 thread_join_data[tid].state = pthreads_st_run;
117 /* Now that we copied/updated the guys, we may release the caller... */
118 MUTEX_UNLOCK(&start_thread_mutex);
119 thread_join_data[tid].status = (*start_routine)(arg);
120 switch (thread_join_data[tid].state) {
121 case pthreads_st_waited:
122 COND_SIGNAL(&thread_join_data[tid].cond);
125 thread_join_data[tid].state = pthreads_st_exited;
131 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
132 void *(*start_routine)(void*), void *arg)
136 args[0] = (void*)start_routine;
139 MUTEX_LOCK(&start_thread_mutex);
140 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
141 /*stacksize*/ 10*1024*1024, (void*)args);
142 MUTEX_LOCK(&start_thread_mutex);
143 MUTEX_UNLOCK(&start_thread_mutex);
144 return *tid ? 0 : EINVAL;
148 pthread_detach(perl_os_thread tid)
150 MUTEX_LOCK(&start_thread_mutex);
151 switch (thread_join_data[tid].state) {
152 case pthreads_st_waited:
153 MUTEX_UNLOCK(&start_thread_mutex);
154 Perl_croak_nocontext("detach on a thread with a waiter");
156 case pthreads_st_run:
157 thread_join_data[tid].state = pthreads_st_detached;
158 MUTEX_UNLOCK(&start_thread_mutex);
161 MUTEX_UNLOCK(&start_thread_mutex);
162 Perl_croak_nocontext("detach: unknown thread state: '%s'",
163 pthreads_states[thread_join_data[tid].state]);
169 /* This is a very bastardized version: */
171 os2_cond_wait(perl_cond *c, perl_mutex *m)
175 if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET))
176 Perl_croak_nocontext("panic: COND_WAIT-reset: rc=%i", rc);
177 if (m) MUTEX_UNLOCK(m);
178 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
179 && (rc != ERROR_INTERRUPT))
180 Perl_croak_nocontext("panic: COND_WAIT: rc=%i", rc);
181 if (rc == ERROR_INTERRUPT)
183 if (m) MUTEX_LOCK(m);
187 /*****************************************************************************/
188 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
189 static PFN ExtFCN[2]; /* Labeled by ord below. */
190 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
191 #define ORD_QUERY_ELP 0
192 #define ORD_SET_ELP 1
193 struct PMWIN_entries_t PMWIN_entries;
196 loadModule(char *modname)
198 HMODULE h = (HMODULE)dlopen(modname, 0);
200 Perl_croak_nocontext("Error loading module '%s': %s",
206 loadByOrd(char *modname, ULONG ord)
208 if (ExtFCN[ord] == NULL) {
209 static HMODULE hdosc = 0;
214 hdosc = loadModule(modname);
215 if (CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
216 Perl_croak_nocontext(
217 "This version of OS/2 does not support %s.%i",
218 modname, loadOrd[ord]);
221 if ((long)ExtFCN[ord] == -1)
222 Perl_croak_nocontext("panic queryaddr");
226 init_PMWIN_entries(void)
228 static HMODULE hpmwin = 0;
229 static const int ords[] = {
230 763, /* Initialize */
231 716, /* CreateMsgQueue */
232 726, /* DestroyMsgQueue */
235 912, /* DispatchMsg */
236 753, /* GetLastError */
237 705, /* CancelShutdown */
245 hpmwin = loadModule("pmwin");
246 while (i < sizeof(ords)/sizeof(int)) {
247 if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL,
248 ((PFN*)&PMWIN_entries)+i)))
249 Perl_croak_nocontext("This version of OS/2 does not support pmwin.%d", ords[i]);
256 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
258 #define QSS_INI_BUFFER 1024
261 get_sysinfo(ULONG pid, ULONG flags)
264 ULONG rc, buf_len = QSS_INI_BUFFER;
266 New(1322, pbuffer, buf_len, char);
267 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
268 rc = QuerySysState(flags, pid, pbuffer, buf_len);
269 while (rc == ERROR_BUFFER_OVERFLOW) {
270 Renew(pbuffer, buf_len *= 2, char);
271 rc = QuerySysState(flags, pid, pbuffer, buf_len);
278 return (PQTOPLEVEL)pbuffer;
281 #define PRIO_ERR 0x1111
289 psi = get_sysinfo(pid, QSS_PROCESS);
293 if (pid != psi->procdata->pid) {
295 Perl_croak_nocontext("panic: wrong pid in sysinfo");
297 prio = psi->procdata->threads->priority;
303 setpriority(int which, int pid, int val)
305 ULONG rc, prio = sys_prio(pid);
307 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
308 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
309 /* Do not change class. */
310 return CheckOSError(DosSetPriority((pid < 0)
311 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
313 (32 - val) % 32 - (prio & 0xFF),
316 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
317 /* Documentation claims one can change both class and basevalue,
318 * but I find it wrong. */
319 /* Change class, but since delta == 0 denotes absolute 0, correct. */
320 if (CheckOSError(DosSetPriority((pid < 0)
321 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
322 priors[(32 - val) >> 5] + 1,
326 if ( ((32 - val) % 32) == 0 ) return 0;
327 return CheckOSError(DosSetPriority((pid < 0)
328 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
334 /* else return CheckOSError(DosSetPriority((pid < 0) */
335 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
336 /* priors[(32 - val) >> 5] + 1, */
337 /* (32 - val) % 32 - (prio & 0xFF), */
343 getpriority(int which /* ignored */, int pid)
347 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
349 if (ret == PRIO_ERR) {
352 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
355 /*****************************************************************************/
358 /* There is no big sense to make it thread-specific, since signals
359 are delivered to thread 1 only. XXXX Maybe make it into an array? */
360 static int spawn_pid;
361 static int spawn_killed;
364 spawn_sighandler(int sig)
366 /* Some programs do not arrange for the keyboard signals to be
367 delivered to them. We need to deliver the signal manually. */
368 /* We may get a signal only if
369 a) kid does not receive keyboard signal: deliver it;
370 b) kid already died, and we get a signal. We may only hope
371 that the pid number was not reused.
375 sig = SIGKILL; /* Try harder. */
376 kill(spawn_pid, sig);
381 result(pTHX_ int flag, int pid)
384 Signal_t (*ihand)(); /* place to save signal during system() */
385 Signal_t (*qhand)(); /* place to save signal during system() */
391 if (pid < 0 || flag != 0)
397 ihand = rsignal(SIGINT, &spawn_sighandler);
398 qhand = rsignal(SIGQUIT, &spawn_sighandler);
400 r = wait4pid(pid, &status, 0);
401 } while (r == -1 && errno == EINTR);
402 rsignal(SIGINT, ihand);
403 rsignal(SIGQUIT, qhand);
405 PL_statusvalue = (U16)status;
408 return status & 0xFFFF;
410 ihand = rsignal(SIGINT, SIG_IGN);
411 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
412 rsignal(SIGINT, ihand);
413 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
416 return PL_statusvalue;
420 #define EXECF_SPAWN 0
422 #define EXECF_TRUEEXEC 2
423 #define EXECF_SPAWN_NOWAIT 3
424 #define EXECF_SPAWN_BYFLAG 4
426 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
435 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
436 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
439 return (pib->pib_ultype);
443 file_type(char *path)
448 if (!(_emx_env & 0x200))
449 Perl_croak_nocontext("file_type not implemented on DOS"); /* not OS/2. */
450 if (CheckOSError(DosQueryAppType(path, &apptype))) {
452 case ERROR_FILE_NOT_FOUND:
453 case ERROR_PATH_NOT_FOUND:
455 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
457 default: /* Found, but not an
458 executable, or some other
466 static ULONG os2_mytype;
468 /* Spawn/exec a program, revert to shell if needed. */
469 /* global PL_Argv[] contains arguments. */
472 do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
477 char buf[256], scrbuf[280];
479 static char * fargs[4]
480 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
481 char **argsp = fargs;
484 int new_stderr = -1, nostderr = 0;
492 if (strEQ(PL_Argv[0],"/bin/sh"))
493 PL_Argv[0] = PL_sh_path;
495 if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\'
496 && !(PL_Argv[0][0] && PL_Argv[0][1] == ':'
497 && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\'))
498 ) /* will spawnvp use PATH? */
499 TAINT_ENV(); /* testing IFS here is overkill, probably */
500 /* We should check PERL_SH* and PERLLIB_* as well? */
501 if (!really || !*(tmps = SvPV(really, n_a)))
506 if (_emx_env & 0x200) { /* OS/2. */
507 int type = file_type(tmps);
509 if (type == -1) { /* Not found */
514 else if (type == -2) { /* Not an EXE */
519 else if (type == -3) { /* Is a directory? */
520 /* Special-case this */
522 int l = strlen(tmps);
524 if (l + 5 <= sizeof tbuf) {
526 strcpy(tbuf + l, ".exe");
527 type = file_type(tbuf);
537 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
538 case FAPPTYP_WINDOWAPI:
540 if (os2_mytype != 3) { /* not PM */
541 if (flag == P_NOWAIT)
543 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
544 Perl_warner(aTHX_ WARN_EXEC, "Starting PM process with flag=%d, mytype=%d",
549 case FAPPTYP_NOTWINDOWCOMPAT:
551 if (os2_mytype != 0) { /* not full screen */
552 if (flag == P_NOWAIT)
554 else if ((flag & 7) != P_SESSION)
555 Perl_warner(aTHX_ WARN_EXEC, "Starting Full Screen process with flag=%d, mytype=%d",
560 case FAPPTYP_NOTSPEC:
561 /* Let the shell handle this... */
570 new_stderr = dup(2); /* Preserve stderr */
571 if (new_stderr == -1) {
579 fl_stderr = fcntl(2, F_GETFD);
583 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
587 rc = result(aTHX_ trueflag, spawnvp(flag,tmps,PL_Argv));
589 if (execf == EXECF_TRUEEXEC)
590 rc = execvp(tmps,PL_Argv);
591 else if (execf == EXECF_EXEC)
592 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
593 else if (execf == EXECF_SPAWN_NOWAIT)
594 rc = spawnvp(flag,tmps,PL_Argv);
595 else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
596 rc = result(aTHX_ trueflag,
597 spawnvp(flag,tmps,PL_Argv));
599 if (rc < 0 && pass == 1
600 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
605 if (err == ENOENT || err == ENOEXEC) {
606 /* No such file, or is a script. */
607 /* Try adding script extensions to the file name, and
609 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
614 char *s = 0, *s1, *s2;
619 if (l >= sizeof scrbuf) {
622 Perl_warner(aTHX_ WARN_EXEC, "Size of scriptname too big: %d", l);
630 file = PerlIO_open(scr, "r");
635 rd = PerlIO_read(file, buf, sizeof buf-1);
637 if ((s2 = strchr(buf, '\n')) != NULL) *++s2 = '\0';
639 if (!rd) { /* Empty... */
642 /* Special case: maybe from -Zexe build, so
643 there is an executable around (contrary to
644 documentation, DosQueryAppType sometimes (?)
645 does not append ".exe", so we could have
646 reached this place). */
647 if (l + 5 < sizeof scrbuf) {
648 strcpy(scrbuf + l, ".exe");
649 if (PerlLIO_stat(scrbuf,&PL_statbuf) >= 0
650 && !S_ISDIR(PL_statbuf.st_mode)) {
660 if (PerlIO_close(file) != 0) { /* Failure */
662 Perl_warner(aTHX_ WARN_EXEC, "Error reading \"%s\": %s",
663 scr, Strerror(errno));
664 buf[0] = 0; /* Not #! */
670 } else if (buf[0] == 'e') {
671 if (strnEQ(buf, "extproc", 7)
674 } else if (buf[0] == 'E') {
675 if (strnEQ(buf, "EXTPROC", 7)
680 buf[0] = 0; /* Not #! */
688 /* Do better than pdksh: allow a few args,
689 strip trailing whitespace. */
699 while (*s && !isSPACE(*s))
706 Perl_warner(aTHX_ WARN_EXEC, "Too many args on %.*s line of \"%s\"",
717 || (!buf[0] && file)) { /* File without magic */
718 /* In fact we tried all what pdksh would
719 try. There is no point in calling
720 pdksh, we may just emulate its logic. */
721 char *shell = getenv("EXECSHELL");
722 char *shell_opt = NULL;
728 shell = getenv("OS2_SHELL");
729 if (inicmd) { /* No spaces at start! */
731 while (*s && !isSPACE(*s)) {
733 inicmd = NULL; /* Cannot use */
741 /* Dosish shells will choke on slashes
742 in paths, fortunately, this is
743 important for zeroth arg only. */
750 /* If EXECSHELL is set, we do not set */
753 shell = ((_emx_env & 0x200)
756 nargs = shell_opt ? 2 : 1; /* shell file args */
757 exec_args[0] = shell;
758 exec_args[1] = shell_opt;
760 if (nargs == 2 && inicmd) {
761 /* Use the original cmd line */
762 /* XXXX This is good only until we refuse
763 quoted arguments... */
767 } else if (!buf[0] && inicmd) { /* No file */
768 /* Start with the original cmdline. */
769 /* XXXX This is good only until we refuse
770 quoted arguments... */
774 nargs = 2; /* shell -c */
777 while (a[1]) /* Get to the end */
779 a++; /* Copy finil NULL too */
780 while (a >= PL_Argv) {
781 *(a + nargs) = *a; /* PL_Argv was preallocated to be
786 PL_Argv[nargs] = argsp[nargs];
787 /* Enable pathless exec if #! (as pdksh). */
788 pass = (buf[0] == '#' ? 2 : 3);
792 /* Not found: restore errno */
796 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
797 char *no_dir = strrchr(PL_Argv[0], '/');
799 /* Do as pdksh port does: if not found with /, try without
802 PL_Argv[0] = no_dir + 1;
807 if (rc < 0 && ckWARN(WARN_EXEC))
808 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s\n",
809 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
811 PL_Argv[0], Strerror(errno));
812 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
813 && ((trueflag & 0xFF) == P_WAIT))
817 if (new_stderr != -1) { /* How can we use error codes? */
820 fcntl(2, F_SETFD, fl_stderr);
826 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
828 do_spawn3(pTHX_ char *cmd, int execf, int flag)
832 char *shell, *copt, *news = NULL;
833 int rc, seenspace = 0, mergestderr = 0;
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 void **vmark, register void **vsp)
955 register SV **mark = (SV **)vmark;
956 register SV **sp = (SV **)vsp;
959 int flag = P_WAIT, flag_set = 0;
963 New(1301,PL_Argv, sp - mark + 3, char*);
966 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
973 while (++mark <= sp) {
975 *a++ = SvPVx(*mark, n_a);
981 if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
982 rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
984 rc = do_spawn_ve(aTHX_ really, flag, EXECF_SPAWN, NULL, 0);
992 os2_do_spawn(pTHX_ char *cmd)
994 return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
998 do_spawn_nowait(pTHX_ char *cmd)
1000 return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
1004 Perl_do_exec(pTHX_ char *cmd)
1006 do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
1011 os2exec(pTHX_ char *cmd)
1013 return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
1017 my_syspopen(pTHX_ char *cmd, char *mode)
1021 register I32 this, that, newfd;
1024 int fh_fl = 0; /* Pacify the warning */
1026 /* `this' is what we use in the parent, `that' in the child. */
1027 this = (*mode == 'w');
1031 taint_proper("Insecure %s%s", "EXEC");
1035 /* Now we need to spawn the child. */
1036 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1037 int new = dup(p[this]);
1044 newfd = dup(*mode == 'r'); /* Preserve std* */
1046 /* This cannot happen due to fh being bad after pipe(), since
1047 pipe() should have created fh 0 and 1 even if they were
1048 initially closed. But we closed p[this] before. */
1049 if (errno != EBADF) {
1056 fh_fl = fcntl(*mode == 'r', F_GETFD);
1057 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1058 dup2(p[that], *mode == 'r');
1061 /* Where is `this' and newfd now? */
1062 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1064 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1065 pid = do_spawn_nowait(aTHX_ cmd);
1067 close(*mode == 'r'); /* It was closed initially */
1068 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1069 dup2(newfd, *mode == 'r'); /* Return std* back. */
1071 fcntl(*mode == 'r', F_SETFD, fh_fl);
1073 fcntl(*mode == 'r', F_SETFD, fh_fl);
1074 if (p[that] == (*mode == 'r'))
1080 if (p[that] < p[this]) { /* Make fh as small as possible */
1081 dup2(p[this], p[that]);
1085 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1086 (void)SvUPGRADE(sv,SVt_IV);
1088 PL_forkprocess = pid;
1089 return PerlIO_fdopen(p[this], mode);
1091 #else /* USE_POPEN */
1097 res = popen(cmd, mode);
1099 char *shell = getenv("EMXSHELL");
1101 my_setenv("EMXSHELL", PL_sh_path);
1102 res = popen(cmd, mode);
1103 my_setenv("EMXSHELL", shell);
1105 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1106 (void)SvUPGRADE(sv,SVt_IV);
1107 SvIVX(sv) = -1; /* A cooky. */
1110 #endif /* USE_POPEN */
1114 /******************************************************************/
1120 Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
1126 /*******************************************************************/
1127 /* not implemented in EMX 0.9d */
1129 char * ctermid(char *s) { return 0; }
1131 #ifdef MYTTYNAME /* was not in emx0.9a */
1132 void * ttyname(x) { return 0; }
1135 /******************************************************************/
1136 /* my socket forwarders - EMX lib only provides static forwarders */
1138 static HMODULE htcp = 0;
1145 if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */
1147 htcp = loadModule("tcp32dll");
1148 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1149 return (void *) ((void * (*)(void)) fcn) ();
1154 tcp1(char *name, int arg)
1156 static BYTE buf[20];
1159 if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */
1161 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1162 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1163 ((void (*)(int)) fcn) (arg);
1166 struct hostent * gethostent() { return tcp0("GETHOSTENT"); }
1167 struct netent * getnetent() { return tcp0("GETNETENT"); }
1168 struct protoent * getprotoent() { return tcp0("GETPROTOENT"); }
1169 struct servent * getservent() { return tcp0("GETSERVENT"); }
1171 void sethostent(x) { tcp1("SETHOSTENT", x); }
1172 void setnetent(x) { tcp1("SETNETENT", x); }
1173 void setprotoent(x) { tcp1("SETPROTOENT", x); }
1174 void setservent(x) { tcp1("SETSERVENT", x); }
1175 void endhostent() { tcp0("ENDHOSTENT"); }
1176 void endnetent() { tcp0("ENDNETENT"); }
1177 void endprotoent() { tcp0("ENDPROTOENT"); }
1178 void endservent() { tcp0("ENDSERVENT"); }
1180 /*****************************************************************************/
1181 /* not implemented in C Set++ */
1184 int setuid(x) { errno = EINVAL; return -1; }
1185 int setgid(x) { errno = EINVAL; return -1; }
1188 /*****************************************************************************/
1189 /* stat() hack for char/block device */
1193 /* First attempt used DosQueryFSAttach which crashed the system when
1194 used with 5.001. Now just look for /dev/. */
1197 os2_stat(const char *name, struct stat *st)
1199 static int ino = SHRT_MAX;
1201 if (stricmp(name, "/dev/con") != 0
1202 && stricmp(name, "/dev/tty") != 0)
1203 return stat(name, st);
1205 memset(st, 0, sizeof *st);
1206 st->st_mode = S_IFCHR|0666;
1207 st->st_ino = (ino-- & 0x7FFF);
1214 #ifdef USE_PERL_SBRK
1216 /* SBRK() emulation, mostly moved to malloc.c. */
1219 sys_alloc(int size) {
1221 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1223 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1226 Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
1230 #endif /* USE_PERL_SBRK */
1234 char *tmppath = TMPPATH1;
1239 char *p = getenv("TMP"), *tpath;
1242 if (!p) p = getenv("TEMP");
1245 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1249 strcpy(tpath + len + 1, TMPPATH1);
1256 XS(XS_File__Copy_syscopy)
1259 if (items < 2 || items > 3)
1260 Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
1263 char * src = (char *)SvPV(ST(0),n_a);
1264 char * dst = (char *)SvPV(ST(1),n_a);
1271 flag = (unsigned long)SvIV(ST(2));
1274 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1275 ST(0) = sv_newmortal();
1276 sv_setiv(ST(0), (IV)RETVAL);
1281 #include "patchlevel.h"
1284 mod2fname(pTHX_ SV *sv)
1286 static char fname[9];
1287 int pos = 6, len, avlen;
1288 unsigned int sum = 0;
1292 if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
1294 if (SvTYPE(sv) != SVt_PVAV)
1295 Perl_croak_nocontext("Not array reference given to mod2fname");
1297 avlen = av_len((AV*)sv);
1299 Perl_croak_nocontext("Empty array reference given to mod2fname");
1301 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1302 strncpy(fname, s, 8);
1304 if (len < 6) pos = len;
1306 sum = 33 * sum + *(s++); /* Checksumming first chars to
1307 * get the capitalization into c.s. */
1310 while (avlen >= 0) {
1311 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1313 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1318 sum++; /* Avoid conflict of DLLs in memory. */
1320 /* We always load modules as *specific* DLLs, and with the full name.
1321 When loading a specific DLL by its full name, one cannot get a
1322 different DLL, even if a DLL with the same basename is loaded already.
1323 Thus there is no need to include the version into the mangling scheme. */
1325 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */
1327 # ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */
1328 # define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2)
1330 sum += COMPATIBLE_VERSION_SUM;
1332 fname[pos] = 'A' + (sum % 26);
1333 fname[pos + 1] = 'A' + (sum / 26 % 26);
1334 fname[pos + 2] = '\0';
1335 return (char *)fname;
1338 XS(XS_DynaLoader_mod2fname)
1342 Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
1347 RETVAL = mod2fname(aTHX_ sv);
1348 ST(0) = sv_newmortal();
1349 sv_setpv((SV*)ST(0), RETVAL);
1357 static char buf[300];
1360 int number = SvTRUE(get_sv("OS2::nsyserror", TRUE));
1362 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1366 sprintf(buf, "SYS%04d=%#x: ", rc, rc);
1367 s = buf + strlen(buf);
1370 if (DosGetMessage(NULL, 0, s, sizeof(buf) - 1 - (s-buf),
1371 rc, "OSO001.MSG", &len)) {
1373 sprintf(buf, "SYS%04d=%#x: ", rc, rc);
1374 s = buf + strlen(buf);
1376 sprintf(s, "[No description found in OSO001.MSG]");
1379 if (len && s[len - 1] == '\n')
1381 if (len && s[len - 1] == '\r')
1383 if (len && s[len - 1] == '.')
1385 if (len >= 10 && number && strnEQ(s, buf, 7)
1386 && s[7] == ':' && s[8] == ' ')
1387 /* Some messages start with SYSdddd:, some not */
1388 Move(s + 9, s, (len -= 9) + 1, char);
1396 char buf[300], *p, *o = PL_origargv[0], ok = 1;
1398 if (_execname(buf, sizeof buf) != 0)
1405 if (ok && *o != '/' && *o != '\\')
1407 } else if (ok && tolower(*o) != tolower(*p))
1412 if (ok) { /* PL_origargv[0] matches the real name. Use PL_origargv[0]: */
1413 strcpy(buf, PL_origargv[0]); /* _execname() is always uppercased */
1427 perllib_mangle(char *s, unsigned int l)
1429 static char *newp, *oldp;
1430 static int newl, oldl, notfound;
1431 static char ret[STATIC_FILE_LENGTH+1];
1433 if (!newp && !notfound) {
1434 newp = getenv("PERLLIB_PREFIX");
1439 while (*newp && !isSPACE(*newp) && *newp != ';') {
1440 newp++; oldl++; /* Skip digits. */
1442 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1443 newp++; /* Skip whitespace. */
1445 newl = strlen(newp);
1446 if (newl == 0 || oldl == 0) {
1447 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1452 if (*s == '\\') *s = '/';
1465 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1468 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1469 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1471 strcpy(ret + newl, s + oldl);
1476 Perl_hab_GET() /* Needed if perl.h cannot be included */
1478 return perl_hab_GET();
1482 Perl_Register_MQ(int serve)
1487 if (Perl_os2_initial_mode++)
1489 DosGetInfoBlocks(&tib, &pib);
1490 Perl_os2_initial_mode = pib->pib_ultype;
1491 /* Try morphing into a PM application. */
1492 if (pib->pib_ultype != 3) /* 2 is VIO */
1493 pib->pib_ultype = 3; /* 3 is PM */
1494 init_PMWIN_entries();
1495 /* 64 messages if before OS/2 3.0, ignored otherwise */
1496 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1500 SAVEINT(cnt); /* Allow catch()ing. */
1502 _exit(188); /* Panic can try to create a window. */
1503 Perl_croak_nocontext("Cannot create a message queue, or morph to a PM application");
1506 if ( Perl_hmq_servers <= 0 /* Safe to inform us on shutdown, */
1507 && Perl_hmq_refcnt > 0 ) /* this was switched off before... */
1508 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 0);
1510 } else if (!Perl_hmq_servers) /* Do not inform us on shutdown */
1511 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
1517 Perl_Serve_Messages(int force)
1522 if (Perl_hmq_servers > 0 && !force)
1524 if (Perl_hmq_refcnt <= 0)
1525 Perl_croak_nocontext("No message queue");
1526 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1528 if (msg.msg == WM_QUIT)
1529 Perl_croak_nocontext("QUITing...");
1530 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1536 Perl_Process_Messages(int force, I32 *cntp)
1540 if (Perl_hmq_servers > 0 && !force)
1542 if (Perl_hmq_refcnt <= 0)
1543 Perl_croak_nocontext("No message queue");
1544 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1547 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1548 if (msg.msg == WM_DESTROY)
1550 if (msg.msg == WM_CREATE)
1553 Perl_croak_nocontext("QUITing...");
1557 Perl_Deregister_MQ(int serve)
1564 if (--Perl_hmq_refcnt <= 0) {
1565 init_PMWIN_entries(); /* To be extra safe */
1566 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1568 /* Try morphing back from a PM application. */
1569 DosGetInfoBlocks(&tib, &pib);
1570 if (pib->pib_ultype == 3) /* 3 is PM */
1571 pib->pib_ultype = Perl_os2_initial_mode;
1573 Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
1575 } else if (serve && Perl_hmq_servers <= 0) /* Last server exited */
1576 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
1579 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1580 && ((path)[2] == '/' || (path)[2] == '\\'))
1581 #define sys_is_rooted _fnisabs
1582 #define sys_is_relative _fnisrel
1583 #define current_drive _getdrive
1585 #undef chdir /* Was _chdir2. */
1586 #define sys_chdir(p) (chdir(p) == 0)
1587 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1589 static int DOS_harderr_state = -1;
1595 Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
1597 int arg1 = SvIV(ST(0));
1598 int arg2 = SvIV(ST(1));
1599 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1600 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1601 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1604 if (CheckOSError(DosError(a)))
1605 Perl_croak_nocontext("DosError(%d) failed", a);
1606 ST(0) = sv_newmortal();
1607 if (DOS_harderr_state >= 0)
1608 sv_setiv(ST(0), DOS_harderr_state);
1609 DOS_harderr_state = RETVAL;
1614 static signed char DOS_suppression_state = -1;
1616 XS(XS_OS2_Errors2Drive)
1620 Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
1624 int suppress = SvOK(sv);
1625 char *s = suppress ? SvPV(sv, n_a) : NULL;
1626 char drive = (s ? *s : 0);
1629 if (suppress && !isALPHA(drive))
1630 Perl_croak_nocontext("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1631 if (CheckOSError(DosSuppressPopUps((suppress
1632 ? SPU_ENABLESUPPRESSION
1633 : SPU_DISABLESUPPRESSION),
1635 Perl_croak_nocontext("DosSuppressPopUps(%c) failed", drive);
1636 ST(0) = sv_newmortal();
1637 if (DOS_suppression_state > 0)
1638 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1639 else if (DOS_suppression_state == 0)
1640 sv_setpvn(ST(0), "", 0);
1641 DOS_suppression_state = drive;
1646 static const char * const si_fields[QSV_MAX] = {
1648 "MAX_TEXT_SESSIONS",
1652 "DYN_PRI_VARIATION",
1670 "FOREGROUND_FS_SESSION",
1671 "FOREGROUND_PROCESS"
1678 Perl_croak_nocontext("Usage: OS2::SysInfo()");
1680 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1681 APIRET rc = NO_ERROR; /* Return code */
1684 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1685 QSV_MAX, /* information */
1688 Perl_croak_nocontext("DosQuerySysInfo() failed");
1689 EXTEND(SP,2*QSV_MAX);
1690 while (i < QSV_MAX) {
1691 ST(j) = sv_newmortal();
1692 sv_setpv(ST(j++), si_fields[i]);
1693 ST(j) = sv_newmortal();
1694 sv_setiv(ST(j++), si[i]);
1698 XSRETURN(2 * QSV_MAX);
1701 XS(XS_OS2_BootDrive)
1705 Perl_croak_nocontext("Usage: OS2::BootDrive()");
1707 ULONG si[1] = {0}; /* System Information Data Buffer */
1708 APIRET rc = NO_ERROR; /* Return code */
1711 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1712 (PVOID)si, sizeof(si))))
1713 Perl_croak_nocontext("DosQuerySysInfo() failed");
1714 ST(0) = sv_newmortal();
1715 c = 'a' - 1 + si[0];
1716 sv_setpvn(ST(0), &c, 1);
1725 Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
1727 bool serve = SvOK(ST(0));
1728 unsigned long pmq = perl_hmq_GET(serve);
1730 ST(0) = sv_newmortal();
1731 sv_setiv(ST(0), pmq);
1736 XS(XS_OS2_UnMorphPM)
1740 Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
1742 bool serve = SvOK(ST(0));
1744 perl_hmq_UNSET(serve);
1749 XS(XS_OS2_Serve_Messages)
1753 Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
1755 bool force = SvOK(ST(0));
1756 unsigned long cnt = Perl_Serve_Messages(force);
1758 ST(0) = sv_newmortal();
1759 sv_setiv(ST(0), cnt);
1764 XS(XS_OS2_Process_Messages)
1767 if (items < 1 || items > 2)
1768 Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
1770 bool force = SvOK(ST(0));
1777 (void)SvIV(sv); /* Force SvIVX */
1779 Perl_croak_nocontext("Can't upgrade count to IV");
1781 cnt = Perl_Process_Messages(force, &cntr);
1784 cnt = Perl_Process_Messages(force, NULL);
1786 ST(0) = sv_newmortal();
1787 sv_setiv(ST(0), cnt);
1792 XS(XS_Cwd_current_drive)
1796 Perl_croak_nocontext("Usage: Cwd::current_drive()");
1800 RETVAL = current_drive();
1801 ST(0) = sv_newmortal();
1802 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1807 XS(XS_Cwd_sys_chdir)
1811 Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
1814 char * path = (char *)SvPV(ST(0),n_a);
1817 RETVAL = sys_chdir(path);
1818 ST(0) = boolSV(RETVAL);
1819 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1824 XS(XS_Cwd_change_drive)
1828 Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
1831 char d = (char)*SvPV(ST(0),n_a);
1834 RETVAL = change_drive(d);
1835 ST(0) = boolSV(RETVAL);
1836 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1841 XS(XS_Cwd_sys_is_absolute)
1845 Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
1848 char * path = (char *)SvPV(ST(0),n_a);
1851 RETVAL = sys_is_absolute(path);
1852 ST(0) = boolSV(RETVAL);
1853 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1858 XS(XS_Cwd_sys_is_rooted)
1862 Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
1865 char * path = (char *)SvPV(ST(0),n_a);
1868 RETVAL = sys_is_rooted(path);
1869 ST(0) = boolSV(RETVAL);
1870 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1875 XS(XS_Cwd_sys_is_relative)
1879 Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
1882 char * path = (char *)SvPV(ST(0),n_a);
1885 RETVAL = sys_is_relative(path);
1886 ST(0) = boolSV(RETVAL);
1887 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1896 Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
1900 RETVAL = _getcwd2(p, MAXPATHLEN);
1901 ST(0) = sv_newmortal();
1902 sv_setpv((SV*)ST(0), RETVAL);
1907 XS(XS_Cwd_sys_abspath)
1910 if (items < 1 || items > 2)
1911 Perl_croak_nocontext("Usage: Cwd::sys_abspath(path, dir = NULL)");
1914 char * path = (char *)SvPV(ST(0),n_a);
1922 dir = (char *)SvPV(ST(1),n_a);
1924 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1928 if (_abspath(p, path, MAXPATHLEN) == 0) {
1934 /* Absolute with drive: */
1935 if ( sys_is_absolute(path) ) {
1936 if (_abspath(p, path, MAXPATHLEN) == 0) {
1941 } else if (path[0] == '/' || path[0] == '\\') {
1942 /* Rooted, but maybe on different drive. */
1943 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1944 char p1[MAXPATHLEN];
1946 /* Need to prepend the drive. */
1949 Copy(path, p1 + 2, strlen(path) + 1, char);
1951 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1956 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1962 /* Either path is relative, or starts with a drive letter. */
1963 /* If the path starts with a drive letter, then dir is
1965 a/b) it is absolute/x:relative on the same drive.
1966 c) path is on current drive, and dir is rooted
1967 In all the cases it is safe to drop the drive part
1969 if ( !sys_is_relative(path) ) {
1970 if ( ( ( sys_is_absolute(dir)
1971 || (isALPHA(dir[0]) && dir[1] == ':'
1972 && strnicmp(dir, path,1) == 0))
1973 && strnicmp(dir, path,1) == 0)
1974 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1975 && toupper(path[0]) == current_drive())) {
1977 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1978 RETVAL = p; goto done;
1980 RETVAL = NULL; goto done;
1984 /* Need to prepend the absolute path of dir. */
1985 char p1[MAXPATHLEN];
1987 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1990 if (p1[ l - 1 ] != '/') {
1994 Copy(path, p1 + l, strlen(path) + 1, char);
1995 if (_abspath(p, p1, MAXPATHLEN) == 0) {
2007 ST(0) = sv_newmortal();
2008 sv_setpv((SV*)ST(0), RETVAL);
2012 typedef APIRET (*PELP)(PSZ path, ULONG type);
2014 /* Kernels after 2000/09/15 understand this too: */
2015 #ifndef LIBPATHSTRICT
2016 # define LIBPATHSTRICT 3
2020 ExtLIBPATH(ULONG ord, PSZ path, IV type)
2024 loadByOrd("doscalls",ord); /* Guarantied to load or die! */
2028 what = BEGIN_LIBPATH;
2030 what = LIBPATHSTRICT;
2031 return (*(PELP)ExtFCN[ord])(path, what);
2034 #define extLibpath(to,type) \
2035 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, (to), (type))) ? NULL : (to) )
2037 #define extLibpath_set(p,type) \
2038 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), (type))))
2040 XS(XS_Cwd_extLibpath)
2043 if (items < 0 || items > 1)
2044 Perl_croak_nocontext("Usage: Cwd::extLibpath(type = 0)");
2057 to[0] = 1; to[1] = 0; /* Sometimes no error reported */
2058 RETVAL = extLibpath(to, type);
2059 if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0)
2060 Perl_croak_nocontext("panic Cwd::extLibpath parameter");
2061 ST(0) = sv_newmortal();
2062 sv_setpv((SV*)ST(0), RETVAL);
2067 XS(XS_Cwd_extLibpath_set)
2070 if (items < 1 || items > 2)
2071 Perl_croak_nocontext("Usage: Cwd::extLibpath_set(s, type = 0)");
2074 char * s = (char *)SvPV(ST(0),n_a);
2085 RETVAL = extLibpath_set(s, type);
2086 ST(0) = boolSV(RETVAL);
2087 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
2092 #define get_control87() _control87(0,0)
2093 #define set_control87 _control87
2095 XS(XS_OS2__control87)
2099 croak("Usage: OS2::_control87(new,mask)");
2101 unsigned new = (unsigned)SvIV(ST(0));
2102 unsigned mask = (unsigned)SvIV(ST(1));
2105 RETVAL = _control87(new, mask);
2106 ST(0) = sv_newmortal();
2107 sv_setiv(ST(0), (IV)RETVAL);
2112 XS(XS_OS2_get_control87)
2116 croak("Usage: OS2::get_control87()");
2120 RETVAL = get_control87();
2121 ST(0) = sv_newmortal();
2122 sv_setiv(ST(0), (IV)RETVAL);
2128 XS(XS_OS2_set_control87)
2131 if (items < 0 || items > 2)
2132 croak("Usage: OS2::set_control87(new=MCW_EM, mask=MCW_EM)");
2141 new = (unsigned)SvIV(ST(0));
2147 mask = (unsigned)SvIV(ST(1));
2150 RETVAL = set_control87(new, mask);
2151 ST(0) = sv_newmortal();
2152 sv_setiv(ST(0), (IV)RETVAL);
2160 char *file = __FILE__;
2164 if (_emx_env & 0x200) { /* OS/2 */
2165 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
2166 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
2167 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
2169 newXS("OS2::Error", XS_OS2_Error, file);
2170 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
2171 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
2172 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
2173 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
2174 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
2175 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
2176 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
2177 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
2178 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
2179 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
2180 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
2181 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
2182 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
2183 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
2184 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
2185 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
2186 newXSproto("OS2::_control87", XS_OS2__control87, file, "$$");
2187 newXSproto("OS2::get_control87", XS_OS2_get_control87, file, "");
2188 newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$");
2189 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
2192 sv_setiv(GvSV(gv), 1);
2194 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
2196 sv_setiv(GvSV(gv), _emx_rev);
2197 sv_setpv(GvSV(gv), _emx_vprt);
2199 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
2201 sv_setiv(GvSV(gv), _emx_env);
2202 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
2204 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
2205 gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV);
2207 sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */
2212 OS2_Perl_data_t OS2_Perl_data;
2215 Perl_OS2_init(char **env)
2221 OS2_Perl_data.xs_init = &Xs_OS2_init;
2222 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
2223 if (environ == NULL && env) {
2226 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
2227 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
2228 strcpy(PL_sh_path, SH_PATH);
2229 PL_sh_path[0] = shell[0];
2230 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
2231 int l = strlen(shell), i;
2232 if (shell[l-1] == '/' || shell[l-1] == '\\') {
2235 New(1304, PL_sh_path, l + 8, char);
2236 strncpy(PL_sh_path, shell, l);
2237 strcpy(PL_sh_path + l, "/sh.exe");
2238 for (i = 0; i < l; i++) {
2239 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
2242 MUTEX_INIT(&start_thread_mutex);
2243 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2244 /* Some DLLs reset FP flags on load. We may have been linked with them */
2245 _control87(MCW_EM, MCW_EM);
2252 my_tmpnam (char *str)
2254 char *p = getenv("TMP"), *tpath;
2256 if (!p) p = getenv("TEMP");
2257 tpath = tempnam(p, "pltmp");
2271 if (s.st_mode & S_IWOTH) {
2274 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2281 my_rmdir (__const__ char *s)
2283 char buf[MAXPATHLEN];
2284 STRLEN l = strlen(s);
2286 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX rmdir fails... */
2297 my_mkdir (__const__ char *s, long perm)
2299 char buf[MAXPATHLEN];
2300 STRLEN l = strlen(s);
2302 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
2307 return mkdir(s, perm);
2312 /* This code was contributed by Rocco Caputo. */
2314 my_flock(int handle, int o)
2316 FILELOCK rNull, rFull;
2317 ULONG timeout, handle_type, flag_word;
2319 int blocking, shared;
2320 static int use_my = -1;
2323 char *s = getenv("USE_PERL_FLOCK");
2329 if (!(_emx_env & 0x200) || !use_my)
2330 return flock(handle, o); /* Delegate to EMX. */
2333 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2334 (handle_type & 0xFF))
2339 // set lock/unlock ranges
2340 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2341 rFull.lRange = 0x7FFFFFFF;
2342 // set timeout for blocking
2343 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2344 // shared or exclusive?
2345 shared = (o & LOCK_SH) ? 1 : 0;
2346 // do not block the unlock
2347 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2348 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2353 case ERROR_INVALID_HANDLE:
2356 case ERROR_SHARING_BUFFER_EXCEEDED:
2359 case ERROR_LOCK_VIOLATION:
2360 break; // not an error
2361 case ERROR_INVALID_PARAMETER:
2362 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2363 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2366 case ERROR_INTERRUPT:
2375 if (o & (LOCK_SH | LOCK_EX)) {
2376 // for blocking operations
2390 case ERROR_INVALID_HANDLE:
2393 case ERROR_SHARING_BUFFER_EXCEEDED:
2396 case ERROR_LOCK_VIOLATION:
2398 errno = EWOULDBLOCK;
2402 case ERROR_INVALID_PARAMETER:
2403 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2404 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2407 case ERROR_INTERRUPT:
2414 // give away timeslice
2423 static int pwent_cnt;
2424 static int _my_pwent = -1;
2429 if (_my_pwent == -1) {
2430 char *s = getenv("USE_PERL_PWENT");
2432 _my_pwent = atoi(s);
2446 if (!use_my_pwent()) {
2447 setpwent(); /* Delegate to EMX. */
2456 if (!use_my_pwent()) {
2457 endpwent(); /* Delegate to EMX. */
2465 if (!use_my_pwent())
2466 return getpwent(); /* Delegate to EMX. */
2468 return 0; // Return one entry only
2472 static int grent_cnt;
2489 return 0; // Return one entry only
2496 /* Too long to be a crypt() of anything, so it is not-a-valid pw_passwd. */
2497 static const char pw_p[] = "Jf0Wb/BzMFvk7K7lrzK";
2499 static struct passwd *
2500 passw_wrap(struct passwd *p)
2502 static struct passwd pw;
2505 if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
2508 s = getenv("PW_PASSWD");
2510 s = (char*)pw_p; /* Make match impossible */
2517 my_getpwuid (uid_t id)
2519 return passw_wrap(getpwuid(id));
2523 my_getpwnam (__const__ char *n)
2525 return passw_wrap(getpwnam(n));