Skip to content

Commit

Permalink
Merge pull request #207 from alfkil/beta10
Browse files Browse the repository at this point in the history
Fix popen/pclose and add test for popen.
  • Loading branch information
afxgroup authored Sep 14, 2024
2 parents 6fcc386 + 6c46112 commit 0aafea3
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 13 deletions.
54 changes: 51 additions & 3 deletions library/misc/children.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ pidChildrenScan(const void *children, void *pid) {
return NULL;
}

static void *
pipeChildrenScan(const void *children, void *pipe) {
const struct Clib4Children *myChildren = children;
FILE *stream = *((FILE **)pipe);
if (myChildren->pipe == stream)
return (struct Clib4Children *) children;
return NULL;
}

BOOL
insertSpawnedChildren(uint32 pid, uint32 ppid, uint32 gid) {
DECLARE_UTILITYBASE();
Expand Down Expand Up @@ -79,6 +88,46 @@ findSpawnedChildrenByPid(uint32 pid) {

struct Clib4Children *
findSpawnedChildrenByGid(uint32 pid, uint32 gid) {
struct Clib4Resource *res = (APTR) OpenResource(RESOURCE_NAME);
if (res) {
uint32 me = GetPID(0, GPID_PROCESS);
size_t iter = 0;
void *item;

while (hashmap_iter(res->children, &iter, &item)) {
const struct Clib4Node *node = item;
// struct Clib4Children *children;
if (node->pid == me) {
//children =
return hashmap_scan_item(node->spawnedProcesses, gidChildrenScan, &gid);
}
}
}
return NULL;
}

pid_t
findSpawnedChildrenPidByPipe(FILE *pipe) {
struct Clib4Resource *res = (APTR) OpenResource(RESOURCE_NAME);
if (res) {
uint32 me = GetPID(0, GPID_PROCESS);
size_t iter = 0;
void *item;

while (hashmap_iter(res->children, &iter, &item)) {
const struct Clib4Node *node = item;
struct Clib4Children *children;
if (node->pid == me) {
children = hashmap_scan_item(node->spawnedProcesses, pipeChildrenScan, &pipe);
if(children) return children->pid;
}
}
}
return -1;
}

void
addSpawnedChildrenPipeHandle(uint32 pid, FILE *pipe) {
struct Clib4Resource *res = (APTR) OpenResource(RESOURCE_NAME);
if (res) {
uint32 me = GetPID(0, GPID_PROCESS);
Expand All @@ -90,12 +139,11 @@ findSpawnedChildrenByGid(uint32 pid, uint32 gid) {
struct Clib4Children *children;
if (node->pid == me) {
children = hashmap_scan_item(node->spawnedProcesses, pidChildrenScan, &pid);
if (children->groupId == gid)
return children;
if (children) children->pipe = pipe;
break;
}
}
}
return NULL;
}

void
Expand Down
4 changes: 3 additions & 1 deletion library/misc/children.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
BOOL insertSpawnedChildren(uint32 pid, uint32 ppid, uint32 gid);
struct Clib4Children *findSpawnedChildrenByPid(uint32 pid);
struct Clib4Children *findSpawnedChildrenByGid(uint32 pid, uint32 gid);
void addSpawnedChildrenPipeHandle(uint32 pid, FILE *pipe);
pid_t findSpawnedChildrenPidByPipe(FILE *pipe);
void spawnedProcessExit(int32 rc, int32 data UNUSED);
void spawnedProcessEnter(int32 entry_data UNUSED);
void spawnedProcessEnter(int32 entry_data);

#endif
1 change: 1 addition & 0 deletions library/shared_library/clib4.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct Clib4Children {
uint32 pid; /* the process PID */
gid_t groupId; /* Group ID of process */
uint32 returnCode; /* the return code of process */
FILE *pipe;
};

int libReserved(void);
Expand Down
58 changes: 49 additions & 9 deletions library/stdio/popen.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#endif /* _STDLIB_MEMORY_H */

#include "children.h"
#include <sys/wait.h>

int
pclose(FILE *stream) {
Expand All @@ -31,12 +32,17 @@ pclose(FILE *stream) {
goto out;
}

int status = 0;
pid_t pid = findSpawnedChildrenPidByPipe(stream);
waitpid(pid, &status, 0);

fclose(stream);

/* ZZZ we actually could catch the program's termination code
* by passing an exit function address to SystemTags() below.
*/
result = OK;
if(status != -1)
result = WEXITSTATUS(status);

out:

Expand All @@ -50,12 +56,13 @@ popen(const char *command, const char *type) {
char *command_copy = NULL;
BPTR input = BZERO;
BPTR output = BZERO;
char pipe_file_name[40];
// char pipe_file_name[40];
FILE *result = NULL;
LONG status;
unsigned long task_address;
time_t now = 0;
// unsigned long task_address;
// time_t now = 0;
int i;

struct _clib4 *__clib4 = __CLIB4;

ENTER();
Expand Down Expand Up @@ -173,6 +180,11 @@ popen(const char *command, const char *type) {
command = command_copy;
}

// Let's use out super cool pipe implementation instead :
int p[2];
pipe(p);

#if 0
/* Build a (hopefully) unique name for the pipe stream to open. We
construct it from the current process address, converted into
an octal number, followed by the current time (in seconds),
Expand All @@ -199,18 +211,32 @@ popen(const char *command, const char *type) {
pipe_file_name[i] = '\0';

SHOWSTRING(pipe_file_name);
#endif

/* Now open the input and output streams for the program to launch. */
if (type[0] == 'r') {
/* Read mode: we want to read the output of the program; the program
should read from "NIL:". */
input = Open("NIL:", MODE_NEWFILE);
if (input != BZERO)
output = Open(pipe_file_name, MODE_NEWFILE);
if (input != BZERO) {
// output = Open(pipe_file_name, MODE_NEWFILE);
int err = __get_default_file(p[1], &output);
if (err) {
__set_errno(EBADF);
goto out;
}
output = DupFileHandle(output);
}
} else {
/* Write mode: we want to send data to the program; the program
should write to "NIL:". */
input = Open(pipe_file_name, MODE_NEWFILE);
// input = Open(pipe_file_name, MODE_NEWFILE);
int err = __get_default_file(p[0], &input);
if (err) {
__set_errno(EBADF);
goto out;
}
input = DupFileHandle(input);
if (input != BZERO)
output = Open("NIL:", MODE_NEWFILE);
}
Expand All @@ -222,6 +248,7 @@ popen(const char *command, const char *type) {
__set_errno_r(__clib4, __translate_io_error_to_errno(IoErr()));
goto out;
}

D(("Launching [%s]", command));
/* Now try to launch the program. */
status = SystemTags((STRPTR) command,
Expand All @@ -231,12 +258,16 @@ popen(const char *command, const char *type) {
SYS_UserShell, TRUE,
NP_Name, command,
NP_EntryCode, spawnedProcessEnter,
NP_EntryData, getgid(),
NP_ExitCode, spawnedProcessExit,
NP_Child, TRUE,
TAG_END);

uint32 ret;

/* If launching the program returned -1 then it could not be started.
We'll need to close the I/O streams we opened above. */

if (status == -1) {
SHOWMSG("SystemTagList() failed");

Expand All @@ -248,14 +279,23 @@ popen(const char *command, const char *type) {
* If mode is set as P_NOWAIT we can retrieve process id calling IoErr()
* just after SystemTags. In this case spawnv will return pid
*/
uint32 ret = IoErr(); // This is our ProcessID;
ret = IoErr(); // This is our ProcessID;
}
/* OK, the program is running. Once it terminates, it will automatically
shut down the streams we opened for it. */
input = output = BZERO;

/* Now try to open the pipe we will use to exchange data with the program. */
result = fopen(pipe_file_name, type);
// result = fopen(pipe_file_name, type);

if (type[0] == 'r') {
result = fdopen(p[0], "r");
close(p[1]);
} else {
result = fdopen(p[1], "w");
close(p[0]);
}
if(result) addSpawnedChildrenPipeHandle(ret, result); //pid, pipe

out:

Expand Down
3 changes: 3 additions & 0 deletions test_programs/popen/child.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int main() {
return 2;
}
25 changes: 25 additions & 0 deletions test_programs/popen/popen_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <stdio.h>
#include <unistd.h>
int main() {
enableUnixPaths();
FILE *proc;
int i;
for(i = 0; i < 100; i++)
// if (proc = popen("list", "r")) {
if (proc = popen("/SDK/gcc/bin/gcc -mcrt=clib4 -Wl,--verbose xc++ -o NIL:", "r")) {
usleep(100);
while (!feof(proc)) {
char buff[10 * 1024];
size_t read_in = fread(buff, 1, sizeof(buff), proc);
if (!read_in)
break;
buff[read_in+1] = '\0';
printf("%s\n", buff);
}
int ec = pclose(proc);

printf("return code : %d\n", ec);
}

return 0;
}

0 comments on commit 0aafea3

Please sign in to comment.