Thread: Execvp help

  1. #1
    Registered User
    Join Date
    Jun 2010
    Posts
    4

    Execvp help

    I just need a little help... my program is pretty simple; it uses execlp to read a file, sort it, put the output into a different file, then close the original file. I've gotten this to work but it wouldn't end. I had to use Ctrl+C to stop the program and then the filename~ would have the sorted results but the actual file would be empty. However, in my playing around mixing up some options, I've not been able to get back to that point. Right now I am on a snag about file directories. Can someone point me where my code is wrong and maybe offer a little advice to help me advance?

    Thanks, code is below:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main (int argc, char *argv[])
    {
    	FILE *in_File;
    	int pid, fd;
    	/*open file with read permissions*/
    	if ((in_File = fopen(argv[1], "r+")) == NULL)
    	{
    		fprintf (stderr, "%s: cannot open %s for reading\n", argv[0], argv[1]);
    		exit(1);	
    	}
    	/*create new process or quit */
    	if ( (pid = fork() ) == -1 ) {
    		perror("fork"); 
    		exit(1);
    	}
    	/*child does the work */
    	if (pid == 0) {
    		close(1);
    		fd = creat("userlist", 0644);
    		execlp("sort","sort",in_File,">", "userlist" , NULL);
    		perror("execlp");
    		exit(1);
    	}
    	/*parent waits then reports */
    	if(pid != 0) {
    		wait(NULL);
    		printf("Done running sort.  Results in userlist\n");
    		fclose(in_File);
    	}
    
    }

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Why do you open this file at all? You never read from it. You do not need to open the file to call sort on it.

    Anyway, AFAICT you can't get exec to work this way:
    Code:
    execlp("sort","sort","file.1",">","file.2" NULL);
    execlp("sort","sort file.1 > file.2" NULL);
    execlp("sort","sort","file.1","> file.2" NULL);
    None of these will work. You have to use system() instead.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Jun 2010
    Posts
    4

    Again

    Ok I changed it a bit, but now I'm having trouble getting the file name into the system call... here's what I did:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main (int argc, char *argv[])
    {
    	int pid, fd;
    	char command;
    	
    	/*attempt to get the file name stored in *argv to append to the sort command*/
    	command = strcat("Sort ",argv[1]);
    
    	/*create new process or quit */
    	if ( (pid = fork() ) == -1 ) {
    		perror("fork"); 
    		exit(1);
    	}
    	/*child does the work */
    	if (pid == 0) {
    		close(1);
    		fd = creat("userlist", 0644);
    		system(command);
    		perror("System");
    		exit(1);
    	}
    	/*parent waits then reports */
    	if(pid != 0) {
    		wait(NULL);
    		printf("Done running sort.  Results in userlist\n");
    	}
    
    }

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by hambergler View Post
    Ok I changed it a bit, but now I'm having trouble getting the file name into the system call... here's what I did:

    [code]

    char command;

    /*attempt to get the file name stored in *argv to append to the sort command*/
    command = strcat("Sort ",argv[1]);
    "char command" is one character. Use "char command[1024]" or something.

    You don't have to use fork() with system. You need it with exec() because exec causes the current process to be replaced (notice, no code after an exec() call gets executed). This is not an issue with system().

    So if this is for an assignment that's supposed to teach you about fork and exec, then choose a different task (if not, just use system with no fork).

    WRT argv[1], the argv array is broken on whitespace unless you use quotes. So eg, if your executable is called a.out:

    ./a.out do > this
    argv[1] will be "do", argv[2] will be ">", argv[3] will be "this".
    ./a.out "do > this"
    argv[1] will be "do > this".
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    Jun 2010
    Posts
    4
    This is for a project. I'm learning to close a "line" like stdout or stdin and open another file to connect to the closed line. Thus the fork and the previous execlp. I'm just having trouble with the syntax of the exec family.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by hambergler View Post
    This is for a project. I'm learning to close a "line" like stdout or stdin and open another file to connect to the closed line. Thus the fork and the previous execlp. I'm just having trouble with the syntax of the exec family.
    Okay -- well, you have hit a limitation of exec/execlp. Someone may come along with evidence to the contrary, but I am pretty sure this kind of command:

    sort somefile > someotherfile

    or anything else involving > redirection is not possible. You can't even use pipes (|) with exec. You can really only issue one single command, and provide values for the arguments it accepts. "> somewhere" and "| whatever" are not arguments to the command. They're part of the shell's own I/O functionality. You may be able to pull it off by opening a file and using dup() and pipe() -- but honestly, I would not bother. This is not what is expected of you. You just need to issue a simple command with optional arguments.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    Not sure what you're looking for, but this should work :

    Code:
    char in_file[] = "input_file.txt"
    
    execlp("sort","sort", in_file, NULL);
    You'll also have better luck if you search for pipes by their correct term - pipes. For example, Mapping UNIX pipe descriptors to stdin and stdout in C.

    Also, to clear up what Mk27 said about command line parsing - " >" and "this" don't show up as command line arguments because they're not. The shell strips them off and uses them to figure out how to redirect stdin/stdout. For instance

    ./a.out 1 2 3
    and
    ./a.out 1 2 3 > foo.txt

    both get the same command line arguments passed to them. The only difference is where stdout goes.

    You can replicate what the shell is doing using the pipe() or open() and dup() functions. There are bazillions of tutorials on the web - this is pretty basic Unis stuff so everyone's had to do it for homework before.

    Anyway, I think there's some confusion on exactly what you're trying to accomplish. How about posting a high level view of what you're trying to do instead of thinking you must use fork/exec and so on?
    Last edited by KCfromNC; 06-02-2010 at 10:02 AM.

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by KCfromNC View Post
    Also, what Mk27 said about command line parsing is wrong.
    Incorrect how?

    " >" and "this" don't show up as command line arguments because they're not. The shell strips them off and uses them to figure out how to redirect stdin/stdout.
    Ah, I said as much* -- but further: that does not happen via exec(). Try it. Instead, the command is fed all that as parameters (and chokes, or ignores them).

    ./a.out 1 2 3
    and
    ./a.out 1 2 3 > foo.txt

    both get the same command line arguments passed to them. The only difference is where stdout goes.
    Right, you, I, and the OP already understand this part. The problem is you cannot issue the 2nd command effectively inside an exec(). You would have to set up redirection for the process yourself first.

    * QUOTE: "> somewhere" and "| whatever" are not arguments to the command. They're part of the shell's own I/O functionality.
    Last edited by MK27; 06-02-2010 at 10:07 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > fd = creat("userlist", 0644);
    > execlp("sort","sort",in_File,">", "userlist" , NULL);
    As already pointed out, exec functions do not do redirections.

    What you need to do here is
    Code:
    		close(1);  // close stdout
    		fd = creat("userlist", 0644);  // creat will use the lowest available fd (in this case, 1)
    		execlp("sort","sort",in_File, NULL);  // sort the in_File, writing to the 'new' stdout
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Jun 2010
    Posts
    4
    Thanks guys. You both helped me finish this. KC, you showed me how to finish my execlp command. MK27 you just helped me focus and get away from the other crap. Everyone else, sorry I wasn't reading, I was coding.

    Here's the finished program that works.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    
    int main (int argc, char *argv[])
    {
    	
    	int pid, fd0, fd1;
    	char line[100];
    	
    	/*create new process or quit */
    	if ( (pid = fork() ) == -1 ) {
    		perror("fork"); 
    		exit(1);
    	}
    	/*child does the work */
    	if (pid == 0) {
    
    		close(0);/*close stdin*/
    		close(1);/*close stdout*/
    
    		/*attach stdin to existing file to be sorted*/
    
    		fd0 = open(argv[1], O_RDONLY);
    
    		if (fd0 != 0) {
    			fprintf(stderr, "Could not open data as fd 0\n");
    		}
    		/*attach stdout to created file userlist*/
    		fd1 = creat("userlist", 0644);
    
    		if (fd1 != 1) {
    			fprintf(stderr, "Could not open data as fd 1\n");
    		}
    		
    		execlp("sort","sort",NULL);	
    		perror("execlp");
    		exit(1);
    	}
    	/*parent waits then reports */
    	if(pid != 0) {
    		wait(NULL);
    		printf("Done running sort.  Results in userlist\n");
    	}
    
    }

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Cool. This works too, it was what I was thinking of earlier, but Salem's solution is much simpler:
    Code:
    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, const char *argv[]) {
    	FILE *in, *out;
    	int pipes[2];
    	char buf[256];
    	pid_t pid;
    
    	if (argc < 2) return 0;
    	if (pipe(pipes)) return 0;
    
    	pid = fork();
    	if (!pid) {
    		close(pipes[0]);
    		dup2(pipes[1],1);
    		close(pipes[1]);
    		execlp("sort","sort",argv[1],NULL);
    	} else {
    		out = fopen("out.txt", "w");
    		close(pipes[1]);
    		in = fdopen(pipes[0], "r");
    		while(fgets(buf,256,in)) fprintf(out,"%s", buf);
    		fclose(in);
    		fclose(out);
    	}
    
    	return 0;
    }
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    Quote Originally Posted by MK27 View Post
    Incorrect how?
    We posted at the same time so I was talking about your earlier response -

    ./a.out do > this
    argv[1] will be "do", argv[2] will be ">", argv[3] will be "this".

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by KCfromNC View Post
    We posted at the same time so I was talking about your earlier response -
    ./a.out do > this
    argv[1] will be "do", argv[2] will be ">", argv[3] will be "this".
    Oh yeah, that would be wrong wouldn't it Sorry.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #14
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    I'd just like to point out that you should not pass NULL to execvp(), but (char *)NULL. This matters on systems where NULL is 0 (thus an int), but pointers are not the same size as an int (or when 0 and (char*)NULL have different representations in any way). Technically it could also matter on systems where void* and char* are passed differently, but I don't suppose any of those exist, or will.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by cas
    I'd just like to point out that you should not pass NULL to execvp(), but (char *)NULL. This matters on systems where NULL is 0 (thus an int), but pointers are not the same size as an int (or when 0 and (char*)NULL have different representations in any way). Technically it could also matter on systems where void* and char* are passed differently, but I don't suppose any of those exist, or will.
    I do not think it should matter, unless there is a compiler bug, because 0 is a valid null pointer constant, so the compiler should be expected to account for this.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How do i make an array of pointers for execvp
    By Blasz in forum C Programming
    Replies: 4
    Last Post: 05-18-2010, 10:42 PM
  2. Using execvp
    By kotoko in forum C Programming
    Replies: 21
    Last Post: 01-06-2009, 02:05 PM
  3. Storing the result of execvp to a char array in C
    By kponenation in forum C Programming
    Replies: 1
    Last Post: 12-14-2005, 11:43 PM
  4. Replies: 1
    Last Post: 10-27-2005, 10:24 AM
  5. getting input from keyboard, passing to execvp
    By jumpyg in forum C++ Programming
    Replies: 4
    Last Post: 11-02-2003, 08:49 PM