I've written a small program (with code from SO) that facilitates printenv | sort | less. Now I want to implement error-handling and I start with execvp. Is it just to check the return value and what more? AFAIK I just check the return value if it was 0 in this function return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);. Is that correct?
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct command
{
const char **argv;
};
/* Helper function that spawns processes */
int spawn_proc (int in, int out, struct command *cmd) {
pid_t pid;
if ((pid = fork ()) == 0) {
if (in != 0) {
dup2 (in, 0);
close (in);
}
if (out != 1) {
dup2 (out, 1);
close (out);
}
return execvp (cmd->argv [0], (char * const *)cmd->argv);
}
return pid;
}
/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
int i;
int in, fd [2];
for (i = 0; i < n - 1; ++i) {
pipe (fd);
spawn_proc (in, fd [1], cmd + i);
close (fd [1]);
in = fd [0];
}
dup2 (in, 0);
return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}
int main (int argc, char ** argv) {
int i;
if (argc == 1) { /* There were no arguments */
const char *printenv[] = { "printenv", 0};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {sort}, {less} };
return fork_pipes (3, cmd);
}
if (argc > 1) { /* I'd like an argument */
if (strncmp(argv[1], "cd", 2) && strncmp(argv[1], "exit", 2)) {
char *tmp;
int len = 1;
for( i=1; i<argc; i++)
{
len += strlen(argv[i]) + 2;
}
tmp = (char*) malloc(len);
tmp[0] = '\0';
int pos = 0;
for( i=1; i<argc; i++)
{
pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
}
const char *printenv[] = { "printenv", 0};
const char *grep[] = { "grep", "-E", tmp, NULL};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
return fork_pipes (4, cmd);
free(tmp);
} else if (! strncmp(argv[1], "cd", 2)) { /* change directory */
printf("change directory to %s\n" , argv[2]);
chdir(argv[2]);
} else if (! strncmp(argv[1], "exit", 2)) { /* change directory */
printf("exit\n");
exit(0);
}
}
exit(0);
}
Look at the manual : execvp change your process's program image to another. So if there is a return value at all, it will be obviously -1, because it will have obviously failed.
As for any syscall or functions calling syscall, execvp with set errno for an appropriate error code, that you can use with perror to know why your function failed. (By the way, you should do the same to any syscall: fork, pipe and dup2 at least.)
Then, if by "error handling", you mean handle errors from the program that you launched, you can make it with wait or waitpid. It will allow you to know how the program ended, it return value, if it ended by a signal, if yes wich one, etc.
Related
// I have commands in commands[] array
pid_t pid[command_count];
for (int i = 0; i < command_count; i++) {
if ((pid[i]=fork()) == 0) {
printf("--%s\n", commands[i][0]);
execvp(commands[i][0],commands[i]);
_exit(1);
}
if (pid[i] < 0) {
}
}
for (i = 0; i < command_count; i++) {
if (pid[i] > 0) {
int status;
waitpid(pid[i], &status, 0);
}
}
I have the above code and want to run commands at once (paralel) that is in commands array and before each run, want to print the command. For example;
ls | pwd | ls -a
It should print each command name before that command run like
--ls
.. a b.txt
--pwd
/a/a/
--ls -a
*some output*
But it prints like following
--ls
--pwd
--ls -a
.. a b.txt
*some directory as a result of pwd*
*some output*
What could be the reason and how can I fix it?
You will have to use pipe() to create new standard output and optionally standard error file descriptors for each command. Then you can read the pipes in order until each command completes.
Otherwise, because each command is forked into its own process it will run at its own convenience. Text output from commands running all at once and producing output to the same terminal can be mixed up even more than you show here.
Maybe something like
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
struct cmd_data {
const char *cmd;
int fd[2]; // stdout pipe for command
pid_t pid;
int status; // exit status
};
void cmd_launch(struct cmd_data *p, const char *cmd) {
int r;
p->cmd = cmd;
r = pipe(p->fd);
if(r<0) {
perror("pipe");
exit(EXIT_FAILURE);
}
r = fork();
if(r < 0) {
perror("fork");
close(p->fd[0]);
close(p->fd[1]);
} else if( r > 0 ) {
p->pid = r;
close(p->fd[1]);
} else {
close(p->fd[0]);
dup2(p->fd[1], STDOUT_FILENO);
close(p->fd[1]);
r = execlp(cmd, cmd, NULL);
perror("execlp");
exit(EXIT_FAILURE);
}
}
void cmd_join(struct cmd_data *p) {
char buf[4096];
const size_t buflen = sizeof buf;
ssize_t bytes;
printf("-- %s\n", p->cmd);
fflush(stdout);
while( 0 != (bytes = read(p->fd[0], buf, buflen)) ) {
write(STDOUT_FILENO, buf, bytes);
}
close(p->fd[0]);
pid_t r = waitpid(p->pid, &p->status, 0);
if(r<0){
perror("waitpid");
}
printf("-- completed with status %d\n", p->status);
fflush(stdout);
}
int main(int argc, char *argv[]) {
size_t cmd_c = argc - 1;
struct cmd_data *p = calloc(argc, sizeof *p);
size_t i;
for(i = 0; i < cmd_c; ++i) {
cmd_launch(p + i, argv[i + 1]);
}
for(i = 0; i < cmd_c; ++i) {
cmd_join(p + i);
}
free(p);
return EXIT_SUCCESS;
}
I have error multi-character tab ` \' \' -k 10 -r -n log.txt'
int
main ()
{
const char *sort[] = { "sort", "-t ' ' -k 10 -r -n log.txt", 0 };
const char *awk[] = { "awk", "{print $10}", 0 };
struct command cmd [] = { {sort}, {awk} };
return fork_pipes (2, cmd);
}
How backspace escape or correct sort argument in C.
All code:
#include <unistd.h>
struct command
{
const char **argv;
};
int
spawn_proc (int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork ()) == 0)
{
if (in != 0)
{
dup2 (in, 0);
close (in);
}
if (out != 1)
{
dup2 (out, 1);
close (out);
}
return execvp (cmd->argv [0], (char * const *)cmd->argv);
}
return pid;
}
int
fork_pipes (int n, struct command *cmd)
{
int i;
pid_t pid;
int in, fd [2];
/* The first process should get its input from the original file descriptor 0. */
in = 0;
/* Note the loop bound, we spawn here all, but the last stage of the pipeline. */
for (i = 0; i < n - 1; ++i)
{
pipe (fd);
/* f [1] is the write end of the pipe, we carry `in` from the prev iteration. */
spawn_proc (in, fd [1], cmd + i);
/* No need for the write and of the pipe, the child will write here. */
close (fd [1]);
/* Keep the read end of the pipe, the next child will read from there. */
in = fd [0];
}
/* Last stage of the pipeline - set stdin be the read end of the previous pipe
and output to the original file descriptor 1. */
if (in != 0)
dup2 (in, 0);
/* Execute the last stage with the current process. */
return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}
int
main ()
{
const char *sort[] = { "sort", "-t ' ' -k 10 -r -n log.txt", 0 };
const char *awk[] = { "awk", "{print $10}", 0 };
struct command cmd [] = { {sort}, {awk} };
return fork_pipes (2, cmd);
}
I assume that the strings are passed as arguments to one of the exec functions? Then you can't put multiple arguments in a single string because exec will treat it as a single argument to the program.
The arguments to exec is what becomes the argv array in the called program, so for example "-t ' ' -k 10 -r -n log.txt" will become a single argument (e.g. argv[1]) in the called program. You need to separate the arguments:
const char *sort[] = { "sort", "-t", " ", "-k", "10", "-r", "-n", "log.txt", 0 };
/tmp/ccpGLxUa.o: In function `Janitor':
digenv2.c:(.text+0x656): undefined reference to `WIFEEXITED'
collect2: error: ld returned 1 exit status
I'm trying to compile a file that worked before. Now I get thi error message when compiling. The full program is
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
pid_t foreground = -1;
struct command
{
char * const *argv;
};
static _Noreturn void err_syserr(char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
exit(EXIT_FAILURE);
}
/* Helper function that spawns processes */
static int spawn_proc(int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork()) == 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: ");
return pid;
}
/* Helper function that forks pipes */
static void fork_pipes(int n, struct command *cmd)
{
int i;
int in = 0;
int fd[2];
for (i = 0; i < n - 1; ++i)
{
pipe(fd);
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]);
}
int main(int argc, char **argv)
{
int i;
if (argc == 1) /* There were no arguments */
{
char *printenv[] = { "printenv", 0};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {sort}, {less} };
fork_pipes(3, cmd);
}
else
{
if (strcmp(argv[1], "cd") == 0) /* change directory */
{
printf("change directory to %s\n", argv[2]);
chdir(argv[2]);
}
else if (strcmp(argv[1], "exit") == 0)
{
printf("exit\n");
exit(0);
}
else
{
char *tmp;
int len = 1;
for (i = 1; i < argc; i++)
{
len += strlen(argv[i]) + 2;
}
tmp = (char *) malloc(len);
tmp[0] = '\0';
int pos = 0;
for (i = 1; i < argc; i++)
{
pos += sprintf(tmp + pos, "%s%s", (i == 1 ? "" : "|"), argv[i]);
}
char *printenv[] = { "printenv", 0};
char *grep[] = { "grep", "-E", tmp, NULL};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {grep}, {sort}, {less} };
fork_pipes(4, cmd);
free(tmp);
}
}
return(0);
}
/*Remove zoombie processes*/
/*Return if background process terminated*/
/*
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
*/
void Janitor(int signal) {
if(signal==SIGCHLD) { /*Child process terminated, stopped, or continued*/
int a = 1;
while(a) {
pid_t pid_my1 = waitpid(-1, &signal, WNOHANG);
/*WNOHANG = return immediately if no child has exited*/
/*http://linux.die.net/man/2/waitpid*/
if(0<pid_my1) { /*Still things to clean up*/
if(pid_my1!=foreground) { /*Don't stop me since it's the foregound process*/
/*http://linux.die.net/man/3/wait*/
if(WIFEEXITED(signal)) { /*Child process terminated*/
/*FIXME*/
}
}
}
else { /*All work done, for now*/
a = 0;
}
}
}
}
The program was compiling fine just a few days ago. It is in a github repository. I compiled, added, commit and pushed and then when I check it out I get the above error message when compiling. Why?
You haven't included the necessary headers for wait(2) options:
#include <sys/types.h>
#include <sys/wait.h>
I asked about my code and the answer was that it is incorrect.
perror usage in this case
Now I wonder how I can adjust and improve so that I no longer will have these errors?
execvp does not return, except if an error occurs, so if all works,
the enclosing function will never return.
the value 'i' is already past the end of the array in 'cmd' due to the
prior loop, so 'cmd[i].argv[0] is not correct.
cmd is not an array, of struct command, so should not be indexed
the first entry in cmd.argv is a pointer to an array where the last
entry is NULL. the execvp will work on that (and only that) array so
all other pointers to arrays will be ignored
There are a large number of errors in the code. for instance, the
first time through the loop in fork_pipe() 'in' contains garbage. the
second parameter passed to execvp() needs to be a pointer to character
strings, with a final NULL pointer. That final NULL pointer is
missing, There are plenty more problems
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct command
{
const char **argv;
};
/* Helper function that spawns processes */
int spawn_proc (int in, int out, struct command *cmd) {
pid_t pid;
if ((pid = fork ()) == 0) {
if (in != 0) {
/*if (dup2(in, 0) == -1) {
perror("dup2 failed");
exit(1);
}*/
dup2 (in, 0);
close (in);
}
if (out != 1) {
dup2 (out, 1);
close (out);
}
if (execvp(cmd->argv [0], (char * const *)cmd->argv) < 0) {
perror("execvp failed");
exit(1);
}
} else if (pid < 0) {
perror("fork failed");
exit(1);
}
return pid;
}
/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
int i;
int in, fd [2];
for (i = 0; i < n - 1; ++i) {
pipe (fd);
spawn_proc (in, fd [1], cmd + i);
close (fd [1]);
in = fd [0];
}
dup2 (in, 0);
/*return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);*/
if (execvp (cmd [i].argv [0], (char * const *)cmd [i].argv) < 0) {
perror("execvp failed");
exit(1);
} else {
return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}
}
int main (int argc, char ** argv) {
int i;
if (argc == 1) { /* There were no arguments */
const char *printenv[] = { "printenv", 0};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {sort}, {less} };
return fork_pipes (3, cmd);
}
if (argc > 1) { /* I'd like an argument */
if (strncmp(argv[1], "cd", 2) && strncmp(argv[1], "exit", 2)) {
char *tmp;
int len = 1;
for( i=1; i<argc; i++)
{
len += strlen(argv[i]) + 2;
}
tmp = (char*) malloc(len);
tmp[0] = '\0';
int pos = 0;
for( i=1; i<argc; i++)
{
pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
}
const char *printenv[] = { "printenv", 0};
const char *grep[] = { "grep", "-E", tmp, NULL};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
return fork_pipes (4, cmd);
free(tmp);
} else if (! strncmp(argv[1], "cd", 2)) { /* change directory */
printf("change directory to %s\n" , argv[2]);
chdir(argv[2]);
} else if (! strncmp(argv[1], "exit", 2)) { /* change directory */
printf("exit\n");
exit(0);
}
}
exit(0);
}
Transferring comments into (part of) an answer.
You don't need the test on execvp() (if it returns, it failed), but you do need the error reporting and exit call after it.
The 'cmd is not an array' comment seems to be bogus; inside fork_pipes(), it is an array. It is not used as an array inside spawn_proc().
I think the comment 'The first entry in cmd.argv is a pointer to an array where the last entry is NULL. The execvp will work on that (and only that) array so all other pointers to arrays will be ignored' is bogus too. I think they overlooked that you're creating an array of struct command's.
I think the comment 'the value i is already past the end of the array in cmd due to the prior loop, so cmd[i].argv[0] is not correct' is incorrect because the loop is for (i = 0; i < n - 1; i++) so i is n-1 after the loop, and the array cmd has elements 0..n-1 to address.
However, the value of in in the first call to spawn_proc() is indeed garbage. Probably you can simply set it to 0 (STDIN_FILENO) and be OK, but you need to verify that. But the comment about the second argument to execvp() is peculiar — the cast should be absent, but otherwise the code looks OK to me. I should add that I've not yet run a compiler over any of this, so anything I've said so far stands to be corrected by a compiler. But I'm not doing the analysis casually either… Are you compiling with your compiler set fussy: gcc -Wall -Wextra -Werror as a minimum (I use more options!)?
In fork_pipes(), the if test on execvp() and the else clause are weird. You just need calls to execvp(), perror() and exit().
These comments above stand basically accurate. Here is some modified code, but the modifications are mostly cosmetic. The err_syserr() function is based on what I use for reporting errors. It is a varargs function that also reports the system error. It is better than perror() because (a) it can format more comprehensively and (b) it exits.
I was getting compilation warnings like:
ft13.c: In function ‘spawn_proc’:
ft13.c:45:9: error: passing argument 2 of ‘execvp’ from incompatible pointer type [-Werror]
execvp(cmd->argv[0], cmd->argv);
^
In file included from ft13.c:6:0:
/usr/include/unistd.h:440:6: note: expected ‘char * const*’ but argument is of type ‘const char **’
int execvp(const char *, char * const *);
The easiest way to fix these is to place the const in the correct place in struct command and to remove the const from the argument lists for the various commands.
Other changes are more cosmetic than really substantive (the uninitialized in was the only serious bug to fix). I've use my error reporting code, and checked some extra system calls (the dup2() ones, for example), and cleaned up the execvp() and error reporting. I moved the tests for exit and cd ahead of the general code to avoid repeating the tests. Also, you were using strncmp() and the test for exit was only looking at ex, but ex is a system command… Use strcmp(). I use strcmp(x, y) == 0 in the condition; the relational operator in use mimics the relational operation I'm testing (so strcmp(x, y) >= 0 tests for x greater than or equal to y, etc.).
Modern POSIX does not require #include <sys/types.h> as an include. The other headers include it as necessary.
Source: ft13.c
Compiled to ft13.
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct command
{
char * const *argv;
};
static _Noreturn void err_syserr(char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
exit(EXIT_FAILURE);
}
/* Helper function that spawns processes */
static int spawn_proc(int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork()) == 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: ");
return pid;
}
/* Helper function that forks pipes */
static void fork_pipes(int n, struct command *cmd)
{
int i;
int in = 0;
int fd[2];
for (i = 0; i < n - 1; ++i)
{
pipe(fd);
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]);
}
int main(int argc, char **argv)
{
int i;
if (argc == 1) /* There were no arguments */
{
char *printenv[] = { "printenv", 0};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {sort}, {less} };
fork_pipes(3, cmd);
}
else
{
if (strcmp(argv[1], "cd") == 0) /* change directory */
{
printf("change directory to %s\n", argv[2]);
chdir(argv[2]);
}
else if (strcmp(argv[1], "exit") == 0)
{
printf("exit\n");
exit(0);
}
else
{
char *tmp;
int len = 1;
for (i = 1; i < argc; i++)
{
len += strlen(argv[i]) + 2;
}
tmp = (char *) malloc(len);
tmp[0] = '\0';
int pos = 0;
for (i = 1; i < argc; i++)
{
pos += sprintf(tmp + pos, "%s%s", (i == 1 ? "" : "|"), argv[i]);
}
char *printenv[] = { "printenv", 0};
char *grep[] = { "grep", "-E", tmp, NULL};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {grep}, {sort}, {less} };
fork_pipes(4, cmd);
free(tmp);
}
}
return(0);
}
Example runs
Sample 1:
$ ./ft13 | cat
1733: executing less
1735: executing printenv
1736: executing sort
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.sl7NmyZPgI/Render
BASH_ENV=/Users/jleffler/.bashrc
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
CLICOLOR=1
…lots of environment omitted…
VISUAL=vim
XPC_FLAGS=0x0
XPC_SERVICE_NAME=0
_=./ft13
__CF_USER_TEXT_ENCODING=0x1F7:0x0:0x0
$
Sample 2:
$ ./ft13 PATH | cat
1739: executing printenv
1737: executing less
1740: executing grep
1741: executing sort
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
DYLD_LIBRARY_PATH=/usr/lib:/usr/informix/11.70.FC6/lib:/usr/informix/11.70.FC6/lib/esql:/usr/informix/11.70.FC6/lib/cli
GOPATH=/Users/jleffler/Software/go-1.2
LD_LIBRARY_PATH=/usr/lib:/usr/gnu/lib:/usr/gcc/v4.9.1/lib
MANPATH=/Users/jleffler/man:/Users/jleffler/share/man:/usr/local/mysql/man:/usr/gcc/v4.9.1/share/man:/Users/jleffler/perl/v5.20.1/man:/usr/local/man:/usr/local/share/man:/opt/local/man:/opt/local/share/man:/usr/share/man:/usr/gnu/man:/usr/gnu/share/man
PATH=/Users/jleffler/bin:/usr/informix/11.70.FC6/bin:.:/usr/local/mysql/bin:/usr/gcc/v4.9.1/bin:/Users/jleffler/perl/v5.20.1/bin:/usr/local/go/bin:/Users/jleffler/Software/go-1.2/bin:/usr/local/bin:/opt/local/bin:/usr/bin:/bin:/usr/gnu/bin:/usr/sbin:/sbin
$
When I try extended grep like this it does not work.
const char *grep[] = { "grep", "-E", "'JOBS|COMPIZ'" };
If I do it just for one string without single quotes then it works. Why? Why can't I build up arguments to extended grep like above? The following with just one string is working.
const char *grep[] = { "grep", "-E", "JOBS" };
My program should do printenv | sort | grep <parameter-list> | less and if no arguments to main then the program should do printenv | sort | less. I already achieved the latter functionality and now I need to achieve the grep of parameter list but I can't seem to do extended grep from within C code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
struct command
{
const char **argv;
};
int
spawn_proc (int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork ()) == 0)
{
if (in != 0)
{
dup2 (in, 0);
close (in);
}
if (out != 1)
{
dup2 (out, 1);
close (out);
}
return execvp (cmd->argv [0], (char * const *)cmd->argv);
}
return pid;
}
int
fork_pipes (int n, struct command *cmd)
{
int i;
pid_t pid;
int in, fd [2];
/* The first process should get its input from the original file descriptor 0. */
in = 0;
/* Note the loop bound, we spawn here all, but the last stage of the pipeline. */
for (i = 0; i < n - 1; ++i)
{
pipe (fd);
/* f [1] is the write end of the pipe, we carry `in` from the prev iteration. */
spawn_proc (in, fd [1], cmd + i);
/* No need for the write and of the pipe, the child will write here. */
close (fd [1]);
/* Keep the read end of the pipe, the next child will read from there. */
in = fd [0];
}
/* Last stage of the pipeline - set stdin be the read end of the previous pipe
and output to the original file descriptor 1. */
if (in != 0)
dup2 (in, 0);
/* Execute the last stage with the current process. */
return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}
int
main (int argc, char ** argv)
{
printf("in main...");
int i;
if (argc == 1) {
const char *printenv[] = { "printenv", 0};
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {sort}, {less} };
return fork_pipes (3, cmd);
}
if (argc > 1) {
/*char *tmp = argv[1];
sprintf(tmp, "%s%s", "'", tmp);*/
for( i=1; i<argc-1; i++)
{
/* tmp = "%s%s%s", tmp, "\\|", argv[i];
printf("tmp:%s", tmp);
sprintf(tmp, "%s%s%s", tmp, "|", argv[i]);
sprintf(tmp, "%s%s", tmp, "'");*/
}
const char *printenv[] = { "printenv", 0};
const char *grep[] = { "grep", "-E", "JOB" };
const char *sort[] = { "sort", 0 };
const char *less[] = { "less", 0 };
struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
return fork_pipes (4, cmd);
}
}
Don't use single quotes in the argument. They are needed only on the command line to prevent shell from interpreting the vertical bar.