1219019Sgabor/* Handle so called `shell archives'. 2219019Sgabor Copyright (C) 1994, 1995 Free Software Foundation, Inc. 3219019Sgabor 4219019Sgabor This program is free software; you can redistribute it and/or modify 5219019Sgabor it under the terms of the GNU General Public License as published by 6219019Sgabor the Free Software Foundation; either version 2, or (at your option) 7219019Sgabor any later version. 8219019Sgabor 9219019Sgabor This program is distributed in the hope that it will be useful, 10219019Sgabor but WITHOUT ANY WARRANTY; without even the implied warranty of 11219019Sgabor MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12219019Sgabor GNU General Public License for more details. 13219019Sgabor 14219019Sgabor You should have received a copy of the GNU General Public License 15219019Sgabor along with this program; if not, write to the Free Software Foundation, 16219019Sgabor Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17219019Sgabor*/ 18219019Sgabor 19219019Sgabor#include "system.h" 20219019Sgabor 21219019Sgaborstatic const char *cut_mark_line 22219019Sgabor = "---- Cut Here and feed the following to sh ----\n"; 23219019Sgabor 24219019Sgabor/* Delimiter to put after each file. */ 25219019Sgabor#define DEFAULT_HERE_DELIMITER "SHAR_EOF" 26219019Sgabor 27219019Sgabor/* Character which goes in front of each line. */ 28219019Sgabor#define DEFAULT_LINE_PREFIX_1 'X' 29219019Sgabor 30219019Sgabor/* Character which goes in front of each line if here_delimiter[0] == 31219019Sgabor DEFAULT_LINE_PREFIX_1. */ 32219019Sgabor#define DEFAULT_LINE_PREFIX_2 'Y' 33219019Sgabor 34219019Sgabor/* Shell command able to count characters from its standard input. We 35219019Sgabor have to take care for the locale setting because wc in multi-byte 36219019Sgabor character environments get different results. */ 37219019Sgabor#define CHARACTER_COUNT_COMMAND "LC_ALL= LC_CTYPE= LANG= wc -c <" 38219019Sgabor 39219019Sgabor/* Command computing MD5 sumof specified file. Because there is not 40219019Sgabor official standard for this we have to restrict ourself to a few 41219019Sgabor versions: GNU md5sum from GNU fileutils and the version by 42219019Sgabor Plumb/Lankester. */ 43219019Sgabor#define MD5SUM_COMMAND "md5sum" 44219019Sgabor 45219019Sgabor/* Maximum length for a text line before it is considered binary. */ 46219019Sgabor#define MAXIMUM_NON_BINARY_LINE 200 47219019Sgabor 48219019Sgabor/* System related declarations. */ 49219019Sgabor 50219019Sgabor#include <ctype.h> 51219019Sgabor 52219019Sgabor#if STDC_HEADERS 53219019Sgabor# define ISASCII(Char) 1 54219019Sgabor#else 55219019Sgabor# ifdef isascii 56219019Sgabor# define ISASCII(Char) isascii (Char) 57219019Sgabor# else 58219019Sgabor# if HAVE_ISASCII 59219019Sgabor# define ISASCII(Char) isascii (Char) 60219019Sgabor# else 61219019Sgabor# define ISASCII(Char) ((Char) & 0x7f == (unsigned char) (Char)) 62219019Sgabor# endif 63219019Sgabor# endif 64219019Sgabor#endif 65219019Sgabor 66219019Sgabor#include <time.h> 67219019Sgabor 68219019Sgaborstruct tm *localtime (); 69219019Sgabor 70219019Sgabor#if !NO_WALKTREE 71219019Sgabor 72219019Sgabor/* Declare directory reading routines and structures. */ 73219019Sgabor 74219019Sgabor#ifdef __MSDOS__ 75219019Sgabor# include "msd_dir.h" 76219019Sgabor# define NAMLEN(dirent) ((dirent)->d_namlen) 77219019Sgabor#else 78219019Sgabor# if HAVE_DIRENT_H 79219019Sgabor# include <dirent.h> 80219019Sgabor# define NAMLEN(dirent) (strlen((dirent)->d_name)) 81219019Sgabor# else 82219019Sgabor# define dirent direct 83219019Sgabor# define NAMLEN(dirent) ((dirent)->d_namlen) 84219019Sgabor# if HAVE_SYS_NDIR_H 85219019Sgabor# include <sys/ndir.h> 86219019Sgabor# endif 87219019Sgabor# if HAVE_SYS_DIR_H 88219019Sgabor# include <sys/dir.h> 89219019Sgabor# endif 90219019Sgabor# if HAVE_NDIR_H 91219019Sgabor# include <ndir.h> 92219019Sgabor# endif 93219019Sgabor# endif 94219019Sgabor#endif 95219019Sgabor 96219019SgaborDIR *opendir (); 97219019Sgaborstruct dirent *readdir (); 98219019Sgabor 99219019Sgabor#endif /* !NO_WALKTREE */ 100219019Sgabor 101219019Sgabor/* Option variables. */ 102219019Sgabor 103219019Sgabor#include "getopt.h" 104219019Sgabor#include "md5.h" 105219019Sgabor 106219019Sgabor/* No Brown-Shirt mode. */ 107219019Sgaborstatic int vanilla_operation_mode = 0; 108219019Sgabor 109219019Sgabor/* Mixed text and binary files. */ 110219019Sgaborstatic int mixed_uuencoded_file_mode = -1; 111219019Sgabor 112219019Sgabor/* Flag for binary files. */ 113219019Sgaborstatic int uuencoded_file_mode = -1; 114219019Sgabor 115219019Sgabor/* Run input files through gzip (requires uuencoded_file_mode). */ 116219019Sgaborstatic int gzipped_file_mode = -1; 117219019Sgabor 118219019Sgabor/* -N option to gzip. */ 119219019Sgaborstatic int gzip_compression_level = 9; 120219019Sgabor 121219019Sgabor/* Run input files through compress (requires uuencoded_file_mode). */ 122219019Sgaborstatic int compressed_file_mode = -1; 123219019Sgabor 124219019Sgabor/* -bN option to compress */ 125219019Sgaborstatic int bits_per_compressed_byte = 12; 126219019Sgabor 127219019Sgabor/* Generate $shar_touch commands. */ 128219019Sgaborstatic int timestamp_mode = 1; 129219019Sgabor 130219019Sgabor/* Option to provide wc checking. */ 131219019Sgaborstatic int character_count_mode = 1; 132219019Sgabor 133219019Sgabor/* Option to provide MD5 sum checking. */ 134219019Sgaborstatic int md5_count_mode = 1; 135219019Sgabor 136219019Sgabor/* Use temp file instead of pipe to feed uudecode. This gives better 137219019Sgabor error detection, at expense of disk space. This is also necessary for 138219019Sgabor those versions of uudecode unwilling to read their standard input. */ 139219019Sgaborstatic int inhibit_piping_mode = 0; 140219019Sgabor 141219019Sgabor/* --no-i18n option to prevent internationalized shell archives. */ 142219019Sgaborstatic int no_i18n; 143219019Sgabor 144219019Sgabor/* Character to get at the beginning of each line. */ 145219019Sgaborstatic int line_prefix; 146219019Sgabor 147219019Sgabor/* Option to generate "Archive-name:" headers. */ 148219019Sgaborstatic int net_headers_mode = 0; 149219019Sgabor 150219019Sgabor/* Documentation name for archive. */ 151219019Sgaborstatic char *archive_name = NULL; 152219019Sgabor 153219019Sgabor/* Option to provide append feedback at shar time. */ 154219019Sgaborstatic int quiet_mode = 0; 155219019Sgabor 156219019Sgabor/* Option to provide extract feedback at unshar time. */ 157219019Sgaborstatic int quiet_unshar_mode = 0; 158219019Sgabor 159219019Sgabor/* Pointer to delimiter string. */ 160219019Sgaborstatic const char *here_delimiter = DEFAULT_HERE_DELIMITER; 161219019Sgabor 162219019Sgabor/* Value of strlen (here_delimiter). */ 163219019Sgaborstatic size_t here_delimiter_length; 164219019Sgabor 165219019Sgabor/* Use line_prefix even when first char does not force it. */ 166219019Sgaborstatic int mandatory_prefix_mode = 0; 167219019Sgabor 168219019Sgabor/* Option to provide cut mark. */ 169219019Sgaborstatic int cut_mark_mode = 0; 170219019Sgabor 171219019Sgabor/* Check if file exists. */ 172219019Sgaborstatic int check_existing_mode = 1; 173219019Sgabor 174219019Sgabor/* Interactive overwrite. */ 175219019Sgaborstatic int query_user_mode = 0; 176219019Sgabor 177219019Sgabor/* Allow positional parameters. */ 178219019Sgaborstatic int intermixed_parameter_mode = 0; 179219019Sgabor 180219019Sgabor/* Strip directories from filenames. */ 181219019Sgaborstatic int basename_mode; 182219019Sgabor 183219019Sgabor/* Switch for debugging on. */ 184219019Sgabor#if DEBUG 185219019Sgaborstatic int debugging_mode = 0; 186219019Sgabor#endif 187219019Sgabor 188219019Sgabor/* Split files in the middle. */ 189219019Sgaborstatic int split_file_mode = 0; 190219019Sgabor 191219019Sgabor/* File size limit in kilobytes. */ 192219019Sgaborstatic unsigned file_size_limit = 0; 193219019Sgabor 194219019Sgabor/* Other global variables. */ 195219019Sgabor 196219019Sgabor/* The name this program was run with. */ 197219019Sgaborconst char *program_name; 198219019Sgabor 199219019Sgabor/* If non-zero, display usage information and exit. */ 200219019Sgaborstatic int show_help = 0; 201219019Sgabor 202219019Sgabor/* If non-zero, print the version on standard output and exit. */ 203219019Sgaborstatic int show_version = 0; 204219019Sgabor 205219019Sgabor/* File onto which the shar script is being written. */ 206219019Sgaborstatic FILE *output = NULL; 207219019Sgabor 208219019Sgabor/* Position for archive type message. */ 209219019Sgaborstatic off_t archive_type_position; 210219019Sgabor 211219019Sgabor/* Position for first file in the shar file. */ 212219019Sgaborstatic long first_file_position; 213219019Sgabor 214219019Sgabor/* Base for output filename. FIXME: No fix limit in GNU... */ 215219019Sgaborstatic char output_base_name[50]; 216219019Sgabor 217219019Sgabor/* Actual output filename. FIXME: No fix limit in GNU... */ 218219019Sgaborstatic char output_filename[50]; 219219019Sgabor 220219019Sgaborstatic char *submitter_address = NULL; 221219019Sgabor 222219019Sgabor/* Output file ordinal. FIXME: also flag for -o. */ 223219019Sgaborstatic int part_number = 0; 224219019Sgabor 225219019Sgabor/* Table saying whether each character is binary or not. */ 226219019Sgaborstatic unsigned char byte_is_binary[256]; 227219019Sgabor 228219019Sgabor/* For checking file type and access modes. */ 229219019Sgaborstatic struct stat struct_stat; 230219019Sgabor 231219019Sgabor/* Nonzero if special NLS option (--print-text-domain-dir) is selected. */ 232219019Sgaborstatic int print_text_dom_dir; 233219019Sgabor 234219019Sgabor/* The number used to make the intermediate files unique. */ 235219019Sgaborstatic int sharpid; 236219019Sgabor 237219019Sgabor#if DEBUG 238219019Sgabor# define DEBUG_PRINT(Format, Value) \ 239219019Sgabor if (debugging_mode) printf(Format, Value) 240219019Sgabor#else 241219019Sgabor# define DEBUG_PRINT(Format, Value) 242219019Sgabor#endif 243219019Sgabor 244219019Sgaborstatic void open_output __P ((void)); 245219019Sgaborstatic void close_output __P ((void)); 246219019Sgaborstatic void usage __P ((int)); 247219019Sgabor 248219019Sgabor/* Walking tree routines. */ 249219019Sgabor 250219019Sgabor/* Define a type just for easing ansi2knr's life. */ 251219019Sgabortypedef int (*walker_t) __P ((const char *, const char *)); 252219019Sgabor 253219019Sgabor#if !NO_WALKTREE 254219019Sgabor 255219019Sgabor/*--------------------------------------------------------------------------. 256219019Sgabor| Recursively call ROUTINE on each entry, down the directory tree. NAME | 257219019Sgabor| is the path to explore. RESTORE_NAME is the name that will be later | 258219019Sgabor| relative to the unsharing directory. ROUTINE may also assume | 259219019Sgabor| struct_stat is set, it accepts updated values for NAME and RESTORE_NAME. | 260219019Sgabor`--------------------------------------------------------------------------*/ 261219019Sgabor 262219019Sgaborstatic int 263219019Sgaborwalkdown (routine, local_name, restore_name) 264219019Sgabor walker_t routine; 265219019Sgabor const char *local_name; 266219019Sgabor const char *restore_name; 267219019Sgabor{ 268219019Sgabor DIR *directory; /* directory being scanned */ 269219019Sgabor struct dirent *entry; /* current entry in directory */ 270219019Sgabor int status; /* status to return */ 271219019Sgabor 272219019Sgabor char *local_name_copy; /* writeable copy of local_name */ 273219019Sgabor size_t local_name_length; /* number of characters in local_name_copy */ 274219019Sgabor size_t sizeof_local_name; /* allocated size of local_name_copy */ 275219019Sgabor 276219019Sgabor char *restore_name_copy; /* writeable copy of restore_name */ 277219019Sgabor size_t restore_name_length; /* number of characters in restore_name_copy */ 278219019Sgabor size_t sizeof_restore_name; /* allocated size of restore_name_copy */ 279219019Sgabor 280219019Sgabor if (stat (local_name, &struct_stat)) 281219019Sgabor { 282219019Sgabor error (0, errno, local_name); 283219019Sgabor return 1; 284219019Sgabor } 285219019Sgabor 286219019Sgabor if (!S_ISDIR (struct_stat.st_mode & S_IFMT)) 287219019Sgabor return (*routine) (local_name, restore_name); 288219019Sgabor 289219019Sgabor if (directory = opendir (local_name), !directory) 290219019Sgabor { 291219019Sgabor error (0, errno, local_name); 292219019Sgabor return 1; 293219019Sgabor } 294219019Sgabor 295219019Sgabor status = 0; 296219019Sgabor 297219019Sgabor local_name_copy = xstrdup (local_name); 298219019Sgabor local_name_length = strlen (local_name_copy); 299219019Sgabor sizeof_local_name = local_name_length + 1; 300219019Sgabor 301219019Sgabor restore_name_copy = xstrdup (restore_name); 302219019Sgabor restore_name_length = strlen (restore_name_copy); 303219019Sgabor sizeof_restore_name = restore_name_length + 1; 304219019Sgabor 305219019Sgabor while (!status && (entry = readdir (directory), entry)) 306219019Sgabor if (strcmp (entry->d_name, ".") && strcmp (entry->d_name, "..")) 307219019Sgabor { 308219019Sgabor int added_size = 1 + NAMLEN (entry); 309219019Sgabor 310219019Sgabor /* Update file names, reallocating them as required. */ 311219019Sgabor 312219019Sgabor if (local_name_length + added_size + 1 > sizeof_local_name) 313219019Sgabor { 314219019Sgabor sizeof_local_name = local_name_length + added_size + 1; 315219019Sgabor local_name_copy = (char *) 316219019Sgabor xrealloc (local_name_copy, sizeof_local_name); 317219019Sgabor } 318219019Sgabor sprintf (local_name_copy + local_name_length, "/%s", entry->d_name); 319219019Sgabor 320219019Sgabor if (restore_name_length + added_size + 1 > sizeof_restore_name) 321219019Sgabor { 322219019Sgabor sizeof_restore_name = restore_name_length + added_size + 1; 323219019Sgabor restore_name_copy = (char *) 324219019Sgabor xrealloc (restore_name_copy, sizeof_restore_name); 325219019Sgabor } 326219019Sgabor sprintf (restore_name_copy + restore_name_length, "/%s", 327219019Sgabor entry->d_name); 328219019Sgabor 329219019Sgabor /* Avoid restoring `./xxx' when shar'ing `.'. */ 330219019Sgabor 331219019Sgabor if (!strncmp (restore_name, "./", 2)) 332219019Sgabor { 333219019Sgabor strcpy (restore_name_copy, restore_name_copy + 2); 334219019Sgabor restore_name_length -= 2; 335219019Sgabor } 336219019Sgabor 337219019Sgabor status = walkdown (routine, local_name_copy, restore_name_copy); 338219019Sgabor } 339219019Sgabor 340219019Sgabor /* Clean up. */ 341219019Sgabor 342219019Sgabor if (sizeof_local_name > 0) 343219019Sgabor free (local_name_copy); 344219019Sgabor if (sizeof_restore_name > 0) 345219019Sgabor free (restore_name_copy); 346219019Sgabor 347219019Sgabor#if CLOSEDIR_VOID 348219019Sgabor closedir (directory); 349219019Sgabor#else 350219019Sgabor if (closedir (directory)) 351219019Sgabor { 352219019Sgabor error (0, errno, local_name); 353219019Sgabor return 1; 354219019Sgabor } 355219019Sgabor#endif 356219019Sgabor 357219019Sgabor return status; 358219019Sgabor} 359219019Sgabor 360219019Sgabor#endif /* !NO_WALKTREE */ 361219019Sgabor 362219019Sgabor/*------------------------------------------------------------------. 363219019Sgabor| Walk through the directory tree, calling ROUTINE for each entry. | 364219019Sgabor| ROUTINE may also assume struct_stat is set. | 365219019Sgabor`------------------------------------------------------------------*/ 366219019Sgabor 367219019Sgaborstatic int 368219019Sgaborwalktree (routine, local_name) 369219019Sgabor walker_t routine; 370219019Sgabor const char *local_name; 371219019Sgabor{ 372219019Sgabor const char *restore_name; 373219019Sgabor char *local_name_copy; 374219019Sgabor char *cursor; 375219019Sgabor int status; 376219019Sgabor int len; 377219019Sgabor 378219019Sgabor /* Remove crumb at end. */ 379219019Sgabor 380219019Sgabor len = strlen (local_name); 381219019Sgabor local_name_copy = (char *) alloca (len + 1); 382219019Sgabor memcpy (local_name_copy, local_name, len + 1); 383219019Sgabor cursor = local_name_copy + len - 1; 384219019Sgabor while (*cursor == '/' && cursor > local_name_copy) 385219019Sgabor *cursor-- = '\0'; 386219019Sgabor 387219019Sgabor /* Remove crumb at beginning. */ 388219019Sgabor 389219019Sgabor if (basename_mode) 390219019Sgabor restore_name = basename (local_name_copy); 391219019Sgabor else if (!strncmp (local_name_copy, "./", 2)) 392219019Sgabor restore_name = local_name_copy + 2; 393219019Sgabor else 394219019Sgabor restore_name = local_name_copy; 395219019Sgabor 396219019Sgabor#if NO_WALKTREE 397219019Sgabor 398219019Sgabor /* Just act on current entry. */ 399219019Sgabor 400219019Sgabor status = stat (local_name_copy, &struct_stat); 401219019Sgabor if (status != 0) 402219019Sgabor error (0, errno, local_name_copy); 403219019Sgabor else 404219019Sgabor status = (*routine) (local_name_copy, restore_name); 405219019Sgabor 406219019Sgabor#else 407219019Sgabor 408219019Sgabor /* Walk recursively. */ 409219019Sgabor 410219019Sgabor status = walkdown (routine, local_name_copy, restore_name); 411219019Sgabor 412219019Sgabor#endif 413219019Sgabor 414219019Sgabor return status; 415219019Sgabor} 416219019Sgabor 417219019Sgabor/* Generating parts of shar file. */ 418219019Sgabor 419219019Sgabor/*---------------------------------------------------------------------. 420219019Sgabor| Build a `drwxrwxrwx' string corresponding to MODE into MODE_STRING. | 421219019Sgabor`---------------------------------------------------------------------*/ 422219019Sgabor 423219019Sgaborstatic char * 424219019Sgabormode_string (mode) 425219019Sgabor unsigned mode; 426219019Sgabor{ 427219019Sgabor static char result[12]; 428219019Sgabor 429219019Sgabor strcpy (result, "----------"); 430219019Sgabor 431219019Sgabor if (mode & 00400) 432219019Sgabor result[1] = 'r'; 433219019Sgabor if (mode & 00200) 434219019Sgabor result[2] = 'w'; 435219019Sgabor if (mode & 00100) 436219019Sgabor result[3] = 'x'; 437219019Sgabor if (mode & 04000) 438219019Sgabor result[3] = 's'; 439219019Sgabor if (mode & 00040) 440219019Sgabor result[4] = 'r'; 441219019Sgabor if (mode & 00020) 442219019Sgabor result[5] = 'w'; 443219019Sgabor if (mode & 00010) 444219019Sgabor result[6] = 'x'; 445219019Sgabor if (mode & 02000) 446219019Sgabor result[6] = 's'; 447219019Sgabor if (mode & 00004) 448219019Sgabor result[7] = 'r'; 449219019Sgabor if (mode & 00002) 450219019Sgabor result[8] = 'w'; 451219019Sgabor if (mode & 00001) 452219019Sgabor result[9] = 'x'; 453219019Sgabor 454219019Sgabor return result; 455219019Sgabor} 456219019Sgabor 457219019Sgabor/*-----------------------------------------------------------------------. 458219019Sgabor| Generate shell code which, at *unshar* time, will study the properties | 459219019Sgabor| of the unpacking system and set some variables accordingly. | 460219019Sgabor`-----------------------------------------------------------------------*/ 461219019Sgabor 462219019Sgaborstatic void 463219019Sgaborgenerate_configure () 464219019Sgabor{ 465219019Sgabor if (no_i18n) 466219019Sgabor fputs ("echo=echo\n", output); 467219019Sgabor else 468219019Sgabor { 469219019Sgabor fprintf (output, "\ 470219019Sgaborsave_IFS=\"${IFS}\"\n\ 471219019SgaborIFS=\"${IFS}:\"\n\ 472219019Sgaborgettext_dir=FAILED\n\ 473219019Sgaborlocale_dir=FAILED\n\ 474219019Sgaborfirst_param=\"$1\"\n\ 475219019Sgaborfor dir in $PATH\n\ 476219019Sgabordo\n\ 477219019Sgabor if test \"$gettext_dir\" = FAILED && test -f $dir/gettext \\\n\ 478219019Sgabor && ($dir/gettext --version >/dev/null 2>&1)\n\ 479219019Sgabor then\n\ 480219019Sgabor set `$dir/gettext --version 2>&1`\n\ 481219019Sgabor if test \"$3\" = GNU\n\ 482219019Sgabor then\n\ 483219019Sgabor gettext_dir=$dir\n\ 484219019Sgabor fi\n\ 485219019Sgabor fi\n\ 486219019Sgabor if test \"$locale_dir\" = FAILED && test -f $dir/%s \\\n\ 487219019Sgabor && ($dir/%s --print-text-domain-dir >/dev/null 2>&1)\n\ 488219019Sgabor then\n\ 489219019Sgabor locale_dir=`$dir/%s --print-text-domain-dir`\n\ 490219019Sgabor fi\n\ 491219019Sgabordone\n\ 492219019SgaborIFS=\"$save_IFS\"\n\ 493219019Sgaborif test \"$locale_dir\" = FAILED || test \"$gettext_dir\" = FAILED\n\ 494219019Sgaborthen\n\ 495219019Sgabor echo=echo\n\ 496219019Sgaborelse\n\ 497219019Sgabor TEXTDOMAINDIR=$locale_dir\n\ 498219019Sgabor export TEXTDOMAINDIR\n\ 499219019Sgabor TEXTDOMAIN=sharutils\n\ 500 export TEXTDOMAIN\n\ 501 echo=\"$gettext_dir/gettext -s\"\n\ 502fi\n", 503 "shar", "shar", "shar"); 504 /* Above the name of the program of the package which supports the 505 --print-text-domain-dir option has to be given. */ 506 } 507 508 if (query_user_mode) 509 if (vanilla_operation_mode) 510 fputs ("\ 511shar_tty= shar_n= shar_c='\n\ 512'\n", 513 output); 514 else 515 { 516 517 /* Check if /dev/tty exists. If yes, define shar_tty to 518 `/dev/tty', else, leave it empty. */ 519 520 fputs ("\ 521if test -n \"`ls /dev/tty 2>/dev/null`\"; then\n\ 522 shar_tty=/dev/tty\n\ 523else\n\ 524 shar_tty=\n\ 525fi\n", 526 output); 527 528 /* Try to find a way to echo a message without newline. Set 529 shar_n to `-n' or nothing for an echo option, and shar_c to 530 `\c' or nothing for a string terminator. */ 531 532 fputs ("\ 533if (echo \"testing\\c\"; echo 1,2,3) | grep c >/dev/null; then\n\ 534 if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then\n\ 535 shar_n= shar_c='\n\ 536'\n\ 537 else\n\ 538 shar_n=-n shar_c=\n\ 539 fi\n\ 540else\n\ 541 shar_n= shar_c='\\c'\n\ 542fi\n", 543 output); 544 } 545 546 if (timestamp_mode) 547 { 548 const char *file = "$$.touch"; 549 const char *stamp1 = "200112312359.59"; 550 const char *stamp2 = "123123592001.59"; 551 const char *stamp2tr = "123123592001.5"; /* old SysV 14-char limit */ 552 const char *stamp3 = "1231235901"; 553 554 /* Set the shell variable shar_touch to an appropriate invocation 555 of `touch' if the touch program is proven able to restore dates. 556 Otherwise, set shar_touch to `:' and issue a warning. */ 557 558 fprintf (output, "\ 559if touch -am -t %s %s >/dev/null 2>&1 && test ! -f %s -a -f %s; then\n\ 560 shar_touch='touch -am -t $1$2$3$4$5$6.$7 \"$8\"'\n\ 561elif touch -am %s %s >/dev/null 2>&1 && test ! -f %s -a ! -f %s -a -f %s; then\n\ 562 shar_touch='touch -am $3$4$5$6$1$2.$7 \"$8\"'\n\ 563elif touch -am %s %s >/dev/null 2>&1 && test ! -f %s -a -f %s; then\n\ 564 shar_touch='touch -am $3$4$5$6$2 \"$8\"'\n\ 565else\n\ 566 shar_touch=:\n\ 567 echo\n\ 568 $echo '%s'\n\ 569 $echo \"%s\"\n\ 570 echo\n\ 571fi\n\ 572rm -f %s %s %s %s %s\n\ 573#\n", 574 stamp1, file, stamp1, file, 575 stamp2, file, stamp2, stamp2tr, file, 576 stamp3, file, stamp3, file, 577 N_("\ 578WARNING: not restoring timestamps. Consider getting and"), 579 N_("\ 580installing GNU \\`touch', distributed in GNU File Utilities..."), 581 stamp1, stamp2, stamp2tr, stamp3, file); 582 } 583 584 if (!split_file_mode || part_number == 1) 585 { 586 /* Create locking directory. */ 587 fprintf (output, "\ 588if mkdir _sh%05d; then\n\ 589 $echo 'x -' '%s'\n\ 590else\n\ 591 $echo '%s'\n\ 592 exit 1\n\ 593fi\n", 594 sharpid, N_("creating lock directory"), 595 N_("failed to create lock directory")); 596 } 597} 598 599/*---. 600| ? | 601`---*/ 602 603/* Ridiculously enough. FIXME: No fix limit in GNU... */ 604#define MAX_MKDIR_ALREADY 128 605 606char *mkdir_already[MAX_MKDIR_ALREADY]; 607int mkdir_already_count = 0; 608 609static void 610generate_mkdir (path) 611 const char *path; 612{ 613 int counter; 614 char *cursor; 615 616 /* If already generated code for this dir creation, don't do again. */ 617 618 for (counter = 0; counter < mkdir_already_count; counter++) 619 if (!strcmp (path, mkdir_already[counter])) 620 return; 621 622 /* Haven't done this one. */ 623 624 if (mkdir_already_count == MAX_MKDIR_ALREADY) 625 error (EXIT_FAILURE, 0, _("Too many directories for mkdir generation")); 626 cursor = mkdir_already[mkdir_already_count++] = xmalloc (strlen (path) + 1); 627 strcpy (cursor, path); 628 629 /* Generate the text. */ 630 631 fprintf (output, "if test ! -d '%s'; then\n", path); 632 if (!quiet_unshar_mode) 633 fprintf (output, " $echo 'x -' '%s' '%s'\n", 634 N_("creating directory"), path); 635 fprintf (output, " mkdir '%s'\n", path); 636 fputs ("fi\n", output); 637} 638 639/*---. 640| ? | 641`---*/ 642 643static void 644generate_mkdir_script (path) 645 const char *path; 646{ 647 char *cursor; 648 649 for (cursor = strchr (path, '/'); cursor; cursor = strchr (cursor + 1, '/')) 650 { 651 652 /* Avoid empty string if leading or double '/'. */ 653 654 if (cursor == path || *(cursor - 1) == '/') 655 continue; 656 657 /* Omit '.'. */ 658 659 if (cursor[-1] == '.' && (cursor == path + 1 || cursor[-2] == '/')) 660 continue; 661 662 /* Temporarily terminate string. FIXME! */ 663 664 *cursor = 0; 665 generate_mkdir (path); 666 *cursor = '/'; 667 } 668} 669 670/* Walking routines. */ 671 672/*---. 673| ? | 674`---*/ 675 676static int 677check_accessibility (local_name, restore_name) 678 const char *local_name; 679 const char *restore_name; 680{ 681 if (access (local_name, 4)) 682 { 683 error (0, 0, _("Cannot access %s"), local_name); 684 return 1; 685 } 686 687 return 0; 688} 689 690/*---. 691| ? | 692`---*/ 693 694static int 695generate_one_header_line (local_name, restore_name) 696 const char *local_name; 697 const char *restore_name; 698{ 699 fprintf (output, "# %6ld %s %s\n", struct_stat.st_size, 700 mode_string (struct_stat.st_mode), restore_name); 701 return 0; 702} 703 704/*---. 705| ? | 706`---*/ 707 708static void 709generate_full_header (argc, argv) 710 int argc; 711 char *const *argv; 712{ 713 char *current_directory; 714 time_t now; 715 struct tm *local_time; 716 char buffer[80]; /* FIXME: No fix limit in GNU... */ 717 int warned_once; 718 int counter; 719 720 warned_once = 0; 721 for (counter = 0; counter < argc; counter++) 722 { 723 724 /* Skip positional parameters. */ 725 726 if (intermixed_parameter_mode && 727 (strcmp (argv[counter], "-B") == 0 || 728 strcmp (argv[counter], "-T") == 0 || 729 strcmp (argv[counter], "-M") == 0 || 730 strcmp (argv[counter], "-z") == 0 || 731 strcmp (argv[counter], "-Z") == 0 || 732 strcmp (argv[counter], "-C") == 0)) 733 { 734 if (!warned_once && strcmp (argv[counter], "-C") == 0) 735 { 736 error (0, 0, _("-C is being deprecated, use -Z instead")); 737 warned_once = 1; 738 } 739 continue; 740 } 741 742 if (walktree (check_accessibility, argv[counter])) 743 exit (EXIT_FAILURE); 744 } 745 746 if (net_headers_mode) 747 { 748 fprintf (output, "Submitted-by: %s\n", submitter_address); 749 fprintf (output, "Archive-name: %s%s%02d\n\n", 750 archive_name, (strchr (archive_name, '/')) ? "" : "/part", 751 part_number ? part_number : 1); 752 } 753 754 if (cut_mark_mode) 755 fputs (cut_mark_line, output); 756 fputs ("\ 757#!/bin/sh\n", 758 output); 759 if (archive_name) 760 fprintf (output, "\ 761# This is %s, a shell archive (produced by GNU %s %s)\n", 762 archive_name, PACKAGE, VERSION); 763 else 764 fprintf (output, "\ 765# This is a shell archive (produced by GNU %s %s).\n", 766 PACKAGE, VERSION); 767 fputs ("\ 768# To extract the files from this archive, save it to some FILE, remove\n\ 769# everything before the `!/bin/sh' line above, then type `sh FILE'.\n\ 770#\n", 771 output); 772 773 time (&now); 774 local_time = localtime (&now); 775 strftime (buffer, 79, "%Y-%m-%d %H:%M %Z", local_time); 776 fprintf (output, "\ 777# Made on %s by <%s>.\n", 778 buffer, submitter_address); 779 780 current_directory = xgetcwd (); 781 if (current_directory) 782 { 783 fprintf (output, "\ 784# Source directory was `%s'.\n", 785 current_directory); 786 free (current_directory); 787 } 788 else 789 error (0, errno, _("Cannot get current directory name")); 790 791 if (check_existing_mode) 792 fputs ("\ 793#\n\ 794# Existing files will *not* be overwritten unless `-c' is specified.\n", 795 output); 796 else if (query_user_mode) 797 fputs ("\ 798#\n\ 799# existing files MAY be overwritten\n", 800 output); 801 else 802 fputs ("\ 803#\n\ 804# existing files WILL be overwritten\n", 805 output); 806 807 if (query_user_mode) 808 fputs ("\ 809# The unsharer will be INTERACTIVELY queried.\n", 810 output); 811 812 if (vanilla_operation_mode) 813 { 814 fputs ("\ 815# This format requires very little intelligence at unshar time.\n\ 816# ", 817 output); 818 if (check_existing_mode || split_file_mode) 819 fputs ("\"if test\", ", output); 820 if (split_file_mode) 821 fputs ("\"cat\", \"rm\", ", output); 822 fputs ("\"echo\", \"mkdir\", and \"sed\" may be needed.\n", output); 823 } 824 825 if (split_file_mode) 826 { 827 828 /* May be split, explain. */ 829 830 fputs ("#\n", output); 831 archive_type_position = ftell (output); 832 fprintf (output, "%-75s\n%-75s\n", "#", "#"); 833 } 834 835 fputs ("\ 836#\n\ 837# This shar contains:\n\ 838# length mode name\n\ 839# ------ ---------- ------------------------------------------\n", 840 output); 841 842 for (counter = 0; counter < argc; counter++) 843 { 844 845 /* Output names of files but not parameters. */ 846 847 if (intermixed_parameter_mode && 848 (strcmp (argv[counter], "-B") == 0 || 849 strcmp (argv[counter], "-T") == 0 || 850 strcmp (argv[counter], "-M") == 0 || 851 strcmp (argv[counter], "-z") == 0 || 852 strcmp (argv[counter], "-Z") == 0 || 853 strcmp (argv[counter], "-C") == 0)) 854 continue; 855 856 if (walktree (generate_one_header_line, argv[counter])) 857 exit (EXIT_FAILURE); 858 } 859 fputs ("#\n", output); 860 861 generate_configure (); 862 863 if (split_file_mode) 864 { 865 866 /* Now check the sequence. */ 867 868 fprintf (output, "\ 869if test -r _sh%05d/seq; then\n\ 870 $echo '%s'\n\ 871 $echo '%s' '`cat _sh%05d/seq`' '%s'\n\ 872 exit 1\n\ 873fi\n", 874 sharpid, 875 N_("Must unpack archives in sequence!"), 876 N_("Please unpack part"), sharpid, N_("next!") 877); 878 } 879} 880 881/* Prepare a shar script. */ 882 883/*---. 884| ? | 885`---*/ 886 887static int 888shar (local_name, restore_name) 889 const char *local_name; 890 const char *restore_name; 891{ 892 char buffer[BUFSIZ]; 893 FILE *input; 894 long current_size; 895 long remaining_size; 896 int split_flag = 0; /* file split flag */ 897 const char *file_type; /* text of binary */ 898 const char *file_type_remote; /* text or binary, avoiding locale */ 899 struct tm *restore_time; 900 901 /* Check to see that this is still a regular file and readable. */ 902 903 if (!S_ISREG (struct_stat.st_mode & S_IFMT)) 904 { 905 error (0, 0, _("%s: Not a regular file"), local_name); 906 return 1; 907 } 908 if (access (local_name, 4)) 909 { 910 error (0, 0, _("Cannot access %s"), local_name); 911 return 1; 912 } 913 914 /* If file_size_limit set, get the current output length. */ 915 916 if (file_size_limit) 917 { 918 current_size = ftell (output); 919 remaining_size = (file_size_limit * 1024L) - current_size; 920 DEBUG_PRINT (_("In shar: remaining size %ld\n"), remaining_size); 921 922 if (!split_file_mode && current_size > first_file_position 923 && ((uuencoded_file_mode 924 ? struct_stat.st_size + struct_stat.st_size / 3 925 : struct_stat.st_size) 926 > remaining_size)) 927 { 928 929 /* Change to another file. */ 930 931 DEBUG_PRINT (_("Newfile, remaining %ld, "), remaining_size); 932 DEBUG_PRINT (_("Limit still %d\n"), file_size_limit); 933 934 /* Close the "&&" and report an error if any of the above 935 failed. */ 936 937 /* The following code is somewhat unreadable because marking 938 the strings is necessary. The complete string is (nice 939 formatted: 940: || $echo 'restore of %s failed'\n\ 941echo 'End of part %d, continue with part %d'\n\ 942exit 0\n", 943 */ 944 fprintf (output, "\ 945: || $echo '%s' '%s' '%s'\n\ 946$echo '%s' '%d,' '%s' '%d'\n\ 947exit 0\n", 948 N_("restore of"), restore_name, N_("failed"), 949 N_("End of part"), part_number, 950 N_("continue with part"), part_number + 1); 951 952 close_output (); 953 954 /* Clear mkdir_already in case the user unshars out of order. */ 955 956 while (mkdir_already_count > 0) 957 free (mkdir_already[--mkdir_already_count]); 958 959 /* Form the next filename. */ 960 961 open_output (); 962 if (!quiet_mode) 963 fprintf (stderr, _("Starting file %s\n"), output_filename); 964 965 if (net_headers_mode) 966 { 967 fprintf (output, "Submitted-by: %s\n", submitter_address); 968 fprintf (output, "Archive-name: %s%s%02d\n\n", archive_name, 969 strchr (archive_name, '/') ? "" : "/part", 970 part_number ? part_number : 1); 971 } 972 973 if (cut_mark_mode) 974 fputs (cut_mark_line, output); 975 976 fprintf (output, "\ 977#!/bin/sh\n\ 978# This is part %02d of %s.\n", 979 part_number, 980 archive_name ? archive_name : "a multipart archive"); 981 982 generate_configure (); 983 984 first_file_position = ftell (output); 985 } 986 } 987 else 988 remaining_size = 0; /* give some value to the variable */ 989 990 fprintf (output, "\ 991# ============= %s ==============\n", 992 restore_name); 993 994 generate_mkdir_script (restore_name); 995 996 if (struct_stat.st_size == 0) 997 { 998 file_type = _("empty"); 999 file_type_remote = N_("(empty)"); 1000 input = NULL; /* give some value to the variable */ 1001 } 1002 else 1003 { 1004 1005 /* If mixed, determine the file type. */ 1006 1007 if (mixed_uuencoded_file_mode) 1008 { 1009 1010 /* Uuencoded was once decided through calling the `file' 1011 program and studying its output: the method was slow and 1012 error prone. There is only one way of doing it correctly, 1013 and this is to read the input file, seeking for one binary 1014 character. Considering the average file size, even reading 1015 the whole file (if it is text) would be usually faster than 1016 calling `file'. */ 1017 1018 int character; 1019 int line_length; 1020 1021 if (input = fopen (local_name, "rb"), input == NULL) 1022 { 1023 error (0, errno, _("Cannot open file %s"), local_name); 1024 return 1; 1025 } 1026 1027 /* Assume initially that the input file is text. Then try to prove 1028 it is binary by looking for binary characters or long lines. */ 1029 1030 uuencoded_file_mode = 0; 1031 line_length = 0; 1032 while (character = getc (input), character != EOF) 1033 if (character == '\n') 1034 line_length = 0; 1035 else if ( 1036#ifdef __CHAR_UNSIGNED__ 1037 byte_is_binary[character] 1038#else 1039 byte_is_binary[character & 0xFF] 1040#endif 1041 || line_length == MAXIMUM_NON_BINARY_LINE) 1042 { 1043 uuencoded_file_mode = 1; 1044 break; 1045 } 1046 else 1047 line_length++; 1048 fclose (input); 1049 1050 /* Text files should terminate by an end of line. */ 1051 1052 if (line_length > 0) 1053 uuencoded_file_mode = 1; 1054 } 1055 1056 if (uuencoded_file_mode) 1057 { 1058 static int pid, pipex[2]; 1059 1060 file_type = (compressed_file_mode ? _("compressed") 1061 : gzipped_file_mode ? _("gzipped") : _("binary")); 1062 file_type_remote = (compressed_file_mode ? N_("(compressed)") 1063 : gzipped_file_mode ? N_("(gzipped)") 1064 : N_("(binary)")); 1065 1066 /* Fork a uuencode process. */ 1067 1068 pipe (pipex); 1069 fflush (output); 1070 1071 if (pid = fork (), pid != 0) 1072 { 1073 1074 /* Parent, create a file to read. */ 1075 1076 if (pid < 0) 1077 error (EXIT_FAILURE, errno, _("Could not fork")); 1078 close (pipex[1]); 1079 input = fdopen (pipex[0], "r"); 1080 if (!input) 1081 { 1082 error (0, errno, _("File %s (%s)"), local_name, file_type); 1083 return 1; 1084 } 1085 } 1086 else 1087 { 1088 1089 /* Start writing the pipe with encodes. */ 1090 1091 FILE *outptr; 1092 1093 if (compressed_file_mode) 1094 { 1095 sprintf (buffer, "compress -b%d < '%s'", 1096 bits_per_compressed_byte, local_name); 1097 input = popen (buffer, "r"); 1098 } 1099 else if (gzipped_file_mode) 1100 { 1101 sprintf (buffer, "gzip -%d < '%s'", 1102 gzip_compression_level, local_name); 1103 input = popen (buffer, "r"); 1104 } 1105 else 1106 input = fopen (local_name, "rb"); 1107 1108 outptr = fdopen (pipex[1], "w"); 1109 fputs ("begin 600 ", outptr); 1110 if (compressed_file_mode) 1111 fprintf (outptr, "_sh%05d/cmp\n", sharpid); 1112 else if (gzipped_file_mode) 1113 fprintf (outptr, "_sh%05d/gzi\n", sharpid); 1114 else 1115 fprintf (outptr, "%s\n", restore_name); 1116 copy_file_encoded (input, outptr); 1117 fprintf (outptr, "end\n"); 1118 if (compressed_file_mode || gzipped_file_mode) 1119 pclose (input); 1120 else 1121 fclose (input); 1122 1123 exit (EXIT_SUCCESS); 1124 } 1125 } 1126 else 1127 { 1128 file_type = _("text"); 1129 file_type_remote = N_("(text)"); 1130 1131 input = fopen (local_name, "r"); 1132 if (!input) 1133 { 1134 error (0, errno, _("File %s (%s)"), local_name, file_type); 1135 return 1; 1136 } 1137 } 1138 } 1139 1140 /* Protect existing files. */ 1141 1142 if (check_existing_mode) 1143 { 1144 fprintf (output, "\ 1145if test -f '%s' && test \"$first_param\" != -c; then\n", 1146 restore_name); 1147 1148 if (query_user_mode) 1149 { 1150 fprintf (output, "\ 1151 case $shar_wish in\n\ 1152 A*|a*)\n\ 1153 $echo 'x -' %s '%s' ;;\n\ 1154 *)\n\ 1155 $echo $shar_n '? -' %s '%s' '%s' $shar_c\n\ 1156 if test -n \"$shar_tty\"; then\n\ 1157 read shar_wish < $shar_tty\n\ 1158 else\n\ 1159 read shar_wish\n\ 1160 fi ;;\n\ 1161 esac\n\ 1162 case $shar_wish in\n\ 1163 Q*|q*)\n\ 1164 $echo '%s'; exit 1 ;;\n\ 1165 A*|a*|Y*|y*)\n\ 1166 shar_skip=no ;;\n\ 1167 *)\n\ 1168 shar_skip=yes ;;\n\ 1169 esac\n\ 1170else\n\ 1171 shar_skip=no\n\ 1172fi\n\ 1173if test $shar_skip = yes; then\n\ 1174 $echo 'x -' %s '%s'\n", 1175 N_("overwriting"), restore_name, 1176 N_("overwrite"), restore_name, 1177 N_("[no, yes, all, quit] (no)?"), 1178 N_("extraction aborted"), 1179 N_("SKIPPING"), restore_name); 1180 } 1181 else 1182 fprintf (output, "\ 1183 $echo 'x -' %s '%s' '%s'\n", 1184 N_("SKIPPING"), restore_name, N_("(file already exists)")); 1185 1186 if (split_file_mode) 1187 fprintf (output, "\ 1188 rm -f _sh%05d/new\n", 1189 sharpid); 1190 1191 fputs ("\ 1192else\n", 1193 output); 1194 1195 if (split_file_mode) 1196 fprintf (output, "\ 1197 > _sh%05d/new\n", 1198 sharpid); 1199 } 1200 1201 if (!quiet_mode) 1202 error (0, 0, _("Saving %s (%s)"), local_name, file_type); 1203 1204 if (!quiet_unshar_mode) 1205 fprintf (output, "\ 1206 $echo 'x -' %s '%s' '%s'\n", 1207 N_("extracting"), restore_name, file_type_remote); 1208 1209 if (struct_stat.st_size == 0) 1210 { 1211 1212 /* Just touch the file, or empty it if it exists. */ 1213 1214 fprintf (output, "\ 1215 > '%s' &&\n", 1216 restore_name); 1217 } 1218 else 1219 { 1220 1221 /* Run sed for non-empty files. */ 1222 1223 if (uuencoded_file_mode) 1224 { 1225 1226 /* Run sed through uudecode (via temp file if might get split). */ 1227 1228 fprintf (output, "\ 1229 sed 's/^%c//' << '%s' ", 1230 line_prefix, here_delimiter); 1231 if (inhibit_piping_mode) 1232 fprintf (output, "> _sh%05d/uue &&\n", sharpid); 1233 else 1234 fputs ("| uudecode &&\n", output); 1235 } 1236 else 1237 { 1238 1239 /* Just run it into the file. */ 1240 1241 fprintf (output, "\ 1242 sed 's/^%c//' << '%s' > '%s' &&\n", 1243 line_prefix, here_delimiter, restore_name); 1244 } 1245 1246 while (fgets (buffer, BUFSIZ, input)) 1247 { 1248 1249 /* Output a line and test the length. */ 1250 1251 if (!mandatory_prefix_mode 1252 && ISASCII (buffer[0]) 1253#ifdef isgraph 1254 && isgraph (buffer[0]) 1255#else 1256 && isprint (buffer[0]) && !isspace (buffer[0]) 1257#endif 1258 /* Protect lines already starting with the prefix. */ 1259 && buffer[0] != line_prefix 1260 1261 /* Old mail programs interpret ~ directives. */ 1262 && buffer[0] != '~' 1263 1264 /* Avoid mailing lines which are just `.'. */ 1265 && buffer[0] != '.' 1266 1267#if STRNCMP_IS_FAST 1268 && strncmp (buffer, here_delimiter, here_delimiter_length) 1269 1270 /* unshar -e: avoid `exit 0'. */ 1271 && strncmp (buffer, "exit 0", 6) 1272 1273 /* Don't let mail prepend a `>'. */ 1274 && strncmp (buffer, "From", 4) 1275#else 1276 && (buffer[0] != here_delimiter[0] 1277 || strncmp (buffer, here_delimiter, here_delimiter_length)) 1278 1279 /* unshar -e: avoid `exit 0'. */ 1280 && (buffer[0] != 'e' || strncmp (buffer, "exit 0", 6)) 1281 1282 /* Don't let mail prepend a `>'. */ 1283 && (buffer[0] != 'F' || strncmp (buffer, "From", 4)) 1284#endif 1285 ) 1286 fputs (buffer, output); 1287 else 1288 { 1289 fprintf (output, "%c%s", line_prefix, buffer); 1290 remaining_size--; 1291 } 1292 1293 /* Try completing an incomplete line, but not if the incomplete 1294 line contains no character. This might occur with -T for 1295 incomplete files, or sometimes when switching to a new file. */ 1296 1297 if (*buffer && buffer[strlen (buffer) - 1] != '\n') 1298 { 1299 putc ('\n', output); 1300 remaining_size--; 1301 } 1302 1303 if (split_file_mode 1304#if MSDOS 1305 /* 1 extra for CR. */ 1306 && (remaining_size -= (int) strlen (buffer) + 1) < 0 1307#else 1308 && (remaining_size -= (int) strlen (buffer)) < 0 1309#endif 1310 ) 1311 { 1312 1313 /* Change to another file. */ 1314 1315 DEBUG_PRINT (_("Newfile, remaining %ld, "), remaining_size); 1316 DEBUG_PRINT (_("Limit still %d\n"), file_size_limit); 1317 1318 fprintf (output, "%s\n", here_delimiter); 1319 1320 /* Close the "&&" and report an error if any of the above 1321 failed. */ 1322 1323 fprintf (output, "\ 1324 : || $echo '%s' '%s' '%s'\n", 1325 N_("restore of"), restore_name, N_("failed")); 1326 1327 if (check_existing_mode) 1328 fputs ("\ 1329fi\n", 1330 output); 1331 1332 if (quiet_unshar_mode) 1333 fprintf (output, "\ 1334$echo '%s' '%d,' '%s' '%d'\n", 1335 N_("End of part"), part_number, 1336 N_("continue with part"), part_number + 1); 1337 else 1338 fprintf (output, "\ 1339$echo '%s' '%s' '%s' '%d'\n\ 1340$echo '%s' '%s' '%s' '%d'\n", 1341 N_("End of"), 1342 archive_name ? archive_name : N_("archive"), 1343 N_("part"), 1344 part_number, 1345 N_("File"), restore_name, 1346 N_("is continued in part"), part_number + 1); 1347 1348 fprintf (output, "\ 1349echo %d > _sh%05d/seq\n\ 1350exit 0\n", 1351 part_number + 1, sharpid); 1352 1353 if (part_number == 1) 1354 { 1355 1356 /* Rewrite the info lines on the first header. */ 1357 1358 fseek (output, archive_type_position, 0); 1359 fprintf (output, "%-75s\n%-75s\n", 1360 "\ 1361# This is part 1 of a multipart archive.", 1362 "\ 1363# Do not concatenate these parts, unpack them in order with `/bin/sh'."); 1364 } 1365 close_output (); 1366 1367 /* Next! */ 1368 1369 open_output (); 1370 1371 if (net_headers_mode) 1372 { 1373 fprintf (output, "Submitted-by: %s\n", submitter_address); 1374 fprintf (output, "Archive-name: %s%s%02d\n\n", 1375 archive_name, 1376 strchr (archive_name, '/') ? "" : "/part", 1377 part_number ? part_number : 1); 1378 } 1379 1380 if (cut_mark_mode) 1381 fputs (cut_mark_line, output); 1382 1383 fprintf (output, "\ 1384#!/bin/sh\n\ 1385# This is `%s' (part %d of %s).\n\ 1386# Do not concatenate these parts, unpack them in order with `/bin/sh'.\n\ 1387# File `%s' is being continued...\n\ 1388#\n", 1389 basename (output_filename), part_number, 1390 archive_name ? archive_name : "a multipart archive", 1391 restore_name); 1392 1393 generate_configure (); 1394 1395 fprintf (output, "\ 1396if test ! -r _sh%05d/seq; then\n\ 1397 $echo '%s'\n\ 1398 exit 1\n\ 1399fi\n\ 1400shar_sequence=`cat _sh%05d/seq`\n\ 1401if test \"$shar_sequence\" != %d; then\n\ 1402 $echo '%s' \"$shar_sequence\" '%s'\n\ 1403 exit 1\n\ 1404fi\n", 1405 sharpid, 1406 N_("Please unpack part 1 first!"), 1407 sharpid, 1408 part_number, 1409 N_("Please unpack part"), 1410 N_("next!")); 1411 1412 if (check_existing_mode) 1413 if (quiet_unshar_mode) 1414 fprintf (output, "\ 1415if test -f _sh%05d/new; then\n", 1416 sharpid); 1417 else 1418 fprintf (output, "\ 1419if test ! -f _sh%05d/new; then\n\ 1420 $echo 'x -' '%s' '%s'\n\ 1421else\n", 1422 sharpid, 1423 N_("STILL SKIPPING"), restore_name); 1424 1425 if (!quiet_mode) 1426 fprintf (stderr, _("Starting file %s\n"), output_filename); 1427 if (!quiet_unshar_mode) 1428 fprintf (output, "\ 1429 $echo 'x -' '%s' '%s'\n", 1430 N_("continuing file"), restore_name); 1431 fprintf (output, "\ 1432 sed 's/^%c//' << '%s' >> ", 1433 line_prefix, here_delimiter); 1434 if (uuencoded_file_mode) 1435 fprintf (output, "_sh%05d/uue &&\n", sharpid); 1436 else 1437 fprintf (output, "%s &&\n", restore_name); 1438 remaining_size = file_size_limit * 1024L; 1439 split_flag = 1; 1440 } 1441 } 1442 1443 fclose (input); 1444 while (wait (NULL) >= 0) 1445 ; 1446 1447 fprintf (output, "%s\n", here_delimiter); 1448 if (split_flag && !quiet_unshar_mode) 1449 fprintf (output, "\ 1450 $echo '%s' '%s' '%s' &&\n", 1451 N_("File"), restore_name, N_("is complete")); 1452 1453 /* If this file was uuencoded w/Split, decode it and drop the temp. */ 1454 1455 if (uuencoded_file_mode && inhibit_piping_mode) 1456 { 1457 if (!quiet_unshar_mode) 1458 fprintf (output, "\ 1459 $echo '%s' '%s' &&\n", 1460 N_("uudecoding file"), restore_name); 1461 1462 fprintf (output, "\ 1463 uudecode _sh%05d/uue < _sh%05d/uue &&\n", 1464 sharpid, sharpid); 1465 } 1466 1467 /* If this file was compressed, uncompress it and drop the temp. */ 1468 1469 if (compressed_file_mode) 1470 { 1471 if (!quiet_unshar_mode) 1472 fprintf (output, "\ 1473 $echo '%s' '%s' &&\n", 1474 N_("uncompressing file"), restore_name); 1475 1476 fprintf (output, "\ 1477 compress -d < _sh%05d/cmp > '%s' &&\n", 1478 sharpid, restore_name); 1479 } 1480 else if (gzipped_file_mode) 1481 { 1482 if (!quiet_unshar_mode) 1483 fprintf (output, "\ 1484 $echo '%s' '%s' &&\n", 1485 N_("gunzipping file"), restore_name); 1486 1487 fprintf (output, "\ 1488 gzip -d < _sh%05d/gzi > '%s' &&\n", 1489 sharpid, restore_name); 1490 } 1491 } 1492 1493 if (timestamp_mode) 1494 { 1495 1496 /* Set the dates as they were. */ 1497 1498 restore_time = localtime (&struct_stat.st_mtime); 1499 fprintf (output, "\ 1500 (set %02d %02d %02d %02d %02d %02d %02d '%s'; eval \"$shar_touch\") &&\n", 1501 (restore_time->tm_year + 1900) / 100, 1502 (restore_time->tm_year + 1900) % 100, 1503 restore_time->tm_mon + 1, restore_time->tm_mday, 1504 restore_time->tm_hour, restore_time->tm_min, 1505 restore_time->tm_sec, restore_name); 1506 } 1507 1508 if (vanilla_operation_mode) 1509 { 1510 1511 /* Close the "&&" and report an error if any of the above 1512 failed. */ 1513 1514 fprintf (output, "\ 1515 : || $echo '%s' '%s' '%s'\n", 1516 N_("restore of"), restore_name, N_("failed")); 1517 } 1518 else 1519 { 1520 unsigned char md5buffer[16]; 1521 FILE *fp = NULL; 1522 int did_md5 = 0; 1523 1524 /* Set the permissions as they were. */ 1525 1526 fprintf (output, "\ 1527 chmod %04o '%s' ||\n", 1528 (unsigned) (struct_stat.st_mode & 0777), restore_name); 1529 1530 /* Report an error if any of the above failed. */ 1531 1532 fprintf (output, "\ 1533 $echo '%s' '%s' '%s'\n", 1534 N_("restore of"), restore_name, N_("failed")); 1535 1536 if (md5_count_mode && (fp = fopen (local_name, "r")) != NULL 1537 && md5_stream (fp, md5buffer) == 0) 1538 { 1539 /* Validate the transferred file using `md5sum' command. */ 1540 size_t cnt; 1541 did_md5 = 1; 1542 1543 fprintf (output, "\ 1544 if ( %s --help 2>&1 | grep 'sage: md5sum \\[' ) >/dev/null 2>&1 \\\n\ 1545 && ( %s --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then\n\ 1546 %s -c << %s >/dev/null 2>&1 \\\n\ 1547 || $echo '%s:' '%s'\n", 1548 MD5SUM_COMMAND, MD5SUM_COMMAND, MD5SUM_COMMAND, 1549 DEFAULT_HERE_DELIMITER, local_name, N_("MD5 check failed")); 1550 1551 for (cnt = 0; cnt < 16; ++cnt) 1552 fprintf (output, "%02x", md5buffer[cnt]); 1553 1554 fprintf (output, " %c%s\n\ 1555%s\n", 1556 ' ', local_name, DEFAULT_HERE_DELIMITER); 1557 /* This ^^^ space is not necessarily a parameter now. But it 1558 is a flag for binary/text mode and will perhaps be used later. */ 1559 } 1560 1561 if (fp != NULL) 1562 fclose (fp); 1563 1564 if (character_count_mode) 1565 { 1566 /* Validate the transferred file using simple `wc' command. */ 1567 1568 FILE *pfp; 1569 char command[BUFSIZ]; 1570 1571 sprintf (command, "%s '%s'", CHARACTER_COUNT_COMMAND, local_name); 1572 if (pfp = popen (command, "r"), pfp) 1573 { 1574 char wc[BUFSIZ]; 1575 const char *prefix = ""; 1576 1577 if (did_md5) 1578 { 1579 fputs (" else\n", output); 1580 prefix = " "; 1581 } 1582 1583 fscanf (pfp, "%s", wc); 1584 fprintf (output, "\ 1585%s shar_count=\"`%s '%s'`\"\n\ 1586%s test %s -eq \"$shar_count\" ||\n\ 1587%s $echo '%s:' '%s' '%s,' '%s' \"$shar_count!\"\n", 1588 prefix, CHARACTER_COUNT_COMMAND, restore_name, 1589 prefix, wc, 1590 prefix, restore_name, N_("original size"), wc, 1591 N_("current size")); 1592 pclose (pfp); 1593 } 1594 } 1595 if (did_md5) 1596 fputs (" fi\n", output); 1597 } 1598 1599 /* If the exists option is in place close the if. */ 1600 1601 if (check_existing_mode) 1602 fputs ("\ 1603fi\n", 1604 output); 1605 1606 return 0; 1607} 1608 1609/* Main control. */ 1610 1611/*-----------------------------------------------------------------------. 1612| Set file mode, accepting a parameter 'M' for mixed uuencoded mode, 'B' | 1613| for uuencoded mode, 'z' for gzipped mode or 'Z' for compressed mode. | 1614| Any other value yields text mode. | 1615`-----------------------------------------------------------------------*/ 1616 1617static void 1618set_file_mode (mode) 1619 int mode; 1620{ 1621 mixed_uuencoded_file_mode = mode == 'M'; 1622 uuencoded_file_mode = mode == 'B'; 1623 gzipped_file_mode = mode == 'z'; 1624 compressed_file_mode = mode == 'Z'; 1625 1626 if (gzipped_file_mode || compressed_file_mode) 1627 uuencoded_file_mode = 1; 1628} 1629 1630/*-------------------------------------------. 1631| Open the next output file, or die trying. | 1632`-------------------------------------------*/ 1633 1634static void 1635open_output () 1636{ 1637 sprintf (output_filename, output_base_name, ++part_number); 1638 output = fopen (output_filename, "w"); 1639 if (!output) 1640 error (EXIT_FAILURE, errno, _("Opening `%s'"), output_filename); 1641} 1642 1643/*-----------------------------------------------. 1644| Close the current output file, or die trying. | 1645`-----------------------------------------------*/ 1646 1647static void 1648close_output () 1649{ 1650 if (fclose (output) != 0) 1651 error (EXIT_FAILURE, errno, _("Closing `%s'"), output_filename); 1652} 1653 1654/*----------------------------------. 1655| Output a command format message. | 1656`----------------------------------*/ 1657 1658static void 1659usage (status) 1660 int status; 1661{ 1662 if (status != EXIT_SUCCESS) 1663 fprintf (stderr, _("Try `%s --help' for more information.\n"), 1664 program_name); 1665 else 1666 { 1667 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); 1668 fputs (_("\ 1669Mandatory arguments to long options are mandatory for short options too.\n"), 1670 stdout); 1671 fputs (_("\ 1672\n\ 1673Giving feedback:\n\ 1674 --help display this help and exit\n\ 1675 --version output version information and exit\n\ 1676 -q, --quiet, --silent do not output verbose messages locally\n\ 1677\n\ 1678Selecting files:\n\ 1679 -p, --intermix-type allow -[BTzZ] in file lists to change mode\n\ 1680 -S, --stdin-file-list read file list from standard input\n\ 1681\n\ 1682Splitting output:\n\ 1683 -o, --output-prefix=PREFIX output to file PREFIX.01 through PREFIX.NN\n\ 1684 -l, --whole-size-limit=SIZE split archive, not files, to SIZE kilobytes\n\ 1685 -L, --split-size-limit=SIZE split archive, or files, to SIZE kilobytes\n"), 1686 stdout); 1687 fputs (_("\ 1688\n\ 1689Controlling the shar headers:\n\ 1690 -n, --archive-name=NAME use NAME to document the archive\n\ 1691 -s, --submitter=ADDRESS override the submitter name\n\ 1692 -a, --net-headers output Submitted-by: & Archive-name: headers\n\ 1693 -c, --cut-mark start the shar with a cut line\n\ 1694\n\ 1695Selecting how files are stocked:\n\ 1696 -M, --mixed-uuencode dynamically decide uuencoding (default)\n\ 1697 -T, --text-files treat all files as text\n\ 1698 -B, --uuencode treat all files as binary, use uuencode\n\ 1699 -z, --gzip gzip and uuencode all files\n\ 1700 -g, --level-for-gzip=LEVEL pass -LEVEL (default 9) to gzip\n\ 1701 -Z, --compress compress and uuencode all files\n\ 1702 -b, --bits-per-code=BITS pass -bBITS (default 12) to compress\n"), 1703 stdout); 1704 fputs (_("\ 1705\n\ 1706Protecting against transmission:\n\ 1707 -w, --no-character-count do not use `wc -c' to check size\n\ 1708 -D, --no-md5-digest do not use `md5sum' digest to verify\n\ 1709 -F, --force-prefix force the prefix character on every line\n\ 1710 -d, --here-delimiter=STRING use STRING to delimit the files in the shar\n\ 1711\n\ 1712Producing different kinds of shars:\n\ 1713 -V, --vanilla-operation produce very simple and undemanding shars\n\ 1714 -P, --no-piping exclusively use temporary files at unshar time\n\ 1715 -x, --no-check-existing blindly overwrite existing files\n\ 1716 -X, --query-user ask user before overwriting files (not for Net)\n\ 1717 -m, --no-timestamp do not restore file modification dates & times\n\ 1718 -Q, --quiet-unshar avoid verbose messages at unshar time\n\ 1719 -f, --basename restore in one directory, despite hierarchy\n\ 1720 --no-i18n do not produce internationalized shell script\n"), 1721 stdout); 1722 fputs (_("\ 1723\n\ 1724Option -o is required with -l or -L, option -n is required with -a.\n\ 1725Option -g implies -z, option -b implies -Z.\n"), 1726 stdout); 1727 } 1728 exit (status); 1729} 1730 1731/*--------------------------------------. 1732| Decode options and launch execution. | 1733`--------------------------------------*/ 1734 1735static const struct option long_options[] = 1736{ 1737 {"archive-name", required_argument, NULL, 'n'}, 1738 {"basename", no_argument, NULL, 'f'}, 1739 {"bits-per-code", required_argument, NULL, 'b'}, 1740 {"compress", no_argument, NULL, 'Z'}, 1741 {"cut-mark", no_argument, NULL, 'c'}, 1742 {"force-prefix", no_argument, NULL, 'F'}, 1743 {"gzip", no_argument, NULL, 'z'}, 1744 {"here-delimiter", required_argument, NULL, 'd'}, 1745 {"intermix-type", no_argument, NULL, 'p'}, 1746 {"level-for-gzip", required_argument, NULL, 'g'}, 1747 {"mixed-uuencode", no_argument, NULL, 'M'}, 1748 {"net-headers", no_argument, NULL, 'a'}, 1749 {"no-character-count", no_argument, &character_count_mode, 0}, 1750 {"no-check-existing", no_argument, NULL, 'x'}, 1751 {"no-i18n", no_argument, &no_i18n, 1}, 1752 {"no-md5-digest", no_argument, &md5_count_mode, 0}, 1753 {"no-piping", no_argument, NULL, 'P'}, 1754 {"no-timestamp", no_argument, NULL, 'm'}, 1755 {"output-prefix", required_argument, NULL, 'o'}, 1756 {"print-text-domain-dir", no_argument, &print_text_dom_dir, 1}, 1757 {"query-user", no_argument, NULL, 'X'}, 1758 {"quiet", no_argument, NULL, 'q'}, 1759 {"quiet-unshar", no_argument, NULL, 'Q'}, 1760 {"split-size-limit", required_argument, NULL, 'L'}, 1761 {"stdin-file-list", no_argument, NULL, 'S'}, 1762 {"submitter", required_argument, NULL, 's'}, 1763 {"text-files", no_argument, NULL, 'T'}, 1764 {"uuencode", no_argument, NULL, 'B'}, 1765 {"vanilla-operation", no_argument, NULL, 'V'}, 1766 {"whole-size-limit", required_argument, NULL, 'l'}, 1767 1768 {"help", no_argument, &show_help, 1}, 1769 {"version", no_argument, &show_version, 1}, 1770 1771 { NULL, 0, NULL, 0 }, 1772}; 1773 1774/*---. 1775| ? | 1776`---*/ 1777 1778int 1779main (argc, argv) 1780 int argc; 1781 char *const *argv; 1782{ 1783 int status = EXIT_SUCCESS; 1784 int stdin_file_list = 0; 1785 int optchar; 1786 1787 program_name = argv[0]; 1788 sharpid = (int) getpid (); 1789 setlocale (LC_ALL, ""); 1790 1791 /* Set the text message domain. */ 1792 bindtextdomain (PACKAGE, LOCALEDIR); 1793 textdomain (PACKAGE); 1794 1795 while (optchar = getopt_long (argc, argv, 1796 "+$BCDFL:MPQSTVXZab:cd:fg:hl:mn:o:pqs:wxz", 1797 long_options, NULL), 1798 optchar != EOF) 1799 switch (optchar) 1800 { 1801 case '\0': 1802 break; 1803 1804 case '$': 1805#if DEBUG 1806 debugging_mode = 1; 1807#else 1808 error (0, 0, _("DEBUG was not selected at compile time")); 1809#endif 1810 break; 1811 1812 case 'B': 1813 set_file_mode ('B'); 1814 break; 1815 1816 case 'D': 1817 md5_count_mode = 0; 1818 break; 1819 1820 case 'F': 1821 mandatory_prefix_mode = 1; 1822 break; 1823 1824 case 'L': 1825 if (file_size_limit = atoi (optarg), file_size_limit > 1) 1826 file_size_limit--; 1827 split_file_mode = file_size_limit != 0; 1828 inhibit_piping_mode = 1; 1829 DEBUG_PRINT (_("Hard limit %dk\n"), file_size_limit); 1830 break; 1831 1832 case 'M': 1833 set_file_mode ('M'); 1834 break; 1835 1836 case 'P': 1837 inhibit_piping_mode = 1; 1838 break; 1839 1840 case 'Q': 1841 quiet_unshar_mode = 1; 1842 break; 1843 1844 case 'S': 1845 stdin_file_list = 1; 1846 break; 1847 1848 case 'V': 1849 vanilla_operation_mode = 1; 1850 break; 1851 1852 case 'T': 1853 set_file_mode ('T'); 1854 break; 1855 1856 case 'X': 1857 query_user_mode = 1; 1858 check_existing_mode = 1; 1859 break; 1860 1861 case 'b': 1862 bits_per_compressed_byte = atoi (optarg); 1863 /* Fall through. */ 1864 1865 case 'C': 1866 case 'Z': 1867 if (optchar == 'C') 1868 error (0, 0, _("-C is being deprecated, use -Z instead")); 1869 set_file_mode ('Z'); 1870 break; 1871 1872 case 'a': 1873 net_headers_mode = 1; 1874 break; 1875 1876 case 'c': 1877 cut_mark_mode = 1; 1878 break; 1879 1880 case 'd': 1881 here_delimiter = optarg; 1882 break; 1883 1884 case 'f': 1885 basename_mode = 1; 1886 break; 1887 1888 case 'h': 1889 usage (EXIT_SUCCESS); 1890 break; 1891 1892 case 'l': 1893 if (file_size_limit = atoi (optarg), file_size_limit > 1) 1894 file_size_limit--; 1895 split_file_mode = 0; 1896 DEBUG_PRINT (_("Soft limit %dk\n"), file_size_limit); 1897 break; 1898 1899 case 'm': 1900 timestamp_mode = 0; 1901 break; 1902 1903 case 'n': 1904 archive_name = optarg; 1905 break; 1906 1907 case 'o': 1908 strcpy (output_base_name, optarg); 1909 if (!strchr (output_base_name, '%')) 1910 strcat (output_base_name, ".%02d"); 1911 part_number = 0; 1912 open_output (); 1913 break; 1914 1915 case 'p': 1916 intermixed_parameter_mode = 1; 1917 break; 1918 1919 case 'q': 1920 quiet_mode = 1; 1921 break; 1922 1923 case 's': 1924 submitter_address = optarg; 1925 break; 1926 1927 case 'w': 1928 character_count_mode = 0; 1929 break; 1930 1931 case 'x': 1932 check_existing_mode = 0; 1933 break; 1934 1935 case 'g': 1936 gzip_compression_level = atoi (optarg); 1937 /* Fall through. */ 1938 1939 case 'z': 1940 set_file_mode ('z'); 1941 break; 1942 1943 default: 1944 usage (EXIT_FAILURE); 1945 } 1946 1947 /* Internationalized shell scripts are not vanilla. */ 1948 if (vanilla_operation_mode) 1949 no_i18n = 1; 1950 1951 if (show_version) 1952 { 1953 printf ("%s - GNU %s %s\n", program_name, PACKAGE, VERSION); 1954 exit (EXIT_SUCCESS); 1955 } 1956 1957 if (show_help) 1958 usage (EXIT_SUCCESS); 1959 1960 if (print_text_dom_dir != 0) 1961 { 1962 /* Support for internationalized shell scripts is only usable with 1963 GNU gettext. If we don't use it simply mark it as not available. */ 1964#if !defined ENABLE_NLS || defined HAVE_CATGETS \ 1965 || (defined HAVE_GETTEXT && !defined __USE_GNU_GETTEXT) 1966 exit (EXIT_FAILURE); 1967#else 1968 extern const char _nl_default_dirname[]; /* Defined in dcgettext.c */ 1969 puts (_nl_default_dirname); 1970 exit (EXIT_SUCCESS); 1971#endif 1972 } 1973 1974 line_prefix = (here_delimiter[0] == DEFAULT_LINE_PREFIX_1 1975 ? DEFAULT_LINE_PREFIX_2 1976 : DEFAULT_LINE_PREFIX_1); 1977 1978 here_delimiter_length = strlen (here_delimiter); 1979 1980 if (vanilla_operation_mode) 1981 { 1982 if (mixed_uuencoded_file_mode < 0) 1983 set_file_mode ('T'); 1984 1985 /* Implies -m, -w, -D, -F and -P. */ 1986 1987 timestamp_mode = 0; 1988 character_count_mode = 0; 1989 md5_count_mode = 0; 1990 mandatory_prefix_mode = 1; 1991 inhibit_piping_mode = 1; 1992 1993 /* Forbids -X. */ 1994 1995 if (query_user_mode) 1996 { 1997 error (0, 0, _("WARNING: No user interaction in vanilla mode")); 1998 query_user_mode = 0; 1999 } 2000 2001 /* Diagnose if not in -T state. */ 2002 2003 if (mixed_uuencoded_file_mode 2004 || uuencoded_file_mode 2005 || gzipped_file_mode 2006 || compressed_file_mode 2007 || intermixed_parameter_mode) 2008 error (0, 0, _("WARNING: Non-text storage options overridden")); 2009 } 2010 2011 /* Set defaults for unset options. */ 2012 2013 if (mixed_uuencoded_file_mode < 0) 2014 set_file_mode ('M'); 2015 2016 if (!submitter_address) 2017 submitter_address = get_submitter (NULL); 2018 2019 if (!output) 2020 output = stdout; 2021 2022 /* Maybe prepare to decide dynamically about file type. */ 2023 2024 if (mixed_uuencoded_file_mode || intermixed_parameter_mode) 2025 { 2026 memset ((char *) byte_is_binary, 1, 256); 2027 byte_is_binary['\b'] = 0; 2028 byte_is_binary['\t'] = 0; 2029 byte_is_binary['\f'] = 0; 2030 memset ((char *) byte_is_binary + 32, 0, 127 - 32); 2031 } 2032 2033 /* Maybe read file list from standard input. */ 2034 2035 if (stdin_file_list) 2036 { 2037 char stdin_buf[258]; /* FIXME: No fix limit in GNU... */ 2038 char **list; 2039 int max_argc; 2040 2041 argc = 0; 2042 max_argc = 32; 2043 list = (char **) xmalloc (max_argc * sizeof (char *)); 2044 stdin_buf[0] = 0; 2045 while (fgets (stdin_buf, sizeof (stdin_buf), stdin)) 2046 { 2047 if (argc == max_argc) 2048 list = (char **) xrealloc (list, 2049 (max_argc *= 2) * sizeof (char *)); 2050 if (stdin_buf[0] != '\0') 2051 stdin_buf[strlen (stdin_buf) - 1] = 0; 2052 list[argc] = xstrdup (stdin_buf); 2053 ++argc; 2054 stdin_buf[0] = 0; 2055 } 2056 argv = list; 2057 optind = 0; 2058 } 2059 2060 /* Diagnose various usage errors. */ 2061 2062 if (optind >= argc) 2063 { 2064 error (0, 0, _("No input files")); 2065 usage (EXIT_FAILURE); 2066 } 2067 2068 if (net_headers_mode && !archive_name) 2069 { 2070 error (0, 0, _("Cannot use -a option without -n")); 2071 usage (EXIT_FAILURE); 2072 } 2073 2074 if (file_size_limit && !part_number) 2075 { 2076 error (0, 0, _("Cannot use -l or -L option without -o")); 2077 usage (EXIT_FAILURE); 2078 } 2079 2080 /* Start making the archive file. */ 2081 2082 generate_full_header (argc - optind, &argv[optind]); 2083 2084 if (query_user_mode) 2085 { 2086 quiet_unshar_mode = 0; 2087 if (net_headers_mode) 2088 error (0, 0, _("PLEASE avoid -X shars on Usenet or public networks")); 2089 2090 fputs ("\ 2091shar_wish=\n", 2092 output); 2093 } 2094 2095 first_file_position = ftell (output); 2096 2097 /* Process positional parameters and files. */ 2098 2099 for (; optind < argc; optind++) 2100 if (intermixed_parameter_mode) 2101 if (strcmp (argv[optind], "-B") == 0) 2102 set_file_mode ('B'); 2103 else if (strcmp (argv[optind], "-T") == 0) 2104 set_file_mode ('T'); 2105 else if (strcmp (argv[optind], "-M") == 0) 2106 set_file_mode ('M'); 2107 else if (strcmp (argv[optind], "-z") == 0) 2108 set_file_mode ('z'); 2109 else if (strcmp (argv[optind], "-Z") == 0 2110 || strcmp (argv[optind], "-C") == 0) 2111 set_file_mode ('Z'); 2112 else 2113 { 2114 if (walktree (shar, argv[optind])) 2115 status = EXIT_FAILURE; 2116 } 2117 else 2118 { 2119 if (walktree (shar, argv[optind])) 2120 status = EXIT_FAILURE; 2121 } 2122 2123 /* Delete the sequence file, if any. */ 2124 2125 if (split_file_mode && part_number > 1) 2126 { 2127 fprintf (output, "\ 2128$echo '%s'\n", 2129 N_("You have unpacked the last part")); 2130 if (quiet_mode) 2131 fprintf (stderr, _("Created %d files\n"), part_number); 2132 } 2133 2134 fprintf (output, "\ 2135rm -fr _sh%05d\n\ 2136exit 0\n", 2137 sharpid); 2138 2139 exit (status); 2140} 2141