Thread: using execvp()/fork() to catenate a file

  1. #1
    Registered User
    Join Date
    Jun 2007
    Posts
    11

    Question using execvp()/fork() to catenate a file

    Hi guys,
    I'm still working on my shell. I'm trying to implement a function typefile that will take a command line input as follows:

    > type <file1>

    This command will implement a catenation of file1, equal to the command cat <file1>

    I need to use execvp() and fork() system calls to create a new process that will type/cat any text file. In my code below, the execvp() call in the function at the bottom gets me the following:

    o-shell.c:128: warning: passing arg 2 of `execvp' from incompatible pointer type

    I know for sure i'm calling execvp incorrectly, any tips/pointers would be great. I want to use /bin/cat followed by filename as the argument.

    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
    	//VARIABLE DECLARATIONS
    
    	char command[50];				//Command line input
    
    	//tokens for strtok() funtion
    	char * com;						//Primary command
    	char * arg1;					//First argument of command (usually a file name)
    	char * arg2;					//2nd argument of command (usually a file name)
    
    	int args;						//Number of arguments entered
    
    	//FUNCTION DECLARATIONS
    
    	void typefile(char * filename);
    
    	printf("***************************************************\n");
    	printf("Welcome to O-Shell! A UNIX shell by O Haqqi\n\n");
    	printf("Type 'help' for list of commands, 'exit' to exit\n");
    	printf("***************************************************\n");
    
    	for(;;)
    	{
    
    	printf("o-shell>");						//user prompts for o-shell
    
    	fgets(command, 1024, stdin);		//command line input from user
    
    	com = strtok(command, " \r\n\t");
    
    	args = 0;
    	arg1 = strtok(NULL, " \r\n\t");
    	if(arg1) args++;						//to see if arguments being tracked
    	arg2 = strtok(NULL, " \r\n\t");
    	if(arg2) args++;						//to see if arguments being tracked
    
    	if(com != NULL)			//Can only execute commands if a command is entered
    							//Otherwise it keeps looping and printing prompt
    	{
    	printf("command entered: %s\n", com);
    	printf("There are %d arguments\n", args);
    
    	if ((strcmp(com,"help")) == 0 || (strcmp(com,"Help")) == 0)
    	{
    		printf("***************************************************\n");
    		printf("\nO-Shell Help Menu:\n");
    		printf("\nhelp - Print help menu\n");
    		printf("\nexit - Exit O-Shell\n");
    		printf("\ntype <file> - Print contents of <file> to terminal\n");
    		printf("\ncopy <file1> <file2> - Copy contents of <file1> to <file2>.");
    		printf("\n     <file2> must be a non-existent file and will be created\n");
    		printf("\ndelete <file> - Delete <file> from system\n");
    		printf("***************************************************\n");
    	}
    
    	else if ((strcmp(com,"exit")) == 0 || (strcmp(com,"Exit")) == 0)
    	{
    		printf("Exiting O-Shell...Goodbye!\n");
    
    		//if exit command is entered, exit() system call is performed
    		exit(1);
    	}
    
    	else if ((strcmp(com,"type")) == 0 || (strcmp(com,"Type")) == 0)
    	{
    		if((arg1 == NULL) || (arg2 != NULL))		//arg1 must exist, arg2 must be empty
    		{
    			printf("Incorrect number of arguments! Type 'help' for correct format.\n");
    		}
    
    		else
    		printf("Printing contents of file: %s\n", arg1);
    		printf("***************************************************\n");
    
    		typefile(arg1);			//call typefile function (see below)
    	}
    
    	else
    	printf("Invalid command!!! Type 'help' for list of valid commands.\n");
    
    	}
    
    	}
    
    	return 0;
    }
    
    /************************************************************************************************
    Function typefile() prints contents of a file to the terminal
    Format: type <file1>
    ************************************************************************************************/
    
    void typefile(char * filename)
    {
    	int pid, status;
    
    	const char cat[] = "/bin/cat";
    
    	pid = fork();
    
    	if(pid < 0)
    	printf("ERROR: Child pid = %i FORK FAILED! Please try again.\n", pid);
    
    	else if(pid > 0)
    	printf("ERROR: Child pid = %i Parent process executing, FORK FAILED!\n", pid);
    
    	else if(pid == 0)				//If the process id is zero, fork() was successful
    	{
    		printf("Child pid = %i FORK SUCCESSFUL...\n");
    
    		execvp(cat, filename);
    	}
    
    }

  2. #2
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Code:
    	//FUNCTION DECLARATIONS
    
    	void typefile(char * filename);
    these don't go in functions
    Code:
    	pid = fork();
    
    	if(pid < 0)
    	printf("ERROR: Child pid = %i FORK FAILED! Please try again.\n", pid);
    
    	else if(pid > 0)
    	printf("ERROR: Child pid = %i Parent process executing, FORK FAILED!\n", pid);
    
    	else if(pid == 0)				//If the process id is zero, fork() was successful
    that's not how fork works

    pid should be type pid_t
    Code:
    printf("Child pid = %i FORK SUCCESSFUL...\n"); /* missing argument */

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    In my code below, the execvp() call in the function at the bottom gets me the following:
    Code:
    o-shell.c:128: warning: passing arg 2 of `execvp' from incompatible pointer type
    I know for sure i'm calling execvp incorrectly, any tips/pointers would be great. I want to use /bin/cat followed by filename as the argument.
    Never say that. Because, guess what? You aren't calling execvp() properly.

    From http://man.he.net/man3/execvp:
    Code:
    int execvp( const char *file, char *const argv[]);
    execvp() takes an array of strings as its second argument, not a single string.

    I suggest you use one of these, perhaps execlp():
    Code:
    int execl( const char *path, const char *arg, ...);
           int execlp( const char *file, const char *arg, ...);
           int execle( const char *path, const char *arg , ...,  char* const envp[]);
    You'd use it like this:
    Code:
    execlp(cat, filename, NULL);
    The execl*() functions are easier to use when you have a single string you want to pass to the process.

    [edit]
    Code:
    fgets(command, 1024, stdin);
    is a bad idea when command is an array with 50 elements. Pass 50 to fgets(). Better yet, use
    Code:
    fgets(command, sizeof(command), stdin);
    Code:
    if ((strcmp(com,"help")) == 0 || (strcmp(com,"Help")) == 0)
    Why not implement your own case-insensitive string comparison function? Then "HELP" etc would work as well. It beats calling strcmp() 2^strlen() times. [/edit]
    Last edited by dwks; 07-02-2007 at 12:18 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Registered User
    Join Date
    Jun 2007
    Posts
    11
    thanks for the tips, I finally got the cat command to work...that link was great. I'm having a problem with the child process creation now

    I have testfile.txt to verify that the cat command works. It does work, but the fork() command is assigning a pid other than 0 to the child, or it just looks that way:

    o-shell>type testfile.txt
    command entered: type
    There are 1 arguments
    Printing contents of file: testfile.txt
    ************************************************** *
    ERROR: Child pid = 15966 FORK FAILED! Please try again.

    Child pid = 0 FORK SUCCESSFUL...

    o-shell>This is a test file for the o-shell terminal. Hit <ENTER> to continue.


    Code:
    void typefile(char * filename)
    {
    	int status;
    	char *arg[] = {"cat", filename, NULL};
    
    	pid_t pid = fork();
    
    
    	if(pid == 0)			//pid=0 indicates child process created, fork() was successful
    	{
    		printf("Child pid = &#37;i FORK SUCCESSFUL...\n\n", pid);
    
    		status = execvp("cat", arg);
    
    		while (wait(&status) != pid)		//parent process waits for child process to complete
    		;
    
    	}
    
    	else
    	printf("ERROR: Child pid = %i FORK FAILED! Please try again.\n\n", pid);
    
    }
    Does something glare out and say "this is why the non-zero pid is showing up!!" ?

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Only when pid is less than zero has fork() failed. http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

    Also, don't assume that a pid_t can be printed with &#37;i. I'd use %li and cast pid to (long).
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Quote Originally Posted by dwks View Post
    Only when pid is less than zero has fork() failed.
    according to this, fork will fail with a -1 and set errno.

  7. #7
    Massively Single Player AverageSoftware's Avatar
    Join Date
    May 2007
    Location
    Buffalo, NY
    Posts
    141
    Quote Originally Posted by robwhit View Post
    Code:
    	//FUNCTION DECLARATIONS
    
    	void typefile(char * filename);
    these don't go in functions
    There's nothing wrong with local function declarations.
    There is no greater sign that a computing technology is worthless than the association of the word "solution" with it.

  8. #8
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    oh

    ...

  9. #9
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Local function prototypes seem rather a waste imo. Just stick them in the .h file and be done with them.

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by robwhit View Post
    Code:
    	//FUNCTION DECLARATIONS
    
    	void typefile(char * filename);
    these don't go in functions
    Sure they can. Not typically done, but perfectly legal. You can also bring in extern variable declarations inside a function scope.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  2. archive format
    By Nor in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 08-05-2003, 07:01 PM
  3. Making a LIB file from a DEF file for a DLL
    By JMPACS in forum C++ Programming
    Replies: 0
    Last Post: 08-02-2003, 08:19 PM
  4. Need a suggestion on a school project..
    By Screwz Luse in forum C Programming
    Replies: 5
    Last Post: 11-27-2001, 02:58 AM