|
|
1.1 ! root 1: static char *rcsid = "$Header$"; ! 2: /* ! 3: * rmproject - remove a project root directory ! 4: * ! 5: * Author: Peter J. Nicklin ! 6: */ ! 7: #include <sys/param.h> ! 8: #include <signal.h> ! 9: #include <stdio.h> ! 10: #include "getarg.h" ! 11: #include "macro.h" ! 12: #include "null.h" ! 13: #include "path.h" ! 14: #include "pdb.h" ! 15: #include "pld.h" ! 16: #include "slist.h" ! 17: #include "spms.h" ! 18: #include "system.h" ! 19: #include "yesno.h" ! 20: ! 21: char CWD[PATHSIZE]; /* current working directory */ ! 22: char *CWP; /* current working project */ ! 23: char *PGN = "rmproject"; /* program name */ ! 24: char *RMFLAG = ""; /* rm "-f" flag */ ! 25: int FORCE = 0; /* brute force remove or undefine */ ! 26: int RECURSIVE = 0; /* remove project dirs recursively */ ! 27: int UNDEFINE = 0; /* remove proj dir definitions only */ ! 28: int WANT_TO_EXIT = 0; /* advisory exit flag */ ! 29: ! 30: main(argc, argv) ! 31: int argc; ! 32: char **argv; ! 33: { ! 34: extern int PPDEBUG; /* project pathname debug flag */ ! 35: char *getcwp(); /* get current working project */ ! 36: char *getwd(); /* get current working directory */ ! 37: int isfg(); /* is process in foreground? */ ! 38: int onintr(); /* process signals */ ! 39: int rmproject(); /* remove a project root directory */ ! 40: int rmtyp(); /* remove project dir type labels */ ! 41: int status = 0; /* exit status */ ! 42: int unproject(); /* undefine project root directory */ ! 43: int xppath(); /* expand project pathname */ ! 44: PATH pathbuf; /* pathname struct buffer */ ! 45: SLIST *pdirtyp; /* project directory type labels list */ ! 46: SLIST *slinit(); /* initialize singly-linked list */ ! 47: void typargtolist(); /* type labels -> pdirtyp list */ ! 48: ! 49: pdirtyp = slinit(); ! 50: { ! 51: register char *s; /* option pointer */ ! 52: while (--argc > 0 && **++argv == '-') ! 53: { ! 54: for (s = argv[0]+1; *s != '\0'; s++) ! 55: switch (*s) ! 56: { ! 57: case 'D': ! 58: PPDEBUG = YES; ! 59: break; ! 60: case 'F': ! 61: /* ! 62: * 'F' option is mentioned in ! 63: * rmproject() and unproject() ! 64: */ ! 65: FORCE++; ! 66: break; ! 67: case 'T': ! 68: typargtolist(GETARG(s), pdirtyp); ! 69: if (*s == '\0') ! 70: status = 1; ! 71: goto endfor; ! 72: case 'f': ! 73: RMFLAG = "-f"; ! 74: break; ! 75: case 'r': ! 76: RECURSIVE++; ! 77: break; ! 78: case 'u': ! 79: UNDEFINE++; ! 80: break; ! 81: default: ! 82: warn("bad option -%c", *s); ! 83: status = 1; ! 84: goto endfor; ! 85: } ! 86: endfor: continue; ! 87: } ! 88: } ! 89: if (status == 1 || argc < 1) ! 90: fatal("usage: rmproject [-fru] [-T type[,type...]] projectname ..."); ! 91: ! 92: if ((CWP = getcwp()) == NULL) ! 93: fatal("no project environment"); ! 94: if (getwd(CWD) == NULL) ! 95: fatal("can't find current working directory"); ! 96: if (isfg() == YES) ! 97: { ! 98: signal(SIGINT, onintr); ! 99: signal(SIGQUIT, onintr); ! 100: signal(SIGHUP, onintr); ! 101: } ! 102: ! 103: for (; argc > 0; ++argv, --argc) ! 104: { ! 105: if (xppath(*argv, &pathbuf) == -1) ! 106: { ! 107: patherr(*argv); ! 108: status = 1; ! 109: continue; ! 110: } ! 111: switch (pathbuf.p_mode & P_IFMT) ! 112: { ! 113: case P_IFHOME: ! 114: case P_IFPROOT: ! 115: if (SLNUM(pdirtyp) > 0) ! 116: status |= rmtyp(*argv, pdirtyp, &pathbuf); ! 117: else if (UNDEFINE) ! 118: status |= unproject(*argv, &pathbuf); ! 119: else ! 120: status |= rmproject(*argv, &pathbuf); ! 121: break; ! 122: case P_IFPDIR: ! 123: warn("%s is a project directory", *argv); ! 124: status = 1; ! 125: break; ! 126: case P_IFNEW: ! 127: case P_IFREG: ! 128: warn("%s: no such project", *argv); ! 129: status = 1; ! 130: break; ! 131: } ! 132: if (WANT_TO_EXIT) ! 133: exit(1); ! 134: } ! 135: exit(status); ! 136: } ! 137: ! 138: ! 139: ! 140: /* ! 141: * onintr() resets interrupt, quit, and hangup signals, and sets a flag ! 142: * which advises the process to exit at the first opportunity. ! 143: */ ! 144: onintr() ! 145: { ! 146: signal(SIGINT, onintr); ! 147: signal(SIGQUIT, onintr); ! 148: signal(SIGHUP, onintr); ! 149: ! 150: WANT_TO_EXIT = 1; ! 151: } ! 152: ! 153: ! 154: ! 155: /* ! 156: * pbrmtyp() removes type labels from database buffer. ! 157: */ ! 158: void ! 159: pbrmtyp(ppathname, typlist) ! 160: char *ppathname; /* project pathname */ ! 161: SLIST *typlist; /* type labels list */ ! 162: { ! 163: char *pbgetstring(); /* get specified string field */ ! 164: char *pdtfind(); /* find type label in buffer */ ! 165: char *slget(); /* get next key from list */ ! 166: char *tp; /* pointer to type label */ ! 167: char typbuf[TYPBUFSIZE]; /* project directory types buffer */ ! 168: int pbaddstring(); /* add string field */ ! 169: int strlen(); /* string length */ ! 170: void slrewind(); /* rewind list */ ! 171: void pdtrm(); /* remove type label */ ! 172: ! 173: pbgetstring(PDIRTYPE, typbuf); ! 174: slrewind(typlist); ! 175: while ((tp = slget(typlist)) != NULL) ! 176: { ! 177: if (pdtfind(tp, typbuf) != NULL) ! 178: pdtrm(tp, typbuf); ! 179: else ! 180: warn("%s: \"%s\" type label not found", ppathname, tp); ! 181: } ! 182: pbaddstring(PDIRTYPE, typbuf); ! 183: } ! 184: ! 185: ! 186: ! 187: /* ! 188: * rmd() removes a project directory. rmd() returns the status of the rm ! 189: * command or 1 if the user decides not to remove a project directory. ! 190: * Before removing a directory the project link directory is moved to ! 191: * safe place. If the directory is removed successfully, the project link ! 192: * directory is removed. ! 193: */ ! 194: rmd(pathname) ! 195: char *pathname; /* full pathname of directory */ ! 196: { ! 197: char cmdbuf[PATHSIZE+9]; /* command buffer */ ! 198: int rmpld(); /* remove project link directory */ ! 199: int savepld(); /* save project link directory */ ! 200: int status; /* return status */ ! 201: int yes(); /* is reply yes? */ ! 202: void restorpld(); /* restore project link directory */ ! 203: void unsavepld(); /* remove saved project link dir */ ! 204: ! 205: if (RECURSIVE) ! 206: { ! 207: sprintf(cmdbuf, "rm %s -r %s", RMFLAG, pathname); ! 208: printf("%s? [yn](n): ", cmdbuf); ! 209: if (!yes()) ! 210: return(1); ! 211: status = system(cmdbuf); ! 212: status >>= NBBY; ! 213: status &= 0xff; ! 214: } ! 215: else { ! 216: if ((status = savepld(pathname)) == 0) ! 217: if ((status = rmpld(pathname)) == 0) ! 218: if ((status = RM_DIR(pathname)) != 0) ! 219: restorpld(pathname); ! 220: else ! 221: unsavepld(); ! 222: } ! 223: return(status); ! 224: } ! 225: ! 226: ! 227: ! 228: /* ! 229: * rmpld() removes a project link directory. Returns 1 if file not ! 230: * removed, otherwise zero. ! 231: */ ! 232: rmpld(pathname) ! 233: char *pathname; /* project root directory pathname */ ! 234: { ! 235: char *pathcat(); /* pathname concatenation */ ! 236: char pldpathname[PATHSIZE]; /* project link directory pathname */ ! 237: ! 238: if (unlink(pathcat(pldpathname, pathname, PLDNAME)) != 0) ! 239: if (!FORCE) ! 240: { ! 241: pperror(pldpathname); ! 242: return(1); ! 243: } ! 244: return(0); ! 245: } ! 246: ! 247: ! 248: ! 249: /* ! 250: * rmproject() removes a project root directory. Returns 0 is successful, ! 251: * otherwise 1. ! 252: */ ! 253: rmproject(ppathname, pb) ! 254: char *ppathname; /* project root directory pathname */ ! 255: PATH *pb; /* pathname struct buffer */ ! 256: { ! 257: char *ppathcat(); /* project pathname concatenation */ ! 258: char *ppathhead(); /* remove tail of project pathname */ ! 259: char pppathname[PPATHSIZE]; /* parent project pathname */ ! 260: char *strcpy(); /* string copy */ ! 261: int _closepdb(); /* close database without updating */ ! 262: int closepdb(); /* close database */ ! 263: int errpdb(); /* print database error */ ! 264: int plen; /* length of regular pathname */ ! 265: int pputent(); /* write buffer to database */ ! 266: int pstatus = 0; /* project status */ ! 267: int strlen(); /* string length */ ! 268: int strncmp(); /* compare n characters */ ! 269: int subprojects(); /* check for subprojects */ ! 270: int xppath(); /* expand project pathname */ ! 271: PATH *pd; /* pathname struct pointer */ ! 272: PATH ppathbuf; /* parent project pathname struct buf */ ! 273: PATH *readpld(); /* read project link directory entry */ ! 274: PDB *openpdb(); /* open database */ ! 275: PDB *pldp; /* project link directory stream */ ! 276: void resetpdb(); /* reset current database pointer */ ! 277: ! 278: if (EQUAL(ppathname, CURPROJECT)) ! 279: { ! 280: warn("%s: can't remove current project", ppathname); ! 281: return(1); ! 282: } ! 283: plen = strlen(pb->p_path); ! 284: if (strncmp(pb->p_path, CWD, plen) == 0) ! 285: { ! 286: warn("can't remove %s from current directory", ppathname); ! 287: return(1); ! 288: } ! 289: if (FORCE) ! 290: { ! 291: if (*ppathname != _PDIRC && *ppathname != _HDIRC) ! 292: { ! 293: warn("%s must an absolute project pathname", ppathname); ! 294: return(1); ! 295: } ! 296: ppathhead(strcpy(pppathname, ppathname)); ! 297: } ! 298: else { ! 299: ppathcat(pppathname, ppathname, PARENTPROJECT); ! 300: } ! 301: if (xppath(pppathname, &ppathbuf) == -1) ! 302: { ! 303: patherr(""); ! 304: warn("force removal by typing `rmproject -F projectname'"); ! 305: return(1); ! 306: } ! 307: if ((pldp = openpdb(PLDNAME, ppathbuf.p_path, "rw")) == NULL) ! 308: return(errpdb((PDB *) NULL)); ! 309: while ((pd = readpld(pldp)) != NULL) ! 310: if (EQUAL(pb->p_alias, pd->p_alias)) ! 311: { ! 312: pstatus = subprojects(pb->p_path); ! 313: if (pstatus == 1) ! 314: { ! 315: warn("%s: project not empty", ppathname); ! 316: resetpdb(pldp); ! 317: break; ! 318: } ! 319: else if (pstatus == 2) ! 320: { ! 321: warn("can't remove %s because subprojects exist", ! 322: ppathname); ! 323: resetpdb(pldp); ! 324: break; ! 325: } ! 326: else if (pstatus == 3) ! 327: { ! 328: resetpdb(pldp); ! 329: break; ! 330: } ! 331: resetpdb(pldp); ! 332: } ! 333: else if (strncmp(pb->p_path, pd->p_path, plen) == 0) ! 334: { /* don't clobber nested projects */ ! 335: if (pd->p_mode == P_IFPROOT) ! 336: { ! 337: warnexist(ppathname, pd->p_alias); ! 338: pstatus = 4; ! 339: break; ! 340: } ! 341: } ! 342: else { ! 343: pputent(pldp); ! 344: } ! 345: if (pstatus != 0) ! 346: _closepdb(pldp); ! 347: else if ((pstatus = rmd(pb->p_path)) != 0) ! 348: _closepdb(pldp); ! 349: else ! 350: pstatus = closepdb(pldp); ! 351: return(pstatus != 0); ! 352: } ! 353: ! 354: ! 355: ! 356: /* ! 357: * rmtyp() removes type labels from an existing project directory. ! 358: */ ! 359: rmtyp(ppathname, pdirtyp, pb) ! 360: char *ppathname; /* project directory pathname */ ! 361: SLIST *pdirtyp; /* project directory type labels list */ ! 362: PATH *pb; /* pathname struct buffer */ ! 363: { ! 364: char *pbfndkey(); /* find key */ ! 365: int closepdb(); /* close database */ ! 366: int errpdb(); /* print database error */ ! 367: int pgetent(); /* load next entry into buffer */ ! 368: int pputent(); /* write buffer to database */ ! 369: int status = 0; /* return status */ ! 370: PDB *openpdb(); /* open database */ ! 371: PDB *pldp; /* project link directory stream */ ! 372: void pbrmtyp(); /* remove type labels from buffer */ ! 373: ! 374: if ((pldp = openpdb(PLDNAME, pb->p_project, "rw")) == NULL) ! 375: return(errpdb((PDB *) NULL)); ! 376: while (pgetent(pldp) != EOF) ! 377: { ! 378: if (pbfndkey(CURPROJECT) != NULL) ! 379: pbrmtyp(ppathname, pdirtyp); ! 380: pputent(pldp); ! 381: } ! 382: status = closepdb(pldp); ! 383: return(status); ! 384: } ! 385: ! 386: ! 387: ! 388: /* ! 389: * subprojects() returns 1 if a project has project directories, 2 if any ! 390: * of these are subprojects, and zero otherwise. ! 391: */ ! 392: subprojects(pathname) ! 393: char *pathname; /* project root directory pathname */ ! 394: { ! 395: char *pbfndkey(); /* find key */ ! 396: int closepdb(); /* close database */ ! 397: int errpdb(); /* print database error */ ! 398: int pbfndflag(); /* find flag field */ ! 399: int pgetent(); /* load next entry into buffer */ ! 400: int status = 0; /* return status */ ! 401: PDB *openpdb(); /* open database */ ! 402: PDB *pldp; /* project link directory stream */ ! 403: ! 404: if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL) ! 405: { ! 406: if (!FORCE) return(errpdb((PDB *) NULL)); ! 407: return(status); ! 408: } ! 409: while (pgetent(pldp) != EOF) ! 410: if (pbfndkey(CURPROJECT) == NULL && ! 411: pbfndkey(PARENTPROJECT) == NULL) ! 412: { ! 413: if (!RECURSIVE) status = 1; ! 414: if (pbfndflag(PROOTDIR) == YES) ! 415: { ! 416: status = 2; ! 417: break; ! 418: } ! 419: } ! 420: closepdb(pldp); ! 421: return(status); ! 422: } ! 423: ! 424: ! 425: ! 426: /* ! 427: * typargtolist() prepends comma-separated type labels specified in typarg ! 428: * to typlist. ! 429: */ ! 430: void ! 431: typargtolist(typarg, typlist) ! 432: register char *typarg; /* type labels argument */ ! 433: SLIST *typlist; /* type labels list */ ! 434: { ! 435: register char *t; /* type label argument pointer */ ! 436: char *slprepend(); /* prepend singly-linked list key */ ! 437: ! 438: for (t = typarg; *t != '\0'; t++) ! 439: continue; ! 440: for (; t >= typarg; t--) ! 441: if (t[0] == ',') ! 442: { ! 443: if (t[1] != '\0') ! 444: slprepend(t+1, typlist); ! 445: t[0] = '\0'; ! 446: } ! 447: slprepend(typarg, typlist); ! 448: } ! 449: ! 450: ! 451: ! 452: /* ! 453: * unproject() undefines a project root directory. Returns 0 is successful, ! 454: * otherwise 1. ! 455: */ ! 456: unproject(ppathname, pb) ! 457: char *ppathname; /* project root directory pathname */ ! 458: PATH *pb; /* pathname struct buffer */ ! 459: { ! 460: char *ppathcat(); /* project pathname concatenation */ ! 461: char *ppathhead(); /* remove tail of project pathname */ ! 462: char pppathname[PPATHSIZE]; /* parent project pathname */ ! 463: char *strcpy(); /* string copy */ ! 464: int _closepdb(); /* close database without updating */ ! 465: int closepdb(); /* close database */ ! 466: int errpdb(); /* print database error */ ! 467: int pputent(); /* write buffer to database */ ! 468: int pstatus = 0; /* project status */ ! 469: int rmpld(); /* remove project link directory */ ! 470: int subprojects(); /* check for subprojects */ ! 471: int xppath(); /* expand project pathname */ ! 472: PATH *pd; /* pathname struct pointer */ ! 473: PATH ppathbuf; /* parent project pathname struct buf */ ! 474: PATH *readpld(); /* read project link directory entry */ ! 475: PDB *openpdb(); /* open database */ ! 476: PDB *pldp; /* project link directory stream */ ! 477: void resetpdb(); /* reset current database pointer */ ! 478: ! 479: if (EQUAL(ppathname, CURPROJECT)) ! 480: { ! 481: warn("%s: can't undefine current project", ppathname); ! 482: return(1); ! 483: } ! 484: if (FORCE) ! 485: { ! 486: if (*ppathname != _PDIRC && *ppathname != _HDIRC) ! 487: { ! 488: warn("%s must an absolute project pathname", ppathname); ! 489: return(1); ! 490: } ! 491: ppathhead(strcpy(pppathname, ppathname)); ! 492: } ! 493: else { ! 494: ppathcat(pppathname, ppathname, PARENTPROJECT); ! 495: } ! 496: if (xppath(pppathname, &ppathbuf) == -1) ! 497: { ! 498: patherr(""); ! 499: warn("force conversion by typing `rmproject -uF projectname'"); ! 500: return(1); ! 501: } ! 502: if ((pldp = openpdb(PLDNAME, ppathbuf.p_path, "rw")) == NULL) ! 503: return(errpdb((PDB *) NULL)); ! 504: while ((pd = readpld(pldp)) != NULL) ! 505: if (EQUAL(pb->p_alias, pd->p_alias)) ! 506: { ! 507: pstatus = subprojects(pb->p_path); ! 508: if (pstatus == 1) ! 509: { ! 510: warn("can't undefine %s: project not empty", ! 511: ppathname); ! 512: resetpdb(pldp); ! 513: break; ! 514: } ! 515: else if (pstatus == 2) ! 516: { ! 517: warn("can't undefine %s because subprojects exist", ! 518: ppathname); ! 519: resetpdb(pldp); ! 520: break; ! 521: } ! 522: else if (pstatus == 3) ! 523: { ! 524: resetpdb(pldp); ! 525: break; ! 526: } ! 527: resetpdb(pldp); ! 528: } ! 529: else { ! 530: pputent(pldp); ! 531: } ! 532: if (pstatus != 0) ! 533: _closepdb(pldp); ! 534: else if ((pstatus = rmpld(pb->p_path)) != 0) ! 535: _closepdb(pldp); ! 536: else ! 537: pstatus = closepdb(pldp); ! 538: return(pstatus != 0); ! 539: } ! 540: ! 541: ! 542: ! 543: /* ! 544: * warnexist() warns of nested or duplicate projects. ! 545: */ ! 546: warnexist(ppathname, alias) ! 547: char *ppathname; /* project to be removed */ ! 548: char *alias; /* nested or duplicate project alias */ ! 549: { ! 550: char npathname[PPATHSIZE]; /* nested project pathname */ ! 551: char *p; /* nested project pathname pointer */ ! 552: char *strpcpy(); /* string copy and update pointer */ ! 553: ! 554: p = strpcpy(npathname, ppathname); ! 555: while (p > npathname && p[-1] != _PPSC) ! 556: p--; ! 557: *p = '\0'; ! 558: warn("can't remove %s because project %s%s exists", ppathname, ! 559: npathname, alias); ! 560: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.