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>
Related
I'm doing an exercise for the multiple execution of commands passed by the cmd arguments.
The description of the exercise is: "The program must read the file line by line, executing the command specified in the command line once for each line, replacing at each occurrence of '#' in the command line, the contents of the current line of the file."
But as soon as I execute ./file_exec esempio.txt cat # the cli shows me this error zsh illegal hardware instruction.
I put here the various file that I've create:
main.c
#include "file_exec.h"
int main(int argc, char **argv) {
if(argc < 3) {
fprintf(stderr,
"Specificare il file di testo e il comando da eseguire.\n");
return 1;
}
char *filename = argv[1];
int cmdargc = argc - 2;
char **opz = argv + 2;
char *cmd = argv[2];
char *line = (char *)malloc(sizeof(char) * BUZZ_SIZE);
int statusLine = 0;
FILE *file = fopen(filename, "r");
if(file == NULL) {
fprintf(stderr, "%s: Impossibile aprire %s: %s\n",
argv[0], argv[1], strerror(errno));
return 2;
}
int size = 1024;
do{
statusLine = fileReadLine(line, file, size); // leggo la singola linea
if(statusLine == 2){
size += 1024;
}
if(strlen(line) != 0){
int ris = executeLine(cmdargc, cmd, opz);
if(ris == -1){
fprintf(stderr, "Impossibile eseguire il comando: %s\n", cmd);
return -1;
}
}
}while(statusLine != -1);
fclose(file);
return 0;
}
file_exec.c
#include "file_exec.h"
int fileReadLine(char *line, FILE *file, int size){
if(!feof(file) && (int)strlen(line) < size){
fgets(line, size, file);
}else if((int)strlen(line) == size){
line = realloc(line, size*2);
return 2;
}else{
free(line);
return -1;
}
return 1;
}
int executeLine(int nOpz, char *cmd, char **opz){
char *pathCmd = strcat("/bin/",cmd);
pid_t pidSon = fork();
opz = addArguments(nOpz, cmd, opz);
switch(pidSon) {
case -1:
perror("fork() failed");
free(opz);
return 1;
case 0:
printf("Esecuzione di ls...\n");
execl(pathCmd, cmd, opz, NULL);
perror("exec failed");
free(opz);
return 1;
default:
wait(NULL);
printf("%s completed\n",cmd);
}
free(opz);
return 0;
}
char **addArguments(int cmdargc, char *line, char **cmdargv){
char **newArgs = (char **)malloc((cmdargc + 1) * sizeof(char *));
for(int i = 0; i < cmdargc; i++){
if(strcmp(cmdargv[i], "#") == 0){
newArgs[i] = line;
}else{
newArgs[i] = cmdargv[i];
}
}
newArgs[cmdargc] = NULL;
return newArgs;
}
file_exec.h
#ifndef FILEEX_H__
#define FILEEX_H__
#define BUZZ_SIZE 1024
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
int fileReadLine(char *, FILE *, int);
int executeLine(int, char *, char **);
char **addArguments(int, char *, char **);
#endif
esempio.txt
file1.txt
file2.txt
file3.txt
file1.txt
Hello
file2.txt
I'm
file3.txt
italian
Makefile
file_exec: file_exec.o main.o
gcc -Wall -Werror -Wextra -std=c99 file_exec.o main.o -o file_exec
file_exec.o: file_exec.h file_exec.c
gcc -Wall -Werror -Wextra -std=c99 -c file_exec.c
main.o: file_exec.h main.c
gcc -Wall -Werror -Wextra -std=c99 -c main.c
clean:
rm -f *.o main
(I'm on an Intel Mac)
The program should show this output from this command ./file_exec esempio.txt cat #:
Hello
I'm
italian
I've just tried to put some debugging printf after the first if statement on the main.c but it was ignored and not executed.
You are using strcat the wrong way
char *pathCmd = strcat("/bin/",cmd);
is adding cmd to the end of string (constant array of char) "/bin". And then is returning this array. To be more accurate, what it does, is going at the address "/bin" - yes, that is an address - iterates 1 by 1 this address until it finds the terminal 0, that is the end of the string. And copy the content of address cmd there. And obviously, you can't do that. Not from a language point of view. Both "/bin" and cmd are pointers to char, as wanted. And the fact that "/bin" is a constant array of chars is not really a problem neither, since strcat doesn't change it: it only changes its content. But that string "/bin" is stored in an area of memory that your program is not supposed to try to write to. Which it does, when it tries to copy cmd after the second / of /bin/. Hence an execution error.
You need to allocate memory for pathCmd and concatenate there
char pathCmd[1024];
strcpy(pathCmd, "/bin/");
strcat(pathCmd, cmd);
Well, in reality, you should not do that neither. It is insecure (if cmd overflow the 1024 bytes I allocated here). So you should rather use strncat
char pathCmd[1024];
strcpy(pathCmd, "/bin/");
strncat(pathCmd, cmd, 1024-5); // 5 bytes already used by "/bin/"
Alternatively, you can use snprintf
char pathCmd[1024];
snprintf(pathCmd, 1024, "/bin/%s", cmd);
(it is 1 less line of code, and you don't need to compute the 1024-5 limit, since the limit is for the whole target)
Note that this has nothing to do with zsh. zsh is just the one complaining because you probably call this in a zsh script.
I'm trying to retract strings from a txt file.
The file content is;
apple
pear
orange
basicly every line has one word and I would like to read every line and retract words into the string char* word[25] because the longer word is 24 characters. When I implement a simple code to read every character in ASCII between each line there was value 10 for end of line. So I created a for loop without any condition and added if condition to spot the 10 value end of line (LF). But it doesn't work and I'm sure I messed in something very basic in code or logic. Sorry if my code seems unlogical or very wrong, I'm fairly new. Also there are lots of libraries added cos I'm going to use them if I could done this step. TIA
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Usage: ./word filename\n");
return 1;
}
FILE* ptr = fopen(argv[1], "r");
char ch;
char* word[45];
for (int i = 0; ;i++)
{
ch = fgetc(ptr);
word[i] = &ch;
if (ch == 10)
{
break;
}
}
printf("%s\n", *word);
return 0;
}
terminal output
~/snippets/ $ make word
clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow word.c -lcrypt -lcs50 -lm -o word
~/snippets/ $ ./word lec3.txt
`
~/snippets/ $
What if you drop the pointers ..
char ch;
char word[45];
for (int i = 0; ;i++)
{
ch = fgetc(ptr);
word[i] = ch;
if (ch == 10)
{
break;
}
}
printf("%s\n", word);
You could do it dynamically too :
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Usage: ./word filename\n");
return 1;
}
FILE *ptr = fopen(argv[1], "r");
char ch;
int i = 0;
char *word = calloc(45, sizeof(char));
for (ch = fgetc(ptr); ch != EOF; ch = fgetc(ptr), i++)
{
if (ch == '\n')
break;
word[i] = ch;
}
printf("%s\n", word);
free(word);
return 0;
}
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;
}
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.
Currently trying to compile this program using
g++ -o crack crack2.c -lcrypt -lpthread -lmalloc and am getting:
z#ubuntu:~/Desktop$ g++ -o crack crack2.c -lcrypt -lpthread -lmalloc
/usr/bin/ld: cannot find -lmalloc
collect2: error: ld returned 1 exit status
So.. If I remove the -lmalloc, I get undefined reference to 'passwordLooper(void*)'.
Really unsure of how to fix this problem. It has to be something related to malloc or -lmalloc because before I worked in the malloc(), everything worked as intended and the program compiled.
/*
crack.exe
*/
/* g++ -o crack crack.c -lcrypt -lpthread -lmalloc */
//define _GNU_SOURCE
#include <malloc.h>
#include <crypt.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
void *passwordLooper(void *passwordData);
//void *threadFunction(void *threads);
typedef struct{
int keysize;
char *target;
char *salt;
}passwordData;
int main(int argc, char *argv[]){ /* usage = crack threads keysize target */
int i = 0;
/* arg[0] = crack, arg[1] = #of threads arg[2] = size of password, arg[3] = hashed password being cracked */
if (argc != 4) {
fprintf(stderr, "Too few/many arguements give.\n");
fprintf(stderr, "Proper usage: ./crack threads keysize target\n");
exit(0);
}
int threads = *argv[1]-'0'; // threads is now equal to the second command line argument number
int keysize = *argv[2]-'0'; // keysize is now equal to the third command line argument number
char target[9];
strcpy(target, argv[3]);
char salt[10];
while ( i < 2 ){ //Takes first two characters of the hashed password and assigns them to the salt variable
salt[i] = target[i];
i++;
}
printf("threads = %d\n", threads); /*used for testing */
printf("keysize = %d\n", keysize);
printf("target = %s\n", target);
printf("salt = %s\n", salt);
if (threads < 1 || threads > 8){
fprintf(stderr, "0 < threads <= 8\n");
exit(0);
} /*Checks to be sure that threads and keysize are*/
if (keysize < 1 || keysize > 8){ /*of the correct size */
fprintf(stderr, "0 < keysize <= 8\n");
exit(0);
}
pthread_t t1,t2,t3,t4,t5,t6,t7,t8;
struct crypt_data data;
data.initialized = 0;
//~ passwordData.keysize = keysize;
//~ passwordData.target = target;
//~ passwordData.salt = salt;
passwordData *pwd = (passwordData *) malloc(sizeof(pwd));
pwd->keysize = keysize;
pwd->target = target;
pwd->salt = salt;
//~ if ( threads = 1 ){
//~ pthread_create(&t1, NULL, *threadFunction, threads);
//~ }
char unSalted[30];
int j = 0;
for (i = 2; target[i] != '\0'; i++){ /*generates variable from target that does not include salt*/
unSalted[j] = target[i];
j++;
}
printf("unSalted = %s\n", unSalted); //unSalted is the variable target without the first two characters (the salt)
char password[9] = {0};
passwordLooper(pwd);
}
/*_____________________________________________________________________________________________________________*/
/*_____________________________________________________________________________________________________________*/
void *passwordLooper(passwordData *pwd){
char password[9] = {0};
int result;
int ks = pwd->keysize;
char *target = pwd->target;
char *s = pwd->salt;
for (;;){
int level = 0;
while (level < ks && strcmp( crypt(password, s), target ) != 0) {
if (password[level] == 0){
password[level] = 'a';
break;
}
if (password[level] >= 'a' && password[level] < 'z'){
password[level]++;
break;
}
if (password[level] == 'z'){
password[level] = 'a';
level++;
}
}
char *cryptPW = crypt(password, s);
result = strcmp(cryptPW, target);
if (result == 0){ //if result is zero, cryptPW and target are the same
printf("result = %d\n", result);
printf ("Password found: %s\n", password);
printf("Hashed version of password is %s\n", cryptPW);
break;
}
if (level >= ks){ //if level ends up bigger than the keysize, break, no longer checking for passwords
printf("Password not found\n");
break;
}
}
exit(0);
}
Your code appears to be pure C. You should compile it with gcc, not g++.
The malloc function is declared in <stdlib.h> and implemented in the standard C library. You don't need either #include <malloc.h> or -lmalloc.
You have two inconsistent declarations for your passwordLooper function. Your "forward declaration":
void *passwordLooper(void *passwordData);
doesn't match the definition:
void *passwordLooper(passwordData *pwd){
/* ... */
}
The "forward declaration" of passwordLooper needs to follow the definition of the type passwordData.
You have this line:
//define _GNU_SOURCE
You need to uncomment it:
#define _GNU_SOURCE
to make the type struct crypt_data visible.
When I make all these changes, I'm able to compile it (at least on my system) with:
gcc c.c -o c -lcrypt