added "del" macro
[unix-history] / usr / src / usr.bin / sccs / sccs.c
CommitLineData
1cc2dcec
EA
1# include <stdio.h>
2# include <sys/types.h>
3# include <sys/stat.h>
4# include <sysexits.h>
5
e672376b 6static 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
10typedef char bool;
a97ecd0d
EA
11# define TRUE 1
12# define FALSE 0
81dc6403 13
1cc2dcec
EA
14struct 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
30struct 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 45char *SccsPath = "SCCS"; /* pathname of SCCS files */
2a0234bf 46bool RealUser; /* if set, running as real user */
1cc2dcec
EA
47
48main(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 92command(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
146callprog(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
218char *
219makefile(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}