xref: /csrg-svn/usr.bin/sccs/sccs.c (revision 201)
1148Seric # include <stdio.h>
2148Seric # include <sys/types.h>
3148Seric # include <sys/stat.h>
4148Seric # include <sysexits.h>
5148Seric 
6*201Seric static char SccsId[] = "@(#)sccs.c 1.8 delta 05/22/80 20:53:30 get 10/14/12 16:33:34";
7155Seric 
8157Seric # define bitset(bit, word)	((bit) & (word))
9157Seric 
10157Seric typedef char	bool;
11200Seric # define TRUE	1
12200Seric # define FALSE	0
13157Seric 
14148Seric struct sccsprog
15148Seric {
16148Seric 	char	*sccsname;	/* name of SCCS routine */
17200Seric 	short	sccsoper;	/* opcode, see below */
18200Seric 	short	sccsflags;	/* flags, see below */
19148Seric 	char	*sccspath;	/* pathname of binary implementing */
20148Seric };
21148Seric 
22200Seric /* values for sccsoper */
23200Seric # define PROG		0	/* call a program */
24*201Seric # define CMACRO		1	/* command substitution macro */
25200Seric 
26157Seric /* bits for sccsflags */
27200Seric # define NO_SDOT	0001	/* no s. on front of args */
28200Seric # define REALUSER	0002	/* protected (e.g., admin) */
29148Seric 
30148Seric struct sccsprog SccsProg[] =
31148Seric {
32200Seric 	"admin",	PROG,	REALUSER,		"/usr/sccs/admin",
33200Seric 	"chghist",	PROG,	0,			"/usr/sccs/rmdel",
34200Seric 	"comb",		PROG,	0,			"/usr/sccs/comb",
35200Seric 	"delta",	PROG,	0,			"/usr/sccs/delta",
36200Seric 	"get",		PROG,	0,			"/usr/sccs/get",
37200Seric 	"help",		PROG,	NO_SDOT,		"/usr/sccs/help",
38200Seric 	"prt",		PROG,	0,			"/usr/sccs/prt",
39200Seric 	"rmdel",	PROG,	REALUSER,		"/usr/sccs/rmdel",
40200Seric 	"what",		PROG,	NO_SDOT,		"/usr/sccs/what",
41*201Seric 	"del",		CMACRO,	0,			"delta/get",
42200Seric 	NULL,		-1,	0,			NULL
43148Seric };
44148Seric 
45157Seric char	*SccsPath = "SCCS";	/* pathname of SCCS files */
46157Seric bool	RealUser;		/* if set, running as real user */
47148Seric 
48148Seric main(argc, argv)
49148Seric 	int argc;
50148Seric 	char **argv;
51148Seric {
52148Seric 	register char *p;
53148Seric 
54148Seric 	/*
55148Seric 	**  Detect and decode flags intended for this program.
56148Seric 	*/
57148Seric 
58200Seric 	if (argc < 2)
59148Seric 	{
60200Seric 		fprintf(stderr, "Usage: sccs [flags] command [flags]\n");
61200Seric 		exit(EX_USAGE);
62200Seric 	}
63200Seric 	argv[argc] = NULL;
64200Seric 
65200Seric 	while ((p = *++argv) != NULL)
66200Seric 	{
67148Seric 		if (*p != '-')
68148Seric 			break;
69148Seric 		switch (*++p)
70148Seric 		{
71148Seric 		  case 'r':		/* run as real user */
72148Seric 			setuid(getuid());
73157Seric 			RealUser++;
74148Seric 			break;
75148Seric 
76148Seric 		  case 'p':		/* path of sccs files */
77148Seric 			SccsPath = ++p;
78148Seric 			break;
79148Seric 
80148Seric 		  default:
81148Seric 			fprintf(stderr, "Sccs: unknown option -%s\n", p);
82148Seric 			break;
83148Seric 		}
84148Seric 	}
85158Seric 	if (SccsPath[0] == '\0')
86158Seric 		SccsPath = ".";
87148Seric 
88*201Seric 	command(argv, FALSE);
89200Seric 	exit(EX_OK);
90200Seric }
91157Seric 
92*201Seric command(argv, forkflag)
93200Seric 	char **argv;
94*201Seric 	bool forkflag;
95200Seric {
96200Seric 	register struct sccsprog *cmd;
97200Seric 	register char *p;
98*201Seric 	register char *q;
99*201Seric 	char buf[40];
100200Seric 
101157Seric 	/*
102148Seric 	**  Look up command.
103200Seric 	**	At this point, argv points to the command name.
104148Seric 	*/
105148Seric 
106200Seric 	p = *argv;
107148Seric 	for (cmd = SccsProg; cmd->sccsname != NULL; cmd++)
108148Seric 	{
109148Seric 		if (strcmp(cmd->sccsname, p) == 0)
110148Seric 			break;
111148Seric 	}
112148Seric 	if (cmd->sccsname == NULL)
113148Seric 	{
114148Seric 		fprintf(stderr, "Sccs: Unknown command \"%s\"\n", p);
115148Seric 		exit(EX_USAGE);
116148Seric 	}
117148Seric 
118148Seric 	/*
119200Seric 	**  Interpret operation associated with this command.
120157Seric 	*/
121157Seric 
122200Seric 	switch (cmd->sccsoper)
123200Seric 	{
124200Seric 	  case PROG:		/* call an sccs prog */
125*201Seric 		callprog(cmd->sccspath, cmd->sccsflags, argv, forkflag);
126*201Seric 		break;
127*201Seric 
128*201Seric 	  case CMACRO:		/* command macro */
129*201Seric 		for (p = cmd->sccspath; *p != '\0'; p++)
130*201Seric 		{
131*201Seric 			for (q = buf; *p != '/' && *p != '\0'; p++, q++)
132*201Seric 				*q = *p;
133*201Seric 			*q = '\0';
134*201Seric 			argv[0] = buf;
135*201Seric 			command(argv, *p != '\0');
136*201Seric 		}
137*201Seric 		fprintf(stderr, "Sccs internal error: CMACRO\n");
138200Seric 		exit(EX_SOFTWARE);
139157Seric 
140200Seric 	  default:
141200Seric 		fprintf(stderr, "Sccs internal error: oper %d\n", cmd->sccsoper);
142200Seric 		exit(EX_SOFTWARE);
143200Seric 	}
144200Seric }
145200Seric 
146200Seric callprog(progpath, flags, argv, forkflag)
147200Seric 	char *progpath;
148200Seric 	short flags;
149200Seric 	char **argv;
150200Seric 	bool forkflag;
151200Seric {
152200Seric 	register char *p;
153200Seric 	register char **av;
154200Seric 	char *newargv[1000];
155200Seric 	extern char *makefile();
156200Seric 	register int i;
157*201Seric 	auto int st;
158200Seric 
159200Seric 	if (*argv == NULL)
160200Seric 		return (-1);
161200Seric 
162157Seric 	/*
163148Seric 	**  Build new argument vector.
164148Seric 	*/
165148Seric 
166148Seric 	av = newargv;
167200Seric 	*av++ = *argv;
168148Seric 
169153Seric 	/* copy program filename arguments and flags */
170200Seric 	while ((p = *++argv) != NULL)
171148Seric 	{
172200Seric 		if (!bitset(NO_SDOT, flags) && *p != '-')
173153Seric 			*av++ = makefile(p);
174148Seric 		else
175153Seric 			*av++ = p;
176148Seric 	}
177148Seric 
178148Seric 	/* terminate argument vector */
179148Seric 	*av = NULL;
180148Seric 
181148Seric 	/*
182148Seric 	**  Call real SCCS program.
183148Seric 	*/
184148Seric 
185200Seric 	if (forkflag)
186200Seric 	{
187200Seric 		i = fork();
188200Seric 		if (i < 0)
189200Seric 		{
190200Seric 			fprintf(stderr, "Sccs: cannot fork");
191200Seric 			exit(EX_OSERR);
192200Seric 		}
193200Seric 		else if (i > 0)
194*201Seric 		{
195*201Seric 			wait(&st);
196*201Seric 			return (st);
197*201Seric 		}
198200Seric 	}
199200Seric 
200200Seric 	/*
201200Seric 	**  Set protection as appropriate.
202200Seric 	*/
203200Seric 
204200Seric 	if (bitset(REALUSER, flags))
205200Seric 		setuid(getuid());
206200Seric 
207200Seric 	/*
208200Seric 	**  Call the program.
209200Seric 	*/
210200Seric 
211200Seric 	execv(progpath, newargv);
212148Seric 	fprintf(stderr, "Sccs: cannot execute ");
213200Seric 	perror(progpath);
214148Seric 	exit(EX_UNAVAILABLE);
215148Seric }
216148Seric 
217148Seric 
218148Seric char *
219148Seric makefile(name)
220148Seric 	char *name;
221148Seric {
222148Seric 	register char *p;
223148Seric 	register char c;
224148Seric 	char buf[512];
225148Seric 	struct stat stbuf;
226148Seric 	extern char *malloc();
227148Seric 
228148Seric 	/*
229148Seric 	**  See if this filename should be used as-is.
230148Seric 	**	There are three conditions where this can occur.
231148Seric 	**	1. The name already begins with "s.".
232148Seric 	**	2. The name has a "/" in it somewhere.
233148Seric 	**	3. The name references a directory.
234148Seric 	*/
235148Seric 
236148Seric 	if (strncmp(name, "s.", 2) == 0)
237148Seric 		return (name);
238148Seric 	for (p = name; (c = *p) != '\0'; p++)
239148Seric 	{
240148Seric 		if (c == '/')
241148Seric 			return (name);
242148Seric 	}
243148Seric 	if (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR)
244148Seric 		return (name);
245148Seric 
246148Seric 	/*
247148Seric 	**  Prepend the path of the sccs file.
248148Seric 	*/
249148Seric 
250148Seric 	strcpy(buf, SccsPath);
251157Seric 	strcat(buf, "/s.");
252148Seric 	strcat(buf, name);
253148Seric 	p = malloc(strlen(buf) + 1);
254148Seric 	if (p == NULL)
255148Seric 	{
256148Seric 		perror("Sccs: no mem");
257148Seric 		exit(EX_OSERR);
258148Seric 	}
259148Seric 	strcpy(p, buf);
260148Seric 	return (p);
261148Seric }
262