1 /* sys3.unx 2 The system dependent spool directory subroutines for Unix. 3 4 Copyright (C) 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22 The author of the program may be contacted at ian@airs.com or 23 c/o AIRS, P.O. Box 520, Waltham, MA 02254. 24 25 $Log: sys3.unx,v $ 26 # Revision 1.2 92/05/13 05:42:07 rich 27 # ported to 386bsd 28 # 29 # Revision 1.1 1992/05/10 18:00:16 rich 30 # Initial revision 31 # 32 Revision 1.48 1992/04/01 22:36:48 ian 33 David J. MacKenzie: some USG_STATFS systems use 512 despite f_bsize 34 35 Revision 1.47 1992/03/30 15:03:07 ian 36 Niels Baggesen: USG statfs has an f_bsize field 37 38 Revision 1.46 1992/03/28 22:06:38 ian 39 Michael I Bushnell: renamed enum tstatus to avoid header file conflict 40 41 Revision 1.45 1992/03/26 20:20:28 ian 42 Reduce race condition in fsdo_lock 43 44 Revision 1.44 1992/03/15 01:54:46 ian 45 All execs are now done in isspawn, all waits are done in iswait 46 47 Revision 1.43 1992/03/12 19:54:43 ian 48 Debugging based on types rather than number 49 50 Revision 1.42 1992/03/10 20:45:58 ian 51 Check size of destination file system as well as temporary system 52 53 Revision 1.41 1992/03/09 19:42:43 ian 54 Ted Lindgreen: don't send mail for nonexistent file 55 56 Revision 1.40 1992/03/04 01:40:51 ian 57 Thomas Fischer: tweaked a bit for the NeXT 58 59 Revision 1.39 1992/02/29 04:07:08 ian 60 Added -j option to uucp and uux 61 62 Revision 1.38 1992/02/29 01:06:59 ian 63 Chip Salzenberg: recheck file permissions before sending 64 65 Revision 1.37 1992/02/28 15:57:58 ian 66 Give error if esysdep_open_send is given a directory 67 68 Revision 1.36 1992/02/24 22:05:30 ian 69 Roberto Biancardi: support F_CHSIZE and F_FREESP in esysdep_truncate 70 71 Revision 1.35 1992/02/24 20:07:43 ian 72 John Theus: some systems don't have <fcntl.h> 73 74 Revision 1.34 1992/02/23 03:26:51 ian 75 Overhaul to use automatic configure shell script 76 77 Revision 1.33 1992/02/20 04:18:59 ian 78 Added uustat 79 80 Revision 1.32 1992/02/08 03:54:18 ian 81 Include <string.h> only in <uucp.h>, added 1992 copyright 82 83 Revision 1.31 1992/02/02 20:42:40 ian 84 Niels Baggesen: case enum to int before comparison 85 86 Revision 1.30 1992/02/01 00:54:31 ian 87 Michael Nolan: cast alloca return value 88 89 Revision 1.29 1992/01/29 04:27:11 ian 90 Jay Vassos-Libove: removed some conflicting declarations 91 92 Revision 1.28 1992/01/28 04:34:10 ian 93 Marty Shannon: handle trailing '/' to indicate directory 94 95 Revision 1.27 1992/01/14 04:51:48 ian 96 David Nugent: don't declare chmod 97 98 Revision 1.26 1992/01/14 04:25:20 ian 99 Chip Salzenberg: avoid use before set warning 100 101 Revision 1.25 1992/01/14 03:46:55 ian 102 Chip Salzenberg: handle invalid status values in status files 103 104 Revision 1.24 1992/01/13 06:11:39 ian 105 David Nugent: can't declare open or fcntl 106 107 Revision 1.23 1992/01/05 03:18:54 ian 108 Avoid redefining SEEK_SET 109 110 Revision 1.22 1992/01/04 22:56:22 ian 111 Added extern definition 112 113 Revision 1.21 1992/01/03 05:44:35 ian 114 Remove temporary file if link fails in fsdo_lock 115 116 Revision 1.20 1991/12/29 04:04:18 ian 117 Added a bunch of extern definitions 118 119 Revision 1.19 1991/12/22 22:14:19 ian 120 Monty Solomon: added HAVE_UNISTD_H configuration parameter 121 122 Revision 1.18 1991/12/22 20:50:47 ian 123 Franc,ois Pinard: fixed bug in fsysdep_get_status 124 125 Revision 1.17 1991/12/12 18:35:47 ian 126 Do locking with link to avoid races and to permit running as root 127 128 Revision 1.16 1991/12/12 17:45:34 ian 129 fcopy_file now creates the file with IPRIVATE_MODE 130 131 Revision 1.15 1991/12/11 03:59:19 ian 132 Create directories when necessary; don't just assume they exist 133 134 Revision 1.14 1991/12/09 19:07:07 ian 135 Richard Todd: add HAVE_V2_LOCKFILES--binary number in lock file 136 137 Revision 1.13 1991/12/03 02:59:46 ian 138 Using LOCKDIR clobbered a byte on the stack 139 140 Revision 1.12 1991/12/01 02:23:12 ian 141 Niels Baggesen: don't multiply include <unistd.h> 142 143 Revision 1.11 1991/12/01 01:12:40 ian 144 Marty Shannon: accept truncated status file; also eliminated scanf calls 145 146 Revision 1.10 1991/11/30 23:28:26 ian 147 Marty Shannon: some systems need a fake version of the rename system call 148 149 Revision 1.9 1991/11/21 21:43:42 ian 150 Eliminate unused MIN_FREE_BYTES 151 152 Revision 1.8 1991/11/21 21:07:46 ian 153 Brian Campbell: offer ltrunc as an alternative to ftruncate 154 155 Revision 1.7 1991/11/10 21:32:16 ian 156 Fixed ftruncate call 157 158 Revision 1.6 1991/11/10 19:24:22 ian 159 Added pffile protocol entry point for file level control 160 161 Revision 1.5 1991/11/07 19:32:28 ian 162 Chip Salzenberg: allow LOCKDIR, and check that locking process exists 163 164 Revision 1.4 1991/09/19 17:28:01 ian 165 Chip Salzenberg: make sure spool directory files are not world readable 166 167 Revision 1.3 1991/09/19 03:23:34 ian 168 Chip Salzenberg: append to private debugging file, don't overwrite it 169 170 Revision 1.2 1991/09/19 03:06:04 ian 171 Chip Salzenberg: put BNU temporary files in system's directory 172 173 Revision 1.1 1991/09/10 19:45:50 ian 174 Initial revision 175 176 */ 177 178 #include "uucp.h" 179 180 #if USE_RCS_ID 181 char sys3_unx_rcsid[] = "$Id: sys3.unx,v 1.2 92/05/13 05:42:07 rich Exp Locker: root $"; 182 #endif 183 184 #include <ctype.h> 185 #include <errno.h> 186 187 #if USE_STDIO && HAVE_UNISTD_H 188 #include <unistd.h> 189 #endif 190 191 #include "system.h" 192 #include "sysdep.h" 193 194 #include <pwd.h> 195 196 #if HAVE_FCNTL_H 197 #include <fcntl.h> 198 #else 199 #if HAVE_SYS_FILE_H 200 #include <sys/file.h> 201 #endif 202 #endif 203 204 #ifndef O_RDONLY 205 #define O_RDONLY 0 206 #define O_WRONLY 1 207 #define O_RDWR 2 208 #endif 209 210 /* Get the right header files for statfs and friends. This stuff is 211 from David MacKenzie's df program. */ 212 213 #ifdef FS_STATVFS 214 #include <sys/statvfs.h> 215 extern int statvfs (); 216 #endif 217 218 #ifdef FS_USG_STATFS 219 #include <sys/statfs.h> 220 extern int statfs (); 221 #endif 222 223 #ifdef FS_MNTENT 224 #include <sys/vfs.h> 225 extern int statfs (); 226 #endif 227 228 #ifdef FS_GETMNT 229 #include <sys/param.h> 230 #include <sys/mount.h> 231 extern int statfs (); 232 #endif 233 234 #ifdef FS_STATFS 235 #include <sys/mount.h> 236 extern int statfs (); 237 #endif 238 239 #ifdef FS_USTAT 240 #include <ustat.h> 241 extern int ustat (); 242 #endif 243 244 /* We need a definition for SEEK_SET. */ 245 246 #ifndef SEEK_SET 247 #define SEEK_SET 0 248 #endif 249 250 /* External functions. */ 251 extern int close (), link (), read (), write (); 252 #ifndef __386BSD__ 253 extern int kill (); 254 #endif __386BSD__ 255 extern int fstat (), stat (); 256 extern int fclose (), fseek (), pclose (); 257 extern pid_t getpid (); 258 extern off_t lseek (); 259 extern char *strrchr (); 260 261 #if HAVE_FTRUNCATE 262 extern int ftruncate (); 263 #endif 264 265 #if HAVE_RENAME 266 extern int rename (); 267 #else 268 static int rename P((const char *zfrom, const char *zto)); 269 #endif 270 271 /* There are several types of files that go in the spool directory, 272 and they go into various different subdirectories. When using 273 SPOOLDIR_TAYLOR, there is a subdirectory for each system for which 274 communication occurs; these system names have been made canonical 275 via fread_system_info or ztranslate_name, so they will fit any 276 name length restrictions (namely 14 characters on System V). 277 Whenever the system name LOCAL appears below, it means whatever 278 the local system name is. 279 280 Command files 281 These contain instructions for uucico indicating what files to transfer 282 to and from what systems. Each line of a work file is a command 283 beginning with S, R or X. 284 #if ! SPOOLDIR_TAYLOR 285 They are named C.ssssssgqqqq, where ssssss is the system name to 286 transfer to or from, g is the grade and qqqq is the sequence number. 287 #if SPOOLDIR_V2 288 They are put in the spool directory. 289 #elif SPOOLDIR_BSD42 | SPOOLDIR_BSD43 290 They are put in the directory C. 291 #elif SPOOLDIR_BNU 292 They are put in a directory named for the system for which they were 293 created. 294 #elif SPOOLDIR_ULTRIX 295 If the directory sys/ssssss exists, they are put in the directory 296 sys/ssssss/C; otherwise, they are put in the directory sys/DEFAULT/C. 297 #endif 298 #else SPOOLDIR_TAYLOR 299 They are named C.gqqqq, where g is the grade and qqqq is the sequence 300 number, and are placed in the directory ssssss/C. where ssssss is 301 the system name to transfer to or from. 302 #endif 303 304 Data files 305 There are files to be transferred to other systems. Some files to 306 be transferred may not be in the spool directory, depending on how 307 uucp was invoked. Data files are named in work files, so it is 308 never necessary to look at them directly (except to remove old ones); 309 it is only necessary to create them. These means that the many 310 variations in naming are inconsequential. 311 #if ! SPOOLDIR_TAYLOR 312 They are named D.ssssssgqqqq where ssssss is a system name (which 313 may be LOCAL for locally initiated transfers or a remote system for 314 remotely initiated transfers, except that BNU appears to use the 315 system the file is being transferred to), g is the grade and qqqq 316 is the sequence number. Some systems use a trailing subjob ID 317 number, but we currently do not. The grade is not important, and 318 some systems do not use it. If the data file is to become an 319 execution file on another system the grade (if present) will be 320 'X'. Otherwise Ultrix appears to use 'b'; the uux included with 321 gnuucp 1.0 appears to use 'S'; SCO does not appear to use a grade, 322 although it does use a subjob ID number. 323 #if SPOOLDIR_V2 324 They are put in the spool directory. 325 #elif SPOOLDIR_BSD42 326 If the name begins with D.LOCAL, the file is put in the directory 327 D.LOCAL. Otherwise the file is put in the directory D.. 328 #elif SPOOLDIR_BSD43 329 If the name begins with D.LOCALX, the file is put in the directory 330 D.LOCALX. Otherwise if the name begins with D.LOCAL, the file is 331 put in the directory D.LOCAL Otherwise the file is put in the 332 directory D.. 333 #elif SPOOLDIR_BNU 334 They are put in a directory named for the system for which they 335 were created. 336 #elif SPOOLDIR_ULTRIX 337 Say the file is being transferred to system REMOTE. If the 338 directory sys/REMOTE exists, then if the file begins with D.LOCALX 339 it is put in sys/REMOTE/D.LOCALX, if the file begins with D.LOCAL 340 it is put in sys/REMOTE/D.LOCAL, and otherwise it is put in 341 sys/REMOTE/D.. If the directory sys/REMOTE does not exist, the 342 same applies except that DEFAULT is used instead of REMOTE. 343 #endif 344 #else SPOOLDIR_TAYLOR 345 If the file is to become an executable file on another system it is 346 named D.Xqqqq, otherwise it is named D.qqqq where in both cases 347 qqqq is a sequence number. If the corresponding C. file is in 348 directory ssssss/C., a D.X file is placed in ssssss/D.X and a D. 349 file is placed in ssssss/D.. 350 #endif 351 352 Execute files 353 These are files that specify programs to be executed. They are 354 created by uux, perhaps as run on another system. These names are 355 important, because a file transfer done to an execute file name 356 causes an execution to occur. The name is X.ssssssgqqqq, where 357 ssssss is the requesting system, g is the grade, and qqqq is a 358 sequence number. 359 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 360 These files are placed in the spool directory. 361 #elif SPOOLDIR_BSD43 362 These files are placed in the directory X.. 363 #elif SPOOLDIR_BNU 364 These files are put in a directory named for the system for which 365 the files were created. 366 #elif SPOOLDIR_ULTRIX 367 If there is a spool directory (sys/ssssss) for the requesting 368 system, the files are placed in sys/ssssss/X.; otherwise, the files 369 are placed in sys/DEFAULT/X.. 370 #elif SPOOLDIR_TAYLOR 371 The system name is automatically truncated to seven characters when 372 a file is created. The files are placed in the subdirectory X. of 373 a directory named for the system for which the files were created. 374 #endif 375 376 Temporary receive files 377 These are used when receiving files from another system. They are 378 later renamed to the final name. The actual name is unimportant, 379 although it generally begins with TM.. 380 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 381 These files are placed in the spool directory. 382 #elif SPOOLDIR_BSD43 | SPOOLDIR_ULTRIX | SPOOLDIR_TAYLOR 383 These files are placed in the directory .Temp. 384 #elif SPOOLDIR_BNU 385 These files are placed in a directory named for the system for 386 which they were created. 387 #endif 388 389 Lock files 390 These files are used to lock systems, devices and special files. 391 The file LCK..ssssss is used to lock a system, where ssssss is the 392 system name. The file LCK..dev is used to lock a device, where dev 393 is the device name. The file LCK.file is used to lock a file, 394 where file is LOG for the log file, SQ for the system sequence 395 number file, or SEQF for the work queue sequence number file. At 396 least under Ultrix, the file LCK.XQT is used to lock uuxqt 397 execution. Some systems supposedly use LCK.SEQL for something. On 398 some systems, the contents of the lock file is the ASCII process 399 id; on others, it is the process id as four data bytes. As far as 400 I can tell, the only lock file I really have to get right is the 401 one locking a device, so that cu won't use it; if somebody tries to 402 run old UUCP and this at the same time, they will probably have 403 trouble unless they make sure the locking is correct for their 404 system. Not that there is any easy way to make that check, 405 unfortunately. Supposedly all normal systems put the LCK files in 406 the spool directory, and this package will do that also. 407 408 System status files 409 These are used to record when the last call was made to the system 410 and what the status is. They are used to prevent frequent recalls 411 to a system which is not responding. I will not attempt to 412 recreate the format of these exactly, since they are not all that 413 important. They will be put in the directory .Status, as in BNU, 414 and they use the system name as the name of the file. 415 416 Log files 417 These are used to record what UUCP has done. I will not attempt to 418 recreate the format of these at all. They will be stored in the 419 directory .Log/uucico (or .Log/uucp, .Log/uux, .Log/uuxqt) and 420 named for the relevant system. This is the format used by BNU. 421 422 Statistics files 423 I don't really know the format of these. They are apparently used 424 to keep track of what jobs have been run by UUCP, but at least on 425 Ultrix they don't seem to be used very consistently. 426 427 Sequence file 428 This is used to generate a unique sequence number. It contains an 429 ASCII number. 430 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 | SPOOLDIR_BSD43 431 The file is named SEQF and is kept in the spool directory. 432 #elif SPOOLDIR_BNU 433 A separate sequence file is kept for each system in the directory 434 .Sequence with the name of the system. 435 #elif SPOOLDIR_ULTRIX 436 Each system with a file sys/ssssss has a sequence file in 437 sys/ssssss/.SEQF. Other systems use sys/DEFAULT/.SEQF. 438 #else SPOOLDIR_TAYLOR 439 A sequence file named SEQF is kept in the directory ssssss for each 440 system. 441 #endif 442 443 Audit files 444 Debugging messages are stored in these when running as a slave. We 445 use the file AUDIT in the spool directory. */ 446 447 /* Local functions. */ 448 449 static char *zsstatic_size P((int c)); 450 #if SPOOLDIR_TAYLOR 451 static const char *zsappend3 P((const char *zdir1, const char *zdir2, 452 const char *zfile)); 453 #endif 454 #if SPOOLDIR_ULTRIX 455 static const char *zsappend4 P((const char *zdir1, const char *zdir2, 456 const char *zdir3, const char *zfile)); 457 #endif 458 static const char *zsfind_file P((const char *zsimple, 459 const char *zsystem)); 460 static boolean fscmd_seq P((const char *zsystem, char *zseq)); 461 static const char *zsfile_name P((int btype, const char *zsystem, 462 int bgrade, char *ztname, 463 char *zdname, char *zxname)); 464 465 /* A few routines to manipulate strings with directories. */ 466 467 #define CSTATICLEN (50) 468 static char abSstatic[CSTATICLEN]; 469 static char *zSstatic_alloc; 470 static int cSstatic_alloc; 471 472 /* Return a pointer to a static buffer of a certain size. */ 473 474 static char * 475 zsstatic_size (c) 476 int c; 477 { 478 if (c <= CSTATICLEN) 479 return abSstatic; 480 if (cSstatic_alloc < c) 481 { 482 xfree ((pointer) zSstatic_alloc); 483 zSstatic_alloc = (char *) xmalloc (c); 484 cSstatic_alloc = c; 485 } 486 return zSstatic_alloc; 487 } 488 489 /* Copy a string into a static buffer. */ 490 491 const char * 492 zscopy (z) 493 const char *z; 494 { 495 char *zret; 496 497 zret = zsstatic_size (strlen (z) + 1); 498 strcpy (zret, z); 499 return (const char *) zret; 500 } 501 502 /* Stick a directory and file name together. Return a static buffer 503 holding the combined name. This is called by Unix system dependent 504 routines outside this file. */ 505 506 const char * 507 zsappend (zdir, zfile) 508 const char *zdir; 509 const char *zfile; 510 { 511 char *zret; 512 513 zret = zsstatic_size (strlen (zdir) + strlen (zfile) + sizeof "/"); 514 sprintf (zret, "%s/%s", zdir, zfile); 515 return (const char *) zret; 516 } 517 518 #if SPOOLDIR_TAYLOR 519 520 /* Stick two directories and a file name together. Return a static 521 buffer holding the combined name. */ 522 523 static const char * 524 zsappend3 (zdir1, zdir2, zfile) 525 const char *zdir1; 526 const char *zdir2; 527 const char *zfile; 528 { 529 char *zret; 530 531 zret = zsstatic_size (strlen (zdir1) + strlen (zdir2) 532 + strlen (zfile) + sizeof "//"); 533 sprintf (zret, "%s/%s/%s", zdir1, zdir2, zfile); 534 return (const char *) zret; 535 } 536 537 #endif /* SPOOLDIR_TAYLOR */ 538 539 #if SPOOLDIR_ULTRIX 540 541 /* Stick three directories and a file name together. Return a static 542 buffer holding the combined name. */ 543 544 static const char * 545 zsappend4 (zdir1, zdir2, zdir3, zfile) 546 const char *zdir1; 547 const char *zdir2; 548 const char *zdir3; 549 const char *zfile; 550 { 551 char *zret; 552 553 zret = zsstatic_size (strlen (zdir1) + strlen (zdir2) + strlen (zdir3) 554 + strlen (zfile) + sizeof "///"); 555 sprintf (zret, "%s/%s/%s/%s", zdir1, zdir2, zdir3, zfile); 556 return (const char *) zret; 557 } 558 559 /* See whether an ULTRIX spool directory exists for a system. For system 560 ssssss, the spool directory is called sys/ssssss. */ 561 562 boolean 563 fsultrix_has_spool (zsystem) 564 const char *zsystem; 565 { 566 char *z; 567 568 z = (char *) alloca (sizeof "sys/" + strlen (zsystem)); 569 sprintf (z, "sys/%s", zsystem); 570 return fsdirectory_exists (z); 571 } 572 573 #endif /* SPOOLDIR_ULTRIX */ 574 575 /* Create a spool directory for a system. This is only relevant for 576 SPOOLDIR_BNU or SPOOLDIR_TAYLOR. The system specific directories 577 for Ultrix are meant to be created by hand. */ 578 579 #if SPOOLDIR_TAYLOR | SPOOLDIR_BNU 580 581 static boolean fsmkdir P((const char *zdir)); 582 583 static boolean 584 fsmkdir (zdir) 585 const char *zdir; 586 { 587 if (mkdir ((char *) zdir, IDIRECTORY_MODE) < 0) 588 { 589 ulog (LOG_ERROR, "mkdir (%s): %s", zdir, strerror (errno)); 590 return FALSE; 591 } 592 return TRUE; 593 } 594 595 #endif /* SPOOLDIR_TAYLOR | SPOOLDIR_BNU */ 596 597 boolean 598 fsysdep_make_spool_dir (qsys) 599 const struct ssysteminfo *qsys; 600 { 601 const char *zsystem; 602 603 zsystem = qsys->zname; 604 605 #if SPOOLDIR_BNU 606 if (fsdirectory_exists (zsystem)) 607 return TRUE; 608 if (! fsmkdir (zsystem)) 609 return FALSE; 610 #endif /* SPOOLDIR_BNU */ 611 612 #if SPOOLDIR_TAYLOR 613 if (fsdirectory_exists (zsystem)) 614 return TRUE; 615 if (! fsmkdir (zsystem) 616 || ! fsmkdir (zsappend (zsystem, "C.")) 617 || ! fsmkdir (zsappend (zsystem, "D.")) 618 || ! fsmkdir (zsappend (zsystem, "D.X")) 619 || ! fsmkdir (zsappend (zsystem, "X."))) 620 return FALSE; 621 #endif /* SPOOLDIR_TAYLOR */ 622 623 return TRUE; 624 } 625 626 /* Given the name of a file as specified in a UUCP command, and the 627 system for which this file has been created, return where to find 628 it in the spool directory. The file will begin with C. (a command 629 file), D. (a data file) or X. (an execution file). The return 630 value of this function will point to a static buffer. */ 631 632 static const char * 633 zsfind_file (zsimple, zsystem) 634 const char *zsimple; 635 const char *zsystem; 636 { 637 if (zsimple[1] != '.' 638 || (*zsimple != 'C' 639 && *zsimple != 'D' 640 && *zsimple != 'X')) 641 { 642 ulog (LOG_ERROR, "Unrecognized file name %s", zsimple); 643 return NULL; 644 } 645 646 switch (*zsimple) 647 { 648 case 'C': 649 #if SPOOLDIR_V2 650 return zscopy (zsimple); 651 #endif /* SPOOLDIR_V2 */ 652 #if SPOOLDIR_BSD42 | SPOOLDIR_BSD43 653 return zsappend ("C.", zsimple); 654 #endif /* SPOOLDIR_BSD42 | SPOOLDIR_BSD43 */ 655 #if SPOOLDIR_BNU 656 return zsappend (zsystem, zsimple); 657 #endif /* SPOOLDIR_BNU */ 658 #if SPOOLDIR_ULTRIX 659 if (fsultrix_has_spool (zsystem)) 660 return zsappend4 ("sys", zsystem, "C.", zsimple); 661 else 662 return zsappend4 ("sys", "DEFAULT", "C.", zsimple); 663 #endif 664 #if SPOOLDIR_TAYLOR 665 return zsappend3 (zsystem, "C.", zsimple); 666 #endif 667 668 case 'D': 669 #if SPOOLDIR_V2 670 return zscopy (zsimple); 671 #endif /* SPOOLDIR_V2 */ 672 #if SPOOLDIR_BSD42 | SPOOLDIR_BSD43 673 { 674 int c; 675 boolean ftruncated; 676 char *zalloc; 677 678 /* D.LOCAL in D.LOCAL/, others in D./. If BSD43, D.LOCALX in 679 D.LOCALX/. */ 680 ftruncated = TRUE; 681 if (strncmp (zsimple + 2, zLocalname, strlen (zLocalname)) == 0) 682 { 683 c = strlen (zLocalname); 684 ftruncated = FALSE; 685 } 686 else if (strncmp (zsimple + 2, zLocalname, 7) == 0) 687 c = 7; 688 else if (strncmp (zsimple + 2, zLocalname, 6) == 0) 689 c = 6; 690 else 691 c = 0; 692 #if SPOOLDIR_BSD43 693 if (c > 0 && zsimple[c + 2] == 'X') 694 c++; 695 #endif /* SPOOLDIR_BSD43 */ 696 if (c > 0) 697 { 698 zalloc = (char *) alloca (c + 3); 699 strncpy (zalloc, zsimple, c + 2); 700 zalloc[c + 2] = '\0'; 701 702 /* If we truncated the system name, and there is no existing 703 directory with the truncated name, then just use D.. */ 704 if (ftruncated && ! fsdirectory_exists (zalloc)) 705 return zsappend ("D.", zsimple); 706 707 return zsappend (zalloc, zsimple); 708 } 709 else 710 return zsappend ("D.", zsimple); 711 } 712 #endif /* SPOOLDIR_BSD42 | SPOOLDIR_BSD43 */ 713 #if SPOOLDIR_BNU 714 return zsappend (zsystem, zsimple); 715 #endif /* SPOOLDIR_BNU */ 716 #if SPOOLDIR_ULTRIX 717 { 718 int c; 719 boolean ftruncated; 720 char *zalloc; 721 const char *zdir; 722 723 /* D.LOCALX in D.LOCALX/, D.LOCAL in D.LOCAL/, others in D./. */ 724 725 ftruncated = TRUE; 726 if (strncmp (zsimple + 2, zLocalname, strlen (zLocalname)) == 0) 727 { 728 c = strlen (zLocalname); 729 ftruncated = FALSE; 730 } 731 else if (strncmp (zsimple + 2, zLocalname, 7) == 0) 732 c = 7; 733 else if (strncmp (zsimple + 2, zLocalname, 6) == 0) 734 c = 6; 735 else 736 c = 0; 737 if (c > 0 && zsimple[c + 2] == 'X') 738 c++; 739 if (c > 0) 740 { 741 zalloc = (char *) alloca (c + 3); 742 strncpy (zalloc, zsimple, c + 2); 743 zalloc[c + 2] = '\0'; 744 zdir = zalloc; 745 746 /* If we truncated the name, and there is no directory for 747 the truncated name, then don't use it. */ 748 if (ftruncated) 749 { 750 char *zlook; 751 752 zlook = (char *) alloca (c + 20 + strlen (zsystem)); 753 if (fsultrix_has_spool (zsystem)) 754 sprintf (zlook, "sys/%s/%s", zsystem, zdir); 755 else 756 sprintf (zlook, "sys/DEFAULT/%s", zdir); 757 if (! fsdirectory_exists (zlook)) 758 zdir = "D."; 759 } 760 } 761 else 762 zdir = "D."; 763 764 if (fsultrix_has_spool (zsystem)) 765 return zsappend4 ("sys", zsystem, zdir, zsimple); 766 else 767 return zsappend4 ("sys", "DEFAULT", zdir, zsimple); 768 } 769 #endif /* SPOOLDIR_ULTRIX */ 770 #if SPOOLDIR_TAYLOR 771 if (zsimple[2] == 'X') 772 return zsappend3 (zsystem, "D.X", zsimple); 773 else 774 return zsappend3 (zsystem, "D.", zsimple); 775 #endif /* SPOOLDIR_TAYLOR */ 776 777 /* Files beginning with X. are execute files. It is important 778 for security reasons that we know the system which created 779 the X. file. This is easy under SPOOLDIR_BNU or 780 SPOOLDIR_TAYLOR, because the file will be in a directory 781 named for the system. Under other schemes, we must get the 782 system name from the X. file name. To prevent security 783 violations, we set the system name directly here; this will 784 cause problems if the maximum file name length is too short, 785 but hopefully no problem will occur since any System V 786 systems will be using either BNU or TAYLOR. */ 787 788 case 'X': 789 #if ! SPOOLDIR_BNU && ! SPOOLDIR_TAYLOR 790 if (strncmp (zsimple + 2, zsystem, strlen (zsimple) - 7) != 0) 791 { 792 char *zcopy; 793 794 zcopy = (char *) alloca (strlen (zsystem) + 8); 795 sprintf (zcopy, "X.%s%s", zsystem, 796 zsimple + strlen (zsimple) - 5); 797 zsimple = zcopy; 798 } 799 #endif /* ! SPOOLDIR_BNU && ! SPOOLDIR_TAYLOR */ 800 801 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 802 return zscopy (zsimple); 803 #endif 804 #if SPOOLDIR_BSD43 805 return zsappend ("X.", zsimple); 806 #endif 807 #if SPOOLDIR_BNU 808 return zsappend (zsystem, zsimple); 809 #endif 810 #if SPOOLDIR_ULTRIX 811 if (fsultrix_has_spool (zsystem)) 812 return zsappend4 ("sys", zsystem, "X.", zsimple); 813 else 814 return zsappend4 ("sys", "DEFAULT", "X.", zsimple); 815 #endif 816 #if SPOOLDIR_TAYLOR 817 return zsappend3 (zsystem, "X.", zsimple); 818 #endif 819 820 default: 821 #if DEBUG > 0 822 ulog (LOG_FATAL, "zsfind_file: Can't happen"); 823 #endif /* DEBUG */ 824 return NULL; 825 } 826 /*NOTREACHED*/ 827 } 828 829 /* Get the status of a system. */ 830 831 /*ARGSUSED*/ 832 boolean 833 fsysdep_get_status (qsys, qret) 834 const struct ssysteminfo *qsys; 835 struct sstatus *qret; 836 { 837 const char *zname; 838 FILE *e; 839 char *zline; 840 char *zend, *znext; 841 boolean fbad; 842 int istat; 843 844 zname = zsappend (".Status", qsys->zname); 845 e = fopen (zname, "r"); 846 if (e == NULL) 847 { 848 if (errno != ENOENT) 849 { 850 ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); 851 return FALSE; 852 } 853 zline = NULL; 854 } 855 else 856 { 857 zline = zfgets (e, FALSE); 858 (void) fclose (e); 859 } 860 861 if (zline == NULL) 862 { 863 /* There is either no status file for this system, or it's been 864 truncated, so fake a good status. */ 865 qret->ttype = STATUS_COMPLETE; 866 qret->cretries = 0; 867 qret->ilast = 0; 868 qret->cwait = 0; 869 return TRUE; 870 } 871 872 /* It turns out that scanf is not used much in this program, so for 873 the benefit of small computers we avoid linking it in. This is 874 basically 875 876 sscanf (zline, "%d %d %ld %d", &qret->ttype, &qret->cretries, 877 &qret->ilast, &qret->cwait); 878 879 except that it's done with strtol. */ 880 881 fbad = FALSE; 882 istat = (int) strtol (zline, &zend, 10); 883 if (zend == zline) 884 fbad = TRUE; 885 886 /* On some systems it may be appropriate to map system dependent status 887 values on to our status values. Perhaps someday. */ 888 889 if (istat < 0 || istat >= (int) STATUS_VALUES) 890 istat = (int) STATUS_COMPLETE; 891 qret->ttype = (enum tstatus_type) istat; 892 znext = zend; 893 qret->cretries = (int) strtol (znext, &zend, 10); 894 if (zend == znext) 895 fbad = TRUE; 896 znext = zend; 897 qret->ilast = strtol (znext, &zend, 10); 898 if (zend == znext) 899 fbad = TRUE; 900 znext = zend; 901 qret->cwait = (int) strtol (znext, &zend, 10); 902 if (zend == znext) 903 fbad = TRUE; 904 905 xfree ((pointer) zline); 906 907 if (fbad) 908 { 909 ulog (LOG_ERROR, "Bad format of status file for %s", qsys->zname); 910 return FALSE; 911 } 912 913 return TRUE; 914 } 915 916 /* Set the status of a remote system. We assume the system is locked 917 when this is called. */ 918 919 /*ARGSUSED*/ 920 boolean 921 fsysdep_set_status (qsys, qset) 922 const struct ssysteminfo *qsys; 923 const struct sstatus *qset; 924 { 925 const char *zname; 926 FILE *e; 927 int istat; 928 929 zname = zsappend (".Status", qsys->zname); 930 931 e = esysdep_fopen (zname, TRUE, FALSE, TRUE); 932 if (e == NULL) 933 return FALSE; 934 istat = (int) qset->ttype; 935 936 /* On some systems it may be appropriate to map istat onto a system 937 dependent number. Perhaps someday. */ 938 939 fprintf (e, "%d %d %ld %d %s %s\n", istat, qset->cretries, 940 qset->ilast, qset->cwait, azStatus[(int) qset->ttype], 941 qsys->zname); 942 if (fclose (e) != 0) 943 { 944 ulog (LOG_ERROR, "fclose: %s", strerror (errno)); 945 return FALSE; 946 } 947 948 return TRUE; 949 } 950 951 /* Get the real name of a spool file. */ 952 953 const char * 954 zsysdep_spool_file_name (qsys, zfile) 955 const struct ssysteminfo *qsys; 956 const char *zfile; 957 { 958 return zsfind_file (zfile, qsys->zname); 959 } 960 961 /* Expand a file name on the local system. The qsys argument is only 962 used to determine which public directory to use. */ 963 964 const char * 965 zsysdep_real_file_name (qsys, zfile, zname) 966 const struct ssysteminfo *qsys; 967 const char *zfile; 968 const char *zname; 969 { 970 const char *ztry; 971 char *zlook; 972 973 if (zfile[0] == '/') 974 ztry = zfile; 975 else if (zfile[0] == '~') 976 { 977 const char *z; 978 char *zcopy; 979 980 z = zstilde_expand (qsys, zfile); 981 zcopy = (char *) alloca (strlen (z) + 1); 982 strcpy (zcopy, z); 983 ztry = zcopy; 984 } 985 else 986 { 987 const char *zpub, *z; 988 char *zcopy; 989 990 /* Put the file in the public directory. */ 991 if (qsys == NULL || qsys->zpubdir == NULL) 992 zpub = zPubdir; 993 else 994 zpub = qsys->zpubdir; 995 z = zsappend (zpub, zfile); 996 zcopy = (char *) alloca (strlen (z) + 1); 997 strcpy (zcopy, z); 998 ztry = zcopy; 999 } 1000 1001 /* If we don't have a file name to use within a directory, or we 1002 haven't named a directory, we use what we've got so far. If the 1003 name ends in a '/', it is assumed to name a directory. */ 1004 1005 if (zname == NULL) 1006 return zscopy (ztry); 1007 1008 if (ztry[strlen (ztry) - 1] != '/') 1009 { 1010 if (! fsdirectory_exists (ztry)) 1011 return zscopy (ztry); 1012 } 1013 else 1014 { 1015 char *zcopy; 1016 int clen; 1017 1018 clen = strlen (ztry); 1019 zcopy = (char *) alloca (clen + 1); 1020 strcpy (zcopy, ztry); 1021 zcopy[clen - 1] = '\0'; 1022 ztry = zcopy; 1023 } 1024 1025 /* Get a name out of zname and tag it on. */ 1026 1027 zlook = strrchr (zname, '/'); 1028 if (zlook != NULL) 1029 zname = zlook + 1; 1030 1031 return zsappend (ztry, zname); 1032 } 1033 1034 /* Return a file name within a directory. */ 1035 1036 const char * 1037 zsysdep_in_dir (zdir, zfile) 1038 const char *zdir; 1039 const char *zfile; 1040 { 1041 if (fsdirectory_exists (zdir)) 1042 return zsappend (zdir, zfile); 1043 else 1044 return zdir; 1045 } 1046 1047 /* Open a file to send to another system, and return the mode and 1048 the size. */ 1049 1050 /*ARGSUSED*/ 1051 openfile_t 1052 esysdep_open_send (qsys, zfile, fcheck, zuser, pimode, pcbytes, pfgone) 1053 const struct ssysteminfo *qsys; 1054 const char *zfile; 1055 boolean fcheck; 1056 const char *zuser; 1057 unsigned int *pimode; 1058 long *pcbytes; 1059 boolean *pfgone; 1060 { 1061 struct stat s; 1062 openfile_t e; 1063 int o; 1064 1065 if (pfgone != NULL) 1066 *pfgone = FALSE; 1067 1068 if (fsdirectory_exists (zfile)) 1069 { 1070 ulog (LOG_ERROR, "%s: is a directory", zfile); 1071 return EFILECLOSED; 1072 } 1073 #if USE_STDIO 1074 e = fopen (zfile, BINREAD); 1075 if (e == NULL) 1076 { 1077 ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); 1078 if (pfgone != NULL && errno == ENOENT) 1079 *pfgone = TRUE; 1080 return NULL; 1081 } 1082 o = fileno (e); 1083 #else 1084 e = open (zfile, O_RDONLY, 0); 1085 if (e == -1) 1086 { 1087 ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); 1088 if (pfgone != NULL && errno == ENOENT) 1089 *pfgone = TRUE; 1090 return -1; 1091 } 1092 o = e; 1093 #endif 1094 1095 if (fstat (o, &s) == -1) 1096 { 1097 ulog (LOG_ERROR, "fstat: %s", strerror (errno)); 1098 s.st_mode = 0666; 1099 } 1100 1101 /* We have to recheck the file permission, although we probably 1102 checked it already, because otherwise there would be a window in 1103 which somebody could change the contents of a symbolic link to 1104 point to some file which was only readable by uucp. */ 1105 if (fcheck) 1106 { 1107 if (! fsuser_access (&s, R_OK, zuser)) 1108 { 1109 ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES)); 1110 (void) ffileclose (e); 1111 return EFILECLOSED; 1112 } 1113 } 1114 1115 *pimode = s.st_mode & 0777; 1116 *pcbytes = s.st_size; 1117 return e; 1118 } 1119 1120 /* Get a temporary file name. */ 1121 1122 /*ARGSUSED*/ 1123 const char * 1124 zstemp_file (qsys) 1125 const struct ssysteminfo *qsys; 1126 { 1127 static int icount; 1128 char *zret; 1129 1130 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 1131 { 1132 static char ab[sizeof "TM.12345.123"]; 1133 1134 sprintf (ab, "TM.%05d.%03d", getpid (), icount); 1135 zret = ab; 1136 } 1137 #endif 1138 #if SPOOLDIR_BSD43 | SPOOLDIR_ULTRIX | SPOOLDIR_TAYLOR 1139 { 1140 static char ab[sizeof ".Temp/TM.12345.123"]; 1141 1142 sprintf (ab, ".Temp/TM.%05d.%03d", getpid (), icount); 1143 zret = ab; 1144 } 1145 #endif 1146 #if SPOOLDIR_BNU 1147 { 1148 static char *z; 1149 static int calc; 1150 int cneed; 1151 1152 cneed = strlen (qsys->zname) + sizeof "/TM.12345.123"; 1153 if (cneed > calc) 1154 { 1155 xfree ((pointer) z); 1156 z = (char *) xmalloc (cneed); 1157 calc = cneed; 1158 } 1159 sprintf (z, "%s/TM.%05d.%03d", qsys->zname, getpid (), icount); 1160 zret = z; 1161 } 1162 #endif 1163 1164 ++icount; 1165 1166 return zret; 1167 } 1168 1169 /* Open a temporary file to receive into. This should, perhaps, check 1170 that we have write permission on the receiving directory, but it 1171 doesn't. It is supposed to set *pcbytes to the size of the largest 1172 file that can be accepted. */ 1173 1174 /*ARGSUSED*/ 1175 openfile_t 1176 esysdep_open_receive (qsys, zto, pztemp, pcbytes) 1177 const struct ssysteminfo *qsys; 1178 const char *zto; 1179 const char **pztemp; 1180 long *pcbytes; 1181 { 1182 const char *z; 1183 int o; 1184 openfile_t e; 1185 long c1, c2; 1186 char *zcopy, *zslash; 1187 1188 z = zstemp_file (qsys); 1189 1190 o = creat (z, IPRIVATE_FILE_MODE); 1191 1192 if (o == -1) 1193 { 1194 if (errno == ENOENT) 1195 { 1196 if (! fsysdep_make_dirs (z, FALSE)) 1197 return EFILECLOSED; 1198 o = creat (z, IPRIVATE_FILE_MODE); 1199 } 1200 if (o == -1) 1201 { 1202 ulog (LOG_ERROR, "creat (%s): %s", z, strerror (errno)); 1203 return EFILECLOSED; 1204 } 1205 } 1206 1207 #if USE_STDIO 1208 e = fdopen (o, (char *) BINWRITE); 1209 1210 if (e == NULL) 1211 { 1212 ulog (LOG_ERROR, "fdopen (%s): %s", z, strerror (errno)); 1213 (void) close (o); 1214 (void) remove (z); 1215 return NULL; 1216 } 1217 #else 1218 e = o; 1219 #endif 1220 1221 *pztemp = z; 1222 1223 /* Try to determine the amount of free space available for the 1224 temporary file and for the final destination. This code is 1225 mostly from David MacKenzie's df program. */ 1226 1227 c1 = (long) -1; 1228 c2 = (long) -1; 1229 1230 zcopy = (char *) alloca (strlen (zto) + 1); 1231 strcpy (zcopy, zto); 1232 zslash = strrchr (zcopy, '/'); 1233 if (zslash != NULL) 1234 *zslash = '\0'; 1235 else 1236 { 1237 zcopy[0] = '.'; 1238 zcopy[1] = '\0'; 1239 } 1240 1241 { 1242 #ifdef FS_STATVFS 1243 struct statvfs s; 1244 1245 if (statvfs (z, &s) >= 0) 1246 c1 = (long) s.f_bavail * (long) s.f_frsize; 1247 if (statvfs (zcopy, &s) >= 0) 1248 c2 = (long) s.f_bavail * (long) s.f_frsize; 1249 #endif 1250 #ifdef FS_USG_STATFS 1251 struct statfs s; 1252 1253 /* This structure has an f_bsize field, but on many systems 1254 f_bfree is measured in 512 byte blocks. On some systems, 1255 f_bfree is measured in f_bsize byte blocks. Rather than 1256 overestimate the amount of free space, this code assumes that 1257 f_bfree is measuring 512 byte blocks. */ 1258 1259 if (statfs (z, &s, sizeof s, 0) >= 0) 1260 c1 = (long) s.f_bfree * (long) 512; 1261 if (statfs (zcopy, &s, sizeof s, 0) >= 0) 1262 c2 = (long) s.f_bfree * (long) 512; 1263 #endif 1264 #ifdef FS_MNTENT 1265 struct statfs s; 1266 1267 if (statfs (z, &s) == 0) 1268 c1 = (long) s.f_bavail * (long) s.f_bsize; 1269 if (statfs (zcopy, &s) == 0) 1270 c2 = (long) s.f_bavail * (long) s.f_bsize; 1271 #endif 1272 #ifdef FS_GETMNT 1273 struct fs_data s; 1274 1275 if (statfs (z, &s) == 1) 1276 c1 = (long) s.fd_req.bfreen * (long) 1024; 1277 if (statfs (zcopy, &s) == 1) 1278 c2 = (long) s.fd_req.bfreen * (long) 1024; 1279 #endif 1280 #ifdef FS_STATFS 1281 struct statfs s; 1282 1283 if (statfs (z, &s) >= 0) 1284 c1 = (long) s.f_bavail * (long) s.f_fsize; 1285 if (statfs (zcopy, &s) >= 0) 1286 c2 = (long) s.f_bavail * (long) s.f_fsize; 1287 #endif 1288 #ifdef FS_USTAT 1289 struct stat sstat; 1290 struct ustat s; 1291 1292 if (fstat (o, &sstat) == 0 1293 && ustat (sstat.st_dev, &s) == 0) 1294 c1 = (long) s.f_tfree * (long) 512; 1295 if (stat (zcopy, &sstat) == 0 1296 && ustat (sstat.st_dev, &s) == 0) 1297 c2 = (long) s.f_tfree * (long) 512; 1298 #endif 1299 } 1300 1301 if (c1 == (long) -1) 1302 *pcbytes = c2; 1303 else if (c2 == (long) -1) 1304 *pcbytes = c1; 1305 else if (c1 < c2) 1306 *pcbytes = c1; 1307 else 1308 *pcbytes = c2; 1309 1310 return e; 1311 } 1312 1313 /* After the temporary file has been completely written out, the file 1314 is closed and this routine is called to move it into its final 1315 location. If we fail, we must remove the temporary file. */ 1316 1317 boolean 1318 fsysdep_move_file (zorig, zto, imode, fcheck, zuser) 1319 const char *zorig; 1320 const char *zto; 1321 unsigned int imode; 1322 boolean fcheck; 1323 const char *zuser; 1324 { 1325 DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, 1326 "fsysdep_move_file: Moving %s to %s", zorig, zto); 1327 1328 /* Unless and until we add an option to change the ownership of the 1329 file, the only information we want from the mode is whether the 1330 file is executable or not. It would be dumb to create a file 1331 with mode 0600, for example, since the owner will be uucp and the 1332 recipient will not be able to read it. If we do not have an 1333 absolute path to the file, which means that it is being moved 1334 somewhere in the spool directory, we don't change the mode; in 1335 general, the files in the spool directory should not be 1336 publically readable. */ 1337 1338 if (*zto != '/') 1339 imode = 0; 1340 1341 if (imode != 0) 1342 { 1343 if ((imode & 0111) != 0) 1344 imode = S_IRWXU | S_IRWXG | S_IRWXO; 1345 else 1346 imode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 1347 } 1348 1349 /* Optionally make sure that zuser has write access on the 1350 directory. We only check files that are not in the spool 1351 directory. */ 1352 if (fcheck && *zto == '/') 1353 { 1354 char *zcopy; 1355 char *zslash; 1356 struct stat s; 1357 1358 zcopy = (char *) alloca (strlen (zto) + 1); 1359 strcpy (zcopy, zto); 1360 zslash = strrchr (zcopy, '/'); 1361 if (zslash == zcopy) 1362 zslash[1] = '\0'; 1363 else 1364 *zslash = '\0'; 1365 1366 if (stat (zcopy, &s) != 0) 1367 { 1368 ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno)); 1369 (void) remove (zorig); 1370 return FALSE; 1371 } 1372 if (! fsuser_access (&s, W_OK, zuser)) 1373 { 1374 ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); 1375 (void) remove (zorig); 1376 return FALSE; 1377 } 1378 1379 /* A malicious user now has a few milliseconds to change a 1380 symbolic link to a directory uucp has write permission on but 1381 the user does not (the obvious choice being /usr/lib/uucp). 1382 The only certain method I can come up with to close this race 1383 is to fork an suid process which takes on the users identity 1384 and does the actual copy. This is sufficiently high overhead 1385 that I'm not going to do it. */ 1386 } 1387 1388 /* We try to use rename to move the file. */ 1389 1390 if (rename (zorig, zto) == 0) 1391 { 1392 /* We must set the correct file mode, but don't worry if it doesn't 1393 work. There should be an option for setting the owner, as 1394 well. */ 1395 if (imode != 0) 1396 (void) chmod (zto, imode); 1397 return TRUE; 1398 } 1399 1400 /* If this file is in the spool directory, make sure all directories 1401 exist. */ 1402 if (*zto != '/' && errno == ENOENT) 1403 { 1404 if (! fsysdep_make_dirs (zto, FALSE)) 1405 { 1406 (void) remove (zorig); 1407 return FALSE; 1408 } 1409 if (rename (zorig, zto) == 0) 1410 { 1411 if (imode != 0) 1412 (void) chmod (zto, imode); 1413 return TRUE; 1414 } 1415 } 1416 1417 /* If we can't link across devices, we must copy the file by hand. */ 1418 if (errno != EXDEV) 1419 { 1420 ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto, 1421 strerror (errno)); 1422 (void) remove (zorig); 1423 return FALSE; 1424 } 1425 1426 /* If the destination file is not in the spool directory, any 1427 necessary directories should already have been made. */ 1428 if (! fcopy_file (zorig, zto, FALSE, *zto != '/')) 1429 { 1430 (void) remove (zorig); 1431 return FALSE; 1432 } 1433 1434 if (remove (zorig) < 0) 1435 ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno)); 1436 1437 if (imode != 0) 1438 (void) chmod (zto, imode); 1439 1440 return TRUE; 1441 } 1442 1443 /* Truncate a file to zero length. If this fails, it closes and 1444 removes the file. We support a number of different means of 1445 truncation, which is probably a waste of time since this function 1446 is currently only called when the 'f' protocol resends a file. */ 1447 1448 #if HAVE_FTRUNCATE 1449 #undef HAVE_LTRUNC 1450 #define HAVE_LTRUNC 0 1451 #endif 1452 1453 #if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC 1454 #ifdef F_CHSIZE 1455 #define HAVE_F_CHSIZE 1 1456 #else /* ! defined (F_CHSIZE) */ 1457 #ifdef F_FREESP 1458 #define HAVE_F_FREESP 1 1459 #endif /* defined (F_FREESP) */ 1460 #endif /* ! defined (F_CHSIZE) */ 1461 #endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */ 1462 1463 openfile_t 1464 esysdep_truncate (e, zname) 1465 openfile_t e; 1466 const char *zname; 1467 { 1468 int o; 1469 1470 #if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP 1471 int itrunc; 1472 1473 if (! ffilerewind (e)) 1474 { 1475 ulog (LOG_ERROR, "rewind: %s", strerror (errno)); 1476 (void) ffileclose (e); 1477 (void) remove (zname); 1478 return EFILECLOSED; 1479 } 1480 1481 #if USE_STDIO 1482 o = fileno (e); 1483 #else 1484 o = e; 1485 #endif 1486 1487 #if HAVE_FTRUNCATE 1488 itrunc = ftruncate (o, 0); 1489 #endif 1490 #if HAVE_LTRUNC 1491 itrunc = ltrunc (o, (long) 0, SEEK_SET); 1492 #endif 1493 #if HAVE_F_CHSIZE 1494 itrunc = fcntl (o, F_CHSIZE, (off_t) 0); 1495 #endif 1496 #if HAVE_F_FREESP 1497 /* This selection is based on an implementation of ftruncate by 1498 kucharsk@Solbourne.com (William Kucharski). */ 1499 { 1500 struct flock fl; 1501 1502 fl.l_whence = 0; 1503 fl.l_len = 0; 1504 fl.l_start = 0; 1505 fl.l_type = F_WRLCK; 1506 1507 itrunc = fcntl (o, F_FREESP, &fl); 1508 } 1509 #endif 1510 1511 if (itrunc != 0) 1512 { 1513 #if HAVE_FTRUNCATE 1514 ulog (LOG_ERROR, "ftruncate: %s", strerror (errno)); 1515 #endif 1516 #ifdef HAVE_LTRUNC 1517 ulog (LOG_ERROR, "ltrunc: %s", strerror (errno)); 1518 #endif 1519 #ifdef HAVE_F_CHSIZE 1520 ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno)); 1521 #endif 1522 #ifdef HAVE_F_FREESP 1523 ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno)); 1524 #endif 1525 1526 (void) ffileclose (e); 1527 (void) remove (zname); 1528 return EFILECLOSED; 1529 } 1530 1531 return e; 1532 #else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC) */ 1533 (void) ffileclose (e); 1534 (void) remove (zname); 1535 1536 o = creat (zname, IPRIVATE_FILE_MODE); 1537 1538 if (o == -1) 1539 { 1540 ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno)); 1541 return EFILECLOSED; 1542 } 1543 1544 #if USE_STDIO 1545 e = fdopen (o, (char *) BINWRITE); 1546 1547 if (e == NULL) 1548 { 1549 ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno)); 1550 (void) close (o); 1551 (void) remove (zname); 1552 return NULL; 1553 } 1554 #else /* ! USE_STDIO */ 1555 e = o; 1556 #endif /* ! USE_STDIO */ 1557 1558 return e; 1559 #endif /* ! HAVE_FTRUNCATE */ 1560 } 1561 1562 /* Lock something. If the fspooldir argument is TRUE, the argument is 1563 a file name relative to the spool directory; otherwise the argument 1564 is a simple file name which should be created in the system lock 1565 directory (under BNU this is /etc/locks). */ 1566 1567 /*ARGSUSED*/ 1568 boolean 1569 fsdo_lock (zlock, fspooldir) 1570 const char *zlock; 1571 boolean fspooldir; 1572 { 1573 const char *zpath, *zslash; 1574 int cslash; 1575 char *ztempfile; 1576 char abtempfile[20]; 1577 int o; 1578 pid_t ime; 1579 #if HAVE_V2_LOCKFILES 1580 int i; 1581 #else 1582 char ab[12]; 1583 #endif 1584 int cwrote; 1585 const char *zerr; 1586 boolean fret; 1587 1588 #ifdef LOCKDIR 1589 if (fspooldir) 1590 zpath = zlock; 1591 else 1592 { 1593 char *zalc; 1594 1595 zalc = (char *) alloca (sizeof LOCKDIR + strlen (zlock) + 1); 1596 sprintf (zalc, "%s/%s", LOCKDIR, zlock); 1597 zpath = zalc; 1598 } 1599 #else /* ! defined (LOCKDIR) */ 1600 zpath = zlock; 1601 #endif 1602 1603 ime = getpid (); 1604 1605 /* We do the actual lock by creating a file and then linking it to 1606 the final file name we want. This avoids race conditions due to 1607 one process checking the file before we have finished writing it, 1608 and also works even if we are somehow running as root. 1609 1610 First, create the file in the right directory (we must create the 1611 file in the same directory since otherwise we might attempt a 1612 cross-device link). */ 1613 zslash = strrchr (zpath, '/'); 1614 if (zslash == NULL) 1615 cslash = 0; 1616 else 1617 cslash = zslash - zpath + 1; 1618 1619 ztempfile = (char *) alloca (cslash + sizeof "TMP1234567890"); 1620 strncpy (ztempfile, zpath, cslash); 1621 sprintf (abtempfile, "TMP%010d", (int) ime); 1622 ztempfile[cslash] = '\0'; 1623 strcat (ztempfile, abtempfile); 1624 1625 o = creat (ztempfile, IPUBLIC_FILE_MODE); 1626 if (o < 0) 1627 { 1628 if (errno == ENOENT) 1629 { 1630 if (! fsysdep_make_dirs (ztempfile, FALSE)) 1631 return FALSE; 1632 o = creat (ztempfile, IPUBLIC_FILE_MODE); 1633 } 1634 if (o < 0) 1635 { 1636 ulog (LOG_ERROR, "open (%s): %s", ztempfile, strerror (errno)); 1637 return FALSE; 1638 } 1639 } 1640 1641 #if HAVE_V2_LOCKFILES 1642 i = ime; 1643 cwrote = write (o, &i, sizeof i); 1644 #else 1645 sprintf (ab, "%10d\n", (int) ime); 1646 cwrote = write (o, ab, strlen (ab)); 1647 #endif 1648 1649 zerr = NULL; 1650 if (cwrote < 0) 1651 zerr = "write"; 1652 if (close (o) < 0) 1653 zerr = "close"; 1654 if (zerr != NULL) 1655 { 1656 ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno)); 1657 (void) remove (ztempfile); 1658 return FALSE; 1659 } 1660 1661 /* Now try to link the file we just created to the lock file that we 1662 want. If it fails, try reading the existing file to make sure 1663 the process that created it still exists. We do this in a loop 1664 to make it easy to retry if the old locking process no longer 1665 exists. */ 1666 1667 fret = TRUE; 1668 o = -1; 1669 zerr = NULL; 1670 1671 while (link (ztempfile, zpath) != 0) 1672 { 1673 int cgot; 1674 int ipid; 1675 1676 fret = FALSE; 1677 1678 if (errno != EEXIST) 1679 { 1680 ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath, 1681 strerror (errno)); 1682 break; 1683 } 1684 1685 o = open (zpath, O_RDWR, 0); 1686 if (o < 0) 1687 { 1688 zerr = "open"; 1689 break; 1690 } 1691 1692 /* The race starts here. See below for a discussion. */ 1693 1694 #if HAVE_V2_LOCKFILES 1695 cgot = read (o, &i, sizeof i); 1696 #else 1697 cgot = read (o, ab, sizeof ab - 1); 1698 #endif 1699 1700 if (cgot < 0) 1701 { 1702 zerr = "read"; 1703 break; 1704 } 1705 1706 #if HAVE_V2_LOCKFILES 1707 ipid = i; 1708 #else 1709 ab[cgot] = '\0'; 1710 ipid = atoi (ab); 1711 #endif 1712 1713 /* If the process still exists, we will get EPERM rather than 1714 ESRCH. We then return FALSE to indicate that we cannot make 1715 the lock. */ 1716 if (kill (ipid, 0) == 0 || errno == EPERM) 1717 break; 1718 1719 /* On NFS, the link might have actually succeeded even though we 1720 got a failure return. This can happen if the original 1721 acknowledgement was lost or delayed and the operation was 1722 retried. In this case the pid will be our own. This 1723 introduces a rather improbable race condition: if a stale 1724 lock was left with our process ID in it, and another process 1725 just did the above kill but has not yet changed the lock file 1726 to hold its own process ID, we could start up and make it all 1727 the way to here and think we have the lock. I'm not going to 1728 worry about this possibility. */ 1729 if (ipid == ime) 1730 { 1731 fret = TRUE; 1732 break; 1733 } 1734 1735 ulog (LOG_ERROR, "Found stale lock %s held by process %d", 1736 zpath, ipid); 1737 1738 /* This is a stale lock, created by a process that no longer 1739 exists. 1740 1741 Now we could remove the file, but that would be a race 1742 condition. If we were interrupted any time after we did the 1743 read until we did the remove, another process could get in, 1744 open the file, find that it was a stale lock, remove the file 1745 and create a new one. When we woke up we would remove the 1746 file the other process just created. 1747 1748 These files are being generated partially for the benefit of 1749 cu, and it would be nice to avoid the race however cu avoids 1750 it, so that the programs remain compatible. Unfortunately, 1751 nobody seems to know how cu avoids the race, or even if it 1752 tries to avoid it at all. 1753 1754 There are a few ways to avoid the race. We could use kernel 1755 locking primitives, but they may not be available. We could 1756 link to a special file name, but if that file were left lying 1757 around then no stale lock could ever be broken (Henry Spencer 1758 would think this was a good thing). 1759 1760 Instead I've implemented the following procedure: seek to the 1761 start of the file, write our pid into it, sleep for five 1762 seconds, and then make sure our pid is still there. Anybody 1763 who checks the file while we're asleep will find our pid 1764 there and fail the lock. The only race will come from 1765 another process which has done the read by the time we do our 1766 write. That process will then have five seconds to do its 1767 own write. When we wake up, we'll notice that our pid is no 1768 longer in the file, and retry the lock from the beginning. 1769 1770 This relies on the atomicity of write(2). If it possible for 1771 the writes of two processes to be interleaved, the two 1772 processes could livelock. POSIX unfortunately leaves this 1773 case explicitly undefined; however, given that the write is 1774 of less than a disk block, it's difficult to imagine an 1775 interleave occurring. 1776 1777 Note that this is still a race. If it takes the second 1778 process more than five seconds to do the kill, the lseek, and 1779 the write, both processes will think they have the lock. 1780 Perhaps the length of time to sleep should be configurable. 1781 Even better, perhaps I should add a configuration option to 1782 use a permanent lock file, which eliminates any race and 1783 forces the installer to be aware of the existence of the 1784 permanent lock file. 1785 1786 For the benefit of cu, we stat the file after the sleep, to 1787 make sure some cu program hasn't deleted it for us. */ 1788 1789 if (lseek (o, (off_t) 0, SEEK_SET) != 0) 1790 { 1791 zerr = "lseek"; 1792 break; 1793 } 1794 1795 #if HAVE_V2_LOCKFILES 1796 i = ime; 1797 cwrote = write (o, &i, sizeof i); 1798 #else 1799 sprintf (ab, "%10d\n", (int) ime); 1800 cwrote = write (o, ab, strlen (ab)); 1801 #endif 1802 1803 if (cwrote < 0) 1804 { 1805 zerr = "write"; 1806 break; 1807 } 1808 1809 (void) sleep (5); 1810 1811 if (lseek (o, (off_t) 0, SEEK_SET) != 0) 1812 { 1813 zerr = "lseek"; 1814 break; 1815 } 1816 1817 #if HAVE_V2_LOCKFILES 1818 cgot = read (o, &i, sizeof i); 1819 #else 1820 cgot = read (o, ab, sizeof ab - 1); 1821 #endif 1822 1823 if (cgot < 0) 1824 { 1825 zerr = "read"; 1826 break; 1827 } 1828 1829 #if HAVE_V2_LOCKFILES 1830 ipid = i; 1831 #else 1832 ab[cgot] = '\0'; 1833 ipid = atoi (ab); 1834 #endif 1835 1836 if (ipid == ime) 1837 { 1838 struct stat sfile, sdescriptor; 1839 1840 /* It looks like we have the lock. Do the final stat 1841 check. */ 1842 1843 if (stat (zpath, &sfile) != 0) 1844 { 1845 if (errno != ENOENT) 1846 { 1847 zerr = "stat"; 1848 break; 1849 } 1850 /* Loop around and try again. */ 1851 } 1852 else 1853 { 1854 if (fstat (o, &sdescriptor) < 0) 1855 { 1856 zerr = "fstat"; 1857 break; 1858 } 1859 1860 if (sfile.st_ino == sdescriptor.st_ino 1861 && sfile.st_dev == sdescriptor.st_dev) 1862 { 1863 /* Close the file before assuming we've succeeded to 1864 pick up any trailing errors. */ 1865 if (close (o) < 0) 1866 { 1867 zerr = "close"; 1868 break; 1869 } 1870 1871 o = -1; 1872 1873 /* We have the lock. */ 1874 fret = TRUE; 1875 break; 1876 } 1877 } 1878 } 1879 1880 /* Loop around and try the lock again. We keep doing this until 1881 the lock file holds a pid that exists. */ 1882 1883 (void) close (o); 1884 o = -1; 1885 fret = TRUE; 1886 } 1887 1888 if (zerr != NULL) 1889 ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno)); 1890 1891 if (o >= 0) 1892 (void) close (o); 1893 1894 /* It would be nice if we could leave the temporary file around for 1895 future calls, but considering that we create lock files in 1896 various different directories it's probably more trouble than 1897 it's worth. */ 1898 if (remove (ztempfile) != 0) 1899 ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno)); 1900 1901 return fret; 1902 } 1903 1904 /* Unlock something. The fspooldir argument is as in fsdo_lock. */ 1905 1906 boolean 1907 fsdo_unlock (zlock, fspooldir) 1908 const char *zlock; 1909 boolean fspooldir; 1910 { 1911 const char *zpath; 1912 1913 #ifdef LOCKDIR 1914 if (fspooldir) 1915 zpath = zlock; 1916 else 1917 { 1918 char *zalc; 1919 1920 zalc = (char *) alloca (sizeof LOCKDIR + strlen (zlock) + 1); 1921 sprintf (zalc, "%s/%s", LOCKDIR, zlock); 1922 zpath = zalc; 1923 } 1924 #else /* ! defined (LOCKDIR) */ 1925 zpath = zlock; 1926 #endif 1927 1928 if (remove (zpath) == 0 1929 || errno == ENOENT) 1930 return TRUE; 1931 else 1932 { 1933 ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno)); 1934 return FALSE; 1935 } 1936 } 1937 1938 /* Lock a remote system. */ 1939 1940 /*ARGSUSED*/ 1941 boolean 1942 fsysdep_lock_system (qsys) 1943 const struct ssysteminfo *qsys; 1944 { 1945 char *z; 1946 1947 z = (char *) alloca (strlen (qsys->zname) + sizeof "LCK.."); 1948 sprintf (z, "LCK..%.8s", qsys->zname); 1949 return fsdo_lock (z, FALSE); 1950 } 1951 1952 /* Unlock a remote system. */ 1953 1954 /*ARGSUSED*/ 1955 boolean 1956 fsysdep_unlock_system (qsys) 1957 const struct ssysteminfo *qsys; 1958 { 1959 char *z; 1960 1961 z = (char *) alloca (strlen (qsys->zname) + sizeof "LCK.."); 1962 sprintf (z, "LCK..%.8s", qsys->zname); 1963 return fsdo_unlock (z, FALSE); 1964 } 1965 1966 /* Get a new command sequence number (this is not a sequence number to 1967 be used for communicating with another system, but a sequence 1968 number to be used when generating the name of a command file). 1969 The sequence number is placed into zseq, which should be five 1970 characters long. */ 1971 1972 #define CSEQLEN (4) 1973 1974 static boolean 1975 fscmd_seq (zsystem, zseq) 1976 const char *zsystem; 1977 char *zseq; 1978 { 1979 int ctries; 1980 const char *zfile; 1981 int o; 1982 int i; 1983 1984 /* Lock the sequence file. This may not be correct for all systems, 1985 but it only matters if the system UUCP and this UUCP are running 1986 at the same time. */ 1987 1988 ctries = 0; 1989 while (! fsdo_lock ("LCK..SEQ", TRUE)) 1990 { 1991 ++ctries; 1992 if (ctries > 10) 1993 { 1994 ulog (LOG_ERROR, "Can't lock sequence file"); 1995 return FALSE; 1996 } 1997 sleep (1); 1998 } 1999 2000 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 | SPOOLDIR_BSD43 2001 zfile = "SEQF"; 2002 #endif 2003 #if SPOOLDIR_BNU 2004 { 2005 char *zalc; 2006 2007 zalc = (char *) alloca (strlen (zsystem) + sizeof ".Sequence/"); 2008 sprintf (zalc, ".Sequence/%s", zsystem); 2009 zfile = zalc; 2010 } 2011 #endif 2012 #if SPOOLDIR_ULTRIX 2013 if (fsultrix_has_spool (zsystem)) 2014 { 2015 char *zalc; 2016 2017 zalc = (char *) alloca (strlen (zsystem) + sizeof "sys//.SEQF"); 2018 sprintf (zalc, "sys/%s/.SEQF", zsystem); 2019 zfile = zalc; 2020 } 2021 else 2022 zfile = "sys/DEFAULT/.SEQF"; 2023 #endif /* SPOOLDIR_ULTRIX */ 2024 #if SPOOLDIR_TAYLOR 2025 { 2026 char *zalc; 2027 2028 zalc = (char *) alloca (strlen (zsystem) + sizeof "/SEQF"); 2029 sprintf (zalc, "%s/SEQF", zsystem); 2030 zfile = zalc; 2031 } 2032 #endif /* SPOOLDIR_TAYLOR */ 2033 2034 #ifdef O_CREAT 2035 o = open (zfile, O_RDWR | O_CREAT, IPUBLIC_FILE_MODE); 2036 #else 2037 o = open (zfile, O_RDWR); 2038 if (o < 0 && errno == ENOENT) 2039 { 2040 o = creat (zfile, IPUBLIC_FILE_MODE); 2041 if (o >= 0) 2042 { 2043 (void) close (o); 2044 o = open (zfile, O_RDWR); 2045 } 2046 } 2047 #endif 2048 2049 if (o < 0) 2050 { 2051 if (errno == ENOENT) 2052 { 2053 if (! fsysdep_make_dirs (zfile, FALSE)) 2054 { 2055 (void) fsdo_unlock ("LCK..SEQ", TRUE); 2056 return FALSE; 2057 } 2058 #ifdef O_CREAT 2059 o = open (zfile, O_RDWR | O_CREAT, IPUBLIC_FILE_MODE); 2060 #else 2061 o = creat (zfile, IPUBLIC_FILE_MODE); 2062 if (o >= 0) 2063 { 2064 (void) close (o); 2065 o = open (zfile, O_RDWR); 2066 } 2067 #endif 2068 } 2069 if (o < 0) 2070 { 2071 ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); 2072 (void) fsdo_unlock ("LCK..SEQ", TRUE); 2073 return FALSE; 2074 } 2075 } 2076 2077 if (read (o, zseq, CSEQLEN) != CSEQLEN) 2078 strcpy (zseq, "0000"); 2079 zseq[CSEQLEN] = '\0'; 2080 2081 /* We must add one to the sequence number and return the new value. 2082 On Ultrix, arbitrary characters are allowed in the sequence number. 2083 On other systems, the sequence number apparently must be in hex. */ 2084 2085 #if SPOOLDIR_V2 | SPOOLDIR_BSD42 | SPOOLDIR_BSD43 | SPOOLDIR_BNU 2086 i = strtol (zseq, (char **) NULL, 16); 2087 ++i; 2088 if (i > 0xffff) 2089 i = 0; 2090 /* The sprintf argument has CSEQLEN built into it. */ 2091 sprintf (zseq, "%04x", (unsigned int) i); 2092 #endif /* SPOOLDIR_V2 | SPOOLDIR_BSD42 | SPOOLDIR_BSD43 | SPOOLDIR_BNU */ 2093 #if SPOOLDIR_ULTRIX | SPOOLDIR_TAYLOR 2094 for (i = CSEQLEN - 1; i >= 0; i--) 2095 { 2096 if (zseq[i] == 'z') 2097 { 2098 zseq[i] = '0'; 2099 continue; 2100 } 2101 2102 if (zseq[i] == '9') 2103 zseq[i] = 'A'; 2104 else if (zseq[i] == 'Z') 2105 zseq[i] = 'a'; 2106 else if ((zseq[i] >= '0' && zseq[i] < '9') 2107 || (zseq[i] >= 'A' && zseq[i] < 'Z') 2108 || (zseq[i] >= 'a' && zseq[i] < 'z')) 2109 ++zseq[i]; 2110 else 2111 { 2112 /* A bad character was found; reset the entire sequence 2113 number. */ 2114 ulog (LOG_ERROR, 2115 "Bad sequence number %s for system %s", 2116 zseq, zsystem); 2117 strcpy (zseq, "0000"); 2118 } 2119 2120 break; 2121 } 2122 #endif /* SPOOLDIR_ULTRIX | SPOOLDIR_TAYLOR */ 2123 2124 if (lseek (o, (off_t) 0, SEEK_SET) < 0 2125 || write (o, zseq, CSEQLEN) != CSEQLEN 2126 || close (o) < 0) 2127 { 2128 ulog (LOG_ERROR, "lseek or write or close: %s", strerror (errno)); 2129 (void) close (o); 2130 (void) fsdo_unlock ("LCK..SEQ", TRUE); 2131 return FALSE; 2132 } 2133 2134 (void) fsdo_unlock ("LCK..SEQ", TRUE); 2135 2136 return TRUE; 2137 } 2138 2139 /* Get the name of a command or data file for a remote system. The 2140 btype argument should be C for a command file or D for a data file. 2141 If the grade of a data file is X, it is assumed that this is going 2142 to become an execute file on some other system. The zsystem 2143 argument is the system that the file will be transferred to. The 2144 ztname argument will be set to a file name that could be passed to 2145 zsysdep_spool_file_name. The zdname argument, if not NULL, will be 2146 set to a data file name appropriate for the remote system. The 2147 zxname argument, if not NULL, will be set to the name of an execute 2148 file on the remote system. None of the names will be more than 14 2149 characters long. */ 2150 2151 static const char * 2152 zsfile_name (btype, zsystem, bgrade, ztname, zdname, zxname) 2153 int btype; 2154 const char *zsystem; 2155 int bgrade; 2156 char *ztname; 2157 char *zdname; 2158 char *zxname; 2159 { 2160 char abseq[CSEQLEN + 1]; 2161 char absimple[11 + CSEQLEN]; 2162 const char *zname; 2163 struct stat s; 2164 2165 do 2166 { 2167 if (! fscmd_seq (zsystem, abseq)) 2168 return NULL; 2169 2170 if (btype == 'C') 2171 { 2172 #if ! SPOOLDIR_TAYLOR 2173 sprintf (absimple, "C.%.7s%c%s", zsystem, bgrade, abseq); 2174 #else 2175 sprintf (absimple, "C.%c%s", bgrade, abseq); 2176 #endif 2177 } 2178 else if (btype == 'D') 2179 { 2180 #if ! SPOOLDIR_TAYLOR 2181 /* Note that a data file uses the local system's name. */ 2182 sprintf (absimple, "D.%.7s%c%s", zLocalname, bgrade, abseq); 2183 #else 2184 if (bgrade == 'X') 2185 sprintf (absimple, "D.X%s", abseq); 2186 else 2187 sprintf (absimple, "D.%s", abseq); 2188 #endif 2189 } 2190 #if DEBUG > 0 2191 else 2192 ulog (LOG_FATAL, "zsfile_name: Can't happen (%d)", btype); 2193 #endif 2194 2195 zname = zsfind_file (absimple, zsystem); 2196 if (zname == NULL) 2197 return NULL; 2198 } 2199 while (stat (zname, &s) == 0); 2200 2201 if (ztname != NULL) 2202 strcpy (ztname, absimple); 2203 2204 if (zdname != NULL) 2205 sprintf (zdname, "D.%.7s%c%s", zLocalname, bgrade, abseq); 2206 2207 if (zxname != NULL) 2208 sprintf (zxname, "X.%.7s%c%s", zLocalname, bgrade, abseq); 2209 2210 return zname; 2211 } 2212 2213 /* Given a set of commands to execute for a remote system, create a 2214 command file holding them. This creates a single command file 2215 holding all the commands passed in. It returns a jobid. */ 2216 2217 const char * 2218 zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds) 2219 const struct ssysteminfo *qsys; 2220 int bgrade; 2221 int ccmds; 2222 const struct scmd *pascmds; 2223 { 2224 const char *z; 2225 FILE *e; 2226 int i; 2227 const struct scmd *q; 2228 const char *zjobid; 2229 2230 #if DEBUG > 0 2231 if (! FGRADE_LEGAL (bgrade)) 2232 ulog (LOG_FATAL, "Bad grade %d", bgrade); 2233 #endif 2234 2235 z = zsfile_name ('C', qsys->zname, bgrade, (char *) NULL, (char *) NULL, 2236 (char *) NULL); 2237 if (z == NULL) 2238 return NULL; 2239 2240 e = esysdep_fopen (z, FALSE, FALSE, TRUE); 2241 if (e == NULL) 2242 return NULL; 2243 2244 for (i = 0, q = pascmds; i < ccmds; i++, q++) 2245 { 2246 switch (q->bcmd) 2247 { 2248 case 'S': 2249 fprintf (e, "S %s %s %s -%s %s 0%o %s\n", q->zfrom, q->zto, 2250 q->zuser, q->zoptions, q->ztemp, q->imode, 2251 q->znotify); 2252 break; 2253 case 'R': 2254 fprintf (e, "R %s %s %s -%s\n", q->zfrom, q->zto, q->zuser, 2255 q->zoptions); 2256 break; 2257 case 'X': 2258 fprintf (e, "X %s %s %s -%s\n", q->zfrom, q->zto, q->zuser, 2259 q->zoptions); 2260 break; 2261 default: 2262 ulog (LOG_ERROR, 2263 "zsysdep_spool_commands: Unrecognized type %d", 2264 q->bcmd); 2265 (void) fclose (e); 2266 (void) remove (z); 2267 return NULL; 2268 } 2269 } 2270 2271 if (fclose (e) != 0) 2272 { 2273 ulog (LOG_ERROR, "fclose: %s", strerror (errno)); 2274 (void) remove (z); 2275 return NULL; 2276 } 2277 2278 zjobid = zsfile_to_jobid (qsys, z); 2279 if (zjobid == NULL) 2280 (void) remove (z); 2281 return zjobid; 2282 } 2283 2284 /* Return a name to use for a data file to be copied to another 2285 system. The name returned will be for a real file. The ztname 2286 argument, if not NULL, will be set to a name that could be passed 2287 to zsysdep_spool_file_name to get back the return value of this 2288 function. The zdname argument, if not NULL, will be set to a name 2289 that the file could be given on another system. The zxname 2290 argument, if not NULL, will be set to a name for an execute file on 2291 another system. */ 2292 2293 const char * 2294 zsysdep_data_file_name (qsys, bgrade, ztname, zdname, zxname) 2295 const struct ssysteminfo *qsys; 2296 int bgrade; 2297 char *ztname; 2298 char *zdname; 2299 char *zxname; 2300 { 2301 return zsfile_name ('D', qsys->zname, bgrade, ztname, zdname, zxname); 2302 } 2303 2304 /* Return a name for an execute file to be created locally. This is 2305 used by uux to execute a command locally with remote files. */ 2306 2307 const char * 2308 zsysdep_xqt_file_name () 2309 { 2310 char abseq[CSEQLEN + 1]; 2311 char absx[11 + CSEQLEN]; 2312 const char *zname; 2313 struct stat s; 2314 2315 while (TRUE) 2316 { 2317 if (! fscmd_seq (zLocalname, abseq)) 2318 return NULL; 2319 2320 sprintf (absx, "X.%.7sX%s", zLocalname, abseq); 2321 2322 zname = zsfind_file (absx, zLocalname); 2323 if (zname == NULL) 2324 return NULL; 2325 if (stat (zname, &s) != 0) 2326 break; 2327 } 2328 2329 return zname; 2330 } 2331 2332 /* Start getting a wildcarded file spec. We use the shell to expand 2333 the wildcard. */ 2334 2335 static char *zSwildcard_alloc; 2336 static char *zSwildcard; 2337 2338 boolean 2339 fsysdep_wildcard_start (qsys, zfile) 2340 const struct ssysteminfo *qsys; 2341 const char *zfile; 2342 { 2343 char *zcmd; 2344 const char *azargs[4]; 2345 FILE *e; 2346 pid_t ipid; 2347 2348 zSwildcard_alloc = NULL; 2349 zSwildcard = NULL; 2350 2351 if (*zfile == '~') 2352 { 2353 zfile = zstilde_expand (qsys, zfile); 2354 if (zfile == NULL) 2355 return FALSE; 2356 } 2357 2358 if (*zfile != '/') 2359 { 2360 ulog (LOG_ERROR, "Relative path not permitted in wildcard"); 2361 return FALSE; 2362 } 2363 2364 zcmd = (char *) alloca (sizeof ECHO_PROGRAM + sizeof " " + strlen (zfile)); 2365 sprintf (zcmd, "%s %s", ECHO_PROGRAM, zfile); 2366 2367 azargs[0] = "/bin/sh"; 2368 azargs[1] = "-c"; 2369 azargs[2] = zcmd; 2370 azargs[3] = NULL; 2371 2372 e = espopen (azargs, TRUE, &ipid); 2373 if (e == NULL) 2374 { 2375 ulog (LOG_ERROR, "espopen: %s", strerror (errno)); 2376 return FALSE; 2377 } 2378 2379 zSwildcard_alloc = zfgets (e, FALSE); 2380 2381 if (iswait ((unsigned long) ipid, ECHO_PROGRAM) != 0) 2382 { 2383 xfree ((pointer) zSwildcard_alloc); 2384 return FALSE; 2385 } 2386 2387 if (zSwildcard_alloc == NULL) 2388 return FALSE; 2389 2390 DEBUG_MESSAGE1 (DEBUG_EXECUTE, 2391 "fsysdep_wildcard_start: got \"%s\"", 2392 zSwildcard_alloc); 2393 2394 zSwildcard = zSwildcard_alloc; 2395 2396 return TRUE; 2397 } 2398 2399 /* Get the next wildcard spec. */ 2400 2401 /*ARGSUSED*/ 2402 const char * 2403 zsysdep_wildcard (qsys, zfile) 2404 const struct ssysteminfo *qsys; 2405 const char *zfile; 2406 { 2407 char *zret; 2408 2409 if (zSwildcard_alloc == NULL || zSwildcard == NULL) 2410 return NULL; 2411 2412 zret = zSwildcard; 2413 2414 while (*zSwildcard != '\0' && ! isspace (BUCHAR (*zSwildcard))) 2415 ++zSwildcard; 2416 2417 if (*zSwildcard == '\0') 2418 zSwildcard = NULL; 2419 else 2420 { 2421 *zSwildcard = '\0'; 2422 ++zSwildcard; 2423 while (*zSwildcard != '\0' && isspace (BUCHAR (*zSwildcard))) 2424 ++zSwildcard; 2425 if (*zSwildcard == '\0') 2426 zSwildcard = NULL; 2427 } 2428 2429 return zret; 2430 } 2431 2432 /* Finish up getting wildcard specs. */ 2433 2434 boolean 2435 fsysdep_wildcard_end () 2436 { 2437 xfree ((pointer) zSwildcard_alloc); 2438 zSwildcard_alloc = NULL; 2439 zSwildcard = NULL; 2440 return TRUE; 2441 } 2442 2443 /* Get the current conversation sequence number for a remote system, 2444 and increment it for next time. The conversation sequence number 2445 is kept in a file named .SQ in the spool directory for that system. 2446 This is not compatible with other versions of UUCP, but it makes 2447 more sense to me. The sequence file is only used if specified in 2448 the information for that system. In V2, the file 2449 /usr/lib/uucp/SQFILE is searched for each system to get a 2450 conversation sequence number. */ 2451 2452 long 2453 isysdep_get_sequence (qsys) 2454 const struct ssysteminfo *qsys; 2455 { 2456 FILE *e; 2457 const char *zname; 2458 struct stat s; 2459 long iseq; 2460 2461 /* This will only be called when the system is locked anyhow, so there 2462 is no need to use a separate lock for the conversation sequence 2463 file. */ 2464 2465 zname = zsappend (".Sequence", qsys->zname); 2466 2467 iseq = 0; 2468 if (stat (zname, &s) == 0) 2469 { 2470 boolean fok; 2471 char *zline; 2472 2473 /* The file should only be readable and writable by uucp. */ 2474 2475 if ((s.st_mode & (S_IRWXG | S_IRWXO)) != 0) 2476 { 2477 ulog (LOG_ERROR, 2478 "Bad file protection for conversation sequence file"); 2479 return -1; 2480 } 2481 2482 /* The file already exists, so we don't have to worry about 2483 its protection. */ 2484 e = fopen (zname, "r+"); 2485 if (e == NULL) 2486 { 2487 ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); 2488 return -1; 2489 } 2490 2491 zline = zfgets (e, FALSE); 2492 2493 fok = TRUE; 2494 if (zline == NULL) 2495 fok = FALSE; 2496 else 2497 { 2498 char *zend; 2499 2500 iseq = strtol (zline, &zend, 10); 2501 if (zend == zline) 2502 fok = FALSE; 2503 xfree ((pointer) zline); 2504 } 2505 2506 if (! fok) 2507 { 2508 ulog (LOG_ERROR, "Bad format for conversation sequence file"); 2509 return -1; 2510 } 2511 2512 rewind (e); 2513 } 2514 else 2515 { 2516 e = esysdep_fopen (zname, FALSE, FALSE, TRUE); 2517 if (e == NULL) 2518 return -1; 2519 } 2520 2521 ++iseq; 2522 2523 fprintf (e, "%ld", iseq); 2524 2525 if (fclose (e) != 0) 2526 { 2527 ulog (LOG_ERROR, "fclose: %s", strerror (errno)); 2528 return -1; 2529 } 2530 2531 return iseq; 2532 } 2533 2534 /* Get the Unix file mode of a file. */ 2535 2536 unsigned int 2537 isysdep_file_mode (zfile) 2538 const char *zfile; 2539 { 2540 struct stat s; 2541 2542 if (stat (zfile, &s) != 0) 2543 { 2544 ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); 2545 return 0; 2546 } 2547 2548 #if S_IRWXU != 0700 2549 #error Files modes need to be translated 2550 #endif 2551 2552 /* We can't return 0, since that indicate an error. */ 2553 if ((s.st_mode & 0777) == 0) 2554 return 0400; 2555 2556 return s.st_mode & 0777; 2557 } 2558 2559 /* Translate a file name and an associated system into a job id. 2560 These job ids are used by uustat. We use the system name attached 2561 to the grade and sequence number. */ 2562 2563 const char * 2564 zsfile_to_jobid (qsys, zfile) 2565 const struct ssysteminfo *qsys; 2566 const char *zfile; 2567 { 2568 char *zid; 2569 2570 zid = (char *) alloca (strlen (qsys->zname) + CSEQLEN + 2); 2571 sprintf (zid, "%s%s", qsys->zname, 2572 zfile + strlen (zfile) - CSEQLEN - 1); 2573 2574 return zscopy (zid); 2575 } 2576 2577 /* Turn a job id back into a file name. */ 2578 2579 const char * 2580 zsjobid_to_file (zid, pzsystem) 2581 const char *zid; 2582 const char **pzsystem; 2583 { 2584 int clen; 2585 char abend[CSEQLEN + 2]; 2586 static char *zsys; 2587 static int csyslen; 2588 char abname[CSEQLEN + 11]; 2589 2590 clen = strlen (zid); 2591 strcpy (abend, zid + clen - CSEQLEN - 1); 2592 2593 if (clen - CSEQLEN > csyslen) 2594 { 2595 zsys = (char *) xrealloc ((pointer) zsys, clen - CSEQLEN); 2596 csyslen = clen - CSEQLEN; 2597 } 2598 2599 strncpy (zsys, zid, clen - CSEQLEN - 1); 2600 zsys[clen - CSEQLEN - 1] = '\0'; 2601 if (pzsystem != NULL) 2602 *pzsystem = zsys; 2603 2604 /* This must correspond to zsfile_name. */ 2605 #if ! SPOOLDIR_TAYLOR 2606 sprintf (abname, "C.%.7s%s", zsys, abend); 2607 #else 2608 sprintf (abname, "C.%s", abend); 2609 #endif 2610 2611 return zsfind_file (abname, zsys); 2612 } 2613 2614 #if ! HAVE_RENAME 2615 2616 /* This is currently the only file which calls rename, so I've put my 2617 fake rename function in here. */ 2618 2619 static int 2620 rename (zfrom, zto) 2621 const char *zfrom; 2622 const char *zto; 2623 { 2624 /* Try to make the link without removing the old file first. */ 2625 if (link (zfrom, zto) == -1) 2626 { 2627 if (errno != EEXIST) 2628 return -1; 2629 2630 /* Assume that this will never be called with zfrom the same as 2631 zto. If it could be, this is wrong. */ 2632 (void) remove (zto); 2633 2634 if (link (zfrom, zto) == -1) 2635 return -1; 2636 } 2637 2638 return remove (zfrom); 2639 } 2640 2641 #endif /* ! HAVE_RENAME */ 2642 2643 /* 2644 Local variables: 2645 mode:c 2646 End: 2647 */ 2648