You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
libisoburn/test/xorriso.c

8932 lines
235 KiB

/*
( cd .. ; libisoburn-develop/test/compile_xorriso.sh -g )
or
cc -g -DXorriso_with_maiN -DXorriso_with_regeX -DXorriso_with_readlinE \
-DXorriso_build_timestamP='"'"$(date -u '+%Y.%m.%d.%H%M%S')"'"' \
-Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
-o test/xorriso \
test/xorriso.c test/xorrisoburn.c \
-lpthread -lreadline -lburn -lisofs -lisoburn
or
cc -g -DXorriso_with_regeX -DXorriso_with_readlinE \
-DXorriso_build_timestamP='"'"$(date -u '+%Y.%m.%d.%H%M%S')"'"' \
-Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
-c \
test/xorriso.c test/xorrisoburn.c
*/
/* Command line oriented batch and dialog tool which creates, loads,
manipulates and burns ISO 9660 filesystem images.
Copyright 2007-2008 Thomas Schmitt, <scdbackup@gmx.net>
Initial code of this program was derived from program src/askme.c out
of scdbackup-0.8.8, Copyright 2007 Thomas Schmitt, BSD-License.
Provided under GPL version 2, with the announcement that this might
get changed in future. I would prefer BSD or a modified LGPL with no
option to choose any kind of future GPL version.
(This announcement affects only future releases of xorriso.
If you obtain a copy licensed as "GPL version 2" then this license is
not revocable for that particular copy, of course.)
Overview of xorriso architecture:
libburn provides the ability to read and write data.
libisofs interprets and manipulates ISO 9660 directory trees. It generates
the output stream which is handed over to libburn.
libisoburn encapsulates the connectivity issues between libburn and
libisofs. It also enables multi-session emulation on overwritable media
and random access file objects.
xorriso is intended as reference application of libisoburn.
xorrisoburn.[ch] encapsulate any usage of the libraries by xorriso.
xorriso.h exposes the public functions of xorriso which are intended
to be used by programs which link with xorriso.o. These functions are
direct equivalents of the xorriso interpreter commands.
There is also the API for handling event messages.
xorriso_private.h is not to be included by other software. It encapsulates
the inner interfaces of xorriso.
xorriso.c provides the command interpreter as described in xorriso.1.
It performs any activity that does not demand a reference to a symbol
of the library APIs. This includes:
- Interpretation of user input from arguments, dialog, and scripting.
- Output of result text and event messages.
- POSIX filesystem operations.
- Public functions which perform the particular xorriso commands.
- The main() function, if enabled by #define Xorriso_with_maiN.
*/
#define PROG_VERSION "0.0.0"
/** The source code release timestamp */
#include "xorriso_timestamp.h"
#ifndef Xorriso_timestamP
#define Xorriso_timestamP "-none-given-"
#endif
/** The binary build timestamp is to be set externally by the compiler */
#ifndef Xorriso_build_timestamP
#define Xorriso_build_timestamP "-none-given-"
#endif
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <dirent.h>
#include <time.h>
#include <utime.h>
#include <pwd.h>
#include <grp.h>
/* eventually, this is done in xorriso_private.h : #include <regex.h> */
#ifdef Xorriso_with_readlinE
#ifdef Xorriso_with_old_readlinE
#include <readline.h>
#include <history.h>
#else /* Xorriso_with_old_readlinE */
#include <readline/readline.h>
#include <readline/history.h>
#endif /* ! Xorriso_with_old_readlinE */
#endif /* Xorriso_with_readlinE */
#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ));
/* Diet facility: exclude help texts from binaries */
/* This will eventually be redefined to eat up its content */
#define AlN(x) x
/* There is only one stage of diet: Xorriso_no_helP */
#ifdef Xorriso_no_helP
#undef AlN
#define AlN(x)
#endif
/* ------------------------------------------------------------------------ */
/* The official xorriso options API. "No shortcuts" */
#include "xorriso.h"
/* The inner isofs- and burn-library interface */
#include "xorrisoburn.h"
/* The inner description of XorrisO */
#define Xorriso_is_xorriso_selF 1
#include "xorriso_private.h"
/* ------------------------------------------------------------------------ */
#ifndef Xorriso_sfile_externaL
char *Sfile_fgets(char *line, int maxl, FILE *fp)
{
int l;
char *ret;
ret= fgets(line,maxl,fp);
if(ret==NULL)
return(NULL);
l= strlen(line);
if(l>0) if(line[l-1]=='\r') line[--l]= 0;
if(l>0) if(line[l-1]=='\n') line[--l]= 0;
if(l>0) if(line[l-1]=='\r') line[--l]= 0;
return(ret);
}
int Sfile_fclose(FILE *fp)
{
if(fp!=stdout && fp!=stdin && fp!=NULL)
fclose(fp);
return(1);
}
int Sfile_count_components(char *path, int flag)
/*
bit0= do not ignore trailing slash
bit1= do not ignore empty components (other than the empty root name)
*/
{
int l,count= 0;
char *cpt;
l= strlen(path);
if(l==0)
return(0);
count= 1;
for(cpt= path+l-1;cpt>=path;cpt--) {
if(*cpt=='/') {
if(*(cpt+1)==0 && !(flag&1))
continue;
if(*(cpt+1)=='/' && !(flag&2))
continue;
count++;
}
}
return(count);
}
int Sfile_component_pointer(char *path, char **sourcept, int idx, int flag)
/*
bit0= do not ignore trailing slash
bit1= do not ignore empty components (other than the empty root name)
bit2= accept 0 as '/'
*/
{
int count= 0;
char *spt;
for(spt= path;*spt!=0 || (flag&4);spt++) {
if(count>=idx) {
*sourcept= spt;
return(1);
}
if(*spt=='/' || *spt==0) {
if(*(spt+1)=='/' && !(flag&2))
continue;
if(*(spt+1)==0 && !(flag&1))
continue;
count++;
}
}
if((flag&1) && count>=idx)
return(1);
return(0);
}
int Sfile_leafname(char *path, char leafname[SfileadrL], int flag)
{
int count, ret;
char *lpt;
leafname[0]= 0;
count= Sfile_count_components(path, 0);
if(count==0)
return(0);
ret= Sfile_component_pointer(path, &lpt, count-1, 0);
if(ret<=0)
return(ret);
if(Sfile_str(leafname, lpt, 0)<=0)
return(0);
lpt= strchr(leafname, '/');
if(lpt!=NULL)
*lpt= 0;
return(1);
}
int Sfile_add_to_path(char path[SfileadrL], char *addon, int flag)
{
int l;
l= strlen(path);
if(l+1>=SfileadrL)
return(0);
if(l==0) {
strcpy(path,"/");
l= 1;
} else if(path[l-1]!='/') {
path[l++]= '/';
path[l]= 0;
}
if(l+strlen(addon)>=SfileadrL)
return(0);
if(addon[0]=='/')
strcpy(path+l,addon+1);
else
strcpy(path+l,addon);
return(1);
}
int Sfile_prepend_path(char *prefix, char path[SfileadrL], int flag)
{
int l, i;
l= strlen(path)+strlen(prefix)+1;
if(l>=SfileadrL) {
#ifdef Not_yeT
/* >>> ??? how to transport messages to xorriso ? */
sprintf(xorriso->info_text,
"Combination of wd and relative address too long (%d > %d)",
l,SfileadrL-1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
#endif
return(-1);
}
l-= strlen(path);
for(i= strlen(path)+1; i>=0; i--)
path[i+l]= path[i];
strcpy(path,prefix);
path[l-1]= '/';
return(1);
}
int Sfile_being_group_member(struct stat *stbuf, int flag)
{
int i, suppl_groups;
gid_t *suppl_glist;
if (getegid()==stbuf->st_gid)
return(1);
suppl_groups= getgroups(0, NULL);
suppl_glist= (gid_t *) malloc((suppl_groups + 1) * sizeof(gid_t));
if (suppl_glist==NULL)
return(-1);
suppl_groups= getgroups(suppl_groups+1,suppl_glist);
for (i= 0; i<suppl_groups; i++) {
if (suppl_glist[i]==stbuf->st_gid) {
free((char *) suppl_glist);
return(1);
}
}
free((char *) suppl_glist);
return(0);
}
int Sfile_type(char *filename, int flag)
/*
bit0= return -1 if file is missing
bit1= return a hardlink with siblings as type 5
bit2= evaluate eventual link target rather than the link object itself
bit3= return a socket or a char device as types 7 or 8 rather than 0
*/
/*
return:
0=unknown
1=regular
2=directory
3=symbolic link
4=named pipe
5=multiple hardlink (with bit1)
6=block device
7=socket (with bit3)
8=character device (with bit3)
*/
{
struct stat stbuf;
if(flag&4) {
if(stat(filename,&stbuf)==-1) {
if(flag&1) return(-1);
else return(0);
}
} else {
if(lstat(filename,&stbuf)==-1) {
if(flag&1) return(-1);
else return(0);
}
}
if(S_ISREG(stbuf.st_mode)) {
if(flag&2)
if(stbuf.st_nlink>1)
return(5);
return(1);
}
if(S_ISDIR(stbuf.st_mode))
return(2);
if((stbuf.st_mode&S_IFMT)==S_IFLNK)
return(3);
if(S_ISFIFO(stbuf.st_mode))
return(4);
if(S_ISBLK(stbuf.st_mode))
return(6);
if(flag&8)
if((stbuf.st_mode&S_IFMT)==S_IFSOCK)
return(7);
if(flag&8)
if(S_ISCHR(stbuf.st_mode))
return(8);
return(0);
}
int Sfile_lookup_permissions(char *fname, int *perms, mode_t *st_mode,int flag)
/* @param perms bit0= r , bit1= w , bit2= x */
/* return: <0 fatal error, 0= file nonexistent, 1=owner, 2=group, 3=other */
{
struct stat stbuf;
int is_root;
*perms= 0;
if(stat(fname,&stbuf)==-1)
return(0);
*st_mode= stbuf.st_mode;
is_root= (geteuid()==0);
if(is_root) /* root can always read and write */
*perms= 3;
if(is_root || geteuid()==stbuf.st_uid) {
if(stbuf.st_mode & S_IRUSR)
(*perms)|= 1;
if(stbuf.st_mode & S_IWUSR)
(*perms)|= 2;
if(stbuf.st_mode & S_IXUSR)
(*perms)|= 4;
if(!is_root)
return(1);
}
/* group membership is a complicated thing */
if(is_root || Sfile_being_group_member(&stbuf,0)>0) {
if(stbuf.st_mode & S_IRGRP)
(*perms)|= 1;
if(stbuf.st_mode & S_IWGRP)
(*perms)|= 2;
if(stbuf.st_mode & S_IXGRP)
(*perms)|= 4;
if(!is_root)
return(2);
}
if(stbuf.st_mode & S_IROTH)
(*perms)|= 1;
if(stbuf.st_mode & S_IWOTH)
(*perms)|= 2;
if(stbuf.st_mode & S_IXOTH)
(*perms)|= 4;
if(is_root)
return(1);
return(3);
}
int Sfile_select(int *fds, int fdcount, int fdidx[3], unsigned int microsec,
int flag)
/*
bit0= check for reading (and choose one into fdidx[0])
bit1= check for writing (and choose one into fdidx[1])
bit2= check for exception (and choose one into fdidx[2])
bit3= initialize fdidx
return-bits are set according to matching flag-bits
*/
{
struct timeval wt;
fd_set rds,wts,exs,*s;
int ready,ret,i,j,max_fd= -1;
if(flag&8)
for(j=0;j<3;j++)
fdidx[j]= 0;
wt.tv_sec= microsec/1000000;
wt.tv_usec= microsec%1000000;
FD_ZERO(&rds);
FD_ZERO(&wts);
FD_ZERO(&exs);
for(i= 0;i<fdcount;i++) {
if(fds[i]<0)
continue;
if(flag&1)
FD_SET(fds[i],&rds);
if(flag&2)
FD_SET(fds[i],&wts);
if(flag&4)
FD_SET(fds[i],&exs);
if(fds[i]>max_fd)
max_fd= fds[i];
}
ready= select(max_fd+1,&rds,&wts,&exs,&wt);
if(ready<=0)
return(0);
ret= 0;
if(fdcount>0)
for(j=0;j<2;j++)
fdidx[j]= (fdidx[j]+1)%fdcount;
for(i= 0;i<fdcount;i++) {
for(j=0;j<3;j++) {
if(j==0)
s= &rds;
else if(j==1)
s= &wts;
else
s= &exs;
if((flag&(1<<j)) && !(ret&(1<<j))) {
if(fds[fdidx[j]]<0)
fdidx[j]= (fdidx[j]+1)%fdcount;
else if(FD_ISSET(fds[fdidx[j]],s))
ret|= (1<<j);
else
fdidx[j]= (fdidx[j]+1)%fdcount;
}
}
}
return(ret);
}
int Sfile_identical(char *file1, char *file2, int flag)
/*
bit0= check whether it is the same i-node
*/
{
FILE *fp1,*fp2;
struct stat stbuf;
int ret,c1,c2;
ino_t ino1,ino2;
dev_t dev1,dev2;
ret= 0;
if(flag&1){
if(stat(file1,&stbuf)==-1) return(0);
ino1= stbuf.st_ino;
dev1= stbuf.st_dev;
if(stat(file2,&stbuf)==-1) return(0);
ino2= stbuf.st_ino;
dev2= stbuf.st_dev;
return((ino1==ino2) && (dev1==dev2));
}
fp1= fopen(file1,"rb");
fp2= fopen(file2,"rb");
if(fp1==NULL||fp2==NULL) goto fertig;
while(1){
c1= fgetc(fp1);
c2= fgetc(fp2);
if(c1==EOF && c2==EOF){
ret= 1;
break;
}
if(c1!=c2)
break;
}
fertig:;
if(fp1!=NULL) fclose(fp1);
if(fp2!=NULL) fclose(fp2);
return(ret);
}
char *Sfile_datestr(time_t tim, short int flag)
/*
bit0=with hours+minutes
bit1=with seconds
bit8= local time rather than UTC
*/
{
static char zeitcode[80]={"000000"};
char puff[80];
struct tm *azt;
if(flag&256)
azt = localtime(&tim);
else
azt = gmtime(&tim);
if(azt->tm_year>99)
sprintf(zeitcode,"%c%1.1d%2.2d%2.2d",
'A'+(azt->tm_year-100)/10,azt->tm_year%10,
azt->tm_mon+1,azt->tm_mday);
else
sprintf(zeitcode,"%2.2d%2.2d%2.2d",
azt->tm_year,azt->tm_mon+1,azt->tm_mday);
if(flag&1){
sprintf(puff,".%2.2d%2.2d",azt->tm_hour,azt->tm_min);
strcat(zeitcode,puff);
}
if(flag&2){
sprintf(puff,"%2.2d",azt->tm_sec);
strcat(zeitcode,puff);
}
return(zeitcode);
}
int Sfile_scale(double value, char *result, int siz, double thresh, int flag)
/*
bit0= eventually ommit 'b'
bit1= make text as short as possible
bit2= no fraction (if it would fit at all)
*/
{
char scale_c,scales[6],form[80];
int i,dec_siz= 0,avail_siz= 1;
strcpy(scales,"bkmgtp");
scale_c= scales[0];
for(i=1;scales[i]!=0;i++) {
if(value<thresh-0.5)
break;
value/= 1024.0;
scale_c= scales[i];
}
if(scale_c!='b' && !(flag&4)) { /* is there room for fractional part ? */
avail_siz= siz-1;
sprintf(form,"%%.lf");
sprintf(result,"%.lf",value);
if(strlen(result)<=avail_siz-2)
dec_siz= 1; /* we are very modest */
}
if(scale_c=='b' && (flag&1)) {
if(flag&2)
sprintf(form,"%%.lf");
else
sprintf(form,"%%%d.lf",siz);
sprintf(result,form,value);
} else {
if(flag&2)
sprintf(form,"%%.lf%%c");
else if(dec_siz>0)
sprintf(form,"%%%d.%dlf%%c",avail_siz,dec_siz);
else
sprintf(form,"%%%d.lf%%c",siz-1);
sprintf(result,form,value,scale_c);
}
return(1);
}
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)
Smem_freE((*argv)[i]);
}
Smem_freE((char *) *argv);
}
*argc= 0;
*argv= NULL;
return(1);
}
int Sfile_make_argv(char *progname, char *line, 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
*/
{
int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc;
char *cpt,*start;
char buf[SfileadrL];
Sfile_destroy_argv(argc,argv,0);
if(flag&2) return(1);
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(isspace(*cpt)) continue;
start= cpt;
buf[0]= 0;
cpt--;
while(*(++cpt)!=0) {
if(isspace(*cpt)) break;
if(*cpt=='"'){
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
l= strlen(buf);
start= cpt+1;
while(*(++cpt)!=0) if(*cpt=='"') break;
if((flag&4) && *cpt==0)
return(0);
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
start= cpt+1;
}else if(*cpt=='\''){
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
l= strlen(buf);
start= cpt+1;
while(*(++cpt)!=0) if(*cpt=='\'') break;
if((flag&4) && *cpt==0)
return(0);
l= cpt-start; bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
start= cpt+1;
}
if(*cpt==0) break;
}
l= cpt-start;
bufl= strlen(buf);
if(l>0) {strncat(buf,start,l);buf[bufl+l]= 0;}
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){
*argc= argzaehl;
if(argzaehl>0) {
*argv= (char **) Smem_malloC(argzaehl*sizeof(char *));
if(*argv==NULL)
return(-1);
}
for(i=0;i<*argc;i++) {
(*argv)[i]= (char *) Smem_malloC((maxl+1));
if((*argv)[i]==NULL)
return(-1);
}
}
}
return(1);
}
/* @param flag bit0= append */
int Sfile_str(char target[SfileadrL], char *source, int flag)
{
int l;
l= strlen(source);
if(flag&1)
l+= strlen(target);
if(l>=SfileadrL) {
fprintf(stderr, "--- Path string overflow (%d > %d). Malicious input ?\n",
l,SfileadrL-1);
return(0);
}
if(flag&1)
strcat(target, source);
else
strcpy(target, source);
return(1);
}
/** Combine environment variable HOME with given filename
@param filename Address relative to $HOME
@param fileadr Resulting combined address
@param fa_size Size of array fileadr
@param flag Unused yet
@return 1=ok , 0=no HOME variable , -1=result address too long
*/
int Sfile_home_adr_s(char *filename, char *fileadr, int fa_size, int flag)
{
char *home;
strcpy(fileadr,filename);
home= getenv("HOME");
if(home==NULL)
return(0);
if(strlen(home)+strlen(filename)+1>=fa_size)
return(-1);
strcpy(fileadr,home);
if(filename[0]!=0){
strcat(fileadr,"/");
strcat(fileadr,filename);
}
return(1);
}
/** Return a double representing seconds and microseconds since 1 Jan 1970 */
double Sfile_microtime(int flag)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
return((double) (tv.tv_sec+1.0e-6*tv.tv_usec));
}
int Sfile_decode_datestr(struct tm *reply, char *text, int flag)
/* YYMMDD[.hhmm[ss]] */
{
int i,l;
time_t current_time;
struct tm *now;
current_time= time(0);
now= localtime(&current_time);
for(i=0;i<sizeof(struct tm);i++)
((char *) reply)[i]= ((char *) now)[i];
if(text[0]<'0'|| (text[0]>'9' && text[0]<'A') || text[0]>'Z')
return(0);
l= strlen(text);
for(i=1;i<l;i++)
if(text[i]<'0'||text[i]>'9')
break;
if(i!=6)
return(0);
if(text[i]==0)
goto decode;
if(text[i]!='.' || (l!=11 && l!=13))
return(0);
for(i++;i<l;i++)
if(text[i]<'0'||text[i]>'9')
break;
if(i!=l)
return(0);
decode:;
reply->tm_hour= 0;
reply->tm_min= 0;
reply->tm_sec= 0;
i= 0;
if(text[0]>='A')
reply->tm_year= 100+(text[i]-'A')*10+text[1]-'0';
else
reply->tm_year= 10*(text[0]-'0')+text[1]-'0';
reply->tm_mon= 10*(text[2]-'0')+text[3]-'0'-1;
reply->tm_mday= 10*(text[4]-'0')+text[5]-'0';
if(l==6)
return(1);
reply->tm_hour= 10*(text[7]-'0')+text[8]-'0';
reply->tm_min= 10*(text[9]-'0')+text[10]-'0';
if(l==11)
return(1);
reply->tm_sec= 10*(text[11]-'0')+text[12]-'0';
return(1);
}
#endif /* Xorriso_sfile_externaL */
/* --------------------------------- misc --------------------------------- */
int Write_to_channel(char *text, int channel_no, int flag)
/*
bit0= packet write disabled, write to stdin resp. stderr
bit1= text is the name of the log file for the given channel
bit2= text is the name of the consolidated packet log file for all channels
bit15= with bit1 or bit2: close depicted log file
*/
{
char *rpt,*npt,ret= 1;
char prefix[16];
static int num_channels= 4;
static char channel_prefixes[4][4]= {".","R","I","M"};
static FILE *logfile_fp[4]= {NULL,NULL,NULL,NULL};
static FILE *pktlog_fp= NULL;
if(channel_no<0 || channel_no>=num_channels)
return(-1);
/* Logfiles */
if((flag&2) && logfile_fp[channel_no]!=NULL) {
fprintf(logfile_fp[channel_no],
"! end ! end ! end ! end ! end ! end ! end ! end xorriso log : %s : %s\n",
channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
fclose(logfile_fp[channel_no]);
logfile_fp[channel_no]= NULL;
}
if((flag&4) && pktlog_fp!=NULL) {
fprintf(pktlog_fp,
"I:1:! end ! end ! end ! end ! end ! end ! end ! end xorriso log : %s : %s\n",
channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
fclose(pktlog_fp);
pktlog_fp= NULL;
}
if(flag&(1<<15))
return(1);
if((flag&2)) {
logfile_fp[channel_no]= fopen(text,"a");
if(logfile_fp[channel_no]==NULL)
return(0);
fprintf(logfile_fp[channel_no],
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xorriso log : %s : %s\n",
channel_prefixes[channel_no],Sfile_datestr(time(0),1|2|256));
fflush(logfile_fp[channel_no]);
}
if((flag&4)) {
pktlog_fp= fopen(text,"a");
if(pktlog_fp==NULL)
return(0);
fprintf(pktlog_fp,
"I:1:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! xorriso log : . : %s\n",
Sfile_datestr(time(0),1|2|256));
fflush(pktlog_fp);
}
if(flag&(2|4))
return(1);
if(flag&1) {
if(channel_no==1 || channel_no==3)
printf("%s",text);
if(channel_no==2 || channel_no==3)
fprintf(stderr,"%s",text);
if(logfile_fp[channel_no]!=NULL) {
fprintf(logfile_fp[channel_no],"%s",text);
fflush(logfile_fp[channel_no]);
}
if(pktlog_fp!=NULL)
return(1);
}
rpt= text;
sprintf(prefix,"%s:x: ",channel_prefixes[channel_no]);
while(*rpt!=0) {
npt= strchr(rpt,'\n');
if(npt==NULL)
prefix[2]= '0';
else
prefix[2]= '1';
if(!(flag&1)) {
ret= fwrite(prefix,5,1,stdout);
if(ret<=0)
return(0);
}
if(pktlog_fp!=NULL) {
ret= fwrite(prefix,5,1,pktlog_fp);
if(ret<=0)
return(0);
}
if(npt==NULL) {
if(!(flag&1)) {
ret= fwrite(rpt,strlen(rpt),1,stdout);
if(ret<=0)
return(0);
ret= fwrite("\n",1,1,stdout);
if(ret<=0)
return(0);
}
if(pktlog_fp!=NULL) {
ret= fwrite(rpt,strlen(rpt),1,pktlog_fp);
if(ret<=0)
return(0);
ret= fwrite("\n",1,1,pktlog_fp);
if(ret<=0)
return(0);
}
break;
} else {
if(!(flag&1)) {
ret= fwrite(rpt,npt+1-rpt,1,stdout);
if(ret<=0)
return(0);
}
if(pktlog_fp!=NULL) {
ret= fwrite(rpt,npt+1-rpt,1,pktlog_fp);
if(ret<=0)
return(0);
}
}
rpt= npt+1;
}
if(!(flag&1))
fflush(stdout);
if(pktlog_fp!=NULL)
fflush(pktlog_fp);
return(1);
}
int Exec_cmd(char *prog, char *cmd, char *simple_arg, char **argv,
char errmsg[SfileadrL], int flag)
/*
bit0= package mode (!bit0 of Write_to_channel())
*/
{
int wait_status,is_dead= 0,pipes_open= 0,ret,channel_no;
int stdout_pipe[2],stderr_pipe[2],fds[2],fdidx[3];
char **exec_argv,*simple_argv[3],buffer[256];
pid_t pid,dead_pid;
static int debug= 0;
errmsg[0]= 0;
if(debug)
fprintf(stderr,"Exec_cmd():fork\n");
/* create pipes */
if(pipe(stdout_pipe)==-1) {
cannot_make_pipe:;
sprintf(errmsg,"%s : cannot create two pipes\n reason given: %s\n",
prog,strerror(errno));
return(-1);
}
if(pipe(stderr_pipe)==-1) {
close(stdout_pipe[0]);
close(stdout_pipe[1]);
goto cannot_make_pipe;
}
pipes_open= 1;
pid= fork();
if(pid==-1) {
sprintf(errmsg,"%s : cannot fork a new process\n reason given: %s\n",
prog,strerror(errno));
{ret= -1; goto father_ex;}
} else if(pid>0) { /* original process */
if(debug)
fprintf(stderr,"Exec_cmd():father\n");
/* close unused pipe ends so we register EOF by the child process */
close(stdout_pipe[1]);
close(stderr_pipe[1]);
fds[0]= stdout_pipe[0];
fds[1]= stderr_pipe[0];
is_dead= 0;
while(1) {
if((fds[0]==-1 && fds[1]==-1)) { /* not before both pipes have closed */
dead_pid= wait3(&wait_status,WNOHANG,NULL);
if(dead_pid==pid) {
is_dead= 1;
break;
} else if(dead_pid<0) {
sprintf(errmsg,
"%s : error while waiting for end of sub process\n %s\n",
prog,strerror(errno));
{ret= -1; goto father_ex;}
}
}
/* check for input at both pipes */;
ret= Sfile_select(fds,2,fdidx,100000,1|8);
if(ret<=0 || fdidx[0]<0 || fdidx[0]>1)
continue;
ret= read(fds[fdidx[0]],buffer,sizeof(buffer)-3);
if(ret<0) {
sprintf(errmsg,"--- error %d on read from %s pipe : %s\n",
errno,(fdidx[0]?"stdout":"stderr"),
(errno>0?strerror(errno):"-unknown error-"));
{ret= -1; goto father_ex;}
}
if(ret==0) {
fds[fdidx[0]]= -1;
continue;
}
buffer[ret]= 0;
channel_no= fdidx[0]+1;
ret= Write_to_channel(buffer,channel_no,!(flag&1));
if(ret<=0) {
sprintf(errmsg,"--- error %d on write to %s : %s\n",
errno,(fdidx[0]?"stdout":"stderr"),
(errno>0?strerror(errno):"-unknown error-"));
{ret= -1; goto father_ex;}
}
}
ret= 127;
if(WIFEXITED(wait_status))
ret= WEXITSTATUS(wait_status);
father_ex:;
if(pipes_open) {
close(stdout_pipe[0]);
close(stderr_pipe[0]);
}
return(ret);
}
if(debug)
fprintf(stderr,"Exec_cmd():child\n");
/* Connect stdout and stderr to the appropriate ends of the pipes. */
close(1);
ret= dup(stdout_pipe[1]);
if(ret==-1) {
cannot_dup_pipe:;
sprintf(errmsg,
"%s : cannot redirect standard i/o to pipes\n reason given: %s\n",
prog,strerror(errno));
Write_to_channel(errmsg,2,!(flag&1));
exit(1);
}
close(2);
ret= dup(stderr_pipe[1]);
if(ret==-1)
goto cannot_dup_pipe;
/* close pipes so we register EOF by the father process */
close(stdout_pipe[0]);
close(stdout_pipe[1]);
close(stderr_pipe[0]);
close(stderr_pipe[1]);
/* switch process to desired program */
if(simple_arg!=NULL) {
simple_argv[0]= cmd;
simple_argv[1]= simple_arg;
simple_argv[2]= NULL;
exec_argv= simple_argv;
} else {
exec_argv= argv;
}
if(debug) { int i;
fprintf(stderr,"debug: cmd='%s'\n",cmd);
for(i=0;exec_argv[i]!=NULL;i++)
fprintf(stderr,"debug: argv[%d]='%s'\n",i,exec_argv[i]);
}
if(strchr(cmd,'/')!=NULL)
execv(cmd,exec_argv);
else
execvp(cmd,exec_argv);
sprintf(errmsg,"%s : cannot start program %s\n reason given: %s\n",
prog,cmd,strerror(errno));
Write_to_channel(errmsg,2,!(flag&1));
exit(127);
}
int Exec_cmd_line(char *prog, char *cmd_line,
int extra_argc, char **extra_argv, char *errmsg, int flag)
/*
bit0= packade mode (!bit0 of Write_to_channel())
*/
{
int ret,cmd_argc= 0,i,w;
char **cmd_argv= NULL,**argv= NULL;
ret= Sfile_make_argv("",cmd_line,&cmd_argc,&cmd_argv,1);
if(ret<=0)
{ret= -1; goto ex;}
argv= TSOB_FELD(char *,cmd_argc+extra_argc+1);
if(argv==NULL)
{ret= -1; goto ex;}
w= 0;
for(i=0;i<cmd_argc;i++)
argv[w++]= cmd_argv[i];
for(i=0;i<extra_argc;i++)
argv[w++]= extra_argv[i];
argv[w]= NULL;
ret= Exec_cmd(prog,argv[0],NULL,argv,errmsg,flag&1);
ex:;
if(argv!=NULL)
free((char *) argv);
Sfile_make_argv("",cmd_line,&cmd_argc,&cmd_argv,2);
return(ret);
}
int Strcmp(const void *pt1, const void *pt2)
{
return(strcmp(*((char **) pt1), *((char **) pt2)));
}
int Sort_argv(int argc, char **argv, int flag)
{
if(argc<=0)
return(2);
qsort(argv,(size_t) argc,sizeof(char *),Strcmp);
return(1);
}
int Set_bit(int *data, int idx, int flag)
/*
bit0= clear bit
*/
{
if(idx<0 || idx>31)
return(0);
if(flag&1)
(*data)&= ~(1<<idx);
else
(*data)|= (1<<idx);
return(1);
}
FILE *Afile_fopen(char *filename, char *mode, int flag)
/*
bit0= do not print error message on failure
bit6= write packeted error messages (see Write_to_channel())
*/
{
FILE *fp= NULL;
char errmsg[2*SfileadrL];
if(strcmp(filename,"-")==0) {
if(mode[0]=='a' || mode[0]=='w' ||
(mode[0]=='r' && mode[1]=='+') ||
(mode[0]=='r' && mode[1]=='b' && mode[2]=='+'))
fp= stdout;
else
fp= stdin;
} else if(strncmp(filename,"tcp:",4)==0){
sprintf(errmsg,"sorry - TCP/IP service isn't implemented yet.\n");
Write_to_channel(errmsg,2,!(flag&64));
} else if(strncmp(filename,"file:",5)==0){
fp= fopen(filename+5,mode);
} else {
fp= fopen(filename,mode);
}
if(fp==NULL){
if(!(flag&1)) {
sprintf(errmsg,"failed to open file '%s' in %s mode\n",filename,mode);
if(errno>0)
sprintf(errmsg+strlen(errmsg)," %s\n",strerror(errno));
Write_to_channel(errmsg,2,!(flag&64));
}
return(NULL);
}
return(fp);
}
/** Convert a text into a number of type double and multiply it by unit code
[kmgtpe] (2^10 to 2^60) or [s] (2048). (Also accepts capital letters.)
@param text Input like "42", "2k", "3.14m" or "-1g"
@param flag Bitfield for control purposes:
bit0= return -1 rathern than 0 on failure
@return The derived double value
*/
double Scanf_io_size(char *text, int flag)
/*
bit0= default value -1 rather than 0
*/
{
int c;
double ret= 0.0;
if(flag&1)
ret= -1.0;
if(text[0]==0)
return(ret);
sscanf(text,"%lf",&ret);
c= text[strlen(text)-1];
if(c=='k' || c=='K') ret*= 1024.0;
if(c=='m' || c=='M') ret*= 1024.0*1024.0;
if(c=='g' || c=='G') ret*= 1024.0*1024.0*1024.0;
if(c=='t' || c=='T') ret*= 1024.0*1024.0*1024.0*1024.0;
if(c=='p' || c=='P') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0;
if(c=='e' || c=='E') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0*1024.0;
if(c=='s' || c=='S') ret*= 2048.0;
return(ret);
}
int Decode_date_input_format(struct tm *erg, char *text, int flag)
/* MMDDhhmm[[CC]YY][.ss]] */
{
int i,l,year;
time_t current_time;
struct tm *now;
current_time= time(0);
now= localtime(&current_time);
for(i=0;i<sizeof(struct tm);i++)
((char *) erg)[i]= ((char *) now)[i];
l= strlen(text);
for(i=0;i<l;i++)
if(text[i]<'0'||text[i]>'9')
break;
if(i!=8 && i!=10 && i!=12)
return(0);
if(text[i]==0)
goto decode;
if(text[i]!='.' || l!=15)
return(0);
i++;
if(text[i]<'0'||text[i]>'9')
return(0);
i++;
if(text[i]<'0'||text[i]>'9')
return(0);
decode:;
/* MMDDhhmm[[CC]YY][.ss]] */
i= 0;
erg->tm_mon= 10*(text[0]-'0')+text[1]-'0'-1;
erg->tm_mday= 10*(text[2]-'0')+text[3]-'0';
erg->tm_hour= 10*(text[4]-'0')+text[5]-'0';
erg->tm_min= 10*(text[6]-'0')+text[7]-'0';
erg->tm_sec= 0;
if(l==8)
return(1);
if(l>10){
year= 1000*(text[8]-'0')+100*(text[9]-'0')+10*(text[10]-'0')+(text[11]-'0');
}else{
year= 1900+10*(text[8]-'0')+(text[9]-'0');
if(year<1970)
year+= 100;
}
erg->tm_year= year-1900;
if(l<=12)
return(1);
erg->tm_sec= 10*(text[13]-'0')+text[14]-'0';
return(1);
}
int Decode_date_weekday(char *text, int flag)
{
int i;
static char days[][4]= {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", ""};
for(i= 0; days[i][0]!=0; i++)
if(strncmp(text,days[i],3)==0)
return(i);
if((strlen(text)==3 || (strlen(text)==4 && text[3]==',')) &&
isalpha(text[0]) && isalpha(text[1]) && isalpha(text[2]))
return(7);
return(-1);
}
int Decode_date_month(char *text, int flag)
{
int i;
static char months[][4]= {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
for(i= 0; months[i][0]!=0; i++)
if(strncmp(text,months[i],3)==0)
return(i);
return(-1);
}
/* @return -1=not a number, -2=not a day , 1 to 31 day of month */
int Decode_date_mday(char *text, int flag)
{
int ret, i;
for(i= 0; text[i]!=0; i++)
if(!isdigit(text[i]))
return(-1);
if(strlen(text)>2 || text[0]==0)
return(-2);
sscanf(text, "%d", &ret);
if(ret<=0 || ret>31)
return(-2);
return(ret);
}
int Decode_date_hms(char *text, struct tm *erg, int flag)
{
int i, hour= -1, minute= -1, second= 0;
for(i= 0; i<9; i+= 3) {
if(i==6&&text[i]==0)
break;
if(!isdigit(text[i]))
return(-1);
if(!isdigit(text[i+1]))
return(-1);
if(text[i+2]!=':' && !(text[i+2]==0 && i>=3))
return(-1);
if(i==0)
sscanf(text+i,"%d",&hour);
else if(i==3)
sscanf(text+i,"%d",&minute);
else
sscanf(text+i,"%d",&second);
}
if(hour<0 || hour>23 || minute<0 || minute>59 || second>59)
return(-1);
erg->tm_hour= hour;
erg->tm_min= minute;
erg->tm_sec= second;
return(1);
}
/* @return -1=not a number, -2=not a year , >=0 years AD */
int Decode_date_year(char *text, int flag)
{
int ret, i;
for(i= 0; text[i]!=0; i++)
if(!isdigit(text[i]))
return(-1);
if(strlen(text)!=4)
return(-2);
sscanf(text, "%d", &ret);
if(ret<0 || ret>3000)
return(-2);
return(ret);
}
int Decode_date_timezone(char *text, struct tm *erg, int flag)
{
int i;
static char tzs[][5]= {"GMT", "CET", "CEST", "0000", ""};
for(i= 0; tzs[i][0]!=0; i++)
if(strcmp(text,tzs[i])==0) {
/* ??? >>> what to do with timezone info ? Add to ->tm_hour ? */
return(1);
}
if(text[0]=='+' || text[0]=='-') {
for(i= 1; text[i]!=0; i++)
if(!isdigit(text[i]))
return(-1);
if(i!=5)
return(-1);
/* ??? >>> what to do with timezone info ? Add to ->tm_hour ? */
return(1);
} else {
for(i= 0; text[i]!=0; i++)
if(text[i]<'A' || text[i]>'Z')
return(-1);
if(i!=3 && i!=4)
return(-1);
return(2);
}
}
int Decode_date_output_format(struct tm *erg, char *text, int flag)
/* Thu Nov 8 09:07:50 CET 2007 */
/* Sat, 03 Nov 2007 08:58:30 +0100 */
/* Nov 7 23:24 */
{
int ret, i, argc= 0, seen_year= 0, seen_month= 0, seen_day= 0, seen_time= 0;
char **argv= NULL;
struct tm *now;
time_t timep;
memset(erg, 0, sizeof(*erg));
erg->tm_isdst= -1;
ret= Sfile_make_argv("xorriso", text, &argc, &argv, 0);
if(ret<=0)
goto ex;
for(i= 1; i<argc; i++) {
if(!seen_month) {
ret= Decode_date_month(argv[i], 0);
if(ret>=0) {
seen_month= 1;
erg->tm_mon= ret;
continue;
}
}
if(!seen_day) {
ret= Decode_date_mday(argv[i], 0);
if(ret>0) {
seen_day= 1;
erg->tm_mday= ret;
continue;
}
if(ret==-2) /* first pure number must be day of month */
{ret= 0; goto ex;}
}
if(!seen_time) {
ret= Decode_date_hms(argv[i], erg, 0);
if(ret>0) {
seen_time= 1;
continue;
}
}
if(!seen_year) {
ret= Decode_date_year(argv[i], 0);
if(ret>0) {
erg->tm_year= ret-1900;
seen_year= 1;
continue;
}
}
/* ignorants have to stay at the end of the loop */
ret= Decode_date_timezone(argv[i], erg, 0);
if(ret>=0)
continue;
ret= Decode_date_weekday(argv[i], 0);
if(ret>=0)
continue; /* ignore weekdays */
{ret= 0; goto ex;} /* unrecognizable component */
}
if(!(seen_day && seen_month))
{ret= 0; goto ex;}
if(!seen_year) { /* then use this year */
timep= time(NULL);
now= localtime(&timep);
erg->tm_year= now->tm_year;
}
ret= 1;
ex:
Sfile_make_argv("", "", &argc, &argv, 2); /* release storage */
return(ret);
}
int Decode_xorriso_timestamp(struct tm *erg, char *code, int flag)
/* 2007.11.07.225624 */
{
char buf[20];
int year,month,day,hour= 0,minute= 0,second= 0, i, l, mem;
memset(erg, 0, sizeof(*erg));
erg->tm_isdst= -1;
l= strlen(code);
if(l>17 || l<10)
return(0);
strcpy(buf, code);
for(i= 0; buf[i]!=0 && i<4; i++)
if(!isdigit(buf[i]))
return(0);
if(buf[4]!='.')
return(0);
buf[4]= 0;
sscanf(buf, "%d", &year);
if(year<1900 || year>3000)
return(0);
if(!(isdigit(buf[5]) && isdigit(buf[6]) && buf[7]=='.'))
return(0);
buf[7]= 0;
sscanf(buf+5, "%d", &month);
if(month<1 || month>12)
return(0);
if(!(isdigit(buf[8]) && isdigit(buf[9]) && (buf[10]=='.' || buf[10]==0)))
return(0);
buf[10]= 0;
sscanf(buf+8, "%d", &day);
if(day<1 || day>31)
return(0);
if(l==10)
goto done;
if(!(isdigit(buf[11]) && isdigit(buf[12]) &&
(isdigit(buf[13]) || buf[13]==0)))
return(0);
mem= buf[13];
buf[13]= 0;
sscanf(buf+11, "%d", &hour);
buf[13]= mem;
if(hour<0 || hour>23)
return(0);
if(l==13)
goto done;
if(!(isdigit(buf[13]) && isdigit(buf[14]) &&
(isdigit(buf[15]) || buf[15]==0)))
return(0);
mem= buf[15];
buf[15]= 0;
sscanf(buf+13, "%d", &minute);
buf[15]= mem;
if(minute<0 || minute>59)
return(0);
if(l==15)
goto done;
if(!(isdigit(buf[15]) && isdigit(buf[16]) && buf[17]==0))
return(0);
sscanf(buf+15, "%d", &second);
if(second<0 || second>59)
return(0);
done:;
erg->tm_year= year-1900;
erg->tm_mon= month-1;
erg->tm_mday= day;
erg->tm_hour= hour;
erg->tm_min= minute;
erg->tm_sec= second;
return(1);
}
time_t Decode_timestring(char *code, time_t *date, int flag)
{
char *cpt,scale_chr;
double value,seconds;
struct tm result_tm;
int seconds_valid= 0;
*date= 0;
cpt= code;
if(code[0]=='-' || code[0]=='+' || code[0]=='='){
if(code[1]==0)
return(0);
if(!isdigit(code[1]))
return(0);
value= -1;
if(code[0]=='=') {
seconds= 0;
sscanf(code+1,"%lf",&value);
} else {
seconds= time(NULL);
sscanf(code,"%lf",&value);
}
scale_chr= code[strlen(code)-1];
if(isalpha(scale_chr))
scale_chr= tolower(scale_chr);
if (scale_chr=='s') seconds+= 1.0*value;
else if(scale_chr=='h') seconds+= 3600.0*value;
else if(scale_chr=='d') seconds+= 86400.0*value;
else if(scale_chr=='w') seconds+= 86400.0*7.0*value;
else if(scale_chr=='m') seconds+= 86400.0*31.0*value;
else if(scale_chr=='y') seconds+= 86400.0*(365.25*value+1.0);
else seconds+= 1.0*value;
seconds_valid= 1;
goto completed;
} else if(Sfile_decode_datestr(&result_tm,code,0)>0) {
/* YYMMDD[.hhmm[ss]] */
result_tm.tm_isdst= -1;
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
} else if(Decode_date_input_format(&result_tm,code,0)>0) {
/* MMDDhhmm[[CC]YY][.ss]] */
result_tm.tm_isdst= -1;
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
} else if(Decode_xorriso_timestamp(&result_tm, code, 0)>0) {
/* 2007.11.07.225624 */
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
} else if(Decode_date_output_format(&result_tm, code, 0)>0) {
/* Thu Nov 8 09:07:50 CET 2007 */;
/* Sat, 03 Nov 2007 08:58:30 +0100 */;
/* Nov 7 23:24 */;
seconds= mktime(&result_tm);
seconds_valid= 1;
goto completed;
}
return(0);
completed:;
if(!seconds_valid)
return(0);
*date= seconds;
return(1);
}
/* ------------------------------------------------------------------------ */
#ifndef Xorriso_sregex_externaL
#ifndef Smem_malloC
#define Smem_malloC malloc
#endif
#ifndef Smem_freE
#define Smem_freE free
#endif
int Sregex_string_cut(char **handle, char *text, int len, int flag)
/*
bit0= append (text!=NULL)
*/
{
int l=0;
char *old_handle;
if((flag&1)&&*handle!=NULL)
l+= strlen(*handle);
old_handle= *handle;
if(text!=NULL) {
l+= len;
*handle= TSOB_FELD(char,l+1);
if(*handle==NULL) {
*handle= old_handle;
return(0);
}
if((flag&1) && old_handle!=NULL)
strcpy(*handle,old_handle);
else
(*handle)[0]= 0;
if(len>0)
strncat(*handle,text,len);
} else {
*handle= NULL;
}
if(old_handle!=NULL)
Smem_freE(old_handle);
return(1);
}
int Sregex_string(char **handle, char *text, int flag)
/*
bit0= append (text!=NULL)
*/
{
int ret,l=0;
if(text!=NULL)
l= strlen(text);
/* #define Sregex_looking_for_contenT 1 */
#ifdef Sregex_looking_for_contenT
/* a debugging point if a certain text content has to be caught */
if(text!=NULL)
if(strcmp(text,"clear")==0)
ret= 0;
#endif
ret= Sregex_string_cut(handle,text,l,flag&1);
return(ret);
}
/*
from Juergen Helbing's yencode-c.txt
found at www.yenc.org , Feb 4, 2002
license : "It is public domain - as well as the yEnc specification"
some alterations made to adapt it to Sregex_crc32()
seems to be compatible with SFV/CSV files
*/
int Sregex_crc32_yenc(char *data, int len, unsigned long *crc, int flag)
/*
bit0= start of data polynom
*/
{
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
static unsigned long crc_tab[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
int k;
unsigned long crc_val,ch1,ch2,cc;
if(flag&1)
crc_val = ~0;
else
crc_val = ~*crc;
for(k=0;k<len;k++) {
cc= data[k] & 0xffL;
ch1= (crc_val ^ cc) & 0xffL;
ch1= crc_tab[ch1];
ch2= (crc_val>>8L) & 0xffffffL;
crc_val= ch1 ^ ch2;
}
*crc= ~crc_val;
return(1);
}
#endif /* Xorriso_sregex_externaL */
#ifndef Xorriso_text_shellsafe_externaL
char *Text_shellsafe(char *in_text, char *out_text, int flag)
{
int l,i,w=0;
/* enclose everything by hard quotes */
l= strlen(in_text);
out_text[w++]= '\'';
for(i=0;i<l;i++){
if(in_text[i]=='\''){
if(w+7>5*SfileadrL)
goto overflow;
/* escape hard quote within the text */
out_text[w++]= '\'';
out_text[w++]= '"';
out_text[w++]= '\'';
out_text[w++]= '"';
out_text[w++]= '\'';
} else {
if(w+3>5*SfileadrL) {
overflow:;
strncpy(out_text, "'xorriso: TEXT MUCH TOO LONG ... ",33);
break;
}
out_text[w++]= in_text[i];
}
}
out_text[w++]= '\'';
out_text[w++]= 0;
return(out_text);
}
#endif /* ! Xorriso_text_shellsafe_externaL */
#ifndef Xorriso_fileliste_externaL
/* ??? ts A71006 : Is this compatible with mkisofs pathspecs ?
I dimly remember so */
int Fileliste__target_source_limit(char *line, char sep, char **limit_pt,
int flag)
{
char *npt;
for(npt= line;*npt!=0;npt++) {
if(*npt=='\\') {
if(*(npt+1)!=0)
npt++;
continue;
}
if(*npt=='=')
break;
}
if(*npt==0)
npt= NULL;
(*limit_pt)= npt;
return(npt!=NULL);
}
int Fileliste__unescape_target(char *line, char *endpt, char sep, int flag)
{
char *wpt,*rpt;
if(endpt==NULL)
endpt= line+strlen(line);
/* unescape sep and '\\' */
wpt= line;
for(rpt= line; rpt<endpt; rpt++) {
if(*rpt=='\\') {
if(*(rpt+1)==sep || *(rpt+1)=='\\')
rpt++;
}
*(wpt++)= *rpt;
}
*wpt= 0;
return(1);
}
int Fileliste__escape_target(char *target, int flag)
{
int i,offset= 0;
/* escape '=' and '\\' in target address */
for(i= strlen(target)-1;i>=0;i--)
if(target[i]=='=' || target[i]=='\\')
offset++;
target[strlen(target)+offset]= 0;
for(i= strlen(target)-1;i>=0;i--) {
if(target[i]=='=' || target[i]=='\\') {
target[i+offset]= target[i];
offset--;
target[i+offset]= '\\';
} else {
target[i+offset]= target[i];
}
}
return(1);
}
#endif /* ! Xorriso_fileliste_externaL */
#define Xorriso_cleanup_externaL 1
#ifndef Xorriso_cleanup_externaL
/* <<< ??? ts A71006 : will this be replaced by the libburn signal handler ? */
#include <signal.h>
typedef void (*sighandler_t)(int);
/* Signals to be caught */
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
SIGTTOU,
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
"SIGTTOU",
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 24;
/* Signals not to be caught */
static int non_signal_list[]= {
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH, -1
};
static int non_signal_list_count= 5;
/* run time dynamic part */
static char cleanup_msg[SfileadrL]= {""};
static int cleanup_exiting= 0;
static void *cleanup_app_handle= NULL;
static Cleanup_app_handler_T cleanup_app_handler= NULL;
static int cleanup_perform_app_handler_first= 0;
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
{
int ret;
if(cleanup_perform_app_handler_first)
if(cleanup_app_handler!=NULL) {
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
if(ret==2)
return(2);
}
if(cleanup_exiting) {
if(cleanup_msg[0]!=0)
fprintf(stderr,"%s\n",cleanup_msg);
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
getpid(),signum);
return(0);
}
cleanup_exiting= 1;
if(cleanup_msg[0]!=0)
fprintf(stderr,"%s\n",cleanup_msg);
alarm(0);
if(!cleanup_perform_app_handler_first)
if(cleanup_app_handler!=NULL)
(*cleanup_app_handler)(cleanup_app_handle,signum,0);
exit(exit_value);
}
static void Cleanup_handler_generic(int signum)
{
int i;
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
for(i= 0; i<signal_list_count; i++)
if(signum==signal_list[i]) {
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
signal_name_list[i],errno);
break;
}
Cleanup_handler_exit(1,signum,0);
}
static int Cleanup_set_handlers(void *handle,
Cleanup_app_handler_T handler, int flag)
/*
bit0= set to default handlers
bit1= set to ignore
bit2= set cleanup_perform_app_handler_first
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
*/
{
int i,j,max_sig= -1,min_sig= 0x7fffffff;
sighandler_t sig_handler;
cleanup_msg[0]= 0;
cleanup_app_handle= handle;
cleanup_app_handler= handler;
if(flag&4)
cleanup_perform_app_handler_first= 1;
if(flag&1)
sig_handler= SIG_DFL;
else if(flag&2)
sig_handler= SIG_IGN;
else
sig_handler= Cleanup_handler_generic;
/* set all signal numbers between the lowest and highest in the list
except those in the non-signal list */
for(i= 0; i<signal_list_count; i++) {
if(signal_list[i]>max_sig)
max_sig= signal_list[i];
if(signal_list[i]<min_sig)
min_sig= signal_list[i];
}
for(i= min_sig; i<=max_sig; i++) {
for(j= 0; j<non_signal_list_count; j++)
if(i==non_signal_list[j])
break;
if(j>=non_signal_list_count) {
if(i==SIGABRT && (flag&8))
signal(i,Cleanup_handler_generic);
else
signal(i,sig_handler);
}
}
return(1);
}
#endif /* ! Xorriso_cleanup_externaL */
/* ------------------------------------------------------------------------ */
/* DirseQ : crawl along a directory's content list */
static int Dirseq_buffer_sizE= 100;
struct DirseQ {
char adr[SfileadrL];
DIR *dirpt;
int count;
char **buffer;
int buffer_size;
int buffer_fill;
int buffer_rpt;
struct DirseQ *next;
};
int Dirseq_destroy(struct DirseQ **o, int flag);
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
int max_replies, int flag);
int Dirseq_new(struct DirseQ **o, char *adr, int flag)
/*
bit0= with non-fatal errors do not complain about failed opendir()
*/
{
int ret,i,severe_error;
struct DirseQ *m;
m= *o= TSOB_FELD(struct DirseQ,1);
if(m==NULL)
return(-1);
m->adr[0]= 0;
m->dirpt= NULL;
m->count= 0;
m->buffer= NULL;
m->buffer_size= 0;
m->buffer_fill= 0;
m->buffer_rpt= 0;
m->next= NULL;
if(Sfile_str(m->adr, adr, 0)<=0)
{ret= 0; goto failed;}
m->buffer= TSOB_FELD(char *,Dirseq_buffer_sizE);
if(m->buffer==NULL)
{ret= -1; goto failed;}
m->buffer_size= Dirseq_buffer_sizE;
for(i= 0;i<m->buffer_size;i++)
m->buffer[i]= NULL;
if(adr[0]==0)
m->dirpt= opendir(".");
else
m->dirpt= opendir(adr);
if(m->dirpt==NULL) {
severe_error= (errno && errno!=ENOENT && errno!=EACCES && errno!=ENOTDIR);
if(severe_error || !(flag&1))
fprintf(stderr,"opendir(%s) failed : %s\n",adr,strerror(errno));
ret= -severe_error;
goto failed;
}
return(1);
failed:;
Dirseq_destroy(o,0);
return(ret);
}
int Dirseq_destroy(struct DirseQ **o, int flag)
{
int i;
if(*o==NULL)
return(0);
if((*o)->dirpt!=NULL)
closedir((*o)->dirpt);
if((*o)->buffer!=NULL) {
for(i=0;i<(*o)->buffer_size;i++)
if((*o)->buffer[i]!=NULL)
free((*o)->buffer[i]);
free((char *) (*o)->buffer);
}
free((char *) *o);
(*o)= NULL;
return(1);
}
int Dirseq_set_next(struct DirseQ *o, struct DirseQ *next, int flag)
{
o->next= next;
return(1);
}
int Dirseq_get_next(struct DirseQ *o, struct DirseQ **next, int flag)
{
*next= o->next;
return(1);
}
int Dirseq_get_adr(struct DirseQ *o, char **adrpt, int flag)
{
*adrpt= o->adr;
return(1);
}
int Dirseq_rewind(struct DirseQ *o, int flag)
{
rewinddir(o->dirpt);
return(1);
}
int Dirseq_next_adr(struct DirseQ *o, char reply[SfileadrL], int flag)
/*
flag:
bit0= permission to use buffer
bit1= do not increment counter
bit2= ignore buffer in any case
bit3= do not exclude '.' and '..'
bit4= sort buffer
bit5= sort only incomplete last buffer
return:
<0 error
0= no more entries available
1= ok, reply is valid
*/
{
int ret;
struct dirent *entry;
char *name;
static int override_flag_0= 0,override_flag_1= 32;
flag= (flag&~override_flag_0)|override_flag_1;
if((flag&1) && o->buffer_rpt>=o->buffer_fill) {
/* permission to buffer and buffer empty : load a buffer */
ret= Dirseq_next_adrblock(o,o->buffer,&(o->buffer_fill),
o->buffer_size,2|4|(flag&16));
if(ret<=0)
return(ret);
o->buffer_rpt= 0;
if((flag&32) && o->buffer_fill<o->buffer_size && o->buffer_fill>0)
Sort_argv(o->buffer_fill,o->buffer,0);
}
if(o->buffer_rpt<o->buffer_fill && !(flag&4)) {
ret= Sfile_str(reply,o->buffer[o->buffer_rpt],0);
Sregex_string(&(o->buffer[o->buffer_rpt]),NULL,0);
if(ret<=0)
return(-1);
(o->buffer_rpt)++;
if(!(flag&2))
o->count++;
return(1);
}
do {
entry= readdir(o->dirpt);
if(entry==NULL) {
/* >>> how to distinguish error from EOF , do i need a (FILE *) ? */
return(0);
}
if(strlen(entry->d_name)>=SfileadrL) {
fprintf(stderr,"--- oversized directory entry (number %d) :\n %s",
o->count+1,entry->d_name);
return(-1);
}
name= entry->d_name;
if(flag&8)
break;
/* skip "." and ".." */
} while(name[0]=='.' && ((name[1]=='.' && name[2]==0) || name[1]==0));
if(Sfile_str(reply,name,0)<=0)
return(-1);
if(!(flag&2))
o->count++;
return(1);
}
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
int max_replies, int flag)
/* @param replies A vector of Sregex_string pointers */
/*
flag:
bit0= permission to use buffer
bit1= do not increment counter
bit2= ignore buffer in any case
bit4= sort replies
return:
<0 error
0= no more entries available
1= ok, reply is valid
*/
{
int i,ret;
char reply[SfileadrL];
*reply_count= 0;
for(i=0;i<max_replies;i++) {
ret= Dirseq_next_adr(o,reply,flag&(1|2|4));
if(ret<0)
return(ret);
if(ret==0)
break;
if(Sregex_string(&(replies[i]),reply,0)<=0)
return(-1);
(*reply_count)++;
}
if((*reply_count)==0)
return(0);
if(flag&16)
Sort_argv(*reply_count,replies,0);
return(1);
}
/* ------------------------------- TreeseQ -------------------------------- */
/* DirseQ : crawl along a filesystem subtree */
struct TreeseQ {
char adr[SfileadrL];
char path[SfileadrL];
struct DirseQ *dir_stack;
struct stat stbuf;
int follow_links;
int unused_yet;
};
int Treeseq_destroy(struct TreeseQ **o, int flag);
/* @param flag bit0= follow symbolic links */
int Treeseq_new(struct TreeseQ **o, char *adr, int flag)
{
int ret;
struct TreeseQ *m;
m= *o= TSOB_FELD(struct TreeseQ,1);
if(m==NULL)
return(-1);
m->adr[0]= 0;
m->path[0]= 0;
m->dir_stack= NULL;
m->follow_links= (flag&1);
m->unused_yet= 1;
if(Sfile_str(m->adr, adr, 0)<=0)
{ret= 0; goto failed;}
strcpy(m->path, adr);
if(m->follow_links)
ret= stat(adr, &(m->stbuf));
else
ret= lstat(adr, &(m->stbuf));
if(ret==-1)
{ret= 0; goto failed;}
if(S_ISDIR(m->stbuf.st_mode)) {
ret= Dirseq_new(&(m->dir_stack), adr, 0);
if(ret<=0)
goto failed;
}
return(1);
failed:;
Treeseq_destroy(o,0);
return(ret);
}
int Treeseq_destroy(struct TreeseQ **o, int flag)
{
struct DirseQ *dirseq, *next;
for(dirseq= (*o)->dir_stack; dirseq!=NULL; dirseq= next) {
next= dirseq->next;
Dirseq_destroy(&dirseq,0);
}
free((char *) *o);
(*o)= NULL;
return(1);
}
/* @return <0 error, 0= no more entries available, 1= ok, reply is valid
*/
int Treeseq_next(struct TreeseQ *o, char adr[SfileadrL], struct stat **stbuf,
int flag)
{
int ret;
char next_name[SfileadrL], *spt;
struct DirseQ *next_dirseq;
if(o->dir_stack==NULL) {
if(!o->unused_yet)
return(0);
strcpy(adr, o->adr);
*stbuf= &(o->stbuf);
o->unused_yet= 0;
return(1);
}
o->unused_yet= 0;
next_in_dirseq:;
ret= Dirseq_next_adr(o->dir_stack, next_name, 1);
if(ret<0)
return(ret);
if(ret>0) {
strcpy(adr, o->path);
ret= Sfile_add_to_path(adr, next_name, 0);
if(ret<=0)
return(-1);
if(o->follow_links)
ret= stat(adr, &(o->stbuf));
else
ret= lstat(adr, &(o->stbuf));
*stbuf= &(o->stbuf);
if(!S_ISDIR(o->stbuf.st_mode))
return(1);
/* Directory found: push new DirseQ on stack */
ret= Dirseq_new(&next_dirseq, adr, 0);
if(ret<=0)
return(-1);
Dirseq_set_next(next_dirseq, o->dir_stack, 0);
o->dir_stack= next_dirseq;
strcpy(o->path, adr);
return(1);
}
/* pop DirseQ from stack */
Dirseq_get_next(o->dir_stack, &next_dirseq, 0);
Dirseq_destroy(&(o->dir_stack), 0);
o->dir_stack= next_dirseq;
spt= strrchr(o->path, '/');
if(spt!=NULL)
(*spt)= 0;
else
o->path[0]= 0;
if(o->dir_stack!=NULL)
goto next_in_dirseq;
return(0); /* it is done */
}
/* ------------------------------ LinkiteM -------------------------------- */
struct LinkiteM {
char *link_path;
dev_t target_dev;
ino_t target_ino;
int link_count;
struct LinkiteM *next;
};
int Linkitem_destroy(struct LinkiteM **o, int flag);
int Linkitem_new(struct LinkiteM **o, char *link_path, dev_t target_dev,
ino_t target_ino, struct LinkiteM *next, int flag)
{
struct LinkiteM *m;
m= *o= TSOB_FELD(struct LinkiteM,1);
if(m==NULL)
return(-1);
m->target_dev= target_dev;
m->target_ino= target_ino;
m->next= next;
m->link_count= 1;
if(next!=NULL)
m->link_count= m->next->link_count+1;
m->link_path= strdup(link_path);
if(m->link_path==NULL)
goto failed;
return(1);
failed:;
Linkitem_destroy(o, 0);
return(-1);
}
int Linkitem_destroy(struct LinkiteM **o, int flag)
{
if((*o)==NULL)
return(0);
if((*o)->link_path!=NULL)
free((*o)->link_path);
free((char *) (*o));
*o= NULL;
return(1);
}
int Linkitem_reset_stack(struct LinkiteM **o, struct LinkiteM *to, int flag)
{
struct LinkiteM *m, *m_next= NULL;
/* Prevent memory corruption */
for(m= *o; m!=to; m= m->next)
if(m==NULL) { /* this may actually not happen */
*o= to;
return(-1);
}
for(m= *o; m!=to; m= m_next) {
m_next= m->next;
Linkitem_destroy(&m, 0);
}
*o= to;
return(1);
}
int Linkitem_find(struct LinkiteM *stack, dev_t target_dev, ino_t target_ino,
struct LinkiteM **result, int flag)
{
struct LinkiteM *m;
for(m= stack; m!=NULL; m= m->next) {
if(target_dev == m->target_dev && target_ino == m->target_ino) {
*result= m;
return(1);
}
}
return(0);
}
/* ------------------------------- FindjoB -------------------------------- */
struct FindjoB {
char *start_path;
char *name_expr;
#ifdef Xorriso_with_regeX
regex_t name_re;
regmatch_t name_match;
#endif
/* b = blockdev, c = chardev, d = directory, p = fifo, f = reg , - = reg,
s = socket, X = other , 0x0 = test inactive
*/
char file_type;
/* 0= echo
>>> 1= rm
>>> 2= rm_r
>>> 3= mv target
4= chown user
5= chgrp group
6= chmod mode_and mode_or
7= alter_date type date
8= lsdl
9= chown_r user
10= chgrp_r group
11= chmod_r mode_and mode_or
12= alter_date_r type date
13= find
*/
int action;
char *target;
uid_t user;
gid_t group;
mode_t mode_and, mode_or;
int type; /* see Xorriso_set_time flag */
time_t date;
struct FindjoB *subjob;
};
int Findjob_destroy(struct FindjoB **job, int flag);
int Findjob_new(struct FindjoB **o, char *start_path, int flag)
{
struct FindjoB *m;
m= *o= TSOB_FELD(struct FindjoB,1);
if(m==NULL)
return(-1);
m->start_path= NULL;