ci.c

Go to the documentation of this file.
00001 /* ci - check in                        Author: Peter S. Housel 12/17/87 */
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"    /* svc indicator */
00016 #define SVCDIR          "SVC"   /* svc postfix indicator */
00017 
00018 #define LINELEN         256     /* maximum line length */
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 /* !PATCH */
00025 
00026 #ifdef MAXPATHLEN
00027 #define PATHLEN MAXPATHLEN
00028 #else
00029 #define PATHLEN 128             /* buffer length for filenames */
00030 #endif
00031 
00032 int unlocked = 0;               /* leave unlocked after checkin */
00033 int relock = 0;                 /* lock next revision after checkin */
00034 char file[PATHLEN];             /* file to be checked in */
00035 char svc[PATHLEN];              /* filename for svc file */
00036 char newsvc[PATHLEN];           /* new copy of SVC file */
00037 char line[LINELEN];             /* temporary line buffer */
00038 char *p;                        /* scratch character pointer */
00039 
00040 FILE *svcfp;                    /* svc file */
00041 FILE *origfp, *newfp;           /* "orig" and "new" temp files */
00042 FILE *srcfp;                    /* source file */
00043 int rev;                        /* new revision number */
00044 int status;                     /* wait() buffer */
00045 struct stat stb1, stb2;         /* stat buffers for size compare */
00046 char original[] = "/tmp/cioXXXXXX";     /* previous revision */
00047 char diffout[] = "/tmp/cidXXXXXX";      /* diffs */
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 /* !BSD */
00107 
00108   strcpy(newsvc, svc);
00109   *(strrchr(newsvc, ',')) = ';';        /* temporary file will be "file;S" */
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"))) {      /* does svc-file exist? */
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);    /* skip "cat <<***MAIN-eof***" line */
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 {                      /* no - create one */
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);      /* disable during critical section */
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 {                               /* do "diff file original > diffout" */
00222   int fd;                       /* redirected output file */
00223 
00224   switch (fork()) {
00225       case -1:
00226         perror("ci: fork");     /* error */
00227         clean();
00228         exit(1);
00229 
00230       case 0:                   /* child */
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;          /* parent */
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; /* to keep the compiler happy */
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))         /* if only more programs made this check! */
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 }

Generated on Fri Apr 14 22:57:04 2006 for minix by  doxygen 1.4.6