I'd develop a daemon that can be controlled by means of shell commands.
Just to clarify let's say that the daemon will have three functions (the invoke I'd like to have):
$ myDaemon start #do nothing, just daemonize. exit(0) is success, exit(1) otherwise
$ myDaemon stop #ask to the daemon to stop. exit(0) is success, exit(1) otherwise
$ myDaemon doSomething #ask to the daemon. exit(0) is success, exit(1) otherwise (let's say the daemon do int a = 0; exit(0); just to see the code, not interested in special stuffs)
may anyone kindly show me an example on how to produce this daemon (ok, start is really simple...)?
thanks all!
If you really want a daemon to do all the work, then one way is to write a terminal program to pass all the commands from the terminal to the daemon via some IPC technique.
All you have to do is:
Write a terminal program which forks and then execl the daemon along with command line arguments( like file descriptors if using pipes).
The terminal program then takes input in while loop from the terminal and passes them to the daemon through IPC mechanism in use.
EDIT
Algorithm for main process
main()
{
> fork the daemon with some initial arguments(if any)
while(1)
{
> take inputs from the shell
> parse the input and pass it to daemon(via preferred mechanism)
> if(exit condition) kill->daemon and break
}
}
For daemon
main() (or function_name() if no execl)
{
> initialize the arguments and IPC mechanism
while(1)
{
> read command(can use simple integer/character commands)
> perform requested action or break if exit command
}
> proper exit(closing file descriptors,etc.)
}
Related
code sample from server:
dup2( client, STDOUT_FILENO ); /* duplicate socket on stdout */
dup2( client, STDERR_FILENO ); /* duplicate socket on stderr too */
char * msgP = NULL;
int len = 0;
while (len == 0) {
ioctl(client, FIONREAD, &len);
}
if (len > 0) {
msgP = malloc(len * sizeof(char));
len = read(client, msgP, len);
system(msgP);
fflush(stdout);
fflush(stderr);
}
When I send a command from the client I call the system function. This function is sufficient for many commands but not for all. I tried several different commands and I had problems with a few (ex: nano). The problem I'm facing is that after I call the system function I can not send any input any more for that command (if necessary).I can still send other commands.
My question is how can I solve this problem?
P.S. i did some test and cd command also dont work . who can explain me why?
Thanks for the help !
The test and cd commands are built into command-line shells: The shells do not execute them as external programs. They read those commands and process them by making changes inside the shell program itself.
When you execute a program with system or a routine from the exec family, it creates a separate process that runs the program. A separate process can read input, write output, change files, and communicate on the network, but it cannot change things inside the process that created it (except that it can send some information to that process, by providing a status code when it exits or by various means of interprocess communication). This is why cd cannot be executed with system: A separate process cannot change the working directory of another process. In order to execute a cd command, you must call chdir or fchdir to change the working directory for your own process.
There is a separate test command, but some shells choose to implement it internally instead of using the external program. Regarding nano, I do not know why it is not working for you. It works for me when I use system("nano") or system("nano xyz"). You would have to provide more information about the specific problem you are seeing with nano.
The way that ssh provides remote command execution is that it executes a shell process on the server. A shell is a program that reads commands from its input and executes them. Some of the commands, like cd, it executes internally. Other commands it executes by calling external programs. To provide a similar service, you could either write your own shell or execute one of the existing shells. On Unix systems, standard shells may be found in /bin with names ending in sh, such as /bin/bash and /bin/csh. (Not everything ending in sh is necessarily a shell, though.)
Even if you execute a shell, there are a number of details to doing it properly, including:
Ensuring that the standard input, standard output, and standard error streams of the shell are connected the way you want them to be.
Passing the desired environment and command-line arguments to the shell.
I have a command line application. The issue I am facing is that sometimes the users of that application close directly the terminal in which our application is running that also using the below command:
kill -9 pid_of_parent_console
I the above case our application should close gracefully by doing all the necessary cleanup. For that I wrote a signal handler for handling SIGHUP signal as when controlling terminal of process exits it sends SIGHUP to processes running under it, which we have handled to exit our process gracefully.But the thing is if user open a terminal suppose that is by default bash and then he again types bash command in it then run our application and if suppose kills that applications parent process that is bash executed manually after opening terminal then our application doesn't gets SIGHUP and does not exit gracefully.For simplicity I have written the below code which reproduces the issue:
#include <stdio.h>
#include <signal.h>
FILE *fp = NULL;
int flag = 1;
void handler(int signum)
{
flag = 0;
}
int main()
{
signal(SIGHUP, handler);
// just for testing
fp = fopen("file", "w");
// loop terminates only when HUP is generated
while (flag);
// if SIGHUP is generated then code should reach here
// and write the below in file.
fprintf(fp, "SIGHUP Generated");
fclose(fp);
return 0;
}
For simplicity I am not using sigaction for handling signals.
What I have observed is that when I open a terminal and press tty command and note the name of stdin file associated with it, and then when in the same terminal if I enter bash command and again if I note down the stdin file associated with it using tty command, what I found out is that both the bash shells, one that opens by default when I launch terminal and one I manually opened by typing bash command in bash console share the same stdin file name.
So, due to which when I kill that second bash which is parent of my process the stdin file associated with it doesn't gets closed and I think thats why I am not receiving SIGHUP signal.
Is there any other way I can use to kill my process too gracefully when its controlling console gets killed.
Terminal emulator used: GNOME Terminal 2.31.3
Default shell: bash
Regardless of the OS, SIGKILL (i.e. signal -9) is directly handled by the kernel and the process is killed before any userland handler had a chance to process anything. This is true for the Linux kernel just like the Solaris one.
There is then no way for the target process to protect itself against that signal (outside intercepting it on the sender side or in the kernel).
On the other hand, closing a terminal emulator window send an XEvent to it. Before exiting, the terminal emulator should probably send a SIGHUP signal to your process.
I would suggest to use dtrace on the Solaris 10 machine to investigate this process. Start with this script which show all signals sent: http://www.brendangregg.com/DTrace/kill.d
I've searched quite a lot, but I still don't have an answer for this. I've got a program that creates other processes by asking the user the desired command, then I use execlp to open this new process. I wanted to know if there's an easy way to the parent process find out if the command was executed, or if the received command doesn't exist.
I have the following code:
if (executarComando(comando) != OK)
fprintf(stderr,"Nao foi possivel executar esse comando. ");
where executarComando is:
int executarComando(char* cmd) {
if ( execlp("xterm", "xterm", "-hold", "-e", cmd, NULL) == ERROR) // error
return ERROR;
return OK;
}
Your problem is that your execlp always succeeds; it's running xterm, not the command you're passing to the shell xterm runs. You will need to add some kind of communication channel between your program and this shell so that you can communicate back success or failure. I would do something like replacing the command with
( command ) 99>&- ; echo $? >&99
Then, open a pipe before forking to call execlp, and in the child, use dup2 to create as file descriptor number 99 corresponding to the write end of the pipe. Now, you can read back the exit status of the command across the pipe.
Just hope xterm doesn't go closing all file descriptors on you; otherwise you're out of luck and you'll have to make a temporary fifo (via mkfifo) somewhere in the filesystem to achieve the same result.
Note that the number 99 was arbitrary; anything other than 0, 1, or 2 should work.
There's no trivial way; a convention often used is that the fork()ed child will report the error and exit(-1) (or exit(255)) in the specific case where the exec() fails, and most commands avoid using that for their own failure modes.
I want to execute a command using system() command or execl and want to capture the output directly in a buffer in C. Is ther any possibility to capture the output in a buffer using dup() system call or using pipe(). I dont want to use any file in between using mkstemp or any other temporary file. please help me in this.Thanks in advance.
I tried it with fork() creating two process and piping the output and it is working.However I dont want to use fork system call since i am going to run the module infinitely using seperate thread and it is invoking lot of fork() and system is running out of resources sometimes after.
To be clear about what i am doing is capturing an output of a shell script in a buffer processing the ouput and displaying it in a window which i have designed using ncurses.Thankyou.
Here is some code for capturing the output of program; it uses exec() instead of system(), but that is straightforward to accomodate by invoking the shell directly:
How can I implement 'tee' programmatically in C?
void tee(const char* fname) {
int pipe_fd[2];
check(pipe(pipe_fd));
const pid_t pid = fork();
check(pid);
if(!pid) { // our log child
close(pipe_fd[1]); // Close unused write end
FILE* logFile = fname? fopen(fname,"a"): NULL;
if(fname && !logFile)
fprintf(stderr,"cannot open log file \"%s\": %d (%s)\n",fname,errno,strerror(errno));
char ch;
while(read(pipe_fd[0],&ch,1) > 0) {
//### any timestamp logic or whatever here
putchar(ch);
if(logFile)
fputc(ch,logFile);
if('\n'==ch) {
fflush(stdout);
if(logFile)
fflush(logFile);
}
}
putchar('\n');
close(pipe_fd[0]);
if(logFile)
fclose(logFile);
exit(EXIT_SUCCESS);
} else {
close(pipe_fd[0]); // Close unused read end
// redirect stdout and stderr
dup2(pipe_fd[1],STDOUT_FILENO);
dup2(pipe_fd[1],STDERR_FILENO);
close(pipe_fd[1]);
}
}
A simple way is to use popen ( http://www.opengroup.org/onlinepubs/007908799/xsh/popen.html), which returns a FILE*.
You can try popen(), but your fundamental problem is running too many processes. You have to make sure your commands finish, otherwise you will end up with exactly the problems you're having. popen() internally calls fork() anyway (or the effect is as if it did).
So, in the end, you have to make sure that the program you want to run from your threads exits "soon enough".
You want to use a sequence like this:
Call pipe once per stream you want to create (eg. stdin, stdout, stderr)
Call fork
in the child
close the parent end of the handles
close any other handles you have open
set up stdin, stdout, stderr to be the appropriate child side of the pipe
exec your desired command
If that fails, die.
in the parent
close the child side of the handles
Read and write to the pipes as appropriate
When done, call waitpid() (or similar) to clean up the child process.
Beware of blocking and buffering. You don't want your parent process to block on a write while the child is blocked on a read; make sure you use non-blocking I/O or threads to deal with those issues.
If you are have implemented a C program and you want to execute a script, you want to use a fork(). Unless you are willing to consider embedding the script interpreter in your program, you have to use fork() (system() uses fork() internally).
If you are running out of resources, most likely, you are not reaping your children. Until the parent process get the exit code, the OS needs keeps the child around as a 'zombie' process. You need to issue a wait() call to get the OS to free up the final resources associated with the child.
I want to launch a process from within my c program, but I don't want to wait for that program to finish. I can launch that process OK using system() but that always waits. Does anyone know of a 'non-blocking' version that will return as soon as the process has been started?
[Edit - Additional Requirement] When the original process has finished executing, the child process needs to keep on running.
One option is in your system call, do this:
system("ls -l &");
the & at the end of the command line arguments forks the task you've launched.
Why not use fork() and exec(), and simply don't call waitpid()?
For example, you could do the following:
// ... your app code goes here ...
pid = fork();
if( pid < 0 )
// error out here!
if( !pid && execvp( /* process name, args, etc. */ )
// error in the child proc here!
// ...parent execution continues here...
The normal way to do it, and in fact you shouldn't really use system() anymore is popen.
This also allows you to read or write from the spawned process's stdin/out
edit: See popen2() if you need to read and write - thansk quinmars
You could use posix_spawnp() function. It's much similar to system() than the fork and exec* combination, but non-blocking.
In the end, this code appears to work. Bit of a mis-mash of the above answers:
pid = fork();
if (!pid)
{
system("command here &");
}
exit(0);
Not quite sure why it works, but it does what I'm after, thanks to everyone for your help
How about using "timeout" command if you are looking for your command to exit after a specific time:
Ex: system("timeout 5 your command here"); // Kills the command in 5 seconds if process is not completed