I read cat /proc/[pid]/maps gives the informaion about its address space.
So I want to write a program which will print its own address space.
My program is this;
pid_t pid;
int fd;
char *buf;
pid = getpid();
fd = open("/proc/????/maps", O_RDONLY);
I'm getting the PID, but it won't help me to open the file.
How to convert the pid from pid_t to string and add it to open call?
Or is there any other way to open the file?
All modern procfs systems implement "/proc/self/" for the running process. Just
fd = open("/proc/self/maps", O_RDONLY);
If you still wish to create the path string yourself then you have to use sprintf
char filename[128];
sprintf(filename, "/proc/%d/maps", getpid());
fd = open(filename, O_RDONLY);
If you just want to print mapping information for review, one simple method:
you can use system library call to execute cat /proc/[pid]/maps
A simple C code is as follows:
char command[256];
sprintf(command, "cat /proc/%d/maps", getpid());
system(command);
You can refer to one example in my Gist.
Related
I need to kill java process, that runs main class blabla.class. I can use function kill(pid_t, SIGKILL) for this reason, but I need to get PID ID.
I could run linux command ps-ax | grep blabla to find PID ID. What is the best way to do this using C ?
Adapting the link given by Marco https://stackoverflow.com/a/8166467/1967396:
#define LEN 100
char line[LEN];
FILE *cmd = popen("ps -ax | grep blabla", "r");
fgets(line, LEN, cmd);
// now parse `line` for the information you want, using sscanf perhaps?
// I believe the pid is the first word on the line returned, and it fits in an int:
int pid;
sscanf(line, "%d", &pid);
pclose(cmd);
I want stdin to be redirected to a string of text supplied in my program. I want to write the string of text to a temporary file and then point stdin to that file. I'm a little unsure about this code because it seems to blend low level function calls like write() and dup() with higher level function calls like fclose(). Is this the correct approach?:
char* buffer = "This is some text";
int nBytes = strlen(buffer);
FILE* file = tmpfile();
int fd = fileno(file);
write(fd,buffer,nBytes);
rewind(file);
dup2(fd,0);
fclose(file);
EDIT
As per a suggestion in the comments, I tried approaching this problem with pipes. If I want to use pipes, would this be the correct approach? I still want feedback on the first approach as well:
int fd[2];
pipe(fd); // For sake of simplicity assume returns 0 (no error).
char* buffer = "This is some text";
int nBytes = strlen(buffer);
write(fd[1],buffer,nBytes);
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
I'm just starting to learn C programming and I have some uncertainty about fork(), exec(), pipe(), etc.
I've developed this code, but when I execute it, the variable c remains empty, so I don't know if the child isn't writing to the pipe, or the parent isn't reading from it.
Could you help me please? This is the code:
int main() {
int pid=0;
int pipefd[2];
char* c=(char *)malloc(sizeof(char));
FILE *fp;
pipe(pipefd);
pid=fork();
if (pid==0){
close(pipefd[0]);
dup2(pipefd[1],1);
close(pipefd[1]);
execl("ls -l | cut -c28","ls -l | cut -c28", (char *) 0);
}
else{
close(pipefd[1]);
read(pipefd[0], c, 1);
char* path="/home/random";
char* txt=".txt";
char* root=malloc(strlen(path) + strlen(txt) + sizeof(char));
strcpy(root,path);
strcat(root,c);
strcat(root,txt);
close(pipefd[0]);
fp=fopen(root,"w+");
(...)
}
The problem is that the final root string its only "/home/random.txt" because there is nothing in the char c, and what I want is to open the file "/home/random(number stored in char c).txt".
execl executes a single command, and is not aware of shell concepts such as pipes. If you want to execute a shell command, you will have to execute a shell, as follows:
execl("/bin/sh","/bin/sh","-c","ls -l | cut -c28", (char*) 0);
Always check the return value of the system calls (like execve(2) and derived functions like execl(3)), and use the errno(3) to figure out what went wrong.
In your case the execl line fails.
Using strcpy/strcat seems a bit excessively complex. snprintf can turn those 3 lines into one.
snprintf( root, size_of_buf, "/home/random%s", c );
Additionally, check your error codes. As noted, execl is failing and you don't know it. fork, dup2, ...,can also fail, you want to know sooner rather than later.
Basically I want to do in C (and without buffering) the same as this bash-script:
#!/bin/sh
cat ./fifo_in | myprogram > ./fifo_out
In other words I want to exec "myprogram" and redirect its stdin and stdout to two pipes which have been created previously.
Another program is feeding data into fifo_in and reading out of fifo_out.
Of course it would be easy to just read from ./fifo_in, buffer it in the parent and write to myprogram's stdin (and reverse for stdout and ./fifo_out) but I think there is probably a way to let "myprogram" read/write directly from/to the fifos without buffering in the parent process.
Edit:
Eugen's answer seems to be the correct one, but I cannot get it to work.
I use this function on the C-side, which seems correct to me:
pid_t execpipes(const char *wd, const char *command, const char *pipename)
{
char pipename_in[FALK_NAMESIZE];
char pipename_out[FALK_NAMESIZE];
strcpy(pipename_in, FALKPATH);
strcat(pipename_in, "/");
strcat(pipename_in, FALK_FIFO_PATH);
strcat(pipename_in, "/");
strncat(pipename_in, pipename, FALK_NAMESIZE-2);
strcpy(pipename_out, pipename_in);
strcat(pipename_out, "R");
pid_t pid;
pid = fork();
if (pid < 0)
{ //Error occured
perror("fork");
exit(1);
}
if (pid == 0)
{
chdir(wd);
d("execpipes: pipename_in=\"%s\"\n", pipename_in);
d(" pipename_out=\"%s\"\n", pipename_out);
freopen(pipename_in,"r",stdin);
freopen(pipename_out,"w",stdout);
d("execpipes: command=\"%s\"\n", command);
execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster
// Should never get here
perror("execl");
exit(1);
}
return pid;
}
I read and write the pipes from a PHP-script (only relevant part posted):
$pipe_in = fopen($fp.$pipename, "w");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000); // Program hangs here
The program is started correctly, receives the input via $pipe_in correctly, processes the data correctly and (because it ran fine for many months) I assume it puts out the data correctly to stdout, but when I try to read from $pipe_out, it hangs. I know that the pipes themselves are set up correctly because if I don't open $pipe_out, the program does not get any input - which makes sense because there is no reader for $pipe_out and therefore the pipeline is not complete. So I can open $pipe_out, but I cannot read anything from it, which is quite strange.
Edit2:
Program works now, thanks guys - For some reason the first pipe has to be closed before you can read from the second pipe:
$pipe_in = fopen($fp.$pipename, "w");
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
fclose($pipe_in);
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000);
fclose($pipe_out);
unlink($fp.$pipename);
unlink($fp.$pipename.'R');
I'd write a small wrapper for myprogram, that does
freopen("./fifo_in","r",stdin)
freopen("./fifo_out","w",stdout)
(Ofcourse not with constant paths!), then execve myprogram
Korn shell supports coprocesses, which I think effectively does what you ask: read from a pipe and write to a pipe (which can be stdout and stdin of a C process)
http://www.dartmouth.edu/~rc/classes/ksh/coprocesses.html
How about
myprogram < ./fifo_in > ./fifo_out
?
As for getting rid of the buffering: Since your program directly reads/writes the pipes, the buffering shouldn't hurt you.
An important point is that the process which writes fifo_in should flush properly so you don't have to wait. The same goes for your output: As soon as a "work unit" is complete, flush your stdout which will make the data available to whoever reads the output pipe.
But you can't do anything in myprogram to make the writer of fifo_in flush its buffers.
[EDIT] To do this from C (without the help of a shell), use code like this:
- Put the names of the two pipes into local variables on the stack
- Call `fork()`. If that returns '0', then open the two fifos with `freopen()` [like Eugen suggested][1]
- Call `execve` to launch the real exec.
That's (in a nutshell) what the shell is doing when it runs commands. Make sure the parent process (the one where fork() returns a PID != 0) handles the signal SIGCHLD
Perhaps you are looking of a named pipe? For example:
mkfifo fifo_in
As a test stub for my_program.c, to read fifo_in via the buffered stdin:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
char buf[80];
if (!freopen("./fifo_in", "r", stdin)) {
perror("freopen");
exit(EXIT_FAILURE);
}
while (!ferror(stdin)) {
while (fgets(buf, sizeof buf, stdin))
fputs(buf, stdout);
sleep(1);
}
return 0;
}
Then as a test for the writer, using the bash shell:
for x in {1..10}; do
echo $x
echo $x >> fifo_in
sleep 1
done
Notes:
I'd prefer to use unbuffered I/O.
The writer, at least on my machine, blocks until there is a reader.
The reader, in this sample, cannot tell when the writer is finished.
Continuing on this problem, but I'll reiterate:
For a homework assignment I have to write a basic shell including redirection. The program uses readline to prompt for input, parses the input string, and breaks it down into the executable name, the arguments, and the input/output file(s), if applicable. After parsing the string, it forks and the child execv()'s to the executable that was passed in. I'm using dup2() to change the file descriptors after the fork and before the execv, but am having a problem once the program has execv'd to the new executable. If in my shell I run ls > foo.out, I get: ls: write error: Bad file descriptor
Here is the code for my child process (this is after fork()):
int _child(struct command *c){
int ret;
/* When given `ls > foo.out`, these next two lines output:
** c->infile is (null)
** c->outfile is foo.out
*/
printf("c->infile is %s\n",c->infile);
printf("c->outfile is %s\n",c->outfile);
if(c->infile){
int fd = open( c->infile, O_RDONLY);
int _fd_dup = dup2(fd,0);
close(0);
if(_fd_dup != 0){
fprintf(stderr, "Failed to redirect command input.\n");
return 0;
}
}
if(c->outfile){
int fd = open( c->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
int _fd_dup = dup2(fd,1);
close(1);
if(_fd_dup != 1){
fprintf(stderr, "Failed to redirect command output.\n");
return 0;
}
}
I do not get the "Failed to redirect command output." error. As I mentioned, this is a homework assignment so I'm not looking for anyone to fix this, but rather point me in the right direction.
The problem is in this bit of code:
int _fd_dup = dup2(fd,1);
close(1);
You should be closing fd, not 1. You have the same problem in the fd 0 case, too.