Using execve() to write the ls program in UNIX - c

At a high level, how would you use the execve() function to write a duplicate of the ls program in UNIX? I am doing an exercise to familiarize myself with the exec() family of functions, command-line arguments, and environment variables. I am not familiar with using these concepts, however I know what they do.

The code below can excute ls command. Do you mean this?
#include <stdio.h>
int main(void)
{
system("ls");
return 0;
}
And I wrote a simple ls demo for you.
my_ls.c
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
return 0;
}
DIR *dir = opendir(argv[1]);
if (dir) {
struct dirent *s_dir;
while((s_dir = readdir(dir))) {
printf("%s ", s_dir->d_name);
}
printf("\n");
}
return 0;
}
Usage:
gcc my_ls.c -o my_ls
./my_ls .

Related

How can I print all PID from /proc/ using C code?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#define PATH_LINE 128
void get_pid(){
char full_path[PATH_LINE]="";
int fd;
char pid[6];
for(int i=0 ;i <99999; i++){
fd =0;
memset(full_path,0,PATH_LINE);
strcat(full_path,PROC_PATH);
sprintf(pid, "%d", i);
strcat(full_path,pid);
fd = open(full_path, O_RDONLY);
if(fd != -1){
printf("%s - fd [%d]\n", full_path, fd);
}
}
}
int main(void){
get_pid();
return 0;
}
I expected this code to print all the PIDs I have on my computer.
That is, it will try to open the folder /proc/PID and if it does not return an error, then it will print the PID.
But, he prints me a lot of PIDs that don't really run on my computer...
Is there an error in my code? I'm trying to do this without built-in structs.
terminal output:
I would not loop from 0 to 99998 and try to open all those. It takes time and it misses processes with greater pids than 99998.
I suggest that you use opendir, readdir and closedir in order to read all directory entries in /proc and to filter out those you are interested in.
Example:
#include <dirent.h> // opendir, readdir, closedir
#include <sys/types.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
// a function to check if a string consists of all digits
bool all_digits(const char *str) {
for(; *str != '\0'; ++str) {
if(!isdigit((unsigned char)*str)) {
return false;
}
}
return true;
}
int main(void) {
DIR* dp = opendir("/proc"); // open /proc
if(dp) {
struct dirent *curr; // see: man 3 readdir
while((curr = readdir(dp))) { // read next directory entry
if(all_digits(curr->d_name)) { // d_name holds the leaf name
puts(curr->d_name); // only print if it only has digits
}
}
closedir(dp); // finally close the directory
}
}
I saw one serious problem here.
First of all, it is easier for us to view all processes with find /proc/ -maxdepth 1 -type d 2>/dev/null this command will show you all the processes in /proc/. I ran your code and saw that you are opening files and never closing them. I added one line close(fd); inside the if statement and I got all the processes that run on my machine.
In my opinion, this will fix your problem.
P.S. There is a limit to opened files from your program. Not closing opened files in for loop is what you missed here. You can check what is it with: ulimit -n.

Run c program from another one using system gcc command

I am trying to run a specific c program from my program using system in c.
gcc tell me "no such file or directory" even if i put the file
in the other program directory. The purpose is to execute the second program if some conditions are reached in the first. any help?
if(a==0){
system(" gcc -g -o iptablesExample mainiptables.c -lip4tc -lip6tc -ldl ");
system(" ./iptablesExample");
}
Maybe you can try your command with execve and fork, but I'm not sure it works
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
int main(int ac, char **av, char **env) {
pid_t pid = fork();
char *args[] = {"/usr/bin/ls", "-la", NULL}; //put the absolute path of gcc
if (pid == 0)
{
if (execve(args[0], args, env) == -1)
perror("error");
}
wait(&pid);
return 0;
}
Make sure to put the absolute path

How to use exec() system call to return the square of a number and store it to a file?

Given a number in the command line by the user, I need to return the square of that number and store it into a file called child.txt, but I need to do this by creating a child process and using exec(). How exactly do I do that? Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *f;
f = fopen("child.txt", "w");
int pid = fork();
square(argv);
exec(); // This is wrong, I need to fix this
return 0;
}
int square(char *argv[]) {
int i;
i = atoi(argv[1]);
return i*i;
}
What parameters should I be passing into exec()? I've seen other examples where exec() has parameters such as echo or -ls, but is it possible to somehow pass in the square() function I've written?
This is such a terrible idea for so many reasons....
But you can certainly do it:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int square(const char *arg) {
int i;
i = strtoll(arg, NULL, 10);
return i*i;
}
int main(int argc, char *argv[]) {
FILE *f;
char cmd[128];
int rv;
if( argc < 3 ) {
fputs( "Please specify target file and integer to square\n", stderr);
exit(EXIT_FAILURE);
}
f = fopen(argv[1], "w");
if( f == NULL ) {
perror(argv[1]);
exit(EXIT_FAILURE);
}
rv = snprintf(cmd, sizeof cmd, "echo %d >& %d", square(argv[2]), fileno(f));
if( rv >= sizeof cmd ) {
fputs( "Choose a smaller int\n", stderr);
exit(EXIT_FAILURE);
}
execl("/bin/sh", "sh", "-c", cmd, NULL);
perror("execl");
return EXIT_FAILURE;
}
But note that if this is for an assignment and you've been told to use exec*, then this solution would be an F grade. This is not what you're supposed to do. (At least I hope not. If that is the goal, then this is a terrible assignment.)
If you want to make some calculation not in main thread, you can create thread and detach it.
If you use c11 compiler you can use threads.h.
thrd_create wil create your thread, thrd_detach will detach it from main process.
If your compiler doesn't support c11 you can use native multitreading options.
#include <pthread.h> for Unix systems
#include <windows.h for Windows

Trying to use 'system()' and 'execv()' function calls

I want to execute a C program from another C program. Actually I need to use system() function for my functionality as the control returns to the calling program. As I was not able to get the result with system(), I tried using execv() which was not successful either.
Below are the sample codes which I was trying
int main(void) {
puts("executing this prog from another prog");
return EXIT_SUCCESS;
}
The above one is called test1.c
int main(void) {
execv("./test1",NULL); //system("./test1");
puts("!!!Hello World!!!");
return EXIT_SUCCESS;
}
This is test2.c
With system(), I am getting the sh: 1: ./test1: not found error and with execv() its just ignoring the statement and printing the !!!Hello World!!!
Note : Mainly I want to know the functioning of system() for the problem I want to solve.
The second parameter of execv must be an array of pointers to null-terminated strings, change to:
#include <unistd.h>
int main(void)
{
char *argv[] = {NULL};
execv("./test1", argv);
return 0;
}
If this fails you can check the cause of the error with perror:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
char *argv[] = {NULL};
if (execv("./test1", argv) == -1) {
perror("execv");
exit(EXIT_FAILURE);
}
return 0;
}

execl command to write on file

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXLINE 512
main(int argc,char* argv[]){
int k;
for (k=0; k<argc; k++) {
if (k%2==0) {
if (fork()==0){
execl("/user/bin/rev","rev",argv[k],">",argv[k],NULL);
exit(1);
}
}
else
{
if (fork()==0){
execl("/usr/bin/awk","awk","-f","ouk.awk",argv[k],">",argv[k],NULL);
exit(1);
}
wait(0);
}
}
}
awk script
{ for (i=NF;i>=1;i--){ if(s){s=s" "$i} else{s=$i }}{print s;s=""}}
Could someone please tell why this does not work? What I am trying to do is modify
the file argv[i] using the awk script or the rev command
Thanks
To have piping (>) work a shell needs to be involved. The OP's code does not call a shell but starts the awk process directly.
You might like to replace this line:
execl("/usr/bin/awk","awk","-f","ouk.awk",argv[k],">",argv[k],NULL);
by those:
char cmd[PATHMAX] = "";
sprintf(cmd, "\"/usr/bin/awk -f out.awk %s > %s\"", argv[k], argv[k]);
execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
/* As execl() does not return if successful, getting here indicates an error! */
perror("execl() failed");
(This implies that the strings referenced by argv[k]do not contain spaces.)
For details please see your shell's man pages. Note that /bin/sh commonly is linked to some other shell program like bash.

Resources