home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / f / futi14as.zip / LN.C < prev    next >
C/C++ Source or Header  |  1990-08-14  |  8KB  |  364 lines

  1. /* `ln' program to create links between files.
  2.    Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Mike Parker and David MacKenzie. */
  19.  
  20. #include <stdio.h>
  21. #include <sys/types.h>
  22. #include <errno.h>
  23. #include <getopt.h>
  24. #include "system.h"
  25. #include "backupfile.h"
  26.  
  27. #ifdef STDC_HEADERS
  28. #include <stdlib.h>
  29. #else
  30. char *getenv ();
  31.  
  32. extern int errno;
  33. #endif
  34.  
  35. #ifndef _POSIX_SOURCE
  36. int link ();
  37. #endif
  38.  
  39. #ifdef S_IFLNK
  40. int symlink ();
  41. #endif
  42.  
  43. char *basename ();
  44. enum backup_type get_version ();
  45. int do_link ();
  46. int isdir ();
  47. int yesno ();
  48. void error ();
  49. void strip_trailing_slashes ();
  50. void usage ();
  51.  
  52. /* A pointer to the function used to make links.  This will point to either
  53.    `link' or `symlink'. */
  54. int (*linkfunc) ();
  55.  
  56. /* If nonzero, make symbolic links; otherwise, make hard links.  */
  57. int symbolic_link;
  58.  
  59. /* If nonzero, ask the user before removing existing files.  */
  60. int interactive;
  61.  
  62. /* If nonzero, remove existing files unconditionally.  */
  63. int remove_existing_files;
  64.  
  65. /* If nonzero, list each file as it is moved. */
  66. int verbose;
  67.  
  68. /* If nonzero, allow the superuser to make hard links to directories. */
  69. int hard_dir_link;
  70.  
  71. /* The name by which the program was run, for error messages.  */
  72. char *program_name;
  73.  
  74. struct option long_options[] = 
  75. {
  76.   {"backup", 0, NULL, 'b'},
  77.   {"directory", 0, &hard_dir_link, 1},
  78.   {"force", 0, NULL, 'f'},
  79.   {"interactive", 0, NULL, 'i'},
  80.   {"suffix", 1, NULL, 'S'},
  81.   {"symbolic", 0, &symbolic_link, 1},
  82.   {"verbose", 0, &verbose, 1},
  83.   {"version-control", 1, NULL, 'V'},
  84.   {NULL, 0, NULL, 0}
  85. };
  86.  
  87. void
  88. main (argc, argv)
  89.      int argc;
  90.      char **argv;
  91. {
  92.   int c;
  93.   int ind;
  94.   int errors;
  95.   int make_backups = 0;
  96.   char *version;
  97.  
  98.   version = getenv ("SIMPLE_BACKUP_SUFFIX");
  99.   if (version)
  100.     simple_backup_suffix = version;
  101.   version = getenv ("VERSION_CONTROL");
  102.   program_name = argv[0];
  103.   linkfunc = link;
  104.   symbolic_link = remove_existing_files = interactive = verbose
  105.     = hard_dir_link = 0;
  106.   errors = 0;
  107.  
  108.   while ((c = getopt_long (argc, argv, "bdfisvFS:V:", long_options, &ind))
  109.      != EOF)
  110.     {
  111.       switch (c)
  112.     {
  113.     case 0:            /* Long-named option. */
  114.        break;
  115.     case 'b':
  116.       make_backups = 1;
  117.       break;
  118.     case 'd':
  119.     case 'F':
  120.       hard_dir_link = 1;
  121.       break;
  122.     case 'f':
  123.       remove_existing_files = 1;
  124.       interactive = 0;
  125.       break;
  126.     case 'i':
  127.       remove_existing_files = 0;
  128.       interactive = 1;
  129.       break;
  130.     case 's':
  131. #ifdef S_IFLNK
  132.       symbolic_link = 1;
  133. #else
  134.       error (0, 0, "symbolic links not supported; making hard links");
  135. #endif
  136.       break;
  137.     case 'v':
  138.       verbose = 1;
  139.       break;
  140.     case 'S':
  141.       simple_backup_suffix = optarg;
  142.       break;
  143.     case 'V':
  144.       version = optarg;
  145.       break;
  146.     default:
  147.       usage ();
  148.       break;
  149.     }
  150.     }
  151.   if (optind == argc)
  152.     usage ();
  153.  
  154.   if (make_backups)
  155.     backup_type = get_version (version);
  156.  
  157. #ifdef S_IFLNK
  158.   if (symbolic_link)
  159.     linkfunc = symlink;
  160. #endif
  161.  
  162.   if (optind == argc - 1)
  163.     errors = do_link (argv[optind], ".");
  164.   else if (optind == argc - 2)
  165.     {
  166.       strip_trailing_slashes (argv[optind + 1]);
  167.       errors = do_link (argv[optind], argv[optind + 1]);
  168.     }
  169.   else
  170.     {
  171.       char *to;
  172.  
  173.       to = argv[argc - 1];
  174.       strip_trailing_slashes (to);
  175.       if (!isdir (to))
  176.     error (1, 0, "when making multiple links, last argument must be a directory");
  177.       for (; optind < argc - 1; ++optind)
  178.     errors += do_link (argv[optind], to);
  179.     }
  180.  
  181.   exit (errors != 0);
  182. }
  183.  
  184. /* Make a link NEW to existing file OLD.
  185.    If NEW is a directory, put the link to OLD in that directory.
  186.    Return 1 if there is an error, otherwise 0.  */
  187.  
  188. int
  189. do_link (old, new)
  190.      char *old;
  191.      char *new;
  192. {
  193.   struct stat new_stats;
  194.   char *new_backup = NULL;
  195.  
  196.   strip_trailing_slashes (old);
  197.  
  198.   /* Since link follows symlinks, isdir uses stat instead of lstat. */
  199.   if (!symbolic_link && !hard_dir_link && isdir (old))
  200.     {
  201.       error (0, 0, "%s: hard link not allowed for directory", old);
  202.       return 1;
  203.     }
  204.   if (isdir (new))
  205.     {
  206.       /* Target is a directory; build the full filename. */
  207.       char *new_new;
  208.       char *old_base;
  209.  
  210.       old_base = basename (old);
  211.       new_new = (char *) alloca (strlen (old_base) + 1 + strlen (new) + 1);
  212.       sprintf (new_new, "%s/%s", new, old_base);
  213.       new = new_new;
  214.     }
  215.  
  216.   if (lstat (new, &new_stats) == 0)
  217.     {
  218.       if ((new_stats.st_mode & S_IFMT) == S_IFDIR)
  219.     {
  220.       error (0, 0, "%s: cannot overwrite directory", new);
  221.       return 1;
  222.     }
  223.       if (interactive)
  224.     {
  225.       fprintf (stderr, "%s: replace `%s'? ", program_name, new);
  226.       if (!yesno ())
  227.         return 0;
  228.     }
  229.       else if (!remove_existing_files)
  230.     {
  231.       error (0, 0, "%s: File exists", new);
  232.       return 1;
  233.     }
  234.  
  235.       if (backup_type != none)
  236.     {
  237.       new_backup = find_backup_file_name (new);
  238.       if (new_backup == NULL)
  239.         error (1, 0, "virtual memory exhausted");
  240.       if (rename (new, new_backup))
  241.         {
  242.           if (errno != ENOENT)
  243.         {
  244.           error (0, errno, "cannot backup `%s'", new);
  245.           free (new_backup);
  246.           return 1;
  247.         }
  248.           else
  249.         {
  250.           free (new_backup);
  251.           new_backup = NULL;
  252.         }
  253.         }
  254.     }
  255.       else if (unlink (new) && errno != ENOENT)
  256.     {
  257.       error (0, errno, "cannot remove old link to `%s'", new);
  258.       return 1;
  259.     }
  260.     }
  261.   else if (errno != ENOENT)
  262.     {
  263.       error (0, errno, "%s", new);
  264.       return 1;
  265.     }
  266.        
  267.   if (verbose)
  268.     printf ("%s -> %s\n", old, new);
  269.  
  270.   if ((*linkfunc) (old, new) == 0)
  271.     {
  272.       if (new_backup)
  273.     free (new_backup);
  274.       return 0;
  275.     }
  276.  
  277.   error (0, errno, "cannot %slink `%s' to `%s'",
  278. #ifdef S_IFLNK
  279.          linkfunc == symlink ? "symbolic " : "",
  280. #else
  281.          "",
  282. #endif
  283.          old, new);
  284.  
  285.   if (new_backup)
  286.     {
  287.       if (rename (new_backup, new))
  288.     error (0, errno, "cannot un-backup `%s'", new);
  289.       free (new_backup);
  290.     }
  291.   return 1;
  292. }
  293.  
  294. /* Return 1 if the user gives permission, 0 if not.  */
  295.  
  296. int
  297. yesno ()
  298. {
  299.   int c;
  300.   int rv;
  301.  
  302.   fflush (stderr);
  303.   c = getchar ();
  304.   rv = (c == 'y') || (c == 'Y');
  305.   while (c != EOF && c != '\n')
  306.     c = getchar ();
  307.  
  308.   return rv;
  309. }
  310.  
  311. /* Return 1 if FILE is a directory or a symlink to a directory;
  312.    otherwise 0. */
  313.  
  314. int
  315. isdir (file)
  316.      char *file;
  317. {
  318.   struct stat stats;
  319.  
  320.   return stat (file, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR;
  321. }
  322.  
  323. /* Return NAME with any leading path stripped off.  */
  324.  
  325. char *
  326. basename (name)
  327.      char *name;
  328. {
  329.   char *base;
  330.  
  331.   base = rindex (name, '/');
  332.   return base ? base + 1 : name;
  333. }
  334.  
  335. /* Remove trailing slashes from PATH. */
  336.  
  337. void
  338. strip_trailing_slashes (path)
  339.      char *path;
  340. {
  341.   int last;
  342.  
  343.   last = strlen (path) - 1;
  344.   while (last > 0 && path[last] == '/')
  345.     path[last--] = '\0';
  346. }
  347.  
  348. void
  349. usage ()
  350. {
  351.   fprintf (stderr, "\
  352. Usage: %s [-bdfisvF] [-S backup-suffix] [-V {numbered,existing,simple}]\n\
  353.        [+version-control {numbered,existing,simple}] [+backup] [+directory]\n\
  354.        [+force] [+interactive] [+symbolic] [+verbose] [+suffix backup-suffix]\n\
  355.        source [dest]\n\
  356. \n\
  357.        %s [-bdfisvF] [-S backup-suffix] [-V {numbered,existing,simple}]\n\
  358.        [+version-control {numbered,existing,simple}] [+backup] [+directory]\n\
  359.        [+force] [+interactive] [+symbolic] [+verbose] [+suffix backup-suffix]\n\
  360.        source... directory\n",
  361.        program_name, program_name);
  362.   exit (1);
  363. }
  364.