Formating execvp output - c

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.

Related

clearing an array in preparation for new array values

The function gets an input from the user using read() and breaks it down using strtok and places it into an array. The program loops until it reaches an error (which i won't get into because that isn't the problem here) or if the program is terminated by the user. However, when it loops back around and reads the input from the user, it seems to be hanging onto the previous input from the user.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
#define BUFFERSIZE 1024
int main(int argc, char* argv[])
{
argc++;
char buf[BUFFERSIZE];
int n;
printf("Please enter commands: \n");
while ((n = read(STDIN_FILENO, buf, BUFFERSIZE)) > 0)
{
printf("original string: %s:\n", buf);
buf[strlen(buf)-1] = '\0';
printf("after change: %s:\n", buf);
int i = 0;
char* array[100];
char* token1 = strtok(buf, " ");
while ((token1 != NULL))
{
array[i++] = token1;
token1 = strtok(NULL, " ");
}//while
for (int j = 0; j < i; j++)
{
printf("Array value %d: %s:\n", j, array[j]);
}//for
if (buf == "exit")
{
printf("found it\n");
}//if
for (int i = 1; i < argc; i++)
{
pid_t pid;
if (argc >= 1)
{
if ((pid = fork()) < 0)
{
perror("fork");
}//if
else if (pid == 0)
{ // child process
if (execvp(array[0], array) == -1)
{
perror("execvp");
return EXIT_FAILURE;
} // if
}//else if
else
{ // parent process
int status;
wait(&status);
printf("Please enter commands again: \n");
}//else
}//if
else
{
fprintf(stderr, "Please specify the name of the program to exec as a command line argument\n");
return EXIT_FAILURE;
}//if
}//for
}//while
if (n == -1) perror("read");
}//main
I've tried to clear the array and clear "buf" but no luck. i have a feeling it has to do with the read() and the fact that "buf" is hanging onto its old value.
Prefaced by my top comments ...
read does not add 0x00 the way fgets does, so we have to do it manually.
execvp needs the array to be terminated with a NULL entry.
child should use exit instead of return.
Here's the refactored code. It is annotated. Note that this code does not do the split/join of the buffer to guarantee the buffer ending in newline as suggested by my top comments:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
#define BUFFERSIZE 1024
int
main(int argc, char *argv[])
{
argc++;
char buf[BUFFERSIZE];
int n;
printf("Please enter commands: \n");
// NOTE/BUG: read does _not_ add 0x00 the way fgets does
#if 0
while ((n = read(STDIN_FILENO, buf, BUFFERSIZE)) > 0) {
#else
while ((n = read(STDIN_FILENO, buf, BUFFERSIZE - 1)) > 0) {
buf[n] = 0;
#endif
printf("original string: %s:\n", buf);
buf[strlen(buf) - 1] = '\0';
printf("after change: %s:\n", buf);
int i = 0;
char *array[100];
char *token1 = strtok(buf, " ");
while ((token1 != NULL)) {
array[i++] = token1;
token1 = strtok(NULL, " ");
}
// NOTE/BUG: execvp needs a NULL terminator
#if 1
array[i] = NULL;
#endif
for (int j = 0; j < i; j++) {
printf("Array value %d: %s:\n", j, array[j]);
}
// NOTE/BUG: wrong way to compare strings
#if 0
if (buf == "exit")
#else
if (strcmp(buf, "exit") == 0) {
printf("found it\n");
break;
}
#endif
for (int i = 1; i < argc; i++) {
pid_t pid;
if (argc >= 1) {
if ((pid = fork()) < 0) {
perror("fork");
}
// child process
else if (pid == 0) {
if (execvp(array[0], array) == -1) {
perror("execvp");
#if 0
return EXIT_FAILURE;
#else
exit(EXIT_FAILURE);
#endif
}
}
// parent process
else {
int status;
wait(&status);
printf("Please enter commands again: \n");
}
}
else {
fprintf(stderr, "Please specify the name of the program to exec as a command line argument\n");
return EXIT_FAILURE;
}
}
}
if (n == -1)
perror("read");
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k

Why are my semaphores not working as expected?

I need to print the following sentence to the console "My name is Bond, James Bond" alternating the words using semaphores.
Whenever I print the words using line breaks "\n", everything prints in the expected order, however if I don't use line breaks everything prints out of order.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <wait.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
int main(){
pid_t pid;
int i = 0;
sem_t *sem[4];
char * names[4] = {"/sem_ex07_1", "/sem_ex07_2", "/sem_ex07_3", "/sem_ex07_4"};
for(i = 0; i < 4; i++){
sem_unlink(names[i]);
}
for(i = 0; i < 4; i++){
if((sem[i] = sem_open(names[i], O_CREAT | O_EXCL, 0644, 0)) == SEM_FAILED){
printf("sem_open() error\n");
sem_unlink(names[i]);
exit(1);
}
}
sem_post(sem[0]);
for(i = 0; i < 3; i++){
pid = fork();
if(pid == 0){
break;
}
}
if(pid == 0){
if(i == 0){
sem_wait(sem[0]);
printf("My");
sem_post(sem[1]);
sem_wait(sem[0]);
printf("Bond, ");
sem_post(sem[1]);
} else if(i == 1){
sem_wait(sem[1]);
printf("name ");
sem_post(sem[2]);
sem_wait(sem[1]);
printf("James ");
sem_post(sem[2]);
} else if(i == 2){
sem_wait(sem[2]);
printf("is ");
sem_post(sem[0]);
sem_wait(sem[2]);
printf("Bond.\n");
sem_post(sem[3]);
}
} else if(pid > 0){
sem_wait(sem[3]);
for(i = 0; i < 4; i++){
sem_unlink(names[i]);
}
}
return 0;
}
Why is my output only correct if I add a line break on each printf?
Why is my output only correct if I add a line break on each printf?
printf() is mostly by default line buffered. stdio functions which use streams (instead of file descriptors like write() does) use a buffer.
The buffer can be set via setvbuf(3).
See also Disable buffering for stdin and stdout using setvbuf()

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.

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]);

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

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.

Resources