Ptrace/wait on a non child - c

int Enable ( int pid)
{
int status;
#if 1
{
printf ( "child pid = %d \n", pid );
long ret = ptrace (PTRACE_ATTACH, pid, NULL, NULL);
do {
int w = waitpid(-1, &status, 0);
if (w == -1) {
perror("waitpid error :");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
#endif
// while ((result = wait(&status)) != -1 && result != pid){ printf (" this is not my child go back \n"); };
}
int main(int arg, char*argv[])
{
Enable(atoi(argv[1]));
sleep(125);
}
-- I ran a daemon with pid 6841 and tried to wait on it after ptrace-attach
./ptrace 6841
child pid = 6841
waitpid error :: No child processes
In short I want to be able to wait on a non-child process - any other program welcome.

oops. not working if Iam not root :)
This is documented behavior; see ptrace() - Unix, Linux System Call e. g.
non-root processes cannot trace processes that they cannot send
signals to

if(ret == 0)
{
//child process
}
else
{
//parent process
}

Related

Fork child process terminates with signal 0

I have a small function that should give me information about how a child process finished.
int debug_wait() {
int status;
wait(&status);
if (WIFSIGNALED(status)) {
int sig = WSTOPSIG(status);
printf("failed with signal %d (%s)\n", sig, strsignal(sig));
return 1;
}
else if (!WIFEXITED(status)) {
printf("ended in an unexpected way\n");
return 1;
}
return 0;
}
But I get the following result:
double free or corruption (out)
tests failed with signal 0 (Unknown signal 0)
I know I should fix my code, but why do I get signal no. 0? Is there a mistake in my function or does it have an other meaning?
Since people asked, here is a example program:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int debug_wait() {
int status;
wait(&status);
if (WIFSIGNALED(status)) {
int sig = WSTOPSIG(status);
printf("tests failed with signal %d (%s)\n", sig, strsignal(sig));
return 1;
}
else if (!WIFEXITED(status)) {
printf("tests ended in an unexpected way\n");
return 1;
}
return 0;
}
int main() {
void* ptr = malloc(10);
pid_t pid = fork();
if (pid == 0) {
free(ptr);
free(ptr);
}
else {
debug_wait();
}
}
You are decoding the wrong thing. If WIFSIGNALED is true you can use WTERMSIG and WCOREDUMP (check #ifdef WCOREDUMP first). To decude the WSTOPSIG then WIFSTOPPED must be true.
Example:
int status;
pid_t pid = wait(&status);
if (pid == -1) return 1;
if (WIFEXITED(status)) {
printf("normal exit %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("termsig %d core dump=%c\n", WTERMSIG(status),
WCOREDUMP(status) ? 'Y' : 'N');
} else if (WIFSTOPPED(status)) {
printf("stop %d cont=%c\n", WSTOPSIG(status),
WIFCONTINUED(status) ? 'Y' : 'N');
}
Without using the feature test macros:
if (WIFEXITED(status)) {
printf("normal exit %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("termsig %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stop %d\n", WSTOPSIG(status));
}

Why will signal TSTP received by sigchld_handler instead of sigtstp_handler?

This is my own shell program.
The TSTP signal is sent by this part of main function, this c file will be ran as a program in the shell.
When the c program runs, it's in a forked child process, when it sends TSTP to itself, the expectation is that the signal should be received by tstp-handler (the printf should be showing up) and then the child process stopped.
However, it's the child-handler that received a signal(17), i.e the printf in sigchld_handler was called without printf in sigtstp_handler being called first. It's the parent process that gets received the sigchld signal, how can I make the child process itself receive the TSTP signal?
All handlers registered correctly as CTRL+Z will invoke the tstp-handler correctly.
Can anyone please help me with this part? Very much appreciate it.
If you need all the source code, please find it here
// the program sending the signal
int main(int argc, char **argv)
{
int i, secs;
pid_t pid;
if (argc != 2) {
fprintf(stderr, "Usage: %s <n>\n", argv[0]);
exit(0);
}
secs = atoi(argv[1]);
for (i=0; i < secs; i++)
sleep(1);
pid = getpid();
// printf("main process id: %d\n", pid);
if (kill(-pid, SIGTSTP) < 0)
fprintf(stderr, "kill (tstp) error");
exit(0);
}
void eval(char *cmdline){
char *argv[MAXARGS];
char buf[MAXLINE];
strcpy(buf, cmdline);
int bg = parseline(buf, argv);
if(argv[0] == NULL) return;
if(builtin_cmd(argv)){
return;
}
/* not built-in commands */
pid_t cpid;
sigset_t mask, prev_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &prev_mask);
cpid = fork();
if(cpid == 0){ // child
setpgid(0, 0);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
Execve(argv[0], argv, environ);
}else{
addjob(jobs, cpid, (bg? BG: FG), cmdline);
sigprocmask(SIG_SETMASK, &prev_mask, NULL);
if(bg){
printf("[%d] (%d) %s", pid2jid(cpid), cpid, cmdline);
/* when bg job is done, how is the child process reaped? => sigchld_handler will be triggered */
}else{
/* fg job, parent process blocked;
delete fg job after it's complete(in sigchld_handler)
*/
waitfg(cpid);
}
}
}
void sigtstp_handler(int sig){
//printf("=== in sigtstp_handler, sig: %d, from %d\n", sig, getpid());
pid_t foreground_pid = fgpid(jobs);
if(foreground_pid == 0) return;
struct job_t *fg_job = getjobpid(jobs, foreground_pid);
if(fg_job != NULL && fg_job->state == FG){
pid_t pgid = getpgid(fg_job->pid);
printf("Job [%d] (%d) stopped by signal %d\n", fg_job->jid, fg_job->pid, sig);
Kill(-pgid, SIGTSTP);
}
}
void sigchld_handler(int sig){
// printf("=== in sigchld_handler: %d\n", sig);
pid_t cpid;
int status;
if((cpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0){
if(WIFEXITED(status)){
// printf("in sigchld_handler, terminated cpid: %d\n", cpid);
deletejob(jobs, cpid);
}
if(WIFSTOPPED(status)){
struct job_t *stopped_job = getjobpid(jobs, cpid);
stopped_job->state = ST;
}
if(WIFSIGNALED(status)){
deletejob(jobs, cpid);
}
}
}

waitpid() hanging when foreground child process stopped SIGTSTP

I'm implementing a simple shell where a child process, with it's own PGID, is given terminal control.
Problem is, when I stop the child process with SIGTSTP (ctrl + z), the terminal just hangs and gets stuck in waitpid:
How do I get waitpid to stop hanging?
void wait_job() {
int status;
int corpse;
int wait_flags = WUNTRACED | WCONTINUED;
while ((corpse = waitpid(-1, &status, wait_flags)) > 0) {
if (WIFSTOPPED(status)) {
printf("child stopped, sign num = %d, corpse = %d\n", WSTOPSIG(status), corpse);
}
else if (WIFEXITED(status)) {
printf("child exited, sign num = %d, corpse = %d\n", status, corpse);
}
else if (WIFCONTINUED(status)) {
printf("child continued, sign num = %d, corpse = %d\n", status, corpse);
}
}
}
int main() {
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
char buffer[100];
char prompt[] = "Press enter: ";
while (1) {
write(STDOUT_FILENO, prompt, sizeof(prompt) - 1);
int n = read(STDIN_FILENO, buffer, 10);
buffer[n - 1] = '\0';
int pid;
if ((pid = fork()) == 0) { // Child
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
signal(SIGTTIN, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
setpgid(pid, pid);
tcsetpgrp(STDIN_FILENO, pid);
char* argv[] = { "sleep", "5", NULL };
execvp(argv[0], argv);
exit(0);
}
// Parent
setpgid(pid, pid);
tcsetpgrp(STDIN_FILENO, pid);
wait_job();
tcsetpgrp(STDIN_FILENO, getpgid(0));
}
}

Execvp doesn't return an error on an unknown command

I have the following code that forks a child and executes the command "a", which is an unknown command. However, execvp does not return an error and instead, "success" is printed. The same thing happens if I do "mv a b", when the file "a" does not exist. How should I capture and handle these errors?
int main ( int argc, char **argv ){
pid_t pid;
char *execArgs[] = { "a", NULL };
pid = fork();
// if fork fails
if (pid < 0){
exit(EXIT_FAILURE);
}
else if (pid == 0){
execvp(execArgs[0], execArgs);
if (errno == ENOENT)
_exit(-1);
_exit(-2);
}
else{
int status;
wait(&status);
if(!WIFEXITED(status)){
printf("error\n");
}
else{
printf("success\n");
}
}
}
The program exited; it just exited with a non-zero status. The primary opposite of WIFEXITED is WIFSIGNALED — see the POSIX specification for wait() and WIFSTOPPED and WIFCONTINUED for the other options.
Use:
int corpse = wait(&status);
if (corpse != -1 && WIFEXITED(status))
{
int estat = WEXITSTATUS(status);
char *err = (estat == 0) ? "success" : "failure";
printf("PID %d exited with status %d (%s)\n", corpse, estat, err);
}
else
printf("PID %d didn't exit; it was signalled\n", corpse);

creating a child and parent process

int main()
{
pid_t cpid, w;
int status;
CreateSocket(); // it recievs data from the client
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
CHECKTASKS(); //timer created for calling the task for every 2ms,10
} else {
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}
I created a child process and I am calling a CreateSocket(); // it recievs data from the client via the ip address and port number. I am calling this before creating a child process. If i do like that- will it be a parent process ?? I am calling a another function after creating a child process i.e CHECKTASKS(); //timer created for calling the task for every 2ms,10ms and 100ms// to run in the background . Is the CHECKTASKS will be running in the background as a separate process. Is it possible if I code like above in c for linux OS ??

Resources