sccs.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,630 行 · 第 1/3 页
C
1,630 行
/* metsky 12/4/86 */ { usrerr("cannot use fix command on version 1.1 (sc24)"); rval = EX_USAGE; break; } /* get the version with all changes */ rval = command(&ap[1], TRUE, "get -k"); /* now remove that version from the s-file */ if (rval == 0) rval = command(&ap[1], TRUE, "rmdel:r"); /* and edit the old version (but don't clobber new vers) */ if (rval == 0) rval = command(&ap[2], FALSE, "get -e -g"); break; case CLEAN: if (bitset(REALUSER,cmd->sccsflags)) setuid(getuid()); rval = clean((int) cmd->sccspath, ap); break; case UNEDIT: for (argv = np = &ap[1]; *argv != NULL; argv++) { if (unedit(*argv)) *np++ = *argv; } *np = NULL; /* * remove g-files here rather than in "unedit", so that * the UID can stay at real user -- depp (06Dec84) */ setuid(getuid()); for (argv = np = &ap[1]; *argv != NULL; argv++) { if (rmgfile(*argv)) *np++ = *argv; } *np = NULL; /* get all the files that we unedited successfully */ if (np > &ap[1]) rval = command(&ap[1], FALSE, "get"); break; case DIFFS: /* diff between s-file & edit file */ /* find the end of the flag arguments */ for (np = &ap[1]; *np != NULL && **np == '-'; np++) continue; argv = np; /* for each file, do the diff */ p = argv[1]; while (*np != NULL) { /* messy, but we need a null terminated argv */ *argv = *np++; argv[1] = NULL; i = dodiff(ap, tail(*argv)); if (rval == 0) rval = i; argv[1] = p; } break; case DODIFF: /* internal diff call */ setuid(getuid()); for (np = ap; *np != NULL; np++) { if ((*np)[0] == '-' && (*np)[1] == 'C') (*np)[1] = 'c'; } /* insert "-" argument */ np[1] = NULL; np[0] = np[-1]; np[-1] = "-"; /* execute the diff program of choice */# ifndef V6 execvp("diff", ap);# endif execv(cmd->sccspath, argv); syserr("cannot exec %s (sc6)", cmd->sccspath); exit(EX_OSERR); case ENTER: /* enter new sccs files */ /* skip over flag arguments */ for (np = &ap[1]; *np != NULL && **np == '-'; np++) continue; argv = np; /* do an admin for each file */ p = argv[1]; while (*np != NULL) { printf("\n%s:\n", *np); strcpy(buf, "-i"); gstrcat(buf, *np, sizeof(buf)); ap[0] = buf; argv[0] = tail(*np); argv[1] = NULL; rval = command(ap, TRUE, "admin"); argv[1] = p; if (rval == 0) { strcpy(buf, ","); gstrcat(buf, tail(*np), sizeof(buf)); if (link(*np, buf) >= 0) unlink(*np); } np++; } break; default: syserr("oper %d (sc7)", cmd->sccsoper); exit(EX_SOFTWARE); }# ifdef DEBUG if (Debug) printf("command: rval=%d\n", rval);# endif return (rval);}/*** LOOKUP -- look up an SCCS command name.**** Parameters:** name -- the name of the command to look up.**** Returns:** ptr to command descriptor for this command.** NULL if no such entry.**** Side Effects:** none.*/struct sccsprog *lookup(name) char *name;{ register struct sccsprog *cmd; for (cmd = SccsProg; cmd->sccsname != NULL; cmd++) { if (strcmp(cmd->sccsname, name) == 0) return (cmd); } return (NULL);}/*** CALLPROG -- call a program**** Used to call the SCCS programs.**** Parameters:** progpath -- pathname of the program to call.** flags -- status flags from the command descriptors.** argv -- an argument vector to pass to the program.** forkflag -- if true, fork before calling, else just** exec.**** Returns:** The exit status of the program.** Nothing if forkflag == FALSE.**** Side Effects:** Can exit if forkflag == FALSE.*/callprog(progpath, flags, argv, forkflag) char *progpath; short flags; char **argv; bool forkflag;{ register int i; auto int st;# ifdef DEBUG if (Debug) { printf("callprog:\n"); for (i = 0; argv[i] != NULL; i++) printf("\t\"%s\"\n", argv[i]); }# endif if (*argv == NULL) return (-1); /* ** Fork if appropriate. */ if (forkflag) {# ifdef DEBUG if (Debug) printf("Forking\n");# endif i = fork(); if (i < 0) { syserr("cannot fork (sc8)"); exit(EX_OSERR); } else if (i > 0) { wait(&st); if ((st & 0377) == 0) st = (st >> 8) & 0377; if (OutFile >= 0) { close(OutFile); OutFile = -1; } return (st); } } else if (OutFile >= 0) { syserr("callprog: setting stdout w/o forking (sc23)"); exit(EX_SOFTWARE); } /* set protection as appropriate */ if (bitset(REALUSER, flags)) setuid(getuid()); /* change standard input & output if needed */ if (OutFile >= 0) { close(1); dup(OutFile); close(OutFile); } /* call real SCCS program */ execv(progpath, argv); syserr("cannot execute %s (sc6)", progpath); exit(EX_UNAVAILABLE); /*NOTREACHED*/}/*** MAKEFILE -- make filename of SCCS file**** If the name passed is already the name of an SCCS file,** just return it. Otherwise, munge the name into the name** of the actual SCCS file.**** There are cases when it is not clear what you want to** do. For example, if SccsPath is an absolute pathname** and the name given is also an absolute pathname, we go** for SccsPath (& only use the last component of the name** passed) -- this is important for security reasons (if** sccs is being used as a setuid front end), but not** particularly intuitive.**** Parameters:** name -- the file name to be munged.**** Returns:** The pathname of the sccs file.** NULL on error.**** Side Effects:** none.*/char *makefile(name) char *name;{ register char *p; char buf[3*FBUFSIZ]; extern char *malloc(); extern char *rindex(); extern bool safepath(); extern bool isdir(); register char *q; p = rindex(name, '/'); if (p == NULL) p = name; else p++; /* ** Check to see that the path is "safe", i.e., that we ** are not letting some nasty person use the setuid part ** of this program to look at or munge some presumably ** hidden files. */ if (SccsDir[0] == '/' && !safepath(name)) return (NULL); /* ** Create the base pathname. */ /* first the directory part */ if (SccsDir[0] != '\0' && name[0] != '/' && strncmp(name, "./", 2) != 0) { gstrcpy(buf, SccsDir, sizeof(buf)); gstrcat(buf, "/", sizeof(buf)); } else gstrcpy(buf, "", sizeof(buf)); /* then the head of the pathname */ gstrncat(buf, name, p - name, sizeof(buf)); q = &buf[strlen(buf)]; /* now copy the final part of the name, in case useful */ gstrcpy(q, p, sizeof(buf)); /* so is it useful? */ if (strncmp(p, "s.", 2) != 0 && !isdir(buf)) { /* sorry, no; copy the SCCS pathname & the "s." */ gstrcpy(q, SccsPath, sizeof(buf)); gstrcat(buf, "/s.", sizeof(buf)); /* and now the end of the name */ gstrcat(buf, p, sizeof(buf)); } /* if i haven't changed it, why did I do all this? */ if (strcmp(buf, name) == 0) p = name; else { /* but if I have, squirrel it away */ p = malloc(strlen(buf) + 1); if (p == NULL) { perror("Sccs: no mem (sc10)"); exit(EX_OSERR); } strcpy(p, buf); } return (p);}/*** ISDIR -- return true if the argument is a directory.**** Parameters:** name -- the pathname of the file to check.**** Returns:** TRUE if 'name' is a directory, FALSE otherwise.**** Side Effects:** none.*/boolisdir(name) char *name;{ struct stat stbuf; return (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR);}/*** SAFEPATH -- determine whether a pathname is "safe"**** "Safe" pathnames only allow you to get deeper into the** directory structure, i.e., full pathnames and ".." are** not allowed.**** Parameters:** p -- the name to check.**** Returns:** TRUE -- if the path is safe.** FALSE -- if the path is not safe.**** Side Effects:** Prints a message if the path is not safe.*/boolsafepath(p) register char *p;{ extern char *index(); if (*p != '/') { while (strncmp(p, "../", 3) != 0 && strcmp(p, "..") != 0) { p = index(p, '/'); if (p == NULL) return (TRUE); p++; } } printf("You may not use full pathnames or \"..\"\n"); return (FALSE);}/*** CLEAN -- clean out recreatable files**** Any file for which an "s." file exists but no "p." file** exists in the current directory is purged.**** Parameters:** mode -- tells whether this came from a "clean", "info", or** "check" command.** argv -- the rest of the argument vector.**** Returns:** none.**** Side Effects:** Removes files in the current directory.** Prints information regarding files being edited.** Exits if a "check" command.*/clean(mode, argv) int mode; char **argv;{ struct direct *dir; char buf[FBUFSIZ]; char *bufend; register DIR *dirfd; register char *basefile; bool gotedit; bool gotpfent; FILE *pfp; bool nobranch = FALSE; extern struct pfile *getpfent(); register struct pfile *pf; register char **ap; extern char *username(); char *usernm = NULL; char *subdir = NULL; char *cmdname; /* ** Process the argv */ cmdname = *argv; for (ap = argv; *++ap != NULL; ) { if (**ap == '-') { /* we have a flag */ switch ((*ap)[1]) { case 'b': nobranch = TRUE; break; case 'u': if ((*ap)[2] != '\0') usernm = &(*ap)[2]; else if (ap[1] != NULL && ap[1][0] != '-') usernm = *++ap; else usernm = username(); break; } } else { if (subdir != NULL) usrerr("too many args (sc11)"); else subdir = *ap; } } /* ** Find and open the SCCS directory. */ gstrcpy(buf, SccsDir, sizeof(buf)); if (buf[0] != '\0') gstrcat(buf, "/", sizeof(buf)); if (subdir != NULL) { gstrcat(buf, subdir, sizeof(buf)); gstrcat(buf, "/", sizeof(buf)); } gstrcat(buf, SccsPath, sizeof(buf)); bufend = &buf[strlen(buf)]; dirfd = opendir(buf); if (dirfd == NULL) { usrerr("cannot open %s (sc12)", buf); return (EX_NOINPUT); } /* ** Scan the SCCS directory looking for s. files. ** gotedit tells whether we have tried to clean any ** files that are being edited. */ gotedit = FALSE; while (dir = readdir(dirfd)) { if (strncmp(dir->d_name, "s.", 2) != 0) continue; /* got an s. file -- see if the p. file exists */ gstrcpy(bufend, "/p.", sizeof(buf)); basefile = bufend + 3; gstrcpy(basefile, &dir->d_name[2], sizeof(buf)); /* ** open and scan the p-file. ** 'gotpfent' tells if we have found a valid p-file ** entry. */ pfp = fopen(buf, "r"); gotpfent = FALSE; if (pfp != NULL) { /* the file exists -- report it's contents */ while ((pf = getpfent(pfp)) != NULL) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?