execvp() doesn't output correctly - c

I am writing the code for a shell, but when i try to run the command cat filename.c it says:
cat: filename.c
:No such file or directory
even though the same command runs outside the shell. For other commands such as lsmod, it prints nothing.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 80 /* 80 chars per line, per command */
int main(void)
{
char *args[MAX_LINE/2 + 1]; /* command line (of 80) has max of 40 arguments */
int should_run = 1;
int i, upper, j;
char *w= (char *)malloc(80*sizeof(char)) ;
char *buffer;
size_t bufsize= 80;
while (should_run){
printf("osh> ");
fflush(stdout);
getline(&w, &bufsize , stdin);
buffer = strtok (w, " ");
i=0;
while (buffer)
{
args[i++] = buffer;
buffer = strtok (NULL, " ");
}
char *ls_arg[i+1];
for(j=0;j<i;j++)
{
ls_arg[j]=args[j];
}
ls_arg[j]=NULL;
int pid;
pid= fork();
if(!pid)//child process
{
execvp(ls_arg[0], ls_arg);
}
wait(5);
}
return 0;
}

Related

Minishell 'segmentation fault, core dumped' error in C

Following is a part of my code for my shell. The code works, but when I try to enter a command like "ls", my program crashes. I think that's a right error because I try to access to the "/bin" file.
void lecture (char cmd1[], char *argv[]){
int x = 0;
char ligne [1024];
char *aux [100], *pch;
while (1){
int mot = fgetc (stdin);
ligne[x] = (char) mot;
x++;
if (mot == (int)'\n') break;
}
aux[0] = strtok (ligne, " \n");
strcpy(cmd1,aux[0]);
for (int i = 1; i <= 1024; i++){
argv[i+1] = aux[i];
}
}
int main(){
char cmd1 [100];
char cmd2 [100];
int a = 10;
char *argv [20];
char *envp[] = {(char *) "PATH=/bin", 0};
while (1){
affichage();
lecture (cmd2, argv);
printf("Test");
if ( fork() != 0){
printf("Err");
wait (NULL);
}else{
strcpy(cmd1, "/bin/");
strcat(cmd1, cmd2);
execve(cmd1, argv, envp);
}
}
}
I get something working without SIGSEGV with following modification in lecture:
for (int i = 0; i < 20; i++){
Example:
./ms
ls
����: cannot access 'ls': No such file or directory
TestErr
...
But you can also debug this as I did with compiling in debug mode:
gcc -o ms -g -Wall -pedantic -Wextra -std=c11 ms.c
and using gdb to check where SIGSEGV occurs.
Note that you are expected to post a https://stackoverflow.com/help/minimal-reproducible-example with full code (here we are missing affichage) and
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

How to count multiple characters from a file in C language using POSIX functions?

I'm trying to write a program that takes a file and a string by using standard POSIX functions, program counts all the characters in file which the string contains.
For example if the user writes:
count.exe x.txt abcd
The program calculates the number of each character: a, b, c, d in file x.txt
Sample message:
Number of 'a' characters in 'x.txt' file is: 4
Number of 'b' characters in 'x.txt' file is: 9
Number of 'c' characters in 'x.txt' file is: 7
Number of 'd' characters in 'x.txt' file is: 0
The code that I got so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define BUFSIZE 1024
void exit_sys(const char* msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
void exit_fail(const char* msg)
{
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
int get_count(char* p, size_t size, char c)
{
int count = 0;
size_t i;
for (i = 0; i < size; ++i)
if (p[i] == c)
++count;
return count;
}
void run_count_characters_application(int argc, char** argv)
{
int fd;
char c;
char buf[BUFSIZE];
int n;
int count;
if (argc != 3)
exit_fail("usage: ./mycounter file character");
if (strlen(argv[2]) < 0)
exit_fail("You have to give at least one character");
c = argv[2][0];
if ((fd = open(argv[1], O_RDONLY)) < 0)
exit_sys("open");
count = 0;
while ((n = read(fd, buf, BUFSIZE)) > 0)
count += get_count(buf, n, c);
if (n < 0)
exit_sys("read");
printf("Count:%d\n", count);
close(fd);
}
int main(int argc, char** argv)
{
run_count_characters_application(argc, argv);
return 0;
}
The problem with what I got so far in this code is that it only counts one character (only the first character), I want to know how to make it read and count the other characters that I write in the command, thank you in advance :)
since you asked for an example in the comments:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void die(const char *reason)
{
fprintf(stderr, "%s\n", reason);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
if (argc != 3)
die("usage: ./count file characters");
FILE *f = fopen(argv[1], "r");
if (f == NULL)
die("unable to open file");
unsigned int counter[UCHAR_MAX + 1] = { 0 };
int c;
while ((c = fgetc(f)) != EOF)
counter[c]++;
fclose(f);
size_t len = strlen(argv[2]);
for (unsigned int i = 0; i < len; i++) {
char c = argv[2][i];
unsigned int count = counter[c];
printf("Number of '%c' characters in '%s' file is: %u\n", c, argv[1], count);
}
}
$ cc count.c -o count
$ echo "bbaaafff" > test.txt
$ ./count test.txt afm
Number of 'a' characters in 'test.txt' file is: 3
Number of 'f' characters in 'test.txt' file is: 3
Number of 'm' characters in 'test.txt' file is: 0
$
the function fgetc()
return the character read as an unsigned char cast to an int or EOF on end of file or error.
there are UCHAR_MAX + 1 possible values that a unsigned char can store (typically 0 to 255) so I made an array that can be indexed by these values (counter) to store ours counts. think of it as a "map" from other languages that maps characters to their count.
then at the end, I loop over the characters from the input string and print their count.
as already mentioned in the comments, this works properly only for ASCII characters.

C Programming Element array into sprintf()

This is a pentesting laboratory environment called "Mutillidae".
This program grabs argv[1] and places into command "curl <[argv[1]>",
then it grabs a line from lfi_test file and places it into second
%s in sprintf(). This program executes %100, I am just having issues with the format( | grep root). Instead, the entire source code is revealed including the entire /etc/passwd file.
If I uncomment line #20:
int passwd = "/etc/passwd";
and change line #27 to
sprintf(url,"/usr/bin/curl %s%s", argv[1], passwd);
I am able to get the formatted result I want.
If anyone can help me out, thank you in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
printf("\nlfi_check searches for system files on a vulnerable URL\n");
printf("<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n\n");
if (argc != 2)
{
printf("\nusage ./lfi_check http://target.php?page= \n");
}
else
{
char url[200];
int i;
FILE *fp;
char line[200];
char *root = "| grep root"
// char *passwd = "/etc/passwd";
fp = fopen("/home/freshnuts/pentest/lfi_rfi/lfi_test","r+");
for (i=0; i <= 1; i++)
{
fgets(line,sizeof(line), fp);
sprintf(url,"/usr/bin/curl %s%s %s", argv[1], line-1, root);
// printf("%s", line);
system(url);
}
}
}
The reason line-1 wasn't working in..
sprintf(url,"/usr/bin/curl %s%s %s\n", argv[1], line-1, root);
was due to line(/etc/passwd\n) from file was being cut by 1 and
it didn't allow char *root variable to be implemented into string format.
The function strtok() breaks line into a series of tokens using a delimiter. I was then able to parse "/etc/passwd\n" to "/etc/passwd" BEFORE sprintf().
Thanks DUman & immibis
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
printf("\nlfi_check searches for system files on a vulnerable URL\n");
printf("<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n\n");
if (argc != 2)
{
printf("\nusage ./lfi_check http://target.php?page= \n");
}
else
{
char url[4096];
int i;
FILE *fp;
char line[200];
char *root = " | grep root";
fp = fopen("/root/freshnuts/pentest/lfi_rfi/lfi_test","r+");
for (i=0; i <= 2; i++)
{
fgets(line,sizeof(line), fp);
strtok(line, "\n");
sprintf(url,"/usr/bin/curl %s%s %s\n", argv[1], line,root);
system(url);
}
}
}

ls: cannot access : No such file or directory

When i type ls i get this message twice : ls: cannot access : No such file or directory. But when i type something like that ls -l /tmp or executing a "c" code located in the path everything is fine. Any ideas what is going wrong?
My code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
for (;;) {
char *cmd,*splitcmd,*pr0,*pr1,*pr2;
int i, j, nargc = 0, characters;
char **cmdArray;
size_t bufsize = 1024;
pid_t pid, wpid;
int status = 0;
printf("Type a command : \n");
cmd = (char *) malloc(bufsize * sizeof(char));
characters = getline(&cmd, &bufsize, stdin);
// printf("cmd===> %s characters===> %d \n",cmd,characters);
if (cmd[characters-1] == '\n')
{
cmd[characters-1] = '\0';
characters--;
}
// printf("cmd===> %s characters===> %d \n",cmd,characters);
cmdArray = (char**) malloc(bufsize * sizeof(char *));
for (i = 0 ; i < bufsize ; i++)
{
cmdArray[i] = (char*) malloc(bufsize*sizeof(char));
}
splitcmd = strtok(cmd," ");
// printf(" cmd==== %s\n",cmd);
while ((splitcmd))
{
cmdArray[nargc] = splitcmd;
if (cmdArray[nargc][(strlen(cmdArray[nargc])) - 1] == ' ')
cmdArray[nargc][(strlen(cmdArray[nargc]))-1] == '\0';
// printf(" nargc====%d cmdArray===[ %s ] \n",nargc,cmdArray[nargc]);
nargc++;
pr0 = cmdArray[0];
pr1 = cmdArray[1];
pr2 = cmdArray[2];
splitcmd = strtok(NULL," ");
//printf(" pr0 %s \n",pr0);
//printf(" pr1 %s \n",pr1);
//printf(" pr2 %s \n",pr2);
}
if ((pid = fork()) == 0)
{
char *argv[] = {pr0, pr1, pr2, NULL};
execvp(argv[0],argv);
for (int i = 0; i < 100; i++) {
free(cmdArray[i]);
}
free(cmdArray);
}
wait(&status);
}
}
Your code has a number of problems, many of which are identified by turning on warnings. Use -Weverything if your compiler supports it, or at least -Wall if it does not. However, your particular question is in how you're calling execvp().
char *argv[] = {pr0, pr1, pr2, NULL};
execvp(argv[0],argv);
This will always pass two arguments to ls. Even if pr1 and pr2 are empty, ls will still act like it was passed arguments. ls will determine how many arguments it has by looking for a NULL entry.
Your code has a flaw in that it is trying to hard code the number of arguments by splitting up the cmdArray into individual variables. This isn't going to work. For starters, commands take more than two arguments. You should instead leave cmdArray together, properly NULL terminate it, and pass that into execvp.

Converting Greek words to uppercase

I have to create a function that reads a file called grwords.txt containing around 540000 words which are written in Greek letters.
I have to convert these words to uppercase and fill an array called char **words.
This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <ctype.h>
void fp();
int main(int argc, char *argv[]) {
SetConsoleOutputCP(1253);
fp();
return 0;
}
void fp(){
char **words;
words = malloc(546490 * sizeof(int *));
for (i = 0; i < 546490; i++)
words[i] = malloc(24 * sizeof(int));
FILE *file;
char *word;
size_t cnt;
file = fopen("grwords.txt", "rt");
if (file == NULL){
printf("File cannot be opened.\n");
exit(1);
}
cnt = 0;
while (1==fscanf(file, "%24s",word)){
if (cnt == 546490)
break;
strcpy(words[cnt++], word);
}
fclose(file);
}
I'm still trying to figure out pointers. I know that & makes a pointer from a value and * a value from a pointer. Updated the program and it successfully fills the array with the words from the file! I still have no idea how to convert Greek lowercase to uppercase.
Handling Greek words can be dependent on your platform.
First of all, you need to understand how file handling works. Here is what I wrote:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define bufSize 1024 // max lenght of word
// we are going to receive the .txt from cmd line
int main(int argc, char *argv[])
{
FILE *fp;
// Assume file has max 10 words
const size_t N = 10;
// Allocate a 2D array of N rows
// and bufSize columns.
// You can think of it like an array
// of N strings, where every string
// has, at most, bufSize length.
char buf[N][bufSize];
// make sure we got the .txt
if (argc != 2)
{
fprintf(stderr,
"Usage: %s <soure-file>\n", argv[0]);
return 1;
}
// open the file
if ((fp = fopen(argv[1], "r")) == NULL)
{ /* Open source file. */
perror("fopen source-file");
return 1;
}
// we will use that for toupper()
char c;
// counters
int i = 0, j;
while (fscanf(fp, "%1024s", buf[i]) == 1)
{ /* While we don't reach the end of source. */
/* Read characters from source file to fill buffer. */
// print what we read
printf("%s\n", buf[i]);
j = 0;
// while we are on a letter of word placed
// in buf[i]
while (buf[i][j])
{
// make the letter capital and print it
c = buf[i][j];
putchar (toupper(c));
j++;
}
i++;
printf("\ndone with this word\n");
}
// close the file
fclose(fp);
return 0;
}
For this test.txt file:
Georgios
Samaras
Γιώργος
Σαμαράς
the code would run as:
./exe test.txt
Georgios
GEORGIOS
done with this word
Samaras
SAMARAS
done with this word
Γιώργος
Γιώργος
done with this word
Σαμαράς
Σαμαράς
done with this word
As you can see, I could read the Greek words, but failed to convert them in upper case ones.
Once you got how file handling goes, you need to use wide characters to read a file with Greek words.
So, by just modifying the above code, we get:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
#define bufSize 1024
int main(int argc, char *argv[])
{
setlocale(LC_CTYPE, "en_GB.UTF-8");
FILE *fp;
const size_t N = 15;
wchar_t buf[N][bufSize];
if (argc != 2)
{
fprintf(stderr,
"Usage: %s <soure-file>\n", argv[0]);
return 1;
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen source-file");
return 1;
}
wchar_t c;
int i = 0, j;
while (fwscanf(fp, L"%ls", buf[i]) == 1)
{
wprintf( L"%ls\n\n", buf[i]);
j = 0;
while (buf[i][j])
{
c = buf[i][j];
putwchar (towupper(c));
j++;
}
i++;
wprintf(L"\ndone with this word\n");
}
fclose(fp);
return 0;
}
And now the output is this:
Georgios
GEORGIOS
done with this word
Samaras
SAMARAS
done with this word
Γιώργος
ΓΙΏΡΓΟΣ
done with this word
Σαμαράς
ΣΑΜΑΡΆΣ
done with this word
I see that you may want to create a function which reads the words. If you need a simple example of functions in C, you can visit my pseudo-site here.
As for the 2D array I mentioned above, this picture might help:
where N is the number of rows (equal to 4) and M is the number of columns (equal to 5). In the code above, N is N and M is bufSize. I explain more here, were you can also found code for dynamic allocation of a 2D array.
I know see that you are on Windows. I tested the code in Ubuntu.
For Windows you might want to take a good look at this question.
So, after you read all the above and understand them, you can see what you asked for with dynamic memory management.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
#define bufSize 1024
wchar_t **get(int N, int M);
void free2Darray(wchar_t** p, int N);
int main(int argc, char *argv[])
{
setlocale(LC_CTYPE, "en_GB.UTF-8");
FILE *fp;
const size_t N = 15;
wchar_t** buf = get(N, bufSize);
if (argc != 2)
{
fprintf(stderr,
"Usage: %s <soure-file>\n", argv[0]);
return 1;
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen source-file");
return 1;
}
wchar_t c;
int i = 0, j;
while (fwscanf(fp, L"%ls", buf[i]) == 1)
{
wprintf( L"%ls\n", buf[i]);
j = 0;
while (buf[i][j])
{
c = buf[i][j];
putwchar (towupper(c));
j++;
}
i++;
wprintf(L"\ndone with this word\n");
}
fclose(fp);
// NEVER FORGET, FREE THE DYNAMIC MEMORY
free2Darray(buf, N);
return 0;
}
// We return the pointer
wchar_t **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
wchar_t **table;
table = malloc(N*sizeof(wchar_t *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(wchar_t) );
return table;
}
void free2Darray(wchar_t** p, int N)
{
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}
Note that this code is expected to work on Linux (tested on Ubuntu 12.04), not on Windows (tested on Win 7).

Resources