execve(2) system commands exit before execution - c

I am trying to implement a container, and for that I create a process using the clone(2) system call with the appropriate flags:
if ((child_pid = clone(child_main, process_struct.Stack + process_struct.StackPtr,
CLONE_NEWCGROUP
|CLONE_NEWIPC
|CLONE_NEWNET
|CLONE_NEWNS
|CLONE_NEWPID
|CLONE_NEWUTS
|SIGCHLD, &process_struct, checkpoint)) == -1){
fprintf(stderr,"Failed...%m \n");
exit(EXIT_FAILURE);
}else{
fprintf(stderr,"Done\n");
waitpid(child_pid, NULL, 0);
}
inside child_main() I Change the host name for the process's namespace, also i set the mount namespace, I installed a Linux file system hierarchy on a partition like a normal Linux installation (I did that to create a clean file system image clean of my files and binaries) and then I set the propagation type to MS_UNBINDABLE, then I pivot_root(2) to change my process's root directory.
const int child_main(struct process *process_struct, int *checkpoint){
char c;
fprintf(stderr,"=> IPC setup...");
//double check the IPC
close(checkpoint[1]);
fprintf(stderr,"Done\n");
if ( sethostname(process_struct->Hostname,
strlen(process_struct->Hostname)) || mounting(process_struct)){
return -1;
}
// startup the IPC pipes
read(checkpoint[0], &c, 1);
if(execve("/bin/bash", (char*)0, NULL) == -1 ){
fprintf(stderr,"--> Launching process Failed %m\n");
return -1;
}
return 0;
}
The problem is that my system goes over the execve(2) and does not launch the /bin/bash and the program flows without errors. When I add system(2) statement before the execve(2) : system("ls"); it lists the appropriate file system and current working directory. Also when I change the execve(2) paramters to either:
execve("/bin/ls", (char*)0, NULL) or execve("/bin/pstree", (char*)0, NULL) or any other parameter it will return an error of: No such file or directory or A NULL argv[0] was passed through an exec system call, also when I strace my program at the execve(2) system call it gives: NULL, 0, NULL) = 17992
The error has nothing to do with the file system image, I have performed more tests and are as the follwoing, I used for my mount namespaces my system's filesystem not the one I installed on a partition and running /bin/bash doesn't still work, I created a simple C program and compiled it, and it ran fine so there is something wrong that prevent bin/bash from being executed, to further test these results I reused for my mount namespaces the file system from my I moved the same executable to the file system first under "/" and second under the same path
my main system path to the executable= /home/omar/docs/test.out
my mounted file system from the partition path to the executable= /home/omar/docs/test.out
since I wanted to check if the same path might have caused a confusion while adding to each executable a statment so can tell which path did my program take, and it worked fine without any problem and correctly as expected, so the problem is just that system essential commands will not work.

You need to pass a proper argv array to execve. And if you just want to pass on the current environment, use execv rather than execve.
char *argv[] = {"bash", NULL};
if(execv("/bin/bash", argv) == -1 ){
perror("execv");
return -1;
}

Related

How to make 'cd' command work from my own custom shell?

I'm currently doing my Homework for UNIX(LINUX) programming.
I was assigned to build my own custom shell that all commonly used linux command and custom program can work.
I also created my_ls, my_cp, my_rm, my_cd for checking that both linux command and my own command works.
Simple story's are below
./myOwnShell // Run my own shell
home/testFolder>>ls . // Shell prompt
a.out helloWorld.txt myOwnShell.c myOwnShell // Print ls command's result
home/test/Folder>>my_ls . // Run my own ls command program
a.out helloWorld.txt myOwnShell.c myOwnShell
So far, all the linux command (which in /bin/) and my own command (which in home//bin/) works.
But it comes with differences when I type cd and my_cd - which changes current cwd
home/testFolder>>cd ..
Fail to run program // Error message from exec function failure
home/testFolder>>my_cd ..
// No message but also cwd is not changed
home/testFolder>> // Prompt from same folder
Somewhat pseudo source codes are below for myShell program
(I cannot copy/paste for my source cause it is in university server and transfer protocols are blocked)
int main() {
char** res; // store command by tokening
while (1) {
printf("%s>>", cwd);
gets(in); // get command
// <Some codes that split `in` by space and store it into res>
// <If cmd is "ls ./folder" -> res = ["ls", "./folder", NULL]>
pid = fork();
if (pid == 0) { // child
if (execvp(res[0], res) == -1) { // Run 'ls' command
printf("Fail to run program");
exit(0); // Exit child process
}
} else { // Parent, I omit in case of fork failure
wait(0);
// Omit exit status checking code
}
}
return 0;
}
Command cd is linux built-in command,
Command my_cd is my own program which change it's cwd.
And I do know that changing child process's cwd cannot effect to parent process and that's why 'cd' dose not change my shell's cwd. And I found that cd command is not in /bin/, so I guess cdis coded inside linux shell.
How can I make it work?
For linux cd
For my own my_cd -- I don't have it's source code, only have program. It is from my professor.
My guess is that cd cannot be implemented unless it is coded in shell itself. But professor give me this homework and it can mean that it is possible.
Any idea please?

C program in Linux to read a file descriptor passed as a terminal argument

I've been looking into different discussions how to get the open file descriptors for a current process on Linux from a c program, but could not find the following example:
./sample 4</some_file 5<some_other_file
Is there any way to get those file descriptors in a sample.c program in this case. I found out that those redirections are not treated as command line arguments. Hope someone can help.
Ofcourse fds 4 and 5 are given just as example, I would like the program to find out which fds were open on execution.
Given sample is started by
./sample 4</some_file 5<some_other_file
this will provide file descriptors that can be used to access those files:
int fd_for_some_file = 4;
int fd_for_some_other_file = 5;
If you don't want to assume file descriptors are fixed values, don't assign the files to hardcoded descriptor values when you start your process.
Edit:
I would like the program to find out which fds were open on execution.
In general, I don't think you can.
If, however, your code to identify pre-opened file descriptors runs before any invocation of open, you may be able to just run through values greater than 2 to see what they are using OS-specific means. On Linux:
for ( int fd = 3; fd < fd_max; fd++ )
{
sprintf( linkname, "/proc/self/fd/%d", fd );
int rc = readlink( linkname, linkvalue, sizeof( linkvalue ) );
if ( rc == 0 )
{
// found a file opened by calling process
}
}
Yes, that's inherently racy for multithreaded programs. If you're using GCC, you can put the code in a function with __attribute__(( constructor )) and it will run before main() is called. But even that could identify files opened by other such functions as being passed by the parent process.

mount of SD card in C program

My environment: Petalinux on Xilinx/Zynq Soc
I am trying to mount microSD card.
I confirmed that following code works to mount SD under root login.
#include <stdio.h>
int main(void)
{
int ret;
ret = system("mkdir /media/card");
printf("%d\n", ret);
ret = system("mount /dev/mmcblk0p1 /media/card");
if (ret == 0) {
printf("sd mounted to /media/card\n");
} else {
printf("sd mount : fail\n");
}
}
Is this a normal way to mount SD card in linux C program?
Or are there any special systemcall/API used in C program to mount SD?
Mounting filesystems is done with the mount(2) system call. That's what the mount program (that you're calling via system) actually does.
The normal way to mount a filesystem from a C program is to use the system call. Forking off a separate process to run a shell command (i.e. using the system function) is inefficient and prone to bugs (such as shell-injection security vulnerabilities), and gives you less control. The same goes for calling the mkdir program; just use the mkdir(2) system call instead. (Your program above is essentially a shell script written in C, which is silly.)

How to delete a file without using remove system call in a C program?

I've been curious how rem in Linux works and trying to write my own C code that can delete a file but when I searched for the answer, I only got the programs that were using remove() system call.
Is there any other way of doing it without using system call like writing your own code to do the job?
I've accomplished copying file through C filing but can't find a solution to delete a file through C.
int unlink (const char *filename)
The unlink function deletes the file name filename. The function unlink is declared in the header file unistd.h. This function returns 0 on successful completion, and -1 on error
If you want to delete a file use the
remove
function. If you want to have a look behind the scenes of the standard library, you may download the source of the glibc (e.g.) and have a look at the implementation. You will see that actually a INTERNAL_SYSCALL will be performed on linux os:
result = INTERNAL_SYSCALL (unlink, err, 1, file);
(from /sysdeps/unix/sysv/linux/unlinkat.c from the debian eglibc-2.15 package)
If you want to go further and even not use that syscall you will have to implement your own file system logic since the file system syscall just gives an abstraction layer to different filesystems.
If you don't want to use the clean, usual way, you can open /dev/sd** and play with your file system.
Btw, remove() isn't a syscall (man 3 remove).
The traditional way to delete a file is to use the unlink(2) function, which is called from remove(3), if path is a file.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
int status;
pid_t pid = fork();
if(-1 == pid){
printf("fork() failed");
exit(EXIT_FAILURE);
}else if(pid == 0){
execl("/bin/sh", "sh", "-c", "rm /tmp/san.txt", (char *) NULL);
}else{
printf("[%d]fork with id %d\n",pid);
waitpid(pid,&status,0);
}
return 0;
}

What system function and cp command return in C/Linux

Here i used below in code on linux.
using cp command in system function.
I know about system function it will return the 0 if command successfully executed.otherwise it will return error code.
If here i use proper source and destination path than i got output like this
Number == 0
If i give wrong source and destination path than i got
cp: cannot create regular file `/home/sam/test/test': No such file or directory
Number == 256
cp: cannot stat `/home/sam/main/test2/test': Not a directory
Number == 256
Here i want to know the error code of cp command what cp command return here.
My questions are here
1 System function return error code of cp command?
2 Can i get error code of cp command from source code of cp command?
3 i want to handle all types of error in this cp command.
code :
#include <stdlib.h>
#include <stdio.h>
void main()
{
int a;
a = system("cp /home/sam/main/test /home/sam");
printf("Number == %d\n",a);
}
So any body please Explain me about this all
The correct way to user the return value of system is with the wait-specific macros.
if (WIFEXITED(a)) {
int rc;
rc = WEXITSTATUS(a);
printf("Exit with status: %d\n", rc);
} else {
/* Killed by a signal. */
}
The man page of system states:
RETURN VALUE
The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command otherwise. This latter return
status is in the format specified in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In case
/bin/sh could not be executed, the exit status will be that of a command that does exit(127).
If the value of command is NULL, system() returns nonzero if the shell is available, and zero if not.
system() does not affect the wait status of any other children.
So, you can get the exit status with WEXITSTATUS(a) whene WIFEXITED(a) is true.
In general, the possible exit codes of a command are specified in the manpage. For cp, there is no documentation, so you can't rely on anything. You might think of going with lower-level system commands (such as open or link).
256 typically means there was a permission issue

Resources