libisoburn/test/frontend_pipes_xorriso.c

236 lines
7.0 KiB
C

/* Beefed-up example from man 2 pipe
to illustrate how xorriso is to be used by frontend programs via two pipes.
Copyright 2012 Thomas Schmitt, <scdbackup@gmx.net>
Unaltered provided under BSD license.
You may issue licenses of your choice for derived code, provided that they
do not infringe anybody's right to do the same for this original code.
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);
}