Thread: Problem with readlink()?

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    16

    Problem with readlink()?

    Hello...

    I am working on a program and I don't quite understand why my last line "Child completed" is not printed out. My idea is to output for the main process in the task, (i) the executable and its pathname used and (ii) the command line used.

    I have the following codes:
    Code:
    int main() {
            int pid, child_pid;
    	char *pid_string;
    	char *buf;
    	char *temp = "/proc";
    	pid = fork();
    	if(pid > 0) {	
    		printf("Parent\n");
    		wait(NULL);
    	}
    	
    	else if(pid == 0) {
    		printf("Child\n");
    		child_pid = getpid();
    		printf("temp1: %s", temp);
    		
    		sprintf(pid_string, "%d", child_pid); // Convert integer to string
    		printf("pid_string %s", pid_string);
    		
    		strcat(temp, pid_string);
    		strcat(temp, "/exe");
    		printf("\ntemp3: %s\n", temp);
    		
    		int len = readlink(temp, buf, sizeof(buf)-1);
    		
    	 	if (len == -1) {
    			// The call failed.
    			if (errno == EINVAL) {
    				// It's not a symbolic link; report that.
    				fprintf (stderr, "%s is not a symbolic link\n", temp);
    			}
    			
    			else {
    				// Some other problem occurred; print the generic message.
    				perror("readlink");
    				return 1;
    			}
    			
    		}
    		
    		else {
    			// NUL-terminate the target path.
    			buf[len] = '\0';
    			// Print it.
    			printf ("%s\n", buf);
    			return 0;
    		}
    		
    		printf("\nChild completed\n");
    	}
    	
    	else {
    		perror(" fork failed...");
    		exit(1);
    	}
    	
    	return 0;
    }
    My problem is, I don't get the words "Child completed" printed at the end when the child finishes. However, if I commet away the codes from sprintf to the bracket just before the printf for "Child completed", I get it printed out.

    Is there something wrong with readlink, or is there already something wrong with the conversion of the integer of pid to string?

    I know readlink would get me the path using readlink on the file exe in the /proc folder, exit status is from the waitpid(). What about the processes and commandlines (which i omitted for this code)? Should I readlink the cmdline in the /proc/[pid] folder as well?

    Thanks a lot... =)

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > int len = readlink(temp, buf, sizeof(buf)-1);
    1. C doesn't have mixed declarations and statements (yet).
    Move "int len;" to the start of the block.

    2. buf isn't allocated any space, so you're just trashing unknown memory (or the process is dying with a segfault).

    char buf[BUFSIZ];
    should fix that.

    > strcat(temp, pid_string);
    temp is a string constant, so
    1. You can't modify it
    2. Even if you could modify it, there is no room.

    Perhaps
    char temp[200] = "/proc";

    Your pid_string is similarly cripped.

    You could do the whole thing with a single sprintf call, say
    sprintf( temp, "/proc/%d/exe", child_pid );
    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.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Thanks a lot Salem. Tried your suggestions, and it worked. So happy... However, the last line "Child Completed" still doesn't printe out. Humm...

    Now I try to include the execvp to run ./busywait and use readlink to get the path of this ./busywait using the child_pid. ./busywait is a program which just performs some 'useless' computations for around 1 second, by default if no arguments put in. Upon completion, it will print out the time taken to run the codes.

    If I leave the readlink alone, ./busywait will finish in 1 sec as per coded. However, if I put in the readlink, be it above or below the execvp, it ended up finishing in 0 sec. The readlink also has got no effect, i.e., it doesn't show the path of the ./busywait in the child and also in parent neither.

    Here's the modification of the previous codes:
    Code:
    int main(){
    	int pid, child_pid;
    	char *pid_string;
    	char buf[50];
    	char temp[50];
    	int len;
    	int execStatus;
    	int status;
    	char *parameter[10];
    	
    	pid = fork();
    	
    	if(pid > 0) {	
    		printf("Parent\n");
                    //len = readlink(temp, buf, sizeof(buf) - 1);
    		waitpid(-1, &status,0);
    		printf("\nexit status: %d\n", status);
    	}
    	
    	else if(pid == 0) {
    		printf("Child\n");
    		child_pid = getpid();
    		sprintf(temp, "/proc/%d/exe", child_pid);
    		parameter[0] = "./busywait";
    		parameter[1] = '\0';
    		
    		//len = readlink(temp, buf, sizeof(buf) - 1);
    		
    		execStatus = execvp("./busywait", parameter);
    		if (execStatus < 0) {
    			perror("Error in executing the process");	
    		}
    		
    		//len = readlink(temp, buf, sizeof(buf) - 1);
    		
    	 	if (len == -1) {
    			// The call failed.
    			if (errno == EINVAL) {
    				// It's not a symbolic link; report that.
    				fprintf (stderr, "%s is not a symbolic link\n", temp);
    			}
    			
    			else {
    				// Some other problem occurred; print the generic message.
    				perror("readlink error");
    				return 1;
    			}
    			
    		}
    		
    		else {
    			buf[len] = '\0';
    			printf ("%s\n", buf);
    			return 0;
    		}
    		
    		printf("\nChild completed\n");
    	}
    	
    	else {
    		perror("fork fail...");
    		exit(1);
    	}
    	
    	return 0;
    }
    What could be the problem? Thank you very much!

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    If the execvp call succeeds, then nothing after it will happen. All the code which was the child code is replaced by the program you run.
    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.

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Oh I see. But how come the readlink before the execvp couldn't work?

    The earlier version too, the "Child finished" also not pritned.

    Thank you very much. =)

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Post your best attempt so far just calling readlink()
    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.

  7. #7
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    This is the one which I have readlink() successfully printed out the path. It does gives me the path from the readlink, and the ./busywait program is executed. My idea is to get the path of the ./busywait and it's exit status. ./busywait is a program which performs some 'useless' computations for approximately 1 second.

    From what I get from readlink now, it gives me the path of main program (/home/QuietBoi/Desktop/TestSysCommand/sys_commandv3) which I run this code on. This sounds logical as readlink is run before execvp. But if I put it after the execvp, the ./busywait program would replace all my child codes from that line onwards. How do I get the path of the ./busywait, say (/home/QuietBoi/Desktop/TestSysCommand/busywait), or even other directories depends on where ./busywait is run?

    Thanks a lot for your help. =)

    Code:
    int main(){
    	int pid, child_pid;
    	char buf[50];
    	char temp[50];
    	int len;
    	int execStatus;
    	int status;
    	char *parameter[10];
    	
    	pid = fork();
    	
    	if(pid > 0) {	
    		printf("Parent\n");
    		waitpid(-1, &status,0);
    		printf("\nexit status: &#37;d\n", status);
    	}
    	
    	else if(pid == 0) {
    		printf("Child\n");
    		child_pid = getpid();
    		sprintf(temp, "/proc/%d/exe", child_pid);
    		parameter[0] = "./busywait";
    		parameter[1] = '\0';
    		
    		
    		len = readlink(temp, buf, sizeof(buf) - 1);
    		
    	 	if (len == -1) {
    			// The call failed.
    			if (errno == EINVAL) {
    				// It's not a symbolic link; report that.
    				fprintf (stderr, "%s is not a symbolic link\n", temp);
    			}
    			
    			else {
    				// Some other problem occurred; print the generic message.
    				perror("readlink error");
    				return 1;
    			}
    			
    		}
    		
    		else {
    			buf[len] = '\0';
    			printf ("%s\n", buf);
    		}
    		
    		execStatus = execvp("./busywait", parameter);
    		if (execStatus < 0) {
    			perror("Error in executing the process");	
    		}
    		
    		printf("\nChild completed\n");
    	}
    	
    	else {
    		perror("oops why did fork fail?");
    		exit(1);
    	}
    	
    	return 0;
    }
    Last edited by QuietBoi; 04-08-2007 at 02:24 AM.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > How do I get the path of the ./busywait, say
    By saying "./", aren't you just implying that busywait is in the same directory?

    If you just used "busywait", then execvp() would indeed search the PATH variable looking in all the directories to see which contains that file. This search is pretty trivial for you to implement directly. There is certainly a command called 'which', which tells you where specific executables are located. I can't remember at the moment whether that maps to some actual API call or not.

    To do it with the method you have already, simply call fork() again, then execvp() in the child of the child, and do another readlink() as you do at the moment, using the pid() of the second fork.
    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.

  9. #9
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Yes, I do have a function earlier which setenv to a PATH. So I should use execvp(busywait) instead and it would go to the PATH to search for the correct path.

    I thought when using execvp, busywait program would take up the child's PID to run since it replaces everything that follows? Why would I need to fork out again and relink to that 'grandchild' PID?

    I've tried to execvp in the current child, and do the readlink in the parent after the waitpid. busywait program ran, but it didn't run for the expected result of 1 seconds. Also, the readlink didn't work, saying that it couldn't get the directory.

    Code:
    int main(){
    	int pid, child_pid;
    	char buf[50];
    	char temp[50];
    	int len;
    	int execStatus;
    	int status;
    	char *parameter[10];
    	
    	setenv("PATH", "home/QuietBoi/Desktop/TestSysCommand", 1);
    	pid = fork();
    	
    	if(pid > 0) {
    		printf("Parent\n");
    		waitpid(-1, &status, 0);
    		
    		sprintf(temp, "/proc/&#37;d/exe", child_pid);
    		len = readlink(temp, buf, sizeof(buf) - 1);
    		
    	 	if (len == -1) {
    			// The call failed.
    			if (errno == EINVAL) {
    				// It's not a symbolic link; report that.
    				fprintf (stderr, "%s is not a symbolic link\n", temp);
    			}
    			
    			else {
    				// Some other problem occurred; print the generic message.
    				perror("readlink error");
    				return 1;
    			}
    			
    		}
    		
    		else {
    			buf[len] = '\0';
    			printf ("%s\n", buf);
    		}
    		
    		printf("\nexit status: %d\n", status);
    	}
    	
    	else if(pid == 0) {
    		printf("Child\n");
    		child_pid = getpid();
    		
    		parameter[0] = "busywait";
    		parameter[1] = '\0';
    		
    		execStatus = execvp("busywait", parameter);
    		if (execStatus < 0) {
    			perror("Error in executing the process");	
    		}
    		
    		printf("\nChild completed\n");
    	}
    	
    	else {
    		perror("oops why did fork fail?");
    		exit(1);
    	}
    	
    	return 0;
    }
    Result I get:
    Code:
    Child
    Parent
    
    
    busywait program finished in 0 secs
    
    
    readlink error: No such file or directory
    Maybe you roughly sketch out your idea, how the code could look like?

    Thanks a lot. =)
    Last edited by QuietBoi; 04-08-2007 at 03:35 AM.

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > I thought when using execvp, busywait program would take up the child's PID
    Yes it does.
    You can do anything you like in the child, but the last thing you can do is the exec() call.


    Perhaps do the readlink() stuff in the parent if you want to save a fork()?
    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.

  11. #11
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Yes, I did. Included my codes at the earlier post, thought could save some space... Copy & paste here agian:

    I've tried to execvp in the current child, and do the readlink in the parent after the waitpid. busywait program ran, but it didn't run for the expected result of 1 seconds. Any possible reasons? Also, the readlink didn't work, saying that it couldn't get the directory. Seems like it couldn't get the PID in time and read the /proc directory. Same results if I put the readlink above the waitpid

    Code:
    int main(){
    	int pid, child_pid;
    	char buf[50];
    	char temp[50];
    	int len;
    	int execStatus;
    	int status;
    	char *parameter[10];
    	
    	setenv("PATH", "home/QuietBoi/Desktop/TestSysCommand", 1);
    	pid = fork();
    	
    	if(pid > 0) {
    		printf("Parent\n");
    		waitpid(-1, &status, 0);
    		
    		sprintf(temp, "/proc/%d/exe", child_pid);
    		len = readlink(temp, buf, sizeof(buf) - 1);
    		
    	 	if (len == -1) {
    			// The call failed.
    			if (errno == EINVAL) {
    				// It's not a symbolic link; report that.
    				fprintf (stderr, "%s is not a symbolic link\n", temp);
    			}
    			
    			else {
    				// Some other problem occurred; print the generic message.
    				perror("readlink error");
    				return 1;
    			}
    			
    		}
    		
    		else {
    			buf[len] = '\0';
    			printf ("%s\n", buf);
    		}
    		
    		printf("\nexit status: %d\n", status);
    	}
    	
    	else if(pid == 0) {
    		printf("Child\n");
    		child_pid = getpid();
    		
    		parameter[0] = "busywait";
    		parameter[1] = '\0';
    		
    		execStatus = execvp("busywait", parameter);
    		if (execStatus < 0) {
    			perror("Error in executing the process");	
    		}
    		
    		printf("\nChild completed\n");
    	}
    	
    	else {
    		perror("oops why did fork fail?");
    		exit(1);
    	}
    	
    	return 0;
    }
    Result I get:
    Code:
    Child
    Parent
    
    
    busywait program finished in 0 secs
    
    
    readlink error: No such file or directory
    Anywhere could have gone wrong?

    Thanks a lot. =)

  12. #12
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    From the above codes, I added in more printf to print the child_pid and here's the result:

    Code:
    Child
    
    In Child: Child pid: 2973
    Parent
    
    
    busywait program finished in 1 secs
    
    In Parent: Child PID: -1080733704
    exit status: 0
    Seems like parent couldn't get the child_pid right... But if I have the readlink after the waitpid, the busywait would have finished by then and there's no point in looking at /proc folder again as the folder containing the PID would have been gone. However, if I have it above, parent couldn't get the child_pid right. Humm...

    Is there a way to execute the readlink while the busywait program is running so that it could get both the child_pid right and the folder in /proc is still around? Any suggestions on where to put the readlink? Thanks... =)
    Last edited by QuietBoi; 04-08-2007 at 04:06 AM.

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Code:
    	if(pid > 0) {
    		printf("Parent\n");
    		waitpid(-1, &status, 0);
    		
    		sprintf(temp, "/proc/&#37;d/exe", pid);  // pid here is the child pid
    In the parent, child_pid is just an uninitialised var
    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.

  14. #14
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Thanks a lot Salem, just figured it out during the numerous tryouts just now. Didn't know that it's just that simple. Haha... Guess I'm still very new in C.

    But then, readlink still can't get the folder right. it still has the

    Code:
    readlink error: No such file or directory.
    Tried before the waitpid and after waitpid also the same error. Where else could I put the readlink so that i can get the path of busywait? Maybe I should sleep for a short while in parent before I readlink? But what happens if busywait takes a very short time, say 0.1ms? After I wait, the process is gone also.

    Thank you very much. =)

  15. #15
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Thank you very much Salem. Finally got it working. Million thanks!

    Now another problem: To get the commands busywait invoked.

    Take example, busywait creates a child process with the command line gcc test.c
    How could I capture the command line and it's path of the program:

    /usr/bin/gcc: gcc test.c

    I think that it has got to do with cmdLine in the /proc. How can I use this? readlink cmdLine doesn't work. Any other special functions which I could use?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Memory problem with Borland C 3.1
    By AZ1699 in forum C Programming
    Replies: 16
    Last Post: 11-16-2007, 11:22 AM
  2. Someone having same problem with Code Block?
    By ofayto in forum C++ Programming
    Replies: 1
    Last Post: 07-12-2007, 08:38 AM
  3. A question related to strcmp
    By meili100 in forum C++ Programming
    Replies: 6
    Last Post: 07-07-2007, 02:51 PM
  4. WS_POPUP, continuation of old problem
    By blurrymadness in forum Windows Programming
    Replies: 1
    Last Post: 04-20-2007, 06:54 PM
  5. beginner problem
    By The_Nymph in forum C Programming
    Replies: 4
    Last Post: 03-05-2002, 05:46 PM