1 /* ci - check in Author: Peter S. Housel 12/17/87 */
15 #define SUFFIX ",S" /* svc indicator */
16 #define SVCDIR "SVC" /* svc postfix indicator */
18 #define LINELEN 256 /* maximum line length */
21 #define FIX "fix $1 Fix.$1 > New.$1; mv New.$1 $1\n"
23 #define FIX "patch -n -s $1 < Fix.$1; rm -f $1.orig\n"
27 #define PATHLEN MAXPATHLEN
29 #define PATHLEN 128 /* buffer length for filenames */
32 int unlocked
= 0; /* leave unlocked after checkin */
33 int relock
= 0; /* lock next revision after checkin */
34 char file
[PATHLEN
]; /* file to be checked in */
35 char svc
[PATHLEN
]; /* filename for svc file */
36 char newsvc
[PATHLEN
]; /* new copy of SVC file */
37 char line
[LINELEN
]; /* temporary line buffer */
38 char *p
; /* scratch character pointer */
40 FILE *svcfp
; /* svc file */
41 FILE *origfp
, *newfp
; /* "orig" and "new" temp files */
42 FILE *srcfp
; /* source file */
43 int rev
; /* new revision number */
44 int status
; /* wait() buffer */
45 struct stat stb1
, stb2
; /* stat buffers for size compare */
46 char original
[] = "/tmp/cioXXXXXX"; /* previous revision */
47 char diffout
[] = "/tmp/cidXXXXXX"; /* diffs */
49 _PROTOTYPE(int main
, (int argc
, char **argv
));
50 _PROTOTYPE(void rundiff
, (void));
51 _PROTOTYPE(void logmsg
, (FILE *fp
));
52 _PROTOTYPE(void fname
, (char *src
, char *dst
));
53 _PROTOTYPE(void svcname
, (char *src
, char *dst
));
54 _PROTOTYPE(int lockcheck
, (FILE *fp
, int rev
));
55 _PROTOTYPE(void onintr
, (int dummy
));
56 _PROTOTYPE(void clean
, (void));
57 _PROTOTYPE(char *whoami
, (void));
65 setbuf(stderr
, errbuf
);
69 while (++argv
, --argc
) {
70 if ('-' == (*argv
)[0]) {
71 if ('u' == (*argv
)[1])
73 else if ('l' == (*argv
)[1])
76 fprintf(stderr
, "ci: illegal option -%c\n", (*argv
)[1]);
84 fprintf(stderr
, "ci: bad number of files arguments\n");
90 fprintf(stderr
, "%s -> %s\n", file
, svc
);
92 signal(SIGHUP
, onintr
);
93 signal(SIGINT
, onintr
);
94 signal(SIGTERM
, onintr
);
97 if (NULL
== (p
= strrchr(file
, '/')))
102 if (strlen(p
) > 13) {
103 fprintf(stderr
, "ci: filename %s is too long\n", p
);
109 *(strrchr(newsvc
, ',')) = ';'; /* temporary file will be "file;S" */
111 if (NULL
== (newfp
= fopen(newsvc
, "w"))) {
112 perror("ci: can't create SVC temporary");
115 (void) mktemp(original
);
116 (void) mktemp(diffout
);
118 if (NULL
!= (svcfp
= fopen(svc
, "r"))) { /* does svc-file exist? */
119 fgets(line
, LINELEN
, svcfp
);
120 if (1 != sscanf(line
, "# %d", &rev
)) {
121 fprintf(stderr
, "ci: %s: illegal SVC file header\n", svc
);
126 if (!lockcheck(svcfp
, rev
)) {
127 fprintf(stderr
, "Revision %d not locked\n", rev
);
131 if (NULL
== (origfp
= fopen(original
, "w"))) {
132 fprintf(stderr
, "ci: can't create %s", original
);
135 fgets(line
, LINELEN
, svcfp
); /* skip "cat <<***MAIN-eof***" line */
137 while (NULL
!= fgets(line
, LINELEN
, svcfp
)
138 && strcmp(line
, "***MAIN-eof***\n")) {
140 if (ferror(origfp
)) {
141 perror("ci: origfile");
149 if (0 != stat(original
, &stb1
) || 0 != stat(diffout
, &stb2
)) {
150 perror("ci: can't stat original or diffout");
154 } else { /* no - create one */
158 fprintf(newfp
, "# %d\n", rev
);
159 fprintf(newfp
, "cat <<***MAIN-eof*** >$1\n");
160 if (NULL
== (srcfp
= fopen(file
, "r"))) {
161 perror("ci: can't read source file");
165 while (NULL
!= fgets(line
, LINELEN
, srcfp
)) fputs(line
, newfp
);
167 fputs("***MAIN-eof***\n", newfp
);
170 fprintf(newfp
, "if test $2 -ge %d ; then rm -f Fix.$1 ; exit 0 ; fi ; cat <<***%d-eof*** >Fix.$1\n", rev
, rev
);
171 p
= (stb1
.st_size
<= stb2
.st_size
) ? original
: diffout
;
172 if (NULL
== (origfp
= fopen(p
, "r"))) {
173 perror("can't open diff output file");
177 while (NULL
!= fgets(line
, LINELEN
, origfp
)) fputs(line
, newfp
);
179 fprintf(newfp
, "***%d-eof***\n", rev
);
180 fputs((original
== p
) ? "mv Fix.$1 $1\n" : FIX
, newfp
);
182 while (NULL
!= fgets(line
, LINELEN
, svcfp
) && strncmp(line
, "#***SVCLOCK***", (size_t)14))
186 fputs("rm -f Fix.$1\n", newfp
);
190 fprintf(stderr
, "(relocking into revision %d)\n", rev
+ 1);
191 fprintf(newfp
, "#***SVCLOCK*** %s %d\n", whoami(), rev
+ 1);
193 signal(SIGHUP
, SIG_IGN
); /* disable during critical section */
194 signal(SIGINT
, SIG_IGN
);
196 if (ferror(newfp
) || fclose(newfp
) || ((rev
> 1) && unlink(svc
))
197 || link(newsvc
, svc
)) {
198 fprintf(stderr
, "SVC file write/link error - Checkin aborted\n");
202 fprintf(stderr
, "Checkin complete.\n");
204 if (stat(svc
, &stb1
) < 0 || chmod(svc
, stb1
.st_mode
& 0555) < 0)
205 perror("ci: can't chmod SVC file");
208 if (stat(file
, &stb1
) < 0 || chmod(file
, stb1
.st_mode
& 0555) < 0)
209 perror("ci: can't chmod source file");
211 if (stat(file
, &stb1
) < 0 || chmod(file
, stb1
.st_mode
| 0200) < 0)
212 perror("ci: can't chmod source file");
221 { /* do "diff file original > diffout" */
222 int fd
; /* redirected output file */
226 perror("ci: fork"); /* error */
231 if ((fd
= creat(diffout
, 0600)) < 0 || -1 == dup2(fd
, 1)) {
232 perror("ci: diffout");
237 execlp("diff", "diff", file
, original
, (char *) 0);
238 perror("ci: exec diff failed");
241 default: break; /* parent */
244 if (0 != status
&& 1 << 8 != status
) {
245 fprintf(stderr
, "ci: bad return status (0x%x) from diff\n", status
);
257 fprintf(stderr
, "Enter log message for revision %d (end with ^D or '.'):\n", rev
);
258 fprintf(fp
, "#***SVC*** revision %d %s %s", rev
, file
, ctime(&now
));
259 while (NULL
!= gets(line
) && strcmp(line
, "."))
260 fprintf(fp
, "#***SVC*** %s\n", line
);
268 p
= &dst
[strlen(src
) - strlen(SUFFIX
)];
269 if (!strcmp(p
, SUFFIX
)) *p
= '\0';
272 void svcname(src
, dst
)
280 if (0 != access(dst
, 4)) {
281 char dirname
[PATHLEN
];
282 if (NULL
!= (p
= strrchr(src
, '/')))
283 strncpy(dirname
, src
, (size_t)(p
- src
+ 1));
286 strcat(dirname
, SVCDIR
);
288 if (0 == access(dirname
, 1)) {
289 strcpy(dst
, dirname
);
300 int lockcheck(fp
, rev
)
304 char lock
[40], check
[40];
308 sprintf(lock
, "#***SVCLOCK*** %s %d\n", whoami(), rev
);
311 fseek(fp
, -((long) strlen(lock
)), 2);
312 fgets(check
, 40, fp
);
313 ret
= (0 == strcmp(lock
, check
));
320 int dummy
; /* to keep the compiler happy */
322 fprintf(stderr
, "Interrupt - Aborting checkin, cleaning up\n");
329 if (strlen(original
)) /* if only more programs made this check! */
331 if (strlen(diffout
)) unlink(diffout
);
332 if (strlen(newsvc
)) unlink(newsvc
);
339 if (NULL
!= (pw
= getpwuid(getuid())))