Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix popen/pclose and add test for popen. #207

Merged
merged 2 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}