Problem with setbuf not working in multi-process - c

As in the following code,
I create a child process using fork function, remove the buffer of stdout, and create a race condition environment,
but the two processes do not compete.
System: Linux user1-ubuntu64 4.18.0-20-generic
Compiler: gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04)
Compile command: gcc -o test test.c
If give the parent process a very small delay(250ns), It work that I want.
The source code :
#include <stdio.h>
#include <sys/types.h>
static void printatime(char *);
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("fork error");
return -1;
}
else if (pid == 0)
{
printatime("AAAAAAAAAAAA");
}
else
{
printatime("BBBBBBBBBBBB");
}
return 0;
}
static void printatime(char *str)
{
char *ptr = str;
setbuf(stdout, NULL);
while (*ptr)
{
putc(*ptr++, stdout);
}
}
Expected results:
user#ubuntu64:~/C$ BAABBABABAABBAAABBABABAB
Actual results:
BBBBBBBBBBBBuser#ubuntu64:~/C$ AAAAAAAAAAAA

Related

Creating a simple shell

I'm trying to program a simple shell in C that can execute an executable by just entering the filename. I've tried writing my code which you will see below, but i keep getting the "NO such file or directory error. I'm new to C and I would really love someone to help.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
/**
* main - a super simple shell
*
* Return: always 0
*/
int main(void)
{
char *command[] = {"", NULL};
size_t len = 0;
int flag = 1;
pid_t child_process;
int status;
while (flag == 1)
{
printf("#fountain-shell$ ");
getline(&command[0], &len, stdin);
child_process = fork();
if (child_process == -1)
{
perror("Error:");
return (1);
}
if (child_process == 0)
{
if (execve(command[0], command, NULL) == -1)
{
perror("Error:");
}
}
else
{
wait(&status);
continue;
}
}
}
This is an example of what I'm trying to achieve.
#cisfun$ /bin/ls
env-environ.c exec fork mypid ppid printenv promptc shell wait
env-main.c exec.c fork.c pid.c ppid.c prompt prompt.c shell.c wait.c
#cisfun$ ./ppid
5451
#cisfun$ ./ppid
5451
#cisfun$ ^C

How to run commands through PTY?

I want to interact with the child process through PTY, the parent process code is as follows:
#include <pty.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t child_pid, current_pid;
char name[BUFSIZ], buffer[BUFSIZ];
int master;
current_pid = getpid();
fprintf(stdout, "pid: %u\n", current_pid);
child_pid = forkpty(&master, &name[0], NULL, NULL);
if (child_pid == -1) {
perror("forkpty faild.");
return EXIT_FAILURE;
} else if (child_pid == 0) {
execl("./child", "./child");
} else {
read(master, &buffer[0], BUFSIZ);
fprintf(stdout, "%u: child message:\n%s", current_pid, buffer);
}
return EXIT_FAILURE;
}
The subprocess code is as follows:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
fprintf(stdout, "%s\n", isatty(fileno(stdout)) ? "true": "false");
return EXIT_SUCCESS;
}
compile and execute:
$ gcc main.c -o main && gcc child.c -o child
$ ./main
Why must the parent process fork first, and then execute the instruction through execl to be effective?
Can't exchange data directly?
Why must the parent process fork first, and then execute the instruction through execl to be effective?
Because that's how fork and everything that wraps it up works. After a successful fork you have two processes that are virtually identical, except for the return value of fork and the process' PID.
To launch a different program, one process must replace its program image with a different one, which is what execl does.

My pid identifier not expected

So for school I got this exercise where I need to make a program that calculates if a number is a prime number or not. This program should make use of parent and child processes, and strtoul should be used to convert the argv to a unsigned long.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
void checkprime(unsigned long num);
int main(int argc, char *argv, char *env)
{
strtoul(argv, NULL, 0);
pid_t pid = fork();
if(pid == 0)
{
unsigned long number;
printf("\nGive number to check: \n");
scanf("%lu",&number);
checkprime(number);
}
else if(pid < 0)
{
perror("Fork Failed!");
}
else
{
int status = -1, result;
waitpid(pid, &status, 0);
result = WEXITSTATUS(status);
if(result == 1)
{
printf("this is a prime number\n");
}
else if(status < 0)
{
perror("Something Failed");
}
else
{
printf("this is not a prime number\n");
}
}
return 0;
}
void checkprime(unsigned long num)
{
int i;
for(i = 2; i < num; i++)
{
if(num % i == 0)
{
exit(0);
}
}
exit(1);
}
So when I try to compile this it says: line 13: identifier not expected. Error code 1.
The code on line 13 says: pid_t pid = fork();
Now my question is: Why do i get that error?
Its fixed, thanks everyone for the help. I appreciate it.
Some old versions of compilers accept C89 (not C99 or C11) as the default C dialect. You want C99 (since you have a declaration after a statement) at least.
If you use some old version of GCC on some old Linux distribution, try compiling with gcc -std=gnu99 -Wall -Wextra -g where -std=gnu99 sets the C dialect (you could also use -std=c99 or better), -Wall -Wextra asks for warnings, -g wants debug information (in DWARF, for the gdb debugger). Better yet, upgrade your GCC to a recent version (like GCC 7 in November 2017) whose default is C11 with GNU extensions.
Or put the declaration
pid_t pid= 0;
(I prefer to systematically initialize variables in C)
before the statements
strtoul(argv, NULL, 0); //useless call, you need to store the result
pid= fork();
The compiler is telling you it didn't expect to encounter an identifier pid_t at that line since the previous line wasn't an identifier. You need to declare your variables at the top of the scope, and put other code below that. You could either do this
int main(int argc, char *argv, char *env)
{
long int val=strtoul(argv, NULL, 0);
pid_t pid = fork();
...
or
int main(int argc, char *argv, char *env)
{
pid_t pid = fork();
strtoul(argv, NULL, 0);
...
But you're missing the value returned from strtol
You can use make shorter prime finder loop by changing, i < num to i < num/2.
This is one of standards for main() arguments:
(int argc, char **argv)
Turn on gcc flag: -Wall to see all warnings in code.
As #cleblanc said in one of answer, store return value of strtoul() to a varibale long int val = strtoul(argv[1], NULL, 0);.
we pass number for check, from command line arguments,
argv[1] refers to number when we run program with
./prime 15
Code
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void checkprime(unsigned long num);
int main(int argc, char **argv)
{
long int val = strtoul(argv[1], NULL, 0);
pid_t pid = fork();
if(pid == 0){
checkprime(val);
}
else if(pid < 0){
perror("Fork Failed!");
}
else{
int status = -1, result;
waitpid(pid, &status, 0);
result = WEXITSTATUS(status);
if(result == 1){
printf("Prime\n");
}
else if(status < 0){
perror("Something Failed");
}
else{
printf("Not prime\n");
}
}
return 0;
}
void checkprime(unsigned long num)
{
int i;
for(i = 2; i < num/2; i++){
if(num % i == 0){
exit(0);
}
}
exit(1);
}
Compile, Run
gcc -Wall prime.c -o prime
./prime 15

Can't get execvp to execute file

I am trying to write a program that will fork, then open a file and execute it. The file it should execute is called child and it has been compiled. When I type ./child, it runs. However, when I run this program it does not execute the child program and I am prompted with the error message I put in "Execution failed". What I am doing wrong?
This is my parent class
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main (int argc, char **argv)
{
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
int var = execvp("./child", NULL);
if(var < 0)
{
printf("Execution failed");
}
}
exit(0); // exec never returns
}
This is the child
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
printf ("Im the child");
exit (0);
}
I actually don't know what you are doing wrong. After a copy and a compilation (and several warning complains) your code runs fine (GCC 7.2).
Obviously, child must be in the same working directory in which you run your main executable (the one that forks).
But probably I would write that code in this way, but I'm not an expert in forking:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
extern int errno;
int main () {
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
if (pid == 0) {
int ret = execl("./child", "", (char *)NULL);
if(ret < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
} else {
wait(NULL);
}
return 0;
}
At least it tells you which error execl has encountered.

setpgrp/setpgid fails (?), works on Mac OSX, not on Linux

I'm trying to write a program that executes a child command, and does not allow that child to be killed by Ctrl+C.
I've read that I can accomplish this with setpgid/setpgrp.
The following code works on OSX, but on Linux (2.6.32, Ubuntu 10.04) running something like,
./a.out ls
causes no output to occur and the program cannot be killed with SIGINT.
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char **argv) {
if (argc < 2) {
printf("Please provide a command\n");
exit(1);
}
int child_pid = vfork();
if (child_pid == 0) {
if (setpgrp() == -1) {
perror("setpgrp error");
exit(1);
}
printf("Now executing the command:\n");
argv++;
if (execvp(argv[0], argv) == -1) {
perror("Could not execute the command");
exit(1);
}
}
int child_status;
wait(&child_status);
}
If you comment out the call to setpgrp, you will see that the remaining code is functional.
I had to modify this section of the code for it to work on both platforms. I guess this is simply a difference between how the kernels treat sessions and process groups.
if (setsid() == -1) {
#ifdef LINUX
perror("setsid error");
exit(1);
#else
if (setpgrp() == -1) {
perror("setpgrp error");
exit(1);
}
#endif
}

Resources