Passing a pipefd through execlp in C - process

I have looked all over and I cannot seem to figure out how to do this.
I have a parent process that has created a pipe()
Now, I want to fork() the parent and then execlp() and pass the pipe() to the new program as a command line argument.
Then from inside the new program I need to be able to read the pipefd.
I've seen a bunch of stuff on how to do it from inside the same process, but nothing on how to do it like this.
Edit: Initial post is/was rather vague.
What I have so far is:
int pfd[2];
if(pipe(pfd) == -1) {
perror("Creating pipe\n");
exit(1);
}
pid_t pid = fork();
if(pid == -1) {
fprintf (stderr, "Initiator Error Message : fork failed\n");
return -1;
}
else if(pid == 0) { // child process
close(pipe0[1]); // close(write);
execlp("program", "program", pipe0[0], NULL);
}
but then I don't really understand what I should do from inside "program" to get the FD. I tried assigning it to all sorts of things, but they all seem to error.
Thank you in advance!

The forked and execed child automatically inherit the open pipe descriptors and the pipe output is usually fed as standard input so that a command line argument to find the pipe is pretty redundant:
if(!pipe(&pipefd))
switch(fork()) {
case 0: !dup2(pipefd[0],0)&&
execlp("cat","cat","-n","/dev/fd/0",0);
case -1: return perror("fork");
default: write(pipefd[1],"OK\n",3);
}

Related

Detect if a Tcl script is run in a background process

I'm looking for a preferably cross-platform way to detect from within a Tcl script if the interpreter is running in a foreground or in a background process.
I've seen how to do it via ps (or /proc/$$/stat on Linux); is there a better way or do I have to hack something around that approach? I already have a utility library written in C so exposing the lowlevel API that ps also uses so I don't have to parse process output (or special file content) would be fine.
There's no truly cross-platform notion of foreground, but the main platforms do have ways of doing it according to the notion they have of foreground.
Linux, macOS, and other Unix:
For determining if a process is foreground or not, you need to check if its process group ID is the terminal's controlling process group ID. For Tcl, you'd be looking to surface the getpgrp() and tcgetpgrp() system calls (both POSIX). Tcl has no built-in exposure of either, so you're talking either a compiled extension (may I recommend Critcl for this?) or calling an external program like ps. Fortunately, if you use the latter (a reasonable option if this is just an occasional operation) you can typically condition the output so that you get just the information you want and need to do next to no parsing.
# Tested on macOS, but may work on other platforms
proc isForeground {{pid 0}} {
try {
lassign [exec ps -p [expr {$pid ? $pid : [pid]}] -o "pgid=,tpgid="] pgid tpgid
} on error {} {
return -code error "no such process"
}
# If tpgid is zero, the process is a daemon of some kind
expr {$pgid == $tpgid && $tpgid != 0}
}
Windows
There's code to do it, and the required calls are supported by the TWAPI extension so you don't need to make your own. (WARNING! I've not tested this!)
package require twapi_ui
proc isForeground {{pid 0}} {
set forground_pid [get_window_thread [get_foreground_window]]
return [expr {($pid ? $pid : [pid]) == $foreground_pid}]
}
Thanks to Donal I came up with the implementation below that should work on all POSIX Unix variants:
/*
processIsForeground
synopsis: processIsForeground
Returns true if the process is running in the foreground or false
if in the background.
*/
int IsProcessForegroundCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
/* Check the arg count */
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
int fd;
errno = 0;
if ((fd = open("/dev/tty", O_RDONLY)) != -1) {
const pid_t pgrp = getpgrp();
const pid_t tcpgrp = tcgetpgrp(fd);
if (pgrp != -1 && tcpgrp != -1) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(pgrp == tcpgrp));
close(fd);
return TCL_OK;
}
close(fd);
}
Tcl_SetErrno(errno);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "processIsForeground: ", (char *)Tcl_PosixError(interp), NULL);
return TCL_ERROR;
}
int Pextlib_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, "8.4", 0) == NULL)
return TCL_ERROR;
// SNIP
Tcl_CreateObjCommand(interp, "processIsForeground", IsProcessForegroundCmd, NULL, NULL);
if (Tcl_PkgProvide(interp, "Pextlib", "1.0") != TCL_OK)
return TCL_ERROR;
return TCL_OK;
}

Linux-Xenomai Serial Communication using xeno_16550A module

I'm starter of RTOS and I'm using Xenomai v2.6.3.
I'm trying to get some data using Serial communication.
I did my best on the task following the xenomai's guide and open sources, but it doesn't work well.
the link of the guide --> (https://xenomai.org//serial-16550a-driver/)
I just followed the sequence to use the module xeno_16550A. (with port io = 0x2f8 and irq=3)
I followed open source http://www.acadis.org/pages/captain.at/serial-port-example
It works well in write task, but read task doesn't work well.
It gave me the error sentence with error while RTSER_RTIOC_WAIT_EVENT, code -110 (it means connection timed out)
Moreover I checked the irq number3 by typing command 'cat /proc/xenomai/irq', but the interrupt number doesn't increase.
In my case, I don't need to write data, so I erase the write task code.
The read task proc is follow
void read_task_proc(void *arg) {
int ret;
ssize_t red = 0;
struct rtser_event rx_event;
while (1) {
/* waiting for event */
ret = rt_dev_ioctl(my_fd, RTSER_RTIOC_WAIT_EVENT, &rx_event );
if (ret) {
printf(RTASK_PREFIX "error while RTSER_RTIOC_WAIT_EVENT, code %d\n",ret);
if (ret == -ETIMEDOUT)
continue;
break;
}
unsigned char buf[1];
red = rt_dev_read(my_fd, &buf, 1);
if (red < 0 ) {
printf(RTASK_PREFIX "error while rt_dev_read, code %d\n",red);
} else {
printf(RTASK_PREFIX "only %d byte received , char : %c\n",red,buf[0]);
}
}
exit_read_task:
if (my_state & STATE_FILE_OPENED) {
if (!close_file( my_fd, READ_FILE " (rtser)")) {
my_state &= ~STATE_FILE_OPENED;
}
}
printf(RTASK_PREFIX "exit\n");
}
I could guess the causes of the problem.
buffer size or buffer is already full when new data is received.
rx_interrupt doesn't work....
I want to check whether the two things are wrong or not, but How can I check?
Furthermore, does anybody know the cause of the problem? Please give me comments.

sending characters from parent to child process and returning char count to parent in C

So for an assignment I have for my Computer Systems class, I need to type characters in the command line when the program runs.
These characters (such as abcd ef) would be stored in argv[].
The parent sends these characters one at a time through a pipe to the child process which then counts the characters and ignores spaces. After all the characters are sent, the child then returns the number of characters that it counted for the parent to report.
When I try to run the program as it is right now, it tells me the value of readIn is 4, the child processed 0 characters and charCounter is 2.
I feel like I'm so close but I'm missing something important :/ The char array for a and in the parent process was an attempt to hardcode the stuff in to see if it worked but I am still unsuccessful. Any help would be greatly appreciated, thank you!
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
//
// Child process counts number of characters sent through pipe.
//
// Child process returns number of characters counted to parent process.
//
// Parent process prints number of characters counted by child process.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> // for fork()
#include <sys/types.h> // for pid_t
#include <sys/wait.h> // for waitpid()
int main(int argc, char **argv)
{
int fd[2];
pid_t pid;
int status;
int charCounter = 0;
int nChar = 0;
char readbuffer[80];
char readIn = 'a';
//char a[] = {'a', 'b', 'c', 'd'};
pipe(fd);
pid = fork();
if (pid < 0) {
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
// code that runs in the child process
close(fd[1]);
while(readIn != 0)
{
readIn = read(fd[0], readbuffer, sizeof(readbuffer));
printf("The value of readIn is %d\n", readIn);
if(readIn != ' ')
{
charCounter++;
}
}
close(fd[0]);
//open(fd[1]);
//write(fd[1], charCounter, sizeof(charCounter));
printf("The value of charCounter is %d\n", charCounter);
return charCounter;
}
else
{
// code that runs in the parent process
close(fd[0]);
write(fd[1], &argv, sizeof(argv));
//write(fd[1], &a, sizeof(a));
close(fd[1]);
//open(fd[0]);
//nChar = read(fd[0], readbuffer, sizeof(readbuffer));
nChar = charCounter;
printf("CS201 - Assignment 3 - Andy Grill\n");
printf("The child processed %d characters\n\n", nChar);
if (waitpid(pid, &status, 0) > 0)
{
if (WIFEXITED(status))
{
}
else if (WIFSIGNALED(status))
{
}
}
return 0;
}
}
You're misusing pipes.
A pipe is a unidirectional communication channel. Either you use it to send data from a parent process to a child process, or to send data from a child process to the parent. You can't do both - even if you kept the pipe's read and write channels open on both processes, each process would never know when it was its turn to read from the pipe (e.g. you could end up reading something in the child that was supposed to be read by the parent).
The code to send the characters from parent to child seems mostly correct (more details below), but you need to redesign child to parent communication. Now, you have two options to send the results from child to parent:
Use another pipe. You set up an additional pipe before forking for child-to-parent communication. This complicates the design and the code, because now you have 4 file descriptors to manage from 2 different pipes, and you need to be careful where you close each file descriptor to make sure processes don't hang. It is also probably a bit overkill because the child is only sending a number to the parent.
Return the result from the child as the exit value. This is what you're doing right now, and it's a good choice. However, you fail to retrieve that information in the parent: the child's termination status tells you the number of characters processed, you can fetch this value with waitpid(2), which you already do, but then you never look at status (which contains the results you're looking for).
Remember that a child process has its own address space. It makes no sense to try to read charCounter in the parent because the parent never modified it. The child process gets its own copy of charCounter, so any modifications are seen by the child only. Your code seems to assume otherwise.
To make this more obvious, I would suggest moving the declarations of variables to the corresponding process code. Only fd and pid need to be copied in both processes, the other variables are specific to the task of each process. So you can move the declarations of status and nChar to the parent process specific code, and you can move charCounter, readbuffer and readIn to the child. This will make it very obvious that the variables are completely independent on each process.
Now, some more specific remarks:
pipe(2) can return an error. You ignore the return value, and you shouldn't. At the very least, you should print an error message and terminate if pipe(2) failed for some reason. I also noticed you report errors in fork(2) with printf("fork error %d\n", pid);. This is not the correct way to do it: fork(2) and other syscalls (and library calls) always return -1 on error and set the errno global variable to indicate the cause. So that printf() will always print fork error -1 no matter what the error cause was. It's not helpful. Also, it prints the error message to stdout, and for a number of reasons, error messages should be printed to stderr instead. So I suggest using perror(3) instead, or manually print the error to stderr with fprintf(3). perror(3) has the added benefit of appending the error message description to the text you feed it, so it's usually a good choice.
Example:
if (pipe(fd) < 0) {
perror("pipe(2) error");
exit(EXIT_FAILURE);
}
Other functions that you use throughout the code may also fail, and again, you are ignoring the (possible) error returns. close(2) can fail, as well as read(2). Handle the errors, they are there for a reason.
The way you use readIn is wrong. readIn is the result of read(2), which returns the number of characters read (and it should be an int). The code uses readIn as if it were the next character read. The characters read are stored in readbuffer, and readIn will tell you how many characters are on that buffer. So you use readIn to loop through the buffer contents and count the characters. Something like this:
readIn = read(fd[0], readbuffer, sizeof(readbuffer));
while (readIn > 0) {
int i;
for (i = 0; i < readIn; i++) {
if (readbuffer[i] != ' ') {
charCounter++;
}
}
readIn = read(fd[0], readbuffer, sizeof(readbuffer));
}
Now, about the parent process:
You are not writing the characters into the pipe. This is meaningless:
write(fd[1], &argv, sizeof(argv));
&argv is of type char ***, and sizeof(argv) is the same as sizeof(char **), because argv is a char **. Array dimensions are not kept when passed into a function.
You need to manually loop through argv and write each entry into the pipe, like so:
int i;
for (i = 1; i < argv; i++) {
size_t to_write = strlen(argv[i]);
ssize_t written = write(fd[1], argv[i], to_write);
if (written != to_write) {
if (written < 0)
perror("write(2) error");
else
fprintf(stderr, "Short write detected on argv[%d]: %zd/zd\n", i, written, to_write);
}
}
Note that argv[0] is the name of the program, that's why i starts at 1. If you want to count argv[0] too, just change it to start at 0.
Finally, as I said before, you need to use the termination status fetched by waitpid(2) to get the actual count returned by the child. So you can only print the result after waitpid(2) returned and after making sure the child terminated gracefully. Also, to fetch the actual exit code you need to use the WEXITSTATUS macro (which is only safe to use if WIFEXITED returns true).
So here's the full program with all of these issues addressed:
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
//
// Child process counts number of characters sent through pipe.
//
// Child process returns number of characters counted to parent process.
//
// Parent process prints number of characters counted by child process.
#include <stdlib.h>
#include <stdio.h>
#include <string.h> // for strlen()
#include <unistd.h> // for fork()
#include <sys/types.h> // for pid_t
#include <sys/wait.h> // for waitpid()
int main(int argc, char **argv)
{
int fd[2];
pid_t pid;
if (pipe(fd) < 0) {
perror("pipe(2) error");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
perror("fork(2) error");
exit(EXIT_FAILURE);
}
if (pid == 0) {
int readIn;
int charCounter = 0;
char readbuffer[80];
if (close(fd[1]) < 0) {
perror("close(2) failed on pipe's write channel");
/* We use abort() here so that the child terminates with SIGABRT
* and the parent knows that the exit code is not meaningful
*/
abort();
}
readIn = read(fd[0], readbuffer, sizeof(readbuffer));
while (readIn > 0) {
int i;
for (i = 0; i < readIn; i++) {
if (readbuffer[i] != ' ') {
charCounter++;
}
}
readIn = read(fd[0], readbuffer, sizeof(readbuffer));
}
if (readIn < 0) {
perror("read(2) error");
}
printf("The value of charCounter is %d\n", charCounter);
return charCounter;
} else {
int status;
if (close(fd[0]) < 0) {
perror("close(2) failed on pipe's read channel");
exit(EXIT_FAILURE);
}
int i;
for (i = 1; i < argc; i++) {
size_t to_write = strlen(argv[i]);
ssize_t written = write(fd[1], argv[i], to_write);
if (written != to_write) {
if (written < 0) {
perror("write(2) error");
} else {
fprintf(stderr, "Short write detected on argv[%d]: %zd/%zd\n", i, written, to_write);
}
}
}
if (close(fd[1]) < 0) {
perror("close(2) failed on pipe's write channel on parent");
exit(EXIT_FAILURE);
}
if (waitpid(pid, &status, 0) < 0) {
perror("waitpid(2) error");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("CS201 - Assignment 3 - Andy Grill\n");
printf("The child processed %d characters\n\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "Child terminated abnormally with signal %d\n", WTERMSIG(status));
} else {
fprintf(stderr, "Unknown child termination status\n");
}
return 0;
}
}
Some final notes:
The shell splits arguments by spaces, so if you start the program as ./a.out this is a test, the code will not see a single space. This is irrelevant, because spaces are supposed to be ignored anyway, but if you want to test that the code really ignores spaces, you need to quote the parameters so that the shell does not process them, as in ./a.out "this is a test" "hello world" "lalala".
Only the rightmost (least significant) 8 bits of a program's exit code are used, so WEXITSTATUS will never return more than 255. If the child reads more than 255 characters, the value will wrap around, so you effectively have a character counter modulo 256. If this is a problem, then you need to go with the other approach and set up a 2nd pipe for child-to-parent communication and write the result there (and have the parent read it). You can confirm this on man 2 waitpid:
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least
significant 8 bits of the status argument that the child
specified in a call to exit(3) or _exit(2) or as the argument for a return
statement in main(). This macro should be employed only if
WIFEXITED returned true.

How to run two loops at the same time?

I have been developing a very simple text game using Objective C and Xcode. It is almost done but I am having a problem, the scanf method stops the loop and asks for user input while I need the computer to be running the rest of the loop, the solution I came up with was running two while loops at the same time, one being the logic loop and another being a loop for user input.
I have been doing my research and it looks like using threads are the way to go, I just have not found a tutorial that will break it down for a n00b in Objective C (I am decent in java, I just have never worked with threads). If anybody could explain them or link me to a very broken down tutorial that would be great. Or if anybody has another idea I am open to anything else.
Necessary Code (The scanf I am having a problem with has asterisks on the line):
while(running != 0)
{
if(gameState == 1)
{
if(timeToGenerateNum == true)
{
while(randNumber < 10000000)
{
randNumber = arc4random() % 100000000;
}
NSLog(#"%i", randNumber);
timeToGenerateNum = false;
}
else
{
while(time <= 2500)
{
NSLog(#"Testing");
time++;
******************scanf("%i", &userNum);************************
if(userNum == randNumber)
{
score += time;
time = 0;
timeToGenerateNum = true;
}
}
NSLog(#"Game Over! Your score was %i!", score);
running = 0;
}
}
else if(gameState == 2)
{
NSLog(#"To play, simply type in the number that appears on the screen.");
NSLog(#"But be careful, you only have a short amount of time before GAME OVER!");
NSLog(#"The quicker you type in the number the more score you get!");
NSLog(#"Are you ready to start, if so type '1' and press enter!");
scanf("%i", &gameState);
}
}
You're going to have to learn a bit about BSD (Unix, Linux) input/output to pull this off: replace your call to scanf with a non-blocking function you write to acquire input from the user's keyboard.
This function should immediately return whatever the user typed, or immediately return with a zero character count if she didn't type anything.
Read up on the select(2) system call, and keep in mind that keyboard input (standard input) is the first file descriptor, file descriptor zero.

DirectShow's PushSource filters cause IMediaControl::Run to return S_FALSE

I'm messing around with the PushSource sample filter shipped with the DirectShow SDK and I'm having the following problem:
When I call IMediaControl::Run(), it returns S_FALSE which means "the graph is preparing to run, but some filters have not completed the transition to a running state". MSDN suggests to then call IMediaControl::GetState() and wait for the transition to finish.
And so, I call IMediaControl::GetState(INFINITE, ...) which is supposed to solve the problem.
However, to the contrary, it returns VFW_S_STATE_INTERMEDIATE even though I've specified an infinite waiting time.
I've tried all three variations (Bitmap, Bitmap Set and Desktop) and they all behave the same way, which initially lead me to believe there is a bug in there somewhere.
However, then, I tried using IFilterGraph::AddSourceFilter to do the same and it did the same thing, which must mean it's my rendering code that is the problem:
CoInitialize(0);
IGraphBuilder *graph = 0;
assert(S_OK == CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&graph));
IBaseFilter *pushSource = 0;
graph->AddSourceFilter(L"sample.bmp", L"Source", &pushSource);
IPin *srcOut = 0;
assert(S_OK == GetPin(pushSource, PINDIR_OUTPUT, &srcOut));
graph->Render(srcOut);
IMediaControl *c = 0;
IMediaEvent *pEvent;
assert(S_OK == graph->QueryInterface(IID_IMediaControl, (void**)&c));
assert(S_OK == graph->QueryInterface(IID_IMediaEvent, (void**)&pEvent));
HRESULT hr = c->Run();
if(hr != S_OK)
{
if(hr == S_FALSE)
{
OAFilterState state;
hr = c->GetState(INFINITE, &state);
assert(hr == S_OK );
}
}
long code;
assert(S_OK == pEvent->WaitForCompletion(INFINITE, &code));
Anyone knows how to fix this?
IBaseFilter *pushSource = 0;
graph->AddSourceFilter(L"sample.bmp", L"Source", &pushSource);
AddSourceFilter adds a default source filter, I don't think it will add your pushsource samplefilter.
I would recommend to add the graph to the ROT, so you can inspect it with graphedit.
And what happens if you don't call GetState()?
hr = pMediaControl->Run();
if(FAILED(hr)) {
/// handle error
}
long evCode=0;
while (evCode == 0)
{
pEvent->WaitForCompletion(1000, &evCode);
/// other code
}
Open GraphEditPlus, add your filter, render its pin and press Run. Then you'll see states of each filter separately, so you'll see what filter didn't run and why.