Wo in meinem Code sollte ich "warten, bis Kinder fertig sind"? Ich habe ein C-Programm, das einer benutzerdefinierten Shell ähnelt. Jetzt habe ich eine eingebaute Funktion checkEnv
, die die sortierten Umgebungsvariablen drucken kann. So kann ich meine Shell starten und die Liste meiner Umgebungsvariablen:Welches Signal soll ich behandeln und wie?
$ ./a.out
miniShell>> checkEnv
"'><;|&(:
_=./a.out
CLUTTER_IM_MODULE=xim
COMPIZ_CONFIG_PROFILE=ubuntu
COMP_WORDBREAKS=
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-mh5oMhyCI6
DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path
DESKTOP_SESSION=ubuntu
Der Code hinter das bedeutet dies folgendes:
if(StartsWith(line, "checkEnv")) {
built_in_command=1;
pagerValue = getenv ("PAGER");
if (! pagerValue) {
if (ret == 0) {
pager_cmd[0]="less";
} else {
pager_cmd[0]="more";
}
}
else {
pager_cmd[0]=pagerValue;
}
if(i==1) {
cmd[0].argv= printenv;
cmd[1].argv= sort;
cmd[2].argv= pager_cmd;
fork_pipes(3, cmd);
}
else {
for (k = 1; k < i; k++)
{
len += strlen(argv2[k]) + 2;
}
tmp = (char *) malloc(len);
tmp[0] = '\0';
for (k = 1; k < i; k++)
{
pos += sprintf(tmp + pos, "%s%s", (k == 1 ? "" : "|"), argv2[k]);
}
grep[0]="grep";
grep[1]="-E";
grep[2]= tmp;
grep[3]= NULL;
cmd2[0].argv= printenv;
cmd2[1].argv= grep;
cmd2[2].argv= sort;
cmd2[3].argv= pager_cmd;
fork_pipes(4, cmd2);
free(tmp);
}
Jetzt möchte ich die Ausgangsabschlußsignal zu fangen, wenn die Umgebungsvariablen listing Verwenden des Pagers, damit das Programm zur benutzerdefinierten Shell zurückkehrt, statt das gesamte Programm zu beenden. Also nehme ich an, dass ich etwas Signalverarbeitung verwenden sollte, aber wie und welches Signal?
Die eigentliche Gabel ist von dieser Funktion.
/* Helper function that forks pipes */
void fork_pipes(int n, struct command *cmd) {
int i;
int in = 0;
int fd[2];
/** loop and fork() */
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]);
}
Wohin soll die Signalverarbeitung gehen? Wo ist ein minimales Arbeitsbeispiel von dem, was ich versuche zu tun? Ich sehe kein Beispiel, das dies tut, und ich denke, die Dokumentation ist schrecklich, nur Schnipsel und kein vollständiges Beispiel.
Meine Hilfsfunktion ist
/* 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);
}
printf("** we are executing parent ***");
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;
}
Meine main()
nun wie folgt aussieht:
int main(int argc, char *argv[]) {
sourceCount = 0;
const char *commandFile;
commandFile = NULL;
char *pathValue;
/* struct sigaction sa, osa;
struct sigaction sa2;*/
int errflag;
int cOption;
struct sigaction action;
/* use getopt_long() */
char *argv1[] = {"version", "par2", 0};
/* char *argv2[] = {"help", "-m", "arg1", 0};*/
/* use sigaction */
sigemptyset(&action.sa_mask);
action.sa_handler = handle_sigchld;
action.sa_flags = 0;
sigaction(SIGPIPE, &action, NULL); //Not work with kill -13 process_id
//works well
sigaction(SIGINT, &action, NULL); //work with kill -2 process_id
errflag = 0;
/* use getopt_long() */
while ((cOption = getopt(2, argv1, "m:t:n:fs?")) != -1) {
switch (cOption) {
case 'a':
printf("apples\n");
break;
case 'b':
printf("bananas\n");
break;
case 't':
printf("tree = %s\n", optarg);
break;
case '?':
++errflag;
break;
}
}
/*
while ((cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) {
switch (cOption) {
case 'm':
printf("\n Help msg : %s \n", optarg);
exit(0);
case '?':
printf("\n -? Arg : %s \n", optarg);
break;
case 'n':
printf("\n -n Arg : %s \n", optarg);
break;
}
}
*/
/* get the PATH environment to find if less is installed */
pathValue = getenv("PATH");
if (!pathValue || getenv("PATH") == NULL) {
printf("'%s' is not set.\n", "PATH");
/* Default our path if it is not set. */
putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc");
}
else {
printf("'%s' is set to %s.\n", "PATH", pathValue);
}
exec_program(commandFile);
return (0);
}
Wenn ich meine Shell laufen in gdb
ich einen normalen Ausgang.
(gdb) run
Starting program: /home/dac/ClionProjects/shell2/openshell/shell
'PATH' is set to /home/dac/proj/google-cloud-sdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin.
dac:/home/dac/ClionProjects/shell2/openshell $ checkenv
7429: executing printenv
7430: executing grep
7417: executing less
7431: executing sort
process 7417 is executing new program: /bin/less
[Inferior 1 (process 7417) exited normally]
(gdb)
Was ist Ihr Programmsignal zu beenden verursacht? SIGPIPE? Deine reale Shell sollte es dir sagen. –