How do I pass pipes and other values through command line parameters in C?
I'm trying to create a several programs, where the first one initiates all the required IPC elements. The problem I am having is executing the subsidiary programs with the values from the first. I have tried the following:
int sem_id = semget (key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
if (pipe (pipe1)){
printf("Error: %s",strerror(errno));
exit(1);
}
if(execl("/home/tropix/program-3","/home/tropix/program-3", sem_id, shmid, pipe1,开发者_开发技巧 (char*)0) == 0){
fprintf(stderr, "File Execution of program 3 failed.\n");
exit(1);
}
Program 3 is not executing, so I obviously have a problem with my execl statement. If I remove the variables sem_id, shmid and pipe2 it runs.
Thanks for any suggestions.
Edit: added statements for creating shmid and sem_id. I can print these int's to stdout, so I'm sure they have a value. And as far as knowing whether program 3 is executing, see program 3:
main(int argc, char *argv[]){
int x;
printf("Number of args = %d", argc);
for(x=0;x<argc;x++){
printf("arg#: %d, %s\n",x,argv[x]);
}
}
Another note: I have compiled program 3. If I remove the execl arguments and replace them with quoted words ("test"), they show up as arguments in the child page. But in this case, NOTHING is printing from program 3.
The arguments to a program must all be strings.
Therefore, to pass the semaphore ID, shared memory ID and file descriptor to the executed program, you need the calling program code to convert the numbers into strings, and the executed program to convert the strings back into number which it then uses appropriately.
Your code doesn't show 'pipe2'...I've assumed it was a simple int
, but if it was an array (like pipe1
is), then you need to subscript it with 0 or 1 to get the relevant file descriptor:
char shmarg[20];
char semarg[20];
char piparg[20];
int semid = semget (key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
const char *cmd = "/home/tropix/program-3";
if (pipe(pipe1))
{
printf("Failed to create pipe: %s\n", strerror(errno));
exit(1);
}
snprintf(shmarg, sizeof(shmarg), "%d", shmid);
snprintf(semarg, sizeof(semarg), "%d", semid);
snprintf(piparg, sizeof(piparg), "%d", pipe2);
execl(cmd, cmd, semarg, shmarg, piparg, (char*)0);
fprintf(stderr, "File Execution of program 3 failed.\n");
exit(1);
It is not clear why you have pipe1
created; you need to do appropriate plumbing with it. If the execl()
returns, it failed. You don't need to test its return value.
From the comments:
[I'm] just cutting out the relevant sections for simplicity [...] [I'm] not sure what you mean about the "appropriate plumbing" with pipe1? Can you tell me how it should be done, or refer me to some information on how I can initialize the pipe and pass it to the next file? I realize creating the pipe in the program that requires it might be a better option, but in this case, initializing it in program 1 is a requirement.
Simplicity in the question is a good idea...
I assume that between the call to pipe()
and the execl()
, there was a fork()
that was omitted. Otherwise, the pipe()
makes no sense whatsoever.
Presumably, the intent of creating the pipe is to let the child process talk to the parent, or for the parent process to talk to the child. There are bi-directional pipes, but they're neither standard nor portable; therefore, I assume you have a regular uni-directional pipe. Since you are passing the file descriptor number as an argument to the child, we are not redirecting standard input or standard output for the child - which is what you often (but not always) do with a pipe.
So, your revised code could be (blank lines removed to avoid scroll bar):
char shmarg[20];
char semarg[20];
char piparg[20];
int semid = semget(key1, 4, IPC_CREAT | 0666);
int shmid = shmget(key2, 1024, 0644 | IPC_CREAT);
int pipe1[2];
const char *cmd = "/home/tropix/program-3";
if (pipe(pipe1))
{
printf("Failed to create pipe: %s\n", strerror(errno));
exit(1);
}
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork");
else if (pid > 0)
{
/* Do parental things */
close(pipe1[0]);
...write to pipe1[1]...
}
else
{
/* Do childish things */
/* Assuming child is reading from pipe */
close(pipe1[1]);
snprintf(shmarg, sizeof(shmarg), "%d", shmid);
snprintf(semarg, sizeof(semarg), "%d", semid);
snprintf(piparg, sizeof(piparg), "%d", pipe1[0]);
execl(cmd, cmd, semarg, shmarg, piparg, (char*)0);
fprintf(stderr, "File Execution of program 3 failed.\n");
exit(1);
}
Clearly, if the pipe is read by the parent and written by the child, you need to juggle the closes and the specified file descriptor number.
Almost always, you end up closing at least one of the two file descriptors returned from pipe()
. If you redirect the pipe to standard input or standard output, you normally use dup2()
to duplicate the appropriate end of the pipe, and then close both file descriptors returned from pipe()
. Since all of this is messing with pipes, it is colloquially known as plumbing.
I'm going to assume that sem_id, shmid and pipe2 are not null terminated strings. You will have to convert them to that as they are they are command's arguments, just like as they would be on the command line.
How do you know that program-3
is not running? The execl
call looks okay provided that /home/tropix/program-3
is an executable program. Could you provide definitions for sem_id
, shmid
, and pipe2
?
精彩评论