1 /*
2 * Copyright (c) 1990 Carnegie Mellon University
3 * All Rights Reserved.
4 *
5 * Permission to use, copy, modify and distribute this software and its
6 * documentation is hereby granted, provided that both the copyright
7 * notice and this permission notice appear in all copies of the
8 * software, derivative works or modified versions, and any portions
9 * thereof, and that both notices appear in supporting documentation.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
12 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT
14 * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
15 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
16 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
17 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *
20 * Users of this software agree to return to Carnegie Mellon any
21 * improvements or extensions that they make and grant Carnegie the
22 * rights to redistribute these changes.
23 *
24 * Export of this software is permitted only after complying with the
25 * regulations of the U.S. Deptartment of Commerce relating to the
26 * Export of Technical Data.
27 */
28 /*
29 * setpath --- smart interface for setting path variables
30 *
31 * usage: setpath(paths, cmds, localsyspath, dosuffix, printerrors)
32 * char **paths, **cmds, *localsyspath;
33 * int dosuffix, printerrors;
34 *
35 * The 'paths' argument is a list of pointers to path lists of the
36 * form "name=value" where name is the name of the path and value
37 * is a colon separated list of directories. There can never be
38 * more than MAXDIRS (64) directories in a path.
39 *
40 * The 'cmds' argument may be a sequence of any of the following:
41 * -r reset path to default
42 * -i newpath insert newpath before localsyspath
43 * -ia oldpath newpath insert newpath after oldpath
44 * -ib oldpath newpath insert newpath before oldpath
45 * -i# newpath insert newpath at position #
46 * -d oldpath delete oldpath
47 * -d# delete path at position #
48 * -c oldpath newpath change oldpath to newpath
49 * -c# newpath change position # to newpath
50 *
51 * The "-i newpath" command is equivilent to "-ib 'localsyspath' newpath".
52 *
53 * If 'dosuffix' is true, the appropriate suffix will be added to
54 * all command operands for any system path in 'paths'.
55 *
56 * Both of the 'paths' and 'cmds' lists are terminated by a NULL
57 * entry.
58 *
59 * if 'printerrors' is true, setpath will printf error diagnostics.
60 *
61 * WARNING !!!: Under no circumstances should anyone change this
62 * module without fully understanding the impact on the C shell.
63 * The C shell has it's own malloc and printf routines and this
64 * module was carefully written taking that into account. Do not
65 * use any stdio routines from this module except printf.
66 *
67 **********************************************************************
68 * HISTORY
69 *
70 * Revision 1.4 90/12/11 17:58:44 mja
71 * Add copyright/disclaimer for distribution.
72 *
73 * 05-Jun-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
74 * Make all non-entry points static.
75 *
76 * 30-Apr-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
77 * Added -r switch to reset paths to their default values.
78 *
79 * 06-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
80 * Created from old setpath program for the shell.
81 *
82 **********************************************************************
83 */
84 #include "sh.h"
85
86 #ifdef MACH
87
88 #define MAXDIRS 64 /* max directories on a path */
89 #ifndef NULL
90 # define NULL 0
91 #endif
92
93 static int npaths; /* # pathlist arguments */
94
95 static struct pelem {
96 struct pelem *pnext; /* pointer to next path */
97 char *pname; /* name of pathlist */
98 char *psuf; /* suffix for pathlist */
99 char *pdef; /* default for pathlist */
100 int pdirs; /* # directories on each pathlist */
101 char *pdir[MAXDIRS]; /* directory names for each pathlist */
102 } *pathhead = NULL;
103
104 static struct {
105 char *name;
106 char *suffix;
107 char *defalt;
108 } syspath[] = {
109 "PATH", "/bin", ":/usr/ucb:/bin:/usr/bin",
110 "CPATH", "/include", ":/usr/include",
111 "LPATH", "/lib", ":/lib:/usr/lib",
112 "MPATH", "/man", ":/usr/man",
113 "EPATH", "/maclib", "",
114 0, 0, 0
115 };
116
117 static int sflag;
118 static int eflag;
119
120 #define INVALID { \
121 if (eflag) xprintf(CGETS(10, 1, \
122 "setpath: invalid command '%s'.\n"), cmd); \
123 freepaths(); \
124 return(-1); \
125 }
126
127 #define TOOFEW { \
128 if (eflag) xprintf(CGETS(10, 2, \
129 "setpath: insufficient arguments to command '%s'.\n"), cmd); \
130 freepaths(); \
131 return(-1); \
132 }
133
134 static int initpaths (char **);
135 static void savepaths (char **);
136 static void freepaths (void);
137 static void tcsh_rcmd (char *);
138 static void icmd (char *, char *);
139 static void iacmd (char *, char *);
140 static void ibcmd (char *, char *);
141 static void incmd (char *, int);
142 static void insert (struct pelem *, int, char *);
143 static void dcmd (char *);
144 static void dncmd (int);
145 static void delete (struct pelem *, int);
146 static void ccmd (char *, char *);
147 static void cncmd (char *, int);
148 static void change (struct pelem *, int, char *);
149 static int locate (struct pelem *, char *);
150
151
152
153 int
setpath(char ** paths,char ** cmds,char * localsyspath,int dosuffix,int printerrors)154 setpath(char **paths, char **cmds, char *localsyspath, int dosuffix,
155 int printerrors)
156 {
157 char *cmd, *cmd1, *cmd2;
158 int ncmd;
159
160 sflag = dosuffix;
161 eflag = printerrors;
162 if (initpaths(paths) < 0)
163 return(-1);
164 if (npaths == 0)
165 return(0);
166 for (ncmd = 0; cmd = cmds[ncmd]; ncmd++) {
167 if (cmd[0] != '-')
168 INVALID;
169 cmd1 = cmds[ncmd+1];
170 cmd2 = cmds[ncmd+2];
171 switch (cmd[1]) {
172 case 'r':
173 if (cmd[2] != '\0')
174 INVALID;
175 tcsh_rcmd(localsyspath);
176 break;
177 case 'i':
178 if (cmd[2] == '\0') {
179 ncmd++;
180 if (cmd1 == NULL) TOOFEW;
181 icmd(cmd1, localsyspath);
182 } else if (isdigit(cmd[2])) {
183 ncmd++;
184 if (cmd1 == NULL) TOOFEW;
185 incmd(cmd1, atoi(cmd+2));
186 } else if (cmd[3] != '\0' || (cmd[2] != 'a' && cmd[2] != 'b')) {
187 INVALID;
188 } else {
189 ncmd += 2;
190 if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
191 if (cmd[2] == 'a')
192 iacmd(cmd1, cmd2);
193 else
194 ibcmd(cmd1, cmd2);
195 }
196 break;
197 case 'd':
198 if (cmd[2] == '\0') {
199 ncmd++;
200 if (cmd1 == NULL) TOOFEW;
201 dcmd(cmd1);
202 } else if (isdigit(cmd[2]))
203 dncmd(atoi(cmd+2));
204 else {
205 INVALID;
206 }
207 break;
208 case 'c':
209 if (cmd[2] == '\0') {
210 ncmd += 2;
211 if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
212 ccmd(cmd1, cmd2);
213 } else if (isdigit(cmd[2])) {
214 ncmd++;
215 if (cmd1 == NULL) TOOFEW;
216 cncmd(cmd1, atoi(cmd+2));
217 } else {
218 INVALID;
219 }
220 break;
221 default:
222 INVALID;
223 }
224 }
225 savepaths(paths);
226 freepaths();
227 return(0);
228 }
229
230 static int
initpaths(char ** paths)231 initpaths(char **paths)
232 {
233 char *path, *val, *p, *q;
234 int i, done;
235 struct pelem *pe, *pathend;
236
237 freepaths();
238 for (npaths = 0; path = paths[npaths]; npaths++) {
239 val = index(path, '=');
240 if (val == NULL) {
241 if (eflag)
242 xprintf(CGETS(10, 3,
243 "setpath: value missing in path '%s'\n"), path);
244 freepaths();
245 return(-1);
246 }
247 *val++ = '\0';
248 pe = xmalloc(sizeof(struct pelem));
249 setzero(pe, sizeof(struct pelem));
250 if (pathhead == NULL)
251 pathhead = pathend = pe;
252 else {
253 pathend->pnext = pe;
254 pathend = pe;
255 }
256 p = strsave(path);
257 pe->pname = p;
258 pe->psuf = "";
259 pe->pdef = "";
260 for (i = 0; syspath[i].name; i++)
261 if (strcmp(pe->pname, syspath[i].name) == 0) {
262 pe->psuf = syspath[i].suffix;
263 pe->pdef = syspath[i].defalt;
264 break;
265 }
266 q = val;
267 for (;;) {
268 q = index(p = q, ':');
269 done = (q == NULL);
270 if (!done)
271 *q++ = '\0';
272 p = strsave(p);
273 pe->pdir[pe->pdirs] = p;
274 pe->pdirs++;
275 if (done)
276 break;
277 }
278 }
279 return(0);
280 }
281
282 static void
savepaths(char ** paths)283 savepaths(char **paths)
284 {
285 char *p, *q;
286 int npath, i, len;
287 struct pelem *pe;
288
289 for (npath = 0, pe = pathhead; pe; npath++, pe = pe->pnext) {
290 len = strlen(pe->pname) + 1;
291 if (pe->pdirs == 0)
292 len++;
293 else for (i = 0; i < pe->pdirs; i++)
294 len += strlen(pe->pdir[i]) + 1;
295 p = xmalloc((unsigned)len);
296 paths[npath] = p;
297 for (q = pe->pname; *p = *q; p++, q++);
298 *p++ = '=';
299 if (pe->pdirs != 0) {
300 for (i = 0; i < pe->pdirs; i++) {
301 for (q = pe->pdir[i]; *p = *q; p++, q++);
302 *p++ = ':';
303 }
304 p--;
305 }
306 *p = '\0';
307 }
308 }
309
310 static void
freepaths(void)311 freepaths(void)
312 {
313 char *p;
314 int i;
315 struct pelem *pe;
316
317 if (npaths == 0 || pathhead == NULL)
318 return;
319 while (pe = pathhead) {
320 if (pe->pname) {
321 for (i = 0; i < pe->pdirs; i++) {
322 if (pe->pdir[i] == NULL)
323 continue;
324 p = pe->pdir[i];
325 pe->pdir[i] = NULL;
326 xfree((ptr_t) p);
327 }
328 pe->pdirs = 0;
329 p = pe->pname;
330 pe->pname = NULL;
331 xfree((ptr_t) p);
332 }
333 pathhead = pe->pnext;
334 xfree((ptr_t) pe);
335 }
336 npaths = 0;
337 }
338
339 /***********************************************
340 *** R E S E T A P A T H N A M E ***
341 ***********************************************/
342
343 static void
tcsh_rcmd(char * localsyspath)344 tcsh_rcmd(char *localsyspath) /* reset path with localsyspath */
345 {
346 int n, done;
347 char *new, *p;
348 struct pelem *pe;
349 char newbuf[MAXPATHLEN+1];/*FIXBUF*/
350
351 for (pe = pathhead; pe; pe = pe->pnext) {
352 new = newbuf;
353 *new = '\0';
354 if (localsyspath != NULL) {
355 *new = ':';
356 (void) strcpy(new + 1, localsyspath);
357 (void) strcat(new, pe->psuf);
358 }
359 (void) strcat(new, pe->pdef);
360 for (n = 0; n < pe->pdirs; n++) {
361 if (pe->pdir[n] == NULL)
362 continue;
363 p = pe->pdir[n];
364 pe->pdir[n] = NULL;
365 xfree((ptr_t) p);
366 }
367 pe->pdirs = 0;
368 for (;;) {
369 new = index(p = new, ':');
370 done = (new == NULL);
371 if (!done)
372 *new++ = '\0';
373 p = strsave(p);
374 pe->pdir[pe->pdirs] = p;
375 pe->pdirs++;
376 if (done)
377 break;
378 }
379 }
380 }
381
382 /***********************************************
383 *** I N S E R T A P A T H N A M E ***
384 ***********************************************/
385
386 static void
icmd(char * path,char * localsyspath)387 icmd(char *path, char *localsyspath) /* insert path before localsyspath */
388 {
389 int n;
390 char *new;
391 struct pelem *pe;
392 char newbuf[MAXPATHLEN+1];/*FIXBUF*/
393
394 for (pe = pathhead; pe; pe = pe->pnext) {
395 if (sflag)
396 new = localsyspath;
397 else {
398 new = newbuf;
399 (void) strcpy(new, localsyspath);
400 (void) strcat(new, pe->psuf);
401 }
402 n = locate(pe, new);
403 if (n >= 0)
404 insert(pe, n, path);
405 else
406 insert(pe, 0, path);
407 }
408 }
409
410 static void
iacmd(char * inpath,char * path)411 iacmd(char *inpath, char *path) /* insert path after inpath */
412 {
413 int n;
414 struct pelem *pe;
415
416 for (pe = pathhead; pe; pe = pe->pnext) {
417 n = locate(pe, inpath);
418 if (n >= 0)
419 insert(pe, n + 1, path);
420 else
421 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
422 inpath, pe->pname);
423 }
424 }
425
426 static void
ibcmd(char * inpath,char * path)427 ibcmd(char *inpath, char *path) /* insert path before inpath */
428 {
429 int n;
430 struct pelem *pe;
431
432 for (pe = pathhead; pe; pe = pe->pnext) {
433 n = locate(pe, inpath);
434 if (n >= 0)
435 insert(pe, n, path);
436 else
437 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
438 inpath, pe->pname);
439 }
440 }
441
442 static void
incmd(char * path,int n)443 incmd(char *path, int n) /* insert path at position n */
444 {
445 struct pelem *pe;
446
447 for (pe = pathhead; pe; pe = pe->pnext)
448 insert(pe, n, path);
449 }
450
451 static void
insert(struct pelem * pe,int loc,char * key)452 insert(struct pelem *pe, int loc, char *key)
453 {
454 int i;
455 char *new;
456 char newbuf[2000];/*FIXBUF*/
457
458 if (sflag) { /* add suffix */
459 new = newbuf;
460 (void) strcpy(new, key);
461 (void) strcat(new, pe->psuf);
462 } else
463 new = key;
464 new = strsave(new);
465 for (i = pe->pdirs; i > loc; --i)
466 pe->pdir[i] = pe->pdir[i-1];
467 if (loc > pe->pdirs)
468 loc = pe->pdirs;
469 pe->pdir[loc] = new;
470 pe->pdirs++;
471 }
472
473 /***********************************************
474 *** D E L E T E A P A T H N A M E ***
475 ***********************************************/
476
477 static void
dcmd(char * path)478 dcmd(char *path) /* delete path */
479 {
480 int n;
481 struct pelem *pe;
482
483 for (pe = pathhead; pe; pe = pe->pnext) {
484 n = locate(pe, path);
485 if (n >= 0)
486 delete(pe, n);
487 else
488 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
489 path, pe->pname);
490 }
491 }
492
493 static void
dncmd(int n)494 dncmd(int n) /* delete at position n */
495 {
496 struct pelem *pe;
497
498 for (pe = pathhead; pe; pe = pe->pnext) {
499 if (n < pe->pdirs)
500 delete(pe, n);
501 else
502 xprintf(CGETS(10, 5,
503 "setpath: %d not valid position in %s\n"),
504 n, pe->pname);
505 }
506 }
507
508 static void
delete(struct pelem * pe,int n)509 delete(struct pelem *pe, int n)
510 {
511 int d;
512
513 xfree((ptr_t) (pe->pdir[n]));
514 for (d = n; d < pe->pdirs - 1; d++)
515 pe->pdir[d] = pe->pdir[d+1];
516 --pe->pdirs;
517 }
518
519 /***********************************************
520 *** C H A N G E A P A T H N A M E ***
521 ***********************************************/
522
523 static void
ccmd(char * inpath,char * path)524 ccmd(char *inpath, char *path) /* change inpath to path */
525 {
526 int n;
527 struct pelem *pe;
528
529 for (pe = pathhead; pe; pe = pe->pnext) {
530 n = locate(pe, inpath);
531 if (n >= 0)
532 change(pe, n, path);
533 else
534 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
535 inpath, pe->pname);
536 }
537 }
538
539 static void
cncmd(char * path,int n)540 cncmd(char *path, int n) /* change at position n to path */
541 {
542 struct pelem *pe;
543
544 for (pe = pathhead; pe; pe = pe->pnext) {
545 if (n < pe->pdirs)
546 change(pe, n, path);
547 else
548 xprintf(CGETS(10, 5,
549 "setpath: %d not valid position in %s\n"),
550 n, pe->pname);
551 }
552 }
553
554 static void
change(struct pelem * pe,int loc,char * key)555 change(struct pelem *pe, int loc, char *key)
556 {
557 char *new;
558 char newbuf[MAXPATHLEN+1];/*FIXBUF*/
559
560 if (sflag) { /* append suffix */
561 new = newbuf;
562 (void) strcpy(new, key);
563 (void) strcat(new, pe->psuf);
564 } else
565 new = key;
566 new = strsave(new);
567 xfree((ptr_t) (pe->pdir[loc]));
568 pe->pdir[loc] = new;
569 }
570
571 /***************************************
572 *** F I N D P A T H N A M E ***
573 ***************************************/
574
575 static int
locate(struct pelem * pe,char * key)576 locate(struct pelem *pe, char *key)
577 {
578 int i;
579 char *realkey;
580 char keybuf[MAXPATHLEN+1];/*FIXBUF*/
581
582 if (sflag) {
583 realkey = keybuf;
584 (void) strcpy(realkey, key);
585 (void) strcat(realkey, pe->psuf);
586 } else
587 realkey = key;
588 for (i = 0; i < pe->pdirs; i++)
589 if (strcmp(pe->pdir[i], realkey) == 0)
590 break;
591 return((i < pe->pdirs) ? i : -1);
592 }
593 #endif
594