execvp(): no such file or directory? - c

For some reason, execvp() doesn't find the commands (like ls, pwd, etc.) in my PATH file, which includes /bin. Since I have a customized terminal alias with ls, I'm using pwd, etc. to test (as well as a fresh Linux machine), but I keep getting this for the output:
gcc main.c
./a.out
What would you like to do?
ls
arg[0]: ls
arg[1]: (null)
arg[2]: (null)
arg[3]: (null)
arg[4]: (null)
arg[5]: (null)
arg[6]: (null)
arg[7]: (null)
arg[8]: (null)
arg[9]: (null)
before exec
after exec
ERROR: No such file or directory
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/*
Write a c program that runs a command line program with exactly one command line argument. It should work as follows:
Prompts the user for a program to run via the command line.
Reads in that line (using fgets) and parses it to be used by one of the exec functions.
Runs the command using exec
You do not need to fork off a separate process and wait, the purpose of this assignment is only to parse a single line of input and run a program once.
*/
int main() {
printf("\nWhat would you like to do?\n");
char* input = malloc( 100 ); //100 character string for input
fgets(input, 100, stdin); //reads from stdin (terminal input "file")
//parses command in input (max of 8 flags)
int number_of_args = 10;
char *args[number_of_args];
//puts cmd && flags in args
int i = 0;
for(; i < number_of_args; i++) {
args[i] = strsep( &input, " ");
printf("arg[%i]: %s\n", i, args[i]);
}
args[number_of_args - 1] = 0; //last element for execvp must be NULL;
// printf("nullify final index -> args[%i] = %s\n", number_of_args - 1, args[number_of_args -1]);
printf("before exec\n");
int e = execvp( args[0], args);
printf("after exec\n");
if(e < 0)
printf("ERROR: %s\n", strerror(errno));
return 0;
}
EDIT: Thought it'd be good to include my PATH as well:
echo $PATH
/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

fgets() reads in the newline character if there's space available in the buffer. So when you input ls, it's actually ls\n. Obivously, execvp() can't find such a command and it fails. So the solution is to remove the trailing newline, if any.
char *p = strchr(input, '\n');
if (p) *p = 0;
You should also use argc for argument processing (if you read in the commands and arguments via main()'s argument) rather than assuming some fixed numbers. Or simply break the loop when strsep() returns NULL the first time. Technically, your code invokes undefined behaviour when you print all those null strings.

Related

How to get the output of another program as pipe to my program?

For e.g i have the following program in windows.
#include <stdio.h>
int main(int argc, char *argv[]) {
char *input = argv[1];
printf("your input: %s", input);
return 0;
}
When i run a cmd shell and invoke
C:\>whoami | main.exe
i get as output
your input: (null)
The first argument argv[0] (the filename itself) is passed correct. How to receive the output of whoami as input to my program?
Edit: Since people mostly ask for code if you ask a question, i will also provide code in my answer. Just to be fair. The solution i use (thanks to Gerardo Zinno) is to read from stdin - so i use scanf.
char input[1024] = {0};
read(STDIN_FILENO, input, 1024);
input[strcspn(input, "\n")] = '\0';
printf("you wrote: %s", input);
return 0;
You have to read from the stdin just like if the input was coming from a user typing in the terminal. The pipe will send (link) the stdout of whoami to the stdin of your program.
There are many options to read from the stdin. You can use fread with stdin as last parameter, scanf, fscanf(stdin,...),...

Process returned -1 (0xFFFFFFFF)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)

What's the difference between system() and execve()

I use linux and c.
First, I soft link bin/zsh to sh
Second, I login as root the run the following program.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *v[3];
if(argc < 2) {
printf("Please type a file name.\n");
return 1;
}
v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = 0;
/* Set q = 0 for system(), and q = 1 for execve */
int q = 0;
if (q == 0){
char *command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
sprintf(command, "%s %s", v[0], v[1]);
system(command);
}
else execve(v[0], v, 0);
return 0 ;
}
Third, I login as a normal user(not root).
Now, I can remove or rewrite a file which I don't have write privilege by using the execute file of this program.
Like this:
./a.out text;\`echo \”Not right\”>text\`”
Now I can write "Not right" into the file "text". I only have read privilege of this file
The read and write privilege of these files.
Fourth, I change q to 1. That means, this time I use execve instead.
And do the same thing as above.
But this time I cannot change the content of the file.
Why?
I google in the internet, but I can not find the different between system and execve.
system invokes a shell to parse the string and handle quoting and variable interpolations and stuff. execve does none of this. It replaces the program with the called program and passes the argument strings exactly as specified; ie. it will not interpret quotes.
You said you did chmod 4755 a.out. That means you're setting the setuid bit and the program will then always run with root privileges, and has write access to text. The string with backquote is passed to the shell which interprets it as a command to write to text.
The reason execve doesn't write to text is that it doesn't interpret its arguments as a shell command and ` doesn't have any special meaning.

How to read data from unknown input type (filestream or stdin) C

I wanted to know how to read data from an unknown source of input, meaning I don't know if the user is going to just type a sentence or is he going to give me some text file.
I've tried using fscanf since I've read it is meant for unformatted input type
this is my code, Im suppose to get some type of input(file or just a sentence (echo bla bla bla) and "int" and print only the "int" first words. The program should be used for piping meaning the command would look like that :
There are 2 ways to ways of using the program:
1.echo "blabla" | myprog 2 (number of words to print)
2.cat input.txt | myprog 2 (number of words to print)
The problematic line is line 16, I tried using fscanf
Thanks!
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <stdlib.h>
5
6
7 int main(int argc, char *argv[]){
8 char *words[32];
9 int numofwords = atoi(argv[2]);
10 int i=0;
11 int len;
12 char *word = malloc (32 * sizeof(char));
13 char c;
14 while (i<=numofwords){
15 if ((c = getc (argv[1])) != EOF){
16 fscanf(argv[1],"%s",&word);
17 len = strlen (word);
18 words[i] = malloc ((len+1) * sizeof(char));
19 i++
20 }
21 printf(words[i]);
22 }
23 return 0;
24 }
25
May be I am correctly understood your need.
I am not rectifying your code but writing my own.
Below is simple code that read from console: code: main.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
if(argc!=2){
printf("\n wrong number of argument\n");
exit(1);
}
int numofwords = atoi(argv[1]);
char buffer[128];
//printf("%d\n",numofwords);
while(numofwords--){
scanf("%s",buffer);
printf("%s\n",buffer);
}
return 0;
}
How does it works:
~$ gcc main.c -o main
execute:
:~$ ./main
wrong number of argument
:~$ ./main 2
grijesh
grijesh
yourname
yourname
:~$
I hope its understood to you. the program simply read (scan) from console and print out to console. The while loop runs for number of time you pass on command line input.
Now, A text file dumy.txt a input file:
:~$ cat dumy.txt
yourname
myname
hisname
hername
:~$
Now see what you want to achieve through you code:
:~$ cat dumy.txt | ./main 2
yourname
myname
:~$
If you want to pass through echo :
:~$ echo $'one\ntwo\nthree' | ./main 2
one
two
:~$
Is this you want?
If yes:
What you miss understood that:
[your code]
(mistake 1,2)
Your fsacnf is wrong in two ways:
fscanf(argv[1],"%s",&word);
First argument is argv[1] is char* that is wrong you need to pass FILE* type. As explained in Mr. Oli Charlesworth's answer.
Second you still need to read from stdin. | operator redirects the output from first command to second command.
(mistake 3, 4, 5, 6)
By sending echo "blabla" you are just sending a single sting you need to do something like I did (I added \n in echo string for new line also my echo string start with $ so it not print as raw string). echo so that you can read from code according to second argument that is argv[1] not argv[2]. So in your code following line is wrong too.
int numofwords = atoi(argv[2]);
I corrected this line in my code.
and i is initialised to zero i = 0 , in while loop condition is <=, I think it should be <.
(mistake 7)
The way you run your code is wrong echo "blabla" | myprog 2 your program not know as mygrog you have to pass complete path. like I did ./main, ./ means current directory.
this just my view about your question. Read also the answer in comment given by Mr. William Pursell.
Let me know if you have other doubts.
I'm not sure exactly what your question is, but I think it may be "how do I treat a file input and console input the same?".
Are you aware that stdin (the standard input) is already a FILE *? So that means you can pass it as the first argument to fscanf, just like a "normal" file:
FILE *normal_file = fopen(...);
// Read from normal file
fscanf(normal_file, "%d", &x);
// Read from stdin
fscanf(stdin, "%d", &y);
An alternate choice would be pass the file name as an argument instead.
echo "blabla" | myprog 2 (number of words to print)
myprog 2 input.txt (number of words to print)
Then you'd:
if argc == 1, then proceed normally and process stdin (stdin is a FILE*) with fgetc, or another alternate f* method.
If argc == 2, then get the filename from argv[1], use fopen(filename) to get a FILE* and process it.
Otherwise, you would do what Oli said and get the first word, then either fopen and pass to your processing function, or fseek(stdin, SEEK_SET, 0) then pass stdin to your processing function.

fopen() always returns NULL

int main()
{
int i;
FILE *list,*file;
char temp[30];
list=fopen("filelist","rb");
while(fgets(temp,30,list)!=NULL)
{
file=fopen(temp,"r");
{
fclose(list);
return 0;
}
This is my code I basically want to open all files in filelist but my fopen call (exept the first one always returns a NULL am i missing something also this is my filelist
file1
file2
file3
file4
also i dont use file extensions and files exist in the same directory wtih executable.
fgets() stores the new-line character into the buffer it is populating so you need to remove it before calling fopen() within the while.
From the linked reference page for fgets():
Reads at most count - 1 characters from the given file stream and stores them in str. The produced character string is always NULL-terminated. Parsing stops if end-of-file occurs or a newline character is found, in which case str will contain that newline character.
Example code to remove the new-line:
char* nl = strrchr(temp, '\n');
if (nl) *nl = 0;
fgets leaves the newline on the end of the string, which you can plainly see if you add the following line afterwards:
printf ("[%s]\n", temp);
You'll see something like:
[file1
]
You need to remove it before use, which you can do this with something like:
size_t sz = strlen (temp);
if (sz > 0)
if (temp[sz-1] == '\n')
temp[sz-1] = '\0';
You can see this effect in action in the following complete program:
#include <stdio.h>
#include <string.h>
int main (void) {
size_t sz;
char temp[30];
printf ("\n> ");
while (fgets (temp, sizeof(temp), stdin) != NULL) {
printf ("before: [%s]\n", temp);
sz = strlen (temp);
if (sz > 0) {
if (temp[sz-1] == '\n') {
temp[sz-1] = '\0';
}
}
printf ("after : [%s]\n", temp);
printf ("\n> ");
}
return 0;
}
It basically uses your exact method to get a line using fgets (but from standard input) and then outputs the result both before and after removal of the trailing newline. A sample run follows:
pax> ./testprog
> hello
before: [hello
]
after : [hello]
> goodbye
before: [goodbye
]
after : [goodbye]
> [CTRL-D]
pax> _
You may also want to look at a few other things in that code segment:
the use of an open brace { at the end of the while loop.
the fact that you're opening the files within the loop and not doing anything with them (including closing them).
the use of "rb" open mode. Usually this is unnecessary, it's certainly unnecessary if you know it's a text file.
you should always check the return codes of functions that can fail (like fopen) before using them.
the canonical form of main in C where no arguments are needed is int main (void).
I'll state my case of which I am still uncertain: I thought my problem was with "fopen", but after trying every single solution, I ran into the extension problem, which I'm facing in Windows 10. It appears that Windows puts ".txt" automatically but, if you put ".txt" as extension, the name becomes ".txt.txt" at the end. So I left the file name with no extension, and put "file.txt" as argument of "fopen", and that was the only way it has worked for me.

Resources