source: trunk/minix/commands/simple/ci.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 7.8 KB
Line 
1/* ci - check in Author: Peter S. Housel 12/17/87 */
2
3#include <sys/types.h>
4#include <string.h>
5#include <sys/stat.h>
6#include <pwd.h>
7#include <signal.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <time.h>
11#include <fcntl.h>
12#include <sys/wait.h>
13#include <stdio.h>
14
15#define SUFFIX ",S" /* svc indicator */
16#define SVCDIR "SVC" /* svc postfix indicator */
17
18#define LINELEN 256 /* maximum line length */
19
20#ifndef PATCH
21#define FIX "fix $1 Fix.$1 > New.$1; mv New.$1 $1\n"
22#else
23#define FIX "patch -n -s $1 < Fix.$1; rm -f $1.orig\n"
24#endif /* !PATCH */
25
26#ifdef MAXPATHLEN
27#define PATHLEN MAXPATHLEN
28#else
29#define PATHLEN 128 /* buffer length for filenames */
30#endif
31
32int unlocked = 0; /* leave unlocked after checkin */
33int relock = 0; /* lock next revision after checkin */
34char file[PATHLEN]; /* file to be checked in */
35char svc[PATHLEN]; /* filename for svc file */
36char newsvc[PATHLEN]; /* new copy of SVC file */
37char line[LINELEN]; /* temporary line buffer */
38char *p; /* scratch character pointer */
39
40FILE *svcfp; /* svc file */
41FILE *origfp, *newfp; /* "orig" and "new" temp files */
42FILE *srcfp; /* source file */
43int rev; /* new revision number */
44int status; /* wait() buffer */
45struct stat stb1, stb2; /* stat buffers for size compare */
46char original[] = "/tmp/cioXXXXXX"; /* previous revision */
47char diffout[] = "/tmp/cidXXXXXX"; /* diffs */
48
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));
58
59int main(argc, argv)
60int argc;
61char **argv;
62{
63#ifdef perprintf
64 char errbuf[BUFSIZ];
65 setbuf(stderr, errbuf);
66 perprintf(stderr);
67#endif
68
69 while (++argv, --argc) {
70 if ('-' == (*argv)[0]) {
71 if ('u' == (*argv)[1])
72 ++unlocked;
73 else if ('l' == (*argv)[1])
74 ++relock;
75 else {
76 fprintf(stderr, "ci: illegal option -%c\n", (*argv)[1]);
77 exit(1);
78 }
79 } else
80 break;
81 }
82
83 if (1 != argc) {
84 fprintf(stderr, "ci: bad number of files arguments\n");
85 exit(1);
86 }
87 fname(*argv, file);
88 svcname(file, svc);
89
90 fprintf(stderr, "%s -> %s\n", file, svc);
91
92 signal(SIGHUP, onintr);
93 signal(SIGINT, onintr);
94 signal(SIGTERM, onintr);
95
96#ifndef BSD
97 if (NULL == (p = strrchr(file, '/')))
98 p = file;
99 else
100 ++p;
101
102 if (strlen(p) > 13) {
103 fprintf(stderr, "ci: filename %s is too long\n", p);
104 exit(1);
105 }
106#endif /* !BSD */
107
108 strcpy(newsvc, svc);
109 *(strrchr(newsvc, ',')) = ';'; /* temporary file will be "file;S" */
110
111 if (NULL == (newfp = fopen(newsvc, "w"))) {
112 perror("ci: can't create SVC temporary");
113 exit(1);
114 }
115 (void) mktemp(original);
116 (void) mktemp(diffout);
117
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);
122 exit(1);
123 }
124 ++rev;
125
126 if (!lockcheck(svcfp, rev)) {
127 fprintf(stderr, "Revision %d not locked\n", rev);
128 clean();
129 exit(1);
130 }
131 if (NULL == (origfp = fopen(original, "w"))) {
132 fprintf(stderr, "ci: can't create %s", original);
133 perror(" ");
134 }
135 fgets(line, LINELEN, svcfp); /* skip "cat <<***MAIN-eof***" line */
136
137 while (NULL != fgets(line, LINELEN, svcfp)
138 && strcmp(line, "***MAIN-eof***\n")) {
139 fputs(line, origfp);
140 if (ferror(origfp)) {
141 perror("ci: origfile");
142 exit(1);
143 }
144 }
145 fclose(origfp);
146
147 rundiff();
148
149 if (0 != stat(original, &stb1) || 0 != stat(diffout, &stb2)) {
150 perror("ci: can't stat original or diffout");
151 clean();
152 exit(1);
153 }
154 } else { /* no - create one */
155 rev = 1;
156 }
157
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");
162 clean();
163 exit(1);
164 }
165 while (NULL != fgets(line, LINELEN, srcfp)) fputs(line, newfp);
166 fclose(srcfp);
167 fputs("***MAIN-eof***\n", newfp);
168
169 if (rev > 1) {
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");
174 clean();
175 exit(1);
176 }
177 while (NULL != fgets(line, LINELEN, origfp)) fputs(line, newfp);
178 fclose(origfp);
179 fprintf(newfp, "***%d-eof***\n", rev);
180 fputs((original == p) ? "mv Fix.$1 $1\n" : FIX, newfp);
181 logmsg(newfp);
182 while (NULL != fgets(line, LINELEN, svcfp) && strncmp(line, "#***SVCLOCK***", (size_t)14))
183 fputs(line, newfp);
184 } else {
185 logmsg(newfp);
186 fputs("rm -f Fix.$1\n", newfp);
187 }
188
189 if (relock) {
190 fprintf(stderr, "(relocking into revision %d)\n", rev + 1);
191 fprintf(newfp, "#***SVCLOCK*** %s %d\n", whoami(), rev + 1);
192 }
193 signal(SIGHUP, SIG_IGN); /* disable during critical section */
194 signal(SIGINT, SIG_IGN);
195
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");
199 clean();
200 exit(1);
201 } else
202 fprintf(stderr, "Checkin complete.\n");
203
204 if (stat(svc, &stb1) < 0 || chmod(svc, stb1.st_mode & 0555) < 0)
205 perror("ci: can't chmod SVC file");
206
207 if (unlocked) {
208 if (stat(file, &stb1) < 0 || chmod(file, stb1.st_mode & 0555) < 0)
209 perror("ci: can't chmod source file");
210 } else if (relock) {
211 if (stat(file, &stb1) < 0 || chmod(file, stb1.st_mode | 0200) < 0)
212 perror("ci: can't chmod source file");
213 } else
214 unlink(file);
215
216 clean();
217 return(0);
218}
219
220void rundiff()
221{ /* do "diff file original > diffout" */
222 int fd; /* redirected output file */
223
224 switch (fork()) {
225 case -1:
226 perror("ci: fork"); /* error */
227 clean();
228 exit(1);
229
230 case 0: /* child */
231 if ((fd = creat(diffout, 0600)) < 0 || -1 == dup2(fd, 1)) {
232 perror("ci: diffout");
233 clean();
234 exit(1);
235 }
236 close(fd);
237 execlp("diff", "diff", file, original, (char *) 0);
238 perror("ci: exec diff failed");
239 exit(1);
240
241 default: break; /* parent */
242}
243 wait(&status);
244 if (0 != status && 1 << 8 != status) {
245 fprintf(stderr, "ci: bad return status (0x%x) from diff\n", status);
246 clean();
247 exit(1);
248 }
249}
250
251void logmsg(fp)
252FILE *fp;
253{
254 long now;
255
256 time(&now);
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);
261}
262
263void fname(src, dst)
264char *src, *dst;
265{
266 char *p;
267 strcpy(dst, src);
268 p = &dst[strlen(src) - strlen(SUFFIX)];
269 if (!strcmp(p, SUFFIX)) *p = '\0';
270}
271
272void svcname(src, dst)
273char *src, *dst;
274{
275 char *p;
276
277 strcpy(dst, src);
278 strcat(dst, SUFFIX);
279
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));
284 else
285 dirname[0] = '\0';
286 strcat(dirname, SVCDIR);
287
288 if (0 == access(dirname, 1)) {
289 strcpy(dst, dirname);
290 if (NULL == p) {
291 strcat(dst, "/");
292 strcat(dst, src);
293 } else
294 strcat(dst, p);
295 strcat(dst, SUFFIX);
296 }
297 }
298}
299
300int lockcheck(fp, rev)
301FILE *fp;
302int rev;
303{
304 char lock[40], check[40];
305 long pos;
306 int ret;
307
308 sprintf(lock, "#***SVCLOCK*** %s %d\n", whoami(), rev);
309
310 pos = ftell(fp);
311 fseek(fp, -((long) strlen(lock)), 2);
312 fgets(check, 40, fp);
313 ret = (0 == strcmp(lock, check));
314 fseek(fp, pos, 0);
315
316 return ret;
317}
318
319void onintr(dummy)
320int dummy; /* to keep the compiler happy */
321{
322 fprintf(stderr, "Interrupt - Aborting checkin, cleaning up\n");
323 clean();
324 exit(1);
325}
326
327void clean()
328{
329 if (strlen(original)) /* if only more programs made this check! */
330 unlink(original);
331 if (strlen(diffout)) unlink(diffout);
332 if (strlen(newsvc)) unlink(newsvc);
333}
334
335char *whoami()
336{
337 struct passwd *pw;
338
339 if (NULL != (pw = getpwuid(getuid())))
340 return pw->pw_name;
341 else
342 return "nobody";
343}
Note: See TracBrowser for help on using the repository browser.