1148Seric # include <stdio.h> 2148Seric # include <sys/types.h> 3148Seric # include <sys/stat.h> 4148Seric # include <sysexits.h> 5148Seric 6*200Seric static char SccsId[] = "@(#)sccs.c 1.7 delta 05/22/80 20:24:38 get 10/14/12 16:33:34"; 7155Seric 8157Seric # define bitset(bit, word) ((bit) & (word)) 9157Seric 10157Seric typedef char bool; 11*200Seric # define TRUE 1 12*200Seric # define FALSE 0 13157Seric 14148Seric struct sccsprog 15148Seric { 16148Seric char *sccsname; /* name of SCCS routine */ 17*200Seric short sccsoper; /* opcode, see below */ 18*200Seric short sccsflags; /* flags, see below */ 19148Seric char *sccspath; /* pathname of binary implementing */ 20148Seric }; 21148Seric 22*200Seric /* values for sccsoper */ 23*200Seric # define PROG 0 /* call a program */ 24*200Seric 25157Seric /* bits for sccsflags */ 26*200Seric # define NO_SDOT 0001 /* no s. on front of args */ 27*200Seric # define REALUSER 0002 /* protected (e.g., admin) */ 28148Seric 29148Seric struct sccsprog SccsProg[] = 30148Seric { 31*200Seric "admin", PROG, REALUSER, "/usr/sccs/admin", 32*200Seric "chghist", PROG, 0, "/usr/sccs/rmdel", 33*200Seric "comb", PROG, 0, "/usr/sccs/comb", 34*200Seric "delta", PROG, 0, "/usr/sccs/delta", 35*200Seric "get", PROG, 0, "/usr/sccs/get", 36*200Seric "help", PROG, NO_SDOT, "/usr/sccs/help", 37*200Seric "prt", PROG, 0, "/usr/sccs/prt", 38*200Seric "rmdel", PROG, REALUSER, "/usr/sccs/rmdel", 39*200Seric "what", PROG, NO_SDOT, "/usr/sccs/what", 40*200Seric NULL, -1, 0, NULL 41148Seric }; 42148Seric 43157Seric char *SccsPath = "SCCS"; /* pathname of SCCS files */ 44157Seric bool RealUser; /* if set, running as real user */ 45148Seric 46148Seric main(argc, argv) 47148Seric int argc; 48148Seric char **argv; 49148Seric { 50148Seric register char *p; 51148Seric 52148Seric /* 53148Seric ** Detect and decode flags intended for this program. 54148Seric */ 55148Seric 56*200Seric if (argc < 2) 57148Seric { 58*200Seric fprintf(stderr, "Usage: sccs [flags] command [flags]\n"); 59*200Seric exit(EX_USAGE); 60*200Seric } 61*200Seric argv[argc] = NULL; 62*200Seric 63*200Seric while ((p = *++argv) != NULL) 64*200Seric { 65148Seric if (*p != '-') 66148Seric break; 67148Seric switch (*++p) 68148Seric { 69148Seric case 'r': /* run as real user */ 70148Seric setuid(getuid()); 71157Seric RealUser++; 72148Seric break; 73148Seric 74148Seric case 'p': /* path of sccs files */ 75148Seric SccsPath = ++p; 76148Seric break; 77148Seric 78148Seric default: 79148Seric fprintf(stderr, "Sccs: unknown option -%s\n", p); 80148Seric break; 81148Seric } 82148Seric } 83158Seric if (SccsPath[0] == '\0') 84158Seric SccsPath = "."; 85148Seric 86*200Seric command(argv); 87*200Seric exit(EX_OK); 88*200Seric } 89157Seric 90*200Seric command(argv) 91*200Seric char **argv; 92*200Seric { 93*200Seric register struct sccsprog *cmd; 94*200Seric register char *p; 95*200Seric 96157Seric /* 97148Seric ** Look up command. 98*200Seric ** At this point, argv points to the command name. 99148Seric */ 100148Seric 101*200Seric p = *argv; 102148Seric for (cmd = SccsProg; cmd->sccsname != NULL; cmd++) 103148Seric { 104148Seric if (strcmp(cmd->sccsname, p) == 0) 105148Seric break; 106148Seric } 107148Seric if (cmd->sccsname == NULL) 108148Seric { 109148Seric fprintf(stderr, "Sccs: Unknown command \"%s\"\n", p); 110148Seric exit(EX_USAGE); 111148Seric } 112148Seric 113148Seric /* 114*200Seric ** Interpret operation associated with this command. 115157Seric */ 116157Seric 117*200Seric switch (cmd->sccsoper) 118*200Seric { 119*200Seric case PROG: /* call an sccs prog */ 120*200Seric callprog(cmd->sccspath, cmd->sccsflags, argv, FALSE); 121*200Seric fprintf(stderr, "Sccs internal error: callprog\n"); 122*200Seric exit(EX_SOFTWARE); 123157Seric 124*200Seric default: 125*200Seric fprintf(stderr, "Sccs internal error: oper %d\n", cmd->sccsoper); 126*200Seric exit(EX_SOFTWARE); 127*200Seric } 128*200Seric } 129*200Seric 130*200Seric callprog(progpath, flags, argv, forkflag) 131*200Seric char *progpath; 132*200Seric short flags; 133*200Seric char **argv; 134*200Seric bool forkflag; 135*200Seric { 136*200Seric register char *p; 137*200Seric register char **av; 138*200Seric char *newargv[1000]; 139*200Seric extern char *makefile(); 140*200Seric register int i; 141*200Seric 142*200Seric if (*argv == NULL) 143*200Seric return (-1); 144*200Seric 145157Seric /* 146148Seric ** Build new argument vector. 147148Seric */ 148148Seric 149148Seric av = newargv; 150*200Seric *av++ = *argv; 151148Seric 152153Seric /* copy program filename arguments and flags */ 153*200Seric while ((p = *++argv) != NULL) 154148Seric { 155*200Seric if (!bitset(NO_SDOT, flags) && *p != '-') 156153Seric *av++ = makefile(p); 157148Seric else 158153Seric *av++ = p; 159148Seric } 160148Seric 161148Seric /* terminate argument vector */ 162148Seric *av = NULL; 163148Seric 164148Seric /* 165148Seric ** Call real SCCS program. 166148Seric */ 167148Seric 168*200Seric if (forkflag) 169*200Seric { 170*200Seric i = fork(); 171*200Seric if (i < 0) 172*200Seric { 173*200Seric fprintf(stderr, "Sccs: cannot fork"); 174*200Seric exit(EX_OSERR); 175*200Seric } 176*200Seric else if (i > 0) 177*200Seric return (i); 178*200Seric } 179*200Seric 180*200Seric /* 181*200Seric ** Set protection as appropriate. 182*200Seric */ 183*200Seric 184*200Seric if (bitset(REALUSER, flags)) 185*200Seric setuid(getuid()); 186*200Seric 187*200Seric /* 188*200Seric ** Call the program. 189*200Seric */ 190*200Seric 191*200Seric execv(progpath, newargv); 192148Seric fprintf(stderr, "Sccs: cannot execute "); 193*200Seric perror(progpath); 194148Seric exit(EX_UNAVAILABLE); 195148Seric } 196148Seric 197148Seric 198148Seric char * 199148Seric makefile(name) 200148Seric char *name; 201148Seric { 202148Seric register char *p; 203148Seric register char c; 204148Seric char buf[512]; 205148Seric struct stat stbuf; 206148Seric extern char *malloc(); 207148Seric 208148Seric /* 209148Seric ** See if this filename should be used as-is. 210148Seric ** There are three conditions where this can occur. 211148Seric ** 1. The name already begins with "s.". 212148Seric ** 2. The name has a "/" in it somewhere. 213148Seric ** 3. The name references a directory. 214148Seric */ 215148Seric 216148Seric if (strncmp(name, "s.", 2) == 0) 217148Seric return (name); 218148Seric for (p = name; (c = *p) != '\0'; p++) 219148Seric { 220148Seric if (c == '/') 221148Seric return (name); 222148Seric } 223148Seric if (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) 224148Seric return (name); 225148Seric 226148Seric /* 227148Seric ** Prepend the path of the sccs file. 228148Seric */ 229148Seric 230148Seric strcpy(buf, SccsPath); 231157Seric strcat(buf, "/s."); 232148Seric strcat(buf, name); 233148Seric p = malloc(strlen(buf) + 1); 234148Seric if (p == NULL) 235148Seric { 236148Seric perror("Sccs: no mem"); 237148Seric exit(EX_OSERR); 238148Seric } 239148Seric strcpy(p, buf); 240148Seric return (p); 241148Seric } 242