I am making linux command Program by C-language. and I want to know what is wrong the code? - c

I wanna ask about how to make exec process programing by C.
Now, I typed like these code, and I use strtok and strdup.
my code wrong assign value from input, so could you see my code and could you teach what is wrong in the code.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(){
int pid;
int status, i = 0;
char input[256], path[30];
const char* a[10];
char* token;
char* split = " ";
while(input != "exit"){
printf("Please type your command:\n");
fgets(input, 256, stdin); /* emxape: ls -alf argv[0] = "ls" argv[1] = -alf*/
printf("Input: %s", input);
i = 0;
token = strdup(strtok(input,split));
while(token != NULL){
a[i] = token;
token = strdup(strtok(NULL,split));
printf("a%d is %s\n", i, a[i]);
i++;
}
int j = 0;
while( j < sizeof(a))
{
printf("%s", a[j]);
j++;
}
//free(copy);
if(strcmp(a[0],"cd")== 0 )/*for compare pointer*/
{
if (chdir((a[1])) == 0) {
printf("Sucess change Directory.\n");
return 0;
}
else {
printf("Fault change Directroy\n");
perror("");
}
if (a[1] == NULL)
{
if(chdir(getenv("HOME"))<<0)
perror("cd");
return 0;
}
else
{
if(chdir(a[1]) <0)
perror("cd");
}
}
sprintf(path,"%s",a[0]);
pid = fork();
/*Child process*/
if(pid == 0){
//execl(path,a[0],a[1],NULL);
execl(a[0],a[1],a[2],NULL);
printf("Wrong child process: %s",path);
exit(0);
}
/*Parents Process*/
else {
wait(&status);
}
}//while
printf("Thank you.");
}/*main*/

There are at least 2 problems
Line 26: token = strdup(strtok(NULL,split)); should be token = strdup(strtok(input,split));
After the first modification, the loop in line 24 can run. but still does not run correctly. It seems the strtok(), and strdup() does not run correctly.

Related

Formating execvp output

I am working on a shell command program in C, I have it working but the output is not formatted correctly. I am unable to see where the problem lies. I have read through the code several times and I am not seeing the issue. I have tried placing \n in various places but that typicality results in worse formatting.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#define MAX_LINE 80 /*Maximum length of a command*/
#define MAX_HST 10
int main(void){
char getInput[MAX_LINE];
char *args[MAX_LINE/2+1]; /*command line arguments*/
int should_run = 1; /*Flag to determine when to exit the program*/
int numCommand = 0;
int cmdHst = 0;
char *cmdHistory[MAX_HST];
char *myCmd;
while (should_run = 1){
printf("osh> ");
fflush(stdout);
fgets(getInput, MAX_LINE, stdin);//read input command
if(strcmp(getInput, "!!\n") == 0){//Command history
if(cmdHst == 0){
printf("No previous commands.\n");
}
for (int i= 0; i<cmdHst; i++){//display all commands in history
strncpy(getInput, cmdHistory[i], MAX_LINE);
printf("%s\n", getInput);
}
}
if (cmdHst < MAX_HST){
cmdHistory[cmdHst] = strdup(getInput);
cmdHst++;
}
else{//shift commands in history to fill gaps
for(int i = 1; i < cmdHst; i++){
free(cmdHistory[i-1]);
cmdHistory[i-1]= strdup(cmdHistory[i]);
}
free(cmdHistory[cmdHst-1]);
cmdHistory[MAX_HST-1] = strdup(getInput);
}
//parsing commands into tokens
numCommand = 0;
args[numCommand] = strtok(getInput, " \n");
while(args[numCommand] != NULL){
numCommand++;
args[numCommand] = strtok(NULL, " \n");
}
args[numCommand]=NULL;
if(strcmp(args[0], "exit")==0){//Check for exit command
should_run =0;
break;
}
pid_t pid = fork();//Create child process
if(pid < 0){
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if(pid == 0){
if(execvp(args[0], args)==-1){
fprintf(stderr, "Command Not Found.\n");
exit(1);
}
else{
if(args[numCommand-1][0] != '&'){
wait(NULL);
}
}
}
}
for(int i = 0; i < cmdHst; i++){//free histrry array
free(cmdHistory[i]);
}
return 0;
}
I have read over the code a few times and tried in putting fprintf("\n");s in various places.
I forgot the parent wait(NULL) command. That fixed it.

Basic shell that takes multiple word command

I am trying to implement a shell that takes a command ; however, I can not get it to work properly. For example, if I type "ls -a", I get this:
invalid option -- '
'
Try 'ls --help' for more information.
I have probably made some bad mistakes as I am a beginner so please forgive me. Also, I will put the code that reads in the command into a function. Its just like this for testing- thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stddef.h>
int main()
{
pid_t pid;
int status;
char* token;
char* argv[20];
char input[100];
printf("AP> ");
while (1)
{
fgets(input, 100, stdin);
token = strtok(input, " ");
int i = 0;
//walk through other tokens
while (token != NULL) {
argv[i] = malloc(strlen(token) + 1);
strncpy(argv[i], token, strlen(token));
//argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
pid = fork();
if (pid < 0)
{
perror("fork error");
return EXIT_FAILURE;
}
else if (pid == 0)
{
// child process
execvp(argv[0], argv);
perror("execl error");
return EXIT_FAILURE;
}
else {
// parent process
if (waitpid(pid, &status, 0)<0)
{
perror("waitpid error");
return EXIT_FAILURE;
}
}
printf("AP> ");
}
return 0;
}
If you insert the following loop after the inner while loop, then you'll see that you aren't removing the newline character at the end of input before the while loop starts.
for (i=0; argv[i]; i++)
printf("argv[%d] = '%s'\n", i, argv[i]);
Alternatively, you can use:
" \n"
as your separators instead of just
" "

Address out of bounds in C, problems with making an ls command

I am trying to make a some what shell in C but I am having problems with making the ls command. mkdir, and cd work fine but with ls it gives me
"Address out of bounds segmentation error"
Hope somebody can help me. Here's my code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <readline/readline.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
printf("\033[1;33mWelcome To Crisp Bacon Shell\n");
while (1) {
printf("\033[0m%s $", hostname);
input = readline("");
command = get_input(input);
child_pid = fork();
if (child_pid < 0) {
perror("Fork failed");
exit(1);
}else if (child_pid == 0) {
/* Never returns if the call is successful */
execvp(command[0], command);
printf("This won't be printed if execvp is successul\n");
} else {
waitpid(child_pid, &stat_loc, WUNTRACED);
}
free(input);
free(command);
}
return 0;
}
char **get_input(char *input) {
char **command = malloc(8 * sizeof(char *));
char *separator = " ";
char *parsed;
int index = 0;
parsed = strtok(input, separator);
while (parsed != NULL) {
command[index] = parsed;
index++;
parsed = strtok(NULL, separator);
}
command[index] = NULL;
return command;
}
The only thing I understand it has something to do with memory and references or pointers but I tried changing everything from & refrencing to pointers and it just gave me more errors what do I do?
There were many undeclared variables in your code snippets. You also need to fetch the hostname, it isn't a global variable. It's also a best practice to declare your functions before using them.
This works fine:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <readline/readline.h>
#include <unistd.h>
#include <sys/wait.h>
char **get_input(char *input) {
char **command = malloc(8 * sizeof(char *));
char *separator = " ";
int index = 0;
char *parsed = strtok(input, separator);
while (parsed != NULL && index < 8) { // you need to make sure the index does not overflow the array
command[index] = parsed;
index++;
parsed = strtok(NULL, separator);
}
command[index] = NULL;
return command;
}
int main() {
printf("\033[1;33mWelcome To Crisp Bacon Shell\n");
while (1) {
// hostname does not exist, you need to fetch it
char hostname[1024];
gethostname(hostname, 1023); // POSIX only
printf("\033[0m%s $", hostname);
char *input = readline(NULL);
char **command = get_input(input);
pid_t child_pid = fork();
if (child_pid < 0) {
perror("Fork failed");
exit(1);
} else if (child_pid == 0) {
/* Never returns if the call is successful */
execvp(command[0], command);
printf("This won't be printed if execvp is successul\n");
} else {
waitpid(child_pid, NULL, WUNTRACED); // since you don't use the middle argument, no need to point to valid data
}
free(input);
free(command);
}
return 0;
}

why wouldn't ls work with execvp?

I have an assignment requesting me to write a mini-shell - something that will get a command to execute, execute it, and wait for some more commands.
when I pass to this mini-shell the command ls . it prints the contest of the current directory. When I pass to it ls it prints nothing. Why?
here is my code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_CMD_SIZE 40
char** parse(char*);//will parse the arguments for the execv/excevp commands.
int main(int argc, char** argv)
{
bool debug = false;
assert(argc <= 2);
if (argc == 2)
{
//check for string -debug
debug = true;
}
if (debug)
printf("INFO: Father started PID[%d]\n", getpid());
char *command = malloc(MAX_CMD_SIZE);
while(true)
{
printf("minishell> ");
fgets(command, MAX_CMD_SIZE, stdin);
if (strcmp(command, "exit\n") == 0)
return 0;
pid_t pid = fork();
assert(pid >= 0);
if (pid == 0) //child
{
if (debug)
printf("INFO: Child started PID[%d]\n", getpid());
char** buf = parse(command);
if (debug)
{
int i;
for (i = 0; buf[i]; i++)
printf("INFO: buf[%d] = %s\n",i,buf[i]);
}
execvp(buf[0],buf);
return 0;
}
else //father
{
int status;
wait(&status);
if (debug)
printf("INFO: Child with PID[%d]terminated, continue waiting commands\n", pid);
}
}
}
char** parse(char *string)
{
char** ret = malloc(sizeof(char*));
ret[0] = strtok(string, " ");
int i = 0;
for (; ret[i]; ret[i] = strtok(NULL, " \n"))
{
ret = realloc(ret, sizeof(char*) * ++i);
}
return ret;
}
Your parse() command includes a \n in the last argument :)
So with a single ls, you're actually executing ls\n, which is not in the PATH (of course)
The problem is that on the first strtok() call, you only pass " " as a delimiter. Use " \n" (like in the subsequent calls) and the problem goes away.
You could also fix it by chomping the \n:
int l = strlen (string);
if (l > 0 && string [l - 1] == '\n') string [l - 1] = '\0';
and only using " " as a delimiter.

Global variable not staying set, maybe caused by fork()

I'm trying to write a very very simple unix shell in C, and I have the basics of what I need working, except support for a history command. I have a global 2D char array that holds the history of all entered commands. Commands are added before the fork() system call, and I was originally printing out the value of the history global array after strings were added, and they were printing out correctly, so I'm not sure why it doesn't print out when the command "history" is used at the shell.
Thank to anyone who takes a look.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "myhistory.h"
int BUFFER_SIZE = 1024;
char history[100][80];
int command_index = 0;
int main(int argc, char *argv[]){
int status = 0;
int num_args;
pid_t pid;
while(1){
char *buffer_input, *full_input;
char command[BUFFER_SIZE];
char *args[BUFFER_SIZE];
printf("myshell> ");
buffer_input = fgets(command, 1024, stdin);
full_input = malloc(strlen(buffer_input)+1);
strcpy(full_input, buffer_input);
if (command_index >= 100) {
command_index = 0;
}
strncpy(history[command_index], full_input, strlen(full_input) + 1);
command_index += 1;
parse_input(command, args, BUFFER_SIZE, &num_args);
//check exit and special command conditions
if (num_args==0)
continue;
if (!strcmp(command, "quit" )){
exit(0);
}
if(!strcmp(command, "history")){
int i;
fprintf(stderr,"%d\n",(int)pid);
for(i = 0; i < command_index; i++){
fprintf(stdout, "%d: %s\n",i+1,history[command_index]);
}
continue;
}
errno = 0;
pid = fork();
if(errno != 0){
perror("Error in fork()");
}
if (pid) {
pid = wait(&status);
} else {
if( execvp(args[0], args)) {
perror("executing command failed");
exit(1);
}
}
}
return 0;
}
void parse_input(char *input, char** args,
int args_size, int *nargs){
char *buffer[BUFFER_SIZE];
buffer[0] = input;
int i = 0;
while((buffer[i] = strtok(buffer[i], " \n\t")) != NULL){
i++;
}
for(i = 0; buffer[i] != NULL; i++){
args[i] = buffer[i];
}
*nargs = i;
args[i] = NULL;
}
Change:
fprintf(stdout, "%d: %s\n",i+1,history[command_index]);
to:
fprintf(stdout, "%d: %s\n",i+1,history[i]);

Resources