3 #define INCL_DOSFILEMGR
9 * Various Unix compatibility functions for OS/2
20 /*****************************************************************************/
22 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
24 #define QSS_INI_BUFFER 1024
27 get_sysinfo(ULONG pid, ULONG flags)
30 ULONG rc, buf_len = QSS_INI_BUFFER;
32 New(1022, pbuffer, buf_len, char);
33 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
34 rc = QuerySysState(flags, pid, pbuffer, buf_len);
35 while (rc == ERROR_BUFFER_OVERFLOW) {
36 Renew(pbuffer, buf_len *= 2, char);
37 rc = QuerySysState(QSS_PROCESS, pid, pbuffer, buf_len);
44 return (PQTOPLEVEL)pbuffer;
47 #define PRIO_ERR 0x1111
55 psi = get_sysinfo(pid, QSS_PROCESS);
59 if (pid != psi->procdata->pid) {
61 croak("panic: wrong pid in sysinfo");
63 prio = psi->procdata->threads->priority;
69 setpriority(int which, int pid, int val)
76 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
77 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
78 /* Do not change class. */
79 return CheckOSError(DosSetPriority((pid < 0)
80 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
82 (32 - val) % 32 - (prio & 0xFF),
85 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
86 /* Documentation claims one can change both class and basevalue,
87 * but I find it wrong. */
88 /* Change class, but since delta == 0 denotes absolute 0, correct. */
89 if (CheckOSError(DosSetPriority((pid < 0)
90 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
91 priors[(32 - val) >> 5] + 1,
95 if ( ((32 - val) % 32) == 0 ) return 0;
96 return CheckOSError(DosSetPriority((pid < 0)
97 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
103 /* else return CheckOSError(DosSetPriority((pid < 0) */
104 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
105 /* priors[(32 - val) >> 5] + 1, */
106 /* (32 - val) % 32 - (prio & 0xFF), */
112 getpriority(int which /* ignored */, int pid)
118 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
119 /* DosGetInfoBlocks has old priority! */
120 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
121 /* if (pid != pib->pib_ulpid) { */
123 if (ret == PRIO_ERR) {
127 /* ret = tib->tib_ptib2->tib2_ulpri; */
128 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
131 /*****************************************************************************/
135 result(int flag, int pid)
138 Signal_t (*ihand)(); /* place to save signal during system() */
139 Signal_t (*qhand)(); /* place to save signal during system() */
145 if (pid < 0 || flag != 0)
149 ihand = signal(SIGINT, SIG_IGN);
150 qhand = signal(SIGQUIT, SIG_IGN);
152 r = wait4pid(pid, &status, 0);
153 } while (r == -1 && errno == EINTR);
154 signal(SIGINT, ihand);
155 signal(SIGQUIT, qhand);
157 statusvalue = (U16)status;
160 return status & 0xFFFF;
162 ihand = signal(SIGINT, SIG_IGN);
163 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
164 signal(SIGINT, ihand);
165 statusvalue = res.codeResult << 8 | res.codeTerminate;
173 do_aspawn(really,mark,sp)
181 int flag = P_WAIT, trueflag;
184 New(401,Argv, sp - mark + 1, char*);
187 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
192 while (++mark <= sp) {
194 *a++ = SvPVx(*mark, na);
204 if (strEQ(Argv[0],"/bin/sh")) Argv[0] = SH_PATH;
206 if (Argv[0][0] != '/' && Argv[0][0] != '\\'
207 && !(Argv[0][0] && Argv[0][1] == ':'
208 && (Argv[0][2] == '/' || Argv[0][2] != '\\'))
209 ) /* will swawnvp use PATH? */
210 TAINT_ENV(); /* testing IFS here is overkill, probably */
211 /* We should check PERL_SH* and PERLLIB_* as well? */
212 if (really && *(tmps = SvPV(really, na)))
213 rc = result(trueflag, spawnvp(flag,tmps,Argv));
215 rc = result(trueflag, spawnvp(flag,Argv[0],Argv));
217 if (rc < 0 && dowarn)
218 warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
219 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
226 #define EXECF_SPAWN 0
228 #define EXECF_TRUEEXEC 2
231 do_spawn2(cmd, execf)
238 char *shell, *copt, *news = NULL;
242 if ((shell = getenv("EMXSHELL")) != NULL)
244 else if ((shell = getenv("SHELL")) != NULL)
246 else if ((shell = getenv("COMSPEC")) != NULL)
251 /* Consensus on perl5-porters is that it is _very_ important to
252 have a shell which will not change between computers with the
253 same architecture, to avoid "action on a distance".
254 And to have simple build, this shell should be sh. */
259 while (*cmd && isSPACE(*cmd))
262 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
263 STRLEN l = strlen(SH_PATH);
265 New(4545, news, strlen(cmd) - 7 + l, char);
266 strcpy(news, SH_PATH);
267 strcpy(news + l, cmd + 7);
271 /* save an extra exec if possible */
272 /* see if there are shell metacharacters in it */
274 if (*cmd == '.' && isSPACE(cmd[1]))
277 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
280 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
284 for (s = cmd; *s; s++) {
285 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
286 if (*s == '\n' && s[1] == '\0') {
291 if (execf == EXECF_TRUEEXEC)
292 return execl(shell,shell,copt,cmd,(char*)0);
293 else if (execf == EXECF_EXEC)
294 return spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
295 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
297 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
298 if (rc < 0 && dowarn)
299 warn("Can't %s \"%s\": %s",
300 (execf == EXECF_SPAWN ? "spawn" : "exec"),
301 shell, Strerror(errno));
302 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
303 if (news) Safefree(news);
308 New(402,Argv, (s - cmd) / 2 + 2, char*);
309 Cmd = savepvn(cmd, s-cmd);
312 while (*s && isSPACE(*s)) s++;
315 while (*s && !isSPACE(*s)) s++;
321 if (execf == EXECF_TRUEEXEC)
322 rc = execvp(Argv[0],Argv);
323 else if (execf == EXECF_EXEC)
324 rc = spawnvp(P_OVERLAY,Argv[0],Argv);
326 rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv));
327 if (rc < 0 && dowarn)
328 warn("Can't %s \"%s\": %s",
329 (execf == EXECF_SPAWN ? "spawn" : "exec"),
330 Argv[0], Strerror(errno));
331 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
334 if (news) Safefree(news);
343 return do_spawn2(cmd, EXECF_SPAWN);
350 return do_spawn2(cmd, EXECF_EXEC);
357 return do_spawn2(cmd, EXECF_TRUEEXEC);
361 my_syspopen(cmd,mode)
369 res = popen(cmd, mode);
371 char *shell = getenv("EMXSHELL");
373 my_setenv("EMXSHELL", SH_PATH);
374 res = popen(cmd, mode);
375 my_setenv("EMXSHELL", shell);
377 sv = *av_fetch(fdpid, PerlIO_fileno(res), TRUE);
378 (void)SvUPGRADE(sv,SVt_IV);
379 SvIVX(sv) = -1; /* A cooky. */
383 /******************************************************************/
389 die(no_func, "Unsupported function fork");
395 /*******************************************************************/
396 /* not implemented in EMX 0.9a */
398 void * ctermid(x) { return 0; }
400 #ifdef MYTTYNAME /* was not in emx0.9a */
401 void * ttyname(x) { return 0; }
404 /******************************************************************/
405 /* my socket forwarders - EMX lib only provides static forwarders */
407 static HMODULE htcp = 0;
415 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
417 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
418 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
419 return (void *) ((void * (*)(void)) fcn) ();
424 tcp1(char *name, int arg)
429 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
431 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
432 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
433 ((void (*)(int)) fcn) (arg);
436 void * gethostent() { return tcp0("GETHOSTENT"); }
437 void * getnetent() { return tcp0("GETNETENT"); }
438 void * getprotoent() { return tcp0("GETPROTOENT"); }
439 void * getservent() { return tcp0("GETSERVENT"); }
440 void sethostent(x) { tcp1("SETHOSTENT", x); }
441 void setnetent(x) { tcp1("SETNETENT", x); }
442 void setprotoent(x) { tcp1("SETPROTOENT", x); }
443 void setservent(x) { tcp1("SETSERVENT", x); }
444 void endhostent() { tcp0("ENDHOSTENT"); }
445 void endnetent() { tcp0("ENDNETENT"); }
446 void endprotoent() { tcp0("ENDPROTOENT"); }
447 void endservent() { tcp0("ENDSERVENT"); }
449 /*****************************************************************************/
450 /* not implemented in C Set++ */
453 int setuid(x) { errno = EINVAL; return -1; }
454 int setgid(x) { errno = EINVAL; return -1; }
457 /*****************************************************************************/
458 /* stat() hack for char/block device */
462 /* First attempt used DosQueryFSAttach which crashed the system when
463 used with 5.001. Now just look for /dev/. */
466 os2_stat(char *name, struct stat *st)
468 static int ino = SHRT_MAX;
470 if (stricmp(name, "/dev/con") != 0
471 && stricmp(name, "/dev/tty") != 0)
472 return stat(name, st);
474 memset(st, 0, sizeof *st);
475 st->st_mode = S_IFCHR|0666;
476 st->st_ino = (ino-- & 0x7FFF);
485 /* SBRK() emulation, mostly moved to malloc.c. */
488 sys_alloc(int size) {
490 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
492 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
494 } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
498 #endif /* USE_PERL_SBRK */
502 char *tmppath = TMPPATH1;
507 char *p = getenv("TMP"), *tpath;
510 if (!p) p = getenv("TEMP");
513 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
516 strcpy(tpath + len + 1, TMPPATH1);
522 XS(XS_File__Copy_syscopy)
525 if (items < 2 || items > 3)
526 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
528 char * src = (char *)SvPV(ST(0),na);
529 char * dst = (char *)SvPV(ST(1),na);
536 flag = (unsigned long)SvIV(ST(2));
539 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
540 ST(0) = sv_newmortal();
541 sv_setiv(ST(0), (IV)RETVAL);
550 static char fname[9];
551 int pos = 6, len, avlen;
552 unsigned int sum = 0;
557 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
559 if (SvTYPE(sv) != SVt_PVAV)
560 croak("Not array reference given to mod2fname");
562 avlen = av_len((AV*)sv);
564 croak("Empty array reference given to mod2fname");
566 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
567 strncpy(fname, s, 8);
569 if (len < 6) pos = len;
571 sum = 33 * sum + *(s++); /* Checksumming first chars to
572 * get the capitalization into c.s. */
576 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
578 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
582 fname[pos] = 'A' + (sum % 26);
583 fname[pos + 1] = 'A' + (sum / 26 % 26);
584 fname[pos + 2] = '\0';
585 return (char *)fname;
588 XS(XS_DynaLoader_mod2fname)
592 croak("Usage: DynaLoader::mod2fname(sv)");
597 RETVAL = mod2fname(sv);
598 ST(0) = sv_newmortal();
599 sv_setpv((SV*)ST(0), RETVAL);
607 static char buf[300];
610 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
613 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
614 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
620 char sh_path[STATIC_FILE_LENGTH+1] = SH_PATH_INI;
623 perllib_mangle(char *s, unsigned int l)
625 static char *newp, *oldp;
626 static int newl, oldl, notfound;
627 static char ret[STATIC_FILE_LENGTH+1];
629 if (!newp && !notfound) {
630 newp = getenv("PERLLIB_PREFIX");
633 while (*newp && !isSPACE(*newp) && *newp != ';') {
634 newp++; oldl++; /* Skip digits. */
636 while (*newp && (isSPACE(*newp) || *newp == ';')) {
637 newp++; /* Skip whitespace. */
640 if (newl == 0 || oldl == 0) {
641 die("Malformed PERLLIB_PREFIX");
653 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
656 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
657 die("Malformed PERLLIB_PREFIX");
659 strncpy(ret, newp, newl);
660 strcpy(ret + newl, s + oldl);
664 extern void dlopen();
665 void *fakedl = &dlopen; /* Pull in dynaloading part. */
667 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
668 && ((path)[2] == '/' || (path)[2] == '\\'))
669 #define sys_is_rooted _fnisabs
670 #define sys_is_relative _fnisrel
671 #define current_drive _getdrive
673 #undef chdir /* Was _chdir2. */
674 #define sys_chdir(p) (chdir(p) == 0)
675 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
677 XS(XS_Cwd_current_drive)
681 croak("Usage: Cwd::current_drive()");
685 RETVAL = current_drive();
686 ST(0) = sv_newmortal();
687 sv_setpvn(ST(0), (char *)&RETVAL, 1);
696 croak("Usage: Cwd::sys_chdir(path)");
698 char * path = (char *)SvPV(ST(0),na);
701 RETVAL = sys_chdir(path);
702 ST(0) = RETVAL ? &sv_yes : &sv_no;
703 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
708 XS(XS_Cwd_change_drive)
712 croak("Usage: Cwd::change_drive(d)");
714 char d = (char)*SvPV(ST(0),na);
717 RETVAL = change_drive(d);
718 ST(0) = RETVAL ? &sv_yes : &sv_no;
719 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
724 XS(XS_Cwd_sys_is_absolute)
728 croak("Usage: Cwd::sys_is_absolute(path)");
730 char * path = (char *)SvPV(ST(0),na);
733 RETVAL = sys_is_absolute(path);
734 ST(0) = RETVAL ? &sv_yes : &sv_no;
735 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
740 XS(XS_Cwd_sys_is_rooted)
744 croak("Usage: Cwd::sys_is_rooted(path)");
746 char * path = (char *)SvPV(ST(0),na);
749 RETVAL = sys_is_rooted(path);
750 ST(0) = RETVAL ? &sv_yes : &sv_no;
751 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
756 XS(XS_Cwd_sys_is_relative)
760 croak("Usage: Cwd::sys_is_relative(path)");
762 char * path = (char *)SvPV(ST(0),na);
765 RETVAL = sys_is_relative(path);
766 ST(0) = RETVAL ? &sv_yes : &sv_no;
767 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
776 croak("Usage: Cwd::sys_cwd()");
780 RETVAL = _getcwd2(p, MAXPATHLEN);
781 ST(0) = sv_newmortal();
782 sv_setpv((SV*)ST(0), RETVAL);
787 XS(XS_Cwd_sys_abspath)
790 if (items < 1 || items > 2)
791 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
793 char * path = (char *)SvPV(ST(0),na);
801 dir = (char *)SvPV(ST(1),na);
803 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
807 if (_abspath(p, path, MAXPATHLEN) == 0) {
813 /* Absolute with drive: */
814 if ( sys_is_absolute(path) ) {
815 if (_abspath(p, path, MAXPATHLEN) == 0) {
820 } else if (path[0] == '/' || path[0] == '\\') {
821 /* Rooted, but maybe on different drive. */
822 if (isALPHA(dir[0]) && dir[1] == ':' ) {
825 /* Need to prepend the drive. */
828 Copy(path, p1 + 2, strlen(path) + 1, char);
830 if (_abspath(p, p1, MAXPATHLEN) == 0) {
835 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
841 /* Either path is relative, or starts with a drive letter. */
842 /* If the path starts with a drive letter, then dir is
844 a/b) it is absolute/x:relative on the same drive.
845 c) path is on current drive, and dir is rooted
846 In all the cases it is safe to drop the drive part
848 if ( !sys_is_relative(path) ) {
851 if ( ( ( sys_is_absolute(dir)
852 || (isALPHA(dir[0]) && dir[1] == ':'
853 && strnicmp(dir, path,1) == 0))
854 && strnicmp(dir, path,1) == 0)
855 || ( !(isALPHA(dir[0]) && dir[1] == ':')
856 && toupper(path[0]) == current_drive())) {
858 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
859 RETVAL = p; goto done;
861 RETVAL = NULL; goto done;
865 /* Need to prepend the absolute path of dir. */
868 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
871 if (p1[ l - 1 ] != '/') {
875 Copy(path, p1 + l, strlen(path) + 1, char);
876 if (_abspath(p, p1, MAXPATHLEN) == 0) {
888 ST(0) = sv_newmortal();
889 sv_setpv((SV*)ST(0), RETVAL);
894 #define extLibpath(type) \
895 (CheckOSError(DosQueryExtLIBPATH(to, ((type) ? END_LIBPATH \
899 #define extLibpath_set(p,type) \
900 (!CheckOSError(DosSetExtLIBPATH((p), ((type) ? END_LIBPATH \
903 XS(XS_Cwd_extLibpath)
906 if (items < 0 || items > 1)
907 croak("Usage: Cwd::extLibpath(type = 0)");
917 type = (int)SvIV(ST(0));
920 RETVAL = extLibpath(type);
921 ST(0) = sv_newmortal();
922 sv_setpv((SV*)ST(0), RETVAL);
927 XS(XS_Cwd_extLibpath_set)
930 if (items < 1 || items > 2)
931 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
933 char * s = (char *)SvPV(ST(0),na);
941 type = (int)SvIV(ST(1));
944 RETVAL = extLibpath_set(s, type);
945 ST(0) = RETVAL ? &sv_yes : &sv_no;
946 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
954 char *file = __FILE__;
958 if (_emx_env & 0x200) { /* OS/2 */
959 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
960 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
961 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
963 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
964 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
965 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
966 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
967 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
968 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
969 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
970 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
971 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
972 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
975 sv_setiv(GvSV(gv), 1);
980 OS2_Perl_data_t OS2_Perl_data;
988 OS2_Perl_data.xs_init = &Xs_OS2_init;
989 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
990 sh_path[0] = shell[0];
991 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
992 int l = strlen(shell);
993 if (shell[l-1] == '/' || shell[l-1] == '\\') {
996 if (l > STATIC_FILE_LENGTH - 7) {
997 die("PERL_SH_DIR too long");
999 strncpy(sh_path, shell, l);
1000 strcpy(sh_path + l, "/sh.exe");
1008 my_tmpnam (char *str)
1010 char *p = getenv("TMP"), *tpath;
1013 if (!p) p = getenv("TEMP");
1014 tpath = tempnam(p, "pltmp");
1028 if (s.st_mode & S_IWOTH) {
1031 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but