1 /* $OpenBSD: rcsclean.c,v 1.52 2010/07/28 09:07:11 ray Exp $ */ 2 /* 3 * Copyright (c) 2005 Joris Vink <joris@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 29 #include <dirent.h> 30 #include <err.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 35 #include "rcsprog.h" 36 #include "diff.h" 37 38 static void rcsclean_file(char *, const char *); 39 40 static int nflag = 0; 41 static int kflag = RCS_KWEXP_ERR; 42 static int uflag = 0; 43 static int flags = 0; 44 static char *locker = NULL; 45 46 int 47 rcsclean_main(int argc, char **argv) 48 { 49 int i, ch; 50 char *rev_str; 51 DIR *dirp; 52 struct dirent *dp; 53 54 rev_str = NULL; 55 56 while ((ch = rcs_getopt(argc, argv, "k:n::q::r::Tu::Vx::")) != -1) { 57 switch (ch) { 58 case 'k': 59 kflag = rcs_kflag_get(rcs_optarg); 60 if (RCS_KWEXP_INVAL(kflag)) { 61 warnx("invalid RCS keyword substitution mode"); 62 (usage)(); 63 exit(1); 64 } 65 break; 66 case 'n': 67 rcs_setrevstr(&rev_str, rcs_optarg); 68 nflag = 1; 69 break; 70 case 'q': 71 rcs_setrevstr(&rev_str, rcs_optarg); 72 flags |= QUIET; 73 break; 74 case 'r': 75 rcs_setrevstr(&rev_str, rcs_optarg); 76 break; 77 case 'T': 78 flags |= PRESERVETIME; 79 break; 80 case 'u': 81 rcs_setrevstr(&rev_str, rcs_optarg); 82 uflag = 1; 83 break; 84 case 'V': 85 printf("%s\n", rcs_version); 86 exit(0); 87 case 'x': 88 /* Use blank extension if none given. */ 89 rcs_suffixes = rcs_optarg ? rcs_optarg : ""; 90 break; 91 default: 92 (usage)(); 93 exit(1); 94 } 95 } 96 97 argc -= rcs_optind; 98 argv += rcs_optind; 99 100 if ((locker = getlogin()) == NULL) 101 err(1, "getlogin"); 102 103 if (argc == 0) { 104 if ((dirp = opendir(".")) == NULL) { 105 warn("opendir"); 106 (usage)(); 107 exit(1); 108 } 109 110 while ((dp = readdir(dirp)) != NULL) { 111 if (dp->d_type == DT_DIR) 112 continue; 113 rcsclean_file(dp->d_name, rev_str); 114 } 115 116 (void)closedir(dirp); 117 } else 118 for (i = 0; i < argc; i++) 119 rcsclean_file(argv[i], rev_str); 120 121 return (0); 122 } 123 124 void 125 rcsclean_usage(void) 126 { 127 fprintf(stderr, 128 "usage: rcsclean [-TV] [-kmode] [-n[rev]] [-q[rev]] [-r[rev]]\n" 129 " [-u[rev]] [-xsuffixes] [-ztz] [file ...]\n"); 130 } 131 132 static void 133 rcsclean_file(char *fname, const char *rev_str) 134 { 135 int fd, match; 136 RCSFILE *file; 137 char fpath[MAXPATHLEN], numb[RCS_REV_BUFSZ]; 138 RCSNUM *rev; 139 BUF *b1, *b2; 140 time_t rcs_mtime = -1; 141 142 b1 = b2 = NULL; 143 file = NULL; 144 rev = NULL; 145 146 if ((fd = rcs_choosefile(fname, fpath, sizeof(fpath))) < 0) 147 goto out; 148 149 if ((file = rcs_open(fpath, fd, RCS_RDWR)) == NULL) 150 goto out; 151 152 if (flags & PRESERVETIME) 153 rcs_mtime = rcs_get_mtime(file); 154 155 rcs_kwexp_set(file, kflag); 156 157 if (rev_str == NULL) 158 rev = file->rf_head; 159 else if ((rev = rcs_getrevnum(rev_str, file)) == NULL) { 160 warnx("%s: Symbolic name `%s' is undefined.", fpath, rev_str); 161 goto out; 162 } 163 164 if ((b1 = rcs_getrev(file, rev)) == NULL) { 165 warnx("failed to get needed revision"); 166 goto out; 167 } 168 if ((b2 = buf_load(fname)) == NULL) { 169 warnx("failed to load `%s'", fname); 170 goto out; 171 } 172 173 /* If buffer lengths are the same, compare contents as well. */ 174 if (buf_len(b1) != buf_len(b2)) 175 match = 0; 176 else { 177 size_t len, n; 178 179 len = buf_len(b1); 180 181 match = 1; 182 for (n = 0; n < len; ++n) 183 if (buf_getc(b1, n) != buf_getc(b2, n)) { 184 match = 0; 185 break; 186 } 187 } 188 189 if (match == 1) { 190 if (uflag == 1 && !TAILQ_EMPTY(&(file->rf_locks))) { 191 if (!(flags & QUIET) && nflag == 0) { 192 printf("rcs -u%s %s\n", 193 rcsnum_tostr(rev, numb, sizeof(numb)), 194 fpath); 195 } 196 (void)rcs_lock_remove(file, locker, rev); 197 } 198 199 if (TAILQ_EMPTY(&(file->rf_locks))) { 200 if (!(flags & QUIET)) 201 printf("rm -f %s\n", fname); 202 203 if (nflag == 0) 204 (void)unlink(fname); 205 } 206 } 207 208 rcs_write(file); 209 if (flags & PRESERVETIME) 210 rcs_set_mtime(file, rcs_mtime); 211 212 out: 213 if (b1 != NULL) 214 buf_free(b1); 215 if (b2 != NULL) 216 buf_free(b2); 217 if (file != NULL) 218 rcs_close(file); 219 } 220