I'm presently executing the following Linux command in one of my c programs to display processes that are running. Is there anyway I can modify it to show stopped processes and running ones?
char *const parmList[] = {"ps","-o","pid,ppid,time","-g","-r",groupProcessID,NULL};
execvp("/bin/ps", parmList);
jobs -s list stopped process by SIGTSTP (20), no SIGSTOP (19). The main difference is that SIGSTOP cannot be ignored. More info with help jobs.
You can SIGTSTP a process with ^Z or from other shell with kill -TSTP PROC_PID (or with pkill, see below), and then list them with jobs.
But what about listing PIDs who had received SIGSTOP? One way to get this is
ps -A -o stat,command,pid | grep '^T '
From man ps:
-A Select all processes. Identical to -e.
T stopped by job control signal
I found very useful this two to stop/cont for a while some process (usually the browser):
kill -STOP $(pgrep procName)
kill -CONT $(pgrep procName)
Or with pkill or killall:
pkill -STOP procName
pkill -CONT procName
Credit to #pablo-bianchi, he gave me the oompff (starting point) to find SIGSTOP'd and SIGTSTP'd processes, however his answers are not completely correct.
Pablo's command should use T rather than S
$ ps -e -o stat,command,pid | grep '^T '
T /bin/rm -r 2021-07-23_22-00 1277441
T pyt 999 1290977
$ ps -e -o stat,command,pid | grep '^S ' | wc -l
153
$
From man ps:
PROCESS STATE CODES
Here are the different values that the s, stat and state output specifiers (header "STAT"
or "S") will display to describe the state of a process:
D uninterruptible sleep (usually IO)
I Idle kernel thread
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped by job control signal
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent
WRT pgrep, it is a real grep, the argument is NOT a program name; rather, it is a regular expression applied to the first item in /proc//cmdline (usually the name from the executing commandline (or execve()).
Therefore if you are trying to kill pyt, you would accidentally also kill all the python programs that are running:
$ pgrep -a pyt
7228 python3 /home/wwalker/bin/i3-alt-tab-ww --debug
1290977 pyt 999
You need to "anchor" the regular expression:
$ pgrep -a '^pyt$'
1290977 pyt 999
ps -e lists all processes.
jobs list all processes currently stopped or in background.
So, you can run jobs command using execvp:
char *arg = {"jobs", NULL};
execvp(arg[0], arg);
Related
How do you kill a running process in a bash script without killing the script?
Goal
So... I need to kill a running process to continue with the execution of my script.
Here´s a stripped down version of my script:
# Setup
echo "Use ctrl+C to stop gathering data..."
./logger
#------------------
echo "Rest..."
I need to be able to kill ./logger without killing my script
Expected vs Actual Results
I was expecting a result like this:
Use ctrl+C to stop gathering data...
^C
Rest...
but it stops when I kill the program
use ctrl+C to stop gathering data...
^C
The ./logger command is a C program that already handles the SIGINT signal (Ctrl + C) but it won't stop until it receives it.
Is there a way to stop the program without killing my script?
The C Program is not important but it looks something like this
#include <stdio.h>
#include <signal.h>
int flag = 1;
void handler(int i)
{
flag = 0;
}
int main(int argc, char** argv)
{
signal(SIGINT, handler);
while(flag)
{
usleep(10000);
}
}
If you type control-C at the terminal where the script is running, the signal goes to all the processes — the logger program and the script. And the script terminates because you've not told it to ignore signals while the logger is run. You can do that using the trap command but you'll need to undo the trapping before running the C program. See the Bash manual on Signals too.
For example, I have a program dribbler that generates messages, one every second by default, but it is configurable. I'm using it as a surrogate for your ./logger program. The -m options specifies the message; the -n option requests that the messages are numbered, and the -t option specifies output to standard output (instead of a file which it writes to by default).
#!/bin/bash
#
# SO 6418-0134
program="dribbler -t -n -m Hello"
echo "About to run '$program' command"
trap "" 2
(trap 2; $program)
echo "Continuing after '$program' exits"
sleep 1
echo "But not for long"
The sub-shell is necessary. When I run that script (trapper.sh), I get, for example:
$ bash trapper.sh
About to run 'dribbler -t -n -m Hello' command
0: Hello
1: Hello
2: Hello
3: Hello
^CContinuing after 'dribbler -t -n -m Hello' exits
But not for long
$
Incidentally, POSIX defines a command logger that writes messages using the syslog() function(s) to the syslog daemon.
It might also be worth reviewing the Q&A about Sending SIGINT to forked exec process which runs a script does not kill it, especially the accepted answer and its links to Q&A on other Stack Exchange sites, as it matters that you and I both executed a C program, not a shell script.
I'm working in C and using the following code to execute the ps linux command:
char *const parmList[] = {"ps","-o","pid","-g",processGroupID,NULL};
execvp(parmList[0], parmList);
The problem is that it prints all the processes from the group including ones that have been terminated. I need to make sure that the group processes that have NOT been terminated are the only ones shown. Is there a way to do this?
ps command display's the list of active processes of that current tty terminal.
ps - axrgo pid or ps -axro pid -g
ps has an simple process selection option.
-a -------> Select all processes except both session leaders and processes not associated with a terminal. i.e includes all active terminals
-e -------> Includes all processes.
-g -------> Select by session OR by effective group name.
-r -------> Restrict the selection to only running processes.
-x -------> option causes ps to list all processes owned by you (same EUID as ps), or to list all processes when used together with the a option.
Add the a x r options to get only running processes.
I am looking to run a program written in C on my machine and have it SSH into another machine to kill a program running on it.
Inside my program, I have attempted:
system("ssh username#machine.com && pkill sleep && exit");
which will cause my terminal to SSH into the remote machine, but it ends there. I have also tried:
execl("ssh","ssh","username#machine.com",NULL);
execl("pkill","pkill","sleep",NULL);
execl("exit","exit",NULL);
but it will not kill my dummy sleep process I have running.
I can't seem to figure out what is wrong with my process.
Your second example won't do what you want as it will execute each execl on the local machine. IE it will
Execute ssh usrname#machine.com
Execute pkill
Execute exit
But, actually, unless you are surrounding these by fork, the first execl if it succeeds in running at all will replace the current process, meaning the second and third ones never get called.
So, let's work out why the first (more hopeful) example doesn't work.
This should do the equivalent of:
/bin/sh -c 'ssh username#machine.com && pkill sleep && exit'
The && exit is superfluous. And you want the pkill to run on the remote machine. Therefore you want something that does:
/bin/sh -c 'ssh username#machine.com pkill sleep'
(note the absence of && so the pkill is run on the remote machine).
That means you want:
system("ssh username#machine.com pkill sleep");
If that doesn't work, check the command starting /bin/sh -c above works. Does ssh ask for a password, for instance? If so, it won't work. You will need to use a public key.
one can always run, over ssh, the command:
kill $(pgrep -o -f 'command optional other stuff')
Get your remote process to handle SIGTERM, where it can do its cleanup's. (including killing any processes its started)
Google 'man pgrep' to see what the -o and -f do. -f is important to correctly target the signal.
the 'pgrep' returns the pid with trailing \n but this does not need to be stripped off before passing it to 'kill'.
Yours
Allan
Assume I have a state machine started as root to run one and only one program in a given reserved vt. The first call I use something like:
execl("/usr/bin/openvt", "/usr/bin/openvt", "-c 12", "-f", "-- su auser /home/auser/sbin/ascript.sh", (char *) 0);
Is the only way to find the PID's of all of the children (The shell script, the calls, etc) to search ps aux for the PID's that are generated on that vt (tty12) and kill them, as fork only will hold the PID of the openvt command which pretty much dies after the new vt is open?
Or is there a slick way to send a SIGINT to a known vt (i.e., /dev/vcs12 dev/tty12)?
The -t tty option to ps may be what you are looking for...
kill -INT `ps -t vcs12 -o pid=`
or, in a sh/bash-specific way:
kill -INT $(ps -t vcs12 -o pid=)
I would like to know if my program is executed from a command line, or executed through system() call, or from a script.
I initially thought about getting parent id (getppid()), and looking up /proc/#pppid directory checking either the exe link or contents of the cmdline file. If it is /bin/bash, or /bin/csh, or /bin/sh I would know that it runs from the command line.
The problem is that it is not true, because a standalone script would also tell me /bin/bash.
Even if it worked, it could have been very specific Linux version approach and could stop working in a future.
Is there a better way to do that?
Thank you for any advice or pointing out to some direction.
Most shells written since 1980 support job control, which is implemented by assigning a process group to each process in a pipeline of commands. The process group is set by setpgrp(), which sets the process's pgrp to its pid.
The pgrp is inherited across forks.
So, if your shell is a relatively modern one, a program started by an interactive shell will have getpid() == getpgrp(), and any additional processes forked by that process (say, if it's a shell script or if it calls system()) will have getpid() != getpgrp().
Here's a test program, and its behavior under bash (it will behave the same under ksh93 and tcsh as well):
pp.c
#include <unistd.h>
#include <stdio.h>
main()
{
printf("pid=%d pgrp=%d\n", (int)getpid(), (int)getpgrp());
}
$ ./pp
pid=3164 pgrp=3164
$ ./pp &
[1] 3165
$ pid=3165 pgrp=3165
In a pipeline, the leftmost command is the process group leader. (This isn't documented, but bash, ksh93, and tcsh all do it this way).
$ ls|./pp
pid=3179 pgrp=3178
$ ./pp|cat
pid=3180 pgrp=3180
A program called with system() will have the same pgrp as its parent:
pps.c
#include <stdlib.h>
main()
{
system("./pp");
}
$ ./pps
pid=4610 pgrp=4608
In a shell script, the shell is the process group leader, and any command invoked by it will inherit the pgrp:
pp.sh
#!/bin/sh
./pp
$ ./pp.sh
pid=4501 pgrp=4500
But if the shell script execs a program, the pid doesn't change, and the execed program will be a process group leader, so you probably don't want to do that.
ppe.sh
#!/bin/sh
exec ./pp
$ ./ppe.sh
pid=4504 pgrp=4504
In the unlikely case that the user turns off job control, every command is going to have the same pgrp as the shell:
$ set +m
$ ./pp
pid=4521 pgrp=2990
$ ./pp
pid=4522 pgrp=2990
You can intercept signal from PID when the script is done and check "kill" for it.
Not sure if that solves your problem but environment variables can give you a good hint. For example:
$ set | grep "^_="
_=
$ bash -c "set" | grep "^_="
_=/bin/bash
$ sh -c "set" | grep "^_="
_='/bin/sh'