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