This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
amigaos4: use raise() instead of kill() on ourselves
[perl5.git] / amigaos4 / amigaos.c
CommitLineData
a83a2cd1
AB
1/* amigaos.c uses only amigaos APIs,
2 * as opposed to amigaio.c which mixes amigaos and perl APIs */
3
4#include <string.h>
5
6#include <sys/stat.h>
7#include <unistd.h>
8#include <assert.h>
9
10#include <errno.h>
11#include <stdio.h>
12#include <stdlib.h>
13#if defined(__CLIB2__)
14# include <dos.h>
15#endif
16#if defined(__NEWLIB__)
17# include <amiga_platform.h>
18#endif
19#include <fcntl.h>
20#include <ctype.h>
21#include <stdarg.h>
738ab09f
AB
22#include <stdbool.h>
23#undef WORD
24#define WORD int16
a83a2cd1
AB
25
26#include <dos/dos.h>
27#include <proto/dos.h>
28#include <proto/exec.h>
29#include <proto/utility.h>
30
31#include "amigaos.h"
32
33struct UtilityIFace *IUtility = NULL;
34
35/***************************************************************************/
36
37struct Interface *OpenInterface(CONST_STRPTR libname, uint32 libver)
38{
6c47084d
JH
39 struct Library *base = IExec->OpenLibrary(libname, libver);
40 struct Interface *iface = IExec->GetInterface(base, "main", 1, NULL);
41 if (iface == NULL)
42 {
43 // We should probably post some kind of error message here.
a83a2cd1 44
6c47084d
JH
45 IExec->CloseLibrary(base);
46 }
a83a2cd1 47
6c47084d 48 return iface;
a83a2cd1
AB
49}
50
51/***************************************************************************/
52
53void CloseInterface(struct Interface *iface)
54{
6c47084d
JH
55 if (iface != NULL)
56 {
57 struct Library *base = iface->Data.LibBase;
58 IExec->DropInterface(iface);
59 IExec->CloseLibrary(base);
60 }
a83a2cd1
AB
61}
62
63BOOL __unlink_retries = FALSE;
64
65void ___makeenviron() __attribute__((constructor));
66void ___freeenviron() __attribute__((destructor));
67
68void ___openinterfaces() __attribute__((constructor));
69void ___closeinterfaces() __attribute__((destructor));
70
71void ___openinterfaces()
72{
6c47084d
JH
73 if (!IDOS)
74 IDOS = (struct DOSIFace *)OpenInterface("dos.library", 53);
75 if (!IUtility)
76 IUtility =
77 (struct UtilityIFace *)OpenInterface("utility.library", 53);
a83a2cd1
AB
78}
79
80void ___closeinterfaces()
81{
6c47084d
JH
82 CloseInterface((struct Interface *)IDOS);
83 CloseInterface((struct Interface *)IUtility);
a83a2cd1
AB
84}
85int VARARGS68K araddebug(UBYTE *fmt, ...);
86int VARARGS68K adebug(UBYTE *fmt, ...);
87
88#define __USE_RUNCOMMAND__
89
90char **myenviron = NULL;
91char **origenviron = NULL;
92
a83a2cd1
AB
93static void createvars(char **envp);
94
95struct args
96{
6c47084d
JH
97 BPTR seglist;
98 int stack;
99 char *command;
100 int length;
101 int result;
102 char **envp;
a83a2cd1
AB
103};
104
105int __myrc(char *arg)
106{
6c47084d
JH
107 struct Task *thisTask = IExec->FindTask(0);
108 struct args *myargs = (struct args *)thisTask->tc_UserData;
109 if (myargs->envp)
110 createvars(myargs->envp);
111 // adebug("%s %ld %s \n",__FUNCTION__,__LINE__,myargs->command);
112 myargs->result = IDOS->RunCommand(myargs->seglist, myargs->stack,
113 myargs->command, myargs->length);
114 return 0;
a83a2cd1
AB
115}
116
117int32 myruncommand(
118 BPTR seglist, int stack, char *command, int length, char **envp)
119{
6c47084d
JH
120 struct args myargs;
121 struct Task *thisTask = IExec->FindTask(0);
122 struct Process *proc;
123
124 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
125
126 myargs.seglist = seglist;
127 myargs.stack = stack;
128 myargs.command = command;
129 myargs.length = length;
130 myargs.result = -1;
131 myargs.envp = envp;
132
133 if ((proc = IDOS->CreateNewProcTags(
134 NP_Entry, __myrc, NP_Child, TRUE, NP_Input, IDOS->Input(),
135 NP_Output, IDOS->Output(), NP_Error, IDOS->ErrorOutput(),
136 NP_CloseInput, FALSE, NP_CloseOutput, FALSE, NP_CloseError,
137 FALSE, NP_CopyVars, FALSE,
138
139 // NP_StackSize, ((struct Process
140 // *)myargs.parent)->pr_StackSize,
141 NP_Cli, TRUE, NP_UserData, (int)&myargs,
142 NP_NotifyOnDeathSigTask, thisTask, TAG_DONE)))
143
144 {
145 IExec->Wait(SIGF_CHILD);
146 }
147 return myargs.result;
a83a2cd1
AB
148}
149
738ab09f 150char *mystrdup(const char *s)
a83a2cd1 151{
6c47084d
JH
152 char *result = NULL;
153 size_t size;
a83a2cd1 154
6c47084d 155 size = strlen(s) + 1;
a83a2cd1 156
6c47084d
JH
157 if ((result = (char *)IExec->AllocVec(size, MEMF_ANY)))
158 {
159 memmove(result, s, size);
160 }
161 return result;
a83a2cd1
AB
162}
163
164static int pipenum = 0;
165
166int pipe(int filedes[2])
167{
6c47084d 168 char pipe_name[1024];
a83a2cd1
AB
169
170// adebug("%s %ld \n",__FUNCTION__,__LINE__);
171#ifdef USE_TEMPFILES
6c47084d 172 sprintf(pipe_name, "/T/%x.%08lx", pipenum++, IUtility->GetUniqueID());
a83a2cd1 173#else
6c47084d
JH
174 sprintf(pipe_name, "/PIPE/%x%08lx/4096/0", pipenum++,
175 IUtility->GetUniqueID());
a83a2cd1
AB
176#endif
177
6c47084d
JH
178 /* printf("pipe: %s \n", pipe_name);*/
179
180 filedes[1] = open(pipe_name, O_WRONLY | O_CREAT);
181 filedes[0] = open(pipe_name, O_RDONLY);
182 if (filedes[0] == -1 || filedes[1] == -1)
183 {
184 if (filedes[0] != -1)
185 close(filedes[0]);
186 if (filedes[1] != -1)
187 close(filedes[1]);
188 return -1;
189 }
190 /* printf("filedes %d %d\n", filedes[0],
191 * filedes[1]);fflush(stdout);*/
192
193 return 0;
a83a2cd1
AB
194}
195
196int fork(void)
197{
6c47084d
JH
198 fprintf(stderr, "Can not bloody fork\n");
199 errno = ENOMEM;
200 return -1;
a83a2cd1
AB
201}
202
203int wait(int *status)
204{
6c47084d
JH
205 fprintf(stderr, "No wait try waitpid instead\n");
206 errno = ECHILD;
207 return -1;
a83a2cd1
AB
208}
209
210char *convert_path_a2u(const char *filename)
211{
6c47084d 212 struct NameTranslationInfo nti;
a83a2cd1 213
6c47084d
JH
214 if (!filename)
215 {
216 return 0;
217 }
a83a2cd1 218
6c47084d 219 __translate_amiga_to_unix_path_name(&filename, &nti);
a83a2cd1 220
6c47084d 221 return mystrdup(filename);
a83a2cd1
AB
222}
223char *convert_path_u2a(const char *filename)
224{
6c47084d 225 struct NameTranslationInfo nti;
a83a2cd1 226
6c47084d
JH
227 if (!filename)
228 {
229 return 0;
230 }
a83a2cd1 231
6c47084d
JH
232 if (strcmp(filename, "/dev/tty") == 0)
233 {
234 return mystrdup("CONSOLE:");
235 ;
236 }
a83a2cd1 237
6c47084d 238 __translate_unix_to_amiga_path_name(&filename, &nti);
a83a2cd1 239
6c47084d 240 return mystrdup(filename);
a83a2cd1
AB
241}
242
243static struct SignalSemaphore environ_sema;
244
6c47084d
JH
245void amigaos4_init_environ_sema()
246{
247 IExec->InitSemaphore(&environ_sema);
248}
a83a2cd1 249
6c47084d
JH
250void amigaos4_obtain_environ()
251{
252 IExec->ObtainSemaphore(&environ_sema);
253}
a83a2cd1 254
6c47084d
JH
255void amigaos4_release_environ()
256{
257 IExec->ReleaseSemaphore(&environ_sema);
258}
a83a2cd1
AB
259
260static void createvars(char **envp)
261{
6c47084d
JH
262 if (envp)
263 {
264 /* Set a local var to indicate to any subsequent sh that it is
265 * not
266 * the top level shell and so should only inherit local amigaos
267 * vars */
268 IDOS->SetVar("ABCSH_IMPORT_LOCAL", "TRUE", 5, GVF_LOCAL_ONLY);
269
270 amigaos4_obtain_environ();
271
272 envp = myenviron;
273
274 while ((envp != NULL) && (*envp != NULL))
275 {
276 int len;
277 char *var;
278 char *val;
279 if ((len = strlen(*envp)))
280 {
281 if ((var = (char *)IExec->AllocVec(
282 len + 1, MEMF_ANY | MEMF_CLEAR)))
283 {
284 strcpy(var, *envp);
285
286 val = strchr(var, '=');
287 if (val)
288 {
289 *val++ = '\0';
290 if (*val)
291 {
292 IDOS->SetVar(
293 var, val,
294 strlen(val) + 1,
295 GVF_LOCAL_ONLY);
296 }
297 }
298 IExec->FreeVec(var);
299 }
300 }
301 envp++;
302 }
303 amigaos4_release_environ();
304 }
a83a2cd1
AB
305}
306
307static BOOL contains_whitespace(char *string)
308{
309
6c47084d
JH
310 if (string)
311 {
312
313 if (strchr(string, ' '))
314 return TRUE;
315 if (strchr(string, '\t'))
316 return TRUE;
317 if (strchr(string, '\n'))
318 return TRUE;
319 if (strchr(string, 0xA0))
320 return TRUE;
321 if (strchr(string, '"'))
322 return TRUE;
323 }
324 return FALSE;
a83a2cd1
AB
325}
326
327static int no_of_escapes(char *string)
328{
6c47084d
JH
329 int cnt = 0;
330 char *p;
331 for (p = string; p < string + strlen(string); p++)
332 {
333 if (*p == '"')
334 cnt++;
335 if (*p == '*')
336 cnt++;
337 if (*p == '\n')
338 cnt++;
339 if (*p == '\t')
340 cnt++;
341 }
342 return cnt;
a83a2cd1
AB
343}
344
345struct command_data
346{
6c47084d
JH
347 STRPTR args;
348 BPTR seglist;
349 struct Task *parent;
a83a2cd1
AB
350};
351
738ab09f 352int myexecvp(bool isperlthread, const char *filename, char *argv[])
a83a2cd1 353{
6c47084d
JH
354 // adebug("%s %ld
355 //%s\n",__FUNCTION__,__LINE__,filename?filename:"NULL");
356 /* if there's a slash or a colon consider filename a path and skip
357 * search */
358 int res;
359 if ((strchr(filename, '/') == NULL) && (strchr(filename, ':') == NULL))
360 {
361 char *path;
362 char *name;
363 char *pathpart;
364 char *p;
365 size_t len;
366 struct stat st;
367
368 if (!(path = getenv("PATH")))
369 {
370 path = ".:/bin:/usr/bin:/c";
371 }
372
373 len = strlen(filename) + 1;
374 name = (char *)alloca(strlen(path) + len);
375 pathpart = (char *)alloca(strlen(path) + 1);
376 p = path;
377 do
378 {
379 path = p;
380
381 if (!(p = strchr(path, ':')))
382 {
383 p = strchr(path, '\0');
384 }
385
386 memcpy(pathpart, path, p - path);
387 pathpart[p - path] = '\0';
388 if (!(strlen(pathpart) == 0))
389 {
390 sprintf(name, "%s/%s", pathpart, filename);
391 }
392 else
393 sprintf(name, "%s", filename);
394
395 if ((stat(name, &st) == 0) && (S_ISREG(st.st_mode)))
396 {
397 /* we stated it and it's a regular file */
398 /* let's boogie! */
399 filename = name;
400 break;
401 }
402
403 }
404 while (*p++ != '\0');
405 }
406 res = myexecve(isperlthread, filename, argv, myenviron);
407 return res;
a83a2cd1
AB
408}
409
738ab09f 410int myexecv(bool isperlthread, const char *path, char *argv[])
a83a2cd1 411{
6c47084d 412 return myexecve(isperlthread, path, argv, myenviron);
a83a2cd1
AB
413}
414
738ab09f 415int myexecl(bool isperlthread, const char *path, ...)
a83a2cd1 416{
6c47084d
JH
417 va_list va;
418 char *argv[1024]; /* 1024 enough? let's hope so! */
419 int i = 0;
420 // adebug("%s %ld\n",__FUNCTION__,__LINE__);
421
422 va_start(va, path);
423 i = 0;
424
425 do
426 {
427 argv[i] = va_arg(va, char *);
428 }
429 while (argv[i++] != NULL);
430
431 va_end(va);
432 return myexecve(isperlthread, path, argv, myenviron);
a83a2cd1
AB
433}
434
738ab09f
AB
435#if 0
436
a83a2cd1
AB
437int myexecve(const char *filename, char *argv[], char *envp[])
438{
6c47084d
JH
439 FILE *fh;
440 char buffer[1000];
441 int size = 0;
442 char **cur;
443 char *interpreter = 0;
444 char *interpreter_args = 0;
445 char *full = 0;
446 char *filename_conv = 0;
447 char *interpreter_conv = 0;
448 // char *tmp = 0;
449 char *fname;
450 // int tmpint;
451 // struct Task *thisTask = IExec->FindTask(0);
452 int result = -1;
453
454 StdioStore store;
455
456 dTHX;
457 if(aTHX) // I hope this is NULL when not on a interpreteer thread nor to level.
458 {
459 /* Save away our stdio */
460 amigaos_stdio_save(aTHX_ & store);
461 }
462
463 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,filename?filename:"NULL");
464
465 /* Calculate the size of filename and all args, including spaces and
466 * quotes */
467 size = 0; // strlen(filename) + 1;
468 for (cur = (char **)argv /* +1 */; *cur; cur++)
469 {
470 size +=
471 strlen(*cur) + 1 +
472 (contains_whitespace(*cur) ? (2 + no_of_escapes(*cur)) : 0);
473 }
474 /* Check if it's a script file */
475
476 fh = fopen(filename, "r");
477 if (fh)
478 {
479 if (fgetc(fh) == '#' && fgetc(fh) == '!')
738ab09f 480 {
6c47084d
JH
481 char *p;
482 char *q;
483 fgets(buffer, 999, fh);
484 p = buffer;
485 while (*p == ' ' || *p == '\t')
486 p++;
487 if (buffer[strlen(buffer) - 1] == '\n')
488 buffer[strlen(buffer) - 1] = '\0';
489 if ((q = strchr(p, ' ')))
490 {
491 *q++ = '\0';
492 if (*q != '\0')
493 {
494 interpreter_args = mystrdup(q);
495 }
496 }
497 else
498 interpreter_args = mystrdup("");
499
500 interpreter = mystrdup(p);
501 size += strlen(interpreter) + 1;
502 size += strlen(interpreter_args) + 1;
738ab09f
AB
503 }
504
6c47084d
JH
505 fclose(fh);
506 }
507 else
508 {
509 /* We couldn't open this why not? */
510 if (errno == ENOENT)
511 {
512 /* file didn't exist! */
513 goto out;
514 }
515 }
516
517 /* Allocate the command line */
518 filename_conv = convert_path_u2a(filename);
519
520 if (filename_conv)
521 size += strlen(filename_conv);
522 size += 1;
523 full = (char *)IExec->AllocVec(size + 10, MEMF_ANY | MEMF_CLEAR);
524 if (full)
525 {
526 if (interpreter)
527 {
528 interpreter_conv = convert_path_u2a(interpreter);
a83a2cd1
AB
529#if !defined(__USE_RUNCOMMAND__)
530#warning(using system!)
6c47084d
JH
531 sprintf(full, "%s %s %s ", interpreter_conv,
532 interpreter_args, filename_conv);
a83a2cd1 533#else
6c47084d
JH
534 sprintf(full, "%s %s ", interpreter_args,
535 filename_conv);
a83a2cd1 536#endif
6c47084d
JH
537 IExec->FreeVec(interpreter);
538 IExec->FreeVec(interpreter_args);
539
540 if (filename_conv)
541 IExec->FreeVec(filename_conv);
542 fname = mystrdup(interpreter_conv);
543
544 if (interpreter_conv)
545 IExec->FreeVec(interpreter_conv);
546 }
547 else
548 {
a83a2cd1 549#ifndef __USE_RUNCOMMAND__
6c47084d 550 sprintf(full, "%s ", filename_conv);
a83a2cd1 551#else
6c47084d 552 sprintf(full, "");
a83a2cd1 553#endif
6c47084d
JH
554 fname = mystrdup(filename_conv);
555 if (filename_conv)
556 IExec->FreeVec(filename_conv);
557 }
558
559 for (cur = (char **)(argv + 1); *cur != 0; cur++)
560 {
561 if (contains_whitespace(*cur))
562 {
563 int esc = no_of_escapes(*cur);
564
565 if (esc > 0)
566 {
567 char *buff = IExec->AllocVec(
568 strlen(*cur) + 4 + esc,
569 MEMF_ANY | MEMF_CLEAR);
570 char *p = *cur;
571 char *q = buff;
572
573 *q++ = '"';
574 while (*p != '\0')
575 {
576
577 if (*p == '\n')
578 {
579 *q++ = '*';
580 *q++ = 'N';
581 p++;
582 continue;
583 }
584 else if (*p == '"')
585 {
586 *q++ = '*';
587 *q++ = '"';
588 p++;
589 continue;
590 }
591 else if (*p == '*')
592 {
593 *q++ = '*';
594 }
595 *q++ = *p++;
596 }
597 *q++ = '"';
598 *q++ = ' ';
599 *q = '\0';
600 strcat(full, buff);
601 IExec->FreeVec(buff);
602 }
603 else
604 {
605 strcat(full, "\"");
606 strcat(full, *cur);
607 strcat(full, "\" ");
608 }
609 }
610 else
611 {
612 strcat(full, *cur);
613 strcat(full, " ");
614 }
615 }
616 strcat(full, "\n");
a83a2cd1
AB
617
618// if(envp)
619// createvars(envp);
620
621#ifndef __USE_RUNCOMMAND__
6c47084d
JH
622 result = IDOS->SystemTags(
623 full, SYS_UserShell, TRUE, NP_StackSize,
624 ((struct Process *)thisTask)->pr_StackSize, SYS_Input,
625 ((struct Process *)thisTask)->pr_CIS, SYS_Output,
626 ((struct Process *)thisTask)->pr_COS, SYS_Error,
627 ((struct Process *)thisTask)->pr_CES, TAG_DONE);
a83a2cd1
AB
628#else
629
6c47084d
JH
630 if (fname)
631 {
632 BPTR seglist = IDOS->LoadSeg(fname);
633 if (seglist)
634 {
635 /* check if we have an executable! */
636 struct PseudoSegList *ps = NULL;
637 if (!IDOS->GetSegListInfoTags(
638 seglist, GSLI_Native, &ps, TAG_DONE))
639 {
640 IDOS->GetSegListInfoTags(
641 seglist, GSLI_68KPS, &ps, TAG_DONE);
642 }
643 if (ps != NULL)
644 {
645 // adebug("%s %ld %s
646 // %s\n",__FUNCTION__,__LINE__,fname,full);
647 IDOS->SetCliProgramName(fname);
648 // result=RunCommand(seglist,8*1024,full,strlen(full));
649 // result=myruncommand(seglist,8*1024,full,strlen(full),envp);
650 result = myruncommand(seglist, 8 * 1024,
651 full, -1, envp);
652 errno = 0;
653 }
654 else
655 {
656 errno = ENOEXEC;
657 }
658 IDOS->UnLoadSeg(seglist);
659 }
660 else
661 {
662 errno = ENOEXEC;
663 }
664 IExec->FreeVec(fname);
665 }
a83a2cd1
AB
666
667#endif /* USE_RUNCOMMAND */
668
6c47084d
JH
669 IExec->FreeVec(full);
670 if (errno == ENOEXEC)
671 {
672 result = -1;
673 }
674 goto out;
675 }
a83a2cd1 676
6c47084d
JH
677 if (interpreter)
678 IExec->FreeVec(interpreter);
679 if (filename_conv)
680 IExec->FreeVec(filename_conv);
a83a2cd1 681
6c47084d 682 errno = ENOMEM;
a83a2cd1 683
738ab09f
AB
684out:
685
6c47084d
JH
686 amigaos_stdio_restore(aTHX_ &store);
687 STATUS_NATIVE_CHILD_SET(result);
688 PL_exit_flags |= PERL_EXIT_EXPECTED;
689 if (result != -1) my_exit(result);
738ab09f 690
6c47084d 691 return(result);
a83a2cd1
AB
692}
693
738ab09f
AB
694#endif
695
a83a2cd1
AB
696int pause(void)
697{
6c47084d 698 fprintf(stderr, "Pause not implemented\n");
a83a2cd1 699
6c47084d
JH
700 errno = EINTR;
701 return -1;
a83a2cd1
AB
702}
703
704uint32 size_env(struct Hook *hook, APTR userdata, struct ScanVarsMsg *message)
705{
6c47084d
JH
706 if (strlen(message->sv_GDir) <= 4)
707 {
708 hook->h_Data = (APTR)(((uint32)hook->h_Data) + 1);
709 }
710 return 0;
a83a2cd1
AB
711}
712
713uint32 copy_env(struct Hook *hook, APTR userdata, struct ScanVarsMsg *message)
714{
6c47084d
JH
715 if (strlen(message->sv_GDir) <= 4)
716 {
717 char **env = (char **)hook->h_Data;
718 uint32 size =
719 strlen(message->sv_Name) + 1 + message->sv_VarLen + 1 + 1;
720 char *buffer = (char *)IExec->AllocVec((uint32)size,
721 MEMF_ANY | MEMF_CLEAR);
722
723 snprintf(buffer, size - 1, "%s=%s", message->sv_Name,
724 message->sv_Var);
725
726 *env = buffer;
727 env++;
728 hook->h_Data = env;
729 }
730 return 0;
a83a2cd1
AB
731}
732
733void ___makeenviron()
734{
6c47084d
JH
735 struct Hook hook;
736
737 char varbuf[8];
738 uint32 flags = 0;
739
740 struct DOSIFace *myIDOS =
741 (struct DOSIFace *)OpenInterface("dos.library", 53);
742 if (myIDOS)
743 {
744 if (myIDOS->GetVar("ABCSH_IMPORT_LOCAL", varbuf, 8,
745 GVF_LOCAL_ONLY) > 0)
746 {
747 flags = GVF_LOCAL_ONLY;
748 }
749 else
750 {
751 flags = GVF_GLOBAL_ONLY;
752 }
753
754 hook.h_Entry = size_env;
755 hook.h_Data = 0;
756
757 myIDOS->ScanVars(&hook, flags, 0);
758 hook.h_Data = (APTR)(((uint32)hook.h_Data) + 1);
759
760 myenviron = (char **)IExec->AllocVec((uint32)hook.h_Data *
761 sizeof(char **),
762 MEMF_ANY | MEMF_CLEAR);
763 origenviron = myenviron;
764 if (!myenviron)
765 {
766 return;
767 }
768 hook.h_Entry = copy_env;
769 hook.h_Data = myenviron;
770
771 myIDOS->ScanVars(&hook, flags, 0);
772 CloseInterface((struct Interface *)myIDOS);
773 }
a83a2cd1
AB
774}
775
776void ___freeenviron()
777{
6c47084d
JH
778 char **i;
779 /* perl might change environ, it puts it back except for ctrl-c */
780 /* so restore our own copy here */
781 struct DOSIFace *myIDOS =
782 (struct DOSIFace *)OpenInterface("dos.library", 53);
783 if (myIDOS)
784 {
785 myenviron = origenviron;
786
787 if (myenviron)
788 {
789 for (i = myenviron; *i != NULL; i++)
790 {
791 IExec->FreeVec(*i);
792 }
793 IExec->FreeVec(myenviron);
794 myenviron = NULL;
795 }
796 CloseInterface((struct Interface *)myIDOS);
797 }
a83a2cd1
AB
798}
799
800/* reimplementation of popen, clib2's doesn't do all we want */
801
802static BOOL is_final_quote_character(const char *str)
803{
6c47084d 804 BOOL result;
a83a2cd1 805
6c47084d 806 result = (BOOL)(str[0] == '\"' && (str[1] == '\0' || isspace(str[1])));
a83a2cd1 807
6c47084d 808 return (result);
a83a2cd1
AB
809}
810
811static BOOL is_final_squote_character(const char *str)
812{
6c47084d 813 BOOL result;
a83a2cd1 814
6c47084d 815 result = (BOOL)(str[0] == '\'' && (str[1] == '\0' || isspace(str[1])));
a83a2cd1 816
6c47084d 817 return (result);
a83a2cd1
AB
818}
819
820int popen_child()
821{
6c47084d 822 struct Task *thisTask = IExec->FindTask(0);
a83a2cd1 823
6c47084d
JH
824 char *command = (char *)thisTask->tc_UserData;
825 size_t len;
826 char *str;
827 int argc;
828 int number_of_arguments;
829 char *argv[4];
a83a2cd1 830
6c47084d
JH
831 argv[0] = "sh";
832 argv[1] = "-c";
833 argv[2] = command ? command : NULL;
834 argv[3] = NULL;
a83a2cd1 835
6c47084d 836 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
a83a2cd1 837
6c47084d
JH
838 /* We need to give this to sh via execvp, execvp expects filename,
839 * argv[]
840 */
a83a2cd1 841
6c47084d
JH
842 myexecvp(FALSE, argv[0], argv);
843 if (command)
844 IExec->FreeVec(command);
a83a2cd1 845
6c47084d
JH
846 IExec->Forbid();
847 return 0;
a83a2cd1
AB
848}
849
850FILE *amigaos_popen(const char *cmd, const char *mode)
851{
6c47084d
JH
852 FILE *result = NULL;
853 char pipe_name[50];
854 char unix_pipe[50];
855 char ami_pipe[50];
856 char *cmd_copy;
857 BPTR input = 0;
858 BPTR output = 0;
859 struct Process *proc = NULL;
860 struct Task *thisTask = IExec->FindTask(0);
861
862 /* First we need to check the mode
863 * We can only have unidirectional pipes
864 */
865 // adebug("%s %ld cmd %s mode %s \n",__FUNCTION__,__LINE__,cmd,
866 // mode);
867
868 switch (mode[0])
869 {
870 case 'r':
871 case 'w':
872 break;
873
874 default:
875
876 errno = EINVAL;
877 return result;
878 }
879
880 /* Make a unique pipe name
881 * we need a unix one and an amigaos version (of the same pipe!)
882 * as were linking with libunix.
883 */
884
885 sprintf(pipe_name, "%x%08lx/4096/0", pipenum++,
886 IUtility->GetUniqueID());
887 sprintf(unix_pipe, "/PIPE/%s", pipe_name);
888 sprintf(ami_pipe, "PIPE:%s", pipe_name);
889
890 /* Now we open the AmigaOs Filehandles That we wil pass to our
891 * Sub process
892 */
893
894 if (mode[0] == 'r')
895 {
896 /* A read mode pipe: Output from pipe input from NIL:*/
897 input = IDOS->Open("NIL:", MODE_NEWFILE);
898 if (input != 0)
899 {
900 output = IDOS->Open(ami_pipe, MODE_NEWFILE);
901 }
902 }
903 else
904 {
905
906 input = IDOS->Open(ami_pipe, MODE_NEWFILE);
907 if (input != 0)
908 {
909 output = IDOS->Open("NIL:", MODE_NEWFILE);
910 }
911 }
912 if ((input == 0) || (output == 0))
913 {
914 /* Ouch stream opening failed */
915 /* Close and bail */
916 if (input)
917 IDOS->Close(input);
918 if (output)
919 IDOS->Close(output);
920 return result;
921 }
922
923 /* We have our streams now start our new process
924 * We're using a new process so that execve can modify the environment
925 * with messing things up for the shell that launched perl
926 * Copy cmd before we launch the subprocess as perl seems to waste
927 * no time in overwriting it! The subprocess will free the copy.
928 */
929
930 if ((cmd_copy = mystrdup(cmd)))
931 {
932 // adebug("%s %ld
933 // %s\n",__FUNCTION__,__LINE__,cmd_copy?cmd_copy:"NULL");
934 proc = IDOS->CreateNewProcTags(
935 NP_Entry, popen_child, NP_Child, TRUE, NP_StackSize,
936 ((struct Process *)thisTask)->pr_StackSize, NP_Input, input,
937 NP_Output, output, NP_Error, IDOS->ErrorOutput(),
938 NP_CloseError, FALSE, NP_Cli, TRUE, NP_Name,
939 "Perl: popen process", NP_UserData, (int)cmd_copy,
940 TAG_DONE);
941 }
942 if (!proc)
943 {
944 /* New Process Failed to start
945 * Close and bail out
946 */
947 if (input)
948 IDOS->Close(input);
949 if (output)
950 IDOS->Close(output);
951 if (cmd_copy)
952 IExec->FreeVec(cmd_copy);
953 }
954
955 /* Our new process is running and will close it streams etc
956 * once its done. All we need to is open the pipe via stdio
957 */
958
959 return fopen(unix_pipe, mode);
a83a2cd1
AB
960}
961
962/* Work arround for clib2 fstat */
963#ifndef S_IFCHR
964#define S_IFCHR 0x0020000
965#endif
966
967#define SET_FLAG(u, v) ((void)((u) |= (v)))
968
969int afstat(int fd, struct stat *statb)
970{
6c47084d
JH
971 int result;
972 BPTR fh;
973 int mode;
974 BOOL input;
975 /* In the first instance pass it to fstat */
976 // adebug("fd %ld ad %ld\n",fd,amigaos_get_file(fd));
a83a2cd1 977
6c47084d
JH
978 if ((result = fstat(fd, statb) >= 0))
979 return result;
a83a2cd1 980
6c47084d
JH
981 /* Now we've got a file descriptor but we failed to stat it */
982 /* Could be a nil: or could be a std#? */
a83a2cd1 983
6c47084d 984 /* if get_default_file fails we had a dud fd so return failure */
a83a2cd1
AB
985#if !defined(__CLIB2__)
986
6c47084d
JH
987 fh = amigaos_get_file(fd);
988
989 /* if nil: return failure*/
990 if (fh == 0)
991 return -1;
992
993 /* Now compare with our process Input() Output() etc */
994 /* if these were regular files sockets or pipes we had already
995 * succeeded */
996 /* so we can guess they a character special console.... I hope */
997
998 struct ExamineData *data;
999 char name[120];
1000 name[0] = '\0';
1001
1002 data = IDOS->ExamineObjectTags(EX_FileHandleInput, fh, TAG_END);
1003 if (data != NULL)
1004 {
1005
1006 IUtility->Strlcpy(name, data->Name, sizeof(name));
1007
1008 IDOS->FreeDosObject(DOS_EXAMINEDATA, data);
1009 }
1010
1011 // adebug("ad %ld '%s'\n",amigaos_get_file(fd),name);
1012 mode = S_IFCHR;
1013
1014 if (fh == IDOS->Input())
1015 {
1016 input = TRUE;
1017 SET_FLAG(mode, S_IRUSR);
1018 SET_FLAG(mode, S_IRGRP);
1019 SET_FLAG(mode, S_IROTH);
1020 }
1021 else if (fh == IDOS->Output() || fh == IDOS->ErrorOutput())
1022 {
1023 input = FALSE;
1024 SET_FLAG(mode, S_IWUSR);
1025 SET_FLAG(mode, S_IWGRP);
1026 SET_FLAG(mode, S_IWOTH);
1027 }
1028 else
1029 {
1030 /* we got a filehandle not handle by fstat or the above */
1031 /* most likely it's NIL: but lets check */
1032 struct ExamineData *exd = NULL;
1033 if ((exd = IDOS->ExamineObjectTags(EX_FileHandleInput, fh,
1034 TAG_DONE)))
1035 {
1036 BOOL isnil = FALSE;
1037 if (exd->Type ==
1038 (20060920)) // Ugh yes I know nasty.....
1039 {
1040 isnil = TRUE;
1041 }
1042 IDOS->FreeDosObject(DOS_EXAMINEDATA, exd);
1043 if (isnil)
1044 {
1045 /* yep we got NIL: */
1046 SET_FLAG(mode, S_IRUSR);
1047 SET_FLAG(mode, S_IRGRP);
1048 SET_FLAG(mode, S_IROTH);
1049 SET_FLAG(mode, S_IWUSR);
1050 SET_FLAG(mode, S_IWGRP);
1051 SET_FLAG(mode, S_IWOTH);
1052 }
1053 else
1054 {
1055 IExec->DebugPrintF(
1056 "unhandled filehandle in afstat()\n");
1057 return -1;
1058 }
1059 }
1060 }
1061
1062 memset(statb, 0, sizeof(statb));
1063
1064 statb->st_mode = mode;
a83a2cd1
AB
1065
1066#endif
6c47084d 1067 return 0;
a83a2cd1
AB
1068}
1069
1070BPTR amigaos_get_file(int fd)
1071{
6c47084d
JH
1072 BPTR fh = (BPTR)NULL;
1073 if (!(fh = _get_osfhandle(fd)))
1074 {
1075 switch (fd)
1076 {
1077 case 0:
1078 fh = IDOS->Input();
1079 break;
1080 case 1:
1081 fh = IDOS->Output();
1082 break;
1083 case 2:
1084 fh = IDOS->ErrorOutput();
1085 break;
1086 default:
1087 break;
1088 }
1089 }
1090 return fh;
a83a2cd1 1091}
1cd70adf
AB
1092
1093/*########################################################################*/
1094
1095#define LOCK_START 0xFFFFFFFFFFFFFFFELL
1096#define LOCK_LENGTH 1LL
1097
1098// No wait forever option so lets wait for a loooong time.
1099#define TIMEOUT 0x7FFFFFFF
1100
1101int amigaos_flock(int fd, int oper)
1102{
6c47084d
JH
1103 BPTR fh;
1104 int32 success = -1;
1105
1106 if (!(fh = amigaos_get_file(fd)))
1107 {
1108 errno = EBADF;
1109 return -1;
1110 }
1111
1112 switch (oper)
1113 {
1114 case LOCK_SH:
1115 {
1116 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
1117 REC_SHARED | RECF_DOS_METHOD_ONLY,
1118 TIMEOUT))
1119 {
1120 success = 0;
1121 }
1122 break;
1123 }
1124 case LOCK_EX:
1125 {
1126 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
1127 REC_EXCLUSIVE | RECF_DOS_METHOD_ONLY,
1128 TIMEOUT))
1129 {
1130 success = 0;
1131 }
1132 break;
1133 }
1134 case LOCK_SH | LOCK_NB:
1135 {
1136 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
1137 REC_SHARED_IMMED | RECF_DOS_METHOD_ONLY,
1138 TIMEOUT))
1139 {
1140 success = 0;
1141 }
1142 else
1143 {
1144 errno = EWOULDBLOCK;
1145 }
1146 break;
1147 }
1148 case LOCK_EX | LOCK_NB:
1149 {
1150 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
1151 REC_EXCLUSIVE_IMMED | RECF_DOS_METHOD_ONLY,
1152 TIMEOUT))
1153 {
1154 success = 0;
1155 }
1156 else
1157 {
1158 errno = EWOULDBLOCK;
1159 }
1160 break;
1161 }
1162 case LOCK_UN:
1163 {
1164 if (IDOS->UnLockRecord(fh, LOCK_START, LOCK_LENGTH))
1165 {
1166 success = 0;
1167 }
1168 break;
1169 }
1170 default:
1171 {
1172 errno = EINVAL;
1173 return -1;
1174 }
1175 }
1176 return success;
1cd70adf 1177}