update changelog
[alioth/cvs.git] / src / main.c
index 45208fa..9854832 100644 (file)
 #include "strftime.h"
 #include "xgethostname.h"
 
+#ifdef USE_LIBBSD
+uint32_t arc4random(void);
+#endif
+
 const char *program_name;
 const char *program_path;
 const char *cvs_cmd_name;
@@ -170,6 +174,7 @@ static const struct cmd
 #ifdef SERVER_SUPPORT
     { "server",   NULL,       NULL,        server,    CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
 #endif
+    { "suck",     NULL,       NULL,        suck,      0 },
     { "status",   "st",       "stat",      cvsstatus, CVS_CMD_USES_WORK_DIR },
     { "tag",      "ta",       "freeze",    cvstag,    CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
     { "unedit",   NULL,       NULL,        unedit,    CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
@@ -283,6 +288,7 @@ static const char *const opt_usage[] =
     "    -q           Cause CVS to be somewhat quiet.\n",
     "    -r           Make checked-out files read-only.\n",
     "    -w           Make checked-out files read-write (default).\n",
+    "    -g           Force group-write permissions on checked-out files.\n",
     "    -n           Do not execute anything that will change the disk.\n",
     "    -t           Show trace of program execution (repeat for more\n",
     "                 verbosity) -- try with -n.\n",
@@ -465,38 +471,6 @@ enum {COMMITID_RAW_SIZE = (sizeof(time_t) + RANDOM_BYTES)};
 static char const alphabet[62] =
   "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
-/* Divide BUF by D, returning the remainder.  Replace BUF by the
-   quotient.  BUF[0] is the most significant part of BUF.
-   D must not exceed UINT_MAX >> CHAR_BIT.  */
-static unsigned int
-divide_by (unsigned char buf[COMMITID_RAW_SIZE], unsigned int d)
-{
-    unsigned int carry = 0;
-    int i;
-    for (i = 0; i < COMMITID_RAW_SIZE; i++)
-    {
-       unsigned int byte = buf[i];
-       unsigned int dividend = (carry << CHAR_BIT) + byte;
-       buf[i] = dividend / d;
-       carry = dividend % d;
-    }
-    return carry;
-}
-
-static void
-convert (char const input[COMMITID_RAW_SIZE], char *output)
-{
-    static char const zero[COMMITID_RAW_SIZE] = { 0, };
-    unsigned char buf[COMMITID_RAW_SIZE];
-    size_t o = 0;
-    memcpy (buf, input, COMMITID_RAW_SIZE);
-    while (memcmp (buf, zero, COMMITID_RAW_SIZE) != 0)
-       output[o++] = alphabet[divide_by (buf, sizeof alphabet)];
-    if (! o)
-       output[o++] = '0';
-    output[o] = '\0';
-}
-
 
 int
 main (int argc, char **argv)
@@ -511,7 +485,7 @@ main (int argc, char **argv)
     int help = 0;              /* Has the user asked for help?  This
                                   lets us support the `cvs -H cmd'
                                   convention to give help for cmd. */
-    static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa";
+    static const char short_options[] = "+QqrwgtnRvb:T:e:d:Hfz:s:xal";
     static struct option long_options[] =
     {
         {"help", 0, NULL, 'H'},
@@ -658,6 +632,13 @@ main (int argc, char **argv)
            case 'w':
                cvswrite = 1;
                break;
+           case 'g':
+               /*
+                * Force full write permissions for the group.
+                * See the user's manual for details and dangers.
+                */
+               umask(umask(S_IRWXG|S_IRWXO) & S_IRWXO);
+               break;
            case 't':
                trace++;
                break;
@@ -669,6 +650,9 @@ main (int argc, char **argv)
                noexec = 1;
                logoff = 1;
                break;
+           case 'l':
+               /* no-op to simply ignore the old -l option */
+               break;
            case 'v':
                (void) fputs ("\n", stdout);
                version (0, NULL);    
@@ -676,6 +660,7 @@ main (int argc, char **argv)
                (void) fputs ("\
 Copyright (C) 2005 Free Software Foundation, Inc.\n\
 \n\
+Portions contributed by Thorsten Glaser for the MirOS Project.\n\
 Senior active maintainers include Larry Jones, Derek R. Price,\n\
 and Mark D. Baushke.  Please see the AUTHORS and README files from the CVS\n\
 distribution kit for a complete list of contributors and copyrights.\n",
@@ -764,56 +749,11 @@ distribution kit for a complete list of contributors and copyrights.\n",
     if (argc < 1)
        usage (usg);
 
-    if (readonlyfs && !really_quiet) {
-       error (0, 0,
-              "WARNING: Read-only repository access mode selected via `cvs -R'.\n\
-Using this option to access a repository which some users write to may\n\
-cause intermittent sandbox corruption.");
-    }
-
     /* Calculate the cvs global session ID */
 
-    {
-       char buf[COMMITID_RAW_SIZE] = { 0, };
-       char out[COMMITID_RAW_SIZE * 2];
-       ssize_t len = 0;
-       time_t rightnow = time (NULL);
-       char *startrand = buf + sizeof (time_t);
-       unsigned char *p = (unsigned char *) startrand;
-       size_t randbytes = RANDOM_BYTES;
-       int flags = O_RDONLY;
-       int fd;
-#ifdef O_NOCTTY
-       flags |= O_NOCTTY;
-#endif
-       if (rightnow != (time_t)-1)
-               while (rightnow > 0) {
-                   *--p = rightnow % (UCHAR_MAX + 1);
-                   rightnow /= UCHAR_MAX + 1;
-               }
-       else {
-           /* try to use more random data */
-           randbytes = COMMITID_RAW_SIZE;
-           startrand = buf;
-       }
-       fd = open ("/dev/urandom", flags);
-       if (fd >= 0) {
-           len = read (fd, startrand, randbytes);
-           close (fd);
-       }
-       if (len <= 0) {
-           /* no random data was available so use pid */
-           long int pid = (long int)getpid ();
-           p = (unsigned char *) (startrand + sizeof (pid));
-           while (pid > 0) {
-               *--p = pid % (UCHAR_MAX + 1);
-               pid /= UCHAR_MAX + 1;
-           }
-       }
-       convert(buf, out);
-       global_session_id = strdup (out);
-    }
-
+    global_session_id = Xasprintf("1%010llX%04X%04X",
+      (unsigned long long)time(NULL),
+      (int)(getpid() & 0xFFFF), (int)(arc4random() & 0xFFFF));
 
     TRACE (TRACE_FUNCTION, "main: Session ID is %s", global_session_id);
 
@@ -1011,7 +951,7 @@ cause intermittent sandbox corruption.");
            /* Now we've reconciled CVSROOT from the command line, the
               CVS/Root file, and the environment variable.  Do the
               last sanity checks on the variable. */
-           if (!CVSroot_parsed)
+           if (!CVSroot_parsed && cm->func != version)
            {
                error (0, 0,
                       "No CVSROOT specified!  Please use the `-d' option");
@@ -1043,6 +983,11 @@ cause intermittent sandbox corruption.");
 
        assert (current_parsed_root == NULL);
 
+       /* Handle running 'cvs version' with no CVSROOT.  */
+
+       if (cm->func == version && !CVSroot_parsed)
+           server_active = !0;
+
        /* If we're running the server, we want to execute this main
           loop once and only once (we won't be serving multiple roots
           from this connection, so there's no need to do it more than
@@ -1244,7 +1189,7 @@ parse_tagdate (char **tag, char **date, const char *input)
        if (*++p)
        {
            if (*date) free (*date);
-           *date = Make_Date (p);
+           *date = strcmp (p, "BASE") ? Make_Date (p) : xstrdup (p);
        }
     }
     else if (strlen (input))
@@ -1285,7 +1230,7 @@ date_from_time_t (time_t unixtime)
        ftm = localtime (&unixtime);
 
     (void) sprintf (date, DATEFORM,
-                   ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
+                   (long)ftm->tm_year + (ftm->tm_year < 100 ? 0L : 1900L),
                    ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
                    ftm->tm_min, ftm->tm_sec);
     ret = xstrdup (date);
@@ -1315,8 +1260,9 @@ date_to_internet (char *dest, const char *source)
 void
 date_to_tm (struct tm *dest, const char *source)
 {
+    int y;
     if (sscanf (source, SDATEFORM,
-               &dest->tm_year, &dest->tm_mon, &dest->tm_mday,
+               &y, &dest->tm_mon, &dest->tm_mday,
                &dest->tm_hour, &dest->tm_min, &dest->tm_sec)
            != 6)
        /* Is there a better way to handle errors here?  I made this
@@ -1324,9 +1270,7 @@ date_to_tm (struct tm *dest, const char *source)
           deal with fatal errors.  */
        error (0, 0, "internal error: bad date %s", source);
 
-    if (dest->tm_year > 100)
-       dest->tm_year -= 1900;
-
+    dest->tm_year = y - ((y > 100) ? 1900 : 0);
     dest->tm_mon -= 1;
 }
 
@@ -1348,10 +1292,10 @@ tm_to_internet (char *dest, const struct tm *source)
       {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
     
-    sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday,
+    sprintf (dest, "%d %s %ld %02d:%02d:%02d -0000", source->tm_mday,
             source->tm_mon < 0 || source->tm_mon > 11
                ? "???" : month_names[source->tm_mon],
-            source->tm_year + 1900, source->tm_hour, source->tm_min,
+            (long)source->tm_year + 1900, source->tm_hour, source->tm_min,
              source->tm_sec);
 }
 
@@ -1458,7 +1402,7 @@ usage (register const char *const *cpp)
 {
     (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name);
     for (; *cpp; cpp++)
-       (void) fprintf (stderr, *cpp);
+       (void) fprintf (stderr, "%s", *cpp);
     exit (EXIT_FAILURE);
 }