2012-09-09 18:18:11 +00:00
|
|
|
|
|
|
|
/* Beefed-up example from man 2 pipe
|
|
|
|
to illustrate how xorriso is to be used by frontend programs via two pipes.
|
|
|
|
|
2012-09-11 12:31:01 +00:00
|
|
|
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.
|
|
|
|
|
2012-09-09 18:18:11 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|