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