1148Seric # include <stdio.h> 2148Seric # include <sys/types.h> 3148Seric # include <sys/stat.h> 4148Seric # include <sysexits.h> 5*202Seric # include <whoami.h> 6148Seric 7*202Seric static char SccsId[] = "@(#)sccs.c 1.9 delta 05/23/80 12:31:38 get 10/14/12 16:33:34"; 8155Seric 9157Seric # define bitset(bit, word) ((bit) & (word)) 10157Seric 11157Seric typedef char bool; 12200Seric # define TRUE 1 13200Seric # define FALSE 0 14157Seric 15148Seric struct sccsprog 16148Seric { 17148Seric char *sccsname; /* name of SCCS routine */ 18200Seric short sccsoper; /* opcode, see below */ 19200Seric short sccsflags; /* flags, see below */ 20148Seric char *sccspath; /* pathname of binary implementing */ 21148Seric }; 22148Seric 23200Seric /* values for sccsoper */ 24200Seric # define PROG 0 /* call a program */ 25201Seric # define CMACRO 1 /* command substitution macro */ 26200Seric 27157Seric /* bits for sccsflags */ 28200Seric # define NO_SDOT 0001 /* no s. on front of args */ 29200Seric # define REALUSER 0002 /* protected (e.g., admin) */ 30148Seric 31*202Seric # ifdef CSVAX 32*202Seric # define PROGPATH(name) "/usr/local/name" 33*202Seric # endif CSVAX 34*202Seric 35*202Seric # ifndef PROGPATH 36*202Seric # define PROGPATH(name) "/usr/sccs/name" 37*202Seric # endif PROGPATH 38*202Seric 39148Seric struct sccsprog SccsProg[] = 40148Seric { 41*202Seric "admin", PROG, REALUSER, PROGPATH(admin), 42*202Seric "chghist", PROG, 0, PROGPATH(rmdel), 43*202Seric "comb", PROG, 0, PROGPATH(comb), 44*202Seric "delta", PROG, 0, PROGPATH(delta), 45*202Seric "get", PROG, 0, PROGPATH(get), 46*202Seric "help", PROG, NO_SDOT, PROGPATH(help), 47*202Seric "prt", PROG, 0, PROGPATH(prt), 48*202Seric "rmdel", PROG, REALUSER, PROGPATH(rmdel), 49*202Seric "what", PROG, NO_SDOT, PROGPATH(what), 50201Seric "del", CMACRO, 0, "delta/get", 51200Seric NULL, -1, 0, NULL 52148Seric }; 53148Seric 54157Seric char *SccsPath = "SCCS"; /* pathname of SCCS files */ 55157Seric bool RealUser; /* if set, running as real user */ 56148Seric 57148Seric main(argc, argv) 58148Seric int argc; 59148Seric char **argv; 60148Seric { 61148Seric register char *p; 62148Seric 63148Seric /* 64148Seric ** Detect and decode flags intended for this program. 65148Seric */ 66148Seric 67200Seric if (argc < 2) 68148Seric { 69200Seric fprintf(stderr, "Usage: sccs [flags] command [flags]\n"); 70200Seric exit(EX_USAGE); 71200Seric } 72200Seric argv[argc] = NULL; 73200Seric 74200Seric while ((p = *++argv) != NULL) 75200Seric { 76148Seric if (*p != '-') 77148Seric break; 78148Seric switch (*++p) 79148Seric { 80148Seric case 'r': /* run as real user */ 81148Seric setuid(getuid()); 82157Seric RealUser++; 83148Seric break; 84148Seric 85148Seric case 'p': /* path of sccs files */ 86148Seric SccsPath = ++p; 87148Seric break; 88148Seric 89148Seric default: 90148Seric fprintf(stderr, "Sccs: unknown option -%s\n", p); 91148Seric break; 92148Seric } 93148Seric } 94158Seric if (SccsPath[0] == '\0') 95158Seric SccsPath = "."; 96148Seric 97201Seric command(argv, FALSE); 98200Seric exit(EX_OK); 99200Seric } 100157Seric 101201Seric command(argv, forkflag) 102200Seric char **argv; 103201Seric bool forkflag; 104200Seric { 105200Seric register struct sccsprog *cmd; 106200Seric register char *p; 107201Seric register char *q; 108201Seric char buf[40]; 109200Seric 110157Seric /* 111148Seric ** Look up command. 112200Seric ** At this point, argv points to the command name. 113148Seric */ 114148Seric 115200Seric p = *argv; 116148Seric for (cmd = SccsProg; cmd->sccsname != NULL; cmd++) 117148Seric { 118148Seric if (strcmp(cmd->sccsname, p) == 0) 119148Seric break; 120148Seric } 121148Seric if (cmd->sccsname == NULL) 122148Seric { 123148Seric fprintf(stderr, "Sccs: Unknown command \"%s\"\n", p); 124148Seric exit(EX_USAGE); 125148Seric } 126148Seric 127148Seric /* 128200Seric ** Interpret operation associated with this command. 129157Seric */ 130157Seric 131200Seric switch (cmd->sccsoper) 132200Seric { 133200Seric case PROG: /* call an sccs prog */ 134201Seric callprog(cmd->sccspath, cmd->sccsflags, argv, forkflag); 135201Seric break; 136201Seric 137201Seric case CMACRO: /* command macro */ 138201Seric for (p = cmd->sccspath; *p != '\0'; p++) 139201Seric { 140201Seric for (q = buf; *p != '/' && *p != '\0'; p++, q++) 141201Seric *q = *p; 142201Seric *q = '\0'; 143201Seric argv[0] = buf; 144201Seric command(argv, *p != '\0'); 145201Seric } 146201Seric fprintf(stderr, "Sccs internal error: CMACRO\n"); 147200Seric exit(EX_SOFTWARE); 148157Seric 149200Seric default: 150200Seric fprintf(stderr, "Sccs internal error: oper %d\n", cmd->sccsoper); 151200Seric exit(EX_SOFTWARE); 152200Seric } 153200Seric } 154200Seric 155200Seric callprog(progpath, flags, argv, forkflag) 156200Seric char *progpath; 157200Seric short flags; 158200Seric char **argv; 159200Seric bool forkflag; 160200Seric { 161200Seric register char *p; 162200Seric register char **av; 163200Seric char *newargv[1000]; 164200Seric extern char *makefile(); 165200Seric register int i; 166201Seric auto int st; 167200Seric 168200Seric if (*argv == NULL) 169200Seric return (-1); 170200Seric 171157Seric /* 172148Seric ** Build new argument vector. 173148Seric */ 174148Seric 175148Seric av = newargv; 176200Seric *av++ = *argv; 177148Seric 178153Seric /* copy program filename arguments and flags */ 179200Seric while ((p = *++argv) != NULL) 180148Seric { 181200Seric if (!bitset(NO_SDOT, flags) && *p != '-') 182153Seric *av++ = makefile(p); 183148Seric else 184153Seric *av++ = p; 185148Seric } 186148Seric 187148Seric /* terminate argument vector */ 188148Seric *av = NULL; 189148Seric 190148Seric /* 191148Seric ** Call real SCCS program. 192148Seric */ 193148Seric 194200Seric if (forkflag) 195200Seric { 196200Seric i = fork(); 197200Seric if (i < 0) 198200Seric { 199200Seric fprintf(stderr, "Sccs: cannot fork"); 200200Seric exit(EX_OSERR); 201200Seric } 202200Seric else if (i > 0) 203201Seric { 204201Seric wait(&st); 205201Seric return (st); 206201Seric } 207200Seric } 208200Seric 209200Seric /* 210200Seric ** Set protection as appropriate. 211200Seric */ 212200Seric 213200Seric if (bitset(REALUSER, flags)) 214200Seric setuid(getuid()); 215200Seric 216200Seric /* 217200Seric ** Call the program. 218200Seric */ 219200Seric 220200Seric execv(progpath, newargv); 221148Seric fprintf(stderr, "Sccs: cannot execute "); 222200Seric perror(progpath); 223148Seric exit(EX_UNAVAILABLE); 224148Seric } 225148Seric 226148Seric 227148Seric char * 228148Seric makefile(name) 229148Seric char *name; 230148Seric { 231148Seric register char *p; 232148Seric register char c; 233148Seric char buf[512]; 234148Seric struct stat stbuf; 235148Seric extern char *malloc(); 236148Seric 237148Seric /* 238148Seric ** See if this filename should be used as-is. 239148Seric ** There are three conditions where this can occur. 240148Seric ** 1. The name already begins with "s.". 241148Seric ** 2. The name has a "/" in it somewhere. 242148Seric ** 3. The name references a directory. 243148Seric */ 244148Seric 245148Seric if (strncmp(name, "s.", 2) == 0) 246148Seric return (name); 247148Seric for (p = name; (c = *p) != '\0'; p++) 248148Seric { 249148Seric if (c == '/') 250148Seric return (name); 251148Seric } 252148Seric if (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) 253148Seric return (name); 254148Seric 255148Seric /* 256148Seric ** Prepend the path of the sccs file. 257148Seric */ 258148Seric 259148Seric strcpy(buf, SccsPath); 260157Seric strcat(buf, "/s."); 261148Seric strcat(buf, name); 262148Seric p = malloc(strlen(buf) + 1); 263148Seric if (p == NULL) 264148Seric { 265148Seric perror("Sccs: no mem"); 266148Seric exit(EX_OSERR); 267148Seric } 268148Seric strcpy(p, buf); 269148Seric return (p); 270148Seric } 271