+ strcpy(q, SccsPath);
+ strcat(buf, "/s.");
+ strcat(buf, p);
+ }
+
+ if (strcmp(buf, name) == 0)
+ p = name;
+
+ return (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR);
+}
+\f/*
+** 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.
+*/
+
+bool
+isdir(name)
+ char *name;
+{
+ struct stat stbuf;
+
+ return (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR);
+}
+\f/*
+** 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.
+*/
+
+bool
+safepath(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);
+}
+\f/*
+** 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:
+** tells whether this came from a "clean", "info", or
+** "check" command.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Removes files in the current directory.
+** Prints information regarding files being edited.
+** Exits if a "check" command.
+*/
+
+clean(mode)
+ int mode;
+{
+ struct direct dir;
+ struct stat stbuf;
+ char buf[100];
+ char pline[120];
+ register FILE *dirfd;
+ register char *basefile;
+ bool gotedit;
+ FILE *pfp;
+
+ strcpy(buf, SccsDir);
+ if (buf[0] != '\0')
+ strcat(buf, "/");
+ strcat(buf, SccsPath);
+ dirfd = fopen(buf, "r");
+ if (dirfd == NULL)
+ {
+ usrerr("cannot open %s", buf);
+ return (EX_NOINPUT);
+ }
+
+ /*
+ ** Scan the SCCS directory looking for s. files.
+ */
+
+ gotedit = FALSE;
+ while (fread(&dir, sizeof dir, 1, dirfd) != NULL)
+ {
+ if (dir.d_ino == 0 || strncmp(dir.d_name, "s.", 2) != 0)
+ continue;
+
+ /* got an s. file -- see if the p. file exists */
+ strcpy(buf, SccsDir);
+ if (buf[0] != '\0')
+ strcat(buf, "/");
+ strcat(buf, SccsPath);
+ strcat(buf, "/p.");
+ basefile = &buf[strlen(buf)];
+ strncpy(basefile, &dir.d_name[2], sizeof dir.d_name - 2);
+ basefile[sizeof dir.d_name - 2] = '\0';
+ pfp = fopen(buf, "r");
+ if (pfp != NULL)
+ {
+ while (fgets(pline, sizeof pline, pfp) != NULL)
+ printf("%12s: being edited: %s", basefile, pline);
+ fclose(pfp);
+ gotedit = TRUE;
+ continue;
+ }
+
+ /* the s. file exists and no p. file exists -- unlink the g-file */
+ if (mode == CLEANC)
+ {
+ strncpy(buf, &dir.d_name[2], sizeof dir.d_name - 2);
+ buf[sizeof dir.d_name - 2] = '\0';
+ unlink(buf);
+ }
+ }
+
+ fclose(dirfd);
+ if (!gotedit && mode == INFOC)
+ printf("Nothing being edited\n");
+ if (mode == CHECKC)
+ exit(gotedit);
+ return (EX_OK);
+}
+\f/*
+** UNEDIT -- unedit a file
+**
+** Checks to see that the current user is actually editting
+** the file and arranges that s/he is not editting it.
+**
+** Parameters:
+** fn -- the name of the file to be unedited.
+**
+** Returns:
+** TRUE -- if the file was successfully unedited.
+** FALSE -- if the file was not unedited for some
+** reason.
+**
+** Side Effects:
+** fn is removed
+** entries are removed from pfile.
+*/
+
+bool
+unedit(fn)
+ char *fn;
+{
+ register FILE *pfp;
+ char *pfn;
+ static char tfn[] = "/tmp/sccsXXXXX";
+ FILE *tfp;
+ register char *p;
+ register char *q;
+ bool delete = FALSE;
+ bool others = FALSE;
+ char *myname;
+ extern char *getlogin();
+ struct pfile *pent;
+ extern struct pfile *getpfile();
+ char buf[120];
+ extern char *makefile();
+# ifdef UIDUSER
+ struct passwd *pw;
+ extern struct passwd *getpwuid();
+# endif UIDUSER
+
+ /* make "s." filename & find the trailing component */
+ pfn = makefile(fn);
+ if (pfn == NULL)
+ return (FALSE);
+ q = rindex(pfn, '/');
+ if (q == NULL)
+ q = &pfn[-1];
+ if (q[1] != 's' || q[2] != '.')
+ {
+ usrerr("bad file name \"%s\"", fn);
+ return (FALSE);
+ }
+
+ /* turn "s." into "p." */
+ *++q = 'p';
+
+ pfp = fopen(pfn, "r");
+ if (pfp == NULL)
+ {
+ printf("%12s: not being edited\n", fn);
+ return (FALSE);
+ }
+
+ /*
+ ** Copy p-file to temp file, doing deletions as needed.
+ */
+
+ mktemp(tfn);
+ tfp = fopen(tfn, "w");
+ if (tfp == NULL)
+ {
+ usrerr("cannot create \"%s\"", tfn);
+ exit(EX_OSERR);
+ }
+
+# ifdef UIDUSER
+ pw = getpwuid(getuid());
+ if (pw == NULL)
+ {
+ syserr("who are you? (uid=%d)", getuid());