1 /* $OpenBSD: update.c,v 1.13 2004/12/21 18:32:10 jfb Exp $ */ 2 /* 3 * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/stat.h> 29 30 #include <errno.h> 31 #include <stdio.h> 32 #include <fcntl.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <sysexits.h> 37 38 #include "cvs.h" 39 #include "rcs.h" 40 #include "log.h" 41 #include "proto.h" 42 43 44 int cvs_update_file (CVSFILE *, void *); 45 int cvs_update_prune (CVSFILE *, void *); 46 47 48 /* 49 * cvs_update() 50 * 51 * Handle the `cvs update' command. 52 * Returns 0 on success, or the appropriate exit code on error. 53 */ 54 int 55 cvs_update(int argc, char **argv) 56 { 57 int i, ch, flags; 58 struct cvsroot *root; 59 60 flags = CF_SORT|CF_RECURSE|CF_IGNORE|CF_KNOWN|CF_NOSYMS; 61 62 while ((ch = getopt(argc, argv, "ACD:dflPpQqRr:")) != -1) { 63 switch (ch) { 64 case 'A': 65 case 'C': 66 case 'D': 67 case 'd': 68 case 'f': 69 break; 70 case 'l': 71 flags &= ~CF_RECURSE; 72 break; 73 case 'P': 74 case 'p': 75 case 'Q': 76 case 'q': 77 break; 78 case 'R': 79 flags |= CF_RECURSE; 80 break; 81 case 'r': 82 break; 83 default: 84 return (EX_USAGE); 85 } 86 } 87 88 argc -= optind; 89 argv += optind; 90 91 if (argc == 0) 92 cvs_files = cvs_file_get(".", flags); 93 else { 94 /* don't perform ignore on explicitly listed files */ 95 flags &= ~(CF_IGNORE | CF_RECURSE | CF_SORT); 96 cvs_files = cvs_file_getspec(argv, argc, flags); 97 } 98 if (cvs_files == NULL) 99 return (EX_DATAERR); 100 101 root = CVS_DIR_ROOT(cvs_files); 102 if (root == NULL) { 103 cvs_log(LP_ERR, 104 "No CVSROOT specified! Please use the `-d' option"); 105 cvs_log(LP_ERR, 106 "or set the CVSROOT environment variable."); 107 return (EX_USAGE); 108 } 109 if ((root->cr_method != CVS_METHOD_LOCAL) && (cvs_connect(root) < 0)) 110 return (EX_PROTOCOL); 111 112 cvs_file_examine(cvs_files, cvs_update_file, NULL); 113 114 if (root->cr_method != CVS_METHOD_LOCAL) { 115 if (cvs_senddir(root, cvs_files) < 0) 116 return (EX_PROTOCOL); 117 118 for (i = 0; i < argc; i++) 119 if (cvs_sendarg(root, argv[i], 0) < 0) 120 return (EX_PROTOCOL); 121 if (cvs_sendreq(root, CVS_REQ_UPDATE, NULL) < 0) 122 return (EX_PROTOCOL); 123 } 124 125 return (0); 126 } 127 128 129 /* 130 * cvs_update_file() 131 * 132 * Update a single file. In the case where we act as client, send any 133 * pertinent information about that file to the server. 134 */ 135 int 136 cvs_update_file(CVSFILE *cf, void *arg) 137 { 138 int ret; 139 char *repo, fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; 140 RCSFILE *rf; 141 struct cvsroot *root; 142 struct cvs_ent *entp; 143 144 ret = 0; 145 rf = NULL; 146 root = CVS_DIR_ROOT(cf); 147 repo = CVS_DIR_REPO(cf); 148 149 if (cf->cf_type == DT_DIR) { 150 if (root->cr_method != CVS_METHOD_LOCAL) { 151 if (cf->cf_cvstat == CVS_FST_UNKNOWN) 152 ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, 153 CVS_FILE_NAME(cf)); 154 else 155 ret = cvs_senddir(root, cf); 156 } 157 158 return (ret); 159 } 160 161 cvs_file_getpath(cf, fpath, sizeof(fpath)); 162 entp = cvs_ent_getent(fpath); 163 164 if (root->cr_method != CVS_METHOD_LOCAL) { 165 if ((entp != NULL) && (cvs_sendentry(root, entp) < 0)) { 166 cvs_ent_free(entp); 167 return (-1); 168 } 169 170 switch (cf->cf_cvstat) { 171 case CVS_FST_UNKNOWN: 172 ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, 173 CVS_FILE_NAME(cf)); 174 break; 175 case CVS_FST_UPTODATE: 176 ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, 177 CVS_FILE_NAME(cf)); 178 break; 179 case CVS_FST_ADDED: 180 case CVS_FST_MODIFIED: 181 ret = cvs_sendreq(root, CVS_REQ_MODIFIED, 182 CVS_FILE_NAME(cf)); 183 if (ret == 0) 184 ret = cvs_sendfile(root, fpath); 185 break; 186 default: 187 break; 188 } 189 } else { 190 if (cf->cf_cvstat == CVS_FST_UNKNOWN) { 191 cvs_printf("? %s\n", fpath); 192 return (0); 193 } 194 195 snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s", 196 root->cr_dir, repo, fpath, RCS_FILE_EXT); 197 198 rf = rcs_open(rcspath, RCS_MODE_READ); 199 if (rf == NULL) { 200 cvs_ent_free(entp); 201 return (-1); 202 } 203 204 rcs_close(rf); 205 } 206 207 if (entp != NULL) 208 cvs_ent_free(entp); 209 return (ret); 210 } 211 212 213 /* 214 * cvs_update_prune() 215 * 216 * Prune all directories which contain no more files known to CVS. 217 */ 218 int 219 cvs_update_prune(CVSFILE *cf, void *arg) 220 { 221 222 return (0); 223 } 224