Dynamic generation of file contents (poor man's proc file) - c

I'm trying to make a simple userspace program that dynamically generates file contents when a file is read, much like a virtual filesystem. I know there are programs like FUSE, but they seem a bit heavy for what I want to do.
For example, a simple counter implementation would look like:
$ cat specialFile
0
$ cat specialFile
1
$ cat specialFile
2
I was thinking that specialFile could be a named pipe, but I haven't had much luck. I was also thinking select may help here, but I'm not sure how I would use it. Am I missing some fundamental concept?
#include <stdio.h>
int main(void)
{
char stdoutEmpty;
char counter;
while (1) {
if (stdoutEmpty = feof(stdout)) { // stdout is never EOF (empty)?
printf("%d\n", counter++);
fflush(stdout);
}
}
return 0;
}
Then usage would be something like:
shell 1 $ mkfifo testing
shell 1 $ ./main > testing
shell 2 $ cat testing
# should be 0?
shell 2 $ cat testing
# should be 1?

You need to use FUSE. A FIFO will not work, because either your program keeps pushing content to stdout (in which case cat will never stop), or it closes stdout, in which case you obviously can't write to it anymore.

Related

Sending inputs to C program and printing them

Trying to write a script that takes a file of inputs and sending them one-by-one to a C program whenever the program asks for input (scanf).
I want my script to print every input before it sends it to the program.
The whole output of the C program (including the inputs I provided) should be print to a file.
Looking for a solution without changing my C code.
For ex:
My C Program: test.c
#include <stdio.h>
int main()
{
char a[50];
int b;
printf("Enter your name:\n");
scanf("%s",a);
printf("HELLO: %s\n\n", a);
printf("Enter your age:\n");
scanf("%d",&b);
printf("Your age is: %d\n\n", b);
return 0;
}
My Script: myscript.sh
#!/bin/bash
gcc test.c -o mytest
cat input | ./mytest >> outputfile
I also tried
#!/bin/bash
gcc test.c -o mytest
./mytest < input > outputfile
My Input File: input
Itzik
25
My Output File: outputfile
Enter your name:
HELLO: Itzik
Enter your age:
Your age is: 25
Desired outPutFile:
Enter your name:
Itzik
HELLO: Itzik
Enter your age:
25
Your age is: 25
Thanks a lot!
Oh my .. this is going to be a bit ugly.
You can start the program in the background, with it reading from a pipe, then hijack that pipe and write to it, but only when the program is waiting for input. And before you write to the pipe, you write to standard output.
# Launch program in background
#
# The tail command hangs forever and does not produce output, thus
# prog will wait.
tail -f /dev/null | ./prog &
# Capture the PIDs of the two processes
PROGPID=$!
TAILPID=$(jobs -p %+)
# Hijack the write end of the pipe (standard out of the tail command).
# Afterwards, the tail command can be killed.
exec 3>/proc/$TAILPID/fd/1
kill $TAILPID
# Now read line by line from our own standard input
while IFS= read -r line
do
# Check the state of prog ... we wait while it is Running. More
# complex programs than prog might enter other states which you
# need to take care of!
state=$(ps --no-headers -wwo stat -p $PROGPID)
while [[ "x$state" == xR* ]]
do
sleep 0.01
state=$(ps --no-headers -wwo stat -p $PROGPID)
done
# Now prog is waiting for input. Display our line, and then send
# it to prog.
echo $line
echo $line >&3
done
# Close the pipe
exec 3>&-
I've compiled your source code above to an executable named prog and saved above code into pibs.sh. The result:
$ bash pibs.sh < input
Enter your name:
Daniel
HELLO: Daniel
Enter your age:
29
Your age is: 29
What you are asking is really not possible without writing a program that parses the output from test.c and knows what is a prompt for input, and what is not.
Depending on how complicated your program is, you may have some luck with the chat program (see man chat) or GNU expect.
Your best bet is, as "BobRun" says, to modify your program. No matter how much you don't want to modify your program, it is time to put all those scanf() you might have littered through you code, behind proper input functions like this:
int input_int(const char *prompt)
{
printf ("%s:\n", prompt)
int i = 0;
scanf("%d", &i);
/* Eat rest of line */
int ch;
do
ch = fgetc(stdin);
while (ch != '\n' && ch != EOF)
return i;
}
Now, adding error checking and echoing of input becomes trivial. And your program might become easier to read
Getting rid of that bug/security-hole to happen scanf("%s", ...) would also become easy.
And if you think this is a large job, well suck it up. You should really have done it from the beginning when the job was small. And if you delay the job any more, it will soon be humungus.

Prevent read() systemcall returing with 0 when run as background process

I have a piece of software that is able to read commands from stdin for debug purposes in a separate thread. When my software runs as foreground process read behaves as expected, its blocking and waits for input by the user, i.e the thread sleeps.
When the software is run as a background process, read constantly returns 0 (possible EOF detected?).
The problem here is, that this specific read is in a while(true) loop. It runs as fast as it can and steals precious CPU load on my embedded device.
I tried redirecting /dev/null to the process but the behavior was the same. I am running my custom Linux on an ARM Cortex A5 board.
The problematic piece of code follows and is run inside its own thread:
char bufferUserInput[256];
const int sizeOfBuffer = SIZE_OF_ARRAY(bufferUserInput);
while (1)
{
int n = read(0, bufferUserInput, sizeOfBuffer); //filedes = 0 equals to reading from stdin
printf("n is: %d\n", n);
printf("Errno: %s",strerror(errno));
if (n == 1)
{
continue;
}
if ((1 < n)
&& (n < sizeOfBuffer)
&& ('\n' == bufferUserInput[n - 1]))
{
printf("\r\n");
bufferUserInput[n - 1] = '\0';
ProcessUserInput(&bufferUserInput[0]);
} else
{
n = 0;
}
}
I am looking for a way to prevent read from constantly returning when running in the background and wait for user input (which of course will never come).
If you start your program in the "background" (as ./program &) from a shell script, it's stdin will be redirected from /dev/null (with some exceptions).
Trying to read from /dev/null will always return 0 (EOF).
Example (on linux):
sh -c 'ls -l /proc/self/fd/0 & wait'
... -> /dev/null
sh -c 'dd & wait'
... -> 0 bytes copied, etc
The fix from the link above should also work for you:
#! /bin/sh
...
exec 3<&0
./your_program <&3 &
...
When stdin is not a terminal, read is returning with 0 because you are at the end of the file. read only blocks after reading all available input when there could be more input in the future, which is considered to be possible for terminals, pipes, sockets, etc. but not for regular files nor for /dev/null. (Yes, another process could make a regular file bigger, but that possibility isn't considered in the specification for read.)
Ignoring the various problems with your read loop that other people have pointed out (which you should fix anyway, as this will make reading debug commands from the user more reliable) the simplest change to your code that will fix the problem you're having right now is: check on startup whether stdin is a terminal, and don't launch the debug thread if it isn't. You do that with the isatty function, declared in unistd.h.
#include <stdio.h>
#include <unistd.h>
// ...
int main(void)
{
if (isatty(fileno(stdin)))
start_debug_thread();
// ...
}
(Depending on your usage context, it might also make sense to run the debug thread when stdin is a pipe or a socket, but I would personally not bother, I would rely on ssh to provide a remote (pseudo-)terminal when necessary.)
read() doesn't return 0 when reading from the terminal in a backgrounded process.
It either continues to block while causing a SIGTTIN to be sent to the process (which may break the blocking and cause retval=-1,errno=EINTR to be returned or it causes retval=-1, errno EIO if SIGTTIN is ignore.
The snippet below demonstrates this:
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
int main()
{
char c[256];
ssize_t nr;
signal(SIGTTIN,SIG_IGN);
nr = read(0,&c,sizeof(c));
printf("%zd\n", nr);
if(0>nr) perror(0);
fflush(stdout);
}
The code snippet you've shown can't possibly test reveal 0-returns since you never test for zero-ness in the return value.

Why doesn't stdbuf line buffer the output of some simple c programs

I'm trying to use stdbuf to line buffer the output of a program but I can't seem to make it work as I would expect. Using this code:
#include <stdio.h>
#include <unistd.h>
int main (void)
{
int i=0;
for(i=0; i<10; i++)
{
printf("This is part one");
fflush(stdout);
sleep(1);
printf(" and this is part two\n");
}
return 0;
}
I see This is part one, a one second wait then and this is part two\nThis is part one.
I expected that running it as
stdbuf --output=L ./test.out
would cause the output to be a 1 second delay and then This is part one and this is part two\n repeating at one second intervals. Instead I see the same output as in the case when I don't use stdbuf.
Am I using stdbuf incorrectly or does the call to fflush count as "adjusting" the buffering as described in the sdtbuf man page?
If I can't use stdbuf to line buffer in this way is there another command line tool that makes it possible?
Here are a couple of options that work for me, given the sample code, and run interactively (the output was to a pseudo-TTY):
./program | grep ^
./program | while IFS= read -r line; do printf "%s\n" "$line"; done
In a couple of quick tests, both output a complete line at a time. If you need to do pipe it further, grep's --line-buffered option should be useful.

Cygwin reading input piped in from tail -f

Using Cygwin on Windows, I wanted to have an audible notification of specific messages in a server's log. I wrote the following:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f = fopen("/dev/stdin", "r");
char bar=' ';
if(f==NULL) {
return 1;
}
do {
bar = fgetc(f);
if((bar=='\n') || (bar=='\r')) {
printf("\a");
}
if(bar!=EOF) {
printf("%c", bar);
}
} while(bar!=EOF);
fclose(f);
printf("Done.\n");
return 0;
}
I then ran the following command:
tail -f serverlog | grep myMessage | ./alerty.exe
Sometimes I get notices and sometimes I don't.
My questions are two-fold:
1) What, in my C program, is wrong? Why can't I consistently read the piped input? It's piqued my curiosity so I'm desperate to know.
2) How do I accomplish the original goal of making my system beep as specific text appears in a file?
By default stdin/stdout are line-buffered if they are terminal and block-buffered otherwise. That affects not just your program (actually gets will return immediately when something is available and you are printing lines), but also the grep. It needs --line-buffered flag.
Sed should be able to do the work for you. Try just:
tail -f serverlog | sed -une 's/myMessage/\a&/p'
(-u sets unbuffered—hopefuly cygwin supports it—I am checking on Linux)
stdout is buffered by default, so the output won't necessarily appear immediately. Try inserting a fflush(stdout) right after your printf("\a").
As Jan mentions, you also may be running into buffering issues on stdin. grep has
a --line-buffered option that might help. (tail -f does this on its own, so you shouldn't need to worry about it.)

Reading correctly from a file

During the course of my program,
I pass the output of an execv() to a file, for logging, (using the outCopy() function)
and then print it back on screen to simulate stdout output. (using the printFile() function)
The 2 functions are:
void printFile(char *fileName)
{
char *fileContent=(char *)malloc(200*sizeof(char)); /* sufficiently large buffer */
if((filePtr=fopen(fileName,"r"))==NULL)
{
printf("Error opening %s: %s\n",fileName,strerror(errno));
if( (strcmp(fileName,"/tmp/command.log")==0) || (strcmp(fileName,"/tmp/output.log")==0) ){exitStatus=255;}
}
else
{
while(fscanf(filePtr,"%s",fileContent)!=EOF)
{
printf("%s",fileContent);
printf("%c",fgetc(filePtr));
}
fclose(filePtr);
}
}
void outCopy(char *fileName)
{
char *fileContent=(char *)malloc(200*sizeof(char)); /* sufficiently large buffer */
if( (filePtr=fopen(fileName,"r"))==NULL || (filePtr2=fopen("/tmp/output.log","a"))==NULL )
{
printf("Error opening files: %s\n",strerror(errno));
}
else
{
while(fscanf(filePtr,"%s",fileContent)!=EOF)
{
fprintf(filePtr2,"%s",fileContent);
fprintf(filePtr2,"%c",fgetc(filePtr));
}
fclose(filePtr);
fclose(filePtr2);
}
}
However, my neat little scheme gets disturbed for the output of the ls command:
Expected output:
a.c c.c e.c
b.c d.c
Current output:
a.c
b.c
c.c
d.c
e.c
How can I change either or both of my functions to get the proper output?
(Please don't suggest using pipes or tees, or I will have to change a major portion of my exec() calling child)
Edit: Please note that both the outCopy() & the printFile() are run by the parent. Output has already been dup2() ed to the required temp file by the child.
Some versions of ls (including the GNU version used in Linux) detect whether they are being run with a terminal or with a pipe as standard output, and change their formatting. If you want exactly the same output, you'll need to create a pseudo-TTY (pty) using the posix_openpt call and friends. Or you can use the script utility, which takes care of this for you.
Another option is to use the -C option to ls to force columnar layout; however, this may not be exactly the same, as ls won't know the width of your terminal, and may assume the wrong width. Additionally, other features such as colored output may be missing.
When stdout is not a tty, ls changes behavior from user-friendly columns to script-friendly lists. The flag ls -C forces columnar output regardless of the type of device stdout is attached to.

Resources