For an assignment, i am supposed to implement the linux terminal. My terminal should support arguments with pipes. Like the user can input:
ls | grep ".cpp"
What i have done so far is:
pid = fork();
if(pid==0)
{
close(fd[0]);
dup2(fd[1],1);
close(fd[1]);
execlp("/bin/ls","ls");
}
wait(NULL);
pid=fork();
if(pid==0)
{
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execlp("/bin/grep","grep",".cpp");
}
my first child works perfectly, writes the output of ls into a pipe declared earlier, however, my second child runs grep, but it apparently can not get input from pipe. Why is that so?
when i run it, my output is
/root/OS $ ls | grep
it just gets stuck like this
Don't ignore compiler warnings:
$ gcc lol.c
lol.c: In function ‘main’:
lol.c:14:5: warning: not enough variable arguments to fit a sentinel [-Wformat=]
execlp("/bin/ls","ls");
^
lol.c:23:5: warning: missing sentinel in function call [-Wformat=]
execlp("/bin/grep","grep",".cpp");
^
Here's man execlp:
The first argument, by convention, should point to the filename associated with the file being executed. The list of arguments must be terminated by a NULL
pointer, and, since these are variadic functions, this pointer must be cast (char *) NULL.
Always compile with -Werror so that compilation fails if there are warnings, and preferably also with -Wall to get warnings for all potential issues.
Here's your program with a main method and sentinels added:
#include <unistd.h>
#include <sys/wait.h>
int main() {
int fd[2];
int pid;
pipe(fd);
pid = fork();
if(pid==0)
{
close(fd[0]);
dup2(fd[1],1);
close(fd[1]);
execlp("/bin/ls","ls", NULL);
}
wait(NULL);
pid=fork();
if(pid==0)
{
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execlp("/bin/grep","grep",".cpp", NULL);
}
return 0;
}
Here's how it runs now:
$ gcc -Wall -Werror lol.c -o lol
$ ./lol
foo.cpp
Related
I have tried to write a program that run in ubuntu terminal .Program will open a new gnome terminal and run command in that new terminal to open new abcd.txt using vim.And then when i Ctrl+C in the first terminal which run the program ,new gnome terminal will shut vim down and have an announcement in the first terminal
I have tried system("`gnome-terminal`<< vim abcd.txt");
and this system("vim abcd.txt>>`gnome-terminal`");
but the new one terminal cannot recieve command
My full code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop=1;
void DEF()
{
system("kill -9 pidof vim");
loop=0;
}
void *subthreads(void *threadid)
{
loop=1;
long tid;
tid=(long)threadid;
system("`gnome-terminal`<< vim abcd.txt");
signal(SIGINT,DEF);
while(loop){}
pthread_exit(NULL);
}
void main()
{
int loop=1;
pthread_t threads;
int check;
long tID;
check= pthread_create(&threads,NULL,&subthreads,(void*)tID);
while(loop){}
printf("Ctrl+C is pressed!\n");
}
Not sure what you are trying to achieve in the end. But here are a few ideas, starting from your code:
The terminal command (in system()) should be something like Mark Setchell pointed out, like for example system("gnome-terminal -e vim file.txt");
The system() command is blocking further execution of your code, so the call to signal() is not happening until you terminate the system() call.
pidof is not working on my Linux system. I would use pkill <program>. Still, that would kill all running instances of , for example vim or your terminal.
You are declaring the variable loop in the global scope first and then redeclaring it in main(). If you really want to use it as a global variable, it should just be loop=1 in main().
You are not using the variable tid for anything.
Here is an improved version of your program, with additional printf calls to explain to the user what is happening. I also used xterm and nano because I don't have gnome-terminal, and I didn't want to interfere with my running instance of vim. But it still is maybe not exactly what you are trying to do. The main problem is that system("xterm -e sh &") is blocking and when you press Ctrl-C, that system call will terminate xterm so that the def() function will do nothing when it is called later.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop = 1;
void def()
{
printf("In def\n");
system("pkill xterm");
loop=0;
}
void *subthreads(void *threadid)
{
printf("Starting subthread\n");
loop = 1;
long tid;
tid = (long)threadid;
signal(SIGINT, def);
system("xterm -e sh -c nano &"); // Note: xterm will still exit when you press Ctrl-C
printf("Terminal exited in subthread\n");
while (loop);
printf("Exited loop in subthread\n");
pthread_exit(NULL);
}
void main()
{
pthread_t threads;
int check;
long tID;
check = pthread_create(&threads, NULL, &subthreads, (void*)tID);
printf("In main after thread creation\n");
while (loop);
printf("Ctrl+C is pressed!\n");
}
Another option is to use fork() instead of pthread to split into a separate process. (Note that processes are like separate applications while threads are processor threads in the same application.)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void def()
{
system("pkill nano");
printf("def(): Killed nano\n");
}
int subprocess()
{
signal(SIGINT, def);
pid_t parent_id = getpid(); // Get process ID of main process
fork(); // Fork into two identical copies of the running app.
if (getpid() != parent_id) { // The part in the if block is only done in the second process!
system("xterm -e sh -c nano &");
printf("subprocess(): system call ended in forked process\n");
exit(0);
}
}
int main()
{
subprocess();
printf("Entering while loop in main process\n");
while (1);
printf("Exited main thread\n");
}
The one flaw with this version is the same as the previous one: when Ctrl-C is pressed, xterm/nano is killed and def() will subsequently do nothing except catch any Ctrl-C done afterwards.
If you explain further what your final goal is, maybe I can give some suggestions.
Like, why do you want to start vim in a terminal from a C application and then kill vim? Do you want to kill the whole terminal or only vim?
All, the first part of my homework assignment is simply a demo program that I need to compile, and then modify. It was provided by the teacher, however I simply cannot get it to compile using g++. I will be creating a make file at the end of the assignment, but for the moment I am simply trying to test it out, and am having no luck. I've tried the most basic g++ command: g++ -o main TwoPipesTwoChildren.cpp . Can someone please help? I can't even get started on this until I can get this working.
// description: This program will execute "ls -ltr | grep 3376"
// by using a parent and child process
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv){
printf("TEST");
int status;
int childpid;
char *cat_args[] = {"ls", "-ltr", NULL};
char *grep_args[] = {"grep", "3376", NULL};
// create one pipe to send the output of "ls" process to "grep" process
int pipes[2];
pipe(pipes);
// fork the first child (to execute cat)
if((childpid = fork()) == -1)
{
perror("Error creating a child process");
exit(1);
}
// replace cat's stdout with write part of 1st pipe
if (childpid == 0)
{
dup2(pipes[1], 1);
printf("AFTER FORK CHILD");
//close all pipes (very important!); end we're using was safely copied
close(pipes[0]);
close(pipes[1]);
execvp(*cat_args, cat_args);
exit(0);
}
else
{
// replace grep's stdin with read end of 1st pipe
dup2(pipes[0], 0);
close(pipes[0]);
close(pipes[1]);
execvp(*grep_args, grep_args);
}
return (0);
}
We have a piece of legacy code that uses Flex with C-style FILE* descriptors. To support reading compressed files into Flex, we extended the "open" semantics to open gzip'ed files using
FILE* file = popen("gzip -cd <filename>");
rather than fopen.
We've encountered some problems recently where attempting this across a unix filesystem (probably another filesystem mounted using NFS on a NetApp) causes this entire code stream to crash (segfault), the first message we see is
gzip: stdout: Broken Pipe
and our own crash frame.
If we take the file and move it to the local filesystem where the process is running, there is no segfault and everything works as normal.
What have we tried to replicate or fix?
read files compressed using gzip/ bzip2 etc from internal test NFS filesystems
verify that the target file can be opened
"open" the file and read a few bytes to make sure it can be opened by this process
All of this succeeds and yet we still encounter the crash.
We are out of ideas and could use some suggestions.
Sam Appleton
When you test it, SIGPIPE has its default action (kill the gzip process). When the process runs on your client's side, SIGPIPE is masked. Here's a minimal program that reproduces the error:
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#define SZ 4096
void mask()
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
if (-1 == sigaction(SIGPIPE, &sa, 0))
{
perror("sigaction");
exit(1);
}
}
int main(int argc, char ** argv)
{
char buf[SZ];
#ifdef MASK
mask();
#endif
FILE * f = popen("gzip -dc foo.gz", "r");
if (0 != fread(buf, SZ, 1, f))
{
fwrite(buf, SZ, 1, stdout);
}
fprintf(stderr, "%d\n", pclose(f));
}
And here's the output with and without MASK:
$ gcc -o foo foo.c
$ gcc -DMASK -o foomask foo.c
$ /foo > /dev/null
13
$ /foomask > /dev/null
gzip: stdout: Broken pipe
256
$
In short, it has nothing to do with NFS. That's a red herring.
I am trying to write a program in C (in Linux 64bit with GCC 4.1.2).
int program_instances(char *cmdname)
{
char buf[32], *ret;
char cmdbuf[512];
FILE *cmdpipe;
sprintf(cmdbuf, "/bin/ps -eo comm | /bin/grep -c '%s'",
cmdname);
cmdpipe = popen(cmdbuf, "r");
if (!cmdpipe)
{
return -1;
}
memset(buf, 0, sizeof(buf));
ret = fgets(buf, sizeof(buf), cmdpipe);
pclose(cmdpipe);
if (!ret)
{
return -1;
}
int nr = atoi(buf);
return nr;
}
Tried to debug the issue through gdb but after the line
sprintf(cmdbuf, "/bin/ps -eo comm | /bin/grep -c '%'",cmdname);
The programm is not crossing the above line , throwing the below lines..
Executing new program: /bin/bash
Error in re-setting breakpoint 1: No symbol table is loaded. Use the "file" command.
[New process 2437]
Executing new program: /bin/ps
Please help us to resolve this issue.
Try to compile your code with -g and remove -O [compiler flag]. When optimizing compiler(gcc) changes order of instructions to improve speed. After recompiling attach debugger again.
I have an application where I need to write a new getpid function to replace the original one of the OS. The implementation would be similar to:
pid_t getpid(void)
{
if (gi_PID != -1)
{
return gi_PID;
}
else
{
// OS level getpid() function
}
}
How can I call the original getpid() implementation of the OS through this function?
EDIT: I tried:
pid_t getpid(void)
{
if (gi_PID != -1)
{
return gi_PID;
}
else
{
return _getpid();
}
}
as Jonathan has suggested. This gave me the following errors when compiling with g++:
In function pid_t getpid()':
SerendibPlugin.cpp:882: error:
_getpid' undeclared (first use this
function) SerendibPlugin.cpp:882:
error: (Each undeclared identifier is
reported only once for each function
it appears in.)
EDIT 2: I've managed to get this to work by using a function pointer and setting it to the next second symbol with the id "getpid", using dlsym(RTLD_NEXT, "getpid").
Here's my sample code:
vi xx.c
"xx.c" 23 lines, 425 characters
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <dlfcn.h>
using namespace std;
pid_t(*___getpid)();
pid_t getpid(void)
{
cout << "My getpid" << endl;
cout << "PID :" << (*___getpid)() << endl;
return (*___getpid)();
}
int main(void)
{
___getpid = (pid_t(*)())dlsym(RTLD_NEXT, "getpid");
pid_t p1 = getpid();
printf("%d \n", (int)p1);
return(0);
}
g++ xx.c -o xout
My getpid
PID :7802
7802
On many systems, you will find that getpid() is a 'weak symbol' for _getpid(), which can be called in lieu of getpid().
The first version of the answer mentioned __getpid(); the mention was removed swiftly since it was erroneous.
This code works for me on Solaris 10 (SPARC) - with a C++ compiler:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
extern "C" pid_t _getpid();
pid_t getpid(void)
{
return(-1);
}
int main(void)
{
pid_t p1 = getpid();
pid_t p2 = _getpid();
printf("%d vs %d\n", (int)p1, (int)p2);
return(0);
}
This code works for me on Solaris 10 (SPARC) - with a C compiler:
Black JL: cat xx.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
pid_t getpid(void)
{
return(-1);
}
int main(void)
{
pid_t p1 = getpid();
pid_t p2 = _getpid();
printf("%d vs %d\n", (int)p1, (int)p2);
return(0);
}
Black JL: make xx && ./xx
cc xx.c -o xx
"xx.c", line 13: warning: implicit function declaration: _getpid
-1 vs 29808
Black JL:
You can use a macro:
in a .h, included in every file where you want to replace the getpid function
#define getpid() mygetpid()
Then, put your own implementation in a .cpp
pid_t mygetpid() {
// do what you want
return (getpid)();
}
You're using the terminology a bit incorrectly. It's not possible to override getpid() because it's not a virtual function. All you can do is attempt to replace getpid with a different function by various evil means.
But I must ask, why are you doing this? Replacing getpid means that any component which was depending on the return of getpid will now be receiving you're presumably modified result. This change has a very high risk of changing some other component.
What you're offering is a new functionality and hence should be a different function.
That being said if you truly want to take this approach the best way is to dynamic loading of the function. The original DLL will still contain the getpid function and you can access that via a combination of LoadLibrary/GetProcAddress on Windows or dlopen/dlsym on Linux. If you're using a different OS please specify.
EDIT Responding to comments that getpid needs to be testable
If testing is the concern then why not instead have a custom getpid method for you're application. For example, applicationGetPid(). For normal execution this could be forwarded off to the system getpid function. But during Unit Testing it could be used to produce more predictable values.
pid_t applicationGetPid() {
#if UNIT_TEST
return SomeCodeForUnitTests;
#else
return getpid();
#endif
}