How to pipe stdout to external app, internally within my code? C - c

I've currently written a udp client, which simply listens on specified port, for packets destined to a specific multicast group.
at the end, i'm printing the input to stdout in the following manner:
write(STDOUT_FILENO, buffer, num_of_bytes);
And executing the program in the following manner:
./udp_listen 224.10.10.10 4567 | mpg321 -
That way all output is piped to mpg321 app, which plays the stream of bytes as music.
The above implementation, is of course making me kind of "lose control" over my program, as it opens mpg321 app and plays.
I want to avoid this, and in someway, pipe the write(....) into mpg321, directly within my program.
How can one achieve this? I'm coding in C.
Thank you.

Thanks #kaylum for providing the answer i was looking for.
i've used popen with the command to initiate mpg321 , with redirecting its stderr output to a file.
After that i've used fileno() method to get the file descriptor number,
to be used with write() calls.
Worked great.
Thanks

Related

How to create an attachable CLI (terminal) for daemon?

Problem
I would like to program an attachable command line interface for my daemon.
I developped a daemon running 24/7 on Linux Openwrt:
#!/bin/sh /etc/rc.common
START=98
USE_PROCD=1
PROCD_DEBUG=1
start_service() {
procd_open_instance
procd_set_param command "/myProgram"
procd_set_param respawn
procd_close_instance
}
I would like to add a debug user interfaces for test. So we could live tune some parameters/actions and print log. Something like the screen package.
Hence i want to create a command line interface for this daemon.
Research
Stdin/Stdout
Ideally i would like to write directly to the stdin of the daemon and read the stdout.
Daemon
Duplicate stdin to a file.
Duplicate stoud to a file.
Client
A launched C program by the tester.
It would relay stdin to stdinfile of daemon and stdoutfile of daemon to stdout.
Critic
That would be maybe the simplest way and I could read stdout.
I couldn't find any exemples, it makes me think i'm overlooking something.
Theres a risk I fill the flash by writing endlessly to the stdoutfile.
Pipes
The creation of 2 named pipe can be possible.
Daemon
The daemon would create a named input pipe and poll the pipe by making non blocking read.
A second output pipe is necessary to write the return of the command received.
Client
A launched C program by the tester.
It would relay stdin to input pipe and output pipe to stdout.
Critic
I don't know if I can properly redirect the stdout of the daemon to output pipe. Which means I wont be able to print the stdout logs but only specific cli coded response.
MessageQ
Same issues as pipe.
Sockets
Seems rather complex for a simple application.
Shared Memory
The paradigm does not seems appropriate.
Pty
Maybe something can be done with pseudo terminals but I don't understand them even after reading explanations: attach a terminal to a process running as a daemon (to run an ncurses UI)
Screen/Tmux
I don't have screen or tmux in my repository.
Question
What is the proper way to create a CLI for a daemon ? Where could I find an exemple ?
I would use a Unix domain stream socket, with the CLI thread in a blocking accept() until a connection is obtained.
These sockets are bidirectional, and you can write a trivial CLI application to read from standard input to the connected socket, and from the connected socket to standard output. (That same trivial CLI program could be used to redirect the output over e.g. SSH to ones local computer with much more storage, running the CLI program remotely using something like ssh -l username openwrt-device.name-or-address cli-program | tee local-logfile. OpenWrt devices often don't have suitable storage for log files, so this can be very useful.)
Use vdprintf() to implement your own printf() that writes to the connected CLI.
Because sockets are bidirectional, if you want to use locking –– for example, to avoid mixing logging output and CLI responses ––, use a mutex for writing; the read side does not need to take the mutex at all.
You cannot really use <stdio.h> FILE * stream handles for this, because its internal buffering can yield unexpected results.
Assuming your service daemon uses sockets or files, it can be very useful to reserve the file descriptor used for the bidirectional CLI connection, by initially opening /dev/null read-write (O_RDWR). Then, when the connection is accept()ed, use dup2() to move the accepted connection descriptor to the reserved one. When the connection is to be closed, use shutdown(fd, SHUT_RDWR) first, then open /dev/null, and dup that descriptor over the connection to be closed. This causes the connection to be closed and the descriptor to be reopened to /dev/null, in an atomic manner: the descriptor is never "unused" in between. (If it is ever close()d in a normal manner, another thread opening a file or socket or accepting a new connection may reuse that descriptor, causing all sorts of odd effects.)
Finally, consider using an internal (cyclic) buffer to store the most recent output messages. You do not need to use a human-readable format, you can use e.g. the first character (codes 1 to 254) to encode the severity or log level, keeping NUL (0) as the end-of-string mark, and 255 as the "CLI response" mark, so that your CLI program can use e.g. ANSI colors to color the output if output is a terminal. (For example, "\033[1;31m" changes output to bright red, and "\033[0m" returns the output back to normal/default. The \033 refers to a single character, code 27, ASCII ESC.) This can be very useful to efficiently indicate the priority/severity of each separate output chunk to the human user. The Linux kernel uses a very similar method in its kernel logging facility.

Outputting to multiple terminals

I'm parsing a large log file. I would like to pull out particular messages based on a severity classification (critical, warning, etc). As I am parsing the log I would like to send messages, based on their severity, to a given, spawned, severity-specific, terminal. The terminals should not close when the main program finishes reading the log file. Environment is solaris 10/gcc 3.4.6. I found the following example that captures what I was thinking of, but doesn't quite work (xterm spawns, but no output is sent to it):
#include <stdio.h>
int main()
{
FILE *output;
int i;
output = popen ("xterm", "w");
for (i = 0; i < 10; i++)
fprintf (output, "%d\n", i);
pclose (output);
}
I'm not married to xterm, I simply used it as handy and I do like the ability to title, color and size them. I sort of get that writing to the handle generated by popen is not the same as writing to the terminal's output (just sort of...). This seems like an easy thing to do.
in general, what can be done is:
1) adjust your application so it can accept a parameter that indicates what level of severity to output to stdout.
2) open three terminals from the keyboard
3) run your application in each terminal, giving each execution the appropriate command line parameter
if your going to open the terminals from your application, for 'xterm' and others, the --hold parameter will stop the terminal from closing when you application exits
The idea of the pipe sounds reasonable, but there are a few problems:
you cannot, of course, simply write to a newly-spawned terminal via a pipe. xterm will ignore that; it is the application running within xterm which reads/writes from the pseudo-terminal.
there is no way to scroll back in the messages sent to a given terminal
the suggested writes to the pty device cannot be captured by a program running in the terminal
Rather than sending to a terminal, you might consider getting xless (a simple X application which might already be part of a package, but is simple enough to build), and structuring your output function to do this:
for each message category, open a pipe to xless once
write the message
do not close the pipe
That would give you windows which do not close. Here is a sample screenshot:
The source can be found on ftp.x.org, as noted in the Debian package description.
Thank you all for the great responses, I do appreciate them!
OK, sounds like a slight re-design is called for =) I did a quick prototype and it looks like it will work. Will write the output to separate severity files, then when complete, pop up an xterm for each file, something like
sprintf (Crit, "xterm <yadda yadda> -e sh -c 'cat <crit-log>; <yadda yadda>');
popen (Crit, "r");
Writing to intermediate log files is actually a bonus should they need to be reviewed at a later time without having to go through the large-log-parsing program again.
Thanks again everyone!

redirection to multiple ttys in c

I see that I can do freopen to redirect stdout going to a console to one another tty. I am trying to redirect the same to multiple terminals including the console. Console is where the program is running. What is the best way to do it?
TIA
You didn't specify what platform you're using, but assuming you can find the file path to the TTY you'd like to redirect to, you can call freopen on the stdout file descriptor. However, that would close the initial file descriptor, which doesn't sound like your desired behavior. A file descriptor can only point to one file.
The easiest C solution is probably going to be a wrapper around printf that calls it on all of your specified files. You might be able to do something with threading, but that's likely to complicate things.
If you're on a *nix system, I suggest using tee which is made for outputting to stdout and secondary files.
There is no really easy way to do this like with freopen. You need some wrapper that takes the input and writes it to each output tty individually.
For example there is the tee program that multiplexes its input to stdout and a number of files. You could for example create a pipe in C that is connected to tee /dev/ttyX /dev/ttyY .... Then you can replace stdout with the pipe file descriptor and you will get the desired behaviour.

How to printf part of command line command

Hello I am currently trying to printf a certain part of the command line when i run my program. I currently run my program as follows
zcat gcc | sim
What i am trying to accomplish is print out to a seperate file the 'gcc' part of the command line. Is there any way to accomplish this. Thanks for the help
I forgot to mention this is in c not C++
The 'sim' program only knows that it has data from stdin. It doesn't know what is handing the data to stdin - it may be another program, or redirected input, or from a device.
From 'sim' POV, there's only data from stdin.
IF you can guarantee that you will always receive data from another process via a pipe, you can start looking for process headers matching the 'sim' process, and from then extracting process info from associated processes. However, I suspect that this is more than you're willing to go.
You are passing output of zcat (through pipe) to your program, it doesn't know details of arguments passed to zcat.
You can explicitly pass it as a part of input stream though,
(echo 'zcat gcc'; zcat gcc ) | sim
but that is a hack. It may be Ok if you are planning to run your
program this way only.

ftp client controlled by pipe in C

I am trying to control ftp client from C program (OS X). I did fork and execve - process is started ok. The problem is with pipes - I can send command to ftp client process and get feedback from it just fine (If i send "help\n" i get back help output) but what I never get in pipe is "ftp> " prompt. Any ideas?
Ivan
Your ftp client is probably behaving differently if stdin/stdout is a terminal or something else (lots of program do, for a start the C library does buffering in a different way...) If you want to control that, search information about pseudo-terminals, that's a little too technical to be explained here. (And looks first at programs like expect, it's possible you won't have to write yours).
A program can examine stdin to find out whether it's a terminal or a pipe. In your case, the FTP program probably does that (for example to know whether it can use escape sequences to render progress bars or offer command line editing).
If you really need the prompt, you have to look into PTYs (pseudo terminals) which emulate a console.
wild guess: isn't the "ftp>" prompt written to STDERR ?

Resources