I'm tasked with programming the linux cd command in C. I thought this would be fairly trivial by using the chdir() method, but my directories aren't changing. What's interesting is that the return status of chdir() is 0, not -1, meaning chdir() has not failed. Here are the two cases where I'm using chdir():
1.
char *dir = getenv("HOME"); // Here dir equals the home environment.
int ret = chdir(dir);
printf("chdir returned %d.\n", ret);
ret returns 1.
2.
int ret = chdir(dir); // Here dir equals the user's input.
printf("chdir returned %d.\n", ret);
ret returns 1 if the directory exists in my path.
Am I using chdir() wrong? I can't seem to find an answer for this anywhere. Any help would be much appreciated.
chdir() changes the working directory of the calling process only.
So when you have code like ...
int main() {
// 1
chdir("/"); // error handling omitted for clarity
// 2
}
... and compile that to a program example and then run it in a shell:
$ pwd # 3
/home/sweet
$ ./example # 4
$ pwd # 5
/home/sweet
Then you have two processes in play,
the shell, which is where you entered pwd and ./example
./example, the process launched (by the shell) with your compile program.
chdir() is part of your compiled program, not the shell, thus it affects only the process with your program, not the shell.
So, at // 1 the working directory of your program (in above example run) is /home/sweet, but at // 2 it is / as specified in the chdir() call above. This doesn't affect the shell and the output of pwd # 5 though!
Related
I want to find the number of context switches of a program. I know there is a file /proc/PID/status which reports the number of context switches continuously while the program is running. However, after the process is finished that file is deleted, so I am not able to check the content.
For this reason, in the following C code, I am trying to copying that file before and after the region of interest.
int pid_num = getpid();
system("sudo cp /proc/$pid_num/status start.txt");
// do
system("sudo cp /proc/$pid_num/status finish.txt");
As I run the program, I get this message
cp: cannot stat '/proc//status': No such file or directory
It seems that $pid_num in the system function is not correct. What is the correct form then?
C uses format specifiers equivalent to more generic $var shell counterpart. You need to prepare the command-string before invoking system() call.
#define START_FILE "start.txt"
#define END_FILE "finish.txt"
#define MAX_CMD_BUFFSIZE 256 // adjust as necessary
char cmdbuf[MAX_CMD_BUFFSIZE];
pid_t pid_num = getpid();
snprintf(cmdbuf, sizeof(cmdbuf), "sudo cp -f /proc/%d/status %s", pid_num, START_FILE);
int cmd_status = system(cmdbuf);
// verify
snprintf(cmdbuf, sizeof(cmdbuf), "sudo cp -f /proc/%d/status %s", pid_num, END_FILE);
cmd_status = system(cmdbuf);
// verify
use -f command option to replace target file if it already exists.
Also, you need to run this program with an user with sudo privileges; which is inviting trouble. If process status file is available for every user for reading, check if you can drop sudo from command.
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?
I'm writing a shell in C. The shell has internal and external commands. The external commands can be extended with an ampersand (&) so they run in the background.
When I type e.g program&, the program executes with no problem in the background, making the shell available while the program is executing.
But, the output of the program can get mixed with the normal output of the shell. And that's what I'm trying to fix, with no success.
Note: In the example above I talked about program as any other command. The program basically sleeps and then prints "Hello, World!". Also, "program" is in /bin/, which is my default directory of external commands.
sish> pwd
[current directory]
sish> program&
sish> [now if I don't type anything...] Hello, World!
[now the current command is being written here].
For example, in bash, this behavior is different, it seems that, if the user is "still" writing the command, the output of the background program is holding (or waiting), so the user can execute a program. Hence, not messing with the output.
I read a bit about signals, I tried to setup a signal handler that printed something on SIGCHLD but it also had the same behavior.
CODE:
while(1) {
int internal=0;
int background=0;
int redirect=0; // 1 - output ; 2 - input
// those variables are not important for the question
printf("sish> ");
fgets(command,BUFFER_SIZE,stdin);
}
... (some lines that are not important for the question)
child = fork(); // pid_t child -> global variable
if(!child) {
if(redirect==1) {
int fd = open(words[2],O_WRONLY|O_CREAT|O_TRUNC,0660);
dup2(fd,1);
execlp(words[0],words[0],NULL);
}
else if(redirect==2) {
int fd = open(words[2],O_RDWR);
dup2(fd,0);
execlp(words[0],words[0],NULL);
}
else {
if(execvp(bin_path,words)==-1) {
printf("Error! Does the program exist?\n");
}
}
}
NOTES:
- I KNOW I'M NOT CHECKING FOR ERRORS IN THE FORK, I WILL ADD THAT WHEN I SOLVE THIS BUG.
- I ALSO PRINTED THE STDERR WITH perror, I GOT NOTHING.
I expect this (e.g):
sish> pwd
[current directory]
sish> program&
sish> [I wait...] pwd
[current directory]
Hello, World!
gcc version 5.3.0 20151204 (Ubuntu 5.3.0-3ubuntu1~14.04)
I read this and and I find this line:
int exit_status = system("gnome-terminal");
so when I add it to my code it only open a new terminal window (well that's what he was asking for) but my program runs in the old one.
is there any way to run my program in a new terminal window.
and also when the program finish executing, the terminal window get closed like I typed the exit command
system("gnome-terminal"); will run the given command, wait for it to exit, and then continue with your program. That's why your program continues to run in the current terminal window.
Rather than trying to do this in C, it probably makes more sense to write a shell script wrapper for your program, and use that script to launch your program in a new terminal window:
#!/bin/bash
gnome-terminal -e ./your-program-name your program arguments
Make the script executable (chmod +x script-name), and then you can run it just like you would a C program. You can even have it forward the arguments from the script to your actual program:
#!/bin/bash
gnome-terminal -e ./your-program-name "$#"
Note that rather than using gnome-terminal (which assumes the user has gnome installed), you can use the more neutral x-terminal-emulator command instead (see How can I make a script that opens terminal windows and executes commands in them?).
If you really want to do this from your C program, then I'd recommend doing something like this:
#include <stdio.h>
#include <stdlib.h>
char cmd[1024];
int main(int argc, char *argv[]){
// re-launch in new window, if needed
char *new_window_val = getenv("IN_NEW_WINDOW");
const char *user_arg = argc < 2 ? "" : argv[1];
if (!new_window_val || new_window_val[0] != '1') {
snprintf(cmd, sizeof(cmd), "gnome-terminal -e IN_NEW_WINDOW=1 %s %s", argv[0], user_arg);
printf("RELAUNCH! %s\n", cmd);
return system(cmd);
}
// do normal stuff
printf("User text: %s\n", argv[1]);
return 0;
}
Using an environment variable (IN_NEW_WINDOW in this case) to check if you've already launched in a new window should make it so that the new window only opens once. Note that the above code assumes a program with only one argument.
However, I still think using the wrapper script is a better solution.
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