Creating a shell - c

When i run the program with the ls > filename command it prints the results in the file but after that it doesn't respond to other commands like ls etc . Here is the code :
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
void execute(char **argv, char ** k, int *l)
{
pid_t pid;
int file_descriptor;
int status;
int file;
if ((pid = fork()) < 0)
{
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0)
{
if (l = 1)
{
file = open(k, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
file_descriptor = dup2(file, 1);
}
if (execvp(argv[0], argv) < 0)
{
printf("*** ERROR: exec failed\n");
exit(1);
}
}
else
{
while (wait(&status) != pid)
;
}
}
void main(void)
{
char **name = (char**) malloc(256 * sizeof(char));
char line[1024];
char ** k;
int file;
int i;
int *l;
while (1)
{
l = 0;
i = 0;
printf("myShell3 -> ");
gets(line); // gets the input command from user
printf("\n");
name[i] = strtok(line, " ");
while (name[i] != NULL)
{
if (strcmp(name[i], ">") == 0)
{
i++;
l = 1;
k = strtok(NULL, " ");
name[i - 1] = name[i];
}
else if (!strcmp(name[i], "<"))
{
i++;
name[i] = strtok(NULL, " ");
name[i - 1] = name[i];
}
else
{
i++;
name[i] = strtok(NULL, " ");
}
}
execute(name, k, l);
}
}
I have spent many hours on how to fix this but didnt find solution . Any help would be very much appreciated

Related

How to synchronize two child fork process with shared memory and semaphores?

I have to do tiny project in linux about sync and semaphores and I have some trouble...
The thing is I want to create two process, child 1 (PP1) and child 2 (PP2), PP1 reads data from file by parts (16 chars) and save them to shared memory which PP2 is using and save this chars to new file AFTER doing on them caezar cipher...
It almost works but I have some fear that it is not correct, cause it works while sleep() is there, without it, synchronize doesn't work.
File tst contains text:
Blockquote
szesnasciebajtow bajtowszesnascie siaaaaalllla
Here is the code:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SHM_SIZE 16
int main()
{
int countToCipher,character, rozmiar=0,rd,i,des;
char nazwaPliku[50];
printf("Type file name \n");
scanf("%s", nazwaPliku);
if( access( nazwaPliku, F_OK ) != -1 ) {
printf("Type key number: \n");
scanf("%i", &countToCipher);
} else {
printf("File does not exist!");
exit(0);
}
if( access( nazwaPliku, R_OK ) == -1 ) {
printf("No permission!");
exit(0);
}
FILE* fodczyt;
fodczyt = fopen(nazwaPliku, "r");
fseek(fodczyt,0,SEEK_END);
rozmiar = ftell(fodczyt);
int shmid,semid;
key_t key;
char *shm,*s;
if ((key = ftok(".", 'B')) == -1)
errx(1, "Error key!");
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0660)) < 0) {
perror("shmget");
errx(2, "Error creatin shm!");
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1){
perror("shmat");
errx(3, "Error connect shm");
}
sem_t *sem1 = mmap(NULL, sizeof(*sem1),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (sem1 == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
sem_init(sem1, 1, 1);
if(fork()==0){
//PP1
int stop = 0,i;
FILE *odczyt = fopen(nazwaPliku, "r");
char ch;
while(stop!=1){
printf("\nPP1 waits\n");
sem_wait(sem1);
printf("PP1 enter\n");
s=shm;
for(i=0;i<SHM_SIZE+1;i++){
ch = getc(odczyt);
if(feof(odczyt)){
stop=1;
s[i]=EOF;
int j;
for(j=0;j<SHM_SIZE-i;j++) s[i]='\0';
break;
}
s[i]=ch;
}
sem_post(sem1);
printf("PP1 exit\n");
sleep(2);
}
fclose(odczyt);
shmdt(shm);
}
if(fork()==0){
//PP2
int stop=0;
char* odbior;
sleep(1);
des = open( "szyfr", O_CREAT | O_WRONLY | O_APPEND, 0666 );
while(stop!=1){
printf("\nPP2 waits\n");
sem_wait(sem1);
printf("PP2 enter\n");
odbior = shm;
for (i = 0; i<SHM_SIZE; i++) {
if(odbior[i]=='\0')
{
stop=1;
break;
}
character = odbior[i];
if (character >= 'a' && character <= 'z') {
character += (int)countToCipher;
if (character > 'z') {
character = character - 'z' + 'a' - 1;
}
odbior[i] = character;
}
else if (character >= 'A' && character <= 'Z') {
character += (int)countToCipher;
if (character > 'z') {
character = character - 'A' + 'Z' - 1;
}
odbior[i] = character;
}
}
write(des,odbior,SHM_SIZE);
sem_post(sem1);
printf("PP2 exit\n");
sleep(2);
}
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
}
wait(NULL);
wait(NULL);
sem_destroy(sem1);
return 0;
}
Here is the console output:
output
Here is output in new file:
Blockquote
taftobtdcbkupxtatjbbbbbmtaftobtdjfcbkupxcbkupxtaftobtdjftjbbbbbmmmmb(NULL)djf

Not completly redirect output to file

Hello and thank you for attention. I am writing my own shell and I have small problem with redirect output to file. For example user wrote: ls -l >> output. If I find ">>", I should redirect first part of command, I mean call effect ls -l to file "output". I try to do it in case 1 but to file is redirected just one lane and the program is stopped, there is not appear "Shell -> " and nothing is going on. Can you give some advice to solve that problem? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
int *parse(char *linia, char **argv)
{
int counter = -1;
while (*linia != '\0')
{
while (*linia == ' ' || *linia == '\t' || *linia == '\n')
*linia++ = '\0';
*argv++ = linia;
counter++;
while (*linia != '\0' && *linia != ' ' && *linia != '\t' && *linia != '\n')
linia++;
}
*argv = '\0';
return counter;
}
void execute(char **argv)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
else if (pid == 0)
{
if (execvp(*argv, argv) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
}
else
{
while (wait(&status) != pid);
}
}
int specialChar(char *argv)
{
int i=0;
while(argv[i]!='\0')
{
if(argv[i]=='>' && argv[i+1]=='>')
return 1;
else if(argv[i]=='&')
return 2;
else if(argv[i]=='|')
return 3;
i++;
}
}
void main()
{
char command[20];
char *argv[64];
char **history = (char**)malloc(20*sizeof(char*));
int counter1=-1;
int counter2=0;
for(counter2 = 0; counter2<20; counter2++)
{
history[counter2]=(char*)malloc(100*sizeof(char));
}
int start = 0;
FILE *file;
file=fopen("his", "w");
if(!file)
printf("ERROR");
int i=0;
while (1)
{
printf("Shell -> ");
gets(command);
counter1++;
strcpy(history[counter1],command);
fopen("his", "w");
if(counter1<20)
for(i=0; i<=counter1; i++)
{
fprintf(file,"%s\n",history[i]);
}
else
for(i=counter1-20; i<counter1; i++)
{
fprintf(file,"%s\n",history[i]);
}
fflush(file);
printf("\n");
switch(specialChar(command))
{
case 1:
i = parse(command, argv);
int file1 = open(argv[i], O_APPEND | O_WRONLY);
dup2(file1,1) ;
if (strcmp(argv[0], "exit") == 0)
exit(0);
execute(argv);
close(file1);
break;
case 2:
break;
case 3:
break;
default:
parse(command, argv);
if (strcmp(argv[0], "exit") == 0)
exit(0);
execute(argv);
break;
}
fclose(file);
}
}

Changing unrelated code gives a segmentation fault. Why is it doing this?

I'm creating my own Shell and I successfully got processes to run in the background by using my is_background function to find a &. It was working fine until i tried to implement redirection of standard output. The chk_if_output function is a part of this as well as the if statement if(out[0] == 1) in the process function. Somehow implementing redirection screwed up the way I implemented background process. If I comment out the redirection code it works again. I get a segmentation fault every time I try to run a background process with the redirection code in the program and I can't for the life of me figure out why. I haven't changed any of the background process code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX_LINE 80 /* The maximum length command */
int is_background(char *args[], int size){
int background = 0;
if (strcmp(args[size-1 ], "&") == 0){
background = 1;
args[size-1] = NULL;
}
return background;
}
int * chk_if_output(char *args[], int size){
int * out = malloc(2);
out[0] = 0; out[1] = 0;
for (int i = 0; i < size; i++){
if (strcmp(args[i],">") == 0){
out[0] = 1;
out[1] = i;
break;
}
}
return out;
}
void process(char *command, char *params[], int size){
pid_t pid;
int background = is_background(params, size);
int *out = chk_if_output(params, size);
int fd;
int fd2;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed\n");
}else if (pid == 0) {
if(out[0] == 1){
for (int i = out[1]; i < size; i++){
params[i] = params[i+1];
}
fd = open(params[out[1]-1],O_RDONLY,0);
dup2(fd,STDIN_FILENO);
close(fd);
fd2 = creat(params[out[1]],0644);
dup2(fd2,STDOUT_FILENO);
close(fd2);
out[0] = 0;
out[1] = 0;
}
execvp(command, params);
}else {
if(background == 1){
waitpid(pid, NULL, 0);
}
background = 0;
}
}
int main(void) {
char *args[MAX_LINE/2 + 1]; /* command line arguments */
int should_run = 1; /* flag to determine when to exit program */
while (should_run) {
char *line;
char *endline;
printf("Leyden_osh>");
fgets(line, MAX_LINE*sizeof line, stdin);
if((endline = strchr(line, '\n')) != NULL){
*endline = '\0';
}
if (strcmp((const char *)line,"exit") == 0){
should_run = 0;
}
int i = 0;
args[i] = strtok(line, " ");
do{
args[++i] = strtok(NULL, " ");
}while(args[i] != NULL);
process(args[0], args, i);
fflush(stdout);
return 0;
}
In the chk_if_output() function, the last element of the array in the loop was NULL.
Fixed it by looping to size -1.

Segmentation fault C in writing a shell program

My code worked fine until I add the extra stuffs into it, like identifying and deal with cd, >, <, >> and |. Could you please check my code and see where did the error happens?
Btw the requirement of the assignment is only up to 1 pipe. And I think the problem starts somewhere from the for loop, cause I put printf right after it to check if it would print args[k], and it did but then the bug popped up and the program stopped.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
int main()
{
const int MAX_ARGS = 10;
char *token[MAX_ARGS + 1]; /*assume max number of token <=10*/
char *temp;
char line[256], command[MAX_ARGS];
char prompt[] = "sh2 % ";
pid_t pid;
int i=0, j,k, status;
printf("%s", prompt);
while (fgets(line, sizeof line, stdin) != NULL)
{
line[strlen(line)-1] = '\0'; /*get rid of \n*/
token[0] = strtok(line," ");
strcpy(command,token[0]);
temp = strtok(NULL," ");
while (temp != NULL)
{
i = i+1;
token[i] = temp;
temp = strtok(NULL," ");
}
char *args[i+2];
for (j = 0; j < (i+1); j++)
{
args[j] = token[j];
}
args[i+1] = NULL;
if (!strcmp("exit",command))
exit(0);
if (!strcmp("cd", command))
{
int success;
if (success = chdir(args[1]) <0)
{
printf("Failed to change dir.\n");
}
}
else
{
int piping = 0;
int fd;
for (k = 0; k < sizeof args; k++)
{
if (!strcmp(">",args[k]))
{
fd = open(args[k+1],O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
if (fd <0) { printf("Open file failed.\n");}
else
{
dup2(fd, 1);
args[k] = '\0';
fflush(stdout);
close(fd);
}
}
if (!strcmp("<", args[k]))
{
fd = open(args[k+1], O_RDONLY);
if (fd <0) {printf("Open file failed.\n");}
else
{
dup2(fd, 0);
args[k] = '\0';
close(fd);
}
}
if (!strcmp(">>", args[k]))
{
fd = open(args[k+1], O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
if (fd <0) {printf("Open file failed");}
else
{
dup2(fd,1);
args[k] = '\0';
fflush(stdout);
close(fd);
}
}
if (!strcmp("|", args[k]))
{
piping = 1;
}
} /*end for*/
if (!(piping))
{
pid = fork();
if (pid <0) {}
else if (pid == 0)
{
if ( (status = execvp(command, args)) < 0 )
{
printf("Command not found\n");
}
}
else /*parent*/
{
wait(&status);
} /*end parent*/
}/*end if not pipe*/
else /*its pipe*/
{
int pfd[2];
pipe(pfd);
fd = fork();
if (fd < 0) {}
else if (fd ==0)
{
close(pfd[1]);
dup2(pfd[0],0);
close(pfd[0]);
execvp(args[2],args[2]);
}
else /*parent*/
{
close(pfd[0]);
dup2(pfd[1],1);
close(pfd[1]);
execvp(args[0],args[0]);
}
}/*end pipe*/
} /*end outter else*/
printf("%s", prompt);
}/*end while*/
return 0;
}
for (k = 0; k < sizeof args; k++)
This is not how you iterate through args: this will go far beyond the end of the array. You want something like:
num = sizeof(args) / sizeof(*args);
for (k = 0; k < num; k++)
Alternatively, since you set the last element as NULL, you could do
for (char **arg = args; *arg; arg++)
Also note that you iterate with k until the end of the array and then use k + 1, which is very likely to cause problems.

making shell for homework

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
void exec(char **args){
pid_t pid;
int status;
if ((pid = fork()) < 0) {
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0) {
if(execvp(args[0],args)<0)//{
//printf("argv[0]=%s argv[1]=%s",args[0],args[1]);
printf("**error in exec\n");
}
else {
while (wait(&status) != pid);
}
}
void exec2(char **args, char *file){
printf("file =%s\n",file);
int fd;
pid_t pid;
int status;
if ((pid = fork()) < 0) {
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0) {
fd = open(file, O_RDWR | O_CREAT, (mode_t)0600);
close(1);
dup2(fd, 1);
if(execvp(args[0],args)<0){
printf("**error in exec");
}
else {
printf("\nhere\n");
close(fd);
while (wait(&status) != pid){
fflush(stdout) ;
}
}
}
close (fd);
}
void main(){
char *command;
char inp[512];
char *filepath;
size_t size=0;
char *substr;
char *args[512];
command = (char *) malloc(sizeof(char *) * 512);
int flag=0;
int redirect=0;
int i=0;
while (1){
printf("$ ");
command = fgets(inp, 512/*sizeof(char *)*/, stdin);
command[strlen(command)-1]='\0';
if (strchr(command,'>')){
redirect=1;
strtok_r(command,">",&filepath);
}
size_t siz=4;
//printf("command=%s\n",command);
int i=0;
while(1){
//printf("i=%d\n",i);
char *tok = strtok_r(command," ",&substr);
if (tok==NULL){
break;
}
args[i++] = tok;
/* printf("tok=%s\n",tok);
printf("len tok = %d\n",(int)strlen(tok));
printf("command=%s\n",command);
printf("substr=%s\n",substr);
*/ command = substr;
}
//printf("args[0]=%s",args[0]);
if (!strncasecmp(args[0],"exit",siz) || !strncasecmp(args[0],"quit",siz))
{
printf("\nBye\n");
exit(0);
}
else if(strcmp(args[0],"cd")==0){
chdir(args[1]);
//printf("chdir") ;
//system("pwd");
}
else if (redirect==1){
exec2(args,filepath);
}
else exec(args);
}
}
Okay this is my code for my shell. When i run it, i put ls and it gives correct output. Then i put ls -l and then ls again and it gives
ls: cannot access : No such file or directory
Also when i use cd, ls doesnt give output and pwd says "ignoring unused arguments"
ALso cat doesnt work.
Though mkdir, ps and ls -l works.
Don't close stdout!
Do it like this, after the fork and before the exec:
if (child) {
int fd = open(file, O_RDWR | O_CREAT, (mode_t)0600);
close(1);
dup2(fd, 1);
if(execvp(args[0],args)<0){
printf("**error in exec");
}
}

Resources