#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
int show_dir_content(char *path);
int show_dir_content(char *path)
{
char readbuffer[80];
char buffer[150];
char uzun[9999];
int totalfound = 0;
DIR *d = opendir(path);
if(d == NULL)
return -3;
struct dirent *dir;
int piper[2];
pid_t typer = 0;
while((dir = readdir(d)) != NULL)
{
pipe(piper);
typer = fork();
if(typer == 0)
{
close(piper[0]);
if(dir->d_type != DT_DIR)
{ // if the type is not directory blue
// printf("%s\n",dir->d_name);
sprintf(buffer, "%s", dir->d_name);
write(piper[1], buffer, (strlen(buffer) + 1));
}
else if(dir->d_type == DT_DIR && strcmp(dir->d_name, ".") != 0 &&
strcmp(dir->d_name, "..") != 0) // if it is a directory
{
char d_path[255]; // here I am using sprintf which is safer than
// strcat
sprintf(d_path, "%s/%s", path, dir->d_name);
show_dir_content(d_path); // recall with the new path
}
exit(0);
close(piper[1]);
}
else if(typer > 0)
{
close(piper[1]);
read(piper[0], readbuffer, sizeof(readbuffer));
// strcat(uzun,readbuffer);
// close(piper[0]);
break;
}
}
while(wait(NULL) > 0)
;
closedir(d);
// printf("%s x_x\n",uzun);
return totalfound + 1; // finally close the directory
}
int main(int argc, char **argv)
{
show_dir_content(argv[1]);
return (0);
}
It doesn't execute on forked child, only on parent and only once.
I use Linux Mint 18 and gcc comes with it.
i don't what causes it, it doesn't seems to be Segmentation fault because it exits correctly. I would be more then happy if anyone can see my errors here
I'm debugging on CLion.
Related
I have been trying to implement an exit command on my C shell. I have tried the fork-exec method since it's a system call.
When I run the program, it prompts for the stdin input and when I type in "exit" it returns a "segmentation fault (core dumped)" error.
What am I doing wrong?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#define ARGVMAX 100
#define LINESIZE 1024
#define EXITCMD "exit"
//makeargv - builds an argv vector from words in a string
int makeargv(char *s, char *argv[ARGVMAX]) {
int ntokens = 0;
if (s == NULL || argv == NULL || ARGVMAX == 0)
return -1;
argv[ntokens] = strtok(s, " \t\n");
while ((argv[ntokens] != NULL) && (ntokens < ARGVMAX)) {
ntokens++;
argv[ntokens] = strtok(NULL, " \t\n");
}
argv[ntokens] = NULL; // it must terminate with NULL
return ntokens;
}
void prompt() {
printf("sish> ");
fflush(stdout); //writes the prompt
}
/****** MAIN ******/
int main() {
char line[LINESIZE];
int wstatus;
while (1) {
prompt();
if (fgets(line, LINESIZE, stdin) == NULL)
break;
// TODO:
if(fgets(line, LINESIZE, strcmp(stdin, EXITCMD )) == 0)
return 0;
signal(SIGINT, SIG_DFL);
if (fork() == 0) exit(execvp(line[0], line));
{
signal(SIGINT, SIG_IGN);
}
wait(&wstatus);
if(WIFEXITED(wstatus))
printf("<%d>", WEXITSTATUS(wstatus));
}
return 0;
}
After reviewing and cleaning the code, I was finally able to implement the exit command.
Here goes the code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#define ARGVMAX 100
#define LINESIZE 1024
#define EXITCMD "exit"
//makeargv - build an argv vector from words in a string
int makeargv(char *s, char *argv[ARGVMAX]) {
int ntokens = 0;
if (s == NULL || argv == NULL || ARGVMAX == 0)
return -1;
argv[ntokens] = strtok(s, " \t\n");
while ((argv[ntokens] != NULL) && (ntokens < ARGVMAX)) {
ntokens++;
argv[ntokens] = strtok(NULL, " \t\n");
}
argv[ntokens] = NULL; // it must terminate with NULL
return ntokens;
}
void prompt() {
printf("C Shell >> ");
fflush(stdout); //writes the prompt
}
/****** MAIN ******/
int main() {
char line[LINESIZE];
while (1) {
prompt();
if (fgets(line, LINESIZE, stdin) == NULL)
break;
// TODO:
char *p = strchr(line, '\n');
if (p)
*p = 0;
if(strcmp(line, "exit") == 0)
break;
char *args[] = {line, (char*) 0};
int pid = fork();
if (pid == 0){
execvp(line, args);
perror("Command Error!");
exit(1);
} else {
wait(NULL);
}
return 0;
}
return 0;
}
I am building a simple shell I want to handle the argument of exit. How can I handle it here?
I have already handle exit but I want to handle exit with argument.
Usage: exit status, where status is an integer used to exit the shell
For example
exit 98
exit 1
Present output
sh: No file or directory found
Expected Output
Exit the shell with the specific status code
shell.h
#ifndef SHELL_H
#define SHELL_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
void print_prompt(void);
void tok_str(char *, char **);
int add_path(char **cmd);
void print_env(char **);
#endif
shell.c
#include "shell.h"
int main(int argc, char **argv, char **env)
{
char *buf = NULL;
size_t buflen = 0;
char *cmd[20];
do
{
fprintf(stderr, ":) ");
if (getline(&buf, &buflen, stdin) == -1)
{
if (feof(stdin))
{
free(buf);
buf = NULL;
exit(EXIT_SUCCESS);
}
perror("Error occurred");
free(buf);
buf = NULL;
exit(EXIT_FAILURE);
}
if (buf[0] == '\0' || strcmp(buf, "\n") == 0)
{
free(buf);
buf = NULL;
continue;
}
if (strcmp(buf, "exit\n") == 0)
{
free(buf);
buf = NULL;
exit(EXIT_SUCCESS);
}
if (strcmp(buf, "env\n") == 0)
{
print_env(env);
free(buf);
buf = NULL;
continue;
}
tok_str(buf, cmd);
add_path(cmd);
if (fork() == 0)
{
execve(cmd[0], cmd, env);
printf("%s: No such file or directory\n", argv[0]);
exit(EXIT_SUCCESS);
}else
{
wait(NULL);
free(buf);
buf = NULL;
}
} while (1);
exit(EXIT_SUCCESS);
}
utils.c
#include "shell.h"
void tok_str(char *buf, char **cmd)
{
char *ptr;
int i = 0;
ptr = strtok(buf, " \n");
while (ptr)
{
cmd[i] = ptr;
ptr = strtok(NULL, " \n");
i++;
}
cmd[i] = NULL;
}
int add_path(char **cmd)
{
const char *PATH[] = {"/usr/local/bin/ls", "/bin/", "/sbin/", "/usr/bin/", NULL};
unsigned int i = 0;
struct stat st;
while (PATH[i])
{
char s[120] = "";
strcat(s, PATH[i]);
strcat(s, cmd[0]);
if (stat(s, &st) == 0)
{
cmd[0] = s;
return (0);
}
i++;
}
return (-1);
}
void print_env(char **env)
{
int i = 0;
while (env[i])
printf("%s\n", env[i++]);
}
I've got a basic shell program that can change directories using cd and list the files with ls. I want to extend this further by adding optional flags to the ls command. In particular, I want to implement the ls -l (lowercase 'ell') command whereby it shows a total sum of all file sizes on the line before the long listing. I'm not sure how I can implement this. My code I have so far is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#define MAX_LENGTH 1024
#define DELIMS " \t\r\n"
int main(int argc, char *argv[]) {
char *cmd;
char line[MAX_LENGTH];
while(1){
printf("> ");
if (!fgets(line, MAX_LENGTH, stdin)) break;
if ((cmd = strtok(line, DELIMS))) {
char *arg = strtok(0, DELIMS);
if (strcmp(cmd, "cd") == 0) {
if (!arg) fprintf(stderr, "cd missing argument.\n");
else {
chdir(arg);
}
}
else if (strcmp(cmd, "ls") == 0) {
struct dirent **namelist;
int n;
n = scandir(".",&namelist,NULL,alphasort);
if(n < 0)
{
perror("scandir");
exit(EXIT_FAILURE);
}
else
{
while (n--)
{
printf("%s\n",namelist[n]->d_name);
free(namelist[n]);
}
free(namelist);
}
}
else if (strcmp(cmd, "exit") == 0) {
break;
}
}
}
return 0;
}
So I'm trying to create a custom shell for my school project. My method was to create child process, and have that process execute the command using the execvp() function that my professor briefly mentioned in class that we are meant to use. Here's my code, as always, any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define MAX_LINE 80
int main(int argc, char *argv[])
{
char *input = (char*)malloc(MAX_LINE*sizeof(char));
int should_run = 1;
while(should_run){
printf("osh>");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0){
printf("error with creating chiled process");
return 0;
}
if(pid == 0){
fgets(input, MAX_LINE, stdin);
char *token = strtok(input," ");
if(execvp(token[0], token) < 0){
printf("Error in execution.");
return(0);
}
//should_run = 0;
}
waitpid(pid, 1, 0);
}
return 0;
}
The prototype of execvp is
int execvp(const char *file, char *const argv[]);
It expects a pointer to char as the first argument, and a NULL-terminated
pointer to an array of char*. You are passing completely wrong arguments.
You are passing a single char as first argument and a char* as the second.
Use execlp instead:
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
So
char *token = strtok(input," \n");
if(token == NULL)
{
fprintf(stderr, "only delimiters in line\n");
exit(1);
}
if(execlp(token, token, NULL) < 0){
fprintf(stderr, "Error in execution: %s\n", strerror(errno));
exit(1);
}
Also the convention in UNIX is to print error messages to stderr and a process with an error should
have an exit status other than 0.
As Pablo's states, you are passing the wrong arguments to execvp().
You can consider coding by yourself a function (char **strsplit(char *str, char delim)) which takes a string and split it into smaller pieces, returning an array of strings.
Also don't ignore compiler's warnings, they tell you a lot of things, and I suggest you to compile with gcc -Wall -Wextra -Werror to get almost any possible error in your program.
I tell you this because waitpid() takes as second argument a pointer to integer, to get an update of the status of the forked program. With this status you how the program exited (normally, segf, bus error...), you can use it to print an error if something went wrong.
You can consider using execv() instead (I know I'm going off topic, but you can learn useful things doing this), and find by yourself the correct executable(s).
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX_LINE 255
char **strsplit(char *str, char delim);
char *strjoin(char const *s1, char const *s2);
int isexec(char *path)
{
struct stat buf;
lstat(path, &buf);
if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode))
return (1);
return (0);
}
static char *find_exec_readdir(char *paths, char *cmd)
{
DIR *dir;
struct dirent *dirent;
char *exec;
exec = NULL;
if ((dir = opendir(paths)) != NULL)
{
while ((dirent = readdir(dir)) != NULL)
{
if (!strcmp(dirent->d_name, cmd))
{
exec = strdup(dirent->d_name);
break ;
}
}
if (closedir(dir))
dprintf(2, "Failed closing dir.\n");
}
return (exec);
}
char *find_exec(char *cmd, char **paths)
{
char *exec;
char *path;
char *tmp;
int i;
i = -1;
exec = NULL;
path = NULL;
if ((cmd[0] == '.' || cmd[0] == '/'))
{
if (isexec(cmd))
return (strdup(cmd));
return (NULL);
}
while (paths[++i])
if ((exec = find_exec_readdir(paths[i], cmd)) != NULL)
{
tmp = strjoin(paths[i], "/");
path = strjoin(tmp, exec);
free(tmp);
free(exec);
break ;
}
return (path);
}
int handle_return_status(int status)
{
int sig;
int i;
if (!WIFEXITED(status) && WIFSIGNALED(status))
{
sig = WTERMSIG(status);
i = -1;
while (++i <= 13)
{
if (print_signal_error(sig))
{
return (-1);
}
}
dprintf(2, "Process terminated with unknown signal: %d\n", sig, NULL);
return (-1);
}
return (0);
}
int main(int argc, char *argv[])
{
char *input = NULL;
char **command = NULL;
int should_run = 1;
int status = 0;
(void)argc;
(void)argv;
if ((input = (char*)malloc(MAX_LINE*sizeof(char))) == NULL)
return (dprintf(2, "Failed to malloc, abort.\n"));
while(should_run){
printf("osh> ");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0)
return (dprintf(2, "error with creating chiled process\n"));
if(pid == 0){
fgets(input, MAX_LINE, stdin);
command = strsplit(input, ' ');
command[0] = find_exec(command[0], strsplit(getenv("PATH"), ':'));
if(execv(command[0], &command[1]) < 0)
return (dprintf(2, "Error in execution.\n"));
//should_run = 0;
}
waitpid(pid, &status, 0);
handle_ret_status(status);
}
return 0;
}
I have problem with achieving int output of numbers of running processes with same PID.
Eg.
ps aux | grep program1
shows me 3 process, 2 of my main app (parent and child). I wanna know how to get it in C. my point is to get like number "2" because i have two processes with same name. As far as i know i cannot get terminal output to C variable so I really dont have idea how to get it.The problem is that I must get this information on progmam2 not program1.
Thanks!
Check this out, I think this is not advanced at all
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
void readProcessName(const char *const comm, char name[PATH_MAX])
{
int fd;
int size;
fd = open(comm, O_RDONLY);
if (fd == -1)
return;
if ((size = read(fd, name, PATH_MAX)) > 1)
name[size - 1] = '\0';
else
name[0] = '\0';
close(fd);
}
void findProcessByName(const char *const find)
{
DIR *dir;
struct dirent *entry;
dir = opendir("/proc");
if (dir == NULL)
return;
chdir("/proc");
while ((entry = readdir(dir)) != NULL)
{
struct stat st;
char comm[PATH_MAX];
const char *name;
char procname[PATH_MAX];
name = entry->d_name;
if (stat(name, &st) == -1)
continue;
if (S_ISDIR(st.st_mode) == 0)
continue;
/* this will skip .. too, and any hidden file? there are no hidden files I think */
if (name[0] == '.')
continue;
snprintf(comm, sizeof(comm), "%s/comm", name);
if (stat(comm, &st) == -1)
continue;
readProcessName(comm, procname);
if (strcmp(procname, find) == 0)
printf("%s pid: %s\n", procname, name);
}
closedir(dir);
}
int main(int argc, char **argv)
{
findProcessByName("process-name-here");
return 0;
}