|
|
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.