legacy/libisoburn/trunk/test/frontend_pipes_xorriso.c

231 lines
6.7 KiB
C

/* Beefed-up example from man 2 pipe
to illustrate how xorriso is to be used by frontend programs via two pipes.
Build:
cc -g -o frontend_pipes_xorriso frontend_pipes_xorriso.c
Usage:
./frontend_pipes_xorriso [path_to_xorriso_binary]
*/
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Local helpers of parent process */
int await_all_replies(int fd, char *pending_mark);
int prompt_for_command(char *line, int line_size);
/* Parent and child */
int main(int argc, char *argv[])
{
int command_pipe[2], reply_pipe[2];
pid_t cpid;
char *xorriso_path = "/usr/bin/xorriso";
if (argc > 1)
xorriso_path = argv[1];
if (pipe(command_pipe) == -1)
{ perror("pipe"); exit(1); }
if (pipe(reply_pipe) == -1)
{ perror("pipe"); exit(1); }
cpid = fork();
if (cpid == -1)
{ perror("fork"); exit(2); }
if (cpid == 0) {
/* Child redirects stdin and stdout. Then it becomes xorriso. */
char *xargv[8];
close(command_pipe[1]); /* Close unused write end */
close(reply_pipe[0]); /* Close unused read end */
/* Attach pipe ends to stdin and stdout */
close(0);
if (dup2(command_pipe[0], 0) == -1)
{ perror("dup2(,0)"); exit(1); }
close(1);
if (dup2(reply_pipe[1], 1) == -1)
{ perror("dup2(,1)"); exit(1); }
xargv[0] = xorriso_path;
xargv[1] = "-dialog";
xargv[2] = "on";
xargv[3] = "-pkt_output";
xargv[4] = "on";
xargv[5] = "-mark";
xargv[6] = "0"; /* corresponds to mark_count = 0 in parent */
xargv[7] = NULL;
execv(xorriso_path, xargv);
perror("execv"); exit(1);
} else {
/* Parent prompts user for command lines and prints xorriso replies.
It knows when all reply text of the pending command line has arrived
by watching for -mark reply pending_mark.
*/
int mark_count = 0, ret;
char pending_mark[16], line[4096];
close(command_pipe[0]); /* Close unused read end */
close(reply_pipe[1]); /* Close unused write end */
/* Dialog loop */
sprintf(pending_mark, "%d", mark_count);
while (1) {
/* Wait for pending mark and print all replies */
ret = await_all_replies(reply_pipe[0], pending_mark);
if (ret < 0)
break;
/* Prompt for command line */
ret = prompt_for_command(line, sizeof(line));
if (ret <= 0)
break;
/* Send line and -mark command */
ret = write(command_pipe[1], line, strlen(line));
if (ret == -1) {
perror("write");
break;
}
/* Produce new unique -mark text to watch for */
mark_count++;
sprintf(pending_mark, "%d", mark_count);
sprintf(line, "-mark %s\n", pending_mark);
ret = write(command_pipe[1], line, strlen(line));
if (ret == -1) {
perror("write");
break;
}
}
/* >>> if child is still operational: send -rollback_end */;
/* >>> wait a short while */;
/* >>> if not yet ended: kill child */;
wait(NULL); /* Wait for child */
exit(0);
}
}
/* Local helpers of parent process */
int await_all_replies(int fd, char *pending_mark)
{
int count, remainder = 0;
char buf[32769], *line, *npt;
while (1) {
count = read(fd, buf + remainder, sizeof(buf) - 1 - remainder);
if (count == -1) {
perror("read");
return(-1);
}
if (count == 0) {
fprintf(stderr, "+++ EOF encounterd by Master process\n");
return(-2);
}
for (npt = buf + remainder; npt < buf + count; npt++) {
if (*npt == 0) {
fprintf(stderr,
"+++ Protocol error : Reply contains 0-chars\n");
return(-1);
}
}
/* Split buf into lines */
buf[remainder + count] = 0; /* for convenience */
line = buf;
while (1) {
npt = strchr(line, '\n');
if (npt == NULL) {
/* Move line to start of buffer and set remainder */
if (line != buf) {
remainder = 0;
for (npt = line; *npt; npt++)
buf[remainder++] = *npt;
}
/* Now read more data in the hope to get a newline char */
break;
}
/* Interpret line */
*npt = 0;
if (line[0] == 'M') {
/* M-replies will be outdated until the pending command line
is completely done and the appended -mark command gets
into effect.
*/
if (strlen(line) < 6) {
fprintf(stderr,
"+++ Protocol error : M-channel line shorter than 6 chars\n");
return(-1);
}
if (strcmp(line + 5, pending_mark) == 0) {
if ((line - buf) + strlen(line) + 1 < count) {
fprintf(stderr,
"+++ Protocol error : Surplus reply data after M-match\n");
fprintf(stderr, "%s\n", line + strlen(line) + 1);
return(-1);
}
return (1); /* Expected mark has arrived */
}
} else if (line[0] == 'R') {
/* R-replies are result lines of inquiry commands, like -ls.
They should be handled by specialized code which knows
how to parse and interpret them.
*/
printf("%s\n", line);
} else {
/* I-replies are pacifiers, notifications, warnings, or
error messages. They should be handled by a general
message interpreter which determines their severity
and decides whether to bother the user.
*/
fprintf(stderr, "%s\n", line);
}
line = npt + 1;
}
}
return(1);
}
int prompt_for_command(char *line, int line_size)
{
int l;
char *line_res;
fprintf(stderr, "+++ Enter a command and its parameters :\n");
line_res = fgets(line, line_size - 1, stdin);
if (line_res == NULL)
return(0);
l = strlen(line);
if (l == 0) {
line[0] = '\n';
line[1] = 0;
} else if (line[l - 1] != '\n') {
line[l] = '\n';
line[l + 1] = 0;
}
return(1);
}