Commit | Line | Data |
---|---|---|
1cc2dcec EA |
1 | # include <stdio.h> |
2 | # include <sys/types.h> | |
3 | # include <sys/stat.h> | |
4 | # include <sysexits.h> | |
5 | ||
e672376b | 6 | static char SccsId[] = "@(#)sccs.c 1.8 delta %G% 20:53:30 get %H% %T%"; |
2a0234bf EA |
7 | |
8 | # define bitset(bit, word) ((bit) & (word)) | |
9 | ||
10 | typedef char bool; | |
a97ecd0d EA |
11 | # define TRUE 1 |
12 | # define FALSE 0 | |
81dc6403 | 13 | |
1cc2dcec EA |
14 | struct sccsprog |
15 | { | |
16 | char *sccsname; /* name of SCCS routine */ | |
a97ecd0d EA |
17 | short sccsoper; /* opcode, see below */ |
18 | short sccsflags; /* flags, see below */ | |
1cc2dcec EA |
19 | char *sccspath; /* pathname of binary implementing */ |
20 | }; | |
21 | ||
a97ecd0d EA |
22 | /* values for sccsoper */ |
23 | # define PROG 0 /* call a program */ | |
e672376b | 24 | # define CMACRO 1 /* command substitution macro */ |
a97ecd0d | 25 | |
2a0234bf | 26 | /* bits for sccsflags */ |
a97ecd0d EA |
27 | # define NO_SDOT 0001 /* no s. on front of args */ |
28 | # define REALUSER 0002 /* protected (e.g., admin) */ | |
1cc2dcec EA |
29 | |
30 | struct sccsprog SccsProg[] = | |
31 | { | |
a97ecd0d EA |
32 | "admin", PROG, REALUSER, "/usr/sccs/admin", |
33 | "chghist", PROG, 0, "/usr/sccs/rmdel", | |
34 | "comb", PROG, 0, "/usr/sccs/comb", | |
35 | "delta", PROG, 0, "/usr/sccs/delta", | |
36 | "get", PROG, 0, "/usr/sccs/get", | |
37 | "help", PROG, NO_SDOT, "/usr/sccs/help", | |
38 | "prt", PROG, 0, "/usr/sccs/prt", | |
39 | "rmdel", PROG, REALUSER, "/usr/sccs/rmdel", | |
40 | "what", PROG, NO_SDOT, "/usr/sccs/what", | |
e672376b | 41 | "del", CMACRO, 0, "delta/get", |
a97ecd0d | 42 | NULL, -1, 0, NULL |
1cc2dcec EA |
43 | }; |
44 | ||
2a0234bf | 45 | char *SccsPath = "SCCS"; /* pathname of SCCS files */ |
2a0234bf | 46 | bool RealUser; /* if set, running as real user */ |
1cc2dcec EA |
47 | |
48 | main(argc, argv) | |
49 | int argc; | |
50 | char **argv; | |
51 | { | |
52 | register char *p; | |
1cc2dcec EA |
53 | |
54 | /* | |
55 | ** Detect and decode flags intended for this program. | |
56 | */ | |
57 | ||
a97ecd0d EA |
58 | if (argc < 2) |
59 | { | |
60 | fprintf(stderr, "Usage: sccs [flags] command [flags]\n"); | |
61 | exit(EX_USAGE); | |
62 | } | |
63 | argv[argc] = NULL; | |
64 | ||
65 | while ((p = *++argv) != NULL) | |
1cc2dcec | 66 | { |
1cc2dcec EA |
67 | if (*p != '-') |
68 | break; | |
69 | switch (*++p) | |
70 | { | |
71 | case 'r': /* run as real user */ | |
72 | setuid(getuid()); | |
2a0234bf | 73 | RealUser++; |
1cc2dcec EA |
74 | break; |
75 | ||
76 | case 'p': /* path of sccs files */ | |
77 | SccsPath = ++p; | |
78 | break; | |
79 | ||
80 | default: | |
81 | fprintf(stderr, "Sccs: unknown option -%s\n", p); | |
82 | break; | |
83 | } | |
84 | } | |
833a2471 EA |
85 | if (SccsPath[0] == '\0') |
86 | SccsPath = "."; | |
1cc2dcec | 87 | |
e672376b | 88 | command(argv, FALSE); |
a97ecd0d EA |
89 | exit(EX_OK); |
90 | } | |
91 | ||
e672376b | 92 | command(argv, forkflag) |
a97ecd0d | 93 | char **argv; |
e672376b | 94 | bool forkflag; |
a97ecd0d EA |
95 | { |
96 | register struct sccsprog *cmd; | |
97 | register char *p; | |
e672376b EA |
98 | register char *q; |
99 | char buf[40]; | |
2a0234bf | 100 | |
1cc2dcec EA |
101 | /* |
102 | ** Look up command. | |
a97ecd0d | 103 | ** At this point, argv points to the command name. |
1cc2dcec EA |
104 | */ |
105 | ||
a97ecd0d | 106 | p = *argv; |
1cc2dcec EA |
107 | for (cmd = SccsProg; cmd->sccsname != NULL; cmd++) |
108 | { | |
109 | if (strcmp(cmd->sccsname, p) == 0) | |
110 | break; | |
111 | } | |
112 | if (cmd->sccsname == NULL) | |
113 | { | |
114 | fprintf(stderr, "Sccs: Unknown command \"%s\"\n", p); | |
115 | exit(EX_USAGE); | |
116 | } | |
117 | ||
2a0234bf | 118 | /* |
a97ecd0d | 119 | ** Interpret operation associated with this command. |
2a0234bf EA |
120 | */ |
121 | ||
a97ecd0d EA |
122 | switch (cmd->sccsoper) |
123 | { | |
124 | case PROG: /* call an sccs prog */ | |
e672376b EA |
125 | callprog(cmd->sccspath, cmd->sccsflags, argv, forkflag); |
126 | break; | |
127 | ||
128 | case CMACRO: /* command macro */ | |
129 | for (p = cmd->sccspath; *p != '\0'; p++) | |
130 | { | |
131 | for (q = buf; *p != '/' && *p != '\0'; p++, q++) | |
132 | *q = *p; | |
133 | *q = '\0'; | |
134 | argv[0] = buf; | |
135 | command(argv, *p != '\0'); | |
136 | } | |
137 | fprintf(stderr, "Sccs internal error: CMACRO\n"); | |
a97ecd0d EA |
138 | exit(EX_SOFTWARE); |
139 | ||
140 | default: | |
141 | fprintf(stderr, "Sccs internal error: oper %d\n", cmd->sccsoper); | |
142 | exit(EX_SOFTWARE); | |
143 | } | |
144 | } | |
145 | ||
146 | callprog(progpath, flags, argv, forkflag) | |
147 | char *progpath; | |
148 | short flags; | |
149 | char **argv; | |
150 | bool forkflag; | |
151 | { | |
152 | register char *p; | |
153 | register char **av; | |
154 | char *newargv[1000]; | |
155 | extern char *makefile(); | |
156 | register int i; | |
e672376b | 157 | auto int st; |
a97ecd0d EA |
158 | |
159 | if (*argv == NULL) | |
160 | return (-1); | |
2a0234bf | 161 | |
1cc2dcec EA |
162 | /* |
163 | ** Build new argument vector. | |
1cc2dcec EA |
164 | */ |
165 | ||
1cc2dcec | 166 | av = newargv; |
a97ecd0d | 167 | *av++ = *argv; |
1cc2dcec | 168 | |
1859e236 | 169 | /* copy program filename arguments and flags */ |
a97ecd0d | 170 | while ((p = *++argv) != NULL) |
1cc2dcec | 171 | { |
a97ecd0d | 172 | if (!bitset(NO_SDOT, flags) && *p != '-') |
1859e236 | 173 | *av++ = makefile(p); |
1cc2dcec | 174 | else |
1859e236 | 175 | *av++ = p; |
1cc2dcec EA |
176 | } |
177 | ||
178 | /* terminate argument vector */ | |
179 | *av = NULL; | |
180 | ||
181 | /* | |
182 | ** Call real SCCS program. | |
183 | */ | |
184 | ||
a97ecd0d EA |
185 | if (forkflag) |
186 | { | |
187 | i = fork(); | |
188 | if (i < 0) | |
189 | { | |
190 | fprintf(stderr, "Sccs: cannot fork"); | |
191 | exit(EX_OSERR); | |
192 | } | |
193 | else if (i > 0) | |
e672376b EA |
194 | { |
195 | wait(&st); | |
196 | return (st); | |
197 | } | |
a97ecd0d EA |
198 | } |
199 | ||
200 | /* | |
201 | ** Set protection as appropriate. | |
202 | */ | |
203 | ||
204 | if (bitset(REALUSER, flags)) | |
205 | setuid(getuid()); | |
206 | ||
207 | /* | |
208 | ** Call the program. | |
209 | */ | |
210 | ||
211 | execv(progpath, newargv); | |
1cc2dcec | 212 | fprintf(stderr, "Sccs: cannot execute "); |
a97ecd0d | 213 | perror(progpath); |
1cc2dcec EA |
214 | exit(EX_UNAVAILABLE); |
215 | } | |
216 | ||
217 | ||
218 | char * | |
219 | makefile(name) | |
220 | char *name; | |
221 | { | |
222 | register char *p; | |
223 | register char c; | |
224 | char buf[512]; | |
225 | struct stat stbuf; | |
226 | extern char *malloc(); | |
227 | ||
228 | /* | |
229 | ** See if this filename should be used as-is. | |
230 | ** There are three conditions where this can occur. | |
231 | ** 1. The name already begins with "s.". | |
232 | ** 2. The name has a "/" in it somewhere. | |
233 | ** 3. The name references a directory. | |
234 | */ | |
235 | ||
236 | if (strncmp(name, "s.", 2) == 0) | |
237 | return (name); | |
238 | for (p = name; (c = *p) != '\0'; p++) | |
239 | { | |
240 | if (c == '/') | |
241 | return (name); | |
242 | } | |
243 | if (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) | |
244 | return (name); | |
245 | ||
246 | /* | |
247 | ** Prepend the path of the sccs file. | |
248 | */ | |
249 | ||
250 | strcpy(buf, SccsPath); | |
2a0234bf | 251 | strcat(buf, "/s."); |
1cc2dcec EA |
252 | strcat(buf, name); |
253 | p = malloc(strlen(buf) + 1); | |
254 | if (p == NULL) | |
255 | { | |
256 | perror("Sccs: no mem"); | |
257 | exit(EX_OSERR); | |
258 | } | |
259 | strcpy(p, buf); | |
260 | return (p); | |
261 | } |