1a7c91847Schristos /* CVS client-related stuff. 2a7c91847Schristos 3a7c91847Schristos This program is free software; you can redistribute it and/or modify 4a7c91847Schristos it under the terms of the GNU General Public License as published by 5a7c91847Schristos the Free Software Foundation; either version 2, or (at your option) 6a7c91847Schristos any later version. 7a7c91847Schristos 8a7c91847Schristos This program is distributed in the hope that it will be useful, 9a7c91847Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 10a7c91847Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11a7c91847Schristos GNU General Public License for more details. */ 12a7c91847Schristos 13a7c91847Schristos #ifdef HAVE_CONFIG_H 14a7c91847Schristos # include "config.h" 15a7c91847Schristos #endif /* HAVE_CONFIG_H */ 16a7c91847Schristos 17a7c91847Schristos #include "cvs.h" 18a7c91847Schristos #include "getline.h" 19a7c91847Schristos #include "edit.h" 20a7c91847Schristos #include "buffer.h" 21a7c91847Schristos #include "save-cwd.h" 22a7c91847Schristos 23a7c91847Schristos #ifdef CLIENT_SUPPORT 24a7c91847Schristos 25a7c91847Schristos # include "log-buffer.h" 26a7c91847Schristos # include "md5.h" 27a7c91847Schristos 28a7c91847Schristos #include "socket-client.h" 29a7c91847Schristos #include "rsh-client.h" 30a7c91847Schristos 31a7c91847Schristos # ifdef HAVE_GSSAPI 32a7c91847Schristos # include "gssapi-client.h" 33a7c91847Schristos # endif 34a7c91847Schristos 35a7c91847Schristos # ifdef HAVE_KERBEROS 36a7c91847Schristos # include "kerberos4-client.h" 37a7c91847Schristos # endif 38a7c91847Schristos 39a7c91847Schristos 40a7c91847Schristos 41a7c91847Schristos /* Keep track of any paths we are sending for Max-dotdot so that we can verify 42a7c91847Schristos * that uplevel paths coming back form the server are valid. 43a7c91847Schristos * 44a7c91847Schristos * FIXME: The correct way to do this is probably provide some sort of virtual 45a7c91847Schristos * path map on the client side. This would be generic enough to be applied to 46a7c91847Schristos * absolute paths supplied by the user too. 47a7c91847Schristos */ 48a7c91847Schristos static List *uppaths; 49a7c91847Schristos 50a7c91847Schristos 51a7c91847Schristos 52a7c91847Schristos static void add_prune_candidate (const char *); 53a7c91847Schristos 54a7c91847Schristos /* All the commands. */ 55a7c91847Schristos int add (int argc, char **argv); 56a7c91847Schristos int admin (int argc, char **argv); 57a7c91847Schristos int checkout (int argc, char **argv); 58a7c91847Schristos int commit (int argc, char **argv); 59a7c91847Schristos int diff (int argc, char **argv); 60a7c91847Schristos int history (int argc, char **argv); 61a7c91847Schristos int import (int argc, char **argv); 62a7c91847Schristos int cvslog (int argc, char **argv); 63a7c91847Schristos int patch (int argc, char **argv); 64a7c91847Schristos int release (int argc, char **argv); 65a7c91847Schristos int cvsremove (int argc, char **argv); 66a7c91847Schristos int rtag (int argc, char **argv); 67a7c91847Schristos int status (int argc, char **argv); 68a7c91847Schristos int tag (int argc, char **argv); 69a7c91847Schristos int update (int argc, char **argv); 70a7c91847Schristos 71*9f2c58f4Schristos #if defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS || defined HAVE_GSSAPI 72*9f2c58f4Schristos static int connect_to(char *, unsigned int); 73*9f2c58f4Schristos #endif 74*9f2c58f4Schristos 75a7c91847Schristos static size_t try_read_from_server (char *, size_t); 76a7c91847Schristos 77a7c91847Schristos static void auth_server (cvsroot_t *, struct buffer *, struct buffer *, 78274254cdSchristos int, int); 79a7c91847Schristos 80a7c91847Schristos 81a7c91847Schristos 82a7c91847Schristos /* This is the referrer who referred us to a primary, or write server, using 83a7c91847Schristos * the "Redirect" request. 84a7c91847Schristos */ 85a7c91847Schristos static cvsroot_t *client_referrer; 86a7c91847Schristos 87a7c91847Schristos /* We need to keep track of the list of directories we've sent to the 88a7c91847Schristos server. This list, along with the current CVSROOT, will help us 89a7c91847Schristos decide which command-line arguments to send. */ 90a7c91847Schristos List *dirs_sent_to_server; 91a7c91847Schristos static int 92a7c91847Schristos is_arg_a_parent_or_listed_dir (Node *n, void *d) 93a7c91847Schristos { 94a7c91847Schristos char *directory = n->key; /* name of the dir sent to server */ 95a7c91847Schristos char *this_argv_elem = d; /* this argv element */ 96a7c91847Schristos 97a7c91847Schristos /* Say we should send this argument if the argument matches the 98a7c91847Schristos beginning of a directory name sent to the server. This way, 99a7c91847Schristos the server will know to start at the top of that directory 100a7c91847Schristos hierarchy and descend. */ 101a7c91847Schristos 102a7c91847Schristos if (!strncmp (directory, this_argv_elem, strlen (this_argv_elem))) 103a7c91847Schristos return 1; 104a7c91847Schristos 105a7c91847Schristos return 0; 106a7c91847Schristos } 107a7c91847Schristos 108a7c91847Schristos 109a7c91847Schristos 110a7c91847Schristos /* Return nonzero if this argument should not be sent to the 111a7c91847Schristos server. */ 112a7c91847Schristos static int 113a7c91847Schristos arg_should_not_be_sent_to_server (char *arg) 114a7c91847Schristos { 115a7c91847Schristos /* Decide if we should send this directory name to the server. We 116a7c91847Schristos should always send argv[i] if: 117a7c91847Schristos 118a7c91847Schristos 1) the list of directories sent to the server is empty (as it 119a7c91847Schristos will be for checkout, etc.). 120a7c91847Schristos 121a7c91847Schristos 2) the argument is "." 122a7c91847Schristos 123a7c91847Schristos 3) the argument is a file in the cwd and the cwd is checked out 124a7c91847Schristos from the current root 125a7c91847Schristos 126a7c91847Schristos 4) the argument lies within one of the paths in 127a7c91847Schristos dirs_sent_to_server. 128a7c91847Schristos 129a7c91847Schristos */ 130a7c91847Schristos 131a7c91847Schristos if (list_isempty (dirs_sent_to_server)) 132a7c91847Schristos return 0; /* always send it */ 133a7c91847Schristos 134a7c91847Schristos if (!strcmp (arg, ".")) 135a7c91847Schristos return 0; /* always send it */ 136a7c91847Schristos 137a7c91847Schristos /* We should send arg if it is one of the directories sent to the 138a7c91847Schristos server or the parent of one; this tells the server to descend 139a7c91847Schristos the hierarchy starting at this level. */ 140a7c91847Schristos if (isdir (arg)) 141a7c91847Schristos { 142a7c91847Schristos if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, arg)) 143a7c91847Schristos return 0; 144a7c91847Schristos 145a7c91847Schristos /* If arg wasn't a parent, we don't know anything about it (we 146a7c91847Schristos would have seen something related to it during the 147a7c91847Schristos send_files phase). Don't send it. */ 148a7c91847Schristos return 1; 149a7c91847Schristos } 150a7c91847Schristos 151a7c91847Schristos /* Try to decide whether we should send arg to the server by 152a7c91847Schristos checking the contents of the corresponding CVSADM directory. */ 153a7c91847Schristos { 154a7c91847Schristos char *t, *root_string; 155a7c91847Schristos cvsroot_t *this_root = NULL; 156a7c91847Schristos 157a7c91847Schristos /* Calculate "dirname arg" */ 158a7c91847Schristos for (t = arg + strlen (arg) - 1; t >= arg; t--) 159a7c91847Schristos { 160a7c91847Schristos if (ISSLASH (*t)) 161a7c91847Schristos break; 162a7c91847Schristos } 163a7c91847Schristos 164a7c91847Schristos /* Now we're either poiting to the beginning of the 165a7c91847Schristos string, or we found a path separator. */ 166a7c91847Schristos if (t >= arg) 167a7c91847Schristos { 168a7c91847Schristos /* Found a path separator. */ 169a7c91847Schristos char c = *t; 170a7c91847Schristos *t = '\0'; 171a7c91847Schristos 172a7c91847Schristos /* First, check to see if we sent this directory to the 173a7c91847Schristos server, because it takes less time than actually 174a7c91847Schristos opening the stuff in the CVSADM directory. */ 175a7c91847Schristos if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, 176a7c91847Schristos arg)) 177a7c91847Schristos { 178a7c91847Schristos *t = c; /* make sure to un-truncate the arg */ 179a7c91847Schristos return 0; 180a7c91847Schristos } 181a7c91847Schristos 182a7c91847Schristos /* Since we didn't find it in the list, check the CVSADM 183a7c91847Schristos files on disk. */ 184a7c91847Schristos this_root = Name_Root (arg, NULL); 185a7c91847Schristos root_string = this_root->original; 186a7c91847Schristos *t = c; 187a7c91847Schristos } 188a7c91847Schristos else 189a7c91847Schristos { 190a7c91847Schristos /* We're at the beginning of the string. Look at the 191a7c91847Schristos CVSADM files in cwd. */ 192a7c91847Schristos if (CVSroot_cmdline) 193a7c91847Schristos root_string = CVSroot_cmdline; 194a7c91847Schristos else 195a7c91847Schristos { 196a7c91847Schristos this_root = Name_Root (NULL, NULL); 197a7c91847Schristos root_string = this_root->original; 198a7c91847Schristos } 199a7c91847Schristos } 200a7c91847Schristos 201a7c91847Schristos /* Now check the value for root. */ 202a7c91847Schristos if (root_string && current_parsed_root 203a7c91847Schristos && strcmp (root_string, original_parsed_root->original)) 204a7c91847Schristos { 205a7c91847Schristos /* Don't send this, since the CVSROOTs don't match. */ 206a7c91847Schristos return 1; 207a7c91847Schristos } 208a7c91847Schristos } 209a7c91847Schristos 210a7c91847Schristos /* OK, let's send it. */ 211a7c91847Schristos return 0; 212a7c91847Schristos } 213a7c91847Schristos #endif /* CLIENT_SUPPORT */ 214a7c91847Schristos 215a7c91847Schristos 216a7c91847Schristos 217a7c91847Schristos #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) 218a7c91847Schristos 219a7c91847Schristos /* Shared with server. */ 220a7c91847Schristos 221a7c91847Schristos /* 222a7c91847Schristos * Return a malloc'd, '\0'-terminated string 223a7c91847Schristos * corresponding to the mode in SB. 224a7c91847Schristos */ 225a7c91847Schristos char * 226a7c91847Schristos mode_to_string (mode_t mode) 227a7c91847Schristos { 228a7c91847Schristos char u[4], g[4], o[4]; 229a7c91847Schristos int i; 230a7c91847Schristos 231a7c91847Schristos i = 0; 232a7c91847Schristos if (mode & S_IRUSR) u[i++] = 'r'; 233a7c91847Schristos if (mode & S_IWUSR) u[i++] = 'w'; 234a7c91847Schristos if (mode & S_IXUSR) u[i++] = 'x'; 235a7c91847Schristos u[i] = '\0'; 236a7c91847Schristos 237a7c91847Schristos i = 0; 238a7c91847Schristos if (mode & S_IRGRP) g[i++] = 'r'; 239a7c91847Schristos if (mode & S_IWGRP) g[i++] = 'w'; 240a7c91847Schristos if (mode & S_IXGRP) g[i++] = 'x'; 241a7c91847Schristos g[i] = '\0'; 242a7c91847Schristos 243a7c91847Schristos i = 0; 244a7c91847Schristos if (mode & S_IROTH) o[i++] = 'r'; 245a7c91847Schristos if (mode & S_IWOTH) o[i++] = 'w'; 246a7c91847Schristos if (mode & S_IXOTH) o[i++] = 'x'; 247a7c91847Schristos o[i] = '\0'; 248a7c91847Schristos 249a7c91847Schristos return Xasprintf ("u=%s,g=%s,o=%s", u, g, o); 250a7c91847Schristos } 251a7c91847Schristos 252a7c91847Schristos 253a7c91847Schristos 254a7c91847Schristos /* 255a7c91847Schristos * Change mode of FILENAME to MODE_STRING. 256a7c91847Schristos * Returns 0 for success or errno code. 257a7c91847Schristos * If RESPECT_UMASK is set, then honor the umask. 258a7c91847Schristos */ 259a7c91847Schristos int 260a7c91847Schristos change_mode (const char *filename, const char *mode_string, int respect_umask) 261a7c91847Schristos { 262a7c91847Schristos #ifdef CHMOD_BROKEN 263a7c91847Schristos char *p; 264a7c91847Schristos int writeable = 0; 265a7c91847Schristos 266a7c91847Schristos /* We can only distinguish between 267a7c91847Schristos 1) readable 268a7c91847Schristos 2) writeable 269a7c91847Schristos 3) Picasso's "Blue Period" 270a7c91847Schristos We handle the first two. */ 271a7c91847Schristos p = mode_string; 272a7c91847Schristos while (*p != '\0') 273a7c91847Schristos { 274a7c91847Schristos if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') 275a7c91847Schristos { 276a7c91847Schristos char *q = p + 2; 277a7c91847Schristos while (*q != ',' && *q != '\0') 278a7c91847Schristos { 279a7c91847Schristos if (*q == 'w') 280a7c91847Schristos writeable = 1; 281a7c91847Schristos ++q; 282a7c91847Schristos } 283a7c91847Schristos } 284a7c91847Schristos /* Skip to the next field. */ 285a7c91847Schristos while (*p != ',' && *p != '\0') 286a7c91847Schristos ++p; 287a7c91847Schristos if (*p == ',') 288a7c91847Schristos ++p; 289a7c91847Schristos } 290a7c91847Schristos 291a7c91847Schristos /* xchmod honors the umask for us. In the !respect_umask case, we 292a7c91847Schristos don't try to cope with it (probably to handle that well, the server 293a7c91847Schristos needs to deal with modes in data structures, rather than via the 294a7c91847Schristos modes in temporary files). */ 295a7c91847Schristos xchmod (filename, writeable); 296a7c91847Schristos return 0; 297a7c91847Schristos 298a7c91847Schristos #else /* ! CHMOD_BROKEN */ 299a7c91847Schristos 300a7c91847Schristos const char *p; 301a7c91847Schristos mode_t mode = 0; 302a7c91847Schristos mode_t oumask; 303a7c91847Schristos 304a7c91847Schristos p = mode_string; 305a7c91847Schristos while (*p != '\0') 306a7c91847Schristos { 307a7c91847Schristos if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') 308a7c91847Schristos { 309a7c91847Schristos int can_read = 0, can_write = 0, can_execute = 0; 310a7c91847Schristos const char *q = p + 2; 311a7c91847Schristos while (*q != ',' && *q != '\0') 312a7c91847Schristos { 313a7c91847Schristos if (*q == 'r') 314a7c91847Schristos can_read = 1; 315a7c91847Schristos else if (*q == 'w') 316a7c91847Schristos can_write = 1; 317a7c91847Schristos else if (*q == 'x') 318a7c91847Schristos can_execute = 1; 319a7c91847Schristos ++q; 320a7c91847Schristos } 321a7c91847Schristos if (p[0] == 'u') 322a7c91847Schristos { 323a7c91847Schristos if (can_read) 324a7c91847Schristos mode |= S_IRUSR; 325a7c91847Schristos if (can_write) 326a7c91847Schristos mode |= S_IWUSR; 327a7c91847Schristos if (can_execute) 328a7c91847Schristos mode |= S_IXUSR; 329a7c91847Schristos } 330a7c91847Schristos else if (p[0] == 'g') 331a7c91847Schristos { 332a7c91847Schristos if (can_read) 333a7c91847Schristos mode |= S_IRGRP; 334a7c91847Schristos if (can_write) 335a7c91847Schristos mode |= S_IWGRP; 336a7c91847Schristos if (can_execute) 337a7c91847Schristos mode |= S_IXGRP; 338a7c91847Schristos } 339a7c91847Schristos else if (p[0] == 'o') 340a7c91847Schristos { 341a7c91847Schristos if (can_read) 342a7c91847Schristos mode |= S_IROTH; 343a7c91847Schristos if (can_write) 344a7c91847Schristos mode |= S_IWOTH; 345a7c91847Schristos if (can_execute) 346a7c91847Schristos mode |= S_IXOTH; 347a7c91847Schristos } 348a7c91847Schristos } 349a7c91847Schristos /* Skip to the next field. */ 350a7c91847Schristos while (*p != ',' && *p != '\0') 351a7c91847Schristos ++p; 352a7c91847Schristos if (*p == ',') 353a7c91847Schristos ++p; 354a7c91847Schristos } 355a7c91847Schristos 356a7c91847Schristos if (respect_umask) 357a7c91847Schristos { 358a7c91847Schristos oumask = umask (0); 359a7c91847Schristos (void) umask (oumask); 360a7c91847Schristos mode &= ~oumask; 361a7c91847Schristos } 362a7c91847Schristos 363a7c91847Schristos if (chmod (filename, mode) < 0) 364a7c91847Schristos return errno; 365a7c91847Schristos return 0; 366a7c91847Schristos #endif /* ! CHMOD_BROKEN */ 367a7c91847Schristos } 368a7c91847Schristos #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ 369a7c91847Schristos 370a7c91847Schristos 371a7c91847Schristos 372a7c91847Schristos #ifdef CLIENT_SUPPORT 373a7c91847Schristos int client_prune_dirs; 374a7c91847Schristos 375a7c91847Schristos static List *ignlist = NULL; 376a7c91847Schristos 377a7c91847Schristos /* Buffer to write to the server. */ 378a7c91847Schristos static struct buffer *global_to_server; 379a7c91847Schristos 380a7c91847Schristos /* Buffer used to read from the server. */ 381a7c91847Schristos static struct buffer *global_from_server; 382a7c91847Schristos 383a7c91847Schristos 384a7c91847Schristos 385a7c91847Schristos /* 386a7c91847Schristos * Read a line from the server. Result does not include the terminating \n. 387a7c91847Schristos * 388a7c91847Schristos * Space for the result is malloc'd and should be freed by the caller. 389a7c91847Schristos * 390a7c91847Schristos * Returns number of bytes read. 391a7c91847Schristos */ 392a7c91847Schristos static size_t 393a7c91847Schristos read_line_via (struct buffer *via_from_buffer, struct buffer *via_to_buffer, 394a7c91847Schristos char **resultp) 395a7c91847Schristos { 396a7c91847Schristos int status; 397a7c91847Schristos char *result; 398a7c91847Schristos size_t len; 399a7c91847Schristos 400a7c91847Schristos status = buf_flush (via_to_buffer, 1); 401a7c91847Schristos if (status != 0) 402a7c91847Schristos error (1, status, "writing to server"); 403a7c91847Schristos 404a7c91847Schristos status = buf_read_line (via_from_buffer, &result, &len); 405a7c91847Schristos if (status != 0) 406a7c91847Schristos { 407a7c91847Schristos if (status == -1) 408a7c91847Schristos error (1, 0, 409a7c91847Schristos "end of file from server (consult above messages if any)"); 410a7c91847Schristos else if (status == -2) 411a7c91847Schristos error (1, 0, "out of memory"); 412a7c91847Schristos else 413a7c91847Schristos error (1, status, "reading from server"); 414a7c91847Schristos } 415a7c91847Schristos 416a7c91847Schristos if (resultp) 417a7c91847Schristos *resultp = result; 418a7c91847Schristos else 419a7c91847Schristos free (result); 420a7c91847Schristos 421a7c91847Schristos return len; 422a7c91847Schristos } 423a7c91847Schristos 424a7c91847Schristos 425a7c91847Schristos 426a7c91847Schristos static size_t 427a7c91847Schristos read_line (char **resultp) 428a7c91847Schristos { 429a7c91847Schristos return read_line_via (global_from_server, global_to_server, resultp); 430a7c91847Schristos } 431a7c91847Schristos #endif /* CLIENT_SUPPORT */ 432a7c91847Schristos 433a7c91847Schristos 434a7c91847Schristos 435a7c91847Schristos #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) 436a7c91847Schristos /* 437a7c91847Schristos * Zero if compression isn't supported or requested; non-zero to indicate 438a7c91847Schristos * a compression level to request from gzip. 439a7c91847Schristos */ 440a7c91847Schristos int gzip_level; 441a7c91847Schristos 442a7c91847Schristos /* 443a7c91847Schristos * Level of compression to use when running gzip on a single file. 444a7c91847Schristos */ 445a7c91847Schristos int file_gzip_level; 446a7c91847Schristos 447a7c91847Schristos #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ 448a7c91847Schristos 449a7c91847Schristos #ifdef CLIENT_SUPPORT 450a7c91847Schristos 451a7c91847Schristos /* Whether the server asked us to force compression. */ 452a7c91847Schristos static bool force_gzip; 453a7c91847Schristos 454a7c91847Schristos /* 455a7c91847Schristos * The Repository for the top level of this command (not necessarily 456a7c91847Schristos * the CVSROOT, just the current directory at the time we do it). 457a7c91847Schristos */ 458a7c91847Schristos static char *toplevel_repos; 459a7c91847Schristos 460a7c91847Schristos /* Working directory when we first started. Note: we could speed things 461a7c91847Schristos up on some systems by using savecwd.h here instead of just always 462a7c91847Schristos storing a name. */ 463a7c91847Schristos char *toplevel_wd; 464a7c91847Schristos 465a7c91847Schristos 466a7c91847Schristos 467a7c91847Schristos static void 468a7c91847Schristos handle_ok (char *args, size_t len) 469a7c91847Schristos { 470a7c91847Schristos return; 471a7c91847Schristos } 472a7c91847Schristos 473a7c91847Schristos 474a7c91847Schristos 475a7c91847Schristos static void 476a7c91847Schristos handle_error (char *args, size_t len) 477a7c91847Schristos { 478a7c91847Schristos int something_printed; 479a7c91847Schristos 480a7c91847Schristos /* 481a7c91847Schristos * First there is a symbolic error code followed by a space, which 482a7c91847Schristos * we ignore. 483a7c91847Schristos */ 484a7c91847Schristos char *p = strchr (args, ' '); 485a7c91847Schristos if (!p) 486a7c91847Schristos { 487a7c91847Schristos error (0, 0, "invalid data from cvs server"); 488a7c91847Schristos return; 489a7c91847Schristos } 490a7c91847Schristos ++p; 491a7c91847Schristos 492a7c91847Schristos /* Next we print the text of the message from the server. We 493a7c91847Schristos probably should be prefixing it with "server error" or some 494a7c91847Schristos such, because if it is something like "Out of memory", the 495a7c91847Schristos current behavior doesn't say which machine is out of 496a7c91847Schristos memory. */ 497a7c91847Schristos 498a7c91847Schristos len -= p - args; 499a7c91847Schristos something_printed = 0; 500a7c91847Schristos for (; len > 0; --len) 501a7c91847Schristos { 502a7c91847Schristos something_printed = 1; 503a7c91847Schristos putc (*p++, stderr); 504a7c91847Schristos } 505a7c91847Schristos if (something_printed) 506a7c91847Schristos putc ('\n', stderr); 507a7c91847Schristos } 508a7c91847Schristos 509a7c91847Schristos 510a7c91847Schristos 511a7c91847Schristos static void 512a7c91847Schristos handle_valid_requests (char *args, size_t len) 513a7c91847Schristos { 514a7c91847Schristos char *p = args; 515a7c91847Schristos char *q; 516a7c91847Schristos struct request *rq; 517a7c91847Schristos do 518a7c91847Schristos { 519a7c91847Schristos q = strchr (p, ' '); 520a7c91847Schristos if (q) 521a7c91847Schristos *q++ = '\0'; 522a7c91847Schristos for (rq = requests; rq->name; ++rq) 523a7c91847Schristos { 524a7c91847Schristos if (!strcmp (rq->name, p)) 525a7c91847Schristos break; 526a7c91847Schristos } 527a7c91847Schristos if (!rq->name) 528a7c91847Schristos /* 529a7c91847Schristos * It is a request we have never heard of (and thus never 530a7c91847Schristos * will want to use). So don't worry about it. 531a7c91847Schristos */ 532a7c91847Schristos ; 533a7c91847Schristos else 534a7c91847Schristos { 535a7c91847Schristos if (rq->flags & RQ_ENABLEME) 536a7c91847Schristos { 537a7c91847Schristos /* 538a7c91847Schristos * Server wants to know if we have this, to enable the 539a7c91847Schristos * feature. 540a7c91847Schristos */ 541a7c91847Schristos send_to_server (rq->name, 0); 542a7c91847Schristos send_to_server ("\012", 0); 543a7c91847Schristos } 544a7c91847Schristos else 545a7c91847Schristos rq->flags |= RQ_SUPPORTED; 546a7c91847Schristos } 547a7c91847Schristos p = q; 548a7c91847Schristos } while (q); 549a7c91847Schristos for (rq = requests; rq->name; ++rq) 550a7c91847Schristos { 551a7c91847Schristos if ((rq->flags & RQ_SUPPORTED) 552a7c91847Schristos || (rq->flags & RQ_ENABLEME)) 553a7c91847Schristos continue; 554a7c91847Schristos if (rq->flags & RQ_ESSENTIAL) 555a7c91847Schristos error (1, 0, "request `%s' not supported by server", rq->name); 556a7c91847Schristos } 557a7c91847Schristos } 558a7c91847Schristos 559a7c91847Schristos static void 560a7c91847Schristos handle_force_gzip (char *args, size_t len) 561a7c91847Schristos { 562a7c91847Schristos force_gzip = true; 563a7c91847Schristos } 564a7c91847Schristos 565a7c91847Schristos 566a7c91847Schristos 567a7c91847Schristos /* Has the server told us its name since the last redirect? 568a7c91847Schristos */ 569a7c91847Schristos static bool referred_since_last_redirect = false; 570a7c91847Schristos static bool free_client_referrer = false; 571a7c91847Schristos 572a7c91847Schristos 573a7c91847Schristos 574a7c91847Schristos static void 575a7c91847Schristos handle_referrer (char *args, size_t len) 576a7c91847Schristos { 577a7c91847Schristos TRACE (TRACE_FUNCTION, "handle_referrer (%s)", args); 578a7c91847Schristos client_referrer = parse_cvsroot (args); 579a7c91847Schristos referred_since_last_redirect = true; 580a7c91847Schristos free_client_referrer = true; 581a7c91847Schristos } 582a7c91847Schristos 583a7c91847Schristos 584a7c91847Schristos 585a7c91847Schristos /* Redirect our connection to a different server and start over. 586a7c91847Schristos * 587a7c91847Schristos * GLOBALS 588a7c91847Schristos * current_parsed_root The CVSROOT being accessed. 589a7c91847Schristos * client_referrer Used to track the server which referred us to a 590a7c91847Schristos * new server. Can be supplied by the referring 591a7c91847Schristos * server. 592a7c91847Schristos * free_client_referrer Used to track whether the client_referrer needs 593a7c91847Schristos * to be freed before changing it. 594a7c91847Schristos * referred_since_last_redirect 595a7c91847Schristos * Tracks whether the currect server told us how 596a7c91847Schristos * to refer to it. 597a7c91847Schristos * 598a7c91847Schristos * OUTPUTS 599a7c91847Schristos * current_parsed_root Updated to point to the new CVSROOT. 600a7c91847Schristos * referred_since_last_redirect 601a7c91847Schristos * Always cleared. 602a7c91847Schristos * client_referrer Set automatically to current_parsed_root if 603a7c91847Schristos * the current server did not give us a name to 604a7c91847Schristos * refer to it by. 605a7c91847Schristos * free_client_referrer Reset when necessary. 606a7c91847Schristos */ 607a7c91847Schristos static void 608a7c91847Schristos handle_redirect (char *args, size_t len) 609a7c91847Schristos { 610a7c91847Schristos static List *redirects = NULL; 611a7c91847Schristos 612a7c91847Schristos TRACE (TRACE_FUNCTION, "handle_redirect (%s)", args); 613a7c91847Schristos 614a7c91847Schristos if (redirects && findnode (redirects, args)) 615a7c91847Schristos error (1, 0, "`Redirect' loop detected. Server misconfiguration?"); 616a7c91847Schristos else 617a7c91847Schristos { 618a7c91847Schristos if (!redirects) redirects = getlist(); 619a7c91847Schristos push_string (redirects, args); 620a7c91847Schristos } 621a7c91847Schristos 622a7c91847Schristos if (referred_since_last_redirect) 623a7c91847Schristos referred_since_last_redirect = false; 624a7c91847Schristos else 625a7c91847Schristos { 626a7c91847Schristos if (free_client_referrer) free (client_referrer); 627a7c91847Schristos client_referrer = current_parsed_root; 628a7c91847Schristos free_client_referrer = false; 629a7c91847Schristos } 630a7c91847Schristos 631a7c91847Schristos current_parsed_root = parse_cvsroot (args); 632a7c91847Schristos 633a7c91847Schristos /* We deliberately do not set ORIGINAL_PARSED_ROOT here. 634a7c91847Schristos * ORIGINAL_PARSED_ROOT is used by the client to determine the current root 635a7c91847Schristos * being processed for the purpose of looking it up in lists and such, even 636a7c91847Schristos * after a redirect. 637a7c91847Schristos * 638a7c91847Schristos * FIXME 639a7c91847Schristos * CURRENT_PARSED_ROOT should not be reset by this function. Redirects 640a7c91847Schristos * should be "added" to it. The REDIRECTS list should also be replaced 641a7c91847Schristos * by this new CURRENT_PARSED_ROOT element. This way, if, for instance, 642a7c91847Schristos * a multi-root workspace had two secondaries pointing to the same 643a7c91847Schristos * primary, then the client would not report a looping error. 644a7c91847Schristos * 645a7c91847Schristos * There is also a potential memory leak above and storing new roots as 646a7c91847Schristos * part of the original could help avoid it fairly elegantly. 647a7c91847Schristos */ 648a7c91847Schristos if (!current_parsed_root) 649a7c91847Schristos error (1, 0, "Server requested redirect to invalid root: `%s'", 650a7c91847Schristos args); 651a7c91847Schristos } 652a7c91847Schristos 653a7c91847Schristos 654a7c91847Schristos 655a7c91847Schristos /* 656a7c91847Schristos * This is a proc for walklist(). It inverts the error return premise of 657a7c91847Schristos * walklist. 658a7c91847Schristos * 659a7c91847Schristos * RETURNS 660a7c91847Schristos * True If this path is prefixed by one of the paths in walklist and 661a7c91847Schristos * does not step above the prefix path. 662a7c91847Schristos * False Otherwise. 663a7c91847Schristos */ 664a7c91847Schristos static 665a7c91847Schristos int path_list_prefixed (Node *p, void *closure) 666a7c91847Schristos { 667a7c91847Schristos const char *questionable = closure; 668a7c91847Schristos const char *prefix = p->key; 669a7c91847Schristos if (strncmp (prefix, questionable, strlen (prefix))) return 0; 670a7c91847Schristos questionable += strlen (prefix); 671a7c91847Schristos while (ISSLASH (*questionable)) questionable++; 672a7c91847Schristos if (*questionable == '\0') return 1; 673a7c91847Schristos return pathname_levels (questionable); 674a7c91847Schristos } 675a7c91847Schristos 676a7c91847Schristos 677a7c91847Schristos 678a7c91847Schristos /* 679a7c91847Schristos * Need to validate the client pathname. Disallowed paths include: 680a7c91847Schristos * 681a7c91847Schristos * 1. Absolute paths. 682a7c91847Schristos * 2. Pathnames that do not reference a specifically requested update 683a7c91847Schristos * directory. 684a7c91847Schristos * 685a7c91847Schristos * In case 2, we actually only check that the directory is under the uppermost 686a7c91847Schristos * directories mentioned on the command line. 687a7c91847Schristos * 688a7c91847Schristos * RETURNS 689a7c91847Schristos * True If the path is valid. 690a7c91847Schristos * False Otherwise. 691a7c91847Schristos */ 692a7c91847Schristos static 693a7c91847Schristos int is_valid_client_path (const char *pathname) 694a7c91847Schristos { 695a7c91847Schristos /* 1. Absolute paths. */ 696a7c91847Schristos if (ISABSOLUTE (pathname)) return 0; 697a7c91847Schristos /* 2. No up-references in path. */ 698a7c91847Schristos if (pathname_levels (pathname) == 0) return 1; 699a7c91847Schristos /* 2. No Max-dotdot paths registered. */ 700a7c91847Schristos if (!uppaths) return 0; 701a7c91847Schristos 702a7c91847Schristos return walklist (uppaths, path_list_prefixed, (void *)pathname); 703a7c91847Schristos } 704a7c91847Schristos 705a7c91847Schristos 706a7c91847Schristos 707a7c91847Schristos /* 708a7c91847Schristos * Do all the processing for PATHNAME, where pathname consists of the 709a7c91847Schristos * repository and the filename. The parameters we pass to FUNC are: 710a7c91847Schristos * DATA is just the DATA parameter which was passed to 711a7c91847Schristos * call_in_directory; ENT_LIST is a pointer to an entries list (which 712a7c91847Schristos * we manage the storage for); SHORT_PATHNAME is the pathname of the 713a7c91847Schristos * file relative to the (overall) directory in which the command is 714a7c91847Schristos * taking place; and FILENAME is the filename portion only of 715a7c91847Schristos * SHORT_PATHNAME. When we call FUNC, the curent directory points to 716a7c91847Schristos * the directory portion of SHORT_PATHNAME. */ 717a7c91847Schristos static void 718a7c91847Schristos call_in_directory (const char *pathname, 719a7c91847Schristos void (*func) (void *, List *, const char *, const char *), 720a7c91847Schristos void *data) 721a7c91847Schristos { 722a7c91847Schristos /* This variable holds the result of Entries_Open. */ 723a7c91847Schristos List *last_entries = NULL; 724a7c91847Schristos char *dir_name; 725a7c91847Schristos char *filename; 726a7c91847Schristos /* This is what we get when we hook up the directory (working directory 727a7c91847Schristos name) from PATHNAME with the filename from REPOSNAME. For example: 728a7c91847Schristos pathname: ccvs/src/ 729a7c91847Schristos reposname: /u/src/master/ccvs/foo/ChangeLog 730a7c91847Schristos short_pathname: ccvs/src/ChangeLog 731a7c91847Schristos */ 732a7c91847Schristos char *short_pathname; 733a7c91847Schristos char *p; 734a7c91847Schristos 735a7c91847Schristos /* 736a7c91847Schristos * Do the whole descent in parallel for the repositories, so we 737a7c91847Schristos * know what to put in CVS/Repository files. I'm not sure the 738a7c91847Schristos * full hair is necessary since the server does a similar 739a7c91847Schristos * computation; I suspect that we only end up creating one 740a7c91847Schristos * directory at a time anyway. 741a7c91847Schristos * 742a7c91847Schristos * Also note that we must *only* worry about this stuff when we 743a7c91847Schristos * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co 744a7c91847Schristos * CVSROOT; cvs update' is legitimate, but in this case 745a7c91847Schristos * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of 746a7c91847Schristos * foo/bar/CVS/Repository. 747a7c91847Schristos */ 748a7c91847Schristos char *reposname; 749a7c91847Schristos char *short_repos; 750a7c91847Schristos char *reposdirname; 751a7c91847Schristos char *rdirp; 752a7c91847Schristos int reposdirname_absolute; 753a7c91847Schristos int newdir = 0; 754a7c91847Schristos 755a7c91847Schristos assert (pathname); 756a7c91847Schristos 757a7c91847Schristos reposname = NULL; 758a7c91847Schristos read_line (&reposname); 759a7c91847Schristos assert (reposname); 760a7c91847Schristos 761a7c91847Schristos reposdirname_absolute = 0; 762a7c91847Schristos if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos))) 763a7c91847Schristos { 764a7c91847Schristos reposdirname_absolute = 1; 765a7c91847Schristos short_repos = reposname; 766a7c91847Schristos } 767a7c91847Schristos else 768a7c91847Schristos { 769a7c91847Schristos short_repos = reposname + strlen (toplevel_repos) + 1; 770a7c91847Schristos if (short_repos[-1] != '/') 771a7c91847Schristos { 772a7c91847Schristos reposdirname_absolute = 1; 773a7c91847Schristos short_repos = reposname; 774a7c91847Schristos } 775a7c91847Schristos } 776a7c91847Schristos 777a7c91847Schristos /* Now that we have SHORT_REPOS, we can calculate the path to the file we 778a7c91847Schristos * are being requested to operate on. 779a7c91847Schristos */ 780a7c91847Schristos filename = strrchr (short_repos, '/'); 781a7c91847Schristos if (!filename) 782a7c91847Schristos filename = short_repos; 783a7c91847Schristos else 784a7c91847Schristos ++filename; 785a7c91847Schristos 786a7c91847Schristos short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5); 787a7c91847Schristos strcpy (short_pathname, pathname); 788a7c91847Schristos strcat (short_pathname, filename); 789a7c91847Schristos 790a7c91847Schristos /* Now that we know the path to the file we were requested to operate on, 791a7c91847Schristos * we can verify that it is valid. 792a7c91847Schristos * 793a7c91847Schristos * For security reasons, if SHORT_PATHNAME is absolute or attempts to 794a7c91847Schristos * ascend outside of the current sanbbox, we abort. The server should not 795a7c91847Schristos * send us anything but relative paths which remain inside the sandbox 796a7c91847Schristos * here. Anything less means a trojan CVS server could create and edit 797a7c91847Schristos * arbitrary files on the client. 798a7c91847Schristos */ 799a7c91847Schristos if (!is_valid_client_path (short_pathname)) 800a7c91847Schristos { 801a7c91847Schristos error (0, 0, 802a7c91847Schristos "Server attempted to update a file via an invalid pathname:"); 803a7c91847Schristos error (1, 0, "`%s'.", short_pathname); 804a7c91847Schristos } 805a7c91847Schristos 806a7c91847Schristos reposdirname = xstrdup (short_repos); 807a7c91847Schristos p = strrchr (reposdirname, '/'); 808a7c91847Schristos if (!p) 809a7c91847Schristos { 810a7c91847Schristos reposdirname = xrealloc (reposdirname, 2); 811a7c91847Schristos reposdirname[0] = '.'; reposdirname[1] = '\0'; 812a7c91847Schristos } 813a7c91847Schristos else 814a7c91847Schristos *p = '\0'; 815a7c91847Schristos 816a7c91847Schristos dir_name = xstrdup (pathname); 817a7c91847Schristos p = strrchr (dir_name, '/'); 818a7c91847Schristos if (!p) 819a7c91847Schristos { 820a7c91847Schristos dir_name = xrealloc (dir_name, 2); 821a7c91847Schristos dir_name[0] = '.'; dir_name[1] = '\0'; 822a7c91847Schristos } 823a7c91847Schristos else 824a7c91847Schristos *p = '\0'; 825a7c91847Schristos if (client_prune_dirs) 826a7c91847Schristos add_prune_candidate (dir_name); 827a7c91847Schristos 828a7c91847Schristos if (!toplevel_wd) 829a7c91847Schristos { 830a7c91847Schristos toplevel_wd = xgetcwd (); 831a7c91847Schristos if (!toplevel_wd) 832a7c91847Schristos error (1, errno, "could not get working directory"); 833a7c91847Schristos } 834a7c91847Schristos 835a7c91847Schristos if (CVS_CHDIR (toplevel_wd) < 0) 836a7c91847Schristos error (1, errno, "could not chdir to %s", toplevel_wd); 837a7c91847Schristos 838a7c91847Schristos /* Create the CVS directory at the top level if needed. The 839a7c91847Schristos isdir seems like an unneeded system call, but it *does* 840a7c91847Schristos need to be called both if the CVS_CHDIR below succeeds 841a7c91847Schristos (e.g. "cvs co .") or if it fails (e.g. basicb-1a in 842a7c91847Schristos testsuite). We only need to do this for the "." case, 843a7c91847Schristos since the server takes care of forcing this directory to be 844a7c91847Schristos created in all other cases. If we don't create CVSADM 845a7c91847Schristos here, the call to Entries_Open below will fail. FIXME: 846a7c91847Schristos perhaps this means that we should change our algorithm 847a7c91847Schristos below that calls Create_Admin instead of having this code 848a7c91847Schristos here? */ 849a7c91847Schristos if (/* I think the reposdirname_absolute case has to do with 850a7c91847Schristos things like "cvs update /foo/bar". In any event, the 851a7c91847Schristos code below which tries to put toplevel_repos into 852a7c91847Schristos CVS/Repository is almost surely unsuited to 853a7c91847Schristos the reposdirname_absolute case. */ 854a7c91847Schristos !reposdirname_absolute 855a7c91847Schristos && !strcmp (dir_name, ".") 856a7c91847Schristos && ! isdir (CVSADM)) 857a7c91847Schristos { 858a7c91847Schristos char *repo; 859a7c91847Schristos char *r; 860a7c91847Schristos 861a7c91847Schristos newdir = 1; 862a7c91847Schristos 863a7c91847Schristos /* If toplevel_repos doesn't have at least one character, then the 864a7c91847Schristos * reference to r[-1] below could be out of bounds. 865a7c91847Schristos */ 866a7c91847Schristos assert (*toplevel_repos); 867a7c91847Schristos 868a7c91847Schristos repo = xmalloc (strlen (toplevel_repos) 869a7c91847Schristos + 10); 870a7c91847Schristos strcpy (repo, toplevel_repos); 871a7c91847Schristos r = repo + strlen (repo); 872a7c91847Schristos if (r[-1] != '.' || r[-2] != '/') 873a7c91847Schristos strcpy (r, "/."); 874a7c91847Schristos 875a7c91847Schristos Create_Admin (".", ".", repo, NULL, NULL, 0, 1, 1); 876a7c91847Schristos 877a7c91847Schristos free (repo); 878a7c91847Schristos } 879a7c91847Schristos 880a7c91847Schristos if (CVS_CHDIR (dir_name) < 0) 881a7c91847Schristos { 882a7c91847Schristos char *dir; 883a7c91847Schristos char *dirp; 884a7c91847Schristos 885a7c91847Schristos if (! existence_error (errno)) 886a7c91847Schristos error (1, errno, "could not chdir to %s", dir_name); 887a7c91847Schristos 888a7c91847Schristos /* Directory does not exist, we need to create it. */ 889a7c91847Schristos newdir = 1; 890a7c91847Schristos 891a7c91847Schristos /* Provided we are willing to assume that directories get 892a7c91847Schristos created one at a time, we could simplify this a lot. 893a7c91847Schristos Do note that one aspect still would need to walk the 894a7c91847Schristos dir_name path: the checking for "fncmp (dir, CVSADM)". */ 895a7c91847Schristos 896a7c91847Schristos dir = xmalloc (strlen (dir_name) + 1); 897a7c91847Schristos dirp = dir_name; 898a7c91847Schristos rdirp = reposdirname; 899a7c91847Schristos 900a7c91847Schristos /* This algorithm makes nested directories one at a time 901a7c91847Schristos and create CVS administration files in them. For 902a7c91847Schristos example, we're checking out foo/bar/baz from the 903a7c91847Schristos repository: 904a7c91847Schristos 905a7c91847Schristos 1) create foo, point CVS/Repository to <root>/foo 906a7c91847Schristos 2) .. foo/bar .. <root>/foo/bar 907a7c91847Schristos 3) .. foo/bar/baz .. <root>/foo/bar/baz 908a7c91847Schristos 909a7c91847Schristos As you can see, we're just stepping along DIR_NAME (with 910a7c91847Schristos DIRP) and REPOSDIRNAME (with RDIRP) respectively. 911a7c91847Schristos 912a7c91847Schristos We need to be careful when we are checking out a 913a7c91847Schristos module, however, since DIR_NAME and REPOSDIRNAME are not 914a7c91847Schristos going to be the same. Since modules will not have any 915a7c91847Schristos slashes in their names, we should watch the output of 916a7c91847Schristos STRCHR to decide whether or not we should use STRCHR on 917a7c91847Schristos the RDIRP. That is, if we're down to a module name, 918a7c91847Schristos don't keep picking apart the repository directory name. */ 919a7c91847Schristos 920a7c91847Schristos do 921a7c91847Schristos { 922a7c91847Schristos dirp = strchr (dirp, '/'); 923a7c91847Schristos if (dirp) 924a7c91847Schristos { 925a7c91847Schristos strncpy (dir, dir_name, dirp - dir_name); 926a7c91847Schristos dir[dirp - dir_name] = '\0'; 927a7c91847Schristos /* Skip the slash. */ 928a7c91847Schristos ++dirp; 929a7c91847Schristos if (!rdirp) 930a7c91847Schristos /* This just means that the repository string has 931a7c91847Schristos fewer components than the dir_name string. But 932a7c91847Schristos that is OK (e.g. see modules3-8 in testsuite). */ 933a7c91847Schristos ; 934a7c91847Schristos else 935a7c91847Schristos rdirp = strchr (rdirp, '/'); 936a7c91847Schristos } 937a7c91847Schristos else 938a7c91847Schristos { 939a7c91847Schristos /* If there are no more slashes in the dir name, 940a7c91847Schristos we're down to the most nested directory -OR- to 941a7c91847Schristos the name of a module. In the first case, we 942a7c91847Schristos should be down to a DIRP that has no slashes, 943a7c91847Schristos so it won't help/hurt to do another STRCHR call 944a7c91847Schristos on DIRP. It will definitely hurt, however, if 945a7c91847Schristos we're down to a module name, since a module 946a7c91847Schristos name can point to a nested directory (that is, 947a7c91847Schristos DIRP will still have slashes in it. Therefore, 948a7c91847Schristos we should set it to NULL so the routine below 949a7c91847Schristos copies the contents of REMOTEDIRNAME onto the 950a7c91847Schristos root repository directory (does this if rdirp 951a7c91847Schristos is set to NULL, because we used to do an extra 952a7c91847Schristos STRCHR call here). */ 953a7c91847Schristos 954a7c91847Schristos rdirp = NULL; 955a7c91847Schristos strcpy (dir, dir_name); 956a7c91847Schristos } 957a7c91847Schristos 958a7c91847Schristos if (fncmp (dir, CVSADM) == 0) 959a7c91847Schristos { 960a7c91847Schristos error (0, 0, "cannot create a directory named %s", dir); 961a7c91847Schristos error (0, 0, "because CVS uses \"%s\" for its own uses", 962a7c91847Schristos CVSADM); 963a7c91847Schristos error (1, 0, "rename the directory and try again"); 964a7c91847Schristos } 965a7c91847Schristos 966a7c91847Schristos if (mkdir_if_needed (dir)) 967a7c91847Schristos { 968a7c91847Schristos /* It already existed, fine. Just keep going. */ 969a7c91847Schristos } 970a7c91847Schristos else if (!strcmp (cvs_cmd_name, "export")) 971a7c91847Schristos /* Don't create CVSADM directories if this is export. */ 972a7c91847Schristos ; 973a7c91847Schristos else 974a7c91847Schristos { 975a7c91847Schristos /* 976a7c91847Schristos * Put repository in CVS/Repository. For historical 977a7c91847Schristos * (pre-CVS/Root) reasons, this is an absolute pathname, 978a7c91847Schristos * but what really matters is the part of it which is 979a7c91847Schristos * relative to cvsroot. 980a7c91847Schristos */ 981a7c91847Schristos char *repo; 982a7c91847Schristos char *r, *b; 983a7c91847Schristos 984a7c91847Schristos repo = xmalloc (strlen (reposdirname) 985a7c91847Schristos + strlen (toplevel_repos) 986a7c91847Schristos + 80); 987a7c91847Schristos if (reposdirname_absolute) 988a7c91847Schristos r = repo; 989a7c91847Schristos else 990a7c91847Schristos { 991a7c91847Schristos strcpy (repo, toplevel_repos); 992a7c91847Schristos strcat (repo, "/"); 993a7c91847Schristos r = repo + strlen (repo); 994a7c91847Schristos } 995a7c91847Schristos 996a7c91847Schristos if (rdirp) 997a7c91847Schristos { 998a7c91847Schristos /* See comment near start of function; the only 999a7c91847Schristos way that the server can put the right thing 1000a7c91847Schristos in each CVS/Repository file is to create the 1001a7c91847Schristos directories one at a time. I think that the 1002a7c91847Schristos CVS server has been doing this all along. */ 1003a7c91847Schristos error (0, 0, "\ 1004a7c91847Schristos warning: server is not creating directories one at a time"); 1005a7c91847Schristos strncpy (r, reposdirname, rdirp - reposdirname); 1006a7c91847Schristos r[rdirp - reposdirname] = '\0'; 1007a7c91847Schristos } 1008a7c91847Schristos else 1009a7c91847Schristos strcpy (r, reposdirname); 1010a7c91847Schristos 1011a7c91847Schristos Create_Admin (dir, dir, repo, NULL, NULL, 0, 0, 1); 1012a7c91847Schristos free (repo); 1013a7c91847Schristos 1014a7c91847Schristos b = strrchr (dir, '/'); 1015a7c91847Schristos if (!b) 1016a7c91847Schristos Subdir_Register (NULL, NULL, dir); 1017a7c91847Schristos else 1018a7c91847Schristos { 1019a7c91847Schristos *b = '\0'; 1020a7c91847Schristos Subdir_Register (NULL, dir, b + 1); 1021a7c91847Schristos *b = '/'; 1022a7c91847Schristos } 1023a7c91847Schristos } 1024a7c91847Schristos 1025a7c91847Schristos if (rdirp) 1026a7c91847Schristos { 1027a7c91847Schristos /* Skip the slash. */ 1028a7c91847Schristos ++rdirp; 1029a7c91847Schristos } 1030a7c91847Schristos 1031a7c91847Schristos } while (dirp); 1032a7c91847Schristos free (dir); 1033a7c91847Schristos /* Now it better work. */ 1034a7c91847Schristos if (CVS_CHDIR (dir_name) < 0) 1035a7c91847Schristos error (1, errno, "could not chdir to %s", dir_name); 1036a7c91847Schristos } 1037a7c91847Schristos else if (!strcmp (cvs_cmd_name, "export")) 1038a7c91847Schristos /* Don't create CVSADM directories if this is export. */ 1039a7c91847Schristos ; 1040a7c91847Schristos else if (!isdir (CVSADM)) 1041a7c91847Schristos { 1042a7c91847Schristos /* 1043a7c91847Schristos * Put repository in CVS/Repository. For historical 1044a7c91847Schristos * (pre-CVS/Root) reasons, this is an absolute pathname, 1045a7c91847Schristos * but what really matters is the part of it which is 1046a7c91847Schristos * relative to cvsroot. 1047a7c91847Schristos */ 1048a7c91847Schristos char *repo; 1049a7c91847Schristos 1050a7c91847Schristos if (reposdirname_absolute) 1051a7c91847Schristos repo = reposdirname; 1052a7c91847Schristos else 1053a7c91847Schristos repo = Xasprintf ("%s/%s", toplevel_repos, reposdirname); 1054a7c91847Schristos 1055a7c91847Schristos Create_Admin (".", ".", repo, NULL, NULL, 0, 1, 1); 1056a7c91847Schristos if (repo != reposdirname) 1057a7c91847Schristos free (repo); 1058a7c91847Schristos } 1059a7c91847Schristos 1060a7c91847Schristos if (strcmp (cvs_cmd_name, "export")) 1061a7c91847Schristos { 1062a7c91847Schristos last_entries = Entries_Open (0, dir_name); 1063a7c91847Schristos 1064a7c91847Schristos /* If this is a newly created directory, we will record 1065a7c91847Schristos all subdirectory information, so call Subdirs_Known in 1066a7c91847Schristos case there are no subdirectories. If this is not a 1067a7c91847Schristos newly created directory, it may be an old working 1068a7c91847Schristos directory from before we recorded subdirectory 1069a7c91847Schristos information in the Entries file. We force a search for 1070a7c91847Schristos all subdirectories now, to make sure our subdirectory 1071a7c91847Schristos information is up to date. If the Entries file does 1072a7c91847Schristos record subdirectory information, then this call only 1073a7c91847Schristos does list manipulation. */ 1074a7c91847Schristos if (newdir) 1075a7c91847Schristos Subdirs_Known (last_entries); 1076a7c91847Schristos else 1077a7c91847Schristos { 1078a7c91847Schristos List *dirlist; 1079a7c91847Schristos 1080a7c91847Schristos dirlist = Find_Directories (NULL, W_LOCAL, last_entries); 1081a7c91847Schristos dellist (&dirlist); 1082a7c91847Schristos } 1083a7c91847Schristos } 1084a7c91847Schristos free (reposdirname); 1085a7c91847Schristos (*func) (data, last_entries, short_pathname, filename); 1086a7c91847Schristos if (last_entries) 1087a7c91847Schristos Entries_Close (last_entries); 1088a7c91847Schristos free (dir_name); 1089a7c91847Schristos free (short_pathname); 1090a7c91847Schristos free (reposname); 1091a7c91847Schristos } 1092a7c91847Schristos 1093a7c91847Schristos 1094a7c91847Schristos 1095a7c91847Schristos static void 1096a7c91847Schristos copy_a_file (void *data, List *ent_list, const char *short_pathname, 1097a7c91847Schristos const char *filename) 1098a7c91847Schristos { 1099a7c91847Schristos char *newname; 1100a7c91847Schristos 1101a7c91847Schristos read_line (&newname); 1102a7c91847Schristos 1103a7c91847Schristos #ifdef USE_VMS_FILENAMES 1104a7c91847Schristos { 1105a7c91847Schristos /* Mogrify the filename so VMS is happy with it. */ 1106a7c91847Schristos char *p; 1107a7c91847Schristos for(p = newname; *p; p++) 1108a7c91847Schristos if(*p == '.' || *p == '#') *p = '_'; 1109a7c91847Schristos } 1110a7c91847Schristos #endif 1111a7c91847Schristos /* cvsclient.texi has said for a long time that newname must be in the 1112a7c91847Schristos same directory. Wouldn't want a malicious or buggy server overwriting 1113a7c91847Schristos ~/.profile, /etc/passwd, or anything like that. */ 1114a7c91847Schristos if (last_component (newname) != newname) 1115a7c91847Schristos error (1, 0, "protocol error: Copy-file tried to specify directory"); 1116a7c91847Schristos 1117a7c91847Schristos if (unlink_file (newname) && !existence_error (errno)) 1118a7c91847Schristos error (0, errno, "unable to remove %s", newname); 1119a7c91847Schristos copy_file (filename, newname); 1120a7c91847Schristos free (newname); 1121a7c91847Schristos } 1122a7c91847Schristos 1123a7c91847Schristos 1124a7c91847Schristos 1125a7c91847Schristos static void 1126a7c91847Schristos handle_copy_file (char *args, size_t len) 1127a7c91847Schristos { 1128a7c91847Schristos call_in_directory (args, copy_a_file, NULL); 1129a7c91847Schristos } 1130a7c91847Schristos 1131a7c91847Schristos 1132a7c91847Schristos 1133a7c91847Schristos /* Read from the server the count for the length of a file, then read 1134a7c91847Schristos the contents of that file and write them to FILENAME. FULLNAME is 1135a7c91847Schristos the name of the file for use in error messages. FIXME-someday: 1136a7c91847Schristos extend this to deal with compressed files and make update_entries 1137a7c91847Schristos use it. On error, gives a fatal error. */ 1138a7c91847Schristos static void 1139274254cdSchristos read_counted_file (const char *filename, const char *fullname) 1140a7c91847Schristos { 1141a7c91847Schristos char *size_string; 1142a7c91847Schristos size_t size; 1143a7c91847Schristos char *buf; 1144a7c91847Schristos 1145a7c91847Schristos /* Pointers in buf to the place to put data which will be read, 1146a7c91847Schristos and the data which needs to be written, respectively. */ 1147a7c91847Schristos char *pread; 1148a7c91847Schristos char *pwrite; 1149a7c91847Schristos /* Number of bytes left to read and number of bytes in buf waiting to 1150a7c91847Schristos be written, respectively. */ 1151a7c91847Schristos size_t nread; 1152a7c91847Schristos size_t nwrite; 1153a7c91847Schristos 1154a7c91847Schristos FILE *fp; 1155a7c91847Schristos 1156a7c91847Schristos read_line (&size_string); 1157a7c91847Schristos if (size_string[0] == 'z') 1158a7c91847Schristos error (1, 0, "\ 1159a7c91847Schristos protocol error: compressed files not supported for that operation"); 1160a7c91847Schristos /* FIXME: should be doing more error checking, probably. Like using 1161a7c91847Schristos strtoul and making sure we used up the whole line. */ 1162a7c91847Schristos size = atoi (size_string); 1163a7c91847Schristos free (size_string); 1164a7c91847Schristos 1165a7c91847Schristos /* A more sophisticated implementation would use only a limited amount 1166a7c91847Schristos of buffer space (8K perhaps), and read that much at a time. We allocate 1167a7c91847Schristos a buffer for the whole file only to make it easy to keep track what 1168a7c91847Schristos needs to be read and written. */ 1169a7c91847Schristos buf = xmalloc (size); 1170a7c91847Schristos 1171a7c91847Schristos /* FIXME-someday: caller should pass in a flag saying whether it 1172a7c91847Schristos is binary or not. I haven't carefully looked into whether 1173a7c91847Schristos CVS/Template files should use local text file conventions or 1174a7c91847Schristos not. */ 1175a7c91847Schristos fp = CVS_FOPEN (filename, "wb"); 1176a7c91847Schristos if (!fp) 1177a7c91847Schristos error (1, errno, "cannot write %s", fullname); 1178a7c91847Schristos nread = size; 1179a7c91847Schristos nwrite = 0; 1180a7c91847Schristos pread = buf; 1181a7c91847Schristos pwrite = buf; 1182a7c91847Schristos while (nread > 0 || nwrite > 0) 1183a7c91847Schristos { 1184a7c91847Schristos size_t n; 1185a7c91847Schristos 1186a7c91847Schristos if (nread > 0) 1187a7c91847Schristos { 1188a7c91847Schristos n = try_read_from_server (pread, nread); 1189a7c91847Schristos nread -= n; 1190a7c91847Schristos pread += n; 1191a7c91847Schristos nwrite += n; 1192a7c91847Schristos } 1193a7c91847Schristos 1194a7c91847Schristos if (nwrite > 0) 1195a7c91847Schristos { 1196a7c91847Schristos n = fwrite (pwrite, sizeof *pwrite, nwrite, fp); 1197a7c91847Schristos if (ferror (fp)) 1198a7c91847Schristos error (1, errno, "cannot write %s", fullname); 1199a7c91847Schristos nwrite -= n; 1200a7c91847Schristos pwrite += n; 1201a7c91847Schristos } 1202a7c91847Schristos } 1203a7c91847Schristos free (buf); 1204a7c91847Schristos if (fclose (fp) < 0) 1205a7c91847Schristos error (1, errno, "cannot close %s", fullname); 1206a7c91847Schristos } 1207a7c91847Schristos 1208a7c91847Schristos 1209a7c91847Schristos 1210a7c91847Schristos /* OK, we want to swallow the "U foo.c" response and then output it only 1211a7c91847Schristos if we can update the file. In the future we probably want some more 1212a7c91847Schristos systematic approach to parsing tagged text, but for now we keep it 1213a7c91847Schristos ad hoc. "Why," I hear you cry, "do we not just look at the 1214a7c91847Schristos Update-existing and Created responses?" That is an excellent question, 1215a7c91847Schristos and the answer is roughly conservatism/laziness--I haven't read through 1216a7c91847Schristos update.c enough to figure out the exact correspondence or lack thereof 1217a7c91847Schristos between those responses and a "U foo.c" line (note that Merged, from 1218a7c91847Schristos join_file, can be either "C foo" or "U foo" depending on the context). */ 1219a7c91847Schristos /* Nonzero if we have seen +updated and not -updated. */ 1220a7c91847Schristos static int updated_seen; 1221a7c91847Schristos /* Filename from an "fname" tagged response within +updated/-updated. */ 1222a7c91847Schristos static char *updated_fname; 1223a7c91847Schristos 1224a7c91847Schristos /* This struct is used to hold data when reading the +importmergecmd 1225a7c91847Schristos and -importmergecmd tags. We put the variables in a struct only 1226a7c91847Schristos for namespace issues. FIXME: As noted above, we need to develop a 1227a7c91847Schristos more systematic approach. */ 1228a7c91847Schristos static struct 1229a7c91847Schristos { 1230a7c91847Schristos /* Nonzero if we have seen +importmergecmd and not -importmergecmd. */ 1231a7c91847Schristos int seen; 1232a7c91847Schristos /* Number of conflicts, from a "conflicts" tagged response. */ 1233a7c91847Schristos int conflicts; 1234a7c91847Schristos /* First merge tag, from a "mergetag1" tagged response. */ 1235a7c91847Schristos char *mergetag1; 1236a7c91847Schristos /* Second merge tag, from a "mergetag2" tagged response. */ 1237a7c91847Schristos char *mergetag2; 1238a7c91847Schristos /* Repository, from a "repository" tagged response. */ 1239a7c91847Schristos char *repository; 1240a7c91847Schristos } importmergecmd; 1241a7c91847Schristos 1242a7c91847Schristos /* Nonzero if we should arrange to return with a failure exit status. */ 1243a7c91847Schristos static bool failure_exit; 1244a7c91847Schristos 1245a7c91847Schristos 1246a7c91847Schristos /* 1247a7c91847Schristos * The time stamp of the last file we registered. 1248a7c91847Schristos */ 1249a7c91847Schristos static time_t last_register_time; 1250a7c91847Schristos 1251a7c91847Schristos 1252a7c91847Schristos 1253a7c91847Schristos /* 1254a7c91847Schristos * The Checksum response gives the checksum for the file transferred 1255a7c91847Schristos * over by the next Updated, Merged or Patch response. We just store 1256a7c91847Schristos * it here, and then check it in update_entries. 1257a7c91847Schristos */ 1258a7c91847Schristos static int stored_checksum_valid; 1259a7c91847Schristos static unsigned char stored_checksum[16]; 1260a7c91847Schristos static void 1261a7c91847Schristos handle_checksum (char *args, size_t len) 1262a7c91847Schristos { 1263a7c91847Schristos char *s; 1264a7c91847Schristos char buf[3]; 1265a7c91847Schristos int i; 1266a7c91847Schristos 1267a7c91847Schristos if (stored_checksum_valid) 1268a7c91847Schristos error (1, 0, "Checksum received before last one was used"); 1269a7c91847Schristos 1270a7c91847Schristos s = args; 1271a7c91847Schristos buf[2] = '\0'; 1272a7c91847Schristos for (i = 0; i < 16; i++) 1273a7c91847Schristos { 1274a7c91847Schristos char *bufend; 1275a7c91847Schristos 1276a7c91847Schristos buf[0] = *s++; 1277a7c91847Schristos buf[1] = *s++; 1278a7c91847Schristos stored_checksum[i] = (char) strtol (buf, &bufend, 16); 1279a7c91847Schristos if (bufend != buf + 2) 1280a7c91847Schristos break; 1281a7c91847Schristos } 1282a7c91847Schristos 1283a7c91847Schristos if (i < 16 || *s != '\0') 1284a7c91847Schristos error (1, 0, "Invalid Checksum response: `%s'", args); 1285a7c91847Schristos 1286a7c91847Schristos stored_checksum_valid = 1; 1287a7c91847Schristos } 1288a7c91847Schristos 1289a7c91847Schristos 1290a7c91847Schristos 1291a7c91847Schristos /* Mode that we got in a "Mode" response (malloc'd), or NULL if none. */ 1292a7c91847Schristos static char *stored_mode; 1293a7c91847Schristos static void 1294a7c91847Schristos handle_mode (char *args, size_t len) 1295a7c91847Schristos { 1296a7c91847Schristos if (stored_mode) 1297a7c91847Schristos error (1, 0, "protocol error: duplicate Mode"); 1298a7c91847Schristos stored_mode = xstrdup (args); 1299a7c91847Schristos } 1300a7c91847Schristos 1301a7c91847Schristos 1302a7c91847Schristos 1303a7c91847Schristos /* Nonzero if time was specified in Mod-time. */ 1304a7c91847Schristos static int stored_modtime_valid; 1305a7c91847Schristos /* Time specified in Mod-time. */ 1306a7c91847Schristos static time_t stored_modtime; 1307a7c91847Schristos static void 1308a7c91847Schristos handle_mod_time (char *args, size_t len) 1309a7c91847Schristos { 1310a7c91847Schristos struct timespec newtime; 1311a7c91847Schristos if (stored_modtime_valid) 1312a7c91847Schristos error (0, 0, "protocol error: duplicate Mod-time"); 1313a7c91847Schristos if (get_date (&newtime, args, NULL)) 1314a7c91847Schristos { 1315a7c91847Schristos /* Truncate nanoseconds. */ 1316a7c91847Schristos stored_modtime = newtime.tv_sec; 1317a7c91847Schristos stored_modtime_valid = 1; 1318a7c91847Schristos } 1319a7c91847Schristos else 1320a7c91847Schristos error (0, 0, "protocol error: cannot parse date %s", args); 1321a7c91847Schristos } 1322a7c91847Schristos 1323a7c91847Schristos 1324a7c91847Schristos 1325a7c91847Schristos /* 1326a7c91847Schristos * If we receive a patch, but the patch program fails to apply it, we 1327a7c91847Schristos * want to request the original file. We keep a list of files whose 1328a7c91847Schristos * patches have failed. 1329a7c91847Schristos */ 1330a7c91847Schristos 1331a7c91847Schristos char **failed_patches; 1332a7c91847Schristos int failed_patches_count; 1333a7c91847Schristos 1334a7c91847Schristos struct update_entries_data 1335a7c91847Schristos { 1336a7c91847Schristos enum { 1337a7c91847Schristos /* 1338a7c91847Schristos * We are just getting an Entries line; the local file is 1339a7c91847Schristos * correct. 1340a7c91847Schristos */ 1341a7c91847Schristos UPDATE_ENTRIES_CHECKIN, 1342a7c91847Schristos /* We are getting the file contents as well. */ 1343a7c91847Schristos UPDATE_ENTRIES_UPDATE, 1344a7c91847Schristos /* 1345a7c91847Schristos * We are getting a patch against the existing local file, not 1346a7c91847Schristos * an entire new file. 1347a7c91847Schristos */ 1348a7c91847Schristos UPDATE_ENTRIES_PATCH, 1349a7c91847Schristos /* 1350a7c91847Schristos * We are getting an RCS change text (diff -n output) against 1351a7c91847Schristos * the existing local file, not an entire new file. 1352a7c91847Schristos */ 1353a7c91847Schristos UPDATE_ENTRIES_RCS_DIFF 1354a7c91847Schristos } contents; 1355a7c91847Schristos 1356a7c91847Schristos enum { 1357a7c91847Schristos /* We are replacing an existing file. */ 1358a7c91847Schristos UPDATE_ENTRIES_EXISTING, 1359a7c91847Schristos /* We are creating a new file. */ 1360a7c91847Schristos UPDATE_ENTRIES_NEW, 1361a7c91847Schristos /* We don't know whether it is existing or new. */ 1362a7c91847Schristos UPDATE_ENTRIES_EXISTING_OR_NEW 1363a7c91847Schristos } existp; 1364a7c91847Schristos 1365a7c91847Schristos /* 1366a7c91847Schristos * String to put in the timestamp field or NULL to use the timestamp 1367a7c91847Schristos * of the file. 1368a7c91847Schristos */ 1369a7c91847Schristos char *timestamp; 1370a7c91847Schristos }; 1371a7c91847Schristos 1372a7c91847Schristos 1373a7c91847Schristos 1374a7c91847Schristos /* Update the Entries line for this file. */ 1375a7c91847Schristos static void 1376a7c91847Schristos update_entries (void *data_arg, List *ent_list, const char *short_pathname, 1377a7c91847Schristos const char *filename) 1378a7c91847Schristos { 1379a7c91847Schristos char *entries_line; 1380a7c91847Schristos struct update_entries_data *data = data_arg; 1381a7c91847Schristos 1382a7c91847Schristos char *cp; 1383a7c91847Schristos char *user; 1384a7c91847Schristos char *vn; 1385a7c91847Schristos /* Timestamp field. Always empty according to the protocol. */ 1386a7c91847Schristos char *ts; 1387a7c91847Schristos char *options = NULL; 1388a7c91847Schristos char *tag = NULL; 1389a7c91847Schristos char *date = NULL; 1390a7c91847Schristos char *tag_or_date; 1391a7c91847Schristos char *scratch_entries = NULL; 1392a7c91847Schristos int bin; 1393a7c91847Schristos 1394a7c91847Schristos #ifdef UTIME_EXPECTS_WRITABLE 1395a7c91847Schristos int change_it_back = 0; 1396a7c91847Schristos #endif 1397a7c91847Schristos 1398a7c91847Schristos read_line (&entries_line); 1399a7c91847Schristos 1400a7c91847Schristos /* 1401a7c91847Schristos * Parse the entries line. 1402a7c91847Schristos */ 1403a7c91847Schristos scratch_entries = xstrdup (entries_line); 1404a7c91847Schristos 1405a7c91847Schristos if (scratch_entries[0] != '/') 1406a7c91847Schristos error (1, 0, "bad entries line `%s' from server", entries_line); 1407a7c91847Schristos user = scratch_entries + 1; 1408a7c91847Schristos if (!(cp = strchr (user, '/'))) 1409a7c91847Schristos error (1, 0, "bad entries line `%s' from server", entries_line); 1410a7c91847Schristos *cp++ = '\0'; 1411a7c91847Schristos vn = cp; 1412a7c91847Schristos if (!(cp = strchr (vn, '/'))) 1413a7c91847Schristos error (1, 0, "bad entries line `%s' from server", entries_line); 1414a7c91847Schristos *cp++ = '\0'; 1415a7c91847Schristos 1416a7c91847Schristos ts = cp; 1417a7c91847Schristos if (!(cp = strchr (ts, '/'))) 1418a7c91847Schristos error (1, 0, "bad entries line `%s' from server", entries_line); 1419a7c91847Schristos *cp++ = '\0'; 1420a7c91847Schristos options = cp; 1421a7c91847Schristos if (!(cp = strchr (options, '/'))) 1422a7c91847Schristos error (1, 0, "bad entries line `%s' from server", entries_line); 1423a7c91847Schristos *cp++ = '\0'; 1424a7c91847Schristos tag_or_date = cp; 1425a7c91847Schristos 1426a7c91847Schristos /* If a slash ends the tag_or_date, ignore everything after it. */ 1427a7c91847Schristos cp = strchr (tag_or_date, '/'); 1428a7c91847Schristos if (cp) 1429a7c91847Schristos *cp = '\0'; 1430a7c91847Schristos if (*tag_or_date == 'T') 1431a7c91847Schristos tag = tag_or_date + 1; 1432a7c91847Schristos else if (*tag_or_date == 'D') 1433a7c91847Schristos date = tag_or_date + 1; 1434a7c91847Schristos 1435a7c91847Schristos /* Done parsing the entries line. */ 1436a7c91847Schristos 1437a7c91847Schristos if (data->contents == UPDATE_ENTRIES_UPDATE 1438a7c91847Schristos || data->contents == UPDATE_ENTRIES_PATCH 1439a7c91847Schristos || data->contents == UPDATE_ENTRIES_RCS_DIFF) 1440a7c91847Schristos { 1441a7c91847Schristos char *size_string; 1442a7c91847Schristos char *mode_string; 1443a7c91847Schristos int size; 1444a7c91847Schristos char *buf; 1445a7c91847Schristos char *temp_filename; 1446a7c91847Schristos int use_gzip; 1447a7c91847Schristos int patch_failed; 1448a7c91847Schristos 1449a7c91847Schristos read_line (&mode_string); 1450a7c91847Schristos 1451a7c91847Schristos read_line (&size_string); 1452a7c91847Schristos if (size_string[0] == 'z') 1453a7c91847Schristos { 1454a7c91847Schristos use_gzip = 1; 1455a7c91847Schristos size = atoi (size_string+1); 1456a7c91847Schristos } 1457a7c91847Schristos else 1458a7c91847Schristos { 1459a7c91847Schristos use_gzip = 0; 1460a7c91847Schristos size = atoi (size_string); 1461a7c91847Schristos } 1462a7c91847Schristos free (size_string); 1463a7c91847Schristos 1464a7c91847Schristos /* Note that checking this separately from writing the file is 1465a7c91847Schristos a race condition: if the existence or lack thereof of the 1466a7c91847Schristos file changes between now and the actual calls which 1467a7c91847Schristos operate on it, we lose. However (a) there are so many 1468a7c91847Schristos cases, I'm reluctant to try to fix them all, (b) in some 1469a7c91847Schristos cases the system might not even have a system call which 1470a7c91847Schristos does the right thing, and (c) it isn't clear this needs to 1471a7c91847Schristos work. */ 1472a7c91847Schristos if (data->existp == UPDATE_ENTRIES_EXISTING 1473a7c91847Schristos && !isfile (filename)) 1474a7c91847Schristos /* Emit a warning and update the file anyway. */ 1475a7c91847Schristos error (0, 0, "warning: %s unexpectedly disappeared", 1476a7c91847Schristos short_pathname); 1477a7c91847Schristos 1478a7c91847Schristos if (data->existp == UPDATE_ENTRIES_NEW 1479a7c91847Schristos && isfile (filename)) 1480a7c91847Schristos { 1481a7c91847Schristos /* Emit a warning and refuse to update the file; we don't want 1482a7c91847Schristos to clobber a user's file. */ 1483a7c91847Schristos size_t nread; 1484a7c91847Schristos size_t toread; 1485a7c91847Schristos 1486a7c91847Schristos /* size should be unsigned, but until we get around to fixing 1487a7c91847Schristos that, work around it. */ 1488a7c91847Schristos size_t usize; 1489a7c91847Schristos 1490a7c91847Schristos char buf[8192]; 1491a7c91847Schristos 1492a7c91847Schristos /* This error might be confusing; it isn't really clear to 1493a7c91847Schristos the user what to do about it. Keep in mind that it has 1494a7c91847Schristos several causes: (1) something/someone creates the file 1495a7c91847Schristos during the time that CVS is running, (2) the repository 1496a7c91847Schristos has two files whose names clash for the client because 1497a7c91847Schristos of case-insensitivity or similar causes, See 3 for 1498a7c91847Schristos additional notes. (3) a special case of this is that a 1499a7c91847Schristos file gets renamed for example from a.c to A.C. A 1500a7c91847Schristos "cvs update" on a case-insensitive client will get this 1501a7c91847Schristos error. In this case and in case 2, the filename 1502a7c91847Schristos (short_pathname) printed in the error message will likely _not_ 1503a7c91847Schristos have the same case as seen by the user in a directory listing. 1504a7c91847Schristos (4) the client has a file which the server doesn't know 1505a7c91847Schristos about (e.g. "? foo" file), and that name clashes with a file 1506a7c91847Schristos the server does know about, (5) classify.c will print the same 1507a7c91847Schristos message for other reasons. 1508a7c91847Schristos 1509a7c91847Schristos I hope the above paragraph makes it clear that making this 1510a7c91847Schristos clearer is not a one-line fix. */ 1511a7c91847Schristos error (0, 0, "move away `%s'; it is in the way", short_pathname); 1512a7c91847Schristos if (updated_fname) 1513a7c91847Schristos { 1514a7c91847Schristos cvs_output ("C ", 0); 1515a7c91847Schristos cvs_output (updated_fname, 0); 1516a7c91847Schristos cvs_output ("\n", 1); 1517a7c91847Schristos } 1518a7c91847Schristos failure_exit = true; 1519a7c91847Schristos 1520a7c91847Schristos discard_file_and_return: 1521a7c91847Schristos /* Now read and discard the file contents. */ 1522a7c91847Schristos usize = size; 1523a7c91847Schristos nread = 0; 1524a7c91847Schristos while (nread < usize) 1525a7c91847Schristos { 1526a7c91847Schristos toread = usize - nread; 1527a7c91847Schristos if (toread > sizeof buf) 1528a7c91847Schristos toread = sizeof buf; 1529a7c91847Schristos 1530a7c91847Schristos nread += try_read_from_server (buf, toread); 1531a7c91847Schristos if (nread == usize) 1532a7c91847Schristos break; 1533a7c91847Schristos } 1534a7c91847Schristos 1535a7c91847Schristos free (mode_string); 1536a7c91847Schristos free (scratch_entries); 1537a7c91847Schristos free (entries_line); 1538a7c91847Schristos 1539a7c91847Schristos /* The Mode, Mod-time, and Checksum responses should not carry 1540a7c91847Schristos over to a subsequent Created (or whatever) response, even 1541a7c91847Schristos in the error case. */ 1542a7c91847Schristos if (stored_mode) 1543a7c91847Schristos { 1544a7c91847Schristos free (stored_mode); 1545a7c91847Schristos stored_mode = NULL; 1546a7c91847Schristos } 1547a7c91847Schristos stored_modtime_valid = 0; 1548a7c91847Schristos stored_checksum_valid = 0; 1549a7c91847Schristos 1550a7c91847Schristos if (updated_fname) 1551a7c91847Schristos { 1552a7c91847Schristos free (updated_fname); 1553a7c91847Schristos updated_fname = NULL; 1554a7c91847Schristos } 1555a7c91847Schristos return; 1556a7c91847Schristos } 1557a7c91847Schristos 1558a7c91847Schristos temp_filename = xmalloc (strlen (filename) + 80); 1559a7c91847Schristos #ifdef USE_VMS_FILENAMES 1560a7c91847Schristos /* A VMS rename of "blah.dat" to "foo" to implies a 1561a7c91847Schristos destination of "foo.dat" which is unfortinate for CVS */ 1562a7c91847Schristos sprintf (temp_filename, "%s_new_", filename); 1563a7c91847Schristos #else 1564a7c91847Schristos #ifdef _POSIX_NO_TRUNC 1565a7c91847Schristos sprintf (temp_filename, ".new.%.9s", filename); 1566a7c91847Schristos #else /* _POSIX_NO_TRUNC */ 1567a7c91847Schristos sprintf (temp_filename, ".new.%s", filename); 1568a7c91847Schristos #endif /* _POSIX_NO_TRUNC */ 1569a7c91847Schristos #endif /* USE_VMS_FILENAMES */ 1570a7c91847Schristos 1571a7c91847Schristos buf = xmalloc (size); 1572a7c91847Schristos 1573a7c91847Schristos /* Some systems, like OS/2 and Windows NT, end lines with CRLF 1574a7c91847Schristos instead of just LF. Format translation is done in the C 1575a7c91847Schristos library I/O funtions. Here we tell them whether or not to 1576a7c91847Schristos convert -- if this file is marked "binary" with the RCS -kb 1577a7c91847Schristos flag, then we don't want to convert, else we do (because 1578a7c91847Schristos CVS assumes text files by default). */ 1579a7c91847Schristos 1580a7c91847Schristos if (options) 1581a7c91847Schristos bin = !strcmp (options, "-kb"); 1582a7c91847Schristos else 1583a7c91847Schristos bin = 0; 1584a7c91847Schristos 1585a7c91847Schristos if (data->contents == UPDATE_ENTRIES_RCS_DIFF) 1586a7c91847Schristos { 1587a7c91847Schristos /* This is an RCS change text. We just hold the change 1588a7c91847Schristos text in memory. */ 1589a7c91847Schristos 1590a7c91847Schristos if (use_gzip) 1591a7c91847Schristos error (1, 0, 1592a7c91847Schristos "server error: gzip invalid with RCS change text"); 1593a7c91847Schristos 1594a7c91847Schristos read_from_server (buf, size); 1595a7c91847Schristos } 1596a7c91847Schristos else 1597a7c91847Schristos { 1598a7c91847Schristos int fd; 1599a7c91847Schristos 1600a7c91847Schristos fd = CVS_OPEN (temp_filename, 1601a7c91847Schristos (O_WRONLY | O_CREAT | O_TRUNC 1602a7c91847Schristos | (bin ? OPEN_BINARY : 0)), 1603a7c91847Schristos 0777); 1604a7c91847Schristos 1605a7c91847Schristos if (fd < 0) 1606a7c91847Schristos { 1607a7c91847Schristos /* I can see a case for making this a fatal error; for 1608a7c91847Schristos a condition like disk full or network unreachable 1609a7c91847Schristos (for a file server), carrying on and giving an 1610a7c91847Schristos error on each file seems unnecessary. But if it is 1611a7c91847Schristos a permission problem, or some such, then it is 1612a7c91847Schristos entirely possible that future files will not have 1613a7c91847Schristos the same problem. */ 1614a7c91847Schristos error (0, errno, "cannot write %s", short_pathname); 1615a7c91847Schristos free (temp_filename); 1616a7c91847Schristos free (buf); 1617a7c91847Schristos goto discard_file_and_return; 1618a7c91847Schristos } 1619a7c91847Schristos 1620a7c91847Schristos if (size > 0) 1621a7c91847Schristos { 1622a7c91847Schristos read_from_server (buf, size); 1623a7c91847Schristos 1624a7c91847Schristos if (use_gzip) 1625a7c91847Schristos { 1626a7c91847Schristos if (gunzip_and_write (fd, short_pathname, 1627a7c91847Schristos (unsigned char *) buf, size)) 1628a7c91847Schristos error (1, 0, "aborting due to compression error"); 1629a7c91847Schristos } 1630a7c91847Schristos else if (write (fd, buf, size) != size) 1631a7c91847Schristos error (1, errno, "writing %s", short_pathname); 1632a7c91847Schristos } 1633a7c91847Schristos 1634a7c91847Schristos if (close (fd) < 0) 1635a7c91847Schristos error (1, errno, "writing %s", short_pathname); 1636a7c91847Schristos } 1637a7c91847Schristos 1638a7c91847Schristos /* This is after we have read the file from the net (a change 1639a7c91847Schristos from previous versions, where the server would send us 1640a7c91847Schristos "M U foo.c" before Update-existing or whatever), but before 1641a7c91847Schristos we finish writing the file (arguably a bug). The timing 1642a7c91847Schristos affects a user who wants status info about how far we have 1643a7c91847Schristos gotten, and also affects whether "U foo.c" appears in addition 1644a7c91847Schristos to various error messages. */ 1645a7c91847Schristos if (updated_fname) 1646a7c91847Schristos { 1647a7c91847Schristos cvs_output ("U ", 0); 1648a7c91847Schristos cvs_output (updated_fname, 0); 1649a7c91847Schristos cvs_output ("\n", 1); 1650a7c91847Schristos free (updated_fname); 1651a7c91847Schristos updated_fname = 0; 1652a7c91847Schristos } 1653a7c91847Schristos 1654a7c91847Schristos patch_failed = 0; 1655a7c91847Schristos 1656a7c91847Schristos if (data->contents == UPDATE_ENTRIES_UPDATE) 1657a7c91847Schristos { 1658a7c91847Schristos rename_file (temp_filename, filename); 1659a7c91847Schristos } 1660a7c91847Schristos else if (data->contents == UPDATE_ENTRIES_PATCH) 1661a7c91847Schristos { 1662a7c91847Schristos /* You might think we could just leave Patched out of 1663a7c91847Schristos Valid-responses and not get this response. However, if 1664a7c91847Schristos memory serves, the CVS 1.9 server bases this on -u 1665a7c91847Schristos (update-patches), and there is no way for us to send -u 1666a7c91847Schristos or not based on whether the server supports "Rcs-diff". 1667a7c91847Schristos 1668a7c91847Schristos Fall back to transmitting entire files. */ 1669a7c91847Schristos patch_failed = 1; 1670a7c91847Schristos } 1671a7c91847Schristos else 1672a7c91847Schristos { 1673a7c91847Schristos char *filebuf; 1674a7c91847Schristos size_t filebufsize; 1675a7c91847Schristos size_t nread; 1676a7c91847Schristos char *patchedbuf; 1677a7c91847Schristos size_t patchedlen; 1678a7c91847Schristos 1679a7c91847Schristos /* Handle UPDATE_ENTRIES_RCS_DIFF. */ 1680a7c91847Schristos 1681a7c91847Schristos if (!isfile (filename)) 1682a7c91847Schristos error (1, 0, "patch original file %s does not exist", 1683a7c91847Schristos short_pathname); 1684a7c91847Schristos filebuf = NULL; 1685a7c91847Schristos filebufsize = 0; 1686a7c91847Schristos nread = 0; 1687a7c91847Schristos 1688a7c91847Schristos get_file (filename, short_pathname, bin ? FOPEN_BINARY_READ : "r", 1689a7c91847Schristos &filebuf, &filebufsize, &nread); 1690a7c91847Schristos /* At this point the contents of the existing file are in 1691a7c91847Schristos FILEBUF, and the length of the contents is in NREAD. 1692a7c91847Schristos The contents of the patch from the network are in BUF, 1693a7c91847Schristos and the length of the patch is in SIZE. */ 1694a7c91847Schristos 1695a7c91847Schristos if (! rcs_change_text (short_pathname, filebuf, nread, buf, size, 1696a7c91847Schristos &patchedbuf, &patchedlen)) 1697a7c91847Schristos patch_failed = 1; 1698a7c91847Schristos else 1699a7c91847Schristos { 1700a7c91847Schristos if (stored_checksum_valid) 1701a7c91847Schristos { 1702a7c91847Schristos unsigned char checksum[16]; 1703a7c91847Schristos 1704a7c91847Schristos /* We have a checksum. Check it before writing 1705a7c91847Schristos the file out, so that we don't have to read it 1706a7c91847Schristos back in again. */ 1707a7c91847Schristos md5_buffer (patchedbuf, patchedlen, checksum); 1708a7c91847Schristos if (memcmp (checksum, stored_checksum, 16) != 0) 1709a7c91847Schristos { 1710a7c91847Schristos error (0, 0, 1711a7c91847Schristos "checksum failure after patch to %s; will refetch", 1712a7c91847Schristos short_pathname); 1713a7c91847Schristos 1714a7c91847Schristos patch_failed = 1; 1715a7c91847Schristos } 1716a7c91847Schristos 1717a7c91847Schristos stored_checksum_valid = 0; 1718a7c91847Schristos } 1719a7c91847Schristos 1720a7c91847Schristos if (! patch_failed) 1721a7c91847Schristos { 1722a7c91847Schristos FILE *e; 1723a7c91847Schristos 1724a7c91847Schristos e = xfopen (temp_filename, 1725a7c91847Schristos bin ? FOPEN_BINARY_WRITE : "w"); 1726a7c91847Schristos if (fwrite (patchedbuf, sizeof *patchedbuf, patchedlen, e) 1727a7c91847Schristos != patchedlen) 1728a7c91847Schristos error (1, errno, "cannot write %s", temp_filename); 1729a7c91847Schristos if (fclose (e) == EOF) 1730a7c91847Schristos error (1, errno, "cannot close %s", temp_filename); 1731a7c91847Schristos rename_file (temp_filename, filename); 1732a7c91847Schristos } 1733a7c91847Schristos 1734a7c91847Schristos free (patchedbuf); 1735a7c91847Schristos } 1736a7c91847Schristos 1737a7c91847Schristos free (filebuf); 1738a7c91847Schristos } 1739a7c91847Schristos 1740a7c91847Schristos free (temp_filename); 1741a7c91847Schristos 1742a7c91847Schristos if (stored_checksum_valid && ! patch_failed) 1743a7c91847Schristos { 1744a7c91847Schristos FILE *e; 1745a7c91847Schristos struct md5_ctx context; 1746a7c91847Schristos unsigned char buf[8192]; 1747a7c91847Schristos unsigned len; 1748a7c91847Schristos unsigned char checksum[16]; 1749a7c91847Schristos 1750a7c91847Schristos /* 1751a7c91847Schristos * Compute the MD5 checksum. This will normally only be 1752a7c91847Schristos * used when receiving a patch, so we always compute it 1753a7c91847Schristos * here on the final file, rather than on the received 1754a7c91847Schristos * data. 1755a7c91847Schristos * 1756a7c91847Schristos * Note that if the file is a text file, we should read it 1757a7c91847Schristos * here using text mode, so its lines will be terminated the same 1758a7c91847Schristos * way they were transmitted. 1759a7c91847Schristos */ 1760a7c91847Schristos e = CVS_FOPEN (filename, "r"); 1761a7c91847Schristos if (!e) 1762a7c91847Schristos error (1, errno, "could not open %s", short_pathname); 1763a7c91847Schristos 1764a7c91847Schristos md5_init_ctx (&context); 1765a7c91847Schristos while ((len = fread (buf, 1, sizeof buf, e)) != 0) 1766a7c91847Schristos md5_process_bytes (buf, len, &context); 1767a7c91847Schristos if (ferror (e)) 1768a7c91847Schristos error (1, errno, "could not read %s", short_pathname); 1769a7c91847Schristos md5_finish_ctx (&context, checksum); 1770a7c91847Schristos 1771a7c91847Schristos fclose (e); 1772a7c91847Schristos 1773a7c91847Schristos stored_checksum_valid = 0; 1774a7c91847Schristos 1775a7c91847Schristos if (memcmp (checksum, stored_checksum, 16) != 0) 1776a7c91847Schristos { 1777a7c91847Schristos if (data->contents != UPDATE_ENTRIES_PATCH) 1778a7c91847Schristos error (1, 0, "checksum failure on %s", 1779a7c91847Schristos short_pathname); 1780a7c91847Schristos 1781a7c91847Schristos error (0, 0, 1782a7c91847Schristos "checksum failure after patch to %s; will refetch", 1783a7c91847Schristos short_pathname); 1784a7c91847Schristos 1785a7c91847Schristos patch_failed = 1; 1786a7c91847Schristos } 1787a7c91847Schristos } 1788a7c91847Schristos 1789a7c91847Schristos if (patch_failed) 1790a7c91847Schristos { 1791a7c91847Schristos /* Save this file to retrieve later. */ 1792a7c91847Schristos failed_patches = xnrealloc (failed_patches, 1793a7c91847Schristos failed_patches_count + 1, 1794a7c91847Schristos sizeof (char *)); 1795a7c91847Schristos failed_patches[failed_patches_count] = xstrdup (short_pathname); 1796a7c91847Schristos ++failed_patches_count; 1797a7c91847Schristos 1798a7c91847Schristos stored_checksum_valid = 0; 1799a7c91847Schristos 1800a7c91847Schristos free (mode_string); 1801a7c91847Schristos free (buf); 1802a7c91847Schristos free (scratch_entries); 1803a7c91847Schristos free (entries_line); 1804a7c91847Schristos 1805a7c91847Schristos return; 1806a7c91847Schristos } 1807a7c91847Schristos 1808a7c91847Schristos { 1809a7c91847Schristos int status = change_mode (filename, mode_string, 1); 1810a7c91847Schristos if (status != 0) 1811a7c91847Schristos error (0, status, "cannot change mode of %s", short_pathname); 1812a7c91847Schristos } 1813a7c91847Schristos 1814a7c91847Schristos free (mode_string); 1815a7c91847Schristos free (buf); 1816a7c91847Schristos } 1817a7c91847Schristos 1818a7c91847Schristos if (stored_mode) 1819a7c91847Schristos { 1820a7c91847Schristos change_mode (filename, stored_mode, 1); 1821a7c91847Schristos free (stored_mode); 1822a7c91847Schristos stored_mode = NULL; 1823a7c91847Schristos } 1824a7c91847Schristos 1825a7c91847Schristos if (stored_modtime_valid) 1826a7c91847Schristos { 1827a7c91847Schristos struct utimbuf t; 1828a7c91847Schristos 1829a7c91847Schristos memset (&t, 0, sizeof (t)); 1830a7c91847Schristos t.modtime = stored_modtime; 1831a7c91847Schristos (void) time (&t.actime); 1832a7c91847Schristos 1833a7c91847Schristos #ifdef UTIME_EXPECTS_WRITABLE 1834a7c91847Schristos if (!iswritable (filename)) 1835a7c91847Schristos { 1836a7c91847Schristos xchmod (filename, 1); 1837a7c91847Schristos change_it_back = 1; 1838a7c91847Schristos } 1839a7c91847Schristos #endif /* UTIME_EXPECTS_WRITABLE */ 1840a7c91847Schristos 1841a7c91847Schristos if (utime (filename, &t) < 0) 1842a7c91847Schristos error (0, errno, "cannot set time on %s", filename); 1843a7c91847Schristos 1844a7c91847Schristos #ifdef UTIME_EXPECTS_WRITABLE 1845a7c91847Schristos if (change_it_back) 1846a7c91847Schristos { 1847a7c91847Schristos xchmod (filename, 0); 1848a7c91847Schristos change_it_back = 0; 1849a7c91847Schristos } 1850a7c91847Schristos #endif /* UTIME_EXPECTS_WRITABLE */ 1851a7c91847Schristos 1852a7c91847Schristos stored_modtime_valid = 0; 1853a7c91847Schristos } 1854a7c91847Schristos 1855a7c91847Schristos /* 1856a7c91847Schristos * Process the entries line. Do this after we've written the file, 1857a7c91847Schristos * since we need the timestamp. 1858a7c91847Schristos */ 1859a7c91847Schristos if (strcmp (cvs_cmd_name, "export")) 1860a7c91847Schristos { 1861a7c91847Schristos char *local_timestamp; 1862a7c91847Schristos char *file_timestamp; 1863a7c91847Schristos 1864a7c91847Schristos (void) time (&last_register_time); 1865a7c91847Schristos 1866a7c91847Schristos local_timestamp = data->timestamp; 1867a7c91847Schristos if (!local_timestamp || ts[0] == '+') 1868a7c91847Schristos file_timestamp = time_stamp (filename); 1869a7c91847Schristos else 1870a7c91847Schristos file_timestamp = NULL; 1871a7c91847Schristos 1872a7c91847Schristos /* 1873a7c91847Schristos * These special version numbers signify that it is not up to 1874a7c91847Schristos * date. Create a dummy timestamp which will never compare 1875a7c91847Schristos * equal to the timestamp of the file. 1876a7c91847Schristos */ 1877a7c91847Schristos if (vn[0] == '\0' || !strcmp (vn, "0") || vn[0] == '-') 1878a7c91847Schristos local_timestamp = "dummy timestamp"; 1879a7c91847Schristos else if (!local_timestamp) 1880a7c91847Schristos { 1881a7c91847Schristos local_timestamp = file_timestamp; 1882a7c91847Schristos 1883a7c91847Schristos /* Checking for cvs_cmd_name of "commit" doesn't seem like 1884a7c91847Schristos the cleanest way to handle this, but it seem to roughly 1885a7c91847Schristos parallel what the :local: code which calls 1886a7c91847Schristos mark_up_to_date ends up amounting to. Some day, should 1887a7c91847Schristos think more about what the Checked-in response means 1888a7c91847Schristos vis-a-vis both Entries and Base and clarify 1889a7c91847Schristos cvsclient.texi accordingly. */ 1890a7c91847Schristos 1891a7c91847Schristos if (!strcmp (cvs_cmd_name, "commit")) 1892a7c91847Schristos mark_up_to_date (filename); 1893a7c91847Schristos } 1894a7c91847Schristos 1895a7c91847Schristos Register (ent_list, filename, vn, local_timestamp, 1896a7c91847Schristos options, tag, date, ts[0] == '+' ? file_timestamp : NULL); 1897a7c91847Schristos 1898a7c91847Schristos if (file_timestamp) 1899a7c91847Schristos free (file_timestamp); 1900a7c91847Schristos 1901a7c91847Schristos } 1902a7c91847Schristos free (scratch_entries); 1903a7c91847Schristos free (entries_line); 1904a7c91847Schristos } 1905a7c91847Schristos 1906a7c91847Schristos 1907a7c91847Schristos 1908a7c91847Schristos static void 1909a7c91847Schristos handle_checked_in (char *args, size_t len) 1910a7c91847Schristos { 1911a7c91847Schristos struct update_entries_data dat; 1912a7c91847Schristos dat.contents = UPDATE_ENTRIES_CHECKIN; 1913a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; 1914a7c91847Schristos dat.timestamp = NULL; 1915a7c91847Schristos call_in_directory (args, update_entries, &dat); 1916a7c91847Schristos } 1917a7c91847Schristos 1918a7c91847Schristos 1919a7c91847Schristos 1920a7c91847Schristos static void 1921a7c91847Schristos handle_new_entry (char *args, size_t len) 1922a7c91847Schristos { 1923a7c91847Schristos struct update_entries_data dat; 1924a7c91847Schristos dat.contents = UPDATE_ENTRIES_CHECKIN; 1925a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; 1926a7c91847Schristos dat.timestamp = "dummy timestamp from new-entry"; 1927a7c91847Schristos call_in_directory (args, update_entries, &dat); 1928a7c91847Schristos } 1929a7c91847Schristos 1930a7c91847Schristos 1931a7c91847Schristos 1932a7c91847Schristos static void 1933a7c91847Schristos handle_updated (char *args, size_t len) 1934a7c91847Schristos { 1935a7c91847Schristos struct update_entries_data dat; 1936a7c91847Schristos dat.contents = UPDATE_ENTRIES_UPDATE; 1937a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; 1938a7c91847Schristos dat.timestamp = NULL; 1939a7c91847Schristos call_in_directory (args, update_entries, &dat); 1940a7c91847Schristos } 1941a7c91847Schristos 1942a7c91847Schristos 1943a7c91847Schristos 1944a7c91847Schristos static void 1945a7c91847Schristos handle_created (char *args, size_t len) 1946a7c91847Schristos { 1947a7c91847Schristos struct update_entries_data dat; 1948a7c91847Schristos dat.contents = UPDATE_ENTRIES_UPDATE; 1949a7c91847Schristos dat.existp = UPDATE_ENTRIES_NEW; 1950a7c91847Schristos dat.timestamp = NULL; 1951a7c91847Schristos call_in_directory (args, update_entries, &dat); 1952a7c91847Schristos } 1953a7c91847Schristos 1954a7c91847Schristos 1955a7c91847Schristos 1956a7c91847Schristos static void 1957a7c91847Schristos handle_update_existing (char *args, size_t len) 1958a7c91847Schristos { 1959a7c91847Schristos struct update_entries_data dat; 1960a7c91847Schristos dat.contents = UPDATE_ENTRIES_UPDATE; 1961a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING; 1962a7c91847Schristos dat.timestamp = NULL; 1963a7c91847Schristos call_in_directory (args, update_entries, &dat); 1964a7c91847Schristos } 1965a7c91847Schristos 1966a7c91847Schristos 1967a7c91847Schristos 1968a7c91847Schristos static void 1969a7c91847Schristos handle_merged (char *args, size_t len) 1970a7c91847Schristos { 1971a7c91847Schristos struct update_entries_data dat; 1972a7c91847Schristos dat.contents = UPDATE_ENTRIES_UPDATE; 1973a7c91847Schristos /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */ 1974a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; 1975a7c91847Schristos dat.timestamp = "Result of merge"; 1976a7c91847Schristos call_in_directory (args, update_entries, &dat); 1977a7c91847Schristos } 1978a7c91847Schristos 1979a7c91847Schristos 1980a7c91847Schristos 1981a7c91847Schristos static void 1982a7c91847Schristos handle_patched (char *args, size_t len) 1983a7c91847Schristos { 1984a7c91847Schristos struct update_entries_data dat; 1985a7c91847Schristos dat.contents = UPDATE_ENTRIES_PATCH; 1986a7c91847Schristos /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */ 1987a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; 1988a7c91847Schristos dat.timestamp = NULL; 1989a7c91847Schristos call_in_directory (args, update_entries, &dat); 1990a7c91847Schristos } 1991a7c91847Schristos 1992a7c91847Schristos 1993a7c91847Schristos 1994a7c91847Schristos static void 1995a7c91847Schristos handle_rcs_diff (char *args, size_t len) 1996a7c91847Schristos { 1997a7c91847Schristos struct update_entries_data dat; 1998a7c91847Schristos dat.contents = UPDATE_ENTRIES_RCS_DIFF; 1999a7c91847Schristos /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */ 2000a7c91847Schristos dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; 2001a7c91847Schristos dat.timestamp = NULL; 2002a7c91847Schristos call_in_directory (args, update_entries, &dat); 2003a7c91847Schristos } 2004a7c91847Schristos 2005a7c91847Schristos 2006a7c91847Schristos 2007a7c91847Schristos static void 2008a7c91847Schristos remove_entry (void *data, List *ent_list, const char *short_pathname, 2009a7c91847Schristos const char *filename) 2010a7c91847Schristos { 2011a7c91847Schristos Scratch_Entry (ent_list, filename); 2012a7c91847Schristos } 2013a7c91847Schristos 2014a7c91847Schristos 2015a7c91847Schristos 2016a7c91847Schristos static void 2017a7c91847Schristos handle_remove_entry (char *args, size_t len) 2018a7c91847Schristos { 2019a7c91847Schristos call_in_directory (args, remove_entry, NULL); 2020a7c91847Schristos } 2021a7c91847Schristos 2022a7c91847Schristos 2023a7c91847Schristos 2024a7c91847Schristos static void 2025a7c91847Schristos remove_entry_and_file (void *data, List *ent_list, const char *short_pathname, 2026a7c91847Schristos const char *filename) 2027a7c91847Schristos { 2028a7c91847Schristos Scratch_Entry (ent_list, filename); 2029a7c91847Schristos /* Note that we don't ignore existence_error's here. The server 2030a7c91847Schristos should be sending Remove-entry rather than Removed in cases 2031a7c91847Schristos where the file does not exist. And if the user removes the 2032a7c91847Schristos file halfway through a cvs command, we should be printing an 2033a7c91847Schristos error. */ 2034a7c91847Schristos if (unlink_file (filename) < 0) 2035a7c91847Schristos error (0, errno, "unable to remove %s", short_pathname); 2036a7c91847Schristos } 2037a7c91847Schristos 2038a7c91847Schristos 2039a7c91847Schristos 2040a7c91847Schristos static void 2041a7c91847Schristos handle_removed (char *args, size_t len) 2042a7c91847Schristos { 2043a7c91847Schristos call_in_directory (args, remove_entry_and_file, NULL); 2044a7c91847Schristos } 2045a7c91847Schristos 2046a7c91847Schristos 2047a7c91847Schristos 2048a7c91847Schristos /* Is this the top level (directory containing CVSROOT)? */ 2049a7c91847Schristos static int 2050a7c91847Schristos is_cvsroot_level (char *pathname) 2051a7c91847Schristos { 2052a7c91847Schristos if (strcmp (toplevel_repos, current_parsed_root->directory)) 2053a7c91847Schristos return 0; 2054a7c91847Schristos 2055a7c91847Schristos return !strchr (pathname, '/'); 2056a7c91847Schristos } 2057a7c91847Schristos 2058a7c91847Schristos 2059a7c91847Schristos 2060a7c91847Schristos static void 2061a7c91847Schristos set_static (void *data, List *ent_list, const char *short_pathname, 2062a7c91847Schristos const char *filename) 2063a7c91847Schristos { 2064a7c91847Schristos FILE *fp; 2065a7c91847Schristos fp = xfopen (CVSADM_ENTSTAT, "w+"); 2066a7c91847Schristos if (fclose (fp) == EOF) 2067a7c91847Schristos error (1, errno, "cannot close %s", CVSADM_ENTSTAT); 2068a7c91847Schristos } 2069a7c91847Schristos 2070a7c91847Schristos 2071a7c91847Schristos 2072a7c91847Schristos static void 2073a7c91847Schristos handle_set_static_directory (char *args, size_t len) 2074a7c91847Schristos { 2075a7c91847Schristos if (!strcmp (cvs_cmd_name, "export")) 2076a7c91847Schristos { 2077a7c91847Schristos /* Swallow the repository. */ 2078a7c91847Schristos read_line (NULL); 2079a7c91847Schristos return; 2080a7c91847Schristos } 2081a7c91847Schristos call_in_directory (args, set_static, NULL); 2082a7c91847Schristos } 2083a7c91847Schristos 2084a7c91847Schristos 2085a7c91847Schristos 2086a7c91847Schristos static void 2087a7c91847Schristos clear_static (void *data, List *ent_list, const char *short_pathname, 2088a7c91847Schristos const char *filename) 2089a7c91847Schristos { 2090a7c91847Schristos if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) 2091a7c91847Schristos error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); 2092a7c91847Schristos } 2093a7c91847Schristos 2094a7c91847Schristos 2095a7c91847Schristos 2096a7c91847Schristos static void 2097a7c91847Schristos handle_clear_static_directory (char *pathname, size_t len) 2098a7c91847Schristos { 2099a7c91847Schristos if (!strcmp (cvs_cmd_name, "export")) 2100a7c91847Schristos { 2101a7c91847Schristos /* Swallow the repository. */ 2102a7c91847Schristos read_line (NULL); 2103a7c91847Schristos return; 2104a7c91847Schristos } 2105a7c91847Schristos 2106a7c91847Schristos if (is_cvsroot_level (pathname)) 2107a7c91847Schristos { 2108a7c91847Schristos /* 2109a7c91847Schristos * Top level (directory containing CVSROOT). This seems to normally 2110a7c91847Schristos * lack a CVS directory, so don't try to create files in it. 2111a7c91847Schristos */ 2112a7c91847Schristos return; 2113a7c91847Schristos } 2114a7c91847Schristos call_in_directory (pathname, clear_static, NULL); 2115a7c91847Schristos } 2116a7c91847Schristos 2117a7c91847Schristos 2118a7c91847Schristos 2119a7c91847Schristos static void 2120a7c91847Schristos set_sticky (void *data, List *ent_list, const char *short_pathname, 2121a7c91847Schristos const char *filename) 2122a7c91847Schristos { 2123a7c91847Schristos char *tagspec; 2124a7c91847Schristos FILE *f; 2125a7c91847Schristos 2126a7c91847Schristos read_line (&tagspec); 2127a7c91847Schristos 2128a7c91847Schristos /* FIXME-update-dir: error messages should include the directory. */ 2129a7c91847Schristos f = CVS_FOPEN (CVSADM_TAG, "w+"); 2130a7c91847Schristos if (!f) 2131a7c91847Schristos { 2132a7c91847Schristos /* Making this non-fatal is a bit of a kludge (see dirs2 2133a7c91847Schristos in testsuite). A better solution would be to avoid having 2134a7c91847Schristos the server tell us about a directory we shouldn't be doing 2135a7c91847Schristos anything with anyway (e.g. by handling directory 2136a7c91847Schristos addition/removal better). */ 2137a7c91847Schristos error (0, errno, "cannot open %s", CVSADM_TAG); 2138a7c91847Schristos free (tagspec); 2139a7c91847Schristos return; 2140a7c91847Schristos } 2141a7c91847Schristos if (fprintf (f, "%s\n", tagspec) < 0) 2142a7c91847Schristos error (1, errno, "writing %s", CVSADM_TAG); 2143a7c91847Schristos if (fclose (f) == EOF) 2144a7c91847Schristos error (1, errno, "closing %s", CVSADM_TAG); 2145a7c91847Schristos free (tagspec); 2146a7c91847Schristos } 2147a7c91847Schristos 2148a7c91847Schristos 2149a7c91847Schristos 2150a7c91847Schristos static void 2151a7c91847Schristos handle_set_sticky (char *pathname, size_t len) 2152a7c91847Schristos { 2153a7c91847Schristos if (!strcmp (cvs_cmd_name, "export")) 2154a7c91847Schristos { 2155a7c91847Schristos /* Swallow the repository. */ 2156a7c91847Schristos read_line (NULL); 2157a7c91847Schristos /* Swallow the tag line. */ 2158a7c91847Schristos read_line (NULL); 2159a7c91847Schristos return; 2160a7c91847Schristos } 2161a7c91847Schristos if (is_cvsroot_level (pathname)) 2162a7c91847Schristos { 2163a7c91847Schristos /* 2164a7c91847Schristos * Top level (directory containing CVSROOT). This seems to normally 2165a7c91847Schristos * lack a CVS directory, so don't try to create files in it. 2166a7c91847Schristos */ 2167a7c91847Schristos 2168a7c91847Schristos /* Swallow the repository. */ 2169a7c91847Schristos read_line (NULL); 2170a7c91847Schristos /* Swallow the tag line. */ 2171a7c91847Schristos read_line (NULL); 2172a7c91847Schristos return; 2173a7c91847Schristos } 2174a7c91847Schristos 2175a7c91847Schristos call_in_directory (pathname, set_sticky, NULL); 2176a7c91847Schristos } 2177a7c91847Schristos 2178a7c91847Schristos 2179a7c91847Schristos 2180a7c91847Schristos static void 2181a7c91847Schristos clear_sticky (void *data, List *ent_list, const char *short_pathname, 2182a7c91847Schristos const char *filename) 2183a7c91847Schristos { 2184a7c91847Schristos if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno)) 2185a7c91847Schristos error (1, errno, "cannot remove %s", CVSADM_TAG); 2186a7c91847Schristos } 2187a7c91847Schristos 2188a7c91847Schristos 2189a7c91847Schristos 2190a7c91847Schristos static void 2191a7c91847Schristos handle_clear_sticky (char *pathname, size_t len) 2192a7c91847Schristos { 2193a7c91847Schristos if (!strcmp (cvs_cmd_name, "export")) 2194a7c91847Schristos { 2195a7c91847Schristos /* Swallow the repository. */ 2196a7c91847Schristos read_line (NULL); 2197a7c91847Schristos return; 2198a7c91847Schristos } 2199a7c91847Schristos 2200a7c91847Schristos if (is_cvsroot_level (pathname)) 2201a7c91847Schristos { 2202a7c91847Schristos /* 2203a7c91847Schristos * Top level (directory containing CVSROOT). This seems to normally 2204a7c91847Schristos * lack a CVS directory, so don't try to create files in it. 2205a7c91847Schristos */ 2206a7c91847Schristos return; 2207a7c91847Schristos } 2208a7c91847Schristos 2209a7c91847Schristos call_in_directory (pathname, clear_sticky, NULL); 2210a7c91847Schristos } 2211a7c91847Schristos 2212a7c91847Schristos 2213a7c91847Schristos 2214a7c91847Schristos /* Handle the client-side support for a successful edit. 2215a7c91847Schristos */ 2216a7c91847Schristos static void 2217a7c91847Schristos handle_edit_file (char *pathname, size_t len) 2218a7c91847Schristos { 2219a7c91847Schristos call_in_directory (pathname, edit_file, NULL); 2220a7c91847Schristos } 2221a7c91847Schristos 2222a7c91847Schristos 2223a7c91847Schristos 2224a7c91847Schristos static void 2225a7c91847Schristos template (void *data, List *ent_list, const char *short_pathname, 2226a7c91847Schristos const char *filename) 2227a7c91847Schristos { 2228a7c91847Schristos char *buf = Xasprintf ("%s/%s", short_pathname, CVSADM_TEMPLATE); 2229a7c91847Schristos read_counted_file (CVSADM_TEMPLATE, buf); 2230a7c91847Schristos free (buf); 2231a7c91847Schristos } 2232a7c91847Schristos 2233a7c91847Schristos 2234a7c91847Schristos 2235a7c91847Schristos static void 2236a7c91847Schristos handle_template (char *pathname, size_t len) 2237a7c91847Schristos { 2238a7c91847Schristos call_in_directory (pathname, template, NULL); 2239a7c91847Schristos } 2240a7c91847Schristos 2241a7c91847Schristos 2242a7c91847Schristos 2243a7c91847Schristos static void 2244a7c91847Schristos clear_template (void *data, List *ent_list, const char *short_pathname, 2245a7c91847Schristos const char *filename) 2246a7c91847Schristos { 2247a7c91847Schristos if (unlink_file (CVSADM_TEMPLATE) < 0 && ! existence_error (errno)) 2248a7c91847Schristos error (1, errno, "cannot remove %s", CVSADM_TEMPLATE); 2249a7c91847Schristos } 2250a7c91847Schristos 2251a7c91847Schristos 2252a7c91847Schristos 2253a7c91847Schristos static void 2254a7c91847Schristos handle_clear_template (char *pathname, size_t len) 2255a7c91847Schristos { 2256a7c91847Schristos call_in_directory (pathname, clear_template, NULL); 2257a7c91847Schristos } 2258a7c91847Schristos 2259a7c91847Schristos 2260a7c91847Schristos 2261a7c91847Schristos struct save_dir { 2262a7c91847Schristos char *dir; 2263a7c91847Schristos struct save_dir *next; 2264a7c91847Schristos }; 2265a7c91847Schristos 2266a7c91847Schristos struct save_dir *prune_candidates; 2267a7c91847Schristos 2268a7c91847Schristos static void 2269a7c91847Schristos add_prune_candidate (const char *dir) 2270a7c91847Schristos { 2271a7c91847Schristos struct save_dir *p; 2272a7c91847Schristos 2273a7c91847Schristos if ((dir[0] == '.' && dir[1] == '\0') 2274a7c91847Schristos || (prune_candidates && !strcmp (dir, prune_candidates->dir))) 2275a7c91847Schristos return; 2276a7c91847Schristos p = xmalloc (sizeof (struct save_dir)); 2277a7c91847Schristos p->dir = xstrdup (dir); 2278a7c91847Schristos p->next = prune_candidates; 2279a7c91847Schristos prune_candidates = p; 2280a7c91847Schristos } 2281a7c91847Schristos 2282a7c91847Schristos 2283a7c91847Schristos 2284a7c91847Schristos static void 2285a7c91847Schristos process_prune_candidates (void) 2286a7c91847Schristos { 2287a7c91847Schristos struct save_dir *p; 2288a7c91847Schristos struct save_dir *q; 2289a7c91847Schristos 2290a7c91847Schristos if (toplevel_wd) 2291a7c91847Schristos { 2292a7c91847Schristos if (CVS_CHDIR (toplevel_wd) < 0) 2293a7c91847Schristos error (1, errno, "could not chdir to %s", toplevel_wd); 2294a7c91847Schristos } 2295a7c91847Schristos for (p = prune_candidates; p; ) 2296a7c91847Schristos { 2297a7c91847Schristos if (isemptydir (p->dir, 1)) 2298a7c91847Schristos { 2299a7c91847Schristos char *b; 2300a7c91847Schristos 2301a7c91847Schristos if (unlink_file_dir (p->dir) < 0) 2302a7c91847Schristos error (0, errno, "cannot remove %s", p->dir); 2303a7c91847Schristos b = strrchr (p->dir, '/'); 2304a7c91847Schristos if (!b) 2305a7c91847Schristos Subdir_Deregister (NULL, NULL, p->dir); 2306a7c91847Schristos else 2307a7c91847Schristos { 2308a7c91847Schristos *b = '\0'; 2309a7c91847Schristos Subdir_Deregister (NULL, p->dir, b + 1); 2310a7c91847Schristos } 2311a7c91847Schristos } 2312a7c91847Schristos free (p->dir); 2313a7c91847Schristos q = p->next; 2314a7c91847Schristos free (p); 2315a7c91847Schristos p = q; 2316a7c91847Schristos } 2317a7c91847Schristos prune_candidates = NULL; 2318a7c91847Schristos } 2319a7c91847Schristos 2320a7c91847Schristos 2321a7c91847Schristos 2322a7c91847Schristos /* Send a Repository line. */ 2323a7c91847Schristos static char *last_repos; 2324a7c91847Schristos static char *last_update_dir; 2325a7c91847Schristos static void 2326a7c91847Schristos send_repository (const char *dir, const char *repos, const char *update_dir) 2327a7c91847Schristos { 2328a7c91847Schristos char *adm_name; 2329a7c91847Schristos 2330a7c91847Schristos /* FIXME: this is probably not the best place to check; I wish I 2331a7c91847Schristos * knew where in here's callers to really trap this bug. To 2332a7c91847Schristos * reproduce the bug, just do this: 2333a7c91847Schristos * 2334a7c91847Schristos * mkdir junk 2335a7c91847Schristos * cd junk 2336a7c91847Schristos * cvs -d some_repos update foo 2337a7c91847Schristos * 2338a7c91847Schristos * Poof, CVS seg faults and dies! It's because it's trying to 2339a7c91847Schristos * send a NULL string to the server but dies in send_to_server. 2340a7c91847Schristos * That string was supposed to be the repository, but it doesn't 2341a7c91847Schristos * get set because there's no CVSADM dir, and somehow it's not 2342a7c91847Schristos * getting set from the -d argument either... ? 2343a7c91847Schristos */ 2344a7c91847Schristos if (!repos) 2345a7c91847Schristos { 2346a7c91847Schristos /* Lame error. I want a real fix but can't stay up to track 2347a7c91847Schristos this down right now. */ 2348a7c91847Schristos error (1, 0, "no repository"); 2349a7c91847Schristos } 2350a7c91847Schristos 2351a7c91847Schristos if (!update_dir || update_dir[0] == '\0') 2352a7c91847Schristos update_dir = "."; 2353a7c91847Schristos 2354a7c91847Schristos if (last_repos && !strcmp (repos, last_repos) 2355a7c91847Schristos && last_update_dir && !strcmp (update_dir, last_update_dir)) 2356a7c91847Schristos /* We've already sent it. */ 2357a7c91847Schristos return; 2358a7c91847Schristos 2359a7c91847Schristos if (client_prune_dirs) 2360a7c91847Schristos add_prune_candidate (update_dir); 2361a7c91847Schristos 2362a7c91847Schristos /* Add a directory name to the list of those sent to the 2363a7c91847Schristos server. */ 2364a7c91847Schristos if (update_dir && *update_dir != '\0' && strcmp (update_dir, ".") 2365a7c91847Schristos && !findnode (dirs_sent_to_server, update_dir)) 2366a7c91847Schristos { 2367a7c91847Schristos Node *n; 2368a7c91847Schristos n = getnode (); 2369a7c91847Schristos n->type = NT_UNKNOWN; 2370a7c91847Schristos n->key = xstrdup (update_dir); 2371a7c91847Schristos n->data = NULL; 2372a7c91847Schristos 2373a7c91847Schristos if (addnode (dirs_sent_to_server, n)) 2374a7c91847Schristos error (1, 0, "cannot add directory %s to list", n->key); 2375a7c91847Schristos } 2376a7c91847Schristos 2377a7c91847Schristos /* 80 is large enough for any of CVSADM_*. */ 2378a7c91847Schristos adm_name = xmalloc (strlen (dir) + 80); 2379a7c91847Schristos 2380a7c91847Schristos send_to_server ("Directory ", 0); 2381a7c91847Schristos { 2382a7c91847Schristos /* Send the directory name. I know that this 2383a7c91847Schristos sort of duplicates code elsewhere, but each 2384a7c91847Schristos case seems slightly different... */ 2385a7c91847Schristos char buf[1]; 2386a7c91847Schristos const char *p = update_dir; 2387a7c91847Schristos while (*p != '\0') 2388a7c91847Schristos { 2389a7c91847Schristos assert (*p != '\012'); 2390a7c91847Schristos if (ISSLASH (*p)) 2391a7c91847Schristos { 2392a7c91847Schristos buf[0] = '/'; 2393a7c91847Schristos send_to_server (buf, 1); 2394a7c91847Schristos } 2395a7c91847Schristos else 2396a7c91847Schristos { 2397a7c91847Schristos buf[0] = *p; 2398a7c91847Schristos send_to_server (buf, 1); 2399a7c91847Schristos } 2400a7c91847Schristos ++p; 2401a7c91847Schristos } 2402a7c91847Schristos } 2403a7c91847Schristos send_to_server ("\012", 1); 2404a7c91847Schristos if (supported_request ("Relative-directory")) 2405a7c91847Schristos { 2406a7c91847Schristos const char *short_repos = Short_Repository (repos); 2407a7c91847Schristos send_to_server (short_repos, 0); 2408a7c91847Schristos } 2409a7c91847Schristos else 2410a7c91847Schristos send_to_server (repos, 0); 2411a7c91847Schristos send_to_server ("\012", 1); 2412a7c91847Schristos 2413a7c91847Schristos if (supported_request ("Static-directory")) 2414a7c91847Schristos { 2415a7c91847Schristos adm_name[0] = '\0'; 2416a7c91847Schristos if (dir[0] != '\0') 2417a7c91847Schristos { 2418a7c91847Schristos strcat (adm_name, dir); 2419a7c91847Schristos strcat (adm_name, "/"); 2420a7c91847Schristos } 2421a7c91847Schristos strcat (adm_name, CVSADM_ENTSTAT); 2422a7c91847Schristos if (isreadable (adm_name)) 2423a7c91847Schristos { 2424a7c91847Schristos send_to_server ("Static-directory\012", 0); 2425a7c91847Schristos } 2426a7c91847Schristos } 2427a7c91847Schristos if (supported_request ("Sticky")) 2428a7c91847Schristos { 2429a7c91847Schristos FILE *f; 2430a7c91847Schristos if (dir[0] == '\0') 2431a7c91847Schristos strcpy (adm_name, CVSADM_TAG); 2432a7c91847Schristos else 2433a7c91847Schristos sprintf (adm_name, "%s/%s", dir, CVSADM_TAG); 2434a7c91847Schristos 2435a7c91847Schristos f = CVS_FOPEN (adm_name, "r"); 2436a7c91847Schristos if (!f) 2437a7c91847Schristos { 2438a7c91847Schristos if (! existence_error (errno)) 2439a7c91847Schristos error (1, errno, "reading %s", adm_name); 2440a7c91847Schristos } 2441a7c91847Schristos else 2442a7c91847Schristos { 2443a7c91847Schristos char line[80]; 2444a7c91847Schristos char *nl = NULL; 2445a7c91847Schristos send_to_server ("Sticky ", 0); 2446a7c91847Schristos while (fgets (line, sizeof (line), f)) 2447a7c91847Schristos { 2448a7c91847Schristos send_to_server (line, 0); 2449a7c91847Schristos nl = strchr (line, '\n'); 2450a7c91847Schristos if (nl) 2451a7c91847Schristos break; 2452a7c91847Schristos } 2453a7c91847Schristos if (!nl) 2454a7c91847Schristos send_to_server ("\012", 1); 2455a7c91847Schristos if (fclose (f) == EOF) 2456a7c91847Schristos error (0, errno, "closing %s", adm_name); 2457a7c91847Schristos } 2458a7c91847Schristos } 2459a7c91847Schristos free (adm_name); 2460a7c91847Schristos if (last_repos) free (last_repos); 2461a7c91847Schristos if (last_update_dir) free (last_update_dir); 2462a7c91847Schristos last_repos = xstrdup (repos); 2463a7c91847Schristos last_update_dir = xstrdup (update_dir); 2464a7c91847Schristos } 2465a7c91847Schristos 2466a7c91847Schristos 2467a7c91847Schristos 2468a7c91847Schristos /* Send a Repository line and set toplevel_repos. */ 2469a7c91847Schristos void 2470a7c91847Schristos send_a_repository (const char *dir, const char *repository, 2471a7c91847Schristos const char *update_dir_in) 2472a7c91847Schristos { 2473a7c91847Schristos char *update_dir = xstrdup (update_dir_in); 2474a7c91847Schristos 2475a7c91847Schristos if (!toplevel_repos && repository) 2476a7c91847Schristos { 2477a7c91847Schristos if (update_dir[0] == '\0' 2478a7c91847Schristos || (update_dir[0] == '.' && update_dir[1] == '\0')) 2479a7c91847Schristos toplevel_repos = xstrdup (repository); 2480a7c91847Schristos else 2481a7c91847Schristos { 2482a7c91847Schristos /* 2483a7c91847Schristos * Get the repository from a CVS/Repository file if update_dir 2484a7c91847Schristos * is absolute. This is not correct in general, because 2485a7c91847Schristos * the CVS/Repository file might not be the top-level one. 2486a7c91847Schristos * This is for cases like "cvs update /foo/bar" (I'm not 2487a7c91847Schristos * sure it matters what toplevel_repos we get, but it does 2488a7c91847Schristos * matter that we don't hit the "internal error" code below). 2489a7c91847Schristos */ 2490a7c91847Schristos if (update_dir[0] == '/') 2491a7c91847Schristos toplevel_repos = Name_Repository (update_dir, update_dir); 2492a7c91847Schristos else 2493a7c91847Schristos { 2494a7c91847Schristos /* 2495a7c91847Schristos * Guess the repository of that directory by looking at a 2496a7c91847Schristos * subdirectory and removing as many pathname components 2497a7c91847Schristos * as are in update_dir. I think that will always (or at 2498a7c91847Schristos * least almost always) be 1. 2499a7c91847Schristos * 2500a7c91847Schristos * So this deals with directories which have been 2501a7c91847Schristos * renamed, though it doesn't necessarily deal with 2502a7c91847Schristos * directories which have been put inside other 2503a7c91847Schristos * directories (and cvs invoked on the containing 2504a7c91847Schristos * directory). I'm not sure the latter case needs to 2505a7c91847Schristos * work. 2506a7c91847Schristos * 2507a7c91847Schristos * 21 Aug 1998: Well, Mr. Above-Comment-Writer, it 2508a7c91847Schristos * does need to work after all. When we are using the 2509a7c91847Schristos * client in a multi-cvsroot environment, it will be 2510a7c91847Schristos * fairly common that we have the above case (e.g., 2511a7c91847Schristos * cwd checked out from one repository but 2512a7c91847Schristos * subdirectory checked out from another). We can't 2513a7c91847Schristos * assume that by walking up a directory in our wd we 2514a7c91847Schristos * necessarily walk up a directory in the repository. 2515a7c91847Schristos */ 2516a7c91847Schristos /* 2517a7c91847Schristos * This gets toplevel_repos wrong for "cvs update ../foo" 2518a7c91847Schristos * but I'm not sure toplevel_repos matters in that case. 2519a7c91847Schristos */ 2520a7c91847Schristos 2521a7c91847Schristos int repository_len, update_dir_len; 2522a7c91847Schristos 2523a7c91847Schristos strip_trailing_slashes (update_dir); 2524a7c91847Schristos 2525a7c91847Schristos repository_len = strlen (repository); 2526a7c91847Schristos update_dir_len = strlen (update_dir); 2527a7c91847Schristos 2528a7c91847Schristos /* Try to remove the path components in UPDATE_DIR 2529a7c91847Schristos from REPOSITORY. If the path elements don't exist 2530a7c91847Schristos in REPOSITORY, or the removal of those path 2531a7c91847Schristos elements mean that we "step above" 2532a7c91847Schristos current_parsed_root->directory, set toplevel_repos to 2533a7c91847Schristos current_parsed_root->directory. */ 2534a7c91847Schristos if (repository_len > update_dir_len 2535a7c91847Schristos && !strcmp (repository + repository_len - update_dir_len, 2536a7c91847Schristos update_dir) 2537a7c91847Schristos /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */ 2538a7c91847Schristos && ((size_t)(repository_len - update_dir_len) 2539a7c91847Schristos > strlen (current_parsed_root->directory))) 2540a7c91847Schristos { 2541a7c91847Schristos /* The repository name contains UPDATE_DIR. Set 2542a7c91847Schristos toplevel_repos to the repository name without 2543a7c91847Schristos UPDATE_DIR. */ 2544a7c91847Schristos 2545a7c91847Schristos toplevel_repos = xmalloc (repository_len - update_dir_len); 2546a7c91847Schristos /* Note that we don't copy the trailing '/'. */ 2547a7c91847Schristos strncpy (toplevel_repos, repository, 2548a7c91847Schristos repository_len - update_dir_len - 1); 2549a7c91847Schristos toplevel_repos[repository_len - update_dir_len - 1] = '\0'; 2550a7c91847Schristos } 2551a7c91847Schristos else 2552a7c91847Schristos { 2553a7c91847Schristos toplevel_repos = xstrdup (current_parsed_root->directory); 2554a7c91847Schristos } 2555a7c91847Schristos } 2556a7c91847Schristos } 2557a7c91847Schristos } 2558a7c91847Schristos 2559a7c91847Schristos send_repository (dir, repository, update_dir); 2560a7c91847Schristos free (update_dir); 2561a7c91847Schristos } 2562a7c91847Schristos 2563a7c91847Schristos 2564a7c91847Schristos 2565a7c91847Schristos static void 2566a7c91847Schristos notified_a_file (void *data, List *ent_list, const char *short_pathname, 2567a7c91847Schristos const char *filename) 2568a7c91847Schristos { 2569a7c91847Schristos FILE *fp; 2570a7c91847Schristos FILE *newf; 2571a7c91847Schristos size_t line_len = 8192; 2572a7c91847Schristos char *line = xmalloc (line_len); 2573a7c91847Schristos char *cp; 2574a7c91847Schristos int nread; 2575a7c91847Schristos int nwritten; 2576a7c91847Schristos char *p; 2577a7c91847Schristos 2578a7c91847Schristos fp = xfopen (CVSADM_NOTIFY, "r"); 2579a7c91847Schristos if (getline (&line, &line_len, fp) < 0) 2580a7c91847Schristos { 2581a7c91847Schristos if (feof (fp)) 2582a7c91847Schristos error (0, 0, "cannot read %s: end of file", CVSADM_NOTIFY); 2583a7c91847Schristos else 2584a7c91847Schristos error (0, errno, "cannot read %s", CVSADM_NOTIFY); 2585a7c91847Schristos goto error_exit; 2586a7c91847Schristos } 2587a7c91847Schristos cp = strchr (line, '\t'); 2588a7c91847Schristos if (!cp) 2589a7c91847Schristos { 2590a7c91847Schristos error (0, 0, "malformed %s file", CVSADM_NOTIFY); 2591a7c91847Schristos goto error_exit; 2592a7c91847Schristos } 2593a7c91847Schristos *cp = '\0'; 2594a7c91847Schristos if (strcmp (filename, line + 1)) 2595a7c91847Schristos error (0, 0, "protocol error: notified %s, expected %s", filename, 2596a7c91847Schristos line + 1); 2597a7c91847Schristos 2598a7c91847Schristos if (getline (&line, &line_len, fp) < 0) 2599a7c91847Schristos { 2600a7c91847Schristos if (feof (fp)) 2601a7c91847Schristos { 2602a7c91847Schristos free (line); 2603a7c91847Schristos if (fclose (fp) < 0) 2604a7c91847Schristos error (0, errno, "cannot close %s", CVSADM_NOTIFY); 2605a7c91847Schristos if ( CVS_UNLINK (CVSADM_NOTIFY) < 0) 2606a7c91847Schristos error (0, errno, "cannot remove %s", CVSADM_NOTIFY); 2607a7c91847Schristos return; 2608a7c91847Schristos } 2609a7c91847Schristos else 2610a7c91847Schristos { 2611a7c91847Schristos error (0, errno, "cannot read %s", CVSADM_NOTIFY); 2612a7c91847Schristos goto error_exit; 2613a7c91847Schristos } 2614a7c91847Schristos } 2615a7c91847Schristos newf = xfopen (CVSADM_NOTIFYTMP, "w"); 2616a7c91847Schristos if (fputs (line, newf) < 0) 2617a7c91847Schristos { 2618a7c91847Schristos error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP); 2619a7c91847Schristos goto error2; 2620a7c91847Schristos } 2621a7c91847Schristos while ((nread = fread (line, 1, line_len, fp)) > 0) 2622a7c91847Schristos { 2623a7c91847Schristos p = line; 2624a7c91847Schristos while ((nwritten = fwrite (p, sizeof *p, nread, newf)) > 0) 2625a7c91847Schristos { 2626a7c91847Schristos nread -= nwritten; 2627a7c91847Schristos p += nwritten; 2628a7c91847Schristos } 2629a7c91847Schristos if (ferror (newf)) 2630a7c91847Schristos { 2631a7c91847Schristos error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP); 2632a7c91847Schristos goto error2; 2633a7c91847Schristos } 2634a7c91847Schristos } 2635a7c91847Schristos if (ferror (fp)) 2636a7c91847Schristos { 2637a7c91847Schristos error (0, errno, "cannot read %s", CVSADM_NOTIFY); 2638a7c91847Schristos goto error2; 2639a7c91847Schristos } 2640a7c91847Schristos if (fclose (newf) < 0) 2641a7c91847Schristos { 2642a7c91847Schristos error (0, errno, "cannot close %s", CVSADM_NOTIFYTMP); 2643a7c91847Schristos goto error_exit; 2644a7c91847Schristos } 2645a7c91847Schristos free (line); 2646a7c91847Schristos if (fclose (fp) < 0) 2647a7c91847Schristos { 2648a7c91847Schristos error (0, errno, "cannot close %s", CVSADM_NOTIFY); 2649a7c91847Schristos return; 2650a7c91847Schristos } 2651a7c91847Schristos 2652a7c91847Schristos { 2653a7c91847Schristos /* In this case, we want rename_file() to ignore noexec. */ 2654a7c91847Schristos int saved_noexec = noexec; 2655a7c91847Schristos noexec = 0; 2656a7c91847Schristos rename_file (CVSADM_NOTIFYTMP, CVSADM_NOTIFY); 2657a7c91847Schristos noexec = saved_noexec; 2658a7c91847Schristos } 2659a7c91847Schristos 2660a7c91847Schristos return; 2661a7c91847Schristos error2: 2662a7c91847Schristos (void)fclose (newf); 2663a7c91847Schristos error_exit: 2664a7c91847Schristos free (line); 2665a7c91847Schristos (void)fclose (fp); 2666a7c91847Schristos } 2667a7c91847Schristos 2668a7c91847Schristos 2669a7c91847Schristos 2670a7c91847Schristos static void 2671a7c91847Schristos handle_notified (char *args, size_t len) 2672a7c91847Schristos { 2673a7c91847Schristos call_in_directory (args, notified_a_file, NULL); 2674a7c91847Schristos } 2675a7c91847Schristos 2676a7c91847Schristos 2677a7c91847Schristos 2678a7c91847Schristos /* The "expanded" modules. */ 2679a7c91847Schristos static int modules_count; 2680a7c91847Schristos static int modules_allocated; 2681a7c91847Schristos static char **modules_vector; 2682a7c91847Schristos 2683a7c91847Schristos static void 2684a7c91847Schristos handle_module_expansion (char *args, size_t len) 2685a7c91847Schristos { 2686a7c91847Schristos if (!modules_vector) 2687a7c91847Schristos { 2688a7c91847Schristos modules_allocated = 1; /* Small for testing */ 2689a7c91847Schristos modules_vector = xnmalloc (modules_allocated, 2690a7c91847Schristos sizeof (modules_vector[0])); 2691a7c91847Schristos } 2692a7c91847Schristos else if (modules_count >= modules_allocated) 2693a7c91847Schristos { 2694a7c91847Schristos modules_allocated *= 2; 2695a7c91847Schristos modules_vector = xnrealloc (modules_vector, 2696a7c91847Schristos modules_allocated, 2697a7c91847Schristos sizeof (modules_vector[0])); 2698a7c91847Schristos } 2699a7c91847Schristos modules_vector[modules_count] = xstrdup (args); 2700a7c91847Schristos ++modules_count; 2701a7c91847Schristos } 2702a7c91847Schristos 2703a7c91847Schristos 2704a7c91847Schristos 2705a7c91847Schristos /* Original, not "expanded" modules. */ 2706a7c91847Schristos static int module_argc; 2707a7c91847Schristos static char **module_argv; 2708a7c91847Schristos 2709a7c91847Schristos void 2710a7c91847Schristos client_expand_modules (int argc, char **argv, int local) 2711a7c91847Schristos { 2712a7c91847Schristos int errs; 2713a7c91847Schristos int i; 2714a7c91847Schristos 2715a7c91847Schristos module_argc = argc; 2716a7c91847Schristos module_argv = xnmalloc (argc + 1, sizeof (module_argv[0])); 2717a7c91847Schristos for (i = 0; i < argc; ++i) 2718a7c91847Schristos module_argv[i] = xstrdup (argv[i]); 2719a7c91847Schristos module_argv[argc] = NULL; 2720a7c91847Schristos 2721a7c91847Schristos for (i = 0; i < argc; ++i) 2722a7c91847Schristos send_arg (argv[i]); 2723a7c91847Schristos send_a_repository ("", current_parsed_root->directory, ""); 2724a7c91847Schristos 2725a7c91847Schristos send_to_server ("expand-modules\012", 0); 2726a7c91847Schristos 2727a7c91847Schristos errs = get_server_responses (); 2728a7c91847Schristos 2729a7c91847Schristos if (last_repos) free (last_repos); 2730a7c91847Schristos last_repos = NULL; 2731a7c91847Schristos 2732a7c91847Schristos if (last_update_dir) free (last_update_dir); 2733a7c91847Schristos last_update_dir = NULL; 2734a7c91847Schristos 2735a7c91847Schristos if (errs) 2736a7c91847Schristos error (errs, 0, "cannot expand modules"); 2737a7c91847Schristos } 2738a7c91847Schristos 2739a7c91847Schristos 2740a7c91847Schristos 2741a7c91847Schristos void 2742a7c91847Schristos client_send_expansions (int local, char *where, int build_dirs) 2743a7c91847Schristos { 2744a7c91847Schristos int i; 2745a7c91847Schristos char *argv[1]; 2746a7c91847Schristos 2747a7c91847Schristos /* Send the original module names. The "expanded" module name might 2748a7c91847Schristos not be suitable as an argument to a co request (e.g. it might be 2749a7c91847Schristos the result of a -d argument in the modules file). It might be 2750a7c91847Schristos cleaner if we genuinely expanded module names, all the way to a 2751a7c91847Schristos local directory and repository, but that isn't the way it works 2752a7c91847Schristos now. */ 2753a7c91847Schristos send_file_names (module_argc, module_argv, 0); 2754a7c91847Schristos 2755a7c91847Schristos for (i = 0; i < modules_count; ++i) 2756a7c91847Schristos { 2757a7c91847Schristos argv[0] = where ? where : modules_vector[i]; 2758a7c91847Schristos if (isfile (argv[0])) 2759a7c91847Schristos send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0); 2760a7c91847Schristos } 2761a7c91847Schristos send_a_repository ("", current_parsed_root->directory, ""); 2762a7c91847Schristos } 2763a7c91847Schristos 2764a7c91847Schristos 2765a7c91847Schristos 2766a7c91847Schristos void 2767a7c91847Schristos client_nonexpanded_setup (void) 2768a7c91847Schristos { 2769a7c91847Schristos send_a_repository ("", current_parsed_root->directory, ""); 2770a7c91847Schristos } 2771a7c91847Schristos 2772a7c91847Schristos 2773a7c91847Schristos 2774a7c91847Schristos /* Receive a cvswrappers line from the server; it must be a line 2775a7c91847Schristos containing an RCS option (e.g., "*.exe -k 'b'"). 2776a7c91847Schristos 2777a7c91847Schristos Note that this doesn't try to handle -t/-f options (which are a 2778a7c91847Schristos whole separate issue which noone has thought much about, as far 2779a7c91847Schristos as I know). 2780a7c91847Schristos 2781a7c91847Schristos We need to know the keyword expansion mode so we know whether to 2782a7c91847Schristos read the file in text or binary mode. */ 2783a7c91847Schristos static void 2784a7c91847Schristos handle_wrapper_rcs_option (char *args, size_t len) 2785a7c91847Schristos { 2786a7c91847Schristos char *p; 2787a7c91847Schristos 2788a7c91847Schristos /* Enforce the notes in cvsclient.texi about how the response is not 2789a7c91847Schristos as free-form as it looks. */ 2790a7c91847Schristos p = strchr (args, ' '); 2791a7c91847Schristos if (!p) 2792a7c91847Schristos goto handle_error; 2793a7c91847Schristos if (*++p != '-' 2794a7c91847Schristos || *++p != 'k' 2795a7c91847Schristos || *++p != ' ' 2796a7c91847Schristos || *++p != '\'') 2797a7c91847Schristos goto handle_error; 2798a7c91847Schristos if (!strchr (p, '\'')) 2799a7c91847Schristos goto handle_error; 2800a7c91847Schristos 2801a7c91847Schristos /* Add server-side cvswrappers line to our wrapper list. */ 2802a7c91847Schristos wrap_add (args, 0); 2803a7c91847Schristos return; 2804a7c91847Schristos handle_error: 2805a7c91847Schristos error (0, errno, "protocol error: ignoring invalid wrappers %s", args); 2806a7c91847Schristos } 2807a7c91847Schristos 2808a7c91847Schristos 2809a7c91847Schristos 2810a7c91847Schristos 2811a7c91847Schristos static void 2812a7c91847Schristos handle_m (char *args, size_t len) 2813a7c91847Schristos { 2814a7c91847Schristos /* In the case where stdout and stderr point to the same place, 2815a7c91847Schristos fflushing stderr will make output happen in the correct order. 2816a7c91847Schristos Often stderr will be line-buffered and this won't be needed, 2817a7c91847Schristos but not always (is that true? I think the comment is probably 2818a7c91847Schristos based on being confused between default buffering between 2819a7c91847Schristos stdout and stderr. But I'm not sure). */ 2820a7c91847Schristos fflush (stderr); 2821a7c91847Schristos fwrite (args, sizeof *args, len, stdout); 2822a7c91847Schristos putc ('\n', stdout); 2823a7c91847Schristos } 2824a7c91847Schristos 2825a7c91847Schristos 2826a7c91847Schristos 2827a7c91847Schristos static void 2828a7c91847Schristos handle_mbinary (char *args, size_t len) 2829a7c91847Schristos { 2830a7c91847Schristos char *size_string; 2831a7c91847Schristos size_t size; 2832a7c91847Schristos size_t totalread; 2833a7c91847Schristos size_t nread; 2834a7c91847Schristos size_t toread; 2835a7c91847Schristos char buf[8192]; 2836a7c91847Schristos 2837a7c91847Schristos /* See comment at handle_m about (non)flush of stderr. */ 2838a7c91847Schristos 2839a7c91847Schristos /* Get the size. */ 2840a7c91847Schristos read_line (&size_string); 2841a7c91847Schristos size = atoi (size_string); 2842a7c91847Schristos free (size_string); 2843a7c91847Schristos 2844a7c91847Schristos /* OK, now get all the data. The algorithm here is that we read 2845a7c91847Schristos as much as the network wants to give us in 2846a7c91847Schristos try_read_from_server, and then we output it all, and then 2847a7c91847Schristos repeat, until we get all the data. */ 2848a7c91847Schristos totalread = 0; 2849a7c91847Schristos while (totalread < size) 2850a7c91847Schristos { 2851a7c91847Schristos toread = size - totalread; 2852a7c91847Schristos if (toread > sizeof buf) 2853a7c91847Schristos toread = sizeof buf; 2854a7c91847Schristos 2855a7c91847Schristos nread = try_read_from_server (buf, toread); 2856a7c91847Schristos cvs_output_binary (buf, nread); 2857a7c91847Schristos totalread += nread; 2858a7c91847Schristos } 2859a7c91847Schristos } 2860a7c91847Schristos 2861a7c91847Schristos 2862a7c91847Schristos 2863a7c91847Schristos static void 2864a7c91847Schristos handle_e (char *args, size_t len) 2865a7c91847Schristos { 2866a7c91847Schristos /* In the case where stdout and stderr point to the same place, 2867a7c91847Schristos fflushing stdout will make output happen in the correct order. */ 2868a7c91847Schristos fflush (stdout); 2869a7c91847Schristos fwrite (args, sizeof *args, len, stderr); 2870a7c91847Schristos putc ('\n', stderr); 2871a7c91847Schristos } 2872a7c91847Schristos 2873a7c91847Schristos 2874a7c91847Schristos 2875a7c91847Schristos /*ARGSUSED*/ 2876a7c91847Schristos static void 2877a7c91847Schristos handle_f (char *args, size_t len) 2878a7c91847Schristos { 2879a7c91847Schristos fflush (stderr); 2880a7c91847Schristos } 2881a7c91847Schristos 2882a7c91847Schristos 2883a7c91847Schristos 2884a7c91847Schristos static void 2885a7c91847Schristos handle_mt (char *args, size_t len) 2886a7c91847Schristos { 2887a7c91847Schristos char *p; 2888a7c91847Schristos char *tag = args; 2889a7c91847Schristos char *text; 2890a7c91847Schristos 2891a7c91847Schristos /* See comment at handle_m for more details. */ 2892a7c91847Schristos fflush (stderr); 2893a7c91847Schristos 2894a7c91847Schristos p = strchr (args, ' '); 2895a7c91847Schristos if (!p) 2896a7c91847Schristos text = NULL; 2897a7c91847Schristos else 2898a7c91847Schristos { 2899a7c91847Schristos *p++ = '\0'; 2900a7c91847Schristos text = p; 2901a7c91847Schristos } 2902a7c91847Schristos 2903a7c91847Schristos switch (tag[0]) 2904a7c91847Schristos { 2905a7c91847Schristos case '+': 2906a7c91847Schristos if (!strcmp (tag, "+updated")) 2907a7c91847Schristos updated_seen = 1; 2908a7c91847Schristos else if (!strcmp (tag, "+importmergecmd")) 2909a7c91847Schristos importmergecmd.seen = 1; 2910a7c91847Schristos break; 2911a7c91847Schristos case '-': 2912a7c91847Schristos if (!strcmp (tag, "-updated")) 2913a7c91847Schristos updated_seen = 0; 2914a7c91847Schristos else if (!strcmp (tag, "-importmergecmd")) 2915a7c91847Schristos { 2916a7c91847Schristos char buf[80]; 2917a7c91847Schristos 2918a7c91847Schristos /* Now that we have gathered the information, we can 2919a7c91847Schristos output the suggested merge command. */ 2920a7c91847Schristos 2921a7c91847Schristos if (importmergecmd.conflicts == 0 2922a7c91847Schristos || !importmergecmd.mergetag1 2923a7c91847Schristos || !importmergecmd.mergetag2 2924a7c91847Schristos || !importmergecmd.repository) 2925a7c91847Schristos { 2926a7c91847Schristos error (0, 0, 2927a7c91847Schristos "invalid server: incomplete importmergecmd tags"); 2928a7c91847Schristos break; 2929a7c91847Schristos } 2930a7c91847Schristos 2931a7c91847Schristos if (importmergecmd.conflicts == -1) 2932a7c91847Schristos sprintf (buf, "\nNo conflicts created by this import.\n"); 2933a7c91847Schristos else 2934a7c91847Schristos sprintf (buf, "\n%d conflicts created by this import.\n", 2935a7c91847Schristos importmergecmd.conflicts); 2936a7c91847Schristos cvs_output (buf, 0); 2937a7c91847Schristos cvs_output ("Use the following command to help the merge:\n\n", 2938a7c91847Schristos 0); 2939a7c91847Schristos cvs_output ("\t", 1); 2940a7c91847Schristos cvs_output (program_name, 0); 2941a7c91847Schristos if (CVSroot_cmdline) 2942a7c91847Schristos { 2943a7c91847Schristos cvs_output (" -d ", 0); 2944a7c91847Schristos cvs_output (CVSroot_cmdline, 0); 2945a7c91847Schristos } 2946a7c91847Schristos cvs_output (" checkout -j", 0); 2947a7c91847Schristos cvs_output (importmergecmd.mergetag1, 0); 2948a7c91847Schristos cvs_output (" -j", 0); 2949a7c91847Schristos cvs_output (importmergecmd.mergetag2, 0); 2950a7c91847Schristos cvs_output (" ", 1); 2951a7c91847Schristos cvs_output (importmergecmd.repository, 0); 2952a7c91847Schristos cvs_output ("\n\n", 0); 2953a7c91847Schristos 2954a7c91847Schristos /* Clear the static variables so that everything is 2955a7c91847Schristos ready for any subsequent importmergecmd tag. */ 2956a7c91847Schristos importmergecmd.conflicts = 0; 2957a7c91847Schristos free (importmergecmd.mergetag1); 2958a7c91847Schristos importmergecmd.mergetag1 = NULL; 2959a7c91847Schristos free (importmergecmd.mergetag2); 2960a7c91847Schristos importmergecmd.mergetag2 = NULL; 2961a7c91847Schristos free (importmergecmd.repository); 2962a7c91847Schristos importmergecmd.repository = NULL; 2963a7c91847Schristos 2964a7c91847Schristos importmergecmd.seen = 0; 2965a7c91847Schristos } 2966a7c91847Schristos break; 2967a7c91847Schristos default: 2968a7c91847Schristos if (updated_seen) 2969a7c91847Schristos { 2970a7c91847Schristos if (!strcmp (tag, "fname")) 2971a7c91847Schristos { 2972a7c91847Schristos if (updated_fname) 2973a7c91847Schristos { 2974a7c91847Schristos /* Output the previous message now. This can happen 2975a7c91847Schristos if there was no Update-existing or other such 2976a7c91847Schristos response, due to the -n global option. */ 2977a7c91847Schristos cvs_output ("U ", 0); 2978a7c91847Schristos cvs_output (updated_fname, 0); 2979a7c91847Schristos cvs_output ("\n", 1); 2980a7c91847Schristos free (updated_fname); 2981a7c91847Schristos } 2982a7c91847Schristos updated_fname = xstrdup (text); 2983a7c91847Schristos } 2984a7c91847Schristos /* Swallow all other tags. Either they are extraneous 2985a7c91847Schristos or they reflect future extensions that we can 2986a7c91847Schristos safely ignore. */ 2987a7c91847Schristos } 2988a7c91847Schristos else if (importmergecmd.seen) 2989a7c91847Schristos { 2990a7c91847Schristos if (!strcmp (tag, "conflicts")) 2991a7c91847Schristos { 2992a7c91847Schristos if (!strcmp (text, "No")) 2993a7c91847Schristos importmergecmd.conflicts = -1; 2994a7c91847Schristos else 2995a7c91847Schristos importmergecmd.conflicts = atoi (text); 2996a7c91847Schristos } 2997a7c91847Schristos else if (!strcmp (tag, "mergetag1")) 2998a7c91847Schristos importmergecmd.mergetag1 = xstrdup (text); 2999a7c91847Schristos else if (!strcmp (tag, "mergetag2")) 3000a7c91847Schristos importmergecmd.mergetag2 = xstrdup (text); 3001a7c91847Schristos else if (!strcmp (tag, "repository")) 3002a7c91847Schristos importmergecmd.repository = xstrdup (text); 3003a7c91847Schristos /* Swallow all other tags. Either they are text for 3004a7c91847Schristos which we are going to print our own version when we 3005a7c91847Schristos see -importmergecmd, or they are future extensions 3006a7c91847Schristos we can safely ignore. */ 3007a7c91847Schristos } 3008a7c91847Schristos else if (!strcmp (tag, "newline")) 3009a7c91847Schristos printf ("\n"); 3010a7c91847Schristos else if (!strcmp (tag, "date")) 3011a7c91847Schristos { 3012a7c91847Schristos char *date = format_date_alloc (text); 3013a7c91847Schristos printf ("%s", date); 3014a7c91847Schristos free (date); 3015a7c91847Schristos } 3016a7c91847Schristos else if (text) 3017a7c91847Schristos printf ("%s", text); 3018a7c91847Schristos } 3019a7c91847Schristos } 3020a7c91847Schristos 3021a7c91847Schristos 3022a7c91847Schristos 3023a7c91847Schristos #endif /* CLIENT_SUPPORT */ 3024a7c91847Schristos #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) 3025a7c91847Schristos 3026a7c91847Schristos /* This table must be writeable if the server code is included. */ 3027a7c91847Schristos struct response responses[] = 3028a7c91847Schristos { 3029a7c91847Schristos #ifdef CLIENT_SUPPORT 3030a7c91847Schristos #define RSP_LINE(n, f, t, s) {n, f, t, s} 3031a7c91847Schristos #else /* ! CLIENT_SUPPORT */ 3032a7c91847Schristos #define RSP_LINE(n, f, t, s) {n, s} 3033a7c91847Schristos #endif /* CLIENT_SUPPORT */ 3034a7c91847Schristos 3035a7c91847Schristos RSP_LINE("ok", handle_ok, response_type_ok, rs_essential), 3036a7c91847Schristos RSP_LINE("error", handle_error, response_type_error, rs_essential), 3037a7c91847Schristos RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal, 3038a7c91847Schristos rs_essential), 3039a7c91847Schristos RSP_LINE("Force-gzip", handle_force_gzip, response_type_normal, 3040a7c91847Schristos rs_optional), 3041a7c91847Schristos RSP_LINE("Referrer", handle_referrer, response_type_normal, rs_optional), 3042a7c91847Schristos RSP_LINE("Redirect", handle_redirect, response_type_redirect, rs_optional), 3043a7c91847Schristos RSP_LINE("Checked-in", handle_checked_in, response_type_normal, 3044a7c91847Schristos rs_essential), 3045a7c91847Schristos RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional), 3046a7c91847Schristos RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional), 3047a7c91847Schristos RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional), 3048a7c91847Schristos RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential), 3049a7c91847Schristos RSP_LINE("Created", handle_created, response_type_normal, rs_optional), 3050a7c91847Schristos RSP_LINE("Update-existing", handle_update_existing, response_type_normal, 3051a7c91847Schristos rs_optional), 3052a7c91847Schristos RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential), 3053a7c91847Schristos RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional), 3054a7c91847Schristos RSP_LINE("Rcs-diff", handle_rcs_diff, response_type_normal, rs_optional), 3055a7c91847Schristos RSP_LINE("Mode", handle_mode, response_type_normal, rs_optional), 3056a7c91847Schristos RSP_LINE("Mod-time", handle_mod_time, response_type_normal, rs_optional), 3057a7c91847Schristos RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential), 3058a7c91847Schristos RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal, 3059a7c91847Schristos rs_optional), 3060a7c91847Schristos RSP_LINE("Set-static-directory", handle_set_static_directory, 3061a7c91847Schristos response_type_normal, 3062a7c91847Schristos rs_optional), 3063a7c91847Schristos RSP_LINE("Clear-static-directory", handle_clear_static_directory, 3064a7c91847Schristos response_type_normal, 3065a7c91847Schristos rs_optional), 3066a7c91847Schristos RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal, 3067a7c91847Schristos rs_optional), 3068a7c91847Schristos RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal, 3069a7c91847Schristos rs_optional), 3070a7c91847Schristos RSP_LINE("Edit-file", handle_edit_file, response_type_normal, 3071a7c91847Schristos rs_optional), 3072a7c91847Schristos RSP_LINE("Template", handle_template, response_type_normal, 3073a7c91847Schristos rs_optional), 3074a7c91847Schristos RSP_LINE("Clear-template", handle_clear_template, response_type_normal, 3075a7c91847Schristos rs_optional), 3076a7c91847Schristos RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional), 3077a7c91847Schristos RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal, 3078a7c91847Schristos rs_optional), 3079a7c91847Schristos RSP_LINE("Wrapper-rcsOption", handle_wrapper_rcs_option, 3080a7c91847Schristos response_type_normal, 3081a7c91847Schristos rs_optional), 3082a7c91847Schristos RSP_LINE("M", handle_m, response_type_normal, rs_essential), 3083a7c91847Schristos RSP_LINE("Mbinary", handle_mbinary, response_type_normal, rs_optional), 3084a7c91847Schristos RSP_LINE("E", handle_e, response_type_normal, rs_essential), 3085a7c91847Schristos RSP_LINE("F", handle_f, response_type_normal, rs_optional), 3086a7c91847Schristos RSP_LINE("MT", handle_mt, response_type_normal, rs_optional), 3087a7c91847Schristos /* Possibly should be response_type_error. */ 3088a7c91847Schristos RSP_LINE(NULL, NULL, response_type_normal, rs_essential) 3089a7c91847Schristos 3090a7c91847Schristos #undef RSP_LINE 3091a7c91847Schristos }; 3092a7c91847Schristos 3093a7c91847Schristos #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ 3094a7c91847Schristos #ifdef CLIENT_SUPPORT 3095a7c91847Schristos 3096a7c91847Schristos 3097a7c91847Schristos 3098a7c91847Schristos /* 3099a7c91847Schristos * If LEN is 0, then send_to_server_via() computes string's length itself. 3100a7c91847Schristos * 3101a7c91847Schristos * Therefore, pass the real length when transmitting data that might 3102a7c91847Schristos * contain 0's. 3103a7c91847Schristos */ 3104a7c91847Schristos void 3105a7c91847Schristos send_to_server_via (struct buffer *via_buffer, const char *str, size_t len) 3106a7c91847Schristos { 3107a7c91847Schristos static int nbytes; 3108a7c91847Schristos 3109a7c91847Schristos if (len == 0) 3110a7c91847Schristos len = strlen (str); 3111a7c91847Schristos 3112a7c91847Schristos buf_output (via_buffer, str, len); 3113a7c91847Schristos 3114a7c91847Schristos /* There is no reason not to send data to the server, so do it 3115a7c91847Schristos whenever we've accumulated enough information in the buffer to 3116a7c91847Schristos make it worth sending. */ 3117a7c91847Schristos nbytes += len; 3118a7c91847Schristos if (nbytes >= 2 * BUFFER_DATA_SIZE) 3119a7c91847Schristos { 3120a7c91847Schristos int status; 3121a7c91847Schristos 3122a7c91847Schristos status = buf_send_output (via_buffer); 3123a7c91847Schristos if (status != 0) 3124a7c91847Schristos error (1, status, "error writing to server"); 3125a7c91847Schristos nbytes = 0; 3126a7c91847Schristos } 3127a7c91847Schristos } 3128a7c91847Schristos 3129a7c91847Schristos 3130a7c91847Schristos 3131a7c91847Schristos void 3132a7c91847Schristos send_to_server (const char *str, size_t len) 3133a7c91847Schristos { 3134a7c91847Schristos send_to_server_via (global_to_server, str, len); 3135a7c91847Schristos } 3136a7c91847Schristos 3137a7c91847Schristos 3138a7c91847Schristos 3139a7c91847Schristos /* Read up to LEN bytes from the server. Returns actual number of 3140a7c91847Schristos bytes read, which will always be at least one; blocks if there is 3141a7c91847Schristos no data available at all. Gives a fatal error on EOF or error. */ 3142a7c91847Schristos static size_t 3143a7c91847Schristos try_read_from_server( char *buf, size_t len ) 3144a7c91847Schristos { 3145a7c91847Schristos int status; 3146a7c91847Schristos size_t nread; 3147a7c91847Schristos char *data; 3148a7c91847Schristos 3149a7c91847Schristos status = buf_read_data (global_from_server, len, &data, &nread); 3150a7c91847Schristos if (status != 0) 3151a7c91847Schristos { 3152a7c91847Schristos if (status == -1) 3153a7c91847Schristos error (1, 0, 3154a7c91847Schristos "end of file from server (consult above messages if any)"); 3155a7c91847Schristos else if (status == -2) 3156a7c91847Schristos error (1, 0, "out of memory"); 3157a7c91847Schristos else 3158a7c91847Schristos error (1, status, "reading from server"); 3159a7c91847Schristos } 3160a7c91847Schristos 3161a7c91847Schristos memcpy (buf, data, nread); 3162a7c91847Schristos 3163a7c91847Schristos return nread; 3164a7c91847Schristos } 3165a7c91847Schristos 3166a7c91847Schristos 3167a7c91847Schristos 3168a7c91847Schristos /* 3169a7c91847Schristos * Read LEN bytes from the server or die trying. 3170a7c91847Schristos */ 3171a7c91847Schristos void 3172a7c91847Schristos read_from_server (char *buf, size_t len) 3173a7c91847Schristos { 3174a7c91847Schristos size_t red = 0; 3175a7c91847Schristos while (red < len) 3176a7c91847Schristos { 3177a7c91847Schristos red += try_read_from_server (buf + red, len - red); 3178a7c91847Schristos if (red == len) 3179a7c91847Schristos break; 3180a7c91847Schristos } 3181a7c91847Schristos } 3182a7c91847Schristos 3183a7c91847Schristos 3184a7c91847Schristos 3185a7c91847Schristos /* Get some server responses and process them. 3186a7c91847Schristos * 3187a7c91847Schristos * RETURNS 3188a7c91847Schristos * 0 Success 3189a7c91847Schristos * 1 Error 3190a7c91847Schristos * 2 Redirect 3191a7c91847Schristos */ 3192a7c91847Schristos int 3193a7c91847Schristos get_server_responses (void) 3194a7c91847Schristos { 3195a7c91847Schristos struct response *rs; 3196a7c91847Schristos do 3197a7c91847Schristos { 3198a7c91847Schristos char *cmd; 3199a7c91847Schristos size_t len; 3200a7c91847Schristos 3201a7c91847Schristos len = read_line (&cmd); 3202a7c91847Schristos for (rs = responses; rs->name; ++rs) 3203a7c91847Schristos if (!strncmp (cmd, rs->name, strlen (rs->name))) 3204a7c91847Schristos { 3205a7c91847Schristos size_t cmdlen = strlen (rs->name); 3206a7c91847Schristos if (cmd[cmdlen] == '\0') 3207a7c91847Schristos ; 3208a7c91847Schristos else if (cmd[cmdlen] == ' ') 3209a7c91847Schristos ++cmdlen; 3210a7c91847Schristos else 3211a7c91847Schristos /* 3212a7c91847Schristos * The first len characters match, but it's a different 3213a7c91847Schristos * response. e.g. the response is "oklahoma" but we 3214a7c91847Schristos * matched "ok". 3215a7c91847Schristos */ 3216a7c91847Schristos continue; 3217a7c91847Schristos (*rs->func) (cmd + cmdlen, len - cmdlen); 3218a7c91847Schristos break; 3219a7c91847Schristos } 3220a7c91847Schristos if (!rs->name) 3221a7c91847Schristos /* It's OK to print just to the first '\0'. */ 3222a7c91847Schristos /* We might want to handle control characters and the like 3223a7c91847Schristos in some other way other than just sending them to stdout. 3224a7c91847Schristos One common reason for this error is if people use :ext: 3225a7c91847Schristos with a version of rsh which is doing CRLF translation or 3226a7c91847Schristos something, and so the client gets "ok^M" instead of "ok". 3227a7c91847Schristos Right now that will tend to print part of this error 3228a7c91847Schristos message over the other part of it. It seems like we could 3229a7c91847Schristos do better (either in general, by quoting or omitting all 3230a7c91847Schristos control characters, and/or specifically, by detecting the CRLF 3231a7c91847Schristos case and printing a specific error message). */ 3232a7c91847Schristos error (0, 0, 3233a7c91847Schristos "warning: unrecognized response `%s' from cvs server", 3234a7c91847Schristos cmd); 3235a7c91847Schristos free (cmd); 3236a7c91847Schristos } while (rs->type == response_type_normal); 3237a7c91847Schristos 3238a7c91847Schristos if (updated_fname) 3239a7c91847Schristos { 3240a7c91847Schristos /* Output the previous message now. This can happen 3241a7c91847Schristos if there was no Update-existing or other such 3242a7c91847Schristos response, due to the -n global option. */ 3243a7c91847Schristos cvs_output ("U ", 0); 3244a7c91847Schristos cvs_output (updated_fname, 0); 3245a7c91847Schristos cvs_output ("\n", 1); 3246a7c91847Schristos free (updated_fname); 3247a7c91847Schristos updated_fname = NULL; 3248a7c91847Schristos } 3249a7c91847Schristos 3250a7c91847Schristos if (rs->type == response_type_redirect) return 2; 3251a7c91847Schristos if (rs->type == response_type_error) return 1; 3252a7c91847Schristos if (failure_exit) return 1; 3253a7c91847Schristos return 0; 3254a7c91847Schristos } 3255a7c91847Schristos 3256a7c91847Schristos 3257a7c91847Schristos 3258a7c91847Schristos static inline void 3259a7c91847Schristos close_connection_to_server (struct buffer **to, struct buffer **from) 3260a7c91847Schristos { 3261a7c91847Schristos int status; 3262a7c91847Schristos 3263a7c91847Schristos /* First we shut down GLOBAL_TO_SERVER. That tells the server that its 3264a7c91847Schristos * input is finished. It then shuts down the buffer it is sending to us, 3265a7c91847Schristos * at which point our shut down of GLOBAL_FROM_SERVER will complete. 3266a7c91847Schristos */ 3267a7c91847Schristos 3268a7c91847Schristos TRACE (TRACE_FUNCTION, "close_connection_to_server ()"); 3269a7c91847Schristos 3270a7c91847Schristos status = buf_shutdown (*to); 3271a7c91847Schristos if (status != 0) 3272a7c91847Schristos error (0, status, "shutting down buffer to server"); 3273a7c91847Schristos buf_free (*to); 3274a7c91847Schristos *to = NULL; 3275a7c91847Schristos 3276a7c91847Schristos status = buf_shutdown (*from); 3277a7c91847Schristos if (status != 0) 3278a7c91847Schristos error (0, status, "shutting down buffer from server"); 3279a7c91847Schristos buf_free (*from); 3280a7c91847Schristos *from = NULL; 3281a7c91847Schristos } 3282a7c91847Schristos 3283a7c91847Schristos 3284a7c91847Schristos 3285a7c91847Schristos /* Get the responses and then close the connection. */ 3286a7c91847Schristos 3287a7c91847Schristos /* 3288a7c91847Schristos * Flag var; we'll set it in start_server() and not one of its 3289a7c91847Schristos * callees, such as start_rsh_server(). This means that there might 3290a7c91847Schristos * be a small window between the starting of the server and the 3291a7c91847Schristos * setting of this var, but all the code in that window shouldn't care 3292a7c91847Schristos * because it's busy checking return values to see if the server got 3293a7c91847Schristos * started successfully anyway. 3294a7c91847Schristos */ 3295a7c91847Schristos int server_started = 0; 3296a7c91847Schristos 3297a7c91847Schristos int 3298a7c91847Schristos get_responses_and_close (void) 3299a7c91847Schristos { 3300a7c91847Schristos int errs = get_server_responses (); 3301a7c91847Schristos 3302a7c91847Schristos /* The following is necessary when working with multiple cvsroots, at least 3303a7c91847Schristos * with commit. It used to be buried nicely in do_deferred_progs() before 3304a7c91847Schristos * that function was removed. I suspect it wouldn't be necessary if 3305a7c91847Schristos * call_in_directory() saved its working directory via save_cwd() before 3306a7c91847Schristos * changing its directory and restored the saved working directory via 3307a7c91847Schristos * restore_cwd() before exiting. Of course, calling CVS_CHDIR only once, 3308a7c91847Schristos * here, may be more efficient. 3309a7c91847Schristos */ 3310a7c91847Schristos if (toplevel_wd) 3311a7c91847Schristos { 3312a7c91847Schristos if (CVS_CHDIR (toplevel_wd) < 0) 3313a7c91847Schristos error (1, errno, "could not chdir to %s", toplevel_wd); 3314a7c91847Schristos } 3315a7c91847Schristos 3316a7c91847Schristos if (client_prune_dirs) 3317a7c91847Schristos process_prune_candidates (); 3318a7c91847Schristos 3319a7c91847Schristos close_connection_to_server (&global_to_server, &global_from_server); 3320a7c91847Schristos server_started = 0; 3321a7c91847Schristos 3322a7c91847Schristos /* see if we need to sleep before returning to avoid time-stamp races */ 3323a7c91847Schristos if (last_register_time) 3324a7c91847Schristos sleep_past (last_register_time); 3325a7c91847Schristos 3326a7c91847Schristos return errs; 3327a7c91847Schristos } 3328a7c91847Schristos 3329a7c91847Schristos 3330a7c91847Schristos 3331a7c91847Schristos bool 3332a7c91847Schristos supported_request (const char *name) 3333a7c91847Schristos { 3334a7c91847Schristos struct request *rq; 3335a7c91847Schristos 3336a7c91847Schristos for (rq = requests; rq->name; rq++) 3337a7c91847Schristos if (!strcmp (rq->name, name)) 3338a7c91847Schristos return (rq->flags & RQ_SUPPORTED) != 0; 3339a7c91847Schristos error (1, 0, "internal error: testing support for unknown request?"); 3340a7c91847Schristos /* NOTREACHED */ 3341a7c91847Schristos return 0; 3342a7c91847Schristos } 3343a7c91847Schristos 3344a7c91847Schristos 3345a7c91847Schristos 3346a7c91847Schristos #if defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) 3347a7c91847Schristos 3348a7c91847Schristos 3349a7c91847Schristos /* Generic function to do port number lookup tasks. 3350a7c91847Schristos * 3351a7c91847Schristos * In order of precedence, will return: 3352a7c91847Schristos * getenv (envname), if defined 3353a7c91847Schristos * getservbyname (portname), if defined 3354a7c91847Schristos * defaultport 3355a7c91847Schristos */ 3356a7c91847Schristos static int 3357a7c91847Schristos get_port_number (const char *envname, const char *portname, int defaultport) 3358a7c91847Schristos { 3359a7c91847Schristos struct servent *s; 3360a7c91847Schristos char *port_s; 3361a7c91847Schristos 3362a7c91847Schristos if (envname && (port_s = getenv (envname))) 3363a7c91847Schristos { 3364a7c91847Schristos int port = atoi (port_s); 3365a7c91847Schristos if (port <= 0) 3366a7c91847Schristos { 3367a7c91847Schristos error (0, 0, "%s must be a positive integer! If you", envname); 3368a7c91847Schristos error (0, 0, "are trying to force a connection via rsh, please"); 3369a7c91847Schristos error (0, 0, "put \":server:\" at the beginning of your CVSROOT"); 3370a7c91847Schristos error (1, 0, "variable."); 3371a7c91847Schristos } 3372a7c91847Schristos return port; 3373a7c91847Schristos } 3374a7c91847Schristos else if (portname && (s = getservbyname (portname, "tcp"))) 3375a7c91847Schristos return ntohs (s->s_port); 3376a7c91847Schristos else 3377a7c91847Schristos return defaultport; 3378a7c91847Schristos } 3379a7c91847Schristos 3380a7c91847Schristos 3381a7c91847Schristos 3382a7c91847Schristos /* get the port number for a client to connect to based on the port 3383a7c91847Schristos * and method of a cvsroot_t. 3384a7c91847Schristos * 3385a7c91847Schristos * we do this here instead of in parse_cvsroot so that we can keep network 3386a7c91847Schristos * code confined to a localized area and also to delay the lookup until the 3387a7c91847Schristos * last possible moment so it remains possible to run cvs client commands that 3388a7c91847Schristos * skip opening connections to the server (i.e. skip network operations 3389a7c91847Schristos * entirely) 3390a7c91847Schristos * 3391a7c91847Schristos * and yes, I know none of the commands do that now, but here's to planning 3392a7c91847Schristos * for the future, eh? cheers. 3393a7c91847Schristos */ 3394a7c91847Schristos int 3395a7c91847Schristos get_cvs_port_number (const cvsroot_t *root) 3396a7c91847Schristos { 3397a7c91847Schristos 3398a7c91847Schristos if (root->port) return root->port; 3399a7c91847Schristos 3400a7c91847Schristos switch (root->method) 3401a7c91847Schristos { 3402a7c91847Schristos # ifdef HAVE_GSSAPI 3403a7c91847Schristos case gserver_method: 3404a7c91847Schristos # endif /* HAVE_GSSAPI */ 3405a7c91847Schristos # ifdef AUTH_CLIENT_SUPPORT 3406a7c91847Schristos case pserver_method: 3407a7c91847Schristos # endif /* AUTH_CLIENT_SUPPORT */ 3408a7c91847Schristos # if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) 3409a7c91847Schristos return get_port_number ("CVS_CLIENT_PORT", "cvspserver", 3410a7c91847Schristos CVS_AUTH_PORT); 3411a7c91847Schristos # endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */ 3412a7c91847Schristos # ifdef HAVE_KERBEROS 3413a7c91847Schristos case kserver_method: 3414a7c91847Schristos return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT); 3415a7c91847Schristos # endif /* HAVE_KERBEROS */ 3416a7c91847Schristos default: 3417a7c91847Schristos error(1, EINVAL, 3418a7c91847Schristos "internal error: get_cvs_port_number called for invalid connection method (%s)", 3419a7c91847Schristos method_names[root->method]); 3420a7c91847Schristos break; 3421a7c91847Schristos } 3422a7c91847Schristos /* NOTREACHED */ 3423a7c91847Schristos return -1; 3424a7c91847Schristos } 3425a7c91847Schristos 3426a7c91847Schristos 3427a7c91847Schristos 3428a7c91847Schristos /* get the port number for a client to connect to based on the proxy port 3429a7c91847Schristos * of a cvsroot_t. 3430a7c91847Schristos */ 3431a7c91847Schristos static int 3432a7c91847Schristos get_proxy_port_number (const cvsroot_t *root) 3433a7c91847Schristos { 3434a7c91847Schristos 3435a7c91847Schristos if (root->proxy_port) return root->proxy_port; 3436a7c91847Schristos 3437a7c91847Schristos return get_port_number ("CVS_PROXY_PORT", NULL, CVS_PROXY_PORT); 3438a7c91847Schristos } 3439a7c91847Schristos 3440a7c91847Schristos 3441a7c91847Schristos 3442a7c91847Schristos void 3443a7c91847Schristos make_bufs_from_fds(int tofd, int fromfd, int child_pid, cvsroot_t *root, 3444a7c91847Schristos struct buffer **to_server_p, 3445a7c91847Schristos struct buffer **from_server_p, int is_sock) 3446a7c91847Schristos { 3447a7c91847Schristos # ifdef NO_SOCKET_TO_FD 3448a7c91847Schristos if (is_sock) 3449a7c91847Schristos { 3450a7c91847Schristos assert (tofd == fromfd); 3451a7c91847Schristos *to_server_p = socket_buffer_initialize (tofd, 0, NULL); 3452a7c91847Schristos *from_server_p = socket_buffer_initialize (tofd, 1, NULL); 3453a7c91847Schristos } 3454a7c91847Schristos else 3455a7c91847Schristos # endif /* NO_SOCKET_TO_FD */ 3456a7c91847Schristos { 3457a7c91847Schristos /* todo: some OS's don't need these calls... */ 3458a7c91847Schristos close_on_exec (tofd); 3459a7c91847Schristos close_on_exec (fromfd); 3460a7c91847Schristos 3461a7c91847Schristos /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes 3462a7c91847Schristos fdopening the same file descriptor twice, so dup it if it is the 3463a7c91847Schristos same. */ 3464a7c91847Schristos if (tofd == fromfd) 3465a7c91847Schristos { 3466a7c91847Schristos fromfd = dup (tofd); 3467a7c91847Schristos if (fromfd < 0) 3468a7c91847Schristos error (1, errno, "cannot dup net connection"); 3469a7c91847Schristos } 3470a7c91847Schristos 3471a7c91847Schristos /* These will use binary mode on systems which have it. */ 3472a7c91847Schristos /* 3473a7c91847Schristos * Also, we know that from_server is shut down second, so we pass 3474a7c91847Schristos * child_pid in there. In theory, it should be stored in both 3475a7c91847Schristos * buffers with a ref count... 3476a7c91847Schristos */ 3477a7c91847Schristos *to_server_p = fd_buffer_initialize (tofd, 0, root, false, NULL); 3478a7c91847Schristos *from_server_p = fd_buffer_initialize (fromfd, child_pid, root, 3479a7c91847Schristos true, NULL); 3480a7c91847Schristos } 3481a7c91847Schristos } 3482a7c91847Schristos #endif /* defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined(HAVE_GSSAPI) */ 3483a7c91847Schristos 3484a7c91847Schristos 3485a7c91847Schristos 3486a7c91847Schristos #if defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) 3487a7c91847Schristos /* Connect to the authenticating server. 3488a7c91847Schristos 3489a7c91847Schristos If VERIFY_ONLY is non-zero, then just verify that the password is 3490a7c91847Schristos correct and then shutdown the connection. 3491a7c91847Schristos 3492a7c91847Schristos If VERIFY_ONLY is 0, then really connect to the server. 3493a7c91847Schristos 3494a7c91847Schristos If DO_GSSAPI is non-zero, then we use GSSAPI authentication rather 3495a7c91847Schristos than the pserver password authentication. 3496a7c91847Schristos 3497a7c91847Schristos If we fail to connect or if access is denied, then die with fatal 3498a7c91847Schristos error. */ 3499a7c91847Schristos void 3500a7c91847Schristos connect_to_pserver (cvsroot_t *root, struct buffer **to_server_p, 3501a7c91847Schristos struct buffer **from_server_p, int verify_only, 3502a7c91847Schristos int do_gssapi) 3503a7c91847Schristos { 3504a7c91847Schristos int sock; 3505a7c91847Schristos int port_number, 3506a7c91847Schristos proxy_port_number = 0; /* Initialize to silence -Wall. Dumb. */ 3507274254cdSchristos char no_passwd = 0; /* gets set if no password found */ 3508a7c91847Schristos struct buffer *to_server, *from_server; 3509a7c91847Schristos 3510a7c91847Schristos port_number = get_cvs_port_number (root); 3511a7c91847Schristos 3512a7c91847Schristos /* if we have a proxy connect to that instead */ 3513a7c91847Schristos if (root->proxy_hostname) 3514a7c91847Schristos { 3515274254cdSchristos TRACE (TRACE_FUNCTION, "Connecting to %s:%d via proxy %s:%d.", 3516a7c91847Schristos root->hostname, port_number, root->proxy_hostname, 3517274254cdSchristos proxy_port_number); 3518274254cdSchristos proxy_port_number = get_proxy_port_number (root); 3519274254cdSchristos sock = connect_to(root->proxy_hostname, proxy_port_number); 3520a7c91847Schristos } 3521a7c91847Schristos else 3522a7c91847Schristos { 3523274254cdSchristos TRACE (TRACE_FUNCTION, "Connecting to %s:%d.", 3524274254cdSchristos root->hostname, port_number); 3525274254cdSchristos sock = connect_to(root->hostname, port_number); 3526a7c91847Schristos } 3527a7c91847Schristos 3528274254cdSchristos if (sock == -1) 3529274254cdSchristos error (1, 0, "connect to %s:%d failed: %s", 3530a7c91847Schristos root->proxy_hostname ? root->proxy_hostname : root->hostname, 3531a7c91847Schristos root->proxy_hostname ? proxy_port_number : port_number, 3532a7c91847Schristos SOCK_STRERROR (SOCK_ERRNO)); 3533a7c91847Schristos 3534a7c91847Schristos make_bufs_from_fds (sock, sock, 0, root, &to_server, &from_server, 1); 3535a7c91847Schristos 3536a7c91847Schristos /* if we have proxy then connect to the proxy first */ 3537a7c91847Schristos if (root->proxy_hostname) 3538a7c91847Schristos { 3539a7c91847Schristos #define CONNECT_STRING "CONNECT %s:%d HTTP/1.0\r\n\r\n" 3540a7c91847Schristos /* Send a "CONNECT" command to proxy: */ 3541a7c91847Schristos char* read_buf; 3542a7c91847Schristos int codenum; 3543a7c91847Schristos size_t count; 3544a7c91847Schristos /* 4 characters for port covered by the length of %s & %d */ 3545a7c91847Schristos char* write_buf = Xasnprintf (NULL, &count, CONNECT_STRING, 3546a7c91847Schristos root->hostname, port_number); 3547a7c91847Schristos send_to_server_via (to_server, write_buf, count); 3548a7c91847Schristos 3549a7c91847Schristos /* Wait for HTTP status code, bail out if you don't get back a 2xx 3550a7c91847Schristos * code. 3551a7c91847Schristos */ 3552a7c91847Schristos read_line_via (from_server, to_server, &read_buf); 3553a7c91847Schristos sscanf (read_buf, "%s %d", write_buf, &codenum); 3554a7c91847Schristos 3555a7c91847Schristos if ((codenum / 100) != 2) 3556a7c91847Schristos error (1, 0, "proxy server %s:%d does not support http tunnelling", 3557a7c91847Schristos root->proxy_hostname, proxy_port_number); 3558a7c91847Schristos free (read_buf); 3559a7c91847Schristos free (write_buf); 3560a7c91847Schristos 3561a7c91847Schristos /* Skip through remaining part of MIME header, recv_line 3562a7c91847Schristos consumes the trailing \n */ 3563a7c91847Schristos while (read_line_via (from_server, to_server, &read_buf) > 0) 3564a7c91847Schristos { 3565a7c91847Schristos if (read_buf[0] == '\r' || read_buf[0] == 0) 3566a7c91847Schristos { 3567a7c91847Schristos free (read_buf); 3568a7c91847Schristos break; 3569a7c91847Schristos } 3570a7c91847Schristos free (read_buf); 3571a7c91847Schristos } 3572a7c91847Schristos } 3573a7c91847Schristos 3574274254cdSchristos auth_server (root, to_server, from_server, verify_only, do_gssapi); 3575a7c91847Schristos 3576a7c91847Schristos if (verify_only) 3577a7c91847Schristos { 3578a7c91847Schristos int status; 3579a7c91847Schristos 3580a7c91847Schristos status = buf_shutdown (to_server); 3581a7c91847Schristos if (status != 0) 3582a7c91847Schristos error (0, status, "shutting down buffer to server"); 3583a7c91847Schristos buf_free (to_server); 3584a7c91847Schristos to_server = NULL; 3585a7c91847Schristos 3586a7c91847Schristos status = buf_shutdown (from_server); 3587a7c91847Schristos if (status != 0) 3588a7c91847Schristos error (0, status, "shutting down buffer from server"); 3589a7c91847Schristos buf_free (from_server); 3590a7c91847Schristos from_server = NULL; 3591a7c91847Schristos 3592a7c91847Schristos /* Don't need to set server_started = 0 since we don't set it to 1 3593a7c91847Schristos * until returning from this call. 3594a7c91847Schristos */ 3595a7c91847Schristos } 3596a7c91847Schristos else 3597a7c91847Schristos { 3598a7c91847Schristos *to_server_p = to_server; 3599a7c91847Schristos *from_server_p = from_server; 3600a7c91847Schristos } 3601a7c91847Schristos 3602a7c91847Schristos return; 3603a7c91847Schristos } 3604a7c91847Schristos 3605a7c91847Schristos 3606a7c91847Schristos 3607a7c91847Schristos static void 3608a7c91847Schristos auth_server (cvsroot_t *root, struct buffer *to_server, 3609274254cdSchristos struct buffer *from_server, int verify_only, int do_gssapi) 3610a7c91847Schristos { 3611a7c91847Schristos char *username = NULL; /* the username we use to connect */ 3612a7c91847Schristos char no_passwd = 0; /* gets set if no password found */ 3613a7c91847Schristos 3614a7c91847Schristos /* Run the authorization mini-protocol before anything else. */ 3615a7c91847Schristos if (do_gssapi) 3616a7c91847Schristos { 3617a7c91847Schristos # ifdef HAVE_GSSAPI 3618a7c91847Schristos int fd = buf_get_fd (to_server); 3619a7c91847Schristos struct stat s; 3620a7c91847Schristos 3621a7c91847Schristos if ((fd < 0) || (fstat (fd, &s) < 0) || !S_ISSOCK(s.st_mode)) 3622a7c91847Schristos { 3623a7c91847Schristos error (1, 0, 3624a7c91847Schristos "gserver currently only enabled for socket connections"); 3625a7c91847Schristos } 3626a7c91847Schristos 3627274254cdSchristos if (! connect_to_gserver (root, fd, root->hostname)) 3628a7c91847Schristos { 3629a7c91847Schristos error (1, 0, 3630a7c91847Schristos "authorization failed: server %s rejected access to %s", 3631a7c91847Schristos root->hostname, root->directory); 3632a7c91847Schristos } 3633a7c91847Schristos # else /* ! HAVE_GSSAPI */ 3634a7c91847Schristos error (1, 0, 3635a7c91847Schristos "INTERNAL ERROR: This client does not support GSSAPI authentication"); 3636a7c91847Schristos # endif /* HAVE_GSSAPI */ 3637a7c91847Schristos } 3638a7c91847Schristos else /* ! do_gssapi */ 3639a7c91847Schristos { 3640a7c91847Schristos # ifdef AUTH_CLIENT_SUPPORT 3641a7c91847Schristos char *begin = NULL; 3642a7c91847Schristos char *password = NULL; 3643a7c91847Schristos char *end = NULL; 3644a7c91847Schristos 3645a7c91847Schristos if (verify_only) 3646a7c91847Schristos { 3647a7c91847Schristos begin = "BEGIN VERIFICATION REQUEST"; 3648a7c91847Schristos end = "END VERIFICATION REQUEST"; 3649a7c91847Schristos } 3650a7c91847Schristos else 3651a7c91847Schristos { 3652a7c91847Schristos begin = "BEGIN AUTH REQUEST"; 3653a7c91847Schristos end = "END AUTH REQUEST"; 3654a7c91847Schristos } 3655a7c91847Schristos 3656a7c91847Schristos /* Get the password, probably from ~/.cvspass. */ 3657a7c91847Schristos password = get_cvs_password (); 3658a7c91847Schristos username = root->username ? root->username : getcaller(); 3659a7c91847Schristos 3660a7c91847Schristos /* Send the empty string by default. This is so anonymous CVS 3661a7c91847Schristos access doesn't require client to have done "cvs login". */ 3662a7c91847Schristos if (!password) 3663a7c91847Schristos { 3664a7c91847Schristos no_passwd = 1; 3665a7c91847Schristos password = scramble (""); 3666a7c91847Schristos } 3667a7c91847Schristos 3668a7c91847Schristos /* Announce that we're starting the authorization protocol. */ 3669a7c91847Schristos send_to_server_via(to_server, begin, 0); 3670a7c91847Schristos send_to_server_via(to_server, "\012", 1); 3671a7c91847Schristos 3672a7c91847Schristos /* Send the data the server needs. */ 3673a7c91847Schristos send_to_server_via(to_server, root->directory, 0); 3674a7c91847Schristos send_to_server_via(to_server, "\012", 1); 3675a7c91847Schristos send_to_server_via(to_server, username, 0); 3676a7c91847Schristos send_to_server_via(to_server, "\012", 1); 3677a7c91847Schristos send_to_server_via(to_server, password, 0); 3678a7c91847Schristos send_to_server_via(to_server, "\012", 1); 3679a7c91847Schristos 3680a7c91847Schristos /* Announce that we're ending the authorization protocol. */ 3681a7c91847Schristos send_to_server_via(to_server, end, 0); 3682a7c91847Schristos send_to_server_via(to_server, "\012", 1); 3683a7c91847Schristos 3684a7c91847Schristos /* Paranoia. */ 3685274254cdSchristos free_cvs_password (password); 3686274254cdSchristos password = NULL; 3687a7c91847Schristos # else /* ! AUTH_CLIENT_SUPPORT */ 3688a7c91847Schristos error (1, 0, "INTERNAL ERROR: This client does not support pserver authentication"); 3689a7c91847Schristos # endif /* AUTH_CLIENT_SUPPORT */ 3690a7c91847Schristos } /* if (do_gssapi) */ 3691a7c91847Schristos 3692a7c91847Schristos { 3693a7c91847Schristos char *read_buf; 3694a7c91847Schristos 3695a7c91847Schristos /* Loop, getting responses from the server. */ 3696a7c91847Schristos while (1) 3697a7c91847Schristos { 3698a7c91847Schristos read_line_via (from_server, to_server, &read_buf); 3699a7c91847Schristos 3700a7c91847Schristos if (!strcmp (read_buf, "I HATE YOU")) 3701a7c91847Schristos { 3702a7c91847Schristos /* Authorization not granted. 3703a7c91847Schristos * 3704a7c91847Schristos * This is a little confusing since we can reach this while 3705a7c91847Schristos * loop in GSSAPI mode, but if GSSAPI authentication failed, 3706a7c91847Schristos * we already jumped to the rejected label (there is no case 3707a7c91847Schristos * where the connect_to_gserver function can return 1 and we 3708a7c91847Schristos * will not receive "I LOVE YOU" from the server, barring 3709a7c91847Schristos * broken connections and garbled messages, of course). The 3710a7c91847Schristos * GSSAPI case is also the case where username can be NULL 3711a7c91847Schristos * since username is initialized in the !gssapi section. 3712a7c91847Schristos * 3713a7c91847Schristos * i.e. This is a pserver specific error message and should be 3714a7c91847Schristos * since GSSAPI doesn't use username. 3715a7c91847Schristos */ 3716a7c91847Schristos error (0, 0, 3717a7c91847Schristos "authorization failed: server %s rejected access to %s for user %s", 3718a7c91847Schristos root->hostname, root->directory, 3719a7c91847Schristos username ? username : "(null)"); 3720a7c91847Schristos 3721a7c91847Schristos /* Output a special error message if authentication was attempted 3722a7c91847Schristos with no password -- the user should be made aware that they may 3723a7c91847Schristos have missed a step. */ 3724a7c91847Schristos if (no_passwd) 3725a7c91847Schristos { 3726a7c91847Schristos error (0, 0, 3727a7c91847Schristos "used empty password; try \"cvs login\" with a real password"); 3728a7c91847Schristos } 3729a7c91847Schristos exit (EXIT_FAILURE); 3730a7c91847Schristos } 3731a7c91847Schristos else if (!strncmp (read_buf, "E ", 2)) 3732a7c91847Schristos { 3733a7c91847Schristos fprintf (stderr, "%s\n", read_buf + 2); 3734a7c91847Schristos 3735a7c91847Schristos /* Continue with the authentication protocol. */ 3736a7c91847Schristos } 3737a7c91847Schristos else if (!strncmp (read_buf, "error ", 6)) 3738a7c91847Schristos { 3739a7c91847Schristos char *p; 3740a7c91847Schristos 3741a7c91847Schristos /* First skip the code. */ 3742a7c91847Schristos p = read_buf + 6; 3743a7c91847Schristos while (*p != ' ' && *p != '\0') 3744a7c91847Schristos ++p; 3745a7c91847Schristos 3746a7c91847Schristos /* Skip the space that follows the code. */ 3747a7c91847Schristos if (*p == ' ') 3748a7c91847Schristos ++p; 3749a7c91847Schristos 3750a7c91847Schristos /* Now output the text. */ 3751a7c91847Schristos fprintf (stderr, "%s\n", p); 3752a7c91847Schristos exit (EXIT_FAILURE); 3753a7c91847Schristos } 3754a7c91847Schristos else if (!strcmp (read_buf, "I LOVE YOU")) 3755a7c91847Schristos { 3756a7c91847Schristos free (read_buf); 3757a7c91847Schristos break; 3758a7c91847Schristos } 3759a7c91847Schristos else 3760a7c91847Schristos { 3761a7c91847Schristos error (1, 0, 3762a7c91847Schristos "unrecognized auth response from %s: %s", 3763a7c91847Schristos root->hostname, read_buf); 3764a7c91847Schristos } 3765a7c91847Schristos free (read_buf); 3766a7c91847Schristos } 3767a7c91847Schristos } 3768a7c91847Schristos } 3769a7c91847Schristos #endif /* defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) */ 3770a7c91847Schristos 3771a7c91847Schristos 3772a7c91847Schristos 3773a7c91847Schristos #if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) 3774a7c91847Schristos /* 3775a7c91847Schristos * Connect to a forked server process. 3776a7c91847Schristos */ 3777a7c91847Schristos static void 3778a7c91847Schristos connect_to_forked_server (cvsroot_t *root, struct buffer **to_server_p, 3779a7c91847Schristos struct buffer **from_server_p) 3780a7c91847Schristos { 3781a7c91847Schristos int tofd, fromfd; 3782a7c91847Schristos int child_pid; 3783a7c91847Schristos 3784a7c91847Schristos /* This is pretty simple. All we need to do is choose the correct 3785a7c91847Schristos cvs binary and call piped_child. */ 3786a7c91847Schristos 3787a7c91847Schristos char *command[3]; 3788a7c91847Schristos 3789a7c91847Schristos command[0] = (root->cvs_server 3790a7c91847Schristos ? root->cvs_server : getenv ("CVS_SERVER")); 3791a7c91847Schristos if (!command[0]) 3792a7c91847Schristos # ifdef SERVER_SUPPORT 3793a7c91847Schristos /* FIXME: 3794a7c91847Schristos * I'm casting out the const below because I know that piped_child, the 3795a7c91847Schristos * only function we pass COMMAND to, accepts COMMAND as a 3796a7c91847Schristos * (char *const *) and won't alter it, and we don't alter it in this 3797a7c91847Schristos * function. This is yucky, there should be a way to declare COMMAND 3798a7c91847Schristos * such that this casting isn't needed, but I don't know how. If I 3799a7c91847Schristos * declare it as (const char *command[]), the compiler complains about 3800a7c91847Schristos * an incompatible arg 1 being passed to piped_child and if I declare 3801a7c91847Schristos * it as (char *const command[3]), then the compiler complains when I 3802a7c91847Schristos * assign values to command[i]. 3803a7c91847Schristos */ 3804a7c91847Schristos command[0] = (char *)program_path; 3805a7c91847Schristos # else /* SERVER_SUPPORT */ 3806a7c91847Schristos { 3807a7c91847Schristos error( 0, 0, "You must set the CVS_SERVER environment variable when" ); 3808a7c91847Schristos error( 0, 0, "using the :fork: access method." ); 3809a7c91847Schristos error( 1, 0, "This CVS was not compiled with server support." ); 3810a7c91847Schristos } 3811a7c91847Schristos # endif /* SERVER_SUPPORT */ 3812a7c91847Schristos 3813a7c91847Schristos command[1] = "server"; 3814a7c91847Schristos command[2] = NULL; 3815a7c91847Schristos 3816a7c91847Schristos TRACE (TRACE_FUNCTION, "Forking server: %s %s", 3817a7c91847Schristos command[0] ? command[0] : "(null)", command[1]); 3818a7c91847Schristos 3819a7c91847Schristos child_pid = piped_child (command, &tofd, &fromfd, false); 3820a7c91847Schristos if (child_pid < 0) 3821a7c91847Schristos error (1, 0, "could not fork server process"); 3822a7c91847Schristos 3823a7c91847Schristos make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p, 3824a7c91847Schristos from_server_p, 0); 3825a7c91847Schristos } 3826a7c91847Schristos #endif /* CLIENT_SUPPORT || SERVER_SUPPORT */ 3827a7c91847Schristos 3828a7c91847Schristos 3829a7c91847Schristos 3830a7c91847Schristos static int 3831a7c91847Schristos send_variable_proc (Node *node, void *closure) 3832a7c91847Schristos { 3833a7c91847Schristos send_to_server ("Set ", 0); 3834a7c91847Schristos send_to_server (node->key, 0); 3835a7c91847Schristos send_to_server ("=", 1); 3836a7c91847Schristos send_to_server (node->data, 0); 3837a7c91847Schristos send_to_server ("\012", 1); 3838a7c91847Schristos return 0; 3839a7c91847Schristos } 3840a7c91847Schristos 3841a7c91847Schristos 3842a7c91847Schristos 3843a7c91847Schristos /* Open up the connection to the server and perform any necessary 3844a7c91847Schristos * authentication. 3845a7c91847Schristos */ 3846a7c91847Schristos void 3847a7c91847Schristos open_connection_to_server (cvsroot_t *root, struct buffer **to_server_p, 3848a7c91847Schristos struct buffer **from_server_p) 3849a7c91847Schristos { 3850a7c91847Schristos /* Note that generally speaking we do *not* fall back to a different 3851a7c91847Schristos way of connecting if the first one does not work. This is slow 3852a7c91847Schristos (*really* slow on a 14.4kbps link); the clean way to have a CVS 3853a7c91847Schristos which supports several ways of connecting is with access methods. */ 3854a7c91847Schristos 3855a7c91847Schristos TRACE (TRACE_FUNCTION, "open_connection_to_server (%s)", root->original); 3856a7c91847Schristos 3857a7c91847Schristos switch (root->method) 3858a7c91847Schristos { 3859a7c91847Schristos case pserver_method: 3860a7c91847Schristos #ifdef AUTH_CLIENT_SUPPORT 3861a7c91847Schristos /* Toss the return value. It will die with an error message if 3862a7c91847Schristos * anything goes wrong anyway. 3863a7c91847Schristos */ 3864a7c91847Schristos connect_to_pserver (root, to_server_p, from_server_p, 0, 0); 3865a7c91847Schristos #else /* AUTH_CLIENT_SUPPORT */ 3866a7c91847Schristos error (0, 0, "CVSROOT is set for a pserver access method but your"); 3867a7c91847Schristos error (1, 0, "CVS executable doesn't support it."); 3868a7c91847Schristos #endif /* AUTH_CLIENT_SUPPORT */ 3869a7c91847Schristos break; 3870a7c91847Schristos 3871a7c91847Schristos case kserver_method: 3872a7c91847Schristos #if HAVE_KERBEROS 3873a7c91847Schristos start_kerberos4_server (root, to_server_p, 3874a7c91847Schristos from_server_p); 3875a7c91847Schristos #else /* !HAVE_KERBEROS */ 3876a7c91847Schristos error (0, 0, 3877a7c91847Schristos "CVSROOT is set for a kerberos access method but your"); 3878a7c91847Schristos error (1, 0, "CVS executable doesn't support it."); 3879a7c91847Schristos #endif /* HAVE_KERBEROS */ 3880a7c91847Schristos break; 3881a7c91847Schristos 3882a7c91847Schristos case gserver_method: 3883a7c91847Schristos #ifdef HAVE_GSSAPI 3884a7c91847Schristos /* GSSAPI authentication is handled by the pserver. */ 3885a7c91847Schristos connect_to_pserver (root, to_server_p, from_server_p, 0, 1); 3886a7c91847Schristos #else /* !HAVE_GSSAPI */ 3887a7c91847Schristos error (0, 0, "CVSROOT is set for a GSSAPI access method but your"); 3888a7c91847Schristos error (1, 0, "CVS executable doesn't support it."); 3889a7c91847Schristos #endif /* HAVE_GSSAPI */ 3890a7c91847Schristos break; 3891a7c91847Schristos 3892a7c91847Schristos case ext_method: 3893a7c91847Schristos #ifdef NO_EXT_METHOD 3894a7c91847Schristos error (0, 0, ":ext: method not supported by this port of CVS"); 3895a7c91847Schristos error (1, 0, "try :server: instead"); 3896a7c91847Schristos #else /* ! NO_EXT_METHOD */ 3897a7c91847Schristos start_rsh_server (root, to_server_p, 3898a7c91847Schristos from_server_p); 3899a7c91847Schristos #endif /* NO_EXT_METHOD */ 3900a7c91847Schristos break; 3901a7c91847Schristos 3902a7c91847Schristos case server_method: 3903a7c91847Schristos #ifdef START_SERVER 3904a7c91847Schristos { 3905a7c91847Schristos int tofd, fromfd; 3906a7c91847Schristos START_SERVER (&tofd, &fromfd, getcaller (), 3907a7c91847Schristos root->username, 3908a7c91847Schristos root->hostname, 3909a7c91847Schristos root->directory); 3910a7c91847Schristos # ifdef START_SERVER_RETURNS_SOCKET 3911a7c91847Schristos make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p, 3912a7c91847Schristos from_server_p, 1); 3913a7c91847Schristos # else /* ! START_SERVER_RETURNS_SOCKET */ 3914a7c91847Schristos make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p, 3915a7c91847Schristos from_server_p, 0); 3916a7c91847Schristos # endif /* START_SERVER_RETURNS_SOCKET */ 3917a7c91847Schristos } 3918a7c91847Schristos #else /* ! START_SERVER */ 3919a7c91847Schristos /* FIXME: It should be possible to implement this portably, 3920a7c91847Schristos like pserver, which would get rid of the duplicated code 3921a7c91847Schristos in {vms,windows-NT,...}/startserver.c. */ 3922a7c91847Schristos error (1, 0, 3923a7c91847Schristos "the :server: access method is not supported by this port of CVS"); 3924a7c91847Schristos #endif /* START_SERVER */ 3925a7c91847Schristos break; 3926a7c91847Schristos 3927a7c91847Schristos case fork_method: 3928a7c91847Schristos connect_to_forked_server (root, to_server_p, from_server_p); 3929a7c91847Schristos break; 3930a7c91847Schristos 3931a7c91847Schristos default: 3932a7c91847Schristos error (1, 0, 3933a7c91847Schristos "(start_server internal error): unknown access method"); 3934a7c91847Schristos break; 3935a7c91847Schristos } 3936a7c91847Schristos 3937a7c91847Schristos /* "Hi, I'm Darlene and I'll be your server tonight..." */ 3938a7c91847Schristos server_started = 1; 3939a7c91847Schristos } 3940a7c91847Schristos 3941a7c91847Schristos 3942a7c91847Schristos 3943a7c91847Schristos /* Contact the server. */ 3944a7c91847Schristos void 3945a7c91847Schristos start_server (void) 3946a7c91847Schristos { 3947a7c91847Schristos bool rootless; 3948a7c91847Schristos int status; 3949a7c91847Schristos bool have_global; 3950a7c91847Schristos 3951a7c91847Schristos do 3952a7c91847Schristos { 3953a7c91847Schristos /* Clear our static variables for this invocation. */ 3954a7c91847Schristos if (toplevel_repos) 3955a7c91847Schristos free (toplevel_repos); 3956a7c91847Schristos toplevel_repos = NULL; 3957a7c91847Schristos 3958a7c91847Schristos open_connection_to_server (current_parsed_root, &global_to_server, 3959a7c91847Schristos &global_from_server); 3960a7c91847Schristos setup_logfiles ("CVS_CLIENT_LOG", &global_to_server, 3961a7c91847Schristos &global_from_server); 3962a7c91847Schristos 3963a7c91847Schristos /* Clear static variables. */ 3964a7c91847Schristos if (toplevel_repos) 3965a7c91847Schristos { 3966a7c91847Schristos free (toplevel_repos); 3967a7c91847Schristos toplevel_repos = NULL; 3968a7c91847Schristos } 3969a7c91847Schristos if (last_repos) 3970a7c91847Schristos { 3971a7c91847Schristos free (last_repos); 3972a7c91847Schristos last_repos = NULL; 3973a7c91847Schristos } 3974a7c91847Schristos if (last_update_dir) 3975a7c91847Schristos { 3976a7c91847Schristos free (last_update_dir); 3977a7c91847Schristos last_update_dir = NULL; 3978a7c91847Schristos } 3979a7c91847Schristos stored_checksum_valid = 0; 3980a7c91847Schristos if (stored_mode) 3981a7c91847Schristos { 3982a7c91847Schristos free (stored_mode); 3983a7c91847Schristos stored_mode = NULL; 3984a7c91847Schristos } 3985a7c91847Schristos 3986a7c91847Schristos rootless = !strcmp (cvs_cmd_name, "init"); 3987a7c91847Schristos if (!rootless) 3988a7c91847Schristos { 3989a7c91847Schristos send_to_server ("Root ", 0); 3990a7c91847Schristos send_to_server (current_parsed_root->directory, 0); 3991a7c91847Schristos send_to_server ("\012", 1); 3992a7c91847Schristos } 3993a7c91847Schristos 3994a7c91847Schristos { 3995a7c91847Schristos struct response *rs; 3996a7c91847Schristos bool suppress_redirect = !current_parsed_root->redirect; 3997a7c91847Schristos 3998a7c91847Schristos send_to_server ("Valid-responses", 0); 3999a7c91847Schristos 4000a7c91847Schristos for (rs = responses; rs->name; ++rs) 4001a7c91847Schristos { 4002a7c91847Schristos if (suppress_redirect && !strcmp (rs->name, "Redirect")) 4003a7c91847Schristos continue; 4004a7c91847Schristos 4005a7c91847Schristos send_to_server (" ", 0); 4006a7c91847Schristos send_to_server (rs->name, 0); 4007a7c91847Schristos } 4008a7c91847Schristos send_to_server ("\012", 1); 4009a7c91847Schristos } 4010a7c91847Schristos send_to_server ("valid-requests\012", 0); 4011a7c91847Schristos 4012a7c91847Schristos if (get_server_responses ()) 4013a7c91847Schristos exit (EXIT_FAILURE); 4014a7c91847Schristos 4015a7c91847Schristos have_global = supported_request ("Global_option"); 4016a7c91847Schristos 4017a7c91847Schristos /* Encryption needs to come before compression. Good encryption can 4018a7c91847Schristos * render compression useless in the other direction. 4019a7c91847Schristos */ 4020a7c91847Schristos if (cvsencrypt && !rootless) 4021a7c91847Schristos { 4022a7c91847Schristos #ifdef ENCRYPTION 4023a7c91847Schristos /* Turn on encryption before turning on compression. We do 4024a7c91847Schristos * not want to try to compress the encrypted stream. Instead, 4025a7c91847Schristos * we want to encrypt the compressed stream. If we can't turn 4026a7c91847Schristos * on encryption, bomb out; don't let the user think the data 4027a7c91847Schristos * is being encrypted when it is not. 4028a7c91847Schristos */ 4029a7c91847Schristos # ifdef HAVE_KERBEROS 4030a7c91847Schristos if (current_parsed_root->method == kserver_method) 4031a7c91847Schristos { 4032a7c91847Schristos if (!supported_request ("Kerberos-encrypt")) 4033a7c91847Schristos error (1, 0, "This server does not support encryption"); 4034a7c91847Schristos send_to_server ("Kerberos-encrypt\012", 0); 4035a7c91847Schristos initialize_kerberos4_encryption_buffers (&global_to_server, 4036a7c91847Schristos &global_from_server); 4037a7c91847Schristos } 4038a7c91847Schristos else 4039a7c91847Schristos # endif /* HAVE_KERBEROS */ 4040a7c91847Schristos # ifdef HAVE_GSSAPI 4041a7c91847Schristos if (current_parsed_root->method == gserver_method) 4042a7c91847Schristos { 4043a7c91847Schristos if (!supported_request ("Gssapi-encrypt")) 4044a7c91847Schristos error (1, 0, "This server does not support encryption"); 4045a7c91847Schristos send_to_server ("Gssapi-encrypt\012", 0); 4046a7c91847Schristos initialize_gssapi_buffers (&global_to_server, 4047a7c91847Schristos &global_from_server); 4048a7c91847Schristos cvs_gssapi_encrypt = 1; 4049a7c91847Schristos } 4050a7c91847Schristos else 4051a7c91847Schristos # endif /* HAVE_GSSAPI */ 4052a7c91847Schristos error (1, 0, 4053a7c91847Schristos "Encryption is only supported when using GSSAPI or Kerberos"); 4054a7c91847Schristos #else /* ! ENCRYPTION */ 4055a7c91847Schristos error (1, 0, "This client does not support encryption"); 4056a7c91847Schristos #endif /* ! ENCRYPTION */ 4057a7c91847Schristos } 4058a7c91847Schristos 4059274254cdSchristos if (nolock && !noexec) 4060274254cdSchristos { 4061274254cdSchristos if (have_global) 4062274254cdSchristos { 4063274254cdSchristos send_to_server ("Global_option -u\012", 0); 4064274254cdSchristos } 4065274254cdSchristos else 4066274254cdSchristos error (1, 0, 4067274254cdSchristos "This server does not support the global -u option."); 4068274254cdSchristos } 4069a7c91847Schristos /* Send this before compression to enable supression of the 4070a7c91847Schristos * "Forcing compression level Z" messages. 4071a7c91847Schristos */ 4072a7c91847Schristos if (quiet) 4073a7c91847Schristos { 4074a7c91847Schristos if (have_global) 4075a7c91847Schristos { 4076a7c91847Schristos send_to_server ("Global_option -q\012", 0); 4077a7c91847Schristos } 4078a7c91847Schristos else 4079a7c91847Schristos error (1, 0, 4080a7c91847Schristos "This server does not support the global -q option."); 4081a7c91847Schristos } 4082a7c91847Schristos if (really_quiet) 4083a7c91847Schristos { 4084a7c91847Schristos if (have_global) 4085a7c91847Schristos { 4086a7c91847Schristos send_to_server ("Global_option -Q\012", 0); 4087a7c91847Schristos } 4088a7c91847Schristos else 4089a7c91847Schristos error (1, 0, 4090a7c91847Schristos "This server does not support the global -Q option."); 4091a7c91847Schristos } 4092a7c91847Schristos 4093a7c91847Schristos /* Compression needs to come before any of the rooted requests to 4094a7c91847Schristos * work with compression limits. 4095a7c91847Schristos */ 4096a7c91847Schristos if (!rootless && (gzip_level || force_gzip)) 4097a7c91847Schristos { 4098a7c91847Schristos if (supported_request ("Gzip-stream")) 4099a7c91847Schristos { 4100a7c91847Schristos char *gzip_level_buf = Xasprintf ("%d", gzip_level); 4101a7c91847Schristos send_to_server ("Gzip-stream ", 0); 4102a7c91847Schristos send_to_server (gzip_level_buf, 0); 4103a7c91847Schristos free (gzip_level_buf); 4104a7c91847Schristos send_to_server ("\012", 1); 4105a7c91847Schristos 4106a7c91847Schristos /* All further communication with the server will be 4107a7c91847Schristos compressed. */ 4108a7c91847Schristos 4109a7c91847Schristos global_to_server = 4110a7c91847Schristos compress_buffer_initialize (global_to_server, 0, 4111a7c91847Schristos gzip_level, NULL); 4112a7c91847Schristos global_from_server = 4113a7c91847Schristos compress_buffer_initialize (global_from_server, 1, 4114a7c91847Schristos gzip_level, NULL); 4115a7c91847Schristos } 4116a7c91847Schristos #ifndef NO_CLIENT_GZIP_PROCESS 4117a7c91847Schristos else if (supported_request ("gzip-file-contents")) 4118a7c91847Schristos { 4119a7c91847Schristos char *gzip_level_buf = Xasprintf ("%d", gzip_level); 4120a7c91847Schristos send_to_server ("gzip-file-contents ", 0); 4121a7c91847Schristos send_to_server (gzip_level_buf, 0); 4122a7c91847Schristos free (gzip_level_buf); 4123a7c91847Schristos send_to_server ("\012", 1); 4124a7c91847Schristos 4125a7c91847Schristos file_gzip_level = gzip_level; 4126a7c91847Schristos } 4127a7c91847Schristos #endif 4128a7c91847Schristos else 4129a7c91847Schristos { 4130a7c91847Schristos fprintf (stderr, "server doesn't support gzip-file-contents\n"); 4131a7c91847Schristos /* Setting gzip_level to 0 prevents us from giving the 4132a7c91847Schristos error twice if update has to contact the server again 4133a7c91847Schristos to fetch unpatchable files. */ 4134a7c91847Schristos gzip_level = 0; 4135a7c91847Schristos } 4136a7c91847Schristos } 4137a7c91847Schristos 4138a7c91847Schristos if (client_referrer && supported_request ("Referrer")) 4139a7c91847Schristos { 4140a7c91847Schristos send_to_server ("Referrer ", 0); 4141a7c91847Schristos send_to_server (client_referrer->original, 0); 4142a7c91847Schristos send_to_server ("\012", 0); 4143a7c91847Schristos } 4144a7c91847Schristos 4145a7c91847Schristos /* FIXME: I think we should still be sending this for init. */ 4146a7c91847Schristos if (!rootless && supported_request ("Command-prep")) 4147a7c91847Schristos { 4148a7c91847Schristos send_to_server ("Command-prep ", 0); 4149a7c91847Schristos send_to_server (cvs_cmd_name, 0); 4150a7c91847Schristos send_to_server ("\012", 0); 4151a7c91847Schristos status = get_server_responses (); 4152a7c91847Schristos if (status == 1) exit (EXIT_FAILURE); 4153a7c91847Schristos if (status == 2) close_connection_to_server (&global_to_server, 4154a7c91847Schristos &global_from_server); 4155a7c91847Schristos } 4156a7c91847Schristos else status = 0; 4157a7c91847Schristos } while (status == 2); 4158a7c91847Schristos 4159a7c91847Schristos 4160a7c91847Schristos /* 4161a7c91847Schristos * Now handle global options. 4162a7c91847Schristos * 4163a7c91847Schristos * -H, -f, -d, -e should be handled OK locally. 4164a7c91847Schristos * 4165a7c91847Schristos * -b we ignore (treating it as a server installation issue). 4166a7c91847Schristos * FIXME: should be an error message. 4167a7c91847Schristos * 4168a7c91847Schristos * -v we print local version info; FIXME: Add a protocol request to get 4169a7c91847Schristos * the version from the server so we can print that too. 4170a7c91847Schristos * 4171a7c91847Schristos * -l -t -r -w -q -n and -Q need to go to the server. 4172a7c91847Schristos */ 4173a7c91847Schristos if (noexec) 4174a7c91847Schristos { 4175a7c91847Schristos if (have_global) 4176a7c91847Schristos { 4177a7c91847Schristos send_to_server ("Global_option -n\012", 0); 4178a7c91847Schristos } 4179a7c91847Schristos else 4180a7c91847Schristos error (1, 0, 4181a7c91847Schristos "This server does not support the global -n option."); 4182a7c91847Schristos } 4183a7c91847Schristos if (!cvswrite) 4184a7c91847Schristos { 4185a7c91847Schristos if (have_global) 4186a7c91847Schristos { 4187a7c91847Schristos send_to_server ("Global_option -r\012", 0); 4188a7c91847Schristos } 4189a7c91847Schristos else 4190a7c91847Schristos error (1, 0, 4191a7c91847Schristos "This server does not support the global -r option."); 4192a7c91847Schristos } 4193a7c91847Schristos if (trace) 4194a7c91847Schristos { 4195a7c91847Schristos if (have_global) 4196a7c91847Schristos { 4197a7c91847Schristos int count = trace; 4198a7c91847Schristos while (count--) send_to_server ("Global_option -t\012", 0); 4199a7c91847Schristos } 4200a7c91847Schristos else 4201a7c91847Schristos error (1, 0, 4202a7c91847Schristos "This server does not support the global -t option."); 4203a7c91847Schristos } 4204a7c91847Schristos 4205a7c91847Schristos /* Find out about server-side cvswrappers. An extra network 4206a7c91847Schristos turnaround for cvs import seems to be unavoidable, unless we 4207a7c91847Schristos want to add some kind of client-side place to configure which 4208a7c91847Schristos filenames imply binary. For cvs add, we could avoid the 4209a7c91847Schristos problem by keeping a copy of the wrappers in CVSADM (the main 4210a7c91847Schristos reason to bother would be so we could make add work without 4211a7c91847Schristos contacting the server, I suspect). */ 4212a7c91847Schristos 4213a7c91847Schristos if (!strcmp (cvs_cmd_name, "import") || !strcmp (cvs_cmd_name, "add")) 4214a7c91847Schristos { 4215a7c91847Schristos if (supported_request ("wrapper-sendme-rcsOptions")) 4216a7c91847Schristos { 4217a7c91847Schristos int err; 4218a7c91847Schristos send_to_server ("wrapper-sendme-rcsOptions\012", 0); 4219a7c91847Schristos err = get_server_responses (); 4220a7c91847Schristos if (err != 0) 4221a7c91847Schristos error (err, 0, "error reading from server"); 4222a7c91847Schristos } 4223a7c91847Schristos } 4224a7c91847Schristos 4225a7c91847Schristos if (cvsauthenticate && ! cvsencrypt && !rootless) 4226a7c91847Schristos { 4227a7c91847Schristos /* Turn on authentication after turning on compression, so 4228a7c91847Schristos that we can compress the authentication information. We 4229a7c91847Schristos assume that encrypted data is always authenticated--the 4230a7c91847Schristos ability to decrypt the data stream is itself a form of 4231a7c91847Schristos authentication. */ 4232a7c91847Schristos #ifdef HAVE_GSSAPI 4233a7c91847Schristos if (current_parsed_root->method == gserver_method) 4234a7c91847Schristos { 4235a7c91847Schristos if (! supported_request ("Gssapi-authenticate")) 4236a7c91847Schristos error (1, 0, 4237a7c91847Schristos "This server does not support stream authentication"); 4238a7c91847Schristos send_to_server ("Gssapi-authenticate\012", 0); 4239a7c91847Schristos initialize_gssapi_buffers(&global_to_server, &global_from_server); 4240a7c91847Schristos 4241a7c91847Schristos } 4242a7c91847Schristos else 4243a7c91847Schristos error (1, 0, "Stream authentication is only supported when using GSSAPI"); 4244a7c91847Schristos #else /* ! HAVE_GSSAPI */ 4245a7c91847Schristos error (1, 0, "This client does not support stream authentication"); 4246a7c91847Schristos #endif /* ! HAVE_GSSAPI */ 4247a7c91847Schristos } 4248a7c91847Schristos 4249a7c91847Schristos /* If "Set" is not supported, just silently fail to send the variables. 4250a7c91847Schristos Users with an old server should get a useful error message when it 4251a7c91847Schristos fails to recognize the ${=foo} syntax. This way if someone uses 4252a7c91847Schristos several servers, some of which are new and some old, they can still 4253a7c91847Schristos set user variables in their .cvsrc without trouble. */ 4254a7c91847Schristos if (supported_request ("Set")) 4255a7c91847Schristos walklist (variable_list, send_variable_proc, NULL); 4256a7c91847Schristos } 4257a7c91847Schristos 4258a7c91847Schristos 4259a7c91847Schristos 4260a7c91847Schristos /* Send an argument STRING. */ 4261a7c91847Schristos void 4262a7c91847Schristos send_arg (const char *string) 4263a7c91847Schristos { 4264a7c91847Schristos const char *p = string; 4265a7c91847Schristos 4266a7c91847Schristos send_to_server ("Argument ", 0); 4267a7c91847Schristos 4268a7c91847Schristos while (*p) 4269a7c91847Schristos { 4270a7c91847Schristos if (*p == '\n') 4271a7c91847Schristos send_to_server ("\012Argumentx ", 0); 4272a7c91847Schristos else 4273a7c91847Schristos send_to_server (p, 1); 4274a7c91847Schristos ++p; 4275a7c91847Schristos } 4276a7c91847Schristos send_to_server ("\012", 1); 4277a7c91847Schristos } 4278a7c91847Schristos 4279a7c91847Schristos 4280a7c91847Schristos 4281a7c91847Schristos /* VERS->OPTIONS specifies whether the file is binary or not. NOTE: BEFORE 4282a7c91847Schristos using any other fields of the struct vers, we would need to fix 4283a7c91847Schristos client_process_import_file to set them up. */ 4284a7c91847Schristos static void 4285a7c91847Schristos send_modified (const char *file, const char *short_pathname, Vers_TS *vers) 4286a7c91847Schristos { 4287a7c91847Schristos /* File was modified, send it. */ 4288a7c91847Schristos struct stat sb; 4289a7c91847Schristos int fd; 4290a7c91847Schristos unsigned char *buf; 4291a7c91847Schristos char *mode_string; 4292a7c91847Schristos size_t bufsize; 4293a7c91847Schristos int bin; 4294a7c91847Schristos 4295a7c91847Schristos TRACE (TRACE_FUNCTION, "Sending file `%s' to server", file); 4296a7c91847Schristos 4297a7c91847Schristos /* Don't think we can assume fstat exists. */ 4298a7c91847Schristos if (stat (file, &sb) < 0) 4299a7c91847Schristos error (1, errno, "reading %s", short_pathname); 4300a7c91847Schristos 4301a7c91847Schristos mode_string = mode_to_string (sb.st_mode); 4302a7c91847Schristos 4303a7c91847Schristos /* Beware: on systems using CRLF line termination conventions, 4304a7c91847Schristos the read and write functions will convert CRLF to LF, so the 4305a7c91847Schristos number of characters read is not the same as sb.st_size. Text 4306a7c91847Schristos files should always be transmitted using the LF convention, so 4307a7c91847Schristos we don't want to disable this conversion. */ 4308a7c91847Schristos bufsize = sb.st_size; 4309a7c91847Schristos buf = xmalloc (bufsize); 4310a7c91847Schristos 4311a7c91847Schristos /* Is the file marked as containing binary data by the "-kb" flag? 4312a7c91847Schristos If so, make sure to open it in binary mode: */ 4313a7c91847Schristos 4314a7c91847Schristos if (vers && vers->options) 4315a7c91847Schristos bin = !strcmp (vers->options, "-kb"); 4316a7c91847Schristos else 4317a7c91847Schristos bin = 0; 4318a7c91847Schristos 4319a7c91847Schristos #ifdef BROKEN_READWRITE_CONVERSION 4320a7c91847Schristos if (!bin) 4321a7c91847Schristos { 4322a7c91847Schristos /* If only stdio, not open/write/etc., do text/binary 4323a7c91847Schristos conversion, use convert_file which can compensate 4324a7c91847Schristos (FIXME: we could just use stdio instead which would 4325a7c91847Schristos avoid the whole problem). */ 4326a7c91847Schristos char *tfile = Xasprintf ("%s.CVSBFCTMP", file); 4327a7c91847Schristos convert_file (file, O_RDONLY, 4328a7c91847Schristos tfile, O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY); 4329a7c91847Schristos fd = CVS_OPEN (tfile, O_RDONLY | OPEN_BINARY); 4330a7c91847Schristos if (fd < 0) 4331a7c91847Schristos error (1, errno, "reading %s", short_pathname); 4332a7c91847Schristos free (tfile); 4333a7c91847Schristos } 4334a7c91847Schristos else 4335a7c91847Schristos fd = CVS_OPEN (file, O_RDONLY | OPEN_BINARY); 4336a7c91847Schristos #else 4337a7c91847Schristos fd = CVS_OPEN (file, O_RDONLY | (bin ? OPEN_BINARY : 0)); 4338a7c91847Schristos #endif 4339a7c91847Schristos 4340a7c91847Schristos if (fd < 0) 4341a7c91847Schristos error (1, errno, "reading %s", short_pathname); 4342a7c91847Schristos 4343a7c91847Schristos if (file_gzip_level && sb.st_size > 100) 4344a7c91847Schristos { 4345a7c91847Schristos size_t newsize = 0; 4346a7c91847Schristos 4347a7c91847Schristos if (read_and_gzip (fd, short_pathname, &buf, 4348a7c91847Schristos &bufsize, &newsize, 4349a7c91847Schristos file_gzip_level)) 4350a7c91847Schristos error (1, 0, "aborting due to compression error"); 4351a7c91847Schristos 4352a7c91847Schristos if (close (fd) < 0) 4353a7c91847Schristos error (0, errno, "warning: can't close %s", short_pathname); 4354a7c91847Schristos 4355a7c91847Schristos { 4356a7c91847Schristos char tmp[80]; 4357a7c91847Schristos 4358a7c91847Schristos send_to_server ("Modified ", 0); 4359a7c91847Schristos send_to_server (file, 0); 4360a7c91847Schristos send_to_server ("\012", 1); 4361a7c91847Schristos send_to_server (mode_string, 0); 4362a7c91847Schristos send_to_server ("\012z", 2); 4363a7c91847Schristos sprintf (tmp, "%lu\n", (unsigned long) newsize); 4364a7c91847Schristos send_to_server (tmp, 0); 4365a7c91847Schristos 4366a7c91847Schristos send_to_server (buf, newsize); 4367a7c91847Schristos } 4368a7c91847Schristos } 4369a7c91847Schristos else 4370a7c91847Schristos { 4371a7c91847Schristos int newsize; 4372a7c91847Schristos 4373a7c91847Schristos { 4374a7c91847Schristos unsigned char *bufp = buf; 4375a7c91847Schristos int len; 4376a7c91847Schristos 4377a7c91847Schristos /* FIXME: This is gross. It assumes that we might read 4378a7c91847Schristos less than st_size bytes (true on NT), but not more. 4379a7c91847Schristos Instead of this we should just be reading a block of 4380a7c91847Schristos data (e.g. 8192 bytes), writing it to the network, and 4381a7c91847Schristos so on until EOF. */ 4382a7c91847Schristos while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0) 4383a7c91847Schristos bufp += len; 4384a7c91847Schristos 4385a7c91847Schristos if (len < 0) 4386a7c91847Schristos error (1, errno, "reading %s", short_pathname); 4387a7c91847Schristos 4388a7c91847Schristos newsize = bufp - buf; 4389a7c91847Schristos } 4390a7c91847Schristos if (close (fd) < 0) 4391a7c91847Schristos error (0, errno, "warning: can't close %s", short_pathname); 4392a7c91847Schristos 4393a7c91847Schristos { 4394a7c91847Schristos char tmp[80]; 4395a7c91847Schristos 4396a7c91847Schristos send_to_server ("Modified ", 0); 4397a7c91847Schristos send_to_server (file, 0); 4398a7c91847Schristos send_to_server ("\012", 1); 4399a7c91847Schristos send_to_server (mode_string, 0); 4400a7c91847Schristos send_to_server ("\012", 1); 4401a7c91847Schristos sprintf (tmp, "%lu\012", (unsigned long) newsize); 4402a7c91847Schristos send_to_server (tmp, 0); 4403a7c91847Schristos } 4404a7c91847Schristos #ifdef BROKEN_READWRITE_CONVERSION 4405a7c91847Schristos if (!bin) 4406a7c91847Schristos { 4407a7c91847Schristos char *tfile = Xasprintf ("%s.CVSBFCTMP", file); 4408a7c91847Schristos if (CVS_UNLINK (tfile) < 0) 4409a7c91847Schristos error (0, errno, "warning: can't remove temp file %s", tfile); 4410a7c91847Schristos free (tfile); 4411a7c91847Schristos } 4412a7c91847Schristos #endif 4413a7c91847Schristos 4414a7c91847Schristos /* 4415a7c91847Schristos * Note that this only ends with a newline if the file ended with 4416a7c91847Schristos * one. 4417a7c91847Schristos */ 4418a7c91847Schristos if (newsize > 0) 4419a7c91847Schristos send_to_server (buf, newsize); 4420a7c91847Schristos } 4421a7c91847Schristos free (buf); 4422a7c91847Schristos free (mode_string); 4423a7c91847Schristos } 4424a7c91847Schristos 4425a7c91847Schristos 4426a7c91847Schristos 4427a7c91847Schristos /* The address of an instance of this structure is passed to 4428a7c91847Schristos send_fileproc, send_filesdoneproc, and send_direntproc, as the 4429a7c91847Schristos callerdat parameter. */ 4430a7c91847Schristos struct send_data 4431a7c91847Schristos { 4432a7c91847Schristos /* Each of the following flags are zero for clear or nonzero for set. */ 4433a7c91847Schristos int build_dirs; 4434a7c91847Schristos int force; 4435a7c91847Schristos int no_contents; 4436a7c91847Schristos int backup_modified; 4437a7c91847Schristos }; 4438a7c91847Schristos 4439a7c91847Schristos /* Deal with one file. */ 4440a7c91847Schristos static int 4441a7c91847Schristos send_fileproc (void *callerdat, struct file_info *finfo) 4442a7c91847Schristos { 4443a7c91847Schristos struct send_data *args = callerdat; 4444a7c91847Schristos Vers_TS *vers; 4445a7c91847Schristos struct file_info xfinfo; 4446a7c91847Schristos /* File name to actually use. Might differ in case from 4447a7c91847Schristos finfo->file. */ 4448a7c91847Schristos const char *filename; 4449a7c91847Schristos 4450a7c91847Schristos send_a_repository ("", finfo->repository, finfo->update_dir); 4451a7c91847Schristos 4452a7c91847Schristos xfinfo = *finfo; 4453a7c91847Schristos xfinfo.repository = NULL; 4454a7c91847Schristos xfinfo.rcs = NULL; 4455a7c91847Schristos vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0); 4456a7c91847Schristos 4457a7c91847Schristos if (vers->entdata) 4458a7c91847Schristos filename = vers->entdata->user; 4459a7c91847Schristos else 4460a7c91847Schristos filename = finfo->file; 4461a7c91847Schristos 4462a7c91847Schristos if (vers->vn_user) 4463a7c91847Schristos { 4464a7c91847Schristos /* The Entries request. */ 4465a7c91847Schristos send_to_server ("Entry /", 0); 4466a7c91847Schristos send_to_server (filename, 0); 4467a7c91847Schristos send_to_server ("/", 0); 4468a7c91847Schristos send_to_server (vers->vn_user, 0); 4469a7c91847Schristos send_to_server ("/", 0); 4470a7c91847Schristos if (vers->ts_conflict) 4471a7c91847Schristos { 4472a7c91847Schristos if (vers->ts_user && !strcmp (vers->ts_conflict, vers->ts_user)) 4473a7c91847Schristos send_to_server ("+=", 0); 4474a7c91847Schristos else 4475a7c91847Schristos send_to_server ("+modified", 0); 4476a7c91847Schristos } 4477a7c91847Schristos send_to_server ("/", 0); 4478a7c91847Schristos send_to_server (vers->entdata ? vers->entdata->options : vers->options, 4479a7c91847Schristos 0); 4480a7c91847Schristos send_to_server ("/", 0); 4481a7c91847Schristos if (vers->entdata && vers->entdata->tag) 4482a7c91847Schristos { 4483a7c91847Schristos send_to_server ("T", 0); 4484a7c91847Schristos send_to_server (vers->entdata->tag, 0); 4485a7c91847Schristos } 4486a7c91847Schristos else if (vers->entdata && vers->entdata->date) 4487a7c91847Schristos { 4488a7c91847Schristos send_to_server ("D", 0); 4489a7c91847Schristos send_to_server (vers->entdata->date, 0); 4490a7c91847Schristos } 4491a7c91847Schristos send_to_server ("\012", 1); 4492a7c91847Schristos } 4493a7c91847Schristos else 4494a7c91847Schristos { 4495a7c91847Schristos /* It seems a little silly to re-read this on each file, but 4496a7c91847Schristos send_dirent_proc doesn't get called if filenames are specified 4497a7c91847Schristos explicitly on the command line. */ 4498a7c91847Schristos wrap_add_file (CVSDOTWRAPPER, 1); 4499a7c91847Schristos 4500a7c91847Schristos if (wrap_name_has (filename, WRAP_RCSOPTION)) 4501a7c91847Schristos { 4502a7c91847Schristos /* No "Entry", but the wrappers did give us a kopt so we better 4503a7c91847Schristos send it with "Kopt". As far as I know this only happens 4504a7c91847Schristos for "cvs add". Question: is there any reason why checking 4505a7c91847Schristos for options from wrappers isn't done in Version_TS? 4506a7c91847Schristos 4507a7c91847Schristos Note: it might have been better to just remember all the 4508a7c91847Schristos kopts on the client side, rather than send them to the server, 4509a7c91847Schristos and have it send us back the same kopts. But that seemed like 4510a7c91847Schristos a bigger change than I had in mind making now. */ 4511a7c91847Schristos 4512a7c91847Schristos if (supported_request ("Kopt")) 4513a7c91847Schristos { 4514a7c91847Schristos char *opt; 4515a7c91847Schristos 4516a7c91847Schristos send_to_server ("Kopt ", 0); 4517a7c91847Schristos opt = wrap_rcsoption (filename, 1); 4518a7c91847Schristos send_to_server (opt, 0); 4519a7c91847Schristos send_to_server ("\012", 1); 4520a7c91847Schristos free (opt); 4521a7c91847Schristos } 4522a7c91847Schristos else 4523a7c91847Schristos error (0, 0, "\ 4524a7c91847Schristos warning: ignoring -k options due to server limitations"); 4525a7c91847Schristos } 4526a7c91847Schristos } 4527a7c91847Schristos 4528a7c91847Schristos if (!vers->ts_user) 4529a7c91847Schristos { 4530a7c91847Schristos /* 4531a7c91847Schristos * Do we want to print "file was lost" like normal CVS? 4532a7c91847Schristos * Would it always be appropriate? 4533a7c91847Schristos */ 4534a7c91847Schristos /* File no longer exists. Don't do anything, missing files 4535a7c91847Schristos just happen. */ 4536a7c91847Schristos } 4537a7c91847Schristos else if (!vers->ts_rcs || args->force 4538a7c91847Schristos || strcmp (vers->ts_conflict 4539a7c91847Schristos ? vers->ts_conflict : vers->ts_rcs, vers->ts_user) 4540a7c91847Schristos || (vers->ts_conflict && !strcmp (cvs_cmd_name, "diff"))) 4541a7c91847Schristos { 4542a7c91847Schristos if (args->no_contents 4543a7c91847Schristos && supported_request ("Is-modified")) 4544a7c91847Schristos { 4545a7c91847Schristos send_to_server ("Is-modified ", 0); 4546a7c91847Schristos send_to_server (filename, 0); 4547a7c91847Schristos send_to_server ("\012", 1); 4548a7c91847Schristos } 4549a7c91847Schristos else 4550a7c91847Schristos send_modified (filename, finfo->fullname, vers); 4551a7c91847Schristos 4552a7c91847Schristos if (args->backup_modified) 4553a7c91847Schristos { 4554a7c91847Schristos char *bakname; 4555a7c91847Schristos bakname = backup_file (filename, vers->vn_user); 4556a7c91847Schristos /* This behavior is sufficiently unexpected to 4557a7c91847Schristos justify overinformativeness, I think. */ 4558a7c91847Schristos if (! really_quiet) 4559a7c91847Schristos printf ("(Locally modified %s moved to %s)\n", 4560a7c91847Schristos filename, bakname); 4561a7c91847Schristos free (bakname); 4562a7c91847Schristos } 4563a7c91847Schristos } 4564a7c91847Schristos else 4565a7c91847Schristos { 4566a7c91847Schristos send_to_server ("Unchanged ", 0); 4567a7c91847Schristos send_to_server (filename, 0); 4568a7c91847Schristos send_to_server ("\012", 1); 4569a7c91847Schristos } 4570a7c91847Schristos 4571a7c91847Schristos /* if this directory has an ignore list, add this file to it */ 4572a7c91847Schristos if (ignlist) 4573a7c91847Schristos { 4574a7c91847Schristos Node *p; 4575a7c91847Schristos 4576a7c91847Schristos p = getnode (); 4577a7c91847Schristos p->type = FILES; 4578a7c91847Schristos p->key = xstrdup (finfo->file); 4579a7c91847Schristos (void) addnode (ignlist, p); 4580a7c91847Schristos } 4581a7c91847Schristos 4582a7c91847Schristos freevers_ts (&vers); 4583a7c91847Schristos return 0; 4584a7c91847Schristos } 4585a7c91847Schristos 4586a7c91847Schristos 4587a7c91847Schristos 4588a7c91847Schristos static void 4589a7c91847Schristos send_ignproc (const char *file, const char *dir) 4590a7c91847Schristos { 4591a7c91847Schristos if (ign_inhibit_server || !supported_request ("Questionable")) 4592a7c91847Schristos { 4593a7c91847Schristos if (dir[0] != '\0') 4594a7c91847Schristos (void) printf ("? %s/%s\n", dir, file); 4595a7c91847Schristos else 4596a7c91847Schristos (void) printf ("? %s\n", file); 4597a7c91847Schristos } 4598a7c91847Schristos else 4599a7c91847Schristos { 4600a7c91847Schristos send_to_server ("Questionable ", 0); 4601a7c91847Schristos send_to_server (file, 0); 4602a7c91847Schristos send_to_server ("\012", 1); 4603a7c91847Schristos } 4604a7c91847Schristos } 4605a7c91847Schristos 4606a7c91847Schristos 4607a7c91847Schristos 4608a7c91847Schristos static int 4609a7c91847Schristos send_filesdoneproc (void *callerdat, int err, const char *repository, 4610a7c91847Schristos const char *update_dir, List *entries) 4611a7c91847Schristos { 4612a7c91847Schristos /* if this directory has an ignore list, process it then free it */ 4613a7c91847Schristos if (ignlist) 4614a7c91847Schristos { 4615a7c91847Schristos ignore_files (ignlist, entries, update_dir, send_ignproc); 4616a7c91847Schristos dellist (&ignlist); 4617a7c91847Schristos } 4618a7c91847Schristos 4619a7c91847Schristos return err; 4620a7c91847Schristos } 4621a7c91847Schristos 4622a7c91847Schristos 4623a7c91847Schristos 4624a7c91847Schristos /* 4625a7c91847Schristos * send_dirent_proc () is called back by the recursion processor before a 4626a7c91847Schristos * sub-directory is processed for update. 4627a7c91847Schristos * A return code of 0 indicates the directory should be 4628a7c91847Schristos * processed by the recursion code. A return of non-zero indicates the 4629a7c91847Schristos * recursion code should skip this directory. 4630a7c91847Schristos * 4631a7c91847Schristos */ 4632a7c91847Schristos static Dtype 4633a7c91847Schristos send_dirent_proc (void *callerdat, const char *dir, const char *repository, 4634a7c91847Schristos const char *update_dir, List *entries) 4635a7c91847Schristos { 4636a7c91847Schristos struct send_data *args = callerdat; 4637a7c91847Schristos int dir_exists; 4638a7c91847Schristos char *cvsadm_name; 4639a7c91847Schristos 4640a7c91847Schristos if (ignore_directory (update_dir)) 4641a7c91847Schristos { 4642a7c91847Schristos /* print the warm fuzzy message */ 4643a7c91847Schristos if (!quiet) 4644a7c91847Schristos error (0, 0, "Ignoring %s", update_dir); 4645a7c91847Schristos return R_SKIP_ALL; 4646a7c91847Schristos } 4647a7c91847Schristos 4648a7c91847Schristos /* 4649a7c91847Schristos * If the directory does not exist yet (e.g. "cvs update -d foo"), 4650a7c91847Schristos * no need to send any files from it. If the directory does not 4651a7c91847Schristos * have a CVS directory, then we pretend that it does not exist. 4652a7c91847Schristos * Otherwise, we will fail when trying to open the Entries file. 4653a7c91847Schristos * This case will happen when checking out a module defined as 4654a7c91847Schristos * ``-a .''. 4655a7c91847Schristos */ 4656a7c91847Schristos cvsadm_name = Xasprintf ("%s/%s", dir, CVSADM); 4657a7c91847Schristos dir_exists = isdir (cvsadm_name); 4658a7c91847Schristos free (cvsadm_name); 4659a7c91847Schristos 4660a7c91847Schristos /* 4661a7c91847Schristos * If there is an empty directory (e.g. we are doing `cvs add' on a 4662a7c91847Schristos * newly-created directory), the server still needs to know about it. 4663a7c91847Schristos */ 4664a7c91847Schristos 4665a7c91847Schristos if (dir_exists) 4666a7c91847Schristos { 4667a7c91847Schristos /* 4668a7c91847Schristos * Get the repository from a CVS/Repository file whenever possible. 4669a7c91847Schristos * The repository variable is wrong if the names in the local 4670a7c91847Schristos * directory don't match the names in the repository. 4671a7c91847Schristos */ 4672a7c91847Schristos char *repos = Name_Repository (dir, update_dir); 4673a7c91847Schristos send_a_repository (dir, repos, update_dir); 4674a7c91847Schristos free (repos); 4675a7c91847Schristos 4676a7c91847Schristos /* initialize the ignore list for this directory */ 4677a7c91847Schristos ignlist = getlist (); 4678a7c91847Schristos } 4679a7c91847Schristos else 4680a7c91847Schristos { 4681a7c91847Schristos /* It doesn't make sense to send a non-existent directory, 4682a7c91847Schristos because there is no way to get the correct value for 4683a7c91847Schristos the repository (I suppose maybe via the expand-modules 4684a7c91847Schristos request). In the case where the "obvious" choice for 4685a7c91847Schristos repository is correct, the server can figure out whether 4686a7c91847Schristos to recreate the directory; in the case where it is wrong 4687a7c91847Schristos (that is, does not match what modules give us), we might as 4688a7c91847Schristos well just fail to recreate it. 4689a7c91847Schristos 4690a7c91847Schristos Checking for noexec is a kludge for "cvs -n add dir". */ 4691a7c91847Schristos /* Don't send a non-existent directory unless we are building 4692a7c91847Schristos new directories (build_dirs is true). Otherwise, CVS may 4693a7c91847Schristos see a D line in an Entries file, and recreate a directory 4694a7c91847Schristos which the user removed by hand. */ 4695a7c91847Schristos if (args->build_dirs && noexec) 4696a7c91847Schristos send_a_repository (dir, repository, update_dir); 4697a7c91847Schristos } 4698a7c91847Schristos 4699a7c91847Schristos return dir_exists ? R_PROCESS : R_SKIP_ALL; 4700a7c91847Schristos } 4701a7c91847Schristos 4702a7c91847Schristos 4703a7c91847Schristos 4704a7c91847Schristos /* 4705a7c91847Schristos * send_dirleave_proc () is called back by the recursion code upon leaving 4706a7c91847Schristos * a directory. All it does is delete the ignore list if it hasn't already 4707a7c91847Schristos * been done (by send_filesdone_proc). 4708a7c91847Schristos */ 4709a7c91847Schristos /* ARGSUSED */ 4710a7c91847Schristos static int 4711a7c91847Schristos send_dirleave_proc (void *callerdat, const char *dir, int err, 4712a7c91847Schristos const char *update_dir, List *entries ) 4713a7c91847Schristos { 4714a7c91847Schristos 4715a7c91847Schristos /* Delete the ignore list if it hasn't already been done. */ 4716a7c91847Schristos if (ignlist) 4717a7c91847Schristos dellist (&ignlist); 4718a7c91847Schristos return err; 4719a7c91847Schristos } 4720a7c91847Schristos 4721a7c91847Schristos 4722a7c91847Schristos 4723a7c91847Schristos /* 4724a7c91847Schristos * Send each option in an array to the server, one by one. 4725a7c91847Schristos * argv might be "--foo=bar", "-C", "5", "-y". 4726a7c91847Schristos */ 4727a7c91847Schristos 4728a7c91847Schristos void 4729a7c91847Schristos send_options (int argc, char * const *argv) 4730a7c91847Schristos { 4731a7c91847Schristos int i; 4732a7c91847Schristos for (i = 0; i < argc; i++) 4733a7c91847Schristos send_arg (argv[i]); 4734a7c91847Schristos } 4735a7c91847Schristos 4736a7c91847Schristos 4737a7c91847Schristos 4738a7c91847Schristos /* Send the names of all the argument files to the server. */ 4739a7c91847Schristos void 4740a7c91847Schristos send_file_names (int argc, char **argv, unsigned int flags) 4741a7c91847Schristos { 4742a7c91847Schristos int i; 4743a7c91847Schristos 4744a7c91847Schristos /* The fact that we do this here as well as start_recursion is a bit 4745a7c91847Schristos of a performance hit. Perhaps worth cleaning up someday. */ 4746a7c91847Schristos if (flags & SEND_EXPAND_WILD) 4747a7c91847Schristos expand_wild (argc, argv, &argc, &argv); 4748a7c91847Schristos 4749a7c91847Schristos for (i = 0; i < argc; ++i) 4750a7c91847Schristos { 4751a7c91847Schristos char buf[1]; 4752a7c91847Schristos char *p; 4753a7c91847Schristos #ifdef FILENAMES_CASE_INSENSITIVE 4754a7c91847Schristos char *line = NULL; 4755a7c91847Schristos #endif /* FILENAMES_CASE_INSENSITIVE */ 4756a7c91847Schristos 4757a7c91847Schristos if (arg_should_not_be_sent_to_server (argv[i])) 4758a7c91847Schristos continue; 4759a7c91847Schristos 4760a7c91847Schristos #ifdef FILENAMES_CASE_INSENSITIVE 4761a7c91847Schristos /* We want to send the path as it appears in the 4762a7c91847Schristos CVS/Entries files. We put this inside an ifdef 4763a7c91847Schristos to avoid doing all these system calls in 4764a7c91847Schristos cases where fncmp is just strcmp anyway. */ 4765a7c91847Schristos /* The isdir (CVSADM) check could more gracefully be replaced 4766a7c91847Schristos with a way of having Entries_Open report back the 4767a7c91847Schristos error to us and letting us ignore existence_error. 4768a7c91847Schristos Or some such. */ 4769a7c91847Schristos { 4770a7c91847Schristos List *stack; 4771a7c91847Schristos size_t line_len = 0; 4772a7c91847Schristos char *q, *r; 4773a7c91847Schristos struct saved_cwd sdir; 4774a7c91847Schristos 4775a7c91847Schristos /* Split the argument onto the stack. */ 4776a7c91847Schristos stack = getlist(); 4777a7c91847Schristos r = xstrdup (argv[i]); 4778a7c91847Schristos /* It's okay to discard the const from the last_component return 4779a7c91847Schristos * below since we know we passed in an arg that was not const. 4780a7c91847Schristos */ 4781a7c91847Schristos while ((q = (char *)last_component (r)) != r) 4782a7c91847Schristos { 4783a7c91847Schristos push (stack, xstrdup (q)); 4784a7c91847Schristos *--q = '\0'; 4785a7c91847Schristos } 4786a7c91847Schristos push (stack, r); 4787a7c91847Schristos 4788a7c91847Schristos /* Normalize the path into outstr. */ 4789a7c91847Schristos save_cwd (&sdir); 4790a7c91847Schristos while (q = pop (stack)) 4791a7c91847Schristos { 4792a7c91847Schristos Node *node = NULL; 4793a7c91847Schristos if (isdir (CVSADM)) 4794a7c91847Schristos { 4795a7c91847Schristos List *entries; 4796a7c91847Schristos 4797a7c91847Schristos /* Note that if we are adding a directory, 4798a7c91847Schristos the following will read the entry 4799a7c91847Schristos that we just wrote there, that is, we 4800a7c91847Schristos will get the case specified on the 4801a7c91847Schristos command line, not the case of the 4802a7c91847Schristos directory in the filesystem. This 4803a7c91847Schristos is correct behavior. */ 4804a7c91847Schristos entries = Entries_Open (0, NULL); 4805a7c91847Schristos node = findnode_fn (entries, q); 4806a7c91847Schristos if (node) 4807a7c91847Schristos { 4808a7c91847Schristos /* Add the slash unless this is our first element. */ 4809a7c91847Schristos if (line_len) 4810a7c91847Schristos xrealloc_and_strcat (&line, &line_len, "/"); 4811a7c91847Schristos xrealloc_and_strcat (&line, &line_len, node->key); 4812a7c91847Schristos delnode (node); 4813a7c91847Schristos } 4814a7c91847Schristos Entries_Close (entries); 4815a7c91847Schristos } 4816a7c91847Schristos 4817a7c91847Schristos /* If node is still NULL then we either didn't find CVSADM or 4818a7c91847Schristos * we didn't find an entry there. 4819a7c91847Schristos */ 4820a7c91847Schristos if (!node) 4821a7c91847Schristos { 4822a7c91847Schristos /* Add the slash unless this is our first element. */ 4823a7c91847Schristos if (line_len) 4824a7c91847Schristos xrealloc_and_strcat (&line, &line_len, "/"); 4825a7c91847Schristos xrealloc_and_strcat (&line, &line_len, q); 4826a7c91847Schristos break; 4827a7c91847Schristos } 4828a7c91847Schristos 4829a7c91847Schristos /* And descend the tree. */ 4830a7c91847Schristos if (isdir (q)) 4831a7c91847Schristos CVS_CHDIR (q); 4832a7c91847Schristos free (q); 4833a7c91847Schristos } 4834a7c91847Schristos restore_cwd (&sdir); 4835a7c91847Schristos free_cwd (&sdir); 4836a7c91847Schristos 4837a7c91847Schristos /* Now put everything we didn't find entries for back on. */ 4838a7c91847Schristos while (q = pop (stack)) 4839a7c91847Schristos { 4840a7c91847Schristos if (line_len) 4841a7c91847Schristos xrealloc_and_strcat (&line, &line_len, "/"); 4842a7c91847Schristos xrealloc_and_strcat (&line, &line_len, q); 4843a7c91847Schristos free (q); 4844a7c91847Schristos } 4845a7c91847Schristos 4846a7c91847Schristos p = line; 4847a7c91847Schristos 4848a7c91847Schristos dellist (&stack); 4849a7c91847Schristos } 4850a7c91847Schristos #else /* !FILENAMES_CASE_INSENSITIVE */ 4851a7c91847Schristos p = argv[i]; 4852a7c91847Schristos #endif /* FILENAMES_CASE_INSENSITIVE */ 4853a7c91847Schristos 4854a7c91847Schristos send_to_server ("Argument ", 0); 4855a7c91847Schristos 4856a7c91847Schristos while (*p) 4857a7c91847Schristos { 4858a7c91847Schristos if (*p == '\n') 4859a7c91847Schristos { 4860a7c91847Schristos send_to_server ("\012Argumentx ", 0); 4861a7c91847Schristos } 4862a7c91847Schristos else if (ISSLASH (*p)) 4863a7c91847Schristos { 4864a7c91847Schristos buf[0] = '/'; 4865a7c91847Schristos send_to_server (buf, 1); 4866a7c91847Schristos } 4867a7c91847Schristos else 4868a7c91847Schristos { 4869a7c91847Schristos buf[0] = *p; 4870a7c91847Schristos send_to_server (buf, 1); 4871a7c91847Schristos } 4872a7c91847Schristos ++p; 4873a7c91847Schristos } 4874a7c91847Schristos send_to_server ("\012", 1); 4875a7c91847Schristos #ifdef FILENAMES_CASE_INSENSITIVE 4876a7c91847Schristos free (line); 4877a7c91847Schristos #endif /* FILENAMES_CASE_INSENSITIVE */ 4878a7c91847Schristos } 4879a7c91847Schristos 4880a7c91847Schristos if (flags & SEND_EXPAND_WILD) 4881a7c91847Schristos { 4882a7c91847Schristos int i; 4883a7c91847Schristos for (i = 0; i < argc; ++i) 4884a7c91847Schristos free (argv[i]); 4885a7c91847Schristos free (argv); 4886a7c91847Schristos } 4887a7c91847Schristos } 4888a7c91847Schristos 4889a7c91847Schristos 4890a7c91847Schristos 4891a7c91847Schristos /* Calculate and send max-dotdot to the server */ 4892a7c91847Schristos static void 4893a7c91847Schristos send_max_dotdot (argc, argv) 4894a7c91847Schristos int argc; 4895a7c91847Schristos char **argv; 4896a7c91847Schristos { 4897a7c91847Schristos int i; 4898a7c91847Schristos int level = 0; 4899a7c91847Schristos int max_level = 0; 4900a7c91847Schristos 4901a7c91847Schristos /* Send Max-dotdot if needed. */ 4902a7c91847Schristos for (i = 0; i < argc; ++i) 4903a7c91847Schristos { 4904a7c91847Schristos level = pathname_levels (argv[i]); 4905a7c91847Schristos if (level > 0) 4906a7c91847Schristos { 4907a7c91847Schristos if (!uppaths) uppaths = getlist(); 4908a7c91847Schristos push_string (uppaths, xstrdup (argv[i])); 4909a7c91847Schristos } 4910a7c91847Schristos if (level > max_level) 4911a7c91847Schristos max_level = level; 4912a7c91847Schristos } 4913a7c91847Schristos 4914a7c91847Schristos if (max_level > 0) 4915a7c91847Schristos { 4916a7c91847Schristos if (supported_request ("Max-dotdot")) 4917a7c91847Schristos { 4918a7c91847Schristos char buf[10]; 4919a7c91847Schristos sprintf (buf, "%d", max_level); 4920a7c91847Schristos 4921a7c91847Schristos send_to_server ("Max-dotdot ", 0); 4922a7c91847Schristos send_to_server (buf, 0); 4923a7c91847Schristos send_to_server ("\012", 1); 4924a7c91847Schristos } 4925a7c91847Schristos else 4926a7c91847Schristos { 4927a7c91847Schristos error (1, 0, 4928a7c91847Schristos "backreference in path (`..') not supported by old (pre-Max-dotdot) servers"); 4929a7c91847Schristos } 4930a7c91847Schristos } 4931a7c91847Schristos } 4932a7c91847Schristos 4933a7c91847Schristos 4934a7c91847Schristos 4935a7c91847Schristos /* Send Repository, Modified and Entry. argc and argv contain only 4936a7c91847Schristos the files to operate on (or empty for everything), not options. 4937a7c91847Schristos local is nonzero if we should not recurse (-l option). flags & 4938a7c91847Schristos SEND_BUILD_DIRS is nonzero if nonexistent directories should be 4939a7c91847Schristos sent. flags & SEND_FORCE is nonzero if we should send unmodified 4940a7c91847Schristos files to the server as though they were modified. flags & 4941a7c91847Schristos SEND_NO_CONTENTS means that this command only needs to know 4942a7c91847Schristos _whether_ a file is modified, not the contents. Also sends Argument 4943a7c91847Schristos lines for argc and argv, so should be called after options are sent. */ 4944a7c91847Schristos void 4945a7c91847Schristos send_files (int argc, char **argv, int local, int aflag, unsigned int flags) 4946a7c91847Schristos { 4947a7c91847Schristos struct send_data args; 4948a7c91847Schristos int err; 4949a7c91847Schristos 4950a7c91847Schristos send_max_dotdot (argc, argv); 4951a7c91847Schristos 4952a7c91847Schristos /* 4953a7c91847Schristos * aflag controls whether the tag/date is copied into the vers_ts. 4954a7c91847Schristos * But we don't actually use it, so I don't think it matters what we pass 4955a7c91847Schristos * for aflag here. 4956a7c91847Schristos */ 4957a7c91847Schristos args.build_dirs = flags & SEND_BUILD_DIRS; 4958a7c91847Schristos args.force = flags & SEND_FORCE; 4959a7c91847Schristos args.no_contents = flags & SEND_NO_CONTENTS; 4960a7c91847Schristos args.backup_modified = flags & BACKUP_MODIFIED_FILES; 4961a7c91847Schristos err = start_recursion 4962a7c91847Schristos (send_fileproc, send_filesdoneproc, send_dirent_proc, 4963a7c91847Schristos send_dirleave_proc, &args, argc, argv, local, W_LOCAL, aflag, 4964a7c91847Schristos CVS_LOCK_NONE, NULL, 0, NULL); 4965a7c91847Schristos if (err) 4966a7c91847Schristos exit (EXIT_FAILURE); 4967a7c91847Schristos if (!toplevel_repos) 4968a7c91847Schristos /* 4969a7c91847Schristos * This happens if we are not processing any files, 4970a7c91847Schristos * or for checkouts in directories without any existing stuff 4971a7c91847Schristos * checked out. The following assignment is correct for the 4972a7c91847Schristos * latter case; I don't think toplevel_repos matters for the 4973a7c91847Schristos * former. 4974a7c91847Schristos */ 4975a7c91847Schristos toplevel_repos = xstrdup (current_parsed_root->directory); 4976a7c91847Schristos send_repository ("", toplevel_repos, "."); 4977a7c91847Schristos } 4978a7c91847Schristos 4979a7c91847Schristos 4980a7c91847Schristos 4981a7c91847Schristos void 4982a7c91847Schristos client_import_setup (char *repository) 4983a7c91847Schristos { 4984a7c91847Schristos if (!toplevel_repos) /* should always be true */ 4985a7c91847Schristos send_a_repository ("", repository, ""); 4986a7c91847Schristos } 4987a7c91847Schristos 4988a7c91847Schristos 4989a7c91847Schristos 4990a7c91847Schristos /* 4991a7c91847Schristos * Process the argument import file. 4992a7c91847Schristos */ 4993a7c91847Schristos int 4994a7c91847Schristos client_process_import_file (char *message, char *vfile, char *vtag, int targc, 4995a7c91847Schristos char *targv[], char *repository, 4996a7c91847Schristos int all_files_binary, 4997a7c91847Schristos int modtime /* Nonzero for "import -d". */ ) 4998a7c91847Schristos { 4999a7c91847Schristos char *update_dir; 5000a7c91847Schristos char *fullname; 5001a7c91847Schristos Vers_TS vers; 5002a7c91847Schristos 5003a7c91847Schristos assert (toplevel_repos); 5004a7c91847Schristos 5005a7c91847Schristos if (strncmp (repository, toplevel_repos, strlen (toplevel_repos))) 5006a7c91847Schristos error (1, 0, 5007a7c91847Schristos "internal error: pathname `%s' doesn't specify file in `%s'", 5008a7c91847Schristos repository, toplevel_repos); 5009a7c91847Schristos 5010a7c91847Schristos if (!strcmp (repository, toplevel_repos)) 5011a7c91847Schristos { 5012a7c91847Schristos update_dir = ""; 5013a7c91847Schristos fullname = xstrdup (vfile); 5014a7c91847Schristos } 5015a7c91847Schristos else 5016a7c91847Schristos { 5017a7c91847Schristos update_dir = repository + strlen (toplevel_repos) + 1; 5018a7c91847Schristos 5019a7c91847Schristos fullname = Xasprintf ("%s/%s", update_dir, vfile); 5020a7c91847Schristos } 5021a7c91847Schristos 5022a7c91847Schristos send_a_repository ("", repository, update_dir); 5023a7c91847Schristos if (all_files_binary) 5024a7c91847Schristos vers.options = xstrdup ("-kb"); 5025a7c91847Schristos else 5026a7c91847Schristos vers.options = wrap_rcsoption (vfile, 1); 5027a7c91847Schristos 5028a7c91847Schristos if (vers.options) 5029a7c91847Schristos { 5030a7c91847Schristos if (supported_request ("Kopt")) 5031a7c91847Schristos { 5032a7c91847Schristos send_to_server ("Kopt ", 0); 5033a7c91847Schristos send_to_server (vers.options, 0); 5034a7c91847Schristos send_to_server ("\012", 1); 5035a7c91847Schristos } 5036a7c91847Schristos else 5037a7c91847Schristos error (0, 0, 5038a7c91847Schristos "warning: ignoring -k options due to server limitations"); 5039a7c91847Schristos } 5040a7c91847Schristos if (modtime) 5041a7c91847Schristos { 5042a7c91847Schristos if (supported_request ("Checkin-time")) 5043a7c91847Schristos { 5044a7c91847Schristos struct stat sb; 5045a7c91847Schristos char *rcsdate; 5046a7c91847Schristos char netdate[MAXDATELEN]; 5047a7c91847Schristos 5048a7c91847Schristos if (stat (vfile, &sb) < 0) 5049a7c91847Schristos error (1, errno, "cannot stat %s", fullname); 5050a7c91847Schristos rcsdate = date_from_time_t (sb.st_mtime); 5051a7c91847Schristos date_to_internet (netdate, rcsdate); 5052a7c91847Schristos free (rcsdate); 5053a7c91847Schristos 5054a7c91847Schristos send_to_server ("Checkin-time ", 0); 5055a7c91847Schristos send_to_server (netdate, 0); 5056a7c91847Schristos send_to_server ("\012", 1); 5057a7c91847Schristos } 5058a7c91847Schristos else 5059a7c91847Schristos error (0, 0, 5060a7c91847Schristos "warning: ignoring -d option due to server limitations"); 5061a7c91847Schristos } 5062a7c91847Schristos send_modified (vfile, fullname, &vers); 5063a7c91847Schristos if (vers.options) 5064a7c91847Schristos free (vers.options); 5065a7c91847Schristos free (fullname); 5066a7c91847Schristos return 0; 5067a7c91847Schristos } 5068a7c91847Schristos 5069a7c91847Schristos 5070a7c91847Schristos 5071a7c91847Schristos void 5072a7c91847Schristos client_import_done (void) 5073a7c91847Schristos { 5074a7c91847Schristos if (!toplevel_repos) 5075a7c91847Schristos /* 5076a7c91847Schristos * This happens if we are not processing any files, 5077a7c91847Schristos * or for checkouts in directories without any existing stuff 5078a7c91847Schristos * checked out. The following assignment is correct for the 5079a7c91847Schristos * latter case; I don't think toplevel_repos matters for the 5080a7c91847Schristos * former. 5081a7c91847Schristos */ 5082a7c91847Schristos /* FIXME: "can't happen" now that we call client_import_setup 5083a7c91847Schristos at the beginning. */ 5084a7c91847Schristos toplevel_repos = xstrdup (current_parsed_root->directory); 5085a7c91847Schristos send_repository ("", toplevel_repos, "."); 5086a7c91847Schristos } 5087a7c91847Schristos 5088a7c91847Schristos 5089a7c91847Schristos 5090a7c91847Schristos void 5091a7c91847Schristos client_notify (const char *repository, const char *update_dir, 5092a7c91847Schristos const char *filename, int notif_type, const char *val) 5093a7c91847Schristos { 5094a7c91847Schristos char buf[2]; 5095a7c91847Schristos 5096a7c91847Schristos send_a_repository ("", repository, update_dir); 5097a7c91847Schristos send_to_server ("Notify ", 0); 5098a7c91847Schristos send_to_server (filename, 0); 5099a7c91847Schristos send_to_server ("\012", 1); 5100a7c91847Schristos buf[0] = notif_type; 5101a7c91847Schristos buf[1] = '\0'; 5102a7c91847Schristos send_to_server (buf, 1); 5103a7c91847Schristos send_to_server ("\t", 1); 5104a7c91847Schristos send_to_server (val, 0); 5105a7c91847Schristos } 5106a7c91847Schristos 5107a7c91847Schristos 5108a7c91847Schristos 5109a7c91847Schristos /* 5110a7c91847Schristos * Send an option with an argument, dealing correctly with newlines in 5111a7c91847Schristos * the argument. If ARG is NULL, forget the whole thing. 5112a7c91847Schristos */ 5113a7c91847Schristos void 5114a7c91847Schristos option_with_arg (const char *option, const char *arg) 5115a7c91847Schristos { 5116a7c91847Schristos if (!arg) 5117a7c91847Schristos return; 5118a7c91847Schristos 5119a7c91847Schristos send_to_server ("Argument ", 0); 5120a7c91847Schristos send_to_server (option, 0); 5121a7c91847Schristos send_to_server ("\012", 1); 5122a7c91847Schristos 5123a7c91847Schristos send_arg (arg); 5124a7c91847Schristos } 5125a7c91847Schristos 5126a7c91847Schristos 5127a7c91847Schristos 5128a7c91847Schristos /* Send a date to the server. The input DATE is in RCS format. 5129a7c91847Schristos The time will be GMT. 5130a7c91847Schristos 5131a7c91847Schristos We then convert that to the format required in the protocol 5132a7c91847Schristos (including the "-D" option) and send it. According to 5133a7c91847Schristos cvsclient.texi, RFC 822/1123 format is preferred. */ 5134a7c91847Schristos void 5135a7c91847Schristos client_senddate (const char *date) 5136a7c91847Schristos { 5137a7c91847Schristos char buf[MAXDATELEN]; 5138a7c91847Schristos 5139a7c91847Schristos date_to_internet (buf, date); 5140a7c91847Schristos option_with_arg ("-D", buf); 5141a7c91847Schristos } 5142a7c91847Schristos 5143a7c91847Schristos 5144a7c91847Schristos 5145a7c91847Schristos void 5146a7c91847Schristos send_init_command (void) 5147a7c91847Schristos { 5148a7c91847Schristos /* This is here because we need the current_parsed_root->directory variable. */ 5149a7c91847Schristos send_to_server ("init ", 0); 5150a7c91847Schristos send_to_server (current_parsed_root->directory, 0); 5151a7c91847Schristos send_to_server ("\012", 0); 5152a7c91847Schristos } 5153a7c91847Schristos 5154a7c91847Schristos 5155a7c91847Schristos 5156a7c91847Schristos #if defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS || defined HAVE_GSSAPI 5157a7c91847Schristos 5158*9f2c58f4Schristos static int 5159274254cdSchristos connect_to(char *hostname, unsigned int port) 5160a7c91847Schristos { 5161274254cdSchristos struct addrinfo hints, *res, *res0 = NULL; 5162274254cdSchristos char pbuf[10]; 5163274254cdSchristos int e, sock; 5164a7c91847Schristos 5165274254cdSchristos memset(&hints, 0, sizeof(hints)); 5166274254cdSchristos hints.ai_family = PF_UNSPEC; 5167274254cdSchristos hints.ai_socktype = SOCK_STREAM; 5168274254cdSchristos hints.ai_flags = AI_CANONNAME; 5169274254cdSchristos 5170274254cdSchristos snprintf(pbuf, sizeof(pbuf), "%d", port); 5171274254cdSchristos e = getaddrinfo(hostname, pbuf, &hints, &res0); 5172274254cdSchristos if (e) 5173a7c91847Schristos { 5174274254cdSchristos error (1, 0, "%s", gai_strerror(e)); 5175a7c91847Schristos } 5176274254cdSchristos sock = -1; 5177274254cdSchristos for (res = res0; res; res = res->ai_next) { 5178274254cdSchristos sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 5179274254cdSchristos if (sock < 0) 5180274254cdSchristos continue; 5181274254cdSchristos 5182274254cdSchristos TRACE (TRACE_FUNCTION, " -> Connecting to %s\n", hostname); 5183274254cdSchristos if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) { 5184274254cdSchristos close(sock); 5185274254cdSchristos sock = -1; 5186274254cdSchristos continue; 5187274254cdSchristos } 5188274254cdSchristos break; 5189274254cdSchristos } 5190274254cdSchristos freeaddrinfo(res0); 5191274254cdSchristos return sock; 5192a7c91847Schristos } 5193a7c91847Schristos 5194a7c91847Schristos #endif /* defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS 5195a7c91847Schristos * || defined HAVE_GSSAPI 5196a7c91847Schristos */ 5197a7c91847Schristos 5198a7c91847Schristos #endif /* CLIENT_SUPPORT */ 5199