I have a task to write a c program that can search for a directory in all the directories listed in $PATH using fork and exec. My question is how do i get the paths from $PATH in a manner that i can then use it in my code with execl
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char* argv[]) {
int pid = 0;
for(int i = 0; i < argc; i++) {
if (pid = fork() != 0){
printf("Arg%d: %c\n", i, *argv[i]); // replace with exec ls -l <dir>/<arg>
return 0;
}
}
return 0;
}
You can get the PATH environment variable using getenv() (man 3 getenv). Copy the string into a char* and then split it with strtok() (man 3 strtok) using ':' as delimiter. You should copy the original string into a new char* because the pointer you get from getenv() actually points inside the environment and strtok() will modify the argument you pass to it. You can then fork in a loop for each substring.
Related
I would like to get argv from an LD_PRELOAD library, for instance, let us assume we call
LD_PRELOAD=/path/to/my/fopen ./program input
Inside my custom fopen I would like to get "input", hence the argv[1] of my program (also the argv[2] and so on).
Is it possible? How?
Read entire /proc/self/cmdline file. Command line arguments are separated with \0.
See man proc for full details.
Linux example without C standard library or error handling:
#include <unistd.h>
#include <fcntl.h>
#include <linux/limits.h>
int main() {
ssize_t i, n;
char cmdline[ARG_MAX];
int cmdline_fd = open("/proc/self/cmdline", O_RDONLY);
n = read(cmdline_fd, cmdline, sizeof cmdline);
for(i = 0; i < n; ++i)
if(!cmdline[i])
cmdline[i] = ' ';
cmdline[n - 1] = '\n';
write(STDOUT_FILENO, cmdline, n);
return 0;
}
Python version for reference:
cmdline = open('/proc/self/cmdline', 'r').read().replace('\0', ' ').strip()
print(cmdline)
I'm using execvp() to run some system calls. Program works great for valid commands, and fails for any command that doesn't exist, which is perfect.
The program is, when I use execvp() on a command that needs extra arguments(like cat) and I don't provide arguments, the program just infinitely reads from input.
I'm not sure how to get around this issue, as I don't know how to 'tell' if a command is incomplete. Any ideas?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
char command[1000];
printf("Enter command: ");
scanf("%[^\n]s", command);
char *temp = strtok(command, " ");
char *commandList[100];
int index = 0;
while (temp != NULL) {
commandList[index] = temp;
index++;
temp = strtok(NULL, " ");
}
commandList[index] = NULL;
execvp(commandList[0], commandList);
printf("Failed");
}
The ideal result would be a print of "Command incomplete" and the process ending.
One of the ideas from the comment completely answered my question (To the exact needs I had). Not sure how to give him credit on here, though.
The solution is to simply close stdin right before I use execvp(). If the command is not completed on the first scanf, the program throws an error, which is perfect.
Since I'm running the main program I'm using this on in a loop, I can use dup and dup2 to save and reload stdin later.
The code I used to test if it'll work:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
char command[1000];
int stdinput = dup(STDIN_FILENO);
close(STDIN_FILENO);
dup2(stdinput, STDIN_FILENO);
printf("Enter command: ");
scanf("%[^\n]s", command);
printf("%s\n", command);
}
I have an assignment, to create a simple linux shell using exec() that runs basic commands (e.g ls, ps) without arguments. When i run the code the execv is not working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char argv[100];
char* path= "/bin/";
char progpath[20];
while(1)
{
printf("My shell>> ");
gets(argv);
if(strcmp(argv, "exit\n")==0){
break;
}
strcpy(progpath, path);
strcat(progpath, argv);
for(int i=0; i<strlen(progpath); i++){
if(progpath[i]=='\n'){
progpath[i]='\0';
}
int pid= fork();
if(pid==0){
execvp(progpath,argv);
exit(1);
}else{
wait(NULL);
}
return 0;
}
}
}
gets(argv) is expecting a char array, not a pointer to a array of char arrays.
change
char* argv[100];
to
char argv[100];
And then
strcat(progpath, argv[0]);
to
strcat(progpath, argv);
Note also that gets etc, is assuming you are not going to provide too many characters to fit in the array, so if the user enters a value that will be more than the 14 characters then progpath will overflow.
You are missing includes for fork, wait etc - likely to be
#include <sys/types.h>
#include <unistd.h>
After that, why for(int i=0; i<strlen(progpath); i++) and run the execvp each character of the progpath ? I assume you are meaning to have to the closing brackets before then.
for(int i=0; i<strlen(progpath); i++){
if(progpath[i]=='\n'){
progpath[i]='\0';
}
}
int pid= fork();
execva expects an array of char arrays, which is probally why you decided to use char *argv[] originally, but is not valid now - use one of the execl type functions instead.
Lastly, there is a chance that ls is a bashonly command - not a real command, so may not work anyway.
use
argv is declared as an array of unallocated strings and is used as an allocated string. As a first step you should remove the * in char* argv[100];.
Here is the general problem:
The program must fork() and wait() for the child to finish.
The child will exec() another program whose name is INPUT by the user.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int status;
char input[BUFSIZ];
printf(">");
scanf("%s",input);
char *args[] = {"./lab1"};
pid_t pid = fork();
if(pid==0){
execvp(args[0],args);
}else if(pid<0){
perror("Fork fail");
}else{
wait(&status);
printf("My Child Information is: %d\n", pid);
}
return 0;
}
My problem is getting the user to input a program name to run (at the ">" prompt) and getting that input into execvp (or another exec() function if anyone has any ideas)
I'm going to hold off lambasting you for using scanf("%s") for now, though you should be aware it's really not robust code.
Your basic task here is going to be taking a character array entered by the user and somehow turning that into an array of character pointers suitable for passing to execvp.
You can use strtok to tokenise the input string into tokens separated by spaces, and malloc/realloc to ensure you have enough elements in an array to store the strings.
Alternatively, since you already have a potential buffer overflow issue, it may be good enough to just use a fixed size array.
For example, the following program shows one way of doing this, it uses a fixed string echo my hovercraft is full of eels and tokenises it to be suitable for execution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static char *myStrDup (char *str) {
char *other = malloc (strlen (str) + 1);
if (other != NULL)
strcpy (other, str);
return other;
}
int main (void) {
char inBuf[] = "echo my hovercraft is full of eels";
char *argv[100];
int argc = 0;
char *str = strtok (inBuf, " ");
while (str != NULL) {
argv[argc++] = myStrDup (str);
str = strtok (NULL, " ");
}
argv[argc] = NULL;
for (int i = 0; i < argc; i++)
printf ("Arg #%d = '%s'\n", i, argv[i]);
putchar ('\n');
execvp (argv[0], argv);
return 0;
}
Then it outputs the tokenised arguments and executes it:
Arg #0 = 'echo'
Arg #1 = 'my'
Arg #2 = 'hovercraft'
Arg #3 = 'is'
Arg #4 = 'full'
Arg #5 = 'of'
Arg #6 = 'eels'
my hovercraft is full of eels
How does one create a function that takes another command as an argument and executes that command. For example say I wanted to do
./func1 cat /etc/motd
and have it execute the cat command on the file /etc/motd so that it would print the message of the day. If someone could show me that would be much appreciated!
EDIT: I cannot use the system() call as later on I have to program a basic command shell. I just need to know how to execute commands so that when a user types in cat foo.txt it executes the command and displays the file. I guess what I'm trying to say is, how do you use execve()? What arguments go inside it?
Use you can use the system function.
Example:
system("cat foo.txt");
Will run this:
cat foo.txt
You could do something like that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
size_t command_length = 0;
if(argc < 2)
return 0;
for(int i = 1; i < argc; i++)
command_length += strlen(argv[i]);
command_length += argc - 2; // spaces between words
command_length++; // terminator '\0'
char command[command_length];
memset(command, 0, sizeof(command));
for(int i = 1; i < argc; i++) {
strcat(command, argv[i]);
if(i < argc - 1)
command[strlen(command)] = ' ';
}
system(command);
}
It first determines the length of all command line parameters. After that it concatenates all command line parameters and inserts a space between each. Last but not least it calls the system() function with this string.
You need to use a C11 compiler with VLA support.
Here is a version without system():
#include <string.h>
#include <unistd.h>
#define MAX 1024
int main(int argc, char *argv[]) {
char buf[MAX] = "/usr/bin/";
size_t len = MAX - strlen(buf) + 1;
if(argc < 2)
return 0;
strncat(buf, argv[1], len);
execve(buf, argv + 1, NULL);
return 0;
}
This program only works under Linux. Unfortunately the execve() expects an absolute path. I assumed that the executable is located under /usr/bin. Additional work is necessary if that's not the case. For example you would have to examine the $PATH environment variable.