1148Seric # include <stdio.h> 2148Seric # include <sys/types.h> 3148Seric # include <sys/stat.h> 4261Seric # include <sys/dir.h> 5148Seric # include <sysexits.h> 6202Seric # include <whoami.h> 7148Seric 8*588Seric static char SccsId[] = "@(#)sccs.c 1.24 08/09/80"; 9155Seric 10157Seric # define bitset(bit, word) ((bit) & (word)) 11157Seric 12157Seric typedef char bool; 13200Seric # define TRUE 1 14200Seric # define FALSE 0 15157Seric 16148Seric struct sccsprog 17148Seric { 18148Seric char *sccsname; /* name of SCCS routine */ 19200Seric short sccsoper; /* opcode, see below */ 20200Seric short sccsflags; /* flags, see below */ 21148Seric char *sccspath; /* pathname of binary implementing */ 22148Seric }; 23148Seric 24200Seric /* values for sccsoper */ 25200Seric # define PROG 0 /* call a program */ 26201Seric # define CMACRO 1 /* command substitution macro */ 27226Seric # define FIX 2 /* fix a delta */ 28261Seric # define CLEAN 3 /* clean out recreatable files */ 29396Seric # define UNEDIT 4 /* unedit a file */ 30200Seric 31157Seric /* bits for sccsflags */ 32200Seric # define NO_SDOT 0001 /* no s. on front of args */ 33200Seric # define REALUSER 0002 /* protected (e.g., admin) */ 34148Seric 35202Seric # ifdef CSVAX 36202Seric # define PROGPATH(name) "/usr/local/name" 37202Seric # endif CSVAX 38202Seric 39202Seric # ifndef PROGPATH 40202Seric # define PROGPATH(name) "/usr/sccs/name" 41202Seric # endif PROGPATH 42202Seric 43148Seric struct sccsprog SccsProg[] = 44148Seric { 45202Seric "admin", PROG, REALUSER, PROGPATH(admin), 46202Seric "chghist", PROG, 0, PROGPATH(rmdel), 47202Seric "comb", PROG, 0, PROGPATH(comb), 48202Seric "delta", PROG, 0, PROGPATH(delta), 49202Seric "get", PROG, 0, PROGPATH(get), 50202Seric "help", PROG, NO_SDOT, PROGPATH(help), 51202Seric "prt", PROG, 0, PROGPATH(prt), 52202Seric "rmdel", PROG, REALUSER, PROGPATH(rmdel), 53202Seric "what", PROG, NO_SDOT, PROGPATH(what), 54393Seric "edit", CMACRO, 0, "get -e", 55393Seric "delget", CMACRO, 0, "delta/get", 56398Seric "deledit", CMACRO, 0, "delta/get -e", 57201Seric "del", CMACRO, 0, "delta/get", 58226Seric "delt", CMACRO, 0, "delta/get", 59226Seric "fix", FIX, 0, NULL, 60346Seric "clean", CLEAN, REALUSER, (char *) TRUE, 61346Seric "info", CLEAN, REALUSER, (char *) FALSE, 62396Seric "unedit", UNEDIT, 0, NULL, 63200Seric NULL, -1, 0, NULL 64148Seric }; 65148Seric 66396Seric struct pfile 67396Seric { 68396Seric char *p_osid; /* old SID */ 69396Seric char *p_nsid; /* new SID */ 70396Seric char *p_user; /* user who did edit */ 71396Seric char *p_date; /* date of get */ 72396Seric char *p_time; /* time of get */ 73396Seric }; 74396Seric 75157Seric char *SccsPath = "SCCS"; /* pathname of SCCS files */ 76*588Seric char *SccsDir = ""; /* directory to begin search from */ 77157Seric bool RealUser; /* if set, running as real user */ 78393Seric # ifdef DEBUG 79393Seric bool Debug; /* turn on tracing */ 80393Seric # endif 81148Seric 82148Seric main(argc, argv) 83148Seric int argc; 84148Seric char **argv; 85148Seric { 86148Seric register char *p; 87262Seric extern struct sccsprog *lookup(); 88148Seric 89148Seric /* 90148Seric ** Detect and decode flags intended for this program. 91148Seric */ 92148Seric 93200Seric if (argc < 2) 94148Seric { 95200Seric fprintf(stderr, "Usage: sccs [flags] command [flags]\n"); 96200Seric exit(EX_USAGE); 97200Seric } 98200Seric argv[argc] = NULL; 99200Seric 100262Seric if (lookup(argv[0]) == NULL) 101200Seric { 102262Seric while ((p = *++argv) != NULL) 103148Seric { 104262Seric if (*p != '-') 105262Seric break; 106262Seric switch (*++p) 107262Seric { 108262Seric case 'r': /* run as real user */ 109262Seric setuid(getuid()); 110262Seric RealUser++; 111262Seric break; 112148Seric 113262Seric case 'p': /* path of sccs files */ 114262Seric SccsPath = ++p; 115262Seric break; 116148Seric 117*588Seric case 'd': /* directory to search from */ 118*588Seric SccsDir = ++p; 119*588Seric break; 120*588Seric 121393Seric # ifdef DEBUG 122393Seric case 'T': /* trace */ 123393Seric Debug++; 124393Seric break; 125393Seric # endif 126393Seric 127262Seric default: 128262Seric fprintf(stderr, "Sccs: unknown option -%s\n", p); 129262Seric break; 130262Seric } 131148Seric } 132262Seric if (SccsPath[0] == '\0') 133262Seric SccsPath = "."; 134148Seric } 135148Seric 136201Seric command(argv, FALSE); 137200Seric exit(EX_OK); 138200Seric } 139157Seric 140201Seric command(argv, forkflag) 141200Seric char **argv; 142201Seric bool forkflag; 143200Seric { 144200Seric register struct sccsprog *cmd; 145200Seric register char *p; 146201Seric register char *q; 147201Seric char buf[40]; 148262Seric extern struct sccsprog *lookup(); 149585Seric char *nav[200]; 150393Seric char **avp; 151585Seric register int i; 152585Seric extern bool unedit(); 153200Seric 154393Seric # ifdef DEBUG 155393Seric if (Debug) 156393Seric { 157393Seric printf("command:\n"); 158393Seric for (avp = argv; *avp != NULL; avp++) 159393Seric printf(" \"%s\"\n", *avp); 160393Seric } 161393Seric # endif 162393Seric 163157Seric /* 164148Seric ** Look up command. 165200Seric ** At this point, argv points to the command name. 166148Seric */ 167148Seric 168396Seric cmd = lookup(argv[0]); 169262Seric if (cmd == NULL) 170148Seric { 171396Seric fprintf(stderr, "Sccs: Unknown command \"%s\"\n", argv[0]); 172148Seric exit(EX_USAGE); 173148Seric } 174148Seric 175148Seric /* 176200Seric ** Interpret operation associated with this command. 177157Seric */ 178157Seric 179200Seric switch (cmd->sccsoper) 180200Seric { 181200Seric case PROG: /* call an sccs prog */ 182201Seric callprog(cmd->sccspath, cmd->sccsflags, argv, forkflag); 183201Seric break; 184201Seric 185201Seric case CMACRO: /* command macro */ 186201Seric for (p = cmd->sccspath; *p != '\0'; p++) 187201Seric { 188393Seric avp = nav; 189393Seric *avp++ = buf; 190201Seric for (q = buf; *p != '/' && *p != '\0'; p++, q++) 191393Seric { 192393Seric if (*p == ' ') 193393Seric { 194393Seric *q = '\0'; 195393Seric *avp++ = &q[1]; 196393Seric } 197393Seric else 198393Seric *q = *p; 199393Seric } 200201Seric *q = '\0'; 201393Seric *avp = NULL; 202393Seric xcommand(&argv[1], *p != '\0', nav[0], nav[1], nav[2], 203393Seric nav[3], nav[4], nav[5], nav[6]); 204201Seric } 205201Seric fprintf(stderr, "Sccs internal error: CMACRO\n"); 206200Seric exit(EX_SOFTWARE); 207157Seric 208226Seric case FIX: /* fix a delta */ 209568Seric if (strncmp(argv[1], "-r", 2) != 0) 210226Seric { 211226Seric fprintf(stderr, "Sccs: -r flag needed for fix command\n"); 212226Seric break; 213226Seric } 214226Seric xcommand(&argv[1], TRUE, "get", "-k", NULL); 215226Seric xcommand(&argv[1], TRUE, "rmdel", NULL); 216226Seric xcommand(&argv[2], FALSE, "get", "-e", "-g", NULL); 217226Seric fprintf(stderr, "Sccs internal error: FIX\n"); 218226Seric exit(EX_SOFTWARE); 219226Seric 220261Seric case CLEAN: 221346Seric clean((bool) cmd->sccspath); 222261Seric break; 223261Seric 224396Seric case UNEDIT: 225585Seric i = 0; 226396Seric for (avp = &argv[1]; *avp != NULL; avp++) 227585Seric { 228585Seric if (unedit(*avp)) 229585Seric nav[i++] = *avp; 230585Seric } 231585Seric nav[i] = NULL; 232585Seric if (i > 0) 233585Seric xcommand(nav, FALSE, "get", NULL); 234396Seric break; 235396Seric 236200Seric default: 237200Seric fprintf(stderr, "Sccs internal error: oper %d\n", cmd->sccsoper); 238200Seric exit(EX_SOFTWARE); 239200Seric } 240200Seric } 241262Seric /* 242262Seric ** LOOKUP -- look up an SCCS command name. 243262Seric ** 244262Seric ** Parameters: 245262Seric ** name -- the name of the command to look up. 246262Seric ** 247262Seric ** Returns: 248262Seric ** ptr to command descriptor for this command. 249262Seric ** NULL if no such entry. 250262Seric ** 251262Seric ** Side Effects: 252262Seric ** none. 253262Seric */ 254200Seric 255262Seric struct sccsprog * 256262Seric lookup(name) 257262Seric char *name; 258262Seric { 259262Seric register struct sccsprog *cmd; 260226Seric 261262Seric for (cmd = SccsProg; cmd->sccsname != NULL; cmd++) 262262Seric { 263262Seric if (strcmp(cmd->sccsname, name) == 0) 264262Seric return (cmd); 265262Seric } 266262Seric return (NULL); 267262Seric } 268262Seric 269262Seric 270226Seric xcommand(argv, forkflag, arg0) 271226Seric char **argv; 272226Seric bool forkflag; 273226Seric char *arg0; 274226Seric { 275226Seric register char **av; 276226Seric char *newargv[1000]; 277226Seric register char **np; 278226Seric 279226Seric np = newargv; 280226Seric for (av = &arg0; *av != NULL; av++) 281226Seric *np++ = *av; 282226Seric for (av = argv; *av != NULL; av++) 283226Seric *np++ = *av; 284226Seric *np = NULL; 285226Seric command(newargv, forkflag); 286226Seric } 287226Seric 288200Seric callprog(progpath, flags, argv, forkflag) 289200Seric char *progpath; 290200Seric short flags; 291200Seric char **argv; 292200Seric bool forkflag; 293200Seric { 294200Seric register char *p; 295200Seric register char **av; 296200Seric extern char *makefile(); 297200Seric register int i; 298201Seric auto int st; 299586Seric register char **nav; 300200Seric 301200Seric if (*argv == NULL) 302200Seric return (-1); 303200Seric 304157Seric /* 305226Seric ** Fork if appropriate. 306148Seric */ 307148Seric 308200Seric if (forkflag) 309200Seric { 310393Seric # ifdef DEBUG 311393Seric if (Debug) 312393Seric printf("Forking\n"); 313393Seric # endif 314200Seric i = fork(); 315200Seric if (i < 0) 316200Seric { 317200Seric fprintf(stderr, "Sccs: cannot fork"); 318200Seric exit(EX_OSERR); 319200Seric } 320200Seric else if (i > 0) 321201Seric { 322201Seric wait(&st); 323201Seric return (st); 324201Seric } 325200Seric } 326200Seric 327200Seric /* 328226Seric ** Build new argument vector. 329226Seric */ 330226Seric 331226Seric /* copy program filename arguments and flags */ 332586Seric nav = &argv[1]; 333226Seric av = argv; 334226Seric while ((p = *++av) != NULL) 335226Seric { 336226Seric if (!bitset(NO_SDOT, flags) && *p != '-') 337586Seric *nav = makefile(p); 338586Seric else 339586Seric *nav = p; 340586Seric if (*nav != NULL) 341586Seric nav++; 342226Seric } 343586Seric *nav = NULL; 344226Seric 345226Seric /* 346200Seric ** Set protection as appropriate. 347200Seric */ 348200Seric 349200Seric if (bitset(REALUSER, flags)) 350200Seric setuid(getuid()); 351226Seric 352200Seric /* 353226Seric ** Call real SCCS program. 354200Seric */ 355200Seric 356226Seric execv(progpath, argv); 357148Seric fprintf(stderr, "Sccs: cannot execute "); 358200Seric perror(progpath); 359148Seric exit(EX_UNAVAILABLE); 360148Seric } 361586Seric /* 362586Seric ** MAKEFILE -- make filename of SCCS file 363586Seric ** 364586Seric ** If the name passed is already the name of an SCCS file, 365586Seric ** just return it. Otherwise, munge the name into the name 366586Seric ** of the actual SCCS file. 367586Seric ** 368586Seric ** There are cases when it is not clear what you want to 369586Seric ** do. For example, if SccsPath is an absolute pathname 370586Seric ** and the name given is also an absolute pathname, we go 371586Seric ** for SccsPath (& only use the last component of the name 372586Seric ** passed) -- this is important for security reasons (if 373586Seric ** sccs is being used as a setuid front end), but not 374586Seric ** particularly intuitive. 375586Seric ** 376586Seric ** Parameters: 377586Seric ** name -- the file name to be munged. 378586Seric ** 379586Seric ** Returns: 380586Seric ** The pathname of the sccs file. 381586Seric ** NULL on error. 382586Seric ** 383586Seric ** Side Effects: 384586Seric ** none. 385586Seric */ 386148Seric 387148Seric char * 388148Seric makefile(name) 389148Seric char *name; 390148Seric { 391148Seric register char *p; 392148Seric register char c; 393148Seric char buf[512]; 394*588Seric struct stat stbuf; 395148Seric extern char *malloc(); 396586Seric extern char *rindex(); 397*588Seric extern bool safepath(); 398587Seric extern bool isdir(); 399587Seric register char *q; 400148Seric 401586Seric p = rindex(name, '/'); 402586Seric if (p == NULL) 403586Seric p = name; 404586Seric else 405586Seric p++; 406586Seric 407148Seric /* 408*588Seric ** Check to see that the path is "safe", i.e., that we 409*588Seric ** are not letting some nasty person use the setuid part 410*588Seric ** of this program to look at or munge some presumably 411*588Seric ** hidden files. 412148Seric */ 413148Seric 414*588Seric if (SccsDir[0] == '/' && !safepath(name)) 415*588Seric return (NULL); 416586Seric 417586Seric /* 418*588Seric ** Create the base pathname. 419586Seric */ 420586Seric 421*588Seric if (SccsDir[0] != '\0' && name[0] != '/' && strncmp(name, "./", 2) != 0) 422148Seric { 423*588Seric strcpy(buf, SccsDir); 424586Seric strcat(buf, "/"); 425586Seric } 426586Seric else 427586Seric strcpy(buf, ""); 428587Seric strncat(buf, name, p - name); 429587Seric q = &buf[strlen(buf)]; 430587Seric strcpy(q, p); 431587Seric if (strncmp(p, "s.", 2) != 0 && !isdir(buf)) 432586Seric { 433*588Seric strcpy(q, SccsPath); 434*588Seric strcat(buf, "/s."); 435586Seric strcat(buf, p); 436586Seric } 437148Seric 438*588Seric if (strcmp(buf, name) == 0) 439*588Seric p = name; 440*588Seric else 441148Seric { 442*588Seric p = malloc(strlen(buf) + 1); 443*588Seric if (p == NULL) 444*588Seric { 445*588Seric perror("Sccs: no mem"); 446*588Seric exit(EX_OSERR); 447*588Seric } 448*588Seric strcpy(p, buf); 449148Seric } 450148Seric return (p); 451148Seric } 452261Seric /* 453587Seric ** ISDIR -- return true if the argument is a directory. 454587Seric ** 455587Seric ** Parameters: 456587Seric ** name -- the pathname of the file to check. 457587Seric ** 458587Seric ** Returns: 459587Seric ** TRUE if 'name' is a directory, FALSE otherwise. 460587Seric ** 461587Seric ** Side Effects: 462587Seric ** none. 463587Seric */ 464587Seric 465587Seric bool 466587Seric isdir(name) 467587Seric char *name; 468587Seric { 469587Seric struct stat stbuf; 470587Seric 471587Seric return (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR); 472587Seric } 473587Seric /* 474586Seric ** SAFEPATH -- determine whether a pathname is "safe" 475586Seric ** 476586Seric ** "Safe" pathnames only allow you to get deeper into the 477586Seric ** directory structure, i.e., full pathnames and ".." are 478586Seric ** not allowed. 479586Seric ** 480586Seric ** Parameters: 481586Seric ** p -- the name to check. 482586Seric ** 483586Seric ** Returns: 484586Seric ** TRUE -- if the path is safe. 485586Seric ** FALSE -- if the path is not safe. 486586Seric ** 487586Seric ** Side Effects: 488586Seric ** Prints a message if the path is not safe. 489586Seric */ 490586Seric 491586Seric bool 492586Seric safepath(p) 493586Seric register char *p; 494586Seric { 495586Seric extern char *index(); 496586Seric 497586Seric if (*p != '/') 498586Seric { 499586Seric while (strncmp(p, "../", 3) != 0 && strcmp(p, "..") != 0) 500586Seric { 501586Seric p = index(p, '/'); 502586Seric if (p == NULL) 503586Seric return (TRUE); 504586Seric p++; 505586Seric } 506586Seric } 507586Seric 508586Seric printf("You may not use full pathnames or \"..\"\n"); 509586Seric return (FALSE); 510586Seric } 511586Seric /* 512261Seric ** CLEAN -- clean out recreatable files 513261Seric ** 514261Seric ** Any file for which an "s." file exists but no "p." file 515261Seric ** exists in the current directory is purged. 516261Seric ** 517261Seric ** Parameters: 518346Seric ** really -- if TRUE, remove everything. 519346Seric ** else, just report status. 520261Seric ** 521261Seric ** Returns: 522261Seric ** none. 523261Seric ** 524261Seric ** Side Effects: 525261Seric ** removes files in the current directory. 526261Seric */ 527261Seric 528346Seric clean(really) 529346Seric bool really; 530261Seric { 531261Seric struct direct dir; 532261Seric struct stat stbuf; 533261Seric char buf[100]; 534394Seric char pline[120]; 535346Seric register FILE *dirfd; 536346Seric register char *basefile; 537351Seric bool gotedit; 538394Seric FILE *pfp; 539261Seric 540261Seric dirfd = fopen(SccsPath, "r"); 541261Seric if (dirfd == NULL) 542261Seric { 543261Seric fprintf(stderr, "Sccs: cannot open %s\n", SccsPath); 544261Seric return; 545261Seric } 546261Seric 547261Seric /* 548261Seric ** Scan the SCCS directory looking for s. files. 549261Seric */ 550261Seric 551351Seric gotedit = FALSE; 552261Seric while (fread(&dir, sizeof dir, 1, dirfd) != NULL) 553261Seric { 554568Seric if (dir.d_ino == 0 || strncmp(dir.d_name, "s.", 2) != 0) 555261Seric continue; 556261Seric 557261Seric /* got an s. file -- see if the p. file exists */ 558261Seric strcpy(buf, SccsPath); 559261Seric strcat(buf, "/p."); 560346Seric basefile = &buf[strlen(buf)]; 561568Seric strncpy(basefile, &dir.d_name[2], sizeof dir.d_name - 2); 562346Seric basefile[sizeof dir.d_name - 2] = '\0'; 563394Seric pfp = fopen(buf, "r"); 564394Seric if (pfp != NULL) 565346Seric { 566394Seric while (fgets(pline, sizeof pline, pfp) != NULL) 567416Seric printf("%12s: being edited: %s", basefile, pline); 568394Seric fclose(pfp); 569351Seric gotedit = TRUE; 570261Seric continue; 571346Seric } 572261Seric 573261Seric /* the s. file exists and no p. file exists -- unlink the g-file */ 574346Seric if (really) 575346Seric { 576568Seric strncpy(buf, &dir.d_name[2], sizeof dir.d_name - 2); 577346Seric buf[sizeof dir.d_name - 2] = '\0'; 578346Seric unlink(buf); 579346Seric } 580261Seric } 581261Seric 582261Seric fclose(dirfd); 583351Seric if (!gotedit && !really) 584416Seric printf("Nothing being edited\n"); 585261Seric } 586396Seric /* 587396Seric ** UNEDIT -- unedit a file 588396Seric ** 589396Seric ** Checks to see that the current user is actually editting 590396Seric ** the file and arranges that s/he is not editting it. 591396Seric ** 592396Seric ** Parameters: 593416Seric ** fn -- the name of the file to be unedited. 594396Seric ** 595396Seric ** Returns: 596585Seric ** TRUE -- if the file was successfully unedited. 597585Seric ** FALSE -- if the file was not unedited for some 598585Seric ** reason. 599396Seric ** 600396Seric ** Side Effects: 601396Seric ** fn is removed 602396Seric ** entries are removed from pfile. 603396Seric */ 604396Seric 605585Seric bool 606396Seric unedit(fn) 607396Seric char *fn; 608396Seric { 609396Seric register FILE *pfp; 610396Seric char *pfn; 611396Seric static char tfn[] = "/tmp/sccsXXXXX"; 612396Seric FILE *tfp; 613396Seric register char *p; 614396Seric register char *q; 615396Seric bool delete = FALSE; 616396Seric bool others = FALSE; 617396Seric char *myname; 618396Seric extern char *getlogin(); 619396Seric struct pfile *pent; 620396Seric extern struct pfile *getpfile(); 621396Seric char buf[120]; 622396Seric 623396Seric /* make "s." filename & find the trailing component */ 624396Seric pfn = makefile(fn); 625586Seric if (pfn == NULL) 626586Seric return (FALSE); 627586Seric q = rindex(pfn, '/'); 628586Seric if (q == NULL) 629586Seric q = &pfn[-1]; 630586Seric if (q[1] != 's' || q[2] != '.') 631396Seric { 632396Seric fprintf(stderr, "Sccs: bad file name \"%s\"\n", fn); 633585Seric return (FALSE); 634396Seric } 635396Seric 636396Seric /* turn "s." into "p." */ 637396Seric *++q = 'p'; 638396Seric 639396Seric pfp = fopen(pfn, "r"); 640396Seric if (pfp == NULL) 641396Seric { 642416Seric printf("%12s: not being edited\n", fn); 643585Seric return (FALSE); 644396Seric } 645396Seric 646396Seric /* 647396Seric ** Copy p-file to temp file, doing deletions as needed. 648396Seric */ 649396Seric 650396Seric mktemp(tfn); 651396Seric tfp = fopen(tfn, "w"); 652396Seric if (tfp == NULL) 653396Seric { 654396Seric fprintf(stderr, "Sccs: cannot create \"%s\"\n", tfn); 655396Seric exit(EX_OSERR); 656396Seric } 657396Seric 658396Seric myname = getlogin(); 659396Seric while ((pent = getpfile(pfp)) != NULL) 660396Seric { 661396Seric if (strcmp(pent->p_user, myname) == 0) 662396Seric { 663396Seric /* a match */ 664396Seric delete++; 665396Seric } 666396Seric else 667396Seric { 668396Seric fprintf(tfp, "%s %s %s %s %s\n", pent->p_osid, 669396Seric pent->p_nsid, pent->p_user, pent->p_date, 670396Seric pent->p_time); 671396Seric others++; 672396Seric } 673396Seric } 674396Seric 675396Seric /* do final cleanup */ 676396Seric if (others) 677396Seric { 678396Seric if (freopen(tfn, "r", tfp) == NULL) 679396Seric { 680396Seric fprintf(stderr, "Sccs: cannot reopen \"%s\"\n", tfn); 681396Seric exit(EX_OSERR); 682396Seric } 683396Seric if (freopen(pfn, "w", pfp) == NULL) 684396Seric { 685396Seric fprintf(stderr, "Sccs: cannot create \"%s\"\n", pfn); 686585Seric return (FALSE); 687396Seric } 688396Seric while (fgets(buf, sizeof buf, tfp) != NULL) 689396Seric fputs(buf, pfp); 690396Seric } 691396Seric else 692396Seric { 693396Seric unlink(pfn); 694396Seric } 695396Seric fclose(tfp); 696396Seric fclose(pfp); 697396Seric unlink(tfn); 698396Seric 699396Seric if (delete) 700396Seric { 701396Seric unlink(fn); 702396Seric printf("%12s: removed\n", fn); 703585Seric return (TRUE); 704396Seric } 705396Seric else 706396Seric { 707416Seric printf("%12s: not being edited by you\n", fn); 708585Seric return (FALSE); 709396Seric } 710396Seric } 711396Seric /* 712396Seric ** GETPFILE -- get an entry from the p-file 713396Seric ** 714396Seric ** Parameters: 715396Seric ** pfp -- p-file file pointer 716396Seric ** 717396Seric ** Returns: 718396Seric ** pointer to p-file struct for next entry 719396Seric ** NULL on EOF or error 720396Seric ** 721396Seric ** Side Effects: 722396Seric ** Each call wipes out results of previous call. 723396Seric */ 724396Seric 725396Seric struct pfile * 726396Seric getpfile(pfp) 727396Seric FILE *pfp; 728396Seric { 729396Seric static struct pfile ent; 730396Seric static char buf[120]; 731396Seric register char *p; 732396Seric extern char *nextfield(); 733396Seric 734396Seric if (fgets(buf, sizeof buf, pfp) == NULL) 735396Seric return (NULL); 736396Seric 737396Seric ent.p_osid = p = buf; 738396Seric ent.p_nsid = p = nextfield(p); 739396Seric ent.p_user = p = nextfield(p); 740396Seric ent.p_date = p = nextfield(p); 741396Seric ent.p_time = p = nextfield(p); 742396Seric if (p == NULL || nextfield(p) != NULL) 743396Seric return (NULL); 744396Seric 745396Seric return (&ent); 746396Seric } 747396Seric 748396Seric 749396Seric char * 750396Seric nextfield(p) 751396Seric register char *p; 752396Seric { 753396Seric if (p == NULL || *p == '\0') 754396Seric return (NULL); 755396Seric while (*p != ' ' && *p != '\n' && *p != '\0') 756396Seric p++; 757396Seric if (*p == '\n' || *p == '\0') 758396Seric { 759396Seric *p = '\0'; 760396Seric return (NULL); 761396Seric } 762396Seric *p++ = '\0'; 763396Seric return (p); 764396Seric } 765