Programmer 400 Programmer 400 - 7 months ago 10
Bash Question

How can I synchronize this C code?

I have written a tokenizer that tokenizes shell command language input and when I execute the commands I get the output in "wrong order" after the

fork
, if I do a
fork
and
exec
then the output from fork and exec might come in the middle of a loop in some other function. The expected output i want is

$ ls openshell.*|grep o
{ls} {openshell.cbp} {|} {grep} {o} {|}
p[0][0] ls
p[0][1] openshell.cbp
p[1][0] grep
p[1][1] o
17109: executing ls
17108: executing grep
openshell.cbp


Whereas the output I get is

$ ls openshell.*|grep o
{ls} {openshell.cbp} {|} {grep} {o} {|}
p[0][0] ls
p[0][1] openshell.cbp
17108: executing grep
p[1][0] grep
openshell.cbp
17109: executing ls
p[1][1] o


Some of the code that does this is

static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command shellcommand[4];
char **argv = 0;
int argc = 1;
bool pipe = false;
char *pString[75][75];
char *command[40];
char *command2[40];
int i1 = 0;
char **tokens;
char tokenscopy[75];
bool keep = false;
char *conc[75];
char *conc2[75];
*conc = "\0";
*conc2 = "\0";
char temp[75] = {'\0'};
int w = 0;
bool quoted = false;
int j = 0;
int i;
int p = 0;
char **ptr;
char *tmpchar;
char *cmdtmp;
bool change = false;
int f = 0;
char *char2;
int y = 0;

for (int i = 0; i < 75; i++) { /* for each pipeline */
for (int j = 0; j < 75; j++) { /* for each pipeline */
pString[i][j] = '\0';
}

}
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)) {
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
char a[20] = {0};
cmdtmp = malloc(sizeof(cmd));
strcpy(cmdtmp, cmd);
tmpchar = malloc(sizeof(cmd));
strcpy(tmpchar, cmd);
tokens = str_split(command, cmdtmp, '|');
if (strstr(cmd, "|") == NULL) {
/* not a pipeline */
makeArgs(cmd, &argc, (const char ***) &argv, pipe, 0, 0);
/*dump_argv((const char *) "d", argc, argv);*/
for (j = 0; j < argc; j++) {
pString[0][j] = argv[j];
shellcommand[i].argv = pString[0]; /*command;*/
}
}
else {
i1 = 1;
for (i = 0; *(tokens + i); i++) { /* for each pipeline*/
i1++;
int e = 0;
*conc2 = "\0";
strcpy(tokenscopy, *(tokens + i));
if ((tokenscopy[0] != '\0') && !isspace(tokenscopy[0])) {

ptr = str_split(command2, *(&tokenscopy), ' ');
f = 0;
int j2 = 0;



for (j = 0; *(ptr + j); j++) {
if (ptr + j && !quoted && strstr(*(ptr + j), "'")) {
quoted = true;
strcpy(temp, *(ptr + j));
if(y<1) {
/* pString[i][j] = temp;*/
y++;
}
}
while (quoted) {
if (*(ptr + j) && strstr(*(ptr + j), "'")) { /* end of quote */
quoted = false;
if(y<1) {
pString[i][j] = strcpy(temp, *(ptr + j));
}
y=0;

}
else if (*(ptr + j)) { /* read until end of quote */
pString[i][j] = temp;
continue;

} else {
quoted = false;
break;
}

}
if (ptr + j) {
if (*(ptr + j)[0] == '{') {
keep = true;
}
if (testFn(*(ptr + j))) { /* test for last char */
pString[i][j - p] = concat(*conc, *(ptr + j));
keep = false;
free(*conc);
goto mylabel;
}
if (keep) {
*conc = concat(*conc, *(ptr + j));
*conc = concat(*conc, " ");
p++;
} else {
if (*(ptr + j + f + 1) == NULL)
break;
strcpy(temp, *(ptr + j));
change = false;
for (e = 0; *(ptr + j + e); e++) {
change = true;
if (*(ptr + e + j)) {
*conc2 = concat(*conc2, *(ptr + e + j));
*conc2 = concat(*conc2, " ");
}
}
if (change) j++;
if (makeArgs(*conc2, &argc, (const char ***) &argv, pipe, i, j2)) {
for (int r = 0; argv[r] != NULL; r++) {
char2 = malloc(sizeof(char *));
*char2 = '0';
strcpy(char2, argv[r]);
pString[w][r] = char2;
}
w++;
dump_argv((const char *) "d", argc, argv);
} else {
if (!change) {
for (int r = 0; argv[r] != NULL; r++) {
pString[i][r] = argv[r];
}

}
}

}
}

}
mylabel:
free(ptr);
}
}
free(tokens);
free(cmdtmp);
free(tmpchar);
for (i = 0; i < i1 - 1; i++) {
for (j = 0; pString[i][j] != 0; j++) {
printf("\np[%d][%d] %s", i, j, pString[i][j]);
}
shellcommand[i].argv = pString[i];
}
}



pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the pString.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(i1 - 1, shellcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));

return -1;
}
return WEXITSTATUS(status);
}


fork_pipes

/* Helper function that forks pipes */
void fork_pipes(int n, struct command *cmd) {
int i;
int in = 0;
int fd[2];

for (i = 0; i < n - 1; ++i) {

if (pipe(fd) == -1) {
err_syserr("Failed creating pipe");
}

spawn_proc(in, fd[1], cmd + i);
close(fd[1]);
in = fd[0];
}
if (dup2(in, 0) < 0) {
err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
}
fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd[i].argv[0]);
execvp(cmd[i].argv[0], cmd[i].argv);
err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}


/* Helper function that spawns processes */
int spawn_proc(int in, int out, struct command *cmd) {
pid_t pid;
pid = fork();
if (pid == 0) {
if (in != 0) {
if (dup2(in, 0) < 0)
err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]);
close(in);
}
if (out != 1) {
if (dup2(out, 1) < 0)
err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]);
close(out);
}
fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd->argv[0]);
execvp(cmd->argv[0], cmd->argv);
err_syserr("failed to execute %s: ", cmd->argv[0]);
}
else if (pid < 0) {
err_syserr("fork failed: ");
} else {
/* printf("** we are the parent ***"); */
}
return pid;
}


It's not absolutely necessary that I fix it in my code but I want to learn why I can''t expect the output to be "straight" when I run fork.

Answer

The reason is standard output is usually line buffered, you will need a new line to flush the output, like printf("p[%d][%d] %s\n", i, j, pString[i][j]);.

Comments