1 /* uucp.c
2 Prepare to copy a file to or from a remote system.
3
4 Copyright (C) 1991, 1992, 1993, 1994, 1995, 2002 Ian Lance Taylor
5
6 This file is part of the Taylor UUCP package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21
22 The author of the program may be contacted at ian@airs.com.
23 */
24
25 #include "uucp.h"
26
27 #if USE_RCS_ID
28 const char uucp_rcsid[] = "$FreeBSD$";
29 #endif
30
31 #include <ctype.h>
32 #include <errno.h>
33
34 #include "getopt.h"
35
36 #include "uudefs.h"
37 #include "uuconf.h"
38 #include "system.h"
39
40 /* Local functions. */
41
42 static void ucusage P((void));
43 static void uchelp P((void));
44 static void ucdirfile P((const char *zdir, const char *zfile,
45 pointer pinfo));
46 static void uccopy P((const char *zfile, const char *zdest,
47 boolean fforcelocal));
48 static void ucadd_cmd P((const struct uuconf_system *qsys,
49 const struct scmd *qcmd, const char *zlog));
50 static void ucspool_cmds P((boolean fjobid));
51 static const char *zcone_system P((boolean *pfany));
52 static void ucrecord_file P((const char *zfile));
53 static void ucabort P((void));
54
55 /* Long getopt options. Note that any changes here must be reflected
56 in the code in uuxqt.c which checks the options used for the uucp
57 command. */
58 static const struct option asClongopts[] =
59 {
60 { "copy", no_argument, NULL, 'C' },
61 { "nocopy", no_argument, NULL, 'c' },
62 { "directories", no_argument, NULL, 'd' },
63 { "nodirectories", no_argument, NULL, 'f' },
64 { "grade", required_argument, NULL, 'g' },
65 { "jobid", no_argument, NULL, 'j' },
66 { "mail", no_argument, NULL, 'm' },
67 { "notify", required_argument, NULL, 'n' },
68 { "nouucico", no_argument, NULL, 'r' },
69 { "recursive", no_argument, NULL, 'R' },
70 { "status", required_argument, NULL, 's' },
71 { "uuto", no_argument, NULL, 't' },
72 { "user", required_argument, NULL, 'u' },
73 { "noexpand", no_argument, NULL, 'W' },
74 { "config", required_argument, NULL, 'I' },
75 { "debug", required_argument, NULL, 'x' },
76 { "version", no_argument, NULL, 'v' },
77 { "help", no_argument, NULL, 1 },
78 { NULL, 0, NULL, 0 }
79 };
80
81 /* Local variables. There are a bunch of these, mostly set by the
82 options and the last (the destination) argument. These have file
83 scope so that they may be easily passed into uccopy; they could for
84 the most part also be wrapped up in a structure and passed in. */
85
86 /* The uuconf global pointer. */
87 static pointer pCuuconf;
88
89 /* TRUE if source files should be copied to the spool directory. */
90 static boolean fCcopy = TRUE;
91
92 /* Grade to use. */
93 static char bCgrade = BDEFAULT_UUCP_GRADE;
94
95 /* Whether to send mail to the requesting user when the copy is
96 complete. */
97 static boolean fCmail = FALSE;
98
99 /* User to notify on remote system. */
100 static const char *zCnotify = "";
101
102 /* TRUE if remote files should be prefixed with the current working
103 directory. */
104 static boolean fCexpand = TRUE;
105
106 /* TRUE if necessary directories should be created on the destination
107 system. */
108 static boolean fCmkdirs = TRUE;
109
110 /* Local name. */
111 static const char *zClocalname;
112
113 /* User name. */
114 static const char *zCuser = NULL;
115
116 /* TRUE if this is a remote request. */
117 static boolean fCremote = FALSE;
118
119 /* TRUE if the destination is this system. */
120 static boolean fClocaldest;
121
122 /* Destination system. */
123 static struct uuconf_system sCdestsys;
124
125 /* Systems to forward to, if not NULL. */
126 static char *zCforward;
127
128 /* Options to use when sending a file. */
129 static char abCsend_options[20];
130
131 /* Options to use when receiving a file. */
132 static char abCrec_options[20];
133
134 /* TRUE if the current file being copied from is in the cwd. */
135 static boolean fCneeds_cwd;
136
137 /* The main program. */
138
139 int
main(argc,argv)140 main (argc, argv)
141 int argc;
142 char **argv;
143 {
144 /* -I: configuration file name. */
145 const char *zconfig = NULL;
146 /* -j: output job id. */
147 boolean fjobid = FALSE;
148 /* -r: don't start uucico when finished. */
149 boolean fuucico = TRUE;
150 /* -R: copy directories recursively. */
151 boolean frecursive = FALSE;
152 /* -s: report status to named file. */
153 const char *zstatus_file = NULL;
154 /* -t: emulate uuto. */
155 boolean fuuto = FALSE;
156 int iopt;
157 pointer puuconf;
158 int iuuconf;
159 int i;
160 boolean fgetcwd;
161 struct uuconf_system slocalsys;
162 char *zexclam;
163 char *zdestfile;
164 const char *zdestsys;
165 char *zoptions;
166 boolean fexit;
167
168 zProgram = argv[0];
169
170 while ((iopt = getopt_long (argc, argv, "cCdfg:I:jmn:prRs:tu:Wvx:",
171 asClongopts, (int *) NULL)) != EOF)
172 {
173 switch (iopt)
174 {
175 case 'c':
176 /* Do not copy local files to spool directory. */
177 fCcopy = FALSE;
178 break;
179
180 case 'p':
181 case 'C':
182 /* Copy local files to spool directory. */
183 fCcopy = TRUE;
184 break;
185
186 case 'd':
187 /* Create directories if necessary. */
188 fCmkdirs = TRUE;
189 break;
190
191 case 'f':
192 /* Do not create directories if they don't exist. */
193 fCmkdirs = FALSE;
194 break;
195
196 case 'g':
197 /* Set job grade. */
198 bCgrade = optarg[0];
199 break;
200
201 case 'I':
202 /* Name configuration file. */
203 if (fsysdep_other_config (optarg))
204 zconfig = optarg;
205 break;
206
207 case 'j':
208 /* Output job id. */
209 fjobid = TRUE;
210 break;
211
212 case 'm':
213 /* Mail to requesting user. */
214 fCmail = TRUE;
215 break;
216
217 case 'n':
218 /* Notify remote user. */
219 zCnotify = optarg;
220 break;
221
222 case 'r':
223 /* Don't start uucico when finished. */
224 fuucico = FALSE;
225 break;
226
227 case 'R':
228 /* Copy directories recursively. */
229 frecursive = TRUE;
230 break;
231
232 case 's':
233 /* Report status to named file. */
234 zstatus_file = optarg;
235 break;
236
237 case 't':
238 /* Emulate uuto. */
239 fuuto = TRUE;
240 break;
241
242 case 'u':
243 /* Set user name. */
244 zCuser = optarg;
245 break;
246
247 case 'W':
248 /* Expand only local file names. */
249 fCexpand = FALSE;
250 break;
251
252 case 'x':
253 #if DEBUG > 1
254 /* Set debugging level. */
255 iDebug |= idebug_parse (optarg);
256 #endif
257 break;
258
259 case 'v':
260 /* Print version and exit. */
261 printf ("uucp (Taylor UUCP) %s\n", VERSION);
262 printf ("Copyright (C) 1991, 92, 93, 94, 1995, 2002 Ian Lance Taylor\n");
263 printf ("This program is free software; you may redistribute it under the terms of\n");
264 printf ("the GNU General Public LIcense. This program has ABSOLUTELY NO WARRANTY.\n");
265 exit (EXIT_SUCCESS);
266 /*NOTREACHED*/
267
268 case 1:
269 /* --help. */
270 uchelp ();
271 exit (EXIT_SUCCESS);
272 /*NOTREACHED*/
273
274 case 0:
275 /* Long option found and flag set. */
276 break;
277
278 default:
279 ucusage ();
280 /*NOTREACHED*/
281 }
282 }
283
284 if (! UUCONF_GRADE_LEGAL (bCgrade)
285 || ((bCgrade < '0' || bCgrade > '9')
286 && (bCgrade < 'a' || bCgrade > 'z')
287 && (bCgrade < 'A' || bCgrade > 'Z')))
288 {
289 ulog (LOG_ERROR, "Ignoring illegal grade");
290 bCgrade = BDEFAULT_UUCP_GRADE;
291 }
292
293 /* The user name must contain a '!', which is treated as a remote
294 name, to avoid spoofing of other users (there is no advantage to
295 spoofing remote users, except to send them random bits of mail,
296 which you can do anyhow). */
297 if (zCuser != NULL)
298 {
299 if (strchr (zCuser, '!') != NULL)
300 fCremote = TRUE;
301 else
302 {
303 ulog (LOG_ERROR, "Ignoring local user name");
304 zCuser = NULL;
305 }
306 }
307
308 if (argc - optind < 2)
309 ucusage ();
310
311 iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
312 if (iuuconf != UUCONF_SUCCESS)
313 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
314 pCuuconf = puuconf;
315
316 #if DEBUG > 1
317 {
318 const char *zdebug;
319
320 iuuconf = uuconf_debuglevel (puuconf, &zdebug);
321 if (iuuconf != UUCONF_SUCCESS)
322 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
323 if (zdebug != NULL)
324 iDebug |= idebug_parse (zdebug);
325 }
326 #endif
327
328 /* See if we are going to need to know the current directory. We
329 just check each argument to see whether it's an absolute
330 pathname. We actually aren't going to need the cwd if fCexpand
331 is FALSE and the file is remote, but so what. */
332 fgetcwd = FALSE;
333 for (i = optind; i < argc; i++)
334 {
335 zexclam = strrchr (argv[i], '!');
336 if (zexclam == NULL)
337 zexclam = argv[i];
338 else
339 ++zexclam;
340 if (fsysdep_needs_cwd (zexclam))
341 {
342 fgetcwd = TRUE;
343 break;
344 }
345 }
346
347 #ifdef SIGINT
348 usysdep_signal (SIGINT);
349 #endif
350 #ifdef SIGHUP
351 usysdep_signal (SIGHUP);
352 #endif
353 #ifdef SIGQUIT
354 usysdep_signal (SIGQUIT);
355 #endif
356 #ifdef SIGTERM
357 usysdep_signal (SIGTERM);
358 #endif
359 #ifdef SIGPIPE
360 usysdep_signal (SIGPIPE);
361 #endif
362
363 usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0));
364
365 ulog_fatal_fn (ucabort);
366
367 if (zCuser == NULL)
368 zCuser = zsysdep_login_name ();
369
370 iuuconf = uuconf_localname (puuconf, &zClocalname);
371 if (iuuconf == UUCONF_NOT_FOUND)
372 {
373 zClocalname = zsysdep_localname ();
374 if (zClocalname == NULL)
375 exit (EXIT_FAILURE);
376 }
377 else if (iuuconf != UUCONF_SUCCESS)
378 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
379
380 /* Get the local system information. */
381 iuuconf = uuconf_system_info (puuconf, zClocalname, &slocalsys);
382 if (iuuconf != UUCONF_SUCCESS)
383 {
384 if (iuuconf != UUCONF_NOT_FOUND)
385 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
386 iuuconf = uuconf_system_local (puuconf, &slocalsys);
387 if (iuuconf != UUCONF_SUCCESS)
388 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
389 slocalsys.uuconf_zname = (char *) zClocalname;
390 }
391
392 /* If we are emulating uuto, translate the destination argument, and
393 notify the destination user. This had better not turn into
394 something that requires the current directory, or we may have
395 passed INIT_GETCWD incorrectly. */
396 if (fuuto)
397 {
398 if (*zCnotify == '\0')
399 {
400 zexclam = strrchr (argv[argc - 1], '!');
401 if (zexclam == NULL)
402 ucusage ();
403 zCnotify = zexclam + 1;
404 }
405 argv[argc - 1] = zsysdep_uuto (argv[argc - 1], zClocalname);
406 if (argv[argc - 1] == NULL)
407 ucusage ();
408 }
409
410 /* Set up the file transfer options. */
411 zoptions = abCsend_options;
412 if (fCcopy)
413 *zoptions++ = 'C';
414 else
415 *zoptions++ = 'c';
416 if (fCmkdirs)
417 *zoptions++ = 'd';
418 else
419 *zoptions++ = 'f';
420 if (fCmail)
421 *zoptions++ = 'm';
422 if (*zCnotify != '\0')
423 *zoptions++ = 'n';
424 *zoptions = '\0';
425
426 zoptions = abCrec_options;
427 if (fCmkdirs)
428 *zoptions++ = 'd';
429 else
430 *zoptions++ = 'f';
431 if (fCmail)
432 *zoptions++ = 'm';
433 *zoptions = '\0';
434
435 argv[argc - 1] = zremove_local_sys (&slocalsys, argv[argc - 1]);
436
437 zexclam = strchr (argv[argc - 1], '!');
438 if (zexclam == NULL)
439 {
440 zdestsys = zClocalname;
441 zdestfile = argv[argc - 1];
442 fClocaldest = TRUE;
443 }
444 else
445 {
446 size_t clen;
447 char *zcopy;
448
449 clen = zexclam - argv[argc - 1];
450 zcopy = zbufalc (clen + 1);
451 memcpy (zcopy, argv[argc - 1], clen);
452 zcopy[clen] = '\0';
453 zdestsys = zcopy;
454
455 zdestfile = zexclam + 1;
456
457 fClocaldest = FALSE;
458 }
459
460 iuuconf = uuconf_system_info (puuconf, zdestsys, &sCdestsys);
461 if (iuuconf != UUCONF_SUCCESS)
462 {
463 if (iuuconf != UUCONF_NOT_FOUND)
464 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
465 if (fClocaldest)
466 {
467 iuuconf = uuconf_system_local (puuconf, &sCdestsys);
468 if (iuuconf != UUCONF_SUCCESS)
469 ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
470 sCdestsys.uuconf_zname = (char *) zClocalname;
471 }
472 else
473 {
474 if (! funknown_system (puuconf, zdestsys, &sCdestsys))
475 ulog (LOG_FATAL, "%s: System not found", zdestsys);
476 }
477 }
478
479 /* Here zdestfile is the destination file name following the
480 destination system name (if any); it may contain other systems to
481 forward the files through. Isolate the file from the list of
482 systems. */
483 zexclam = strrchr (zdestfile, '!');
484 if (zexclam == NULL)
485 zCforward = NULL;
486 else
487 {
488 size_t clen;
489
490 #if DEBUG > 0
491 if (fClocaldest)
492 ulog (LOG_FATAL, "Can't happen");
493 #endif
494 clen = zexclam - zdestfile;
495 zCforward = zbufalc (clen + 1);
496 memcpy (zCforward, zdestfile, clen);
497 zCforward[clen] = '\0';
498 zdestfile = zexclam + 1;
499 }
500
501 /* Turn the destination into an absolute path, unless it is on a
502 remote system and -W was used. */
503 if (fClocaldest)
504 zdestfile = zsysdep_local_file_cwd (zdestfile, sCdestsys.uuconf_zpubdir,
505 (boolean *) NULL);
506 else if (fCexpand)
507 zdestfile = zsysdep_add_cwd (zdestfile);
508 if (zdestfile == NULL)
509 {
510 ulog_close ();
511 usysdep_exit (FALSE);
512 }
513
514 /* Process each source argument. */
515 for (i = optind; i < argc - 1 && ! FGOT_SIGNAL (); i++)
516 {
517 boolean flocal;
518 char *zfrom;
519
520 fCneeds_cwd = FALSE;
521
522 argv[i] = zremove_local_sys (&slocalsys, argv[i]);
523
524 if (strchr (argv[i], '!') != NULL)
525 {
526 flocal = FALSE;
527 zfrom = zbufcpy (argv[i]);
528 }
529 else
530 {
531 /* This is a local file. Make sure we get it out of the
532 original directory. We don't support local wildcards,
533 leaving that to the shell. */
534 flocal = TRUE;
535 if (fsysdep_needs_cwd (argv[i]))
536 fCneeds_cwd = TRUE;
537 zfrom = zsysdep_local_file_cwd (argv[i],
538 sCdestsys.uuconf_zpubdir,
539 (boolean *) NULL);
540 if (zfrom == NULL)
541 ucabort ();
542 }
543
544 if (! flocal || ! fsysdep_directory (zfrom))
545 uccopy (zfrom, zdestfile, FALSE);
546 else
547 {
548 char *zbase, *zindir;
549
550 if (! frecursive)
551 ulog (LOG_FATAL, "%s: directory without -R", zfrom);
552
553 zbase = zsysdep_base_name (zfrom);
554 if (zbase == NULL)
555 ucabort ();
556 zindir = zsysdep_in_dir (zdestfile, zbase);
557 ubuffree (zbase);
558 if (zindir == NULL)
559 ucabort ();
560 usysdep_walk_tree (zfrom, ucdirfile, zindir);
561 ubuffree (zindir);
562 }
563
564 ubuffree (zfrom);
565 }
566
567 /* See if we got an interrupt, presumably from the user. */
568 if (FGOT_SIGNAL ())
569 ucabort ();
570
571 /* Now push out the actual commands, making log entries for them. */
572 ulog_to_file (puuconf, TRUE);
573 ulog_user (zCuser);
574
575 ucspool_cmds (fjobid);
576
577 ulog_close ();
578
579 if (! fuucico)
580 fexit = TRUE;
581 else
582 {
583 const char *zsys;
584 boolean fany;
585
586 zsys = zcone_system (&fany);
587
588 if (zsys == NULL && ! fany)
589 fexit = TRUE;
590 else
591 {
592 const char *zarg;
593 char *zconfigarg;
594
595 if (zsys == NULL)
596 zarg = "-r1";
597 else
598 {
599 char *z;
600
601 z = zbufalc (sizeof "-Cs" + strlen (zsys));
602 sprintf (z, "-Cs%s", zsys);
603 zarg = z;
604 }
605
606 if (zconfig == NULL)
607 zconfigarg = NULL;
608 else
609 {
610 zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
611 sprintf (zconfigarg, "-I%s", zconfig);
612 }
613
614 fexit = fsysdep_run (FALSE, "uucico", zarg, zconfigarg);
615 }
616 }
617
618 usysdep_exit (fexit);
619
620 /* Avoid error about not returning. */
621 return 0;
622 }
623
624 /* Print usage message and die. */
625
626 static void
ucusage()627 ucusage ()
628 {
629 fprintf (stderr,
630 "Usage: %s [options] file1 [file2 ...] dest\n", zProgram);
631 fprintf (stderr, "Use %s --help for help\n", zProgram);
632 exit (EXIT_FAILURE);
633 }
634
635 /* Print help message. */
636
637 static void
uchelp()638 uchelp ()
639 {
640 printf ("Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995, 2002 Ian Lance Taylor\n",
641 VERSION);
642 printf ("Usage: %s [options] file1 [file2 ...] dest\n", zProgram);
643 printf (" -c,--nocopy: Do not copy local files to spool directory\n");
644 printf (" -C,-p,--copy: Copy local files to spool directory (default)\n");
645 printf (" -d,--directories: Create necessary directories (default)\n");
646 printf (" -f,--nodirectories: Do not create directories (fail if they do not exist)\n");
647 printf (" -g,--grade grade: Set job grade (must be alphabetic)\n");
648 printf (" -m,--mail: Report status of copy by mail\n");
649 printf (" -n,--notify user: Report status of copy by mail to remote user\n");
650 printf (" -R,--recursive: Copy directories recursively\n");
651 printf (" -r,--nouucico: Do not start uucico daemon\n");
652 printf (" -s,--status file: Report completion status to file\n");
653 printf (" -j,--jobid: Report job id\n");
654 printf (" -W,--noexpand: Do not add current directory to remote filenames\n");
655 printf (" -t,--uuto: Emulate uuto\n");
656 printf (" -u,--user name: Set user name\n");
657 printf (" -x,--debug debug: Set debugging level\n");
658 #if HAVE_TAYLOR_CONFIG
659 printf (" -I,--config file: Set configuration file to use\n");
660 #endif /* HAVE_TAYLOR_CONFIG */
661 printf (" -v,--version: Print version and exit\n");
662 printf (" --help: Print help and exit\n");
663 printf ("Report bugs to taylor-uucp@gnu.org\n");
664 }
665
666 /* This is called for each file in a directory heirarchy. */
667
668 static void
ucdirfile(zfull,zrelative,pinfo)669 ucdirfile (zfull, zrelative, pinfo)
670 const char *zfull;
671 const char *zrelative;
672 pointer pinfo;
673 {
674 const char *zdestfile = (const char *) pinfo;
675 char *zto;
676
677 zto = zsysdep_in_dir (zdestfile, zrelative);
678 if (zto == NULL)
679 ucabort ();
680
681 uccopy (zfull, zto, TRUE);
682
683 ubuffree (zto);
684 }
685
686 /* Handle the copying of one regular file. The zdest argument is the
687 destination file; if we are recursively copying a directory, it
688 will be extended by any subdirectory names. Note that zdest is an
689 absolute path. */
690
691 static void
uccopy(zfile,zdest,fforcelocal)692 uccopy (zfile, zdest, fforcelocal)
693 const char *zfile;
694 const char *zdest;
695 boolean fforcelocal;
696 {
697 struct scmd s;
698 char *zexclam;
699 char *zto;
700
701 zexclam = strchr (zfile, '!');
702
703 if (zexclam == NULL || fforcelocal)
704 {
705 openfile_t efrom;
706
707 /* Copy from a local file. Make sure the user has access to
708 this file, since we are running setuid. */
709 if (! fsysdep_access (zfile))
710 ucabort ();
711
712 /* If this copy is being requested by a remote system, we may
713 transfer the file if it needs the current working directory
714 (meaning, I hope, that it is in the execution directory) or
715 it is on the permitted transfer list. Note that unlike most
716 of the other checks, this one is not double-checked by
717 uucico. */
718 if (fCremote
719 && ! fCneeds_cwd
720 && ! fin_directory_list (zfile, sCdestsys.uuconf_pzremote_send,
721 sCdestsys.uuconf_zpubdir, TRUE,
722 TRUE, (const char *) NULL))
723 ulog (LOG_FATAL, "Not permitted to send %s", zfile);
724
725 if (fClocaldest)
726 {
727 boolean fok;
728 unsigned int imode;
729
730 /* Copy one local file to another. */
731
732 /* Check that we have permission to receive into the desired
733 directory. */
734 if (fCremote)
735 fok = fin_directory_list (zdest,
736 sCdestsys.uuconf_pzremote_receive,
737 sCdestsys.uuconf_zpubdir, TRUE,
738 FALSE, (const char *) NULL);
739 else
740 fok = fin_directory_list (zdest,
741 sCdestsys.uuconf_pzlocal_receive,
742 sCdestsys.uuconf_zpubdir, TRUE,
743 FALSE, zCuser);
744 if (! fok)
745 ulog (LOG_FATAL, "Not permitted to receive to %s", zdest);
746
747 zto = zsysdep_add_base (zdest, zfile);
748 if (zto == NULL)
749 ucabort ();
750
751 efrom = esysdep_user_fopen (zfile, TRUE, TRUE);
752 if (! ffileisopen (efrom))
753 ucabort ();
754 if (! fcopy_open_file (efrom, zto, FALSE, fCmkdirs, TRUE))
755 ucabort ();
756 (void) ffileclose (efrom);
757 ubuffree (zto);
758
759 imode = ixsysdep_user_file_mode (zfile);
760 if (imode != 0)
761 (void) fsysdep_change_mode (zto, imode);
762 }
763 else
764 {
765 const char *zloc;
766 char abtname[CFILE_NAME_LEN];
767 unsigned int imode;
768 char *ztemp;
769
770 /* Copy a local file to a remote file. We may have to
771 copy the local file to the spool directory. */
772 imode = ixsysdep_user_file_mode (zfile);
773 if (imode == 0)
774 ucabort ();
775
776 zloc = sCdestsys.uuconf_zlocalname;
777 if (zloc == NULL)
778 zloc = zClocalname;
779
780 ztemp = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade,
781 FALSE, abtname, (char *) NULL,
782 (char *) NULL);
783 if (ztemp == NULL)
784 ucabort ();
785
786 if (! fCcopy)
787 {
788 /* If we are copying the file, we don't actually use the
789 temporary file; we still want to get a name for the
790 other system to use as a key for file restart. */
791 ubuffree (ztemp);
792
793 /* Make sure the daemon will be permitted to send
794 this file. */
795 if (! fsysdep_daemon_access (zfile))
796 ucabort ();
797 if (! fin_directory_list (zfile, sCdestsys.uuconf_pzlocal_send,
798 sCdestsys.uuconf_zpubdir, TRUE, TRUE,
799 (fCremote
800 ? (const char *) NULL
801 : zCuser)))
802 ulog (LOG_FATAL,
803 "Daemon not permitted to send %s (suggest --copy)",
804 zfile);
805 }
806 else
807 {
808 efrom = esysdep_user_fopen (zfile, TRUE, TRUE);
809 if (! ffileisopen (efrom))
810 ucabort ();
811 ucrecord_file (ztemp);
812 if (! fcopy_open_file (efrom, ztemp, FALSE, TRUE, TRUE))
813 ucabort ();
814 (void) ffileclose (efrom);
815 }
816
817 if (zCforward == NULL)
818 {
819 /* We're not forwarding. Just send the file. */
820 s.bcmd = 'S';
821 s.bgrade = bCgrade;
822 s.pseq = NULL;
823 s.zfrom = zbufcpy (zfile);
824 s.zto = zbufcpy (zdest);
825 s.zuser = zCuser;
826 s.zoptions = abCsend_options;
827 s.ztemp = zbufcpy (abtname);
828 s.imode = imode;
829 s.znotify = zCnotify;
830 s.cbytes = -1;
831 s.zcmd = NULL;
832 s.ipos = 0;
833
834 ucadd_cmd (&sCdestsys, &s, (const char *) NULL);
835 }
836 else
837 {
838 char *zbase;
839 char *zxqt;
840 char abxtname[CFILE_NAME_LEN];
841 char abdname[CFILE_NAME_LEN];
842 char abxname[CFILE_NAME_LEN];
843 FILE *e;
844 char *zlog;
845
846 /* We want to forward this file through sCdestsys to
847 some other system(s). We set up a remote execution
848 of uucp on sCdestsys to forward the file along. */
849 zbase = zsysdep_base_name (zfile);
850 if (zbase == NULL)
851 ucabort ();
852
853 zxqt = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade,
854 TRUE, abxtname, abdname,
855 abxname);
856 if (zxqt == NULL)
857 ucabort ();
858 e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE);
859 if (e == NULL)
860 ucabort ();
861 ucrecord_file (zxqt);
862
863 fprintf (e, "U %s %s\n", zCuser, zloc);
864 fprintf (e, "F %s %s\n", abdname, zbase);
865 fprintf (e, "C uucp -C");
866 if (fCmkdirs)
867 fprintf (e, " -d");
868 else
869 fprintf (e, " -f");
870 fprintf (e, " -g %c", bCgrade);
871 if (fCmail)
872 fprintf (e, " -m");
873 if (*zCnotify != '\0')
874 fprintf (e, " -n %s", zCnotify);
875 if (! fCexpand)
876 fprintf (e, " -W");
877 fprintf (e, " %s %s!%s\n", zbase, zCforward, zdest);
878
879 ubuffree (zbase);
880
881 if (! fstdiosync (e, zxqt))
882 ulog (LOG_FATAL, "fsync failed");
883 if (fclose (e) != 0)
884 ulog (LOG_FATAL, "fclose: %s", strerror (errno));
885
886 /* Send the execution file. */
887 s.bcmd = 'S';
888 s.bgrade = bCgrade;
889 s.pseq = NULL;
890 s.zfrom = zbufcpy (abxtname);
891 s.zto = zbufcpy (abxname);
892 s.zuser = zCuser;
893 s.zoptions = "C";
894 s.ztemp = s.zfrom;
895 s.imode = 0666;
896 s.znotify = NULL;
897 s.cbytes = -1;
898 s.zcmd = NULL;
899 s.ipos = 0;
900
901 zlog = zbufalc (sizeof "Queuing uucp !" + strlen (zfile)
902 + strlen (zCforward) + strlen (zdest));
903 sprintf (zlog, "Queuing uucp %s %s!%s", zfile, zCforward,
904 zdest);
905
906 ucadd_cmd (&sCdestsys, &s, zlog);
907
908 /* Send the data file. */
909 s.bcmd = 'S';
910 s.bgrade = bCgrade;
911 s.pseq = NULL;
912 s.zfrom = zbufcpy (zfile);
913 s.zto = zbufcpy (abdname);
914 s.zuser = zCuser;
915 s.zoptions = fCcopy ? "C" : "c";
916 s.ztemp = zbufcpy (abtname);
917 s.imode = 0666;
918 s.znotify = NULL;
919 s.cbytes = -1;
920 s.zcmd = NULL;
921 s.ipos = 0;
922
923 ucadd_cmd (&sCdestsys, &s, "");
924 }
925 }
926 }
927 else
928 {
929 char *zfrom;
930 char *zforward;
931 size_t clen;
932 char *zcopy;
933 struct uuconf_system *qfromsys;
934 int iuuconf;
935 const char *zloc;
936
937 /* Copy from a remote file. Get the file name after any systems
938 we may need to forward the file from. */
939 zfrom = strrchr (zfile, '!');
940 if (zfrom == zexclam)
941 zforward = NULL;
942 else
943 {
944 clen = zfrom - zexclam - 1;
945 zforward = zbufalc (clen + 1);
946 memcpy (zforward, zexclam + 1, clen);
947 zforward[clen] = '\0';
948 }
949
950 ++zfrom;
951 if (fCexpand)
952 {
953 /* Add the current directory to the filename if it's not
954 already there. */
955 zfrom = zsysdep_add_cwd (zfrom);
956 if (zfrom == NULL)
957 ucabort ();
958 }
959
960 /* Read the system information. */
961 clen = zexclam - zfile;
962 zcopy = zbufalc (clen + 1);
963 memcpy (zcopy, zfile, clen);
964 zcopy[clen] = '\0';
965
966 qfromsys = ((struct uuconf_system *)
967 xmalloc (sizeof (struct uuconf_system)));
968
969 iuuconf = uuconf_system_info (pCuuconf, zcopy, qfromsys);
970 if (iuuconf == UUCONF_NOT_FOUND)
971 {
972 if (! funknown_system (pCuuconf, zcopy, qfromsys))
973 ulog (LOG_FATAL, "%s: System not found", zcopy);
974 }
975 else if (iuuconf != UUCONF_SUCCESS)
976 ulog_uuconf (LOG_FATAL, pCuuconf, iuuconf);
977 ubuffree (zcopy);
978
979 zloc = qfromsys->uuconf_zlocalname;
980 if (zloc == NULL)
981 zloc = zClocalname;
982
983 if (zforward == NULL && fClocaldest)
984 {
985 boolean fok;
986
987 /* The file is to come directly from qfromsys to the local
988 system. */
989
990 /* Check that we have permission to receive into the desired
991 directory. If we don't have permission, uucico will
992 fail. */
993 if (fCremote)
994 fok = fin_directory_list (zdest,
995 qfromsys->uuconf_pzremote_receive,
996 qfromsys->uuconf_zpubdir, TRUE,
997 FALSE, (const char *) NULL);
998 else
999 fok = fin_directory_list (zdest,
1000 qfromsys->uuconf_pzlocal_receive,
1001 qfromsys->uuconf_zpubdir, TRUE,
1002 FALSE, zCuser);
1003 if (! fok)
1004 ulog (LOG_FATAL, "Not permitted to receive to %s", zdest);
1005
1006 /* If the remote filespec is wildcarded, we must generate an
1007 'X' request. We currently check for Unix shell
1008 wildcards. Note that it should do no harm to mistake a
1009 non-wildcard for a wildcard. */
1010 if (zfrom[strcspn (zfrom, "*?[")] != '\0')
1011 {
1012 s.bcmd = 'X';
1013 zto = zbufalc (strlen (zloc) + strlen (zdest) + sizeof "!");
1014 sprintf (zto, "%s!%s", zloc, zdest);
1015 }
1016 else
1017 {
1018 s.bcmd = 'R';
1019 zto = zbufcpy (zdest);
1020 }
1021
1022 s.bgrade = bCgrade;
1023 s.pseq = NULL;
1024 s.zfrom = zfrom;
1025 s.zto = zto;
1026 s.zuser = zCuser;
1027 s.zoptions = abCrec_options;
1028 s.ztemp = "";
1029 s.imode = 0;
1030 s.znotify = "";
1031 s.cbytes = -1;
1032 s.zcmd = NULL;
1033 s.ipos = 0;
1034
1035 ucadd_cmd (qfromsys, &s, (const char *) NULL);
1036 }
1037 else
1038 {
1039 char *zxqt;
1040 char abtname[CFILE_NAME_LEN];
1041 char abxname[CFILE_NAME_LEN];
1042 FILE *e;
1043 char *zcmd;
1044 char *zlog;
1045
1046 /* The file either comes from some other system through
1047 qfromsys or is intended for some other system. Send an
1048 execution request to qfromsys to handle everything. */
1049 zxqt = zsysdep_data_file_name (qfromsys, zloc, bCgrade, TRUE,
1050 abtname, (char *) NULL,
1051 abxname);
1052 if (zxqt == NULL)
1053 ucabort ();
1054 e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE);
1055 if (e == NULL)
1056 ucabort ();
1057 ucrecord_file (zxqt);
1058
1059 fprintf (e, "U %s %s\n", zCuser, zloc);
1060 fprintf (e, "C uucp -C");
1061 if (fCmkdirs)
1062 fprintf (e, " -d");
1063 else
1064 fprintf (e, " -f");
1065 fprintf (e, " -g %c", bCgrade);
1066 if (fCmail)
1067 fprintf (e, " -m");
1068 if (*zCnotify != '\0')
1069 fprintf (e, " -n %s", zCnotify);
1070 if (! fCexpand)
1071 fprintf (e, " -W");
1072
1073 clen = (strlen (zfrom) + strlen (zloc)
1074 + strlen (sCdestsys.uuconf_zname) + strlen (zdest));
1075 if (zforward != NULL)
1076 clen += strlen (zforward);
1077 if (zCforward != NULL)
1078 clen += strlen (zCforward);
1079 zcmd = zbufalc (sizeof "! !!!" + clen);
1080 *zcmd = '\0';
1081 if (zforward != NULL)
1082 sprintf (zcmd + strlen (zcmd), "%s!", zforward);
1083 sprintf (zcmd + strlen (zcmd), "%s %s!", zfrom, zloc);
1084 if (! fClocaldest)
1085 sprintf (zcmd + strlen (zcmd), "%s!", sCdestsys.uuconf_zname);
1086 if (zCforward != NULL)
1087 sprintf (zcmd + strlen (zcmd), "%s!", zCforward);
1088 sprintf (zcmd + strlen (zcmd), "%s", zdest);
1089
1090 fprintf (e, " %s\n", zcmd);
1091
1092 if (! fstdiosync (e, zxqt))
1093 ulog (LOG_FATAL, "fsync failed");
1094 if (fclose (e) != 0)
1095 ulog (LOG_FATAL, "fclose: %s", strerror (errno));
1096
1097 /* Send the execution file. */
1098 s.bcmd = 'S';
1099 s.bgrade = bCgrade;
1100 s.pseq = NULL;
1101 s.zfrom = zbufcpy (abtname);
1102 s.zto = zbufcpy (abxname);
1103 s.zuser = zCuser;
1104 s.zoptions = "C";
1105 s.ztemp = s.zfrom;
1106 s.imode = 0666;
1107 s.znotify = NULL;
1108 s.cbytes = -1;
1109 s.zcmd = NULL;
1110 s.ipos = 0;
1111
1112 zlog = zbufalc (sizeof "Queueing uucp " + strlen (zcmd));
1113 sprintf (zlog, "Queueing uucp %s", zcmd);
1114
1115 ucadd_cmd (qfromsys, &s, zlog);
1116
1117 ubuffree (zcmd);
1118 ubuffree (zforward);
1119 }
1120 }
1121 }
1122
1123 /* We keep a list of jobs for each system. */
1124
1125 struct sjob
1126 {
1127 struct sjob *qnext;
1128 const struct uuconf_system *qsys;
1129 int ccmds;
1130 struct scmd *pascmds;
1131 const char **pazlogs;
1132 };
1133
1134 static struct sjob *qCjobs;
1135
1136 static void
ucadd_cmd(qsys,qcmd,zlog)1137 ucadd_cmd (qsys, qcmd, zlog)
1138 const struct uuconf_system *qsys;
1139 const struct scmd *qcmd;
1140 const char *zlog;
1141 {
1142 struct sjob *qjob;
1143
1144 if (! qsys->uuconf_fcall_transfer
1145 && ! qsys->uuconf_fcalled_transfer)
1146 ulog (LOG_FATAL, "Not permitted to transfer files to or from %s",
1147 qsys->uuconf_zname);
1148
1149 for (qjob = qCjobs; qjob != NULL; qjob = qjob->qnext)
1150 if (strcmp (qjob->qsys->uuconf_zname, qsys->uuconf_zname) == 0)
1151 break;
1152
1153 if (qjob == NULL)
1154 {
1155 qjob = (struct sjob *) xmalloc (sizeof (struct sjob));
1156 qjob->qnext = qCjobs;
1157 qjob->qsys = qsys;
1158 qjob->ccmds = 0;
1159 qjob->pascmds = NULL;
1160 qjob->pazlogs = NULL;
1161 qCjobs = qjob;
1162 }
1163
1164 qjob->pascmds = ((struct scmd *)
1165 xrealloc ((pointer) qjob->pascmds,
1166 (qjob->ccmds + 1) * sizeof (struct scmd)));
1167 qjob->pascmds[qjob->ccmds] = *qcmd;
1168 qjob->pazlogs = ((const char **)
1169 xrealloc ((pointer) qjob->pazlogs,
1170 (qjob->ccmds + 1) * sizeof (const char *)));
1171 qjob->pazlogs[qjob->ccmds] = zlog;
1172 ++qjob->ccmds;
1173 }
1174
1175 static void
ucspool_cmds(fjobid)1176 ucspool_cmds (fjobid)
1177 boolean fjobid;
1178 {
1179 struct sjob *qjob;
1180 char *zjobid;
1181
1182 for (qjob = qCjobs; qjob != NULL; qjob = qjob->qnext)
1183 {
1184 ulog_system (qjob->qsys->uuconf_zname);
1185 zjobid = zsysdep_spool_commands (qjob->qsys, bCgrade, qjob->ccmds,
1186 qjob->pascmds, (boolean *) NULL);
1187 if (zjobid != NULL)
1188 {
1189 int i;
1190 struct scmd *qcmd;
1191 const char **pz;
1192
1193 for (i = 0, qcmd = qjob->pascmds, pz = qjob->pazlogs;
1194 i < qjob->ccmds;
1195 i++, qcmd++, pz++)
1196 {
1197 if (*pz != NULL)
1198 {
1199 if (**pz != '\0')
1200 ulog (LOG_NORMAL, "%s", *pz);
1201 }
1202 else if (qcmd->bcmd == 'S')
1203 ulog (LOG_NORMAL, "Queuing send of %s to %s",
1204 qcmd->zfrom, qcmd->zto);
1205 else if (qcmd->bcmd == 'R')
1206 ulog (LOG_NORMAL, "Queuing request of %s to %s",
1207 qcmd->zfrom, qcmd->zto);
1208 else
1209 {
1210 const char *zto;
1211
1212 zto = strrchr (qcmd->zto, '!');
1213 if (zto != NULL)
1214 ++zto;
1215 else
1216 zto = qcmd->zto;
1217 ulog (LOG_NORMAL, "Queuing request of %s to %s",
1218 qcmd->zfrom, zto);
1219 }
1220 }
1221
1222 if (fjobid)
1223 printf ("%s\n", zjobid);
1224
1225 ubuffree (zjobid);
1226 }
1227 }
1228 }
1229
1230 /* Return the system name for which we have created commands, or NULL
1231 if we've created commands for more than one system. Set *pfany to
1232 FALSE if we didn't create work for any system. */
1233
1234 static const char *
zcone_system(pfany)1235 zcone_system (pfany)
1236 boolean *pfany;
1237 {
1238 if (qCjobs == NULL)
1239 {
1240 *pfany = FALSE;
1241 return NULL;
1242 }
1243
1244 *pfany = TRUE;
1245
1246 if (qCjobs->qnext == NULL)
1247 return qCjobs->qsys->uuconf_zname;
1248 else
1249 return NULL;
1250 }
1251
1252 /* Keep track of all files we have created so that we can delete them
1253 if we get a signal. The argument will be on the heap. */
1254
1255 static int cCfiles;
1256 static const char **pCaz;
1257
1258 static void
ucrecord_file(zfile)1259 ucrecord_file (zfile)
1260 const char *zfile;
1261 {
1262 pCaz = (const char **) xrealloc ((pointer) pCaz,
1263 (cCfiles + 1) * sizeof (const char *));
1264 pCaz[cCfiles] = zfile;
1265 ++cCfiles;
1266 }
1267
1268 /* Delete all the files we have recorded and exit. */
1269
1270 static void
ucabort()1271 ucabort ()
1272 {
1273 int i;
1274
1275 for (i = 0; i < cCfiles; i++)
1276 (void) remove (pCaz[i]);
1277 ulog_close ();
1278 usysdep_exit (FALSE);
1279 }
1280