Proof-of-concept of a GUI frontend program. Written in Tcl/Tk.
This commit is contained in:
parent
5e6a20e5b0
commit
3cfa0dd380
@ -172,6 +172,11 @@ xorriso_make_xorriso_1_CFLAGS =
|
|||||||
xorriso_make_xorriso_1_LDADD =
|
xorriso_make_xorriso_1_LDADD =
|
||||||
xorriso_make_xorriso_1_SOURCES = xorriso/make_xorriso_1.c
|
xorriso_make_xorriso_1_SOURCES = xorriso/make_xorriso_1.c
|
||||||
|
|
||||||
|
# A Proof-of-concept for frontends
|
||||||
|
bin_SCRIPTS = \
|
||||||
|
frontend/xorriso-tcltk
|
||||||
|
|
||||||
|
|
||||||
## ========================================================================= ##
|
## ========================================================================= ##
|
||||||
|
|
||||||
## Build documentation (You need Doxygen for this to work)
|
## Build documentation (You need Doxygen for this to work)
|
||||||
@ -244,7 +249,8 @@ EXTRA_DIST = \
|
|||||||
doc/partition_offset.wiki \
|
doc/partition_offset.wiki \
|
||||||
doc/qemu_xorriso.wiki \
|
doc/qemu_xorriso.wiki \
|
||||||
doc/startup_file.txt \
|
doc/startup_file.txt \
|
||||||
test/frontend_pipes_xorriso.c \
|
frontend/frontend_pipes_xorriso.c \
|
||||||
|
frontend/README-tcltk \
|
||||||
README \
|
README \
|
||||||
AUTHORS \
|
AUTHORS \
|
||||||
CONTRIBUTORS \
|
CONTRIBUTORS \
|
||||||
|
@ -149,6 +149,28 @@ So after installation of a binary libisoburn package you may find it e.g. as
|
|||||||
/usr/include/libisoburn/xorriso.h
|
/usr/include/libisoburn/xorriso.h
|
||||||
|
|
||||||
|
|
||||||
|
xorriso under control of a (GUI) frontend process
|
||||||
|
|
||||||
|
The dialog mode allows frontend programs to connect via pipes to the standard
|
||||||
|
input and output of xorriso. Several commands of xorriso help with receiving
|
||||||
|
and parsing of reply messages.
|
||||||
|
|
||||||
|
As a proof of concept, there is the Tcl/Tk script xorriso-tcltk which can
|
||||||
|
be launched by this shell command:
|
||||||
|
|
||||||
|
xorriso -launch_frontend $(which xorriso-tcltk) --stdio --
|
||||||
|
|
||||||
|
See file frontend/README-tcltk for a description of its GUI.
|
||||||
|
See its Tcl code for getting an idea how this gets achieved.
|
||||||
|
|
||||||
|
Further there is the C program frontend/frontend_pipes_xorriso.c which
|
||||||
|
forks a xorriso process and shows the same communication gestures as
|
||||||
|
xorriso-tcltk.
|
||||||
|
In particular it connects to xorriso via two pipes, sends commands, waits
|
||||||
|
for all replies of a command, picks info out of the xorriso message sieve,
|
||||||
|
and parses reply message lines into words.
|
||||||
|
|
||||||
|
|
||||||
Drives and Disk File Objects
|
Drives and Disk File Objects
|
||||||
|
|
||||||
The user of libisoburn applications needs operating system dependent
|
The user of libisoburn applications needs operating system dependent
|
||||||
|
291
libisoburn/trunk/frontend/README-tcltk
Normal file
291
libisoburn/trunk/frontend/README-tcltk
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
------------------------------------------------------------------------------
|
||||||
|
xorriso-tcltk
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2012, Thomas Schmitt <scdbackup@gmx.net>, libburnia-project.org
|
||||||
|
Provided under GNU GPL version 2 or later.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
xorriso-tcltk is mainly a proof of concept for a frontend that operates
|
||||||
|
xorriso in dialog mode.
|
||||||
|
|
||||||
|
It exercises several fundamental gestures of communication:
|
||||||
|
- connecting via two pipes
|
||||||
|
- sending commands
|
||||||
|
- receiving replies
|
||||||
|
- inquiring the xorriso message sieve
|
||||||
|
- using the xorriso parsing service
|
||||||
|
|
||||||
|
Note that any other language than Tcl/Tk could be used, if it only can
|
||||||
|
do i/o via standard input and standard output or via named pipes.
|
||||||
|
Further it has to perform integer arithmetics and string manipulations.
|
||||||
|
And, well, a graphical widget set would be nice.
|
||||||
|
|
||||||
|
See man xorriso for a documentation of xorriso concepts and commands.
|
||||||
|
See man xorrecord for details of the burn image file feature.
|
||||||
|
|
||||||
|
|
||||||
|
Quick start:
|
||||||
|
|
||||||
|
xorriso -launch_frontend $(which xorriso-tcltk) --stdio --
|
||||||
|
|
||||||
|
|
||||||
|
The Tcl shell "wish" is allergic to options which start by "-h".
|
||||||
|
So here is the output of xorriso-tcltk --help :
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
Usage:
|
||||||
|
xorriso-tcltk [options]
|
||||||
|
Options:
|
||||||
|
All options must be given with two dashes ("--option") in
|
||||||
|
order to distinguish them from any options of the Tcl shell.
|
||||||
|
--help
|
||||||
|
Print this text and exit.
|
||||||
|
--stdio
|
||||||
|
Establishes connection to xorriso via stdin and stdout.
|
||||||
|
E.g. when letting xorriso start this frontend program:
|
||||||
|
xorriso -launch_frontend $(which xorriso-tcltk) --stdio --
|
||||||
|
--named_pipes cmd_fifo reply_fifo
|
||||||
|
Establishes connection to a xorriso process started by:
|
||||||
|
xorriso -dialog on <cmd_fifo >reply_fifo
|
||||||
|
which is then ready for a run of:
|
||||||
|
xorriso-tcltk --named_pipes cmd_fifo reply_fifo
|
||||||
|
It is important that the parent of xorriso and of this
|
||||||
|
tcl/tk frontend opens the named pipe for commands before
|
||||||
|
it opens the named pipe for replies. This avoids deadlock.
|
||||||
|
--geometry {+|-}X{+|-}Y
|
||||||
|
Sets the position of the main window.
|
||||||
|
--click_to_focus
|
||||||
|
Chooses that input fields and list boxes get the keyboard
|
||||||
|
focus only when being clicked by the mouse.
|
||||||
|
--auto_focus
|
||||||
|
Chooses that the keyboard focus is where the mouse
|
||||||
|
pointer is. (Default)
|
||||||
|
--log_file path
|
||||||
|
Set a file address for logging of xorriso commands and
|
||||||
|
reply messages. The log lines will be appended.
|
||||||
|
|
||||||
|
Either --stdio or --named_pipes must be given for a program run.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Overview of GUI elements
|
||||||
|
|
||||||
|
The window is separated into three main areas:
|
||||||
|
- Connection to xorriso.
|
||||||
|
- Management of drives and image files.
|
||||||
|
- Inspection, manipulation, and exploitation of xorriso ISO image model.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Connection to xorriso
|
||||||
|
|
||||||
|
The "End" button leads to the end of frontend and xorriso process.
|
||||||
|
|
||||||
|
The ready/busy field indicates whether a xorriso command is being executed
|
||||||
|
and the frontend is still waiting for its reply messages.
|
||||||
|
|
||||||
|
The "Command:" field can be used to send commands to xorriso.
|
||||||
|
|
||||||
|
The "Refresh state display" button causes the other two main areas to update
|
||||||
|
their display after manually transmitted commands may have changed the state
|
||||||
|
of drives or ISO model.
|
||||||
|
|
||||||
|
The "Log pipes" switch controls whether all xorriso commands and replies
|
||||||
|
shall be logged to standard error resp. to the file that has been iven
|
||||||
|
with program argumen --log_file. Caution: This log is verbous.
|
||||||
|
|
||||||
|
The message box displays commands sent to xorriso and messages recieved
|
||||||
|
from xorriso.
|
||||||
|
Many commands which are emitted by the GUI will hide themselves and their
|
||||||
|
replies from this display.
|
||||||
|
All event messages with severity WARNING or higher will show up, nevertheless.
|
||||||
|
|
||||||
|
The "Recent problem:" field shows the most severe event message that occured
|
||||||
|
during the execution of the most recent command. It also displays the most
|
||||||
|
recent problem message from the frontend program itself.
|
||||||
|
Several commands emitted by the GUI will not clear this display. But any
|
||||||
|
manually transmitted command and the major GUI gestures will do.
|
||||||
|
|
||||||
|
The "Worst problem:" field shows the most severe event message that occured
|
||||||
|
since last time the "Clear" button was hit. It will not clear automatically.
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Management of drives and image files
|
||||||
|
|
||||||
|
The "Scan for drives" button executes command -devices and puts the list
|
||||||
|
of found optical drives into the box underneath the button.
|
||||||
|
|
||||||
|
The "Pick input drive" button executes command -indev and obtains some
|
||||||
|
information about the medium status. This info is displayed in the
|
||||||
|
"Input drive or image" line.
|
||||||
|
Further it causes the display of the ISO image model to be updated.
|
||||||
|
|
||||||
|
The "Pick output drive" button executes command -outdev and displays the
|
||||||
|
related info in the "Output drive or image" line.
|
||||||
|
|
||||||
|
The "Pick drive for both roles" button executes command -dev and displays
|
||||||
|
info in both "... drive or image" lines.
|
||||||
|
|
||||||
|
The "Give up drives" executes commands -indev "" -outdev "" and clears
|
||||||
|
both "... drive or image" lines, as well as the ISO model.
|
||||||
|
|
||||||
|
The "Calm drives" button executes command -calm_drives which tells the
|
||||||
|
aquired optical drives to stop spinning until the next drive activity
|
||||||
|
gets triggered.
|
||||||
|
|
||||||
|
The "Rollback" button excutes command -rollbackwhich drops all pending
|
||||||
|
changes of the ISO model and reloads it from the input drive, if one is
|
||||||
|
aquired.
|
||||||
|
|
||||||
|
The box underneath these buttons shows the optical drives found by the
|
||||||
|
"Can for drives" button.
|
||||||
|
A double-click on a drive item has the same effect as button "Pick drive
|
||||||
|
for both roles".
|
||||||
|
|
||||||
|
The line "Input drive or image" displays address and medium status of
|
||||||
|
the input drive.
|
||||||
|
Its "Eject" button excutes command -eject "in".
|
||||||
|
Editing the drive address and pressing the Return key causes the execution
|
||||||
|
of command -indev with the field content as drive address. Use this to
|
||||||
|
load the model from ISO image data files on hard disk.
|
||||||
|
|
||||||
|
The line "Output drive or image" does about the same for the output drive.
|
||||||
|
The text input field can be used to address an existing ISO image data
|
||||||
|
file or to address a data file that does not yet exist. In the latter
|
||||||
|
case, the ,edium status will be blank.
|
||||||
|
|
||||||
|
The "Blank" button executes command -blank "as_needed" on the output drive.
|
||||||
|
This also applies to ISO image data files, which will get invalidated by
|
||||||
|
a small write operation.
|
||||||
|
|
||||||
|
The "Format" button executes -format "as_needed".
|
||||||
|
This only applies to real optical drives and s of interest only with DVD-RW
|
||||||
|
or BD-R media, which both can be used formatted and unformatted. Other media
|
||||||
|
types which mandatorily need formatting will be formatted by the write
|
||||||
|
commands.
|
||||||
|
|
||||||
|
The "Write ISO session" executes command -commit, which writes a session
|
||||||
|
with all pending changes to the output drive. The output drive must be
|
||||||
|
either blank or it must be the same as the input drive.
|
||||||
|
|
||||||
|
The "Close" switch controls whether command -close "on" is emitted with
|
||||||
|
"Write ISO session" or whether -as cdrecord option -multi is omitted with
|
||||||
|
"Burn image file:".
|
||||||
|
|
||||||
|
The "TAO" switch controls whether an incremental write type shall be
|
||||||
|
enforced with write commands. Normally xorriso will decide by medium status
|
||||||
|
and job parameters which write type to choose.
|
||||||
|
|
||||||
|
The "Defect Mgt" switch controls whether slow and error-prone drive internal
|
||||||
|
check reading shall be enabled with formatted BD-R or with BD-RE.
|
||||||
|
|
||||||
|
The "Burn image file:" button executes command -as "cdrecord" with the
|
||||||
|
content of its text field as disk file address of a data file that is
|
||||||
|
to be written to the output drive.
|
||||||
|
The medium in the drive may be blank or appendable.
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Inspection, manipulation, and exploitation of xorriso ISO image model
|
||||||
|
|
||||||
|
The "Extract to disk:" button executes command -extract with the whole
|
||||||
|
tree of the current ISO directory or with the selected items of the box
|
||||||
|
underneath "ISO directory:".
|
||||||
|
This copies the selected files or directory trees from the input drive
|
||||||
|
to the address on hard disk which is given by the text filed right of
|
||||||
|
the button.
|
||||||
|
|
||||||
|
The "Underneath" switch controls the effective hard disk address of an item
|
||||||
|
if the address in the text field points to a directory. If "Underneath"
|
||||||
|
is enabled, then the file object from the ISO filesystem will be copied to its
|
||||||
|
name underneath the hard disk directory.
|
||||||
|
If "Underneath" is disabled then an ISO directory tree item will be merged
|
||||||
|
with the disk directory tree at the given address.
|
||||||
|
Example:
|
||||||
|
Selected are "/iso_dir" and "/iso_file".
|
||||||
|
Address for hard disk is "/tmp/from_iso". Switch "Selected" is enabled.
|
||||||
|
"Underneath" enabled causes commands:
|
||||||
|
-extract /iso_dir /tmp/from_iso/iso_dir
|
||||||
|
-extract /iso_file /tmp/from_iso/iso_file
|
||||||
|
"Underneath" disabled:
|
||||||
|
-extract /iso_dir /tmp/from_iso
|
||||||
|
-extract /iso_file /tmp/from_iso
|
||||||
|
The last command will fail because /tmp/from_iso already exists as directory.
|
||||||
|
|
||||||
|
The "Selected" switch controls whether the whole current ISO directory,
|
||||||
|
or only the selected items shall be copied to to hard disk.
|
||||||
|
|
||||||
|
The "Overwrite files" switch controls whether existing files may be
|
||||||
|
overwritten in the ISO image or by extraction on hard disk.
|
||||||
|
The frontend program will only detect the most obvious name collisions,
|
||||||
|
but xorriso will reliably refuse to overwrite files if this is banned.
|
||||||
|
|
||||||
|
The "Overwrite ISO dirs" switch controls whether it is allowed to replace
|
||||||
|
an ISO directory by a non-directory file.
|
||||||
|
If a directory is copied to a directory, then both directory trees will
|
||||||
|
be merged. So this switch applies only to situations where non-directories
|
||||||
|
hit directories.
|
||||||
|
|
||||||
|
The "Enforce disk dir write access" switch enables the options "auto_chmod_on"
|
||||||
|
and "sort_lba_on". "auto_chmod_on" allows xorriso to give itself temporariy
|
||||||
|
w-permission to all disk directories which are owned by the xorriso user.
|
||||||
|
This is not without dangers, of course, but comes in handy with restoring of
|
||||||
|
backups.
|
||||||
|
Option "sort_lba_on" reduces head-moves of optical drives and thus can
|
||||||
|
speed up extraction substantially. It is bound to "auto_chmod_on" because
|
||||||
|
else it might get in trouble when restoring ISO directories which offer
|
||||||
|
no w-permission.
|
||||||
|
|
||||||
|
The "Refresh avail:" button triggers a time consuming exact prediction
|
||||||
|
of the free space on the medium in the output drive. For this purpose,
|
||||||
|
the size of an ISO session with the pending changes is computed.
|
||||||
|
With image files rather than real optical drives, the free space of
|
||||||
|
the hosting filesystem is displayed.
|
||||||
|
|
||||||
|
The "Insert from disk:" button executes command -map with the disk file
|
||||||
|
address that is given by the text field right to the button.
|
||||||
|
|
||||||
|
The switch "Underneath" has the same effect as with file extraction:
|
||||||
|
If enabled, a directory from disk will not be unpacked to its single files
|
||||||
|
but put underneath the target address by its own leaf name.
|
||||||
|
If the switch "Selected" is enabled, then the given disk file or tree will
|
||||||
|
be inserted at or underneath the only selected item in the box inderneath
|
||||||
|
"ISO directory:".
|
||||||
|
|
||||||
|
The text field in the "ISO directory:" line displays the current ISO
|
||||||
|
directory and can be used to toggle its path directly. Hitting the
|
||||||
|
Return key causes the current directory to change and the display in
|
||||||
|
the box underneath to be refreshed.
|
||||||
|
|
||||||
|
The "Up" buttons move the current ISO directory one directory level up.
|
||||||
|
|
||||||
|
The "Verify" button executes -md5_check_r "SORRY" with the current ISO
|
||||||
|
directory. ISO images bear MD5s for each data file if they were produced
|
||||||
|
by xorriso with -md5 "on" resp. -for_backup. This frontend enables this
|
||||||
|
feature on startup.
|
||||||
|
|
||||||
|
The list box underneath the "ISO directory:" line displays the files in
|
||||||
|
the current ISO directory. One or more item can be selected and play a
|
||||||
|
role with extraction or insertion of files.
|
||||||
|
Most of the buttons underneath the box operate on the selected items
|
||||||
|
unconditionally.
|
||||||
|
|
||||||
|
The "Verify" button in the "ISO selection:" line executes command
|
||||||
|
-md5_check_r "SORRY" with each of the selected items.
|
||||||
|
|
||||||
|
The "Delete" button executes command -rm_r with each of the selected items.
|
||||||
|
|
||||||
|
The "Rename to:" button iuses command -mv to move each of the selected
|
||||||
|
items to the address that is given by the text field right to the button.
|
||||||
|
If this address points to an existing ISO directory, then the items will
|
||||||
|
be moved underneath that directory and keep their leaf names.
|
||||||
|
Else there may be only one selected item which will be renamed to the
|
||||||
|
given address.
|
||||||
|
|
||||||
|
The "Make dir" button executes command -mkdir with the address in the
|
||||||
|
text field to its left (the same as used by "Rename to:"). Useful to
|
||||||
|
create a target directory before moving the selection.
|
||||||
|
|
980
libisoburn/trunk/frontend/frontend_pipes_xorriso.c
Normal file
980
libisoburn/trunk/frontend/frontend_pipes_xorriso.c
Normal file
@ -0,0 +1,980 @@
|
|||||||
|
|
||||||
|
/* Beefed-up example from man 2 pipe
|
||||||
|
to illustrate how xorriso is to be used by frontend programs via two pipes.
|
||||||
|
Additionally there is a standalone implementation of Xorriso_parse_line().
|
||||||
|
|
||||||
|
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 | -h]
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int usage()
|
||||||
|
{
|
||||||
|
static char helptext[][80] = {
|
||||||
|
"usage: frontend_pipes_xorriso [path_to_xorriso|-h]",
|
||||||
|
"",
|
||||||
|
"Forks a process that runs xorriso and communicates with it via two pipes.",
|
||||||
|
"The command pipe sends payload commands and -mark commands. The reply pipe",
|
||||||
|
"receives -pkt_output lines which it dispatches to stdout and stderr.",
|
||||||
|
"The communication between both processes is made synchronous by the parent",
|
||||||
|
"awaiting the -mark message of the child.",
|
||||||
|
"Optionally the reply lines can be parsed into words. This is initiated by",
|
||||||
|
"meta command",
|
||||||
|
" @parse [prefix [separators [max_words [flag]]]]",
|
||||||
|
"which sets the four parameters for a function equivalent to",
|
||||||
|
"Xorriso_parse_line() (see xorriso.h). All reply will then be parsed and",
|
||||||
|
"non-empty word arrays are displayed. Meta command",
|
||||||
|
" @noparse",
|
||||||
|
"ends this mode.",
|
||||||
|
"Meta command",
|
||||||
|
" @drain_sieve",
|
||||||
|
"reports all recorded results of all installed message sieve filter rules.",
|
||||||
|
"For illustration perform this xorriso command sequence",
|
||||||
|
" -msg_op start_sieve - -outdev /dev/sr0 -msg_op clear_sieve - -toc",
|
||||||
|
"and then @drain_sieve.",
|
||||||
|
"@END@"
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; strcmp(helptext[i], "@END@") != 0; i++)
|
||||||
|
fprintf(stderr, "%s\n", helptext[i]);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Local helpers of parent process */
|
||||||
|
|
||||||
|
struct boss_state {
|
||||||
|
/* What the parent needs to know about its connection to xorriso */
|
||||||
|
|
||||||
|
/* The ends of the dialog pipes */
|
||||||
|
int command_fd;
|
||||||
|
int reply_fd;
|
||||||
|
|
||||||
|
/* For synchronization between boss and xorriso */
|
||||||
|
int mark_count;
|
||||||
|
char pending_mark[16];
|
||||||
|
|
||||||
|
/* Parsing_parameters. See xorriso.h Xorriso_parse_line */
|
||||||
|
int do_parse;
|
||||||
|
char progname[1024];
|
||||||
|
char prefix[1024];
|
||||||
|
char separators[256];
|
||||||
|
int max_words;
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
/* A primitive catcher for result lines */
|
||||||
|
int reply_lines_size; /* 0= catching disabled */
|
||||||
|
char **reply_lines;
|
||||||
|
int reply_lines_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define Frontend_xorriso_max_resulT 1000
|
||||||
|
|
||||||
|
|
||||||
|
/* Some basic gestures of this program: */
|
||||||
|
|
||||||
|
static int prompt_for_command(struct boss_state *boss,
|
||||||
|
char *line, int line_size);
|
||||||
|
|
||||||
|
static int transmit_command(struct boss_state *boss, char *line);
|
||||||
|
|
||||||
|
static int await_all_replies(struct boss_state *boss);
|
||||||
|
|
||||||
|
static int de_pkt_result(struct boss_state *boss);
|
||||||
|
|
||||||
|
static int drain_sieve(struct boss_state *boss);
|
||||||
|
|
||||||
|
int parse_line(char *progname, char *line,
|
||||||
|
char *prefix, char *separators, int max_words,
|
||||||
|
int *argc, char ***argv, int flag);
|
||||||
|
|
||||||
|
int dispose_parsed_words(int *argc, char ***argv);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 ||
|
||||||
|
strcmp(argv[1], "--help") == 0) {
|
||||||
|
usage();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
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 ret;
|
||||||
|
char line[4096];
|
||||||
|
struct boss_state boss;
|
||||||
|
|
||||||
|
close(command_pipe[0]); /* Close unused read end */
|
||||||
|
close(reply_pipe[1]); /* Close unused write end */
|
||||||
|
|
||||||
|
memset(&boss, 0, sizeof(boss));
|
||||||
|
boss.command_fd = command_pipe[1];
|
||||||
|
boss.reply_fd = reply_pipe[0];
|
||||||
|
strcpy(boss.progname, argv[0]);
|
||||||
|
boss.reply_lines = NULL;
|
||||||
|
|
||||||
|
/* Dialog loop */
|
||||||
|
sprintf(boss.pending_mark, "%d", boss.mark_count);
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
/* Wait for pending mark and print all replies */
|
||||||
|
ret = await_all_replies(&boss);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Prompt for command line */
|
||||||
|
ret = prompt_for_command(&boss, line, sizeof(line));
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Send line and -mark command */
|
||||||
|
ret = transmit_command(&boss, line);
|
||||||
|
if (ret <= 0)
|
||||||
|
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 -------------------- */
|
||||||
|
|
||||||
|
static int show_parsed(struct boss_state *boss, char *line);
|
||||||
|
static int record_reply_line(struct boss_state *boss, char *line);
|
||||||
|
static int make_reply_lines(struct boss_state *boss);
|
||||||
|
static int input_interpreter(char *line, struct boss_state *boss);
|
||||||
|
|
||||||
|
|
||||||
|
/* Ask the user for command input and trigger processing of meta commands.
|
||||||
|
*/
|
||||||
|
static int prompt_for_command(struct boss_state *boss,
|
||||||
|
char *line, int line_size)
|
||||||
|
{
|
||||||
|
int l, ret;
|
||||||
|
char *line_res;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/* Interpret meta commands which begin by @ */
|
||||||
|
ret = input_interpreter(line, boss);
|
||||||
|
if (ret == 0)
|
||||||
|
return(1);
|
||||||
|
if (ret < 0)
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Transmit a command (which must end by white space, e.g. newline)
|
||||||
|
and its unique synchronization mark.
|
||||||
|
*/
|
||||||
|
static int transmit_command(struct boss_state *boss, char *line)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char mark_line[32];
|
||||||
|
|
||||||
|
ret = write(boss->command_fd, line, strlen(line));
|
||||||
|
if (ret == -1) {
|
||||||
|
perror("write");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
/* Produce new unique -mark text to watch for */
|
||||||
|
(boss->mark_count)++;
|
||||||
|
sprintf(boss->pending_mark, "%d", boss->mark_count);
|
||||||
|
sprintf(mark_line, "-mark %s\n", boss->pending_mark);
|
||||||
|
ret = write(boss->command_fd, mark_line, strlen(mark_line));
|
||||||
|
if (ret == -1) {
|
||||||
|
perror("write");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read reply messages from xorriso and wait for the expected synchronization
|
||||||
|
mark. Messages can be printed or collected in boss->reply_lines.
|
||||||
|
*/
|
||||||
|
static int await_all_replies(struct boss_state *boss)
|
||||||
|
{
|
||||||
|
int count, remainder = 0, ret;
|
||||||
|
char buf[32769], *line, *npt;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
count = read(boss->reply_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, boss->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.
|
||||||
|
*/
|
||||||
|
if (boss->reply_lines_count < boss->reply_lines_size) {
|
||||||
|
ret = record_reply_line(boss, line);
|
||||||
|
if (ret <= 0)
|
||||||
|
return(ret);
|
||||||
|
} else
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
if (boss->reply_lines_count < boss->reply_lines_size) {
|
||||||
|
ret = record_reply_line(boss, line);
|
||||||
|
if (ret <= 0)
|
||||||
|
return(ret);
|
||||||
|
} else
|
||||||
|
fprintf(stderr, "%s\n", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse line and show words */
|
||||||
|
if (strlen(line) >= 5)
|
||||||
|
show_parsed(boss, line + 5);
|
||||||
|
|
||||||
|
line = npt + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Throw away I channel.
|
||||||
|
Unpack and reconstruct payload of R channel lines.
|
||||||
|
*/
|
||||||
|
static int de_pkt_result(struct boss_state *boss)
|
||||||
|
{
|
||||||
|
int i, l, w;
|
||||||
|
char *payload = NULL, *new_payload = NULL;
|
||||||
|
|
||||||
|
w = 0;
|
||||||
|
for (i = 0; i < boss->reply_lines_count; i++) {
|
||||||
|
if (boss->reply_lines[i][0] != 'R' ||
|
||||||
|
strlen(boss->reply_lines[i]) < 5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (payload == NULL) {
|
||||||
|
payload = strdup(boss->reply_lines[i] + 5);
|
||||||
|
} else {
|
||||||
|
l = strlen(payload);
|
||||||
|
new_payload = calloc(l + strlen(boss->reply_lines[i] + 5) + 1, 1);
|
||||||
|
if (new_payload == NULL)
|
||||||
|
goto no_mem;
|
||||||
|
strcpy(new_payload, payload);
|
||||||
|
strcpy(new_payload + l, boss->reply_lines[i] + 5);
|
||||||
|
free(payload);
|
||||||
|
payload = new_payload;
|
||||||
|
}
|
||||||
|
if (payload == NULL)
|
||||||
|
goto no_mem;
|
||||||
|
l = strlen(payload);
|
||||||
|
if (l > 0)
|
||||||
|
if (payload[l - 1] == '\n')
|
||||||
|
payload[l - 1] = 0;
|
||||||
|
|
||||||
|
if (boss->reply_lines[i][2] != '0') {
|
||||||
|
free(boss->reply_lines[w]);
|
||||||
|
boss->reply_lines[w] = payload;
|
||||||
|
w++;
|
||||||
|
payload = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = w ; i < boss->reply_lines_count; i++) {
|
||||||
|
free(boss->reply_lines[i]);
|
||||||
|
boss->reply_lines[i] = NULL;
|
||||||
|
}
|
||||||
|
boss->reply_lines_count = w;
|
||||||
|
return(1);
|
||||||
|
no_mem:;
|
||||||
|
fprintf(stderr, "FATAL: Out of memory !\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Inquire and print all recorded message sieve results.
|
||||||
|
*/
|
||||||
|
static int drain_sieve(struct boss_state *boss)
|
||||||
|
{
|
||||||
|
int ret, i, j, names_size = 0, names_count = 0, first_result;
|
||||||
|
int number_of_strings, available, xorriso_ret, number_of_lines, k, r;
|
||||||
|
char **names = NULL, line[1024];
|
||||||
|
|
||||||
|
/* Install catcher for reply_lines */
|
||||||
|
ret = make_reply_lines(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
boss->reply_lines_size = Frontend_xorriso_max_resulT;
|
||||||
|
boss->reply_lines_count = 0;
|
||||||
|
|
||||||
|
/* Get list of filter rule names from -msg_op show_sieve */
|
||||||
|
ret = transmit_command(boss, "-msg_op show_sieve -\n");
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = await_all_replies(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = de_pkt_result(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
|
||||||
|
names = boss->reply_lines;
|
||||||
|
boss->reply_lines = NULL;
|
||||||
|
names_size = Frontend_xorriso_max_resulT;
|
||||||
|
names_count= boss->reply_lines_count;
|
||||||
|
ret = make_reply_lines(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
boss->reply_lines_size = Frontend_xorriso_max_resulT;
|
||||||
|
|
||||||
|
/* Inquire caught results of each name by -msg_op read_sieve
|
||||||
|
until return value is <= 0
|
||||||
|
*/
|
||||||
|
printf("--------------------------------------------------\n");
|
||||||
|
for (i = 0; i < names_count; i++) {
|
||||||
|
available = 1;
|
||||||
|
first_result = 1;
|
||||||
|
while (available > 0) {
|
||||||
|
boss->reply_lines_count = 0;
|
||||||
|
sprintf(line, "-msg_op read_sieve '%s'\n", names[i]);
|
||||||
|
ret = transmit_command(boss, line);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = await_all_replies(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = de_pkt_result(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
|
||||||
|
if (boss->reply_lines_count < 2) {
|
||||||
|
fprintf(stderr, "drain_sieve: illegible result reply\n");
|
||||||
|
{ret= 0; goto ex;}
|
||||||
|
}
|
||||||
|
xorriso_ret = -1;
|
||||||
|
sscanf(boss->reply_lines[0], "%d", &xorriso_ret);
|
||||||
|
if(xorriso_ret <= 0)
|
||||||
|
break;
|
||||||
|
number_of_strings = -1;
|
||||||
|
sscanf(boss->reply_lines[1], "%d", &number_of_strings);
|
||||||
|
if(xorriso_ret < 0)
|
||||||
|
break;
|
||||||
|
if (first_result)
|
||||||
|
printf(" '%s' |\n", names[i]);
|
||||||
|
first_result = 0;
|
||||||
|
for (j = 0; names[i][j] != 0; j++)
|
||||||
|
printf("-");
|
||||||
|
printf("-----\n");
|
||||||
|
r = 2;
|
||||||
|
for (j = 0; j < number_of_strings && r < boss->reply_lines_count;
|
||||||
|
j++) {
|
||||||
|
number_of_lines = -1;
|
||||||
|
sscanf(boss->reply_lines[r], "%d", &number_of_lines);
|
||||||
|
r++;
|
||||||
|
printf("|");
|
||||||
|
for (k = 0; k < number_of_lines
|
||||||
|
&& r < boss->reply_lines_count; k++) {
|
||||||
|
printf("%s%s", boss->reply_lines[r],
|
||||||
|
k < number_of_lines - 1 ? "\n" : "");
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
printf("|\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (first_result == 0)
|
||||||
|
printf("--------------------------------------------------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dispose all recorded results */
|
||||||
|
ret = transmit_command(boss, "-msg_op clear_sieve -\n");
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = await_all_replies(boss);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
ex:;
|
||||||
|
/* Disable result catcher */
|
||||||
|
boss->reply_lines_size = 0;
|
||||||
|
if (names != NULL)
|
||||||
|
dispose_parsed_words(&names_size, &names);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------- Helpers of local helpers ---------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static int show_parsed(struct boss_state *boss, char *line)
|
||||||
|
{
|
||||||
|
int argc, ret = 0, i;
|
||||||
|
char **argv = NULL;
|
||||||
|
|
||||||
|
if (!boss->do_parse)
|
||||||
|
return(2);
|
||||||
|
ret = parse_line(boss->progname, line, boss->prefix, boss->separators,
|
||||||
|
boss->max_words, &argc, &argv, boss->flag);
|
||||||
|
if (ret <= 0 || argc <= 0)
|
||||||
|
return(0);
|
||||||
|
fprintf(stderr, "-----------------------------------------------------\n");
|
||||||
|
fprintf(stderr, "parse_line returns %d, argc = %d\n", ret, argc);
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
fprintf(stderr, "%2d : %s\n", i, argv[i]);
|
||||||
|
fprintf(stderr, "-----------------------------------------------------\n");
|
||||||
|
dispose_parsed_words(&argc, &argv); /* release memory */
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int make_reply_lines(struct boss_state *boss)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (boss->reply_lines != NULL)
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
boss->reply_lines = calloc(Frontend_xorriso_max_resulT,
|
||||||
|
sizeof(char *));
|
||||||
|
if (boss->reply_lines == 0) {
|
||||||
|
fprintf(stderr, "FATAL: Out of memory !\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
boss->reply_lines_count = 0;
|
||||||
|
boss->reply_lines_size = 0;
|
||||||
|
for (i = 0; i < Frontend_xorriso_max_resulT; i++)
|
||||||
|
boss->reply_lines[i] = NULL;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int record_reply_line(struct boss_state *boss, char *line)
|
||||||
|
{
|
||||||
|
if (boss->reply_lines[boss->reply_lines_count] != NULL)
|
||||||
|
free(boss->reply_lines[boss->reply_lines_count]);
|
||||||
|
boss->reply_lines[boss->reply_lines_count] = strdup(line);
|
||||||
|
if (boss->reply_lines[boss->reply_lines_count] == NULL) {
|
||||||
|
fprintf(stderr, "FATAL: Out of memory !\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
boss->reply_lines_count++;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int input_interpreter(char *line, struct boss_state *boss)
|
||||||
|
{
|
||||||
|
int argc, ret = 0;
|
||||||
|
char **argv = NULL;
|
||||||
|
|
||||||
|
ret = parse_line(boss->progname, line, "", "", 6, &argc, &argv, 0);
|
||||||
|
if (ret <= 0 || argc <= 0)
|
||||||
|
return(0);
|
||||||
|
if (strcmp(argv[0], "@parse") == 0) {
|
||||||
|
boss->do_parse = 1;
|
||||||
|
boss->prefix[0] = 0;
|
||||||
|
if (argc > 1)
|
||||||
|
strcpy(boss->prefix, argv[1]);
|
||||||
|
boss->separators[0] = 0;
|
||||||
|
if (argc > 2)
|
||||||
|
strcpy(boss->separators, argv[2]);
|
||||||
|
boss->max_words = 0;
|
||||||
|
if (argc > 3)
|
||||||
|
sscanf(argv[3], "%d", &(boss->max_words));
|
||||||
|
boss->max_words = 0;
|
||||||
|
if (argc > 4)
|
||||||
|
sscanf(argv[4], "%d", &(boss->flag));
|
||||||
|
ret = 1;
|
||||||
|
} else if(strcmp(argv[0], "@noparse") == 0) {
|
||||||
|
boss->do_parse = 0;
|
||||||
|
ret = 1;
|
||||||
|
} else if(strcmp(argv[0], "@drain_sieve") == 0) {
|
||||||
|
ret= drain_sieve(boss);
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
dispose_parsed_words(&argc, &argv); /* release memory */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------- Line-to-word parser equivalent to Xorriso_parse_line() -------- */
|
||||||
|
|
||||||
|
|
||||||
|
static int Sfile_sep_make_argv(char *progname, char *line, char *separators,
|
||||||
|
int max_words, int *argc, char ***argv, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
int parse_line(char *progname, char *line,
|
||||||
|
char *prefix, char *separators, int max_words,
|
||||||
|
int *argc, char ***argv, int flag)
|
||||||
|
{
|
||||||
|
int ret, bsl_mode;
|
||||||
|
char *to_parse;
|
||||||
|
|
||||||
|
*argc = 0;
|
||||||
|
*argv = NULL;
|
||||||
|
|
||||||
|
to_parse = line;
|
||||||
|
bsl_mode = (flag >> 1) & 15;
|
||||||
|
if (prefix[0]) {
|
||||||
|
if (strncmp(line, prefix, strlen(prefix)) == 0) {
|
||||||
|
to_parse = line + strlen(prefix);
|
||||||
|
} else {
|
||||||
|
ret = 2; goto ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = Sfile_sep_make_argv(progname, to_parse, separators,
|
||||||
|
max_words, argc, argv,
|
||||||
|
(!(flag & 32)) | 4 | (bsl_mode << 5));
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s : Severe lack of resources during command line parsing\n",
|
||||||
|
progname);
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s : Incomplete quotation in %s line: %s\n",
|
||||||
|
progname, (flag & 32) ? "command" : "parsed", to_parse);
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
ex:;
|
||||||
|
if (ret <= 0)
|
||||||
|
Sfile_sep_make_argv("", "", "", 0, argc, argv, 2); /* release memory */
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dispose_parsed_words(int *argc, char ***argv)
|
||||||
|
{
|
||||||
|
Sfile_sep_make_argv("", "", "", 0, argc, argv, 2);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------- Some helpers copied from xorriso/sfile.c ----------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static int Sfile_destroy_argv(int *argc, char ***argv, int flag)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(*argc>0 && *argv!=NULL){
|
||||||
|
for(i=0;i<*argc;i++){
|
||||||
|
if((*argv)[i]!=NULL)
|
||||||
|
free((*argv)[i]);
|
||||||
|
}
|
||||||
|
free((char *) *argv);
|
||||||
|
}
|
||||||
|
*argc= 0;
|
||||||
|
*argv= NULL;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Converts backslash codes into single characters:
|
||||||
|
\a BEL 7 , \b BS 8 , \e ESC 27 , \f FF 12 , \n LF 10 , \r CR 13 ,
|
||||||
|
\t HT 9 , \v VT 11 , \\ \ 92
|
||||||
|
\[0-9][0-9][0-9] octal code , \x[0-9a-f][0-9a-f] hex code ,
|
||||||
|
\cX control-x (ascii(X)-64)
|
||||||
|
@param upto maximum number of characters to examine for backslash.
|
||||||
|
The scope of a backslash (0 to 3 characters) is not affected.
|
||||||
|
@param eaten returns the difference in length between input and output
|
||||||
|
@param flag bit0= only determine *eaten, do not convert
|
||||||
|
bit1= allow to convert \000 to binary 0
|
||||||
|
*/
|
||||||
|
static int Sfile_bsl_interpreter(char *text, int upto, int *eaten, int flag)
|
||||||
|
{
|
||||||
|
char *rpt, *wpt, num_text[8], wdummy[8];
|
||||||
|
unsigned int num= 0;
|
||||||
|
|
||||||
|
*eaten= 0;
|
||||||
|
wpt= text;
|
||||||
|
for(rpt= text; *rpt != 0 && rpt - text < upto; rpt++) {
|
||||||
|
if(flag & 1)
|
||||||
|
wpt= wdummy;
|
||||||
|
if(*rpt == '\\') {
|
||||||
|
rpt++;
|
||||||
|
(*eaten)++;
|
||||||
|
if(*rpt == 'a') {
|
||||||
|
*(wpt++)= 7;
|
||||||
|
} else if(*rpt == 'b') {
|
||||||
|
*(wpt++)= 8;
|
||||||
|
} else if(*rpt == 'e') {
|
||||||
|
*(wpt++)= 27;
|
||||||
|
} else if(*rpt == 'f') {
|
||||||
|
*(wpt++)= 12;
|
||||||
|
} else if(*rpt == 'n') {
|
||||||
|
*(wpt++)= 10;
|
||||||
|
} else if(*rpt == 'r') {
|
||||||
|
*(wpt++)= 13;
|
||||||
|
} else if(*rpt == 't') {
|
||||||
|
*(wpt++)= 9;
|
||||||
|
} else if(*rpt == 'v') {
|
||||||
|
*(wpt++)= 11;
|
||||||
|
} else if(*rpt == '\\') {
|
||||||
|
*(wpt++)= '\\';
|
||||||
|
} else if(rpt[0] >= '0' && rpt[0] <= '7' &&
|
||||||
|
rpt[1] >= '0' && rpt[1] <= '7' &&
|
||||||
|
rpt[2] >= '0' && rpt[2] <= '7') {
|
||||||
|
num_text[0]= '0';
|
||||||
|
num_text[1]= *(rpt + 0);
|
||||||
|
num_text[2]= *(rpt + 1);
|
||||||
|
num_text[3]= *(rpt + 2);
|
||||||
|
num_text[4]= 0;
|
||||||
|
sscanf(num_text, "%o", &num);
|
||||||
|
if((num > 0 || (flag & 2)) && num <= 255) {
|
||||||
|
rpt+= 2;
|
||||||
|
(*eaten)+= 2;
|
||||||
|
*(wpt++)= num;
|
||||||
|
} else
|
||||||
|
goto not_a_code;
|
||||||
|
} else if(rpt[0] == 'x' &&
|
||||||
|
((rpt[1] >= '0' && rpt[1] <= '9') ||
|
||||||
|
(rpt[1] >= 'A' && rpt[1] <= 'F') ||
|
||||||
|
(rpt[1] >= 'a' && rpt[1] <= 'f'))
|
||||||
|
&&
|
||||||
|
((rpt[2] >= '0' && rpt[2] <= '9') ||
|
||||||
|
(rpt[2] >= 'A' && rpt[2] <= 'F') ||
|
||||||
|
(rpt[2] >= 'a' && rpt[2] <= 'f'))
|
||||||
|
) {
|
||||||
|
num_text[0]= *(rpt + 1);
|
||||||
|
num_text[1]= *(rpt + 2);
|
||||||
|
num_text[2]= 0;
|
||||||
|
sscanf(num_text, "%x", &num);
|
||||||
|
if(num > 0 && num <= 255) {
|
||||||
|
rpt+= 2;
|
||||||
|
(*eaten)+= 2;
|
||||||
|
*(wpt++)= num;
|
||||||
|
} else
|
||||||
|
goto not_a_code;
|
||||||
|
} else if(*rpt == 'c') {
|
||||||
|
if(rpt[1] > 64 && rpt[1] < 96) {
|
||||||
|
*(wpt++)= rpt[1] - 64;
|
||||||
|
rpt++;
|
||||||
|
(*eaten)++;
|
||||||
|
} else
|
||||||
|
goto not_a_code;
|
||||||
|
} else {
|
||||||
|
not_a_code:;
|
||||||
|
*(wpt++)= '\\';
|
||||||
|
rpt--;
|
||||||
|
(*eaten)--;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
*(wpt++)= *rpt;
|
||||||
|
}
|
||||||
|
*wpt= *rpt;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SfileadrL 4096
|
||||||
|
|
||||||
|
static int Sfile_sep_make_argv(char *progname, char *line, char *separators,
|
||||||
|
int max_words, int *argc, char ***argv, int flag)
|
||||||
|
/*
|
||||||
|
bit0= read progname as first argument from line
|
||||||
|
bit1= just release argument list argv and return
|
||||||
|
bit2= abort with return(0) if incomplete quotes are found
|
||||||
|
bit3= eventually prepend missing '-' to first argument read from line
|
||||||
|
bit4= like bit2 but only check quote completeness, do not allocate memory
|
||||||
|
bit5+6= interpretation of backslashes:
|
||||||
|
0= no interpretation, leave unchanged
|
||||||
|
1= only inside double quotes
|
||||||
|
2= outside single quotes
|
||||||
|
3= everywhere
|
||||||
|
bit7= append a NULL element to argv
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc, bsl_mode, ret= 0, eaten;
|
||||||
|
char *cpt,*start;
|
||||||
|
char *buf= NULL;
|
||||||
|
|
||||||
|
Sfile_destroy_argv(argc,argv,0);
|
||||||
|
if(flag&2)
|
||||||
|
{ret= 1; goto ex;}
|
||||||
|
|
||||||
|
if(flag & 16)
|
||||||
|
flag|= 4;
|
||||||
|
bsl_mode= (flag >> 5) & 3;
|
||||||
|
|
||||||
|
buf= calloc(strlen(line) + SfileadrL, 1);
|
||||||
|
if(buf == NULL)
|
||||||
|
{ret= -1; goto ex;}
|
||||||
|
for(pass=0;pass<2;pass++) {
|
||||||
|
cpt= line-1;
|
||||||
|
if(!(flag&1)){
|
||||||
|
argzaehl= line_start_argc= 1;
|
||||||
|
if(pass==0)
|
||||||
|
maxl= strlen(progname);
|
||||||
|
else
|
||||||
|
strcpy((*argv)[0],progname);
|
||||||
|
} else {
|
||||||
|
argzaehl= line_start_argc= 0;
|
||||||
|
if(pass==0) maxl= 0;
|
||||||
|
}
|
||||||
|
while(*(++cpt)!=0){
|
||||||
|
if(*separators) {
|
||||||
|
if(strchr(separators, *cpt) != NULL)
|
||||||
|
continue;
|
||||||
|
} else if(isspace(*cpt))
|
||||||
|
continue;
|
||||||
|
start= cpt;
|
||||||
|
buf[0]= 0;
|
||||||
|
cpt--;
|
||||||
|
|
||||||
|
if(max_words > 0 && argzaehl >= max_words && *cpt != 0) {
|
||||||
|
/* take uninterpreted up to the end */
|
||||||
|
cpt+= strlen(cpt) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(*(++cpt)!=0) {
|
||||||
|
if(*separators) {
|
||||||
|
if(strchr(separators, *cpt) != NULL)
|
||||||
|
break;
|
||||||
|
} else if(isspace(*cpt))
|
||||||
|
break;
|
||||||
|
if(*cpt=='"'){
|
||||||
|
l= cpt-start; bufl= strlen(buf);
|
||||||
|
if(l>0) {
|
||||||
|
strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
|
||||||
|
if(bsl_mode >= 3) {
|
||||||
|
ret= Sfile_bsl_interpreter(buf, l, &eaten, 0);
|
||||||
|
if(ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l= strlen(buf);
|
||||||
|
start= cpt+1;
|
||||||
|
while(*(++cpt)!=0) if(*cpt=='"') break;
|
||||||
|
if((flag&4) && *cpt==0)
|
||||||
|
{ret= 0; goto ex;}
|
||||||
|
l= cpt-start; bufl= strlen(buf);
|
||||||
|
if(l>0) {
|
||||||
|
strncpy(buf + bufl, start, l);
|
||||||
|
buf[bufl + l]= 0;
|
||||||
|
if(bsl_mode >= 1) {
|
||||||
|
ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
|
||||||
|
if(ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start= cpt+1;
|
||||||
|
}else if(*cpt=='\''){
|
||||||
|
l= cpt-start; bufl= strlen(buf);
|
||||||
|
if(l>0) {
|
||||||
|
strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
|
||||||
|
if(bsl_mode >= 3) {
|
||||||
|
ret= Sfile_bsl_interpreter(buf, l, &eaten, 0);
|
||||||
|
if(ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l= strlen(buf);
|
||||||
|
start= cpt+1;
|
||||||
|
while(*(++cpt)!=0) if(*cpt=='\'') break;
|
||||||
|
if((flag&4) && *cpt==0)
|
||||||
|
{ret= 0; goto ex;}
|
||||||
|
l= cpt-start; bufl= strlen(buf);
|
||||||
|
if(l>0) {
|
||||||
|
strncat(buf,start,l);buf[bufl+l]= 0;
|
||||||
|
if(bsl_mode >= 2) {
|
||||||
|
ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
|
||||||
|
if(ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start= cpt+1;
|
||||||
|
}
|
||||||
|
if(*cpt==0) break;
|
||||||
|
}
|
||||||
|
l= cpt-start;
|
||||||
|
bufl= strlen(buf);
|
||||||
|
if(l>0) {
|
||||||
|
strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
|
||||||
|
if(bsl_mode >= 3) {
|
||||||
|
ret= Sfile_bsl_interpreter(buf, l, &eaten, 0);
|
||||||
|
if(ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l= strlen(buf);
|
||||||
|
if(pass==0){
|
||||||
|
if(argzaehl==line_start_argc && (flag&8))
|
||||||
|
if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
|
||||||
|
l++;
|
||||||
|
if(l>maxl) maxl= l;
|
||||||
|
}else{
|
||||||
|
strcpy((*argv)[argzaehl],buf);
|
||||||
|
if(argzaehl==line_start_argc && (flag&8))
|
||||||
|
if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
|
||||||
|
sprintf((*argv)[argzaehl],"-%s", buf);
|
||||||
|
}
|
||||||
|
argzaehl++;
|
||||||
|
if(*cpt==0) break;
|
||||||
|
}
|
||||||
|
if(pass==0){
|
||||||
|
if(flag & 16)
|
||||||
|
{ret= 1; goto ex;}
|
||||||
|
*argc= argzaehl;
|
||||||
|
if(argzaehl>0 || (flag & 128)) {
|
||||||
|
*argv= (char **) calloc((argzaehl + !!(flag & 128)), sizeof(char *));
|
||||||
|
if(*argv==NULL)
|
||||||
|
{ret= -1; goto ex;}
|
||||||
|
}
|
||||||
|
for(i=0;i<*argc;i++) {
|
||||||
|
(*argv)[i]= (char *) calloc(maxl + 1, 1);
|
||||||
|
if((*argv)[i]==NULL)
|
||||||
|
{ret= -1; goto ex;}
|
||||||
|
}
|
||||||
|
if(flag & 128)
|
||||||
|
(*argv)[*argc]= NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret= 1;
|
||||||
|
ex:
|
||||||
|
if(buf != NULL)
|
||||||
|
free(buf);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
3223
libisoburn/trunk/frontend/xorriso-tcltk
Executable file
3223
libisoburn/trunk/frontend/xorriso-tcltk
Executable file
File diff suppressed because it is too large
Load Diff
@ -142,6 +142,32 @@ closing it immediately, waiting, and only then opening it for real:
|
|||||||
CFLAGS="$CFLAGS -DLibburn_udev_extra_open_cyclE -DLibburn_udev_wait_useC=500000"
|
CFLAGS="$CFLAGS -DLibburn_udev_extra_open_cyclE -DLibburn_udev_wait_useC=500000"
|
||||||
|
|
||||||
|
|
||||||
|
xorriso under control of a (GUI) frontend process
|
||||||
|
|
||||||
|
The dialog mode allows frontend programs to connect via pipes to the standard
|
||||||
|
input and output of xorriso. Several commands of xorriso help with receiving
|
||||||
|
and parsing of reply messages.
|
||||||
|
|
||||||
|
As a proof of concept, there is the Tcl/Tk script xorriso-tcltk which can
|
||||||
|
be launched by this shell command in the directory where xorriso was built:
|
||||||
|
|
||||||
|
xorriso/xorriso -launch_frontend frontend/xorriso-tcltk --stdio --
|
||||||
|
|
||||||
|
resp. after installation:
|
||||||
|
|
||||||
|
xorriso -launch_frontend $(which xorriso-tcltk) --stdio --
|
||||||
|
|
||||||
|
See file frontend/README-tcltk for a description of its GUI.
|
||||||
|
See its Tcl code for getting an idea how this gets achieved.
|
||||||
|
|
||||||
|
Further there is the C program frontend/frontend_pipes_xorriso.c which
|
||||||
|
forks a xorriso process and shows the same communication gestures as
|
||||||
|
xorriso-tcltk.
|
||||||
|
In particular it connects to xorriso via two pipes, sends commands, waits
|
||||||
|
for all replies of a command, picks info out of the xorriso message sieve,
|
||||||
|
and parses reply message lines into words.
|
||||||
|
|
||||||
|
|
||||||
Drives and Disk File Objects
|
Drives and Disk File Objects
|
||||||
|
|
||||||
The user of libisoburn applications needs rw-permission for the CD/DVD/BD
|
The user of libisoburn applications needs rw-permission for the CD/DVD/BD
|
||||||
|
@ -231,9 +231,15 @@ copy_files doc/partition_offset.wiki \
|
|||||||
create_dir "$lone_dir"/test
|
create_dir "$lone_dir"/test
|
||||||
copy_files \
|
copy_files \
|
||||||
test/compare_file.c \
|
test/compare_file.c \
|
||||||
test/frontend_pipes_xorriso.c \
|
|
||||||
"$lone_dir"/test
|
"$lone_dir"/test
|
||||||
|
|
||||||
|
create_dir "$lone_dir"/frontend
|
||||||
|
copy_files \
|
||||||
|
frontend/frontend_pipes_xorriso.c \
|
||||||
|
frontend/README-tcltk \
|
||||||
|
frontend/xorriso-tcltk \
|
||||||
|
"$lone_dir"/frontend
|
||||||
|
|
||||||
|
|
||||||
# releng
|
# releng
|
||||||
|
|
||||||
|
@ -237,6 +237,7 @@ noinst_PROGRAMS = \
|
|||||||
test/compare_file \
|
test/compare_file \
|
||||||
xorriso/make_xorriso_1
|
xorriso/make_xorriso_1
|
||||||
|
|
||||||
|
|
||||||
# A program to compare two trees of files in mounted filesystems
|
# A program to compare two trees of files in mounted filesystems
|
||||||
# To compare tree /media/dvd and /original/dir :
|
# To compare tree /media/dvd and /original/dir :
|
||||||
# find /media/dvd -exec test/compare_file '{}' /media/dvd /original/dir ';'
|
# find /media/dvd -exec test/compare_file '{}' /media/dvd /original/dir ';'
|
||||||
@ -254,6 +255,11 @@ xorriso_make_xorriso_1_LDADD =
|
|||||||
xorriso_make_xorriso_1_SOURCES = xorriso/make_xorriso_1.c
|
xorriso_make_xorriso_1_SOURCES = xorriso/make_xorriso_1.c
|
||||||
|
|
||||||
|
|
||||||
|
# A Proof-of-concept for frontends
|
||||||
|
bin_SCRIPTS = \
|
||||||
|
frontend/xorriso-tcltk
|
||||||
|
|
||||||
|
|
||||||
# Install symbolic links to the xorriso binary
|
# Install symbolic links to the xorriso binary
|
||||||
#
|
#
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@ -328,7 +334,8 @@ EXTRA_DIST = \
|
|||||||
doc/susp_aaip_isofs_names.txt \
|
doc/susp_aaip_isofs_names.txt \
|
||||||
doc/zisofs_format.txt \
|
doc/zisofs_format.txt \
|
||||||
doc/startup_file.txt \
|
doc/startup_file.txt \
|
||||||
test/frontend_pipes_xorriso.c \
|
frontend/frontend_pipes_xorriso.c \
|
||||||
|
frontend/README-tcltk \
|
||||||
libisofs/aaip-os-dummy.c \
|
libisofs/aaip-os-dummy.c \
|
||||||
libisofs/aaip-os-linux.c \
|
libisofs/aaip-os-linux.c \
|
||||||
libisofs/aaip-os-freebsd.c \
|
libisofs/aaip-os-freebsd.c \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user