Prepare to execute a command on a remote system.
Copyright (C) 1991, 1992 Ian Lance Taylor
This file is part of the Taylor UUCP package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
const char uux_rcsid
[] = "$Id: uux.c,v 1.1 1993/08/04 19:37:14 jtc Exp $";
/* These character lists should, perhaps, be in sysdep.h. */
/* This is the list of shell metacharacters that we check for. If one
of these is present, we request uuxqt to execute the command with
/bin/sh. Otherwise we let it execute using execve. */
#define ZSHELLCHARS "\"'`*?[;&()|<>\\$"
/* This is the list of word separators. We break filename arguments
#define ZSHELLSEPS ";&*|<> \t"
/* This is the list of word separators without the redirection
#define ZSHELLNONREDIRSEPS ";&*| \t"
char abProgram
[] = "uux";
/* The name of the execute file. */
/* The execute file we are creating. */
/* A list of commands to be spooled. */
static struct scmd
*pasXcmds
;
/* A file to close if we're forced to exit. */
static void uxusage
P((void));
static void uxadd_xqt_line
P((int bchar
, const char *z1
, const char *z2
));
static void uxadd_send_file
P((const char *zfrom
, const char *zto
,
const char *zoptions
, const char *ztemp
,
const struct uuconf_system
*qxqtsys
,
static void uxcopy_stdin
P((FILE *e
));
static void uxrecord_file
P((const char *zfile
));
static void uxabort
P((void));
/* Long getopt options. */
static const struct option asXlongopts
[] = { { NULL
, 0, NULL
, 0 } };
/* -a: requestor address for status reports. */
const char *zrequestor
= NULL
;
/* -b: if true, return standard input on error. */
boolean fretstdin
= FALSE
;
/* -c,-C: if true, copy to spool directory. */
/* -c: set if -c appears explicitly; if it and -l appear, then if the
link fails we don't copy the file. */
boolean fdontcopy
= FALSE
;
/* -I: configuration file name. */
const char *zconfig
= NULL
;
char bgrade
= BDEFAULT_UUX_GRADE
;
/* -l: link file to spool directory. */
/* -n: do not notify upon command completion. */
/* -p: read standard input for command standard input. */
boolean fread_stdin
= FALSE
;
/* -r: do not start uucico when finished. */
/* -s: report status to named file. */
const char *zstatus_file
= NULL
;
/* -W: only expand local file names. */
/* -z: report status only on error. */
boolean ferror_ack
= FALSE
;
struct uuconf_system sxqtsys
;
char abxqt_tname
[CFILE_NAME_LEN
];
char abxqt_xname
[CFILE_NAME_LEN
];
struct uuconf_system slocalsys
;
/* We need to be able to read a single - as an option, which getopt
won't do. So that we can still use getopt, we run through the
options looking for an option "-"; if we find one we change it to
"-p", which is equivalent to "-". */
for (i
= 1; i
< argc
; i
++)
argv
[i
] = zbufcpy ("-p");
for (z
= argv
[i
] + 1; *z
!= '\0'; z
++)
/* If the option takes an argument, and the argument is
not appended, then skip the next argument. */
if (*z
== 'a' || *z
== 'g' || *z
== 'I'
|| *z
== 's' || *z
== 'x')
/* The leading + in the getopt string means to stop processing
options as soon as a non-option argument is seen. */
while ((iopt
= getopt_long (argc
, argv
, "+a:bcCg:I:jlnprs:Wx:z",
asXlongopts
, (int *) NULL
)) != EOF
)
/* Set requestor name: mail address to which status reports
/* Return standard input on error. */
/* Do not copy local files to spool directory. */
/* Copy local files to spool directory. */
/* Configuration file name. */
if (fsysdep_other_config (optarg
))
/* Link file to spool directory. */
/* Do not notify upon command completion. */
/* Read standard input for command standard input. */
/* Do not start uucico when finished. */
/* Report status to named file. */
/* Only expand local file names. */
/* Set debugging level. */
iDebug
|= idebug_parse (optarg
);
/* Report status only on error. */
/* Long option found and flag set. */
if (! UUCONF_GRADE_LEGAL (bgrade
))
ulog (LOG_ERROR
, "Ignoring illegal grade");
bgrade
= BDEFAULT_UUX_GRADE
;
iuuconf
= uuconf_init (&puuconf
, (const char *) NULL
, zconfig
);
if (iuuconf
!= UUCONF_SUCCESS
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
iuuconf
= uuconf_debuglevel (puuconf
, &zdebug
);
if (iuuconf
!= UUCONF_SUCCESS
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
iDebug
|= idebug_parse (zdebug
);
/* The command and files arguments could be quoted in any number of
ways, so we split them apart ourselves. We do this before
calling usysdep_initialize because we want to set fgetcwd
for (i
= optind
; i
< argc
; i
++)
clen
+= strlen (argv
[i
]) + 1;
for (i
= optind
; i
< argc
; i
++)
/* The first argument is the command to execute. */
clen
= strcspn (zargs
, ZSHELLSEPS
);
zcmd
= zbufalc (clen
+ 1);
strncpy (zcmd
, zargs
, clen
);
/* Split the arguments out into an array. We break the arguments
into alternating sequences of characters not in ZSHELLSEPS
and characters in ZSHELLSEPS. We remove whitespace. We
separate the redirection characters '>' and '<' into their
own arguments to make them easier to process below. */
pzargs
= (char **) xmalloc (calloc_args
* sizeof (char *));
for (zarg
= strtok (zargs
, " \t");
zarg
= strtok ((char *) NULL
, " \t"))
if (cargs
+ 1 >= calloc_args
)
pzargs
= (char **) xrealloc ((pointer
) pzargs
,
calloc_args
* sizeof (char *));
clen
= strcspn (zarg
, ZSHELLSEPS
);
pzargs
[cargs
] = zbufalc (clen
+ 1);
memcpy (pzargs
[cargs
], zarg
, clen
);
pzargs
[cargs
][clen
] = '\0';
/* We deliberately separate '>' and '<' out. */
clen
= strspn (zarg
, ZSHELLNONREDIRSEPS
);
pzargs
[cargs
] = zbufalc (clen
+ 1);
memcpy (pzargs
[cargs
], zarg
, clen
);
pzargs
[cargs
][clen
] = '\0';
/* Now look through the arguments to see if we are going to need the
current working directory. We don't try to make a precise
determination, just a conservative one. The basic idea is that
we don't want to get the cwd for 'foo!rmail - user' (note that we
don't examine the command itself). */
for (i
= 0; i
< cargs
; i
++)
zexclam
= strrchr (pzargs
[i
], '!');
if (zexclam
!= NULL
&& fsysdep_needs_cwd (zexclam
+ 1))
if ((pzargs
[i
][0] == '<' || pzargs
[i
][0] == '>')
&& strchr (pzargs
[i
+ 1], '!') == NULL
&& fsysdep_needs_cwd (pzargs
[i
+ 1]))
usysdep_signal (SIGQUIT
);
usysdep_signal (SIGTERM
);
usysdep_signal (SIGPIPE
);
usysdep_initialize (puuconf
, INIT_SUID
| (fgetcwd
? INIT_GETCWD
: 0));
zuser
= zsysdep_login_name ();
/* Get the local system name. */
iuuconf
= uuconf_localname (puuconf
, &zlocalname
);
if (iuuconf
== UUCONF_NOT_FOUND
)
zlocalname
= zsysdep_localname ();
else if (iuuconf
!= UUCONF_SUCCESS
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
/* Get the local system information. */
iuuconf
= uuconf_system_info (puuconf
, zlocalname
, &slocalsys
);
if (iuuconf
!= UUCONF_SUCCESS
)
if (iuuconf
!= UUCONF_NOT_FOUND
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
iuuconf
= uuconf_system_local (puuconf
, &slocalsys
);
if (iuuconf
!= UUCONF_SUCCESS
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
/* Figure out which system the command is to be executed on. Some
mailers apparently pass local!rmail, so we must explicitly check
zexclam
= strchr (zcmd
, '!');
if (strcmp (zcmd
, zlocalname
) == 0)
else if (slocalsys
.uuconf_pzalias
== NULL
)
for (pzal
= slocalsys
.uuconf_pzalias
; *pzal
!= NULL
; pzal
++)
if (strcmp (zcmd
, *pzal
) == 0)
zexclam
= strchr (zcmd
, '!');
/* See if we must forward this command through other systems
zexclam
= strrchr (zcmd
, '!');
zforward
= zbufalc (clen
);
memcpy (zforward
, zcmd
, clen
);
iuuconf
= uuconf_system_info (puuconf
, zsys
, &sxqtsys
);
if (iuuconf
!= UUCONF_SUCCESS
)
if (iuuconf
!= UUCONF_NOT_FOUND
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
if (! funknown_system (puuconf
, zsys
, &sxqtsys
))
ulog (LOG_FATAL
, "%s: System not found", zsys
);
/* Get the local name the remote system know us as. */
zxqtloc
= sxqtsys
.uuconf_zlocalname
;
/* We can send this as an E command if the execution is on a
different, directly connected, system and the only file used is
the standard input and comes from this system. This is true of
the common cases of rmail and rnews. We get an execute file name
here in case we need it. */
zXxqt_name
= zsysdep_xqt_file_name ();
zXxqt_name
= zsysdep_data_file_name (&sxqtsys
, zxqtloc
, bgrade
, TRUE
,
abxqt_tname
, (char *) NULL
,
uxrecord_file (zXxqt_name
);
/* Look through the arguments. Any argument containing an
exclamation point character is interpreted as a file name, and is
sent to the appropriate system. */
for (i
= 0; i
< cargs
; i
++)
/* Check for a parenthesized argument; remove the parentheses
and otherwise ignore it (this is how an exclamation point is
clen
= strlen (pzargs
[i
]);
if (pzargs
[i
][clen
- 1] != ')')
ulog (LOG_ERROR
, "Mismatched parentheses");
pzargs
[i
][clen
- 1] = '\0';
/* Check whether we are doing a redirection. */
else if (pzargs
[i
][0] == '>')
zexclam
= strchr (pzargs
[i
], '!');
/* If there is no exclamation point and no redirection, this
argument is left untouched. */
if (zexclam
== NULL
&& ! finput
&& ! foutput
)
/* Get the system name and file name for this file. */
zexclam
= strrchr (zfile
, '!');
ulog (LOG_FATAL
, "!%s: Can't figure out where to get file",
/* Check if the file is already on the execution system. */
else if (zforward
== NULL
? zforw
!= NULL
: zforw
== NULL
)
else if (zforward
!= NULL
&& strcmp (zforward
, zforw
) != 0)
else if (strcmp (zsystem
, sxqtsys
.uuconf_zname
) == 0)
else if (sxqtsys
.uuconf_pzalias
== NULL
)
for (pzal
= sxqtsys
.uuconf_pzalias
; *pzal
!= NULL
; pzal
++)
if (strcmp (zsystem
, *pzal
) == 0)
/* Turn the file into an absolute path. */
zfile
= zsysdep_local_file_cwd (zfile
, sxqtsys
.uuconf_zpubdir
);
zfile
= zsysdep_add_cwd (zfile
);
/* Check for output redirection. */
if (! fin_directory_list (zfile
,
sxqtsys
.uuconf_pzremote_receive
,
sxqtsys
.uuconf_zpubdir
, TRUE
,
FALSE
, (const char *) NULL
))
ulog (LOG_FATAL
, "Not permitted to create %s", zfile
);
/* There are various cases of output redirection.
uux cmd >out: The command is executed on the local
system, and the output file is placed on the local
uux cmd >a!out: The command is executed on the local
system, and the output file is sent to a.
uux a!cmd >out: The command is executed on a, and the
output file is returned to the local system (flocal
uux a!cmd >a!out: The command is executed on a, and the
output file is left on a (fonxqt is TRUE).
uux a!cmd >b!out: The command is executed on a, and the
output file is sent to b; traditionally, I believe
that b is relative to a, rather than to the local
system. However, this essentially contradicts the
previous two cases, in which the output file is
relative to the local system.
Now, the cases that we don't handle.
uux cmd >a!b!out: The command is executed on the local
system, and the output file is sent to b via a. This
requires the local uuxqt to support forwarding of the
uux a!b!cmd >out: The command is executed on b, which is
reached via a. Probably the output file is intended
for the local system, in which case the uuxqt on b
must support forwarding of the output file.
uux a!b!cmd >c!out: Is c relative to b or to the local
system? If it's relative to b this is easy to
handle. Otherwise, we must arrange for the file to
be sent back to the local system and for the local
system to send it on to c.
There are many variations of the last case. It's not at
all clear to me how they should be handled. */
if (zforward
!= NULL
|| zforw
!= NULL
)
ulog (LOG_FATAL
, "May not forward standard output");
uxadd_xqt_line ('O', zfile
, (const char *) NULL
);
uxadd_xqt_line ('O', zfile
, zxqtloc
);
uxadd_xqt_line ('O', zfile
, zsystem
);
ulog (LOG_FATAL
, "Standard input specified twice");
char abtname
[CFILE_NAME_LEN
];
char abdname
[CFILE_NAME_LEN
];
/* It's a local file. If requested by -C, copy the file to
the spool directory. If requested by -l, link the file
to the spool directory; if the link fails, we copy the
file, unless -c was explictly used. If the execution is
occurring on the local system, we force the copy as well,
because otherwise we would have to have some way to tell
uuxqt not to move the file. If the file is being shipped
to another system, we must set up a transfer request.
First make sure the user has legitimate access, since we
if (! fsysdep_access (zfile
))
zdata
= zsysdep_data_file_name (&sxqtsys
, zxqtloc
, bgrade
, FALSE
,
abtname
, abdname
, (char *) NULL
);
if (fcopy
|| flink
|| fxqtlocal
)
if (! fsysdep_link (zfile
, zdata
, &fworked
))
ulog (LOG_FATAL
, "%s: Can't link to spool directory",
efile
= esysdep_user_fopen (zfile
, TRUE
, TRUE
);
if (! ffileisopen (efile
))
if (! fcopy_open_file (efile
, zdata
, FALSE
, TRUE
))
(void) ffileclose (efile
);
/* We don't actually use the spool file name, but we
need a name to use as the destination. */
/* Make sure the daemon can access the file. */
if (! fsysdep_daemon_access (zfile
))
if (! fin_directory_list (zfile
, sxqtsys
.uuconf_pzlocal_send
,
sxqtsys
.uuconf_zpubdir
, TRUE
,
ulog (LOG_FATAL
, "Not permitted to send from %s",
uxadd_xqt_line ('I', zuse
, (char *) NULL
);
finputcopied
= fcopy
|| flink
;
zinput_to
= zbufcpy (abdname
);
zinput_temp
= zbufcpy (abtname
);
uxadd_send_file (zuse
, abdname
,
finputcopied
? "C" : "c",
abtname
, zforward
, &sxqtsys
,
zbase
= zsysdep_base_name (zfile
);
uxadd_xqt_line ('F', abdname
, zbase
);
/* The file is already on the system where the command is to
uxadd_xqt_line ('I', zfile
, (const char *) NULL
);
struct uuconf_system sfromsys
;
char abtname
[CFILE_NAME_LEN
];
/* We need to request a remote file. */
iuuconf
= uuconf_system_info (puuconf
, zsystem
, &sfromsys
);
if (iuuconf
!= UUCONF_SUCCESS
)
if (iuuconf
!= UUCONF_NOT_FOUND
)
ulog_uuconf (LOG_FATAL
, puuconf
, iuuconf
);
if (! funknown_system (puuconf
, zsystem
, &sfromsys
))
ulog (LOG_FATAL
, "%s: System not found", zsystem
);
/* The file is already on the system where the command is to
uxadd_xqt_line ('I', zfile
, (const char *) NULL
);
if (! sfromsys
.uuconf_fcall_transfer
&& ! sfromsys
.uuconf_fcalled_transfer
)
"Not permitted to transfer files to or from %s",
/* This is ``uux cmd a!b!file''. To make this work,
we would have to be able to set up a request to a
to fetch file from b and send it to us. But it
turns out that that will not work, because when a
sends us the file we will put it in a's spool
directory, not the local system spool directory.
So we won't have any way to find it. This is not
a conceptual problem, and it could doubtless be
solved. Please feel free to solve it and send me
ulog (LOG_FATAL
, "File forwarding not supported");
/* We must request the file from the remote system to
zdata
= zsysdep_data_file_name (&slocalsys
, zxqtloc
, bgrade
,
FALSE
, abtname
, (char *) NULL
,
/* Request the file. The special option '9' is a signal
to uucico that it's OK to receive a file into the
spool directory; normally such requests are rejected.
This privilege is easy to abuse. */
s
.zto
= zbufcpy (abtname
);
zjobid
= zsysdep_spool_commands (&sfromsys
, bgrade
, 1, &s
);
zcall_system
= zbufcpy (sfromsys
.uuconf_zname
);
/* Tell the command execution to wait until the file
has been received, and tell it the real file
uxadd_xqt_line ('F', abtname
, (char *) NULL
);
uxadd_xqt_line ('I', abtname
, (char *) NULL
);
zbase
= zsysdep_base_name (zfile
);
uxadd_xqt_line ('F', abtname
, zbase
);
char abxtname
[CFILE_NAME_LEN
];
/* Now we must arrange to forward the file on to the
execution system. We need to get a name to give
the file on the execution system (abxtname). */
zdata
= zsysdep_data_file_name (&sxqtsys
, zxqtloc
,
zbase
= zsysdep_base_name (zfile
);
zxqt
= zsysdep_xqt_file_name ();
e
= esysdep_fopen (zxqt
, FALSE
, FALSE
, TRUE
);
fprintf (e
, "U %s %s\n", zsysdep_login_name (),
fprintf (e
, "F %s %s\n", abtname
, zbase
);
fprintf (e
, "C uucp -C -W -d -g %c %s %s!", bgrade
,
zbase
, sxqtsys
.uuconf_zname
);
fprintf (e
, "%s!", zforward
);
fprintf (e
, "%s\n", abxtname
);
ulog (LOG_FATAL
, "fclose: %s", strerror (errno
));
uxadd_xqt_line ('F', abxtname
, (char *) NULL
);
uxadd_xqt_line ('I', abxtname
, (char *) NULL
);
uxadd_xqt_line ('F', abxtname
, zbase
);
(void) uuconf_system_free (puuconf
, &sfromsys
);
/* If standard input is to be read from the stdin of uux, we read it
here into a temporary file and send it to the execute system. */
char abtname
[CFILE_NAME_LEN
];
char abdname
[CFILE_NAME_LEN
];
zdata
= zsysdep_data_file_name (&sxqtsys
, zxqtloc
, bgrade
, FALSE
,
abtname
, abdname
, (char *) NULL
);
e
= esysdep_fopen (zdata
, FALSE
, FALSE
, TRUE
);
ulog (LOG_FATAL
, "fclose: %s", strerror (errno
));
uxadd_xqt_line ('I', abtname
, (const char *) NULL
);
zinput_from
= zbufcpy (abtname
);
zinput_to
= zbufcpy (abdname
);
zinput_temp
= zinput_from
;
/* If we are returning standard input, or we're putting the status
in a file, we can't use an E command. */
uxadd_xqt_line ('B', (const char *) NULL
, (const char *) NULL
);
if (zstatus_file
!= NULL
)
uxadd_xqt_line ('M', zstatus_file
, (const char *) NULL
);
/* Get the complete command line, and decide whether the command
needs to be executed by the shell. */
if (zcmd
[strcspn (zcmd
, ZSHELLCHARS
)] != '\0')
clen
= strlen (zcmd
) + 1;
for (i
= 0; i
< cargs
; i
++)
clen
+= strlen (pzargs
[i
]) + 1;
if (pzargs
[i
][strcspn (pzargs
[i
], ZSHELLCHARS
)] != '\0')
zfullcmd
= zbufalc (clen
);
for (i
= 0; i
< cargs
; i
++)
strcat (zfullcmd
, pzargs
[i
]);
/* If we haven't written anything to the execution file yet, and we
have a standard input file, and we're not forwarding, then every
other option can be handled in an E command. */
if (eXxqt_file
== NULL
&& zinput_from
!= NULL
&& zforward
== NULL
)
/* Set up an E command. */
*zoptions
++ = finputcopied
? 'C' : 'c';
pasXcmds
= (struct scmd
*) xrealloc ((pointer
) pasXcmds
,
cXcmds
* sizeof (struct scmd
));
pasXcmds
[cXcmds
- 1] = s
;
/* Finish up the execute file. */
uxadd_xqt_line ('U', zuser
, zxqtloc
);
uxadd_xqt_line ('F', zinput_to
, (char *) NULL
);
uxadd_xqt_line ('I', zinput_to
, (char *) NULL
);
uxadd_send_file (zinput_from
, zinput_to
,
finputcopied
? "C" : "c",
zinput_temp
, zforward
, &sxqtsys
, zxqtloc
,
uxadd_xqt_line ('N', (const char *) NULL
, (const char *) NULL
);
uxadd_xqt_line ('Z', (const char *) NULL
, (const char *) NULL
);
uxadd_xqt_line ('R', zrequestor
, (const char *) NULL
);
uxadd_xqt_line ('e', (const char *) NULL
, (const char *) NULL
);
uxadd_xqt_line ('C', zfullcmd
, (const char *) NULL
);
if (fclose (eXxqt_file
) != 0)
ulog (LOG_FATAL
, "fclose: %s", strerror (errno
));
/* If the execution is to occur on another system, we must now
arrange to copy the execute file to this system. */
uxadd_send_file (abxqt_tname
, abxqt_xname
, "C", abxqt_tname
,
zforward
, &sxqtsys
, zxqtloc
, bgrade
);
/* If we got a signal, get out before spooling anything. */
/* From here on in, it's too late. We don't call uxabort. */
if (! sxqtsys
.uuconf_fcall_transfer
&& ! sxqtsys
.uuconf_fcalled_transfer
)
ulog (LOG_FATAL
, "Not permitted to transfer files to or from %s",
zjobid
= zsysdep_spool_commands (&sxqtsys
, bgrade
, cXcmds
, pasXcmds
);
zcall_system
= zbufcpy (sxqtsys
.uuconf_zname
);
/* If all that worked, make a log file entry. All log file reports
up to this point went to stderr. */
ulog_to_file (puuconf
, TRUE
);
ulog_system (sxqtsys
.uuconf_zname
);
ulog (LOG_NORMAL
, "Queuing %s", zfullcmd
);
if (zcall_system
!= NULL
)
fexit
= fsysdep_run ("uucico", "-s", zcall_system
);
fexit
= fsysdep_run ("uucico", "-r1", (const char *) NULL
);
/* Avoid error about not returning a value. */
/* Report command usage. */
"Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
"Usage: uux [options] [-] command\n");
" -,-p: Read standard input for standard input of command\n");
" -c: Do not copy local files to spool directory (default)\n");
" -C: Copy local files to spool directory\n");
" -l: link local files to spool directory\n");
" -g grade: Set job grade (must be alphabetic)\n");
" -n: Do not report completion status\n");
" -z: Report completion status only on error\n");
" -r: Do not start uucico daemon\n");
" -a address: Address to mail status report to\n");
" -b: Return standard input with status report\n");
" -s file: Report completion status to file\n");
" -x debug: Set debugging level\n");
" -I file: Set configuration file to use\n");
#endif /* HAVE_TAYLOR_CONFIG */
/* Add a line to the execute file. */
uxadd_xqt_line (bchar
, z1
, z2
)
eXxqt_file
= esysdep_fopen (zXxqt_name
, FALSE
, FALSE
, TRUE
);
fprintf (eXxqt_file
, "%c\n", bchar
);
fprintf (eXxqt_file
, "%c %s\n", bchar
, z1
);
fprintf (eXxqt_file
, "%c %s %s\n", bchar
, z1
, z2
);
/* Add a file to be sent to the execute system. */
uxadd_send_file (zfrom
, zto
, zoptions
, ztemp
, zforward
, qxqtsys
, zxqtloc
,
const struct uuconf_system
*qxqtsys
;
char abtname
[CFILE_NAME_LEN
];
char abdname
[CFILE_NAME_LEN
];
char abxname
[CFILE_NAME_LEN
];
/* We want to forward this file through the first execution
system to other systems. We set up a remote execution of
uucp to forward the file. */
zbase
= zsysdep_base_name (zfrom
);
zxqt
= zsysdep_data_file_name (qxqtsys
, zxqtloc
, bgrade
, TRUE
, abtname
,
e
= esysdep_fopen (zxqt
, FALSE
, FALSE
, TRUE
);
fprintf (e
, "U %s %s\n", zsysdep_login_name (), zxqtloc
);
fprintf (e
, "F %s %s\n", abdname
, zbase
);
fprintf (e
, "C uucp -C -W -d -g %c %s %s!%s\n",
bgrade
, zbase
, zforward
, zto
);
ulog (LOG_FATAL
, "fclose: %s", strerror (errno
));
/* Send the execution file. */
s
.zfrom
= zbufcpy (abtname
);
s
.zto
= zbufcpy (abxname
);
s
.zuser
= zsysdep_login_name ();
pasXcmds
= (struct scmd
*) xrealloc ((pointer
) pasXcmds
,
cXcmds
* sizeof (struct scmd
));
pasXcmds
[cXcmds
- 1] = s
;
/* Send the data file to abdname where the execution file will
s
.zfrom
= zbufcpy (zfrom
);
s
.zuser
= zsysdep_login_name ();
s
.zoptions
= zbufcpy (zoptions
);
s
.ztemp
= zbufcpy (ztemp
);
pasXcmds
= (struct scmd
*) xrealloc ((pointer
) pasXcmds
,
cXcmds
* sizeof (struct scmd
));
pasXcmds
[cXcmds
- 1] = s
;
/* Copy stdin to a file. This is a separate function because it may
CATCH_PROTECT
size_t cread
;
/* I want to use fread here, but there is a bug in some versions
of SVR4 which causes fread to return less than a complete
buffer even if EOF has not been reached. This is not online
time, so speed is not critical, but it's still quite annoying
to have to use an inefficient algorithm. */
while (cread
< sizeof (ab
))
/* There's an unimportant race here. If the user hits
^C between the FGOT_SIGNAL we just did and the time
we enter getchar, we won't know about the signal
(unless we're doing a longjmp, but we normally
aren't). It's not a big problem, because the user
can just hit ^C again. */
cwrite
= fwrite (ab
, sizeof (char), cread
, e
);
ulog (LOG_FATAL
, "fwrite: Wrote %d when attempted %d",
(int) cwrite
, (int) cread
);
while (cread
== sizeof ab
);
/* Keep track of all files we have created so that we can delete them
if we get a signal. The argument will be on the heap. */
static const char **pXaz
;
pXaz
= (const char **) xrealloc ((pointer
) pXaz
,
(cXfiles
+ 1) * sizeof (const char *));
/* Delete all the files we have recorded and exit. */
(void) fclose (eXxqt_file
);
for (i
= 0; i
< cXfiles
; i
++)