home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / rcs / rcs56src / source / cvs / src / update.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-23  |  14.3 KB  |  521 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: update.c,v 1.27.1.2 91/02/06 18:30:07 berliner Exp $";
  3. #endif 
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  *    "update" updates the version in the present directory with respect to
  12.  *    the RCS repository.  The present version must have been created by
  13.  *    "checkout".  The user can keep up-to-date by calling "update" whenever
  14.  *    he feels like it.
  15.  *
  16.  *    The present version can be committed by "commit", but this keeps the
  17.  *    version in tact.
  18.  *
  19.  *    "update" accepts the following options:
  20.  *        -p    Prunes empty directories
  21.  *        -l    Local; does not do a recursive update
  22.  *        -q    Quiet; does not print a message when
  23.  *                recursively updating
  24.  *        -Q    Really quiet
  25.  *        -d    Directory; causes update to create new directories
  26.  *                as they are added to the RCS repository
  27.  *        -f    Forces a match for the -r revision
  28.  *        -r tag    Revision; only extract from revision "tag"
  29.  *        -D date    Updates to the revision specified by "date"
  30.  *
  31.  *    Arguments following the options are taken to be file names
  32.  *    to be updated, rather than updating the entire directory.
  33.  *
  34.  *    Modified or non-existent RCS files are checked out and reported
  35.  *    as U <user_file>
  36.  *
  37.  *    Modified user files are reported as M <user_file>.  If both the
  38.  *    RCS file and the user file have been modified, the user file
  39.  *    is replaced by the result of rcsmerge, and a backup file is
  40.  *    written for the user in .#file.version.  If this throws up
  41.  *    irreconcilable differences, the file is reported as C <user_file>,
  42.  *    and as M <user_file> otherwise.
  43.  *
  44.  *    Files added but not yet committed are reported as A <user_file>.
  45.  *    Files removed but not yet decommitted are reported as R <user_file>.
  46.  *
  47.  *    If the current directory contains subdirectories that hold
  48.  *    concurrent versions, these are updated too.  If the -d option
  49.  *    was specified, new directories added to the repository are
  50.  *    automatically created and updated as well.
  51.  */
  52.  
  53. #include <sys/types.h>
  54. #include <sys/stat.h>
  55. #include "dir.h"
  56. #include "cvs.h"
  57.  
  58. char update_dir[MAXPATHLEN];
  59. int update_recursive = 1;
  60. int update_build_dirs = 0;
  61. int update_prune_dirs = 0;
  62.  
  63. static int really_recursive = 1;
  64.  
  65. update(argc, argv)
  66.     int argc;
  67.     char *argv[];
  68. {
  69.     FILE *fp;
  70.     int c, err = 0;
  71.  
  72.     if (argc == -1)
  73.     update_usage();
  74.     optind = 1;
  75.     while ((c = getopt(argc, argv, "pflQqdr:D:")) != -1) {
  76.     switch (c) {
  77.     case 'l':
  78.         really_recursive = 0;
  79.         update_recursive = 0;
  80.         break;
  81.     case 'Q':
  82.         really_quiet = 1;
  83.         /* FALL THROUGH */
  84.     case 'q':
  85.         quiet = 1;
  86.         break;
  87.     case 'd':
  88.         update_build_dirs = 1;
  89.         break;
  90.     case 'f':
  91.         force_tag_match = 1;
  92.         break;
  93.     case 'r':
  94.         (void) strcpy(Tag, optarg);
  95.         break;
  96.     case 'D':
  97.         Make_Date(optarg, Date);
  98.         break;
  99.     case 'p':
  100.         update_prune_dirs = 1;
  101.         break;
  102.     case '?':
  103.     default:
  104.         update_usage();
  105.         break;
  106.     }
  107.     }
  108.     argc -= optind;
  109.     argv += optind;
  110.     if (!isdir(CVSADM)) {
  111.     if (!quiet)
  112.         warn(0, "warning: no %s directory found", CVSADM);
  113.     if (argc <= 0) {
  114.         err += update_descend(update_recursive);
  115.     } else {
  116.         int i;
  117.  
  118.         for (i = 0; i < argc; i++) {
  119.         if (isdir(argv[i])) {
  120.             (void) strcat(Dlist, " ");
  121.             (void) strcat(Dlist, argv[i]);
  122.         } else {
  123.             warn(0, "nothing known about %s", argv[i]);
  124.             err++;
  125.         }
  126.         }
  127.         err += update_process_lists();
  128.     }
  129.     return (err);
  130.     }
  131.     Name_Repository();
  132.     Reader_Lock();
  133.     if (argc <= 0) {
  134.     /*
  135.      * When updating the entire directory, and recursively building
  136.      * directories, must make sure that the "static" file in the
  137.      * administration is removed before calling Find_Names().
  138.      */
  139.     if (update_build_dirs)
  140.         (void) unlink(CVSADM_ENTSTAT);
  141.     if (force_tag_match && (Tag[0] != '\0' || Date[0] != '\0'))
  142.         Find_Names(&fileargc, fileargv, ALLPLUSATTIC);
  143.     else
  144.         Find_Names(&fileargc, fileargv, ALL);
  145.     fp = open_file(CVSADM_MOD, "w+"); /* create a NULL Mod file */
  146.     (void) fclose(fp);
  147.     argc = fileargc;
  148.     argv = fileargv;
  149.     } else {
  150.     /*
  151.      * Not recursive if files were specified on the command line
  152.      */
  153.     update_recursive = 0;
  154.     }
  155.     if (Collect_Sets(argc, argv) != 0)
  156.     error(0, "failed; correct the above errors first");
  157.     free_names(&fileargc, fileargv);
  158.     err += update_process_lists();
  159.     /*
  160.      * XXX - Might be nice to sort the Mod file here, removing unique
  161.      * entries as we go, but it's currently not necessary, as "diff"
  162.      * is the only one that uses it, and he does the sort "as needed".
  163.      */
  164.     Lock_Cleanup(0);
  165.     /*
  166.      * Make directories, and descend them if requested to.
  167.      */
  168.     err += update_make_dirs(update_build_dirs && update_recursive);
  169.     err += update_descend(update_recursive);
  170.     Lock_Cleanup(0);
  171.     return (err);
  172. }
  173.  
  174. /*
  175.  * Process the lists created by Collect_Sets().
  176.  */
  177. static
  178. update_process_lists()
  179. {
  180.     char backup[MAXPATHLEN], dlist[MAXLISTLEN];
  181.     FILE *fp;
  182.     char *cp;
  183.     int update_Files = 0, err = 0;
  184.     int status;        /* UNOFFICIAL - bug fix */
  185.  
  186.     /*
  187.      * Wlist is the "remove entry" list.
  188.      */
  189.     for (cp = strtok(Wlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  190.     update_Files = 1;
  191.     (void) strcpy(User, cp);
  192.     Scratch_Entry(User);
  193.     (void) unlink(User);
  194.     }
  195.     /*
  196.      * Olist is the "needs checking out" list.
  197.      */
  198.     for (cp = strtok(Olist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  199.     update_Files = 1;
  200.     (void) strcpy(User, cp);
  201.     Locate_RCS();
  202.     (void) sprintf(backup, "%s%c%s%s", CVSADM, DIRSEP, CVSPREFIX, User);
  203.     if (isreadable(User))
  204.         rename_file(User, backup);
  205.     else
  206.         (void) unlink(backup);
  207.     if (Tag[0] != '\0' || Date[0] != '\0') {
  208.         Version_Number(Rcs, Tag, Date, VN_Rcs);
  209.         (void) sprintf(prog, "%s -q -r%s %s %s", RCS_CO, VN_Rcs, Rcs, User);
  210.     } else {
  211.         (void) sprintf(prog, "%s -q %s %s", RCS_CO, Rcs, User);
  212.     }
  213.     if (system(prog) == 0) {
  214.         if (cvswrite == TRUE)
  215.         xchmod(User, 1);
  216.         Version_TS(Rcs, Tag, User);
  217.         Register(User, VN_Rcs, TS_User);
  218.         if (!really_quiet) {
  219.         if (update_dir[0])
  220.             printf("U %s%c%s\n", update_dir, DIRSEP, User);
  221.         else
  222.             printf("U %s\n", User);
  223.         }
  224.     } else {
  225.         if (isreadable(backup))
  226.         rename_file(backup, User);
  227.         warn(0, "could not check out %s", User);
  228.         err++;
  229.     }
  230.     (void) unlink(backup);
  231.     }
  232.     /*
  233.      * Mlist is the "modified, needs checking in" list.
  234.      */
  235.     for (cp = strtok(Mlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  236.     update_Files = 1;
  237.     (void) strcpy(User, cp);
  238.     if (!really_quiet) {
  239.         if (update_dir[0])
  240.         printf("M %s%c%s\n", update_dir, DIRSEP, User);
  241.         else
  242.         printf("M %s\n", User);
  243.     }
  244.     fp = open_file(CVSADM_MOD, "a");
  245.     if (fprintf(fp, "%s\n", User) == EOF)
  246.         error(1, "cannot write %s", CVSADM_MOD);
  247.     (void) fclose(fp);
  248.     }
  249.     /*
  250.      * Alist is the "to be added" list.
  251.      */
  252.     for (cp = strtok(Alist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  253.     update_Files = 1;
  254.     (void) strcpy(User, cp);
  255.     if (!really_quiet) {
  256.         if (update_dir[0])
  257.         printf("A %s%c%s\n", update_dir, DIRSEP, User);
  258.         else
  259.         printf("A %s\n", User);
  260.     }
  261.     }
  262.     /*
  263.      * Rlist is the "to be removed" list.
  264.      */
  265.     for (cp = strtok(Rlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  266.     update_Files = 1;
  267.     (void) strcpy(User, cp);
  268.     if (!really_quiet) {
  269.         if (update_dir[0])
  270.         printf("R %s%c%s\n", update_dir, DIRSEP, User);
  271.         else
  272.         printf("R %s\n", User);
  273.     }
  274.     }
  275.     /*
  276.      * Glist is the "modified, needs merging" list.
  277.      *
  278.      * The users currently modified file is moved to a backup file
  279.      * name ".#filename.version", so that it will stay around for about
  280.      * three days before being automatically removed by some cron
  281.      * daemon.  The "version" is the version of the file that the
  282.      * user was most up-to-date with before the merge.
  283.      */
  284.     for (cp = strtok(Glist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  285.     update_Files = 1;
  286.     (void) strcpy(User, cp);
  287.     Locate_RCS();
  288.     Version_TS(Rcs, Tag, User);
  289.     (void) sprintf(backup, "%s%s.%s", BAKPREFIX, User, VN_User);
  290.     (void) unlink(backup);
  291.     copy_file(User, backup);
  292.     xchmod(User, 1);
  293.     (void) sprintf(prog, "%s -r%s %s", RCS_MERGE, VN_User, Rcs);
  294. /* UNOFFICIAL CHANGE - original code commented out
  295.     if (system(prog) != 0) {
  296. */
  297. /* UNOFFICIAL - start of bug fix
  298.      * rcsmerge now provides a return status similar to diff(1).
  299.      * If there were conflicts, the return status is 1.  It
  300.      * appears that this version of CVS was written assuming that
  301.      * rcsmerge returned 0 in this case.
  302.      */
  303.     status = system(prog);
  304.      if (WEXITSTATUS(status) == 2) {
  305. /* UNOFFICIAL - end of bug fix */
  306.         warn(0, "could not merge revision %s of %s",
  307.          VN_User, User);
  308.         warn(0, "backup file for %s is in %s", User, backup);
  309.         err++;
  310.         continue;
  311.     }
  312.     Register(User, VN_Rcs, TS_Rcs);
  313. /* UNOFFICIAL CHANGE - original code commented out
  314.     (void) sprintf(prog, "%s -s '%s' %s", GREP, RCS_MERGE_PAT, User);
  315.     if (system(prog) == 0) {
  316. */
  317. /* UNOFFICIAL - start of bug fix */
  318.      if (WEXITSTATUS(status) == 1) {
  319. /* UNOFFICIAL - end of bug fix */
  320.         warn(0, "conflicts found in %s", User);
  321.         if (!really_quiet) {
  322.         if (update_dir[0])
  323.             printf("C %s%c%s\n", update_dir, DIRSEP, User);
  324.         else
  325.             printf("C %s\n", User);
  326.         }
  327.     } else {
  328.         if (!really_quiet) {
  329.         if (update_dir[0])
  330.             printf("M %s%c%s\n", update_dir, DIRSEP, User);
  331.         else
  332.             printf("M %s\n", User);
  333.         }
  334.     }
  335.     fp = open_file(CVSADM_MOD, "a");
  336.     if (fprintf(fp, "%s\n", User) == EOF)
  337.         error(1, "cannot write %s", CVSADM_MOD);
  338.     (void) fclose(fp);
  339.     }
  340.     if (Dlist[0]) {
  341.     int save_recursive = update_recursive;
  342.  
  343.     update_recursive = really_recursive;
  344.     Lock_Cleanup(0);        /* cleanup locks before descending */
  345.     (void) strcpy(dlist, Dlist);    /* to get it on the stack... */
  346.     for (cp = strtok(dlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  347.         err += update_descend_dir(cp);
  348.     }
  349.     update_recursive = save_recursive;
  350.     }
  351.     if (update_Files != 0)
  352.     Entries2Files();
  353.     return (err);
  354. }
  355.  
  356. /*
  357.  * When automatically creating directories from the repository in the
  358.  * local work directory, we scan for directories that don't exist locally
  359.  * and create them with a NULL administration directory for now, which
  360.  * is filled by update later.
  361.  */
  362. static
  363. update_make_dirs(doit)
  364.     int doit;
  365. {
  366.     char fname[MAXPATHLEN], tmp[MAXPATHLEN];
  367.     DIR *dirp;
  368.     struct dirent *dp;
  369.     int err = 0;
  370.  
  371.     if (doit) {
  372.     if ((dirp = opendir(Repository)) == NULL) {
  373.         warn(0, "cannot open directory %s", Repository);
  374.         err++;
  375.     } else while ((dp = readdir(dirp)) != NULL) {
  376.         if (strcmp(dp->d_name, ".") == 0 ||
  377.         strcmp(dp->d_name, "..") == 0 ||
  378.         stricmp(dp->d_name, CVSATTIC) == 0 ||
  379.         stricmp(dp->d_name, CVSLCK) == 0)
  380.         continue;
  381.         (void) sprintf(fname, "%s%c%s", Repository, DIRSEP, dp->d_name);
  382.         (void) sprintf(tmp, "%s%c%s", dp->d_name, DIRSEP, CVSADM);
  383.         if (!isdir(fname))
  384.         continue;
  385.         if (islink(dp->d_name) || isdir(tmp))
  386.         continue;
  387.         if (!isdir(dp->d_name) && isfile(dp->d_name)) {
  388.         warn(0, "file %s should be a directory; please move it", dp->d_name);
  389.         err++;
  390.         } else {
  391.         make_directory(dp->d_name);
  392.         if (chdir(dp->d_name) < 0) {
  393.             warn(0, "cannot chdir to %s", dp->d_name);
  394.             err++;
  395.         } else {
  396.             (void) strcpy(tmp, Repository);
  397.             (void) strcpy(Repository, fname);
  398.             Create_Admin(Repository, DFLT_RECORD);
  399.             (void) chdir("..");
  400.             (void) strcpy(Repository, tmp);
  401.         }
  402.         }
  403.     }
  404.     if (dirp)
  405.         (void) closedir(dirp);
  406.     }
  407.     return (err);
  408. }
  409.  
  410. /*
  411.  * If doalldirs is set, does a recursive update by calling update_descend_dir()
  412.  * for each file in the current directory.
  413.  */
  414. static
  415. update_descend(doalldirs)
  416.     int doalldirs;
  417. {
  418.     DIR *dirp;
  419.     struct dirent *dp;
  420.     int err = 0;
  421.  
  422.     if (doalldirs) {
  423.     if ((dirp = opendir(".")) == NULL) {
  424.         err++;
  425.     } else {
  426.         while ((dp = readdir(dirp)) != NULL) {
  427.         if (strcmp(dp->d_name, ".") == 0 ||
  428.             strcmp(dp->d_name, "..") == 0)
  429.             continue;
  430.         err += update_descend_dir(dp->d_name);
  431.         }
  432.         (void) closedir(dirp);
  433.     }
  434.     }
  435.     return (err);
  436. }
  437.  
  438. /*
  439.  * This is the recursive function that walks the argument directory looking
  440.  * for sub-directories that have CVS administration files in them
  441.  * and updates them recursively.
  442.  *
  443.  * Note that we do not follow symbolic links here, which is a feature!
  444.  */
  445. static
  446. update_descend_dir(dir)
  447.     char *dir;
  448. {
  449.     char cwd[MAXPATHLEN], fname[MAXPATHLEN];
  450.     char *cp;
  451.     int err;
  452.  
  453.     (void) sprintf(fname, "%s%c%s", dir, DIRSEP, CVSADM);
  454.     if (!isdir(dir) || islink(dir) || !isdir(fname))
  455.     return (0);
  456.     if (getwd(cwd) == NULL) {
  457.     warn(0, "cannot get working directory: %s", cwd);
  458.     return (1);
  459.     }
  460.     if (update_dir[0] == '\0')
  461.     (void) strcpy(update_dir, dir);
  462.     else {
  463.     (void) strcat(update_dir, DIRSEPSTR);
  464.     (void) strcat(update_dir, dir);
  465.     }
  466.     if (!quiet)
  467.     printf("%s %s: Updating %s\n", progname, command, update_dir);
  468.     if (chdir(dir) < 0) {
  469.     warn(1, "cannot chdir to %s", update_dir);
  470.     err = 1;
  471.     goto out;
  472.     }
  473.     err = update(0, (char **)0);
  474.     if ((cp = rindex_sep(update_dir)) != NULL)
  475.     *cp = '\0';
  476.     else
  477.     update_dir[0] = '\0';
  478. out:
  479.     if (chdir(cwd) < 0)
  480.     error(1, "cannot chdir to %s", cwd);
  481.     if (update_prune_dirs && isemptydir(dir)) {
  482.     (void) sprintf(prog, "%s -fr %s", RM, dir);
  483.     (void) system(prog);
  484.     }
  485.     return (err);
  486. }
  487.  
  488. /*
  489.  * Returns 1 if the argument directory is completely empty, other than
  490.  * the existence of the CVS.adm directory entry.  Zero otherwise.
  491.  */
  492. isemptydir(dir)
  493.     char *dir;
  494. {
  495.     DIR *dirp;
  496.     struct dirent *dp;
  497.  
  498.     if ((dirp = opendir(dir)) == NULL) {
  499.         warn(0, "cannot open directory %s for empty check", dir);
  500.     return (0);
  501.     }
  502.     while ((dp = readdir(dirp)) != NULL) {
  503.         if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 &&
  504.             stricmp(dp->d_name, CVSADM) != 0) {
  505.             (void) closedir(dirp);
  506.             return (0);
  507.         }
  508.     }
  509.     (void) closedir(dirp);
  510.     return (1);
  511. }
  512.  
  513. static
  514. update_usage()
  515. {
  516.     (void) fprintf(stderr,
  517.            "Usage: %s %s [-Qqlfp] [-d] [-r tag|-D date] [files...]\n",
  518.            progname, command);
  519.     exit(1);
  520. }
  521.