1 /* $OpenBSD: commit.c,v 1.11 2004/12/13 23:08:45 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/types.h> 28 #include <sys/queue.h> 29 #include <sys/stat.h> 30 31 #include <errno.h> 32 #include <stdio.h> 33 #include <fcntl.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <sysexits.h> 38 39 #include "cvs.h" 40 #include "log.h" 41 #include "buf.h" 42 #include "proto.h" 43 44 45 46 47 int cvs_commit_prepare (CVSFILE *, void *); 48 int cvs_commit_file (CVSFILE *, void *); 49 50 51 /* 52 * cvs_commit() 53 * 54 * Handler for the `cvs commit' command. 55 */ 56 int 57 cvs_commit(int argc, char **argv) 58 { 59 int i, ch, flags; 60 char *msg, *mfile; 61 struct cvs_flist cl; 62 struct cvsroot *root; 63 64 flags = CF_RECURSE|CF_IGNORE|CF_SORT; 65 mfile = NULL; 66 msg = NULL; 67 TAILQ_INIT(&cl); 68 69 while ((ch = getopt(argc, argv, "F:flm:Rr:")) != -1) { 70 switch (ch) { 71 case 'F': 72 mfile = optarg; 73 break; 74 case 'f': 75 /* XXX half-implemented */ 76 flags &= ~CF_RECURSE; 77 break; 78 case 'l': 79 flags &= ~CF_RECURSE; 80 break; 81 case 'm': 82 msg = optarg; 83 break; 84 case 'R': 85 flags |= CF_RECURSE; 86 break; 87 default: 88 return (EX_USAGE); 89 } 90 } 91 92 if ((msg != NULL) && (mfile != NULL)) { 93 cvs_log(LP_ERR, "the -F and -m flags are mutually exclusive"); 94 return (EX_USAGE); 95 } 96 97 if ((mfile != NULL) && (msg = cvs_logmsg_open(mfile)) == NULL) 98 return (EX_DATAERR); 99 100 argc -= optind; 101 argv += optind; 102 103 if (argc == 0) { 104 cvs_files = cvs_file_get(".", flags); 105 } else { 106 cvs_files = cvs_file_getspec(argv, argc, flags); 107 } 108 if (cvs_files == NULL) 109 return (EX_DATAERR); 110 111 cvs_file_examine(cvs_files, cvs_commit_prepare, &cl); 112 if (TAILQ_EMPTY(&cl)) 113 return (0); 114 115 if (msg == NULL) { 116 msg = cvs_logmsg_get(CVS_FILE_NAME(cvs_files), NULL, &cl, NULL); 117 if (msg == NULL) 118 return (1); 119 } 120 121 root = CVS_DIR_ROOT(cvs_files); 122 cvs_connect(root); 123 cvs_logmsg_send(root, msg); 124 125 cvs_file_examine(cvs_files, cvs_commit_file, &cl); 126 127 if (root->cr_method != CVS_METHOD_LOCAL) { 128 cvs_senddir(root, cvs_files); 129 if (argc > 0) { 130 for (i = 0; i < argc; i++) 131 cvs_sendarg(root, argv[i], 0); 132 } 133 cvs_sendreq(root, CVS_REQ_CI, NULL); 134 } 135 136 return (0); 137 } 138 139 140 /* 141 * cvs_commit_prepare() 142 * 143 * Examine the file <cf> to see if it will be part of the commit, in which 144 * case it gets added to the list passed as second argument. 145 */ 146 int 147 cvs_commit_prepare(CVSFILE *cf, void *arg) 148 { 149 CVSFILE *copy; 150 struct cvs_flist *clp = (struct cvs_flist *)arg; 151 152 if ((cf->cf_type == DT_REG) && (cf->cf_cvstat == CVS_FST_MODIFIED)) { 153 copy = cvs_file_copy(cf); 154 if (copy == NULL) 155 return (-1); 156 157 TAILQ_INSERT_TAIL(clp, copy, cf_list); 158 } 159 160 return (0); 161 } 162 163 164 /* 165 * cvs_commit_file() 166 * 167 * Commit a single file. 168 */ 169 int 170 cvs_commit_file(CVSFILE *cf, void *arg) 171 { 172 char *repo, rcspath[MAXPATHLEN], fpath[MAXPATHLEN]; 173 RCSFILE *rf; 174 struct cvsroot *root; 175 struct cvs_ent *entp; 176 177 rf = NULL; 178 repo = NULL; 179 180 if (cf->cf_type == DT_DIR) { 181 if (cf->cf_cvstat != CVS_FST_UNKNOWN) { 182 root = CVS_DIR_ROOT(cf); 183 if ((cf->cf_parent != NULL) && 184 (root != cf->cf_parent->cf_ddat->cd_root)) { 185 cvs_connect(root); 186 } 187 188 cvs_senddir(root, cf); 189 } 190 191 return (0); 192 } 193 194 195 root = CVS_DIR_ROOT(cf); 196 cvs_file_getpath(cf, fpath, sizeof(fpath)); 197 198 if (cf->cf_parent != NULL) 199 repo = cf->cf_parent->cf_ddat->cd_repo; 200 201 entp = cvs_ent_getent(fpath); 202 if (entp == NULL) 203 return (-1); 204 205 if ((cf->cf_cvstat == CVS_FST_ADDED) || 206 (cf->cf_cvstat == CVS_FST_MODIFIED)) { 207 if ((root->cr_method != CVS_METHOD_LOCAL) && 208 (cvs_sendentry(root, entp) < 0)) { 209 cvs_ent_free(entp); 210 return (-1); 211 } 212 213 cvs_sendreq(root, CVS_REQ_MODIFIED, CVS_FILE_NAME(cf)); 214 cvs_sendfile(root, fpath); 215 } 216 217 snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s", 218 root->cr_dir, repo, fpath, RCS_FILE_EXT); 219 220 cvs_ent_free(entp); 221 222 return (0); 223 } 224