00001
00002
00003 #include <sys/types.h>
00004 #include <string.h>
00005 #include <sys/stat.h>
00006 #include <pwd.h>
00007 #include <signal.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <time.h>
00011 #include <fcntl.h>
00012 #include <sys/wait.h>
00013 #include <stdio.h>
00014
00015 #define SUFFIX ",S"
00016 #define SVCDIR "SVC"
00017
00018 #define LINELEN 256
00019
00020 #ifndef PATCH
00021 #define FIX "fix $1 Fix.$1 > New.$1; mv New.$1 $1\n"
00022 #else
00023 #define FIX "patch -n -s $1 < Fix.$1; rm -f $1.orig\n"
00024 #endif
00025
00026 #ifdef MAXPATHLEN
00027 #define PATHLEN MAXPATHLEN
00028 #else
00029 #define PATHLEN 128
00030 #endif
00031
00032 int unlocked = 0;
00033 int relock = 0;
00034 char file[PATHLEN];
00035 char svc[PATHLEN];
00036 char newsvc[PATHLEN];
00037 char line[LINELEN];
00038 char *p;
00039
00040 FILE *svcfp;
00041 FILE *origfp, *newfp;
00042 FILE *srcfp;
00043 int rev;
00044 int status;
00045 struct stat stb1, stb2;
00046 char original[] = "/tmp/cioXXXXXX";
00047 char diffout[] = "/tmp/cidXXXXXX";
00048
00049 _PROTOTYPE(int main, (int argc, char **argv));
00050 _PROTOTYPE(void rundiff, (void));
00051 _PROTOTYPE(void logmsg, (FILE *fp));
00052 _PROTOTYPE(void fname, (char *src, char *dst));
00053 _PROTOTYPE(void svcname, (char *src, char *dst));
00054 _PROTOTYPE(int lockcheck, (FILE *fp, int rev));
00055 _PROTOTYPE(void onintr, (int dummy));
00056 _PROTOTYPE(void clean, (void));
00057 _PROTOTYPE(char *whoami, (void));
00058
00059 int main(argc, argv)
00060 int argc;
00061 char **argv;
00062 {
00063 #ifdef perprintf
00064 char errbuf[BUFSIZ];
00065 setbuf(stderr, errbuf);
00066 perprintf(stderr);
00067 #endif
00068
00069 while (++argv, --argc) {
00070 if ('-' == (*argv)[0]) {
00071 if ('u' == (*argv)[1])
00072 ++unlocked;
00073 else if ('l' == (*argv)[1])
00074 ++relock;
00075 else {
00076 fprintf(stderr, "ci: illegal option -%c\n", (*argv)[1]);
00077 exit(1);
00078 }
00079 } else
00080 break;
00081 }
00082
00083 if (1 != argc) {
00084 fprintf(stderr, "ci: bad number of files arguments\n");
00085 exit(1);
00086 }
00087 fname(*argv, file);
00088 svcname(file, svc);
00089
00090 fprintf(stderr, "%s -> %s\n", file, svc);
00091
00092 signal(SIGHUP, onintr);
00093 signal(SIGINT, onintr);
00094 signal(SIGTERM, onintr);
00095
00096 #ifndef BSD
00097 if (NULL == (p = strrchr(file, '/')))
00098 p = file;
00099 else
00100 ++p;
00101
00102 if (strlen(p) > 13) {
00103 fprintf(stderr, "ci: filename %s is too long\n", p);
00104 exit(1);
00105 }
00106 #endif
00107
00108 strcpy(newsvc, svc);
00109 *(strrchr(newsvc, ',')) = ';';
00110
00111 if (NULL == (newfp = fopen(newsvc, "w"))) {
00112 perror("ci: can't create SVC temporary");
00113 exit(1);
00114 }
00115 (void) mktemp(original);
00116 (void) mktemp(diffout);
00117
00118 if (NULL != (svcfp = fopen(svc, "r"))) {
00119 fgets(line, LINELEN, svcfp);
00120 if (1 != sscanf(line, "# %d", &rev)) {
00121 fprintf(stderr, "ci: %s: illegal SVC file header\n", svc);
00122 exit(1);
00123 }
00124 ++rev;
00125
00126 if (!lockcheck(svcfp, rev)) {
00127 fprintf(stderr, "Revision %d not locked\n", rev);
00128 clean();
00129 exit(1);
00130 }
00131 if (NULL == (origfp = fopen(original, "w"))) {
00132 fprintf(stderr, "ci: can't create %s", original);
00133 perror(" ");
00134 }
00135 fgets(line, LINELEN, svcfp);
00136
00137 while (NULL != fgets(line, LINELEN, svcfp)
00138 && strcmp(line, "***MAIN-eof***\n")) {
00139 fputs(line, origfp);
00140 if (ferror(origfp)) {
00141 perror("ci: origfile");
00142 exit(1);
00143 }
00144 }
00145 fclose(origfp);
00146
00147 rundiff();
00148
00149 if (0 != stat(original, &stb1) || 0 != stat(diffout, &stb2)) {
00150 perror("ci: can't stat original or diffout");
00151 clean();
00152 exit(1);
00153 }
00154 } else {
00155 rev = 1;
00156 }
00157
00158 fprintf(newfp, "# %d\n", rev);
00159 fprintf(newfp, "cat <<***MAIN-eof*** >$1\n");
00160 if (NULL == (srcfp = fopen(file, "r"))) {
00161 perror("ci: can't read source file");
00162 clean();
00163 exit(1);
00164 }
00165 while (NULL != fgets(line, LINELEN, srcfp)) fputs(line, newfp);
00166 fclose(srcfp);
00167 fputs("***MAIN-eof***\n", newfp);
00168
00169 if (rev > 1) {
00170 fprintf(newfp, "if test $2 -ge %d ; then rm -f Fix.$1 ; exit 0 ; fi ; cat <<***%d-eof*** >Fix.$1\n", rev, rev);
00171 p = (stb1.st_size <= stb2.st_size) ? original : diffout;
00172 if (NULL == (origfp = fopen(p, "r"))) {
00173 perror("can't open diff output file");
00174 clean();
00175 exit(1);
00176 }
00177 while (NULL != fgets(line, LINELEN, origfp)) fputs(line, newfp);
00178 fclose(origfp);
00179 fprintf(newfp, "***%d-eof***\n", rev);
00180 fputs((original == p) ? "mv Fix.$1 $1\n" : FIX, newfp);
00181 logmsg(newfp);
00182 while (NULL != fgets(line, LINELEN, svcfp) && strncmp(line, "#***SVCLOCK***", (size_t)14))
00183 fputs(line, newfp);
00184 } else {
00185 logmsg(newfp);
00186 fputs("rm -f Fix.$1\n", newfp);
00187 }
00188
00189 if (relock) {
00190 fprintf(stderr, "(relocking into revision %d)\n", rev + 1);
00191 fprintf(newfp, "#***SVCLOCK*** %s %d\n", whoami(), rev + 1);
00192 }
00193 signal(SIGHUP, SIG_IGN);
00194 signal(SIGINT, SIG_IGN);
00195
00196 if (ferror(newfp) || fclose(newfp) || ((rev > 1) && unlink(svc))
00197 || link(newsvc, svc)) {
00198 fprintf(stderr, "SVC file write/link error - Checkin aborted\n");
00199 clean();
00200 exit(1);
00201 } else
00202 fprintf(stderr, "Checkin complete.\n");
00203
00204 if (stat(svc, &stb1) < 0 || chmod(svc, stb1.st_mode & 0555) < 0)
00205 perror("ci: can't chmod SVC file");
00206
00207 if (unlocked) {
00208 if (stat(file, &stb1) < 0 || chmod(file, stb1.st_mode & 0555) < 0)
00209 perror("ci: can't chmod source file");
00210 } else if (relock) {
00211 if (stat(file, &stb1) < 0 || chmod(file, stb1.st_mode | 0200) < 0)
00212 perror("ci: can't chmod source file");
00213 } else
00214 unlink(file);
00215
00216 clean();
00217 return(0);
00218 }
00219
00220 void rundiff()
00221 {
00222 int fd;
00223
00224 switch (fork()) {
00225 case -1:
00226 perror("ci: fork");
00227 clean();
00228 exit(1);
00229
00230 case 0:
00231 if ((fd = creat(diffout, 0600)) < 0 || -1 == dup2(fd, 1)) {
00232 perror("ci: diffout");
00233 clean();
00234 exit(1);
00235 }
00236 close(fd);
00237 execlp("diff", "diff", file, original, (char *) 0);
00238 perror("ci: exec diff failed");
00239 exit(1);
00240
00241 default: break;
00242 }
00243 wait(&status);
00244 if (0 != status && 1 << 8 != status) {
00245 fprintf(stderr, "ci: bad return status (0x%x) from diff\n", status);
00246 clean();
00247 exit(1);
00248 }
00249 }
00250
00251 void logmsg(fp)
00252 FILE *fp;
00253 {
00254 long now;
00255
00256 time(&now);
00257 fprintf(stderr, "Enter log message for revision %d (end with ^D or '.'):\n", rev);
00258 fprintf(fp, "#***SVC*** revision %d %s %s", rev, file, ctime(&now));
00259 while (NULL != gets(line) && strcmp(line, "."))
00260 fprintf(fp, "#***SVC*** %s\n", line);
00261 }
00262
00263 void fname(src, dst)
00264 char *src, *dst;
00265 {
00266 char *p;
00267 strcpy(dst, src);
00268 p = &dst[strlen(src) - strlen(SUFFIX)];
00269 if (!strcmp(p, SUFFIX)) *p = '\0';
00270 }
00271
00272 void svcname(src, dst)
00273 char *src, *dst;
00274 {
00275 char *p;
00276
00277 strcpy(dst, src);
00278 strcat(dst, SUFFIX);
00279
00280 if (0 != access(dst, 4)) {
00281 char dirname[PATHLEN];
00282 if (NULL != (p = strrchr(src, '/')))
00283 strncpy(dirname, src, (size_t)(p - src + 1));
00284 else
00285 dirname[0] = '\0';
00286 strcat(dirname, SVCDIR);
00287
00288 if (0 == access(dirname, 1)) {
00289 strcpy(dst, dirname);
00290 if (NULL == p) {
00291 strcat(dst, "/");
00292 strcat(dst, src);
00293 } else
00294 strcat(dst, p);
00295 strcat(dst, SUFFIX);
00296 }
00297 }
00298 }
00299
00300 int lockcheck(fp, rev)
00301 FILE *fp;
00302 int rev;
00303 {
00304 char lock[40], check[40];
00305 long pos;
00306 int ret;
00307
00308 sprintf(lock, "#***SVCLOCK*** %s %d\n", whoami(), rev);
00309
00310 pos = ftell(fp);
00311 fseek(fp, -((long) strlen(lock)), 2);
00312 fgets(check, 40, fp);
00313 ret = (0 == strcmp(lock, check));
00314 fseek(fp, pos, 0);
00315
00316 return ret;
00317 }
00318
00319 void onintr(dummy)
00320 int dummy;
00321 {
00322 fprintf(stderr, "Interrupt - Aborting checkin, cleaning up\n");
00323 clean();
00324 exit(1);
00325 }
00326
00327 void clean()
00328 {
00329 if (strlen(original))
00330 unlink(original);
00331 if (strlen(diffout)) unlink(diffout);
00332 if (strlen(newsvc)) unlink(newsvc);
00333 }
00334
00335 char *whoami()
00336 {
00337 struct passwd *pw;
00338
00339 if (NULL != (pw = getpwuid(getuid())))
00340 return pw->pw_name;
00341 else
00342 return "nobody";
00343 }