Accessing system call from within a new created system call - c

I'm working on Minix 3.
I'm implementing a new system call called do_identify that returns either the id of the current process or the parent process. Here's the definition of the system call under /usr/src/servers/pm/misc.c and it's library, which I named it identifylib.h, under /usr/include:
Definition:
PUBLIC int do_identify()
{
int identifier = m_in.m1_i1;
if(identifier == 1)
{
printf("Current Process ID = %d\n", getpid());
return getpid();
}
else
{
printf("Parent Process ID = %d\n", getppid());
return getppid();
}
}
Library:
#include <lib.h>
#include <unistd.h>
PUBLIC int identify (int process)
{
message m;
m.m1_i1 = process;
return ( _syscall(PM_PROC_NR, IDENTIFY, &m) );
}
Now, when I test it, i get the following error:
undefined reference to getppid
Am I invoking incorrectly this function? or Am I not supposed to invoke this function within the system call? I don't know what it is supposed to mean on minix.
Here is the test file: test_id.c
#include <identifylib.h>
int main(void)
{
printf("Process ID = %d\n" identify(1));
return 0;
}

Related

How to send a kill signal to multiple child processes in case of failure doing a task?

I'm trying to make a program that creates up to 4 child processes. Each child will use a search function to find a certain word in a desired file:
bool search(char *file,char *word,int section)
P.S: You can ignore the search function and what does it exactly do as the main quest here is to send a signal to multiple child processes upon the success of a certain child process.
Each child process will search in a certain section of the file. i.e a file named "foo" that containts:
car
bar
tar
far
the child processes are looking for the string "bar".
If a child process succeeds in finding the string, it will exit with value 0(exit(0)), otherwise if it finished its whole section with no sucess of finding the string it will exit with value 1(exit(1)).
Once a child exists with value 0(succeded in finding the string). The parent will send a kill signal to the other child processes.
Consider the following code:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
pid_t p;
p=fork();
int i;
int storage[4];
for(i=0;i<4;i++)
{
p=fork();
if(p==0)
{
storage[i]=getpid();
open("testfile.txt",O_WRONLY);
if(search("testfile.txt","bar",i))
{
storage[i]=1;
//exit(0);
}
else
//exit(1);
}
}
for(i=0;i<4;i++)
{
if(storage[i]!=1)
kill(stroage[i],SIGTERM);
}
}
What I did in this code is using an array of 4 integers, it contains the ids of the child processes. The case of the child that succeded is changed to 1. Afterwards I sent a kill signal to the other processes except for that specific process.
Is the code I wrote correct? If so How do I use the exit values to send the signal without using the array?
You can run a unix command to get the list of child process IDs using cmd() if you don't want to use the arrays.
Also fork() returns the child process ID to the parent. The parent can store it in the array.
You could try to store the child's pids in the array in shared memory, to do that you probably should create separate .h file with the following content.
struct shared_arr {
int is_full;
int pids_arr[4];
};
You could access that shared structure using the following snippet:
int shm_id = shmget((key_t) 12345, sizeof(struct shared_arr), 0666| IPC_CREAT);
//get the shared data
struct shared_arr *shared_data;
void* shared_memory = (void*) 0;
shared_memory = shmat(shm_id, (void*)0,0);
if(shared_memory == (void *) -1) {
fprintf(stderr, "shmat FAILED\n");
}
shared_data = (struct shared_arr *) shared_memory;
//init shared data with zeros
for(int i = 0; i < MAX_SHARED_ARR_SIZE; i++) {
shared_data->pids_arr[i] = 0;
}
details: https://en.wikipedia.org/wiki/Shared_memory#Support_on_Unix-like_systems
Also, consider setting process group id and send a signal to all processes in the same process group, using just one kill call.
details about set group id: https://www.systutorials.com/docs/linux/man/2-setpgid/
about kill: http://man7.org/linux/man-pages/man2/kill.2.html
Your last approach (in the comment) is better, but still has bugs.
For one, the wait is outside of the loop (it's executed only once)
and the exitstatus variable is undefined in the first iteration - it's assigned only when control reaches the while(...).
I propose something similar to this:
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t p, pids[4];
// Why did you want to fork here?
int i;
int finder = 1; // Which process can find 'bar'
int status;
char signal_name[256];
printf("[Parent] pid=%d\n", getpid());
for (i=0; i<4; i++) {
p=fork(); // fork makes a new process, for a new thread use clone
if (p==0) {
printf("[Child %d] ppid=%d, pid=%d\n", i, getppid(), getpid());
usleep(((random() % 1000) + 500) * 1000); /* microseconds */
printf("[Child %d] %s\n", i, finder==i ? "found" : "not found");
if (finder==i) /* the pseudosearch result */
exit(0);
else
exit(1);
} else {
pids[i] = p;
printf("[Parent] childpid=%d\n", p);
}
}
while (pids[0]>0 || pids[1]>0 || pids[2]>0 || pids[3]>0) {
printf("[Parent] something happened\n");
p = wait(&status);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
printf("[Parent] child with pid=%d exited with code 0\n", p);
for (i=0; i<4; i++)
if (pids[i] > 0 && pids[i] != p) {
printf("[Parent] killing child %d (with pid=%d)\n", i, pids[i]);
kill(pids[i], SIGTERM);
}
break;
} else if (WIFEXITED(status) || WIFSIGNALED(status)) {
if (WIFEXITED(status))
printf("[Parent] child with pid=%d exited with code %d\n", p, WEXITSTATUS(status));
else {
dprintf(2, "[Parent] child with pid=%d was terminated by signal %d: ", p, WTERMSIG(status));
psignal(WTERMSIG(status), "");
}
for (i=0; i<4; i++)
if (pids[i] == p)
pids[i] = 0;
}
}
}
Example output:
[Parent] pid=28375
[Parent] childpid=28376
[Parent] childpid=28377
[Child 0] ppid=28375, pid=28376
[Parent] childpid=28378
[Child 1] ppid=28375, pid=28377
[Parent] childpid=28379
[Parent] event received
[Child 2] ppid=28375, pid=28378
[Child 3] ppid=28375, pid=28379
[Child 0] not found
[Child 1] found
[Parent] child with pid=28376 exited with code 1
[Child 2] not found
[Parent] event received
[Parent] child with pid=28377 exited with code 0
[Parent] killing child 2 (with pid=28378)
[Parent] killing child 3 (with pid=28379)

Adding print parent process ID system call to Minix

This is is the program to Print Process ID and Parent Process ID's in C using Minix. I'm trying to compile the test code below this code to return the ID's but it isn't compiling. Any help would be appreciated.
//Program to print its Process ID, Parent Process ID
#include <stdio.h>
#include "pm.h" // for various global variables
#include "mproc.h" // for process table mproc
int do_printppids(void)
{
int idx = m_in.m1_i1;
int n = m_in.m1_i2;
while(n > 0 )
{
int pid = mproc[idx].mp_pid;
if(pid)
{
int parent = mproc[mproc[idx].mp_parent].mp_pid;
printf("proc: %sn", mproc[idx].mp_name);
printf("Pid: %d, PPid %dn", pid, parent);
n++;
}
else
{
n = 0;
}
idx++;
}
return 1;
}
This is my test class to try and return the Process ID and Parent Process IDs, but it isn't compiling in Minix.
#include <lib.h> // provides _syscall and message
#include <stdio.h>
#include <stdlib.h> // provides atoi
int main(void) {
message m; // Minix uses message to pass parameters to a system call
m_in.m1_i1 = 0;
m_in.m1_i2 = 10;
_syscall(PM_PROC_NR, PRINTPPIDS, &m);
}
Literally make sure to update and save all files before running Make Service + Install and then recompile the test class. Spent 4 hours staring pointlessly at my code because of it sigh

C Programming - Scanf not working in ubuntu

I am writing a C program in Ubuntu 10 to create processes, display process ID and to kill process. I'm using kill() command to kill a process ID that user entered via scanf. However, the scanf is not working at all. I tried to add "space" before %d but nothing happened. Appreciate if anyone can help!
Following are my codes:
include <stdio.h>
include <unistd.h>
include <signal.h>
include <sys/types.h>
include <stdlib.h>
main ()
{
int x;
int pid[10]; // to store fork return value
int p[10]; // to store process ID
// Create 5 new processes and store its process ID
for (x=1;x<=5;x++)
{
if ((pid[x]=fork())==0)
{
p[x]=getpid();
printf("\n I am process: %d, my process ID: %d\n",x,p[x]); // Display process number and PID
}
else
exit(0);
}
{
int y;
y=p[x];
printf("Please enter a process ID to kill: ");
scanf(" %d", &y); //waiting for user input
printf("\nThe process %d is killed.\n",y);
kill(y,9); //Values 9 represents SIGKILL
}
}
Your parent process exits, and so does every process you spawn afterwards (their return value of fork is different than 1 so they exit). If a process has no parent it becomes an "orphan" and has special handling by the OS (some other process adopts it). Are you sure this is the behavior you were looking for?
EDIT:
This is probably what you meant to write:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
int main ()
{
int x;
int pid[10]; // to store fork return value
pid_t parent = getpid();
// Create 5 new processes and store its process ID
for (x=1;x<=5;x++)
{
if ((pid[x]=fork())!=0)
{
printf("\n I spawned process: %d, its process ID: %d\n",x,pid[x]); // Display process number and PID
}else{
while(1){}
}
}
if(getpid() == parent){
int y;
y=pid[x];
printf("Please enter a process ID to kill: ");
scanf(" %d", &y); //waiting for user input
printf("\nThe process %d is killed.\n",y);
kill(y,9); //Values 9 represents SIGKILL
}else{
printf("THIS SHOULD NOT HAPPEN!");
}
return 0;
}
fork returns twice, each time in a different process. One very important thing to realize about the two processes is that they do not share memory. That means that by calling getpid in the child and saving that in an array you are unable to see that value in the parent's copy of the variable.
What you most likely want to do is something like:
for (...) {
if ((pid[x]=fork()) == 0) {
printf("child created, pid = %d\n", getpid());
while(1) sleep(1000); /* children will never run outside this loop */
} else {
continue;
}
}
/* this code only runs in the parent */

Grabbing the return value from execv()

//code for foo (run executable as ./a.out)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
int main (int argc, char **argv) {
pid_t pid;
pid = fork();
int i = 1;
char *parms[] = {"test2", "5", NULL}; //test executable named test2
if(pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
else if(pid == 0) {
printf("Child pid is %d\n", pid);
i = execv("test2", parms); //exec call to test with a param of 5
}
else {
wait(NULL);
}
printf("I is now %d\n", i); //i is still 1 here, why?
return 0;
}
Hey everybody, I am trying to learn a little bit about fork and execv() calls. I make my foo.c program above make a call to a file I have named test.c. I fork a child and have the child make a call to execv, which will just add 10 to the parameter read in. I am unsure of why the variable does not change, at the bottom of my foo.c function. Does the call need to be a pointer or return an address? Any help would be greatly appreciated. Thanks
Code for test.c (executable named test2)
#include <stdio.h>
int main(int argc, char ** argv[]) {
int i = atoi(argv[1]);
i = i +10;
printf("I in test is %d\n", i);
return i;
}
You only call execv() in the child process. The exec() family functions never return if it runs successfully. See evec(3):
The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
You printed the value of i in the parent process, it never changed in the parent process.
To get the exit status from the child process, you can make use of wait() or waitpid():
else {
int waitstatus;
wait(&waitstatus);
i = WEXITSTATUS(waitstatus);
}

Forking two processes results in multiple processes

I wish to design a function called from main that will fork off any process to sleep and then update the "process array" containing all forked pids and a counter of them. It seems to work, only there's other processes being forked as well (here with pid -1 and 11957) that I'm not sure where comes from. The test run gives:
Parent 11954 forks off children..
Children started: 2
Proc 11955 started
Proc 11956 started
Children started: 1
Child -1 terminated with status 0
Children started: 1
Proc 11957 started
Children started: 0
Child 11957 terminated with status 0
Child 11955 terminated with status 0
Child 11956 terminated with status 0
The code:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#define MAXPROC 100
void fork_off(int * proc_t, int * proc_i) {
int f = fork();
if (f == 0) {
fprintf(stderr, "Proc %d started\n", getpid());
usleep(5000000);
} else {
proc_t[*proc_i] = f;
(*proc_i)++;
}
}
int main(void) {
int proc_table[MAXPROC], proc_index, status, i;
proc_index = status = i = 0;
printf("Parent %d forks off children..\n", getpid());
fork_off(proc_table, &proc_index);
fork_off(proc_table, &proc_index);
printf("Children started: %d\n", proc_index);
for (i = 0; i < proc_index; i++) {
printf("Child %d terminated with status %d\n",
waitpid(proc_table[i], &status, 0), status);
}
return 0;
}
I wish only to fork off two processes, not more. What's causing this behaviour?
The problem with your code is that after the child processes have slept, they return from fork_off and repeat everything the parent is doing.
void fork_off(int * proc_t, int * proc_i) {
int f = fork();
if (f == 0) {
fprintf(stderr, "Proc %d started\n", getpid());
usleep(5000000);
exit (0); /* exit() closes the entire child process
* instead of simply return from the function
*/
} else if (f > 0) { /* Make sure there isn't an error being returned.
* Even though I've never seen it happen with fork(2),
* it's a good habit to get into
*/
proc_t[*proc_i] = f;
(*proc_i)++;
} else { /* Adding to the aforementioned point, consider changing
* the return type to int - so that you can return -1
* and check for error.
*/
}
}

Resources