#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(__CLIB2__)
# include <dos.h>
#endif
#if defined(__NEWLIB__)
# include <amiga_platform.h>
#endif
#include <fcntl.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#undef WORD
#define WORD int16
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/utility.h>
#include "amigaos.h"
struct
UtilityIFace *IUtility = NULL;
struct
Interface *OpenInterface(CONST_STRPTR libname, uint32 libver)
{
struct
Library *base = IExec->OpenLibrary(libname, libver);
struct
Interface *iface = IExec->GetInterface(base,
"main"
, 1, NULL);
if
(iface == NULL)
{
IExec->CloseLibrary(base);
}
return
iface;
}
void
CloseInterface(
struct
Interface *iface)
{
if
(iface != NULL)
{
struct
Library *base = iface->Data.LibBase;
IExec->DropInterface(iface);
IExec->CloseLibrary(base);
}
}
BOOL
__unlink_retries = FALSE;
void
___makeenviron() __attribute__((constructor));
void
___freeenviron() __attribute__((destructor));
void
___openinterfaces() __attribute__((constructor));
void
___closeinterfaces() __attribute__((destructor));
void
___openinterfaces()
{
if
(!IDOS)
IDOS = (
struct
DOSIFace *)OpenInterface(
"dos.library"
, 53);
if
(!IUtility)
IUtility =
(
struct
UtilityIFace *)OpenInterface(
"utility.library"
, 53);
}
void
___closeinterfaces()
{
CloseInterface((
struct
Interface *)IDOS);
CloseInterface((
struct
Interface *)IUtility);
}
int
VARARGS68K araddebug(UBYTE *fmt, ...);
int
VARARGS68K adebug(UBYTE *fmt, ...);
#define __USE_RUNCOMMAND__
char
**myenviron = NULL;
char
**origenviron = NULL;
static
void
createvars(
char
**envp);
struct
args
{
BPTR seglist;
int
stack;
char
*command;
int
length;
int
result;
char
**envp;
};
int
__myrc(__attribute__((unused))
char
*arg)
{
struct
Task *thisTask = IExec->FindTask(0);
struct
args *myargs = (
struct
args *)thisTask->tc_UserData;
if
(myargs->envp)
createvars(myargs->envp);
myargs->result = IDOS->RunCommand(myargs->seglist, myargs->stack,
myargs->command, myargs->length);
return
0;
}
int32 myruncommand(
BPTR seglist,
int
stack,
char
*command,
int
length,
char
**envp)
{
struct
args myargs;
struct
Task *thisTask = IExec->FindTask(0);
struct
Process *proc;
myargs.seglist = seglist;
myargs.stack = stack;
myargs.command = command;
myargs.length = length;
myargs.result = -1;
myargs.envp = envp;
if
((proc = IDOS->CreateNewProcTags(
NP_Entry, __myrc, NP_Child, TRUE, NP_Input, IDOS->Input(),
NP_Output, IDOS->Output(), NP_Error, IDOS->ErrorOutput(),
NP_CloseInput, FALSE, NP_CloseOutput, FALSE, NP_CloseError,
FALSE, NP_CopyVars, FALSE,
NP_Cli, TRUE, NP_UserData, (
int
)&myargs,
NP_NotifyOnDeathSigTask, thisTask, TAG_DONE)))
{
IExec->Wait(SIGF_CHILD);
}
return
myargs.result;
}
char
*mystrdup(
const
char
*s)
{
char
*result = NULL;
size_t
size;
size =
strlen
(s) + 1;
if
((result = (
char
*)IExec->AllocVecTags(size, TAG_DONE)))
{
memmove
(result, s, size);
}
return
result;
}
unsigned
int
pipenum = 0;
int
pipe(
int
filedes[2])
{
char
pipe_name[1024];
#ifdef USE_TEMPFILES
sprintf
(pipe_name,
"/T/%x.%08lx"
, pipenum++, IUtility->GetUniqueID());
#else
sprintf
(pipe_name,
"/PIPE/%x%08lx/4096/0"
, pipenum++,
IUtility->GetUniqueID());
#endif
filedes[1] = open(pipe_name, O_WRONLY | O_CREAT);
filedes[0] = open(pipe_name, O_RDONLY);
if
(filedes[0] == -1 || filedes[1] == -1)
{
if
(filedes[0] != -1)
close(filedes[0]);
if
(filedes[1] != -1)
close(filedes[1]);
return
-1;
}
return
0;
}
int
fork(
void
)
{
fprintf
(stderr,
"Can not bloody fork\n"
);
errno
= ENOMEM;
return
-1;
}
int
wait(__attribute__((unused))
int
*status)
{
fprintf
(stderr,
"No wait try waitpid instead\n"
);
errno
= ECHILD;
return
-1;
}
char
*convert_path_a2u(
const
char
*filename)
{
struct
NameTranslationInfo nti;
if
(!filename)
{
return
0;
}
__translate_amiga_to_unix_path_name(&filename, &nti);
return
mystrdup(filename);
}
char
*convert_path_u2a(
const
char
*filename)
{
struct
NameTranslationInfo nti;
if
(!filename)
{
return
0;
}
if
(
strcmp
(filename,
"/dev/tty"
) == 0)
{
return
mystrdup(
"CONSOLE:"
);
;
}
__translate_unix_to_amiga_path_name(&filename, &nti);
return
mystrdup(filename);
}
struct
SignalSemaphore environ_sema;
struct
SignalSemaphore popen_sema;
void
amigaos4_init_environ_sema()
{
IExec->InitSemaphore(&environ_sema);
IExec->InitSemaphore(&popen_sema);
}
void
amigaos4_obtain_environ()
{
IExec->ObtainSemaphore(&environ_sema);
}
void
amigaos4_release_environ()
{
IExec->ReleaseSemaphore(&environ_sema);
}
static
void
createvars(
char
**envp)
{
if
(envp)
{
IDOS->SetVar(
"ABCSH_IMPORT_LOCAL"
,
"TRUE"
, 5, GVF_LOCAL_ONLY);
amigaos4_obtain_environ();
envp = myenviron;
while
((envp != NULL) && (*envp != NULL))
{
int
len;
char
*var;
char
*val;
if
((len =
strlen
(*envp)))
{
if
((var = (
char
*)IExec->AllocVecTags(len + 1, AVT_ClearWithValue,0,TAG_DONE)))
{
strcpy
(var, *envp);
val =
strchr
(var,
'='
);
if
(val)
{
*val++ =
'\0'
;
if
(*val)
{
IDOS->SetVar(
var, val,
strlen
(val) + 1,
GVF_LOCAL_ONLY);
}
}
IExec->FreeVec(var);
}
}
envp++;
}
amigaos4_release_environ();
}
}
struct
command_data
{
STRPTR args;
BPTR seglist;
struct
Task *parent;
};
int
myexecvp(
bool
isperlthread,
const
char
*filename,
char
*argv[])
{
int
res;
char
*name = NULL;
char
*pathpart = NULL;
if
((
strchr
(filename,
'/'
) == NULL) && (
strchr
(filename,
':'
) == NULL))
{
const
char
*path;
const
char
*p;
size_t
len;
struct
stat st;
if
(!(path =
getenv
(
"PATH"
)))
{
path =
".:/bin:/usr/bin:/c"
;
}
len =
strlen
(filename) + 1;
name = (
char
*)IExec->AllocVecTags(
strlen
(path) + len, AVT_ClearWithValue,0,AVT_Type,MEMF_SHARED,TAG_DONE);
pathpart = (
char
*)IExec->AllocVecTags(
strlen
(path) + 1, AVT_ClearWithValue,0,AVT_Type,MEMF_SHARED,TAG_DONE);
p = path;
do
{
path = p;
if
(!(p =
strchr
(path,
':'
)))
{
p =
strchr
(path,
'\0'
);
}
memcpy
(pathpart, path, p - path);
pathpart[p - path] =
'\0'
;
if
(!(
strlen
(pathpart) == 0))
{
sprintf
(name,
"%s/%s"
, pathpart, filename);
}
else
sprintf
(name,
"%s"
, filename);
if
((stat(name, &st) == 0) && (S_ISREG(st.st_mode)))
{
filename = name;
break
;
}
}
while
(*p++ !=
'\0'
);
}
res = myexecve(isperlthread, filename, argv, myenviron);
if
(name)
{
IExec->FreeVec((APTR)name);
name = NULL;
}
if
(pathpart)
{
IExec->FreeVec((APTR)pathpart);
pathpart = NULL;
}
return
res;
}
int
myexecv(
bool
isperlthread,
const
char
*path,
char
*argv[])
{
return
myexecve(isperlthread, path, argv, myenviron);
}
int
myexecl(
bool
isperlthread,
const
char
*path, ...)
{
va_list
va;
char
*argv[1024];
int
i = 0;
va_start
(va, path);
i = 0;
do
{
argv[i] =
va_arg
(va,
char
*);
}
while
(argv[i++] != NULL);
va_end
(va);
return
myexecve(isperlthread, path, argv, myenviron);
}
int
pause(
void
)
{
fprintf
(stderr,
"Pause not implemented\n"
);
errno
= EINTR;
return
-1;
}
uint32 size_env(
struct
Hook *hook, __attribute__((unused))APTR userdata,
struct
ScanVarsMsg *message)
{
if
(
strlen
(message->sv_GDir) <= 4)
{
hook->h_Data = (APTR)(((uint32)hook->h_Data) + 1);
}
return
0;
}
uint32 copy_env(
struct
Hook *hook, __attribute__((unused))APTR userdata,
struct
ScanVarsMsg *message)
{
if
(
strlen
(message->sv_GDir) <= 4)
{
char
**env = (
char
**)hook->h_Data;
uint32 size =
strlen
(message->sv_Name) + 1 + message->sv_VarLen + 1 + 1;
char
*buffer = (
char
*)IExec->AllocVecTags((uint32)size,AVT_ClearWithValue,0,TAG_DONE);
snprintf(buffer, size - 1,
"%s=%s"
, message->sv_Name,
message->sv_Var);
*env = buffer;
env++;
hook->h_Data = env;
}
return
0;
}
void
___makeenviron()
{
struct
Hook *hook = (
struct
Hook *)IExec->AllocSysObjectTags(ASOT_HOOK,TAG_DONE);
if
(hook)
{
char
varbuf[8];
uint32 flags = 0;
struct
DOSIFace *myIDOS =
(
struct
DOSIFace *)OpenInterface(
"dos.library"
, 53);
if
(myIDOS)
{
uint32 size = 0;
if
(myIDOS->GetVar(
"ABCSH_IMPORT_LOCAL"
, varbuf, 8,
GVF_LOCAL_ONLY) > 0)
{
flags = GVF_LOCAL_ONLY;
}
else
{
flags = GVF_GLOBAL_ONLY;
}
hook->h_Entry = size_env;
hook->h_Data = 0;
myIDOS->ScanVars(hook, flags, 0);
size = ((uint32)hook->h_Data) + 1;
myenviron = (
char
**)IExec->AllocVecTags(size *
sizeof
(
char
**),
AVT_ClearWithValue,0,TAG_DONE);
origenviron = myenviron;
if
(!myenviron)
{
IExec->FreeSysObject(ASOT_HOOK,hook);
CloseInterface((
struct
Interface *)myIDOS);
return
;
}
hook->h_Entry = copy_env;
hook->h_Data = myenviron;
myIDOS->ScanVars(hook, flags, 0);
IExec->FreeSysObject(ASOT_HOOK,hook);
CloseInterface((
struct
Interface *)myIDOS);
}
}
}
void
___freeenviron()
{
char
**i;
struct
DOSIFace *myIDOS =
(
struct
DOSIFace *)OpenInterface(
"dos.library"
, 53);
if
(myIDOS)
{
myenviron = origenviron;
if
(myenviron)
{
for
(i = myenviron; *i != NULL; i++)
{
IExec->FreeVec(*i);
}
IExec->FreeVec(myenviron);
myenviron = NULL;
}
CloseInterface((
struct
Interface *)myIDOS);
}
}
#ifndef S_IFCHR
#define S_IFCHR 0x0020000
#endif
#define SET_FLAG(u, v) ((void)((u) |= (v)))
int
afstat(
int
fd,
struct
stat *statb)
{
int
result;
BPTR fh;
int
mode;
BOOL
input;
if
((result = fstat(fd, statb) >= 0))
return
result;
#if !defined(__CLIB2__)
fh = amigaos_get_file(fd);
if
(fh == 0)
return
-1;
struct
ExamineData *data;
char
name[120];
name[0] =
'\0'
;
data = IDOS->ExamineObjectTags(EX_FileHandleInput, fh, TAG_END);
if
(data != NULL)
{
IUtility->Strlcpy(name, data->Name,
sizeof
(name));
IDOS->FreeDosObject(DOS_EXAMINEDATA, data);
}
mode = S_IFCHR;
if
(fh == IDOS->Input())
{
input = TRUE;
SET_FLAG(mode, S_IRUSR);
SET_FLAG(mode, S_IRGRP);
SET_FLAG(mode, S_IROTH);
}
else
if
(fh == IDOS->Output() || fh == IDOS->ErrorOutput())
{
input = FALSE;
SET_FLAG(mode, S_IWUSR);
SET_FLAG(mode, S_IWGRP);
SET_FLAG(mode, S_IWOTH);
}
else
{
struct
ExamineData *exd = NULL;
if
((exd = IDOS->ExamineObjectTags(EX_FileHandleInput, fh,
TAG_DONE)))
{
BOOL
isnil = FALSE;
if
(exd->Type ==
(20060920))
{
isnil = TRUE;
}
IDOS->FreeDosObject(DOS_EXAMINEDATA, exd);
if
(isnil)
{
SET_FLAG(mode, S_IRUSR);
SET_FLAG(mode, S_IRGRP);
SET_FLAG(mode, S_IROTH);
SET_FLAG(mode, S_IWUSR);
SET_FLAG(mode, S_IWGRP);
SET_FLAG(mode, S_IWOTH);
}
else
{
IExec->DebugPrintF(
"unhandled filehandle in afstat()\n"
);
return
-1;
}
}
}
memzero(statb,
sizeof
(statb));
statb->st_mode = mode;
#endif
return
0;
}
BPTR amigaos_get_file(
int
fd)
{
BPTR fh = (BPTR)NULL;
if
(!(fh = _get_osfhandle(fd)))
{
switch
(fd)
{
case
0:
fh = IDOS->Input();
break
;
case
1:
fh = IDOS->Output();
break
;
case
2:
fh = IDOS->ErrorOutput();
break
;
default
:
break
;
}
}
return
fh;
}
#define LOCK_START 0xFFFFFFFFFFFFFFFELL
#define LOCK_LENGTH 1LL
#define TIMEOUT 0x7FFFFFFF
int
amigaos_flock(
int
fd,
int
oper)
{
BPTR fh;
int32 success = -1;
if
(!(fh = amigaos_get_file(fd)))
{
errno
= EBADF;
return
-1;
}
switch
(oper)
{
case
LOCK_SH:
{
if
(IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
REC_SHARED | RECF_DOS_METHOD_ONLY,
TIMEOUT))
{
success = 0;
}
break
;
}
case
LOCK_EX:
{
if
(IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
REC_EXCLUSIVE | RECF_DOS_METHOD_ONLY,
TIMEOUT))
{
success = 0;
}
break
;
}
case
LOCK_SH | LOCK_NB:
{
if
(IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
REC_SHARED_IMMED | RECF_DOS_METHOD_ONLY,
TIMEOUT))
{
success = 0;
}
else
{
errno
= EWOULDBLOCK;
}
break
;
}
case
LOCK_EX | LOCK_NB:
{
if
(IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
REC_EXCLUSIVE_IMMED | RECF_DOS_METHOD_ONLY,
TIMEOUT))
{
success = 0;
}
else
{
errno
= EWOULDBLOCK;
}
break
;
}
case
LOCK_UN:
{
if
(IDOS->UnLockRecord(fh, LOCK_START, LOCK_LENGTH))
{
success = 0;
}
break
;
}
default
:
{
errno
= EINVAL;
return
-1;
}
}
return
success;
}