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 RCSID("$tcsh: ma.setp.c,v 1.19 2007/11/20 20:03:51 christos Exp $")
86
87 #ifdef MACH
88
89 #define MAXDIRS 64 /* max directories on a path */
90 #ifndef NULL
91 # define NULL 0
92 #endif
93
94 static int npaths; /* # pathlist arguments */
95
96 static struct pelem {
97 struct pelem *pnext; /* pointer to next path */
98 char *pname; /* name of pathlist */
99 char *psuf; /* suffix for pathlist */
100 char *pdef; /* default for pathlist */
101 int pdirs; /* # directories on each pathlist */
102 char *pdir[MAXDIRS]; /* directory names for each pathlist */
103 } *pathhead = NULL;
104
105 static struct {
106 char *name;
107 char *suffix;
108 char *defalt;
109 } syspath[] = {
110 "PATH", "/bin", ":/usr/ucb:/bin:/usr/bin",
111 "CPATH", "/include", ":/usr/include",
112 "LPATH", "/lib", ":/lib:/usr/lib",
113 "MPATH", "/man", ":/usr/man",
114 "EPATH", "/maclib", "",
115 0, 0, 0
116 };
117
118 static int sflag;
119 static int eflag;
120
121 #define INVALID { \
122 if (eflag) xprintf(CGETS(10, 1, \
123 "setpath: invalid command '%s'.\n"), cmd); \
124 freepaths(); \
125 return(-1); \
126 }
127
128 #define TOOFEW { \
129 if (eflag) xprintf(CGETS(10, 2, \
130 "setpath: insufficient arguments to command '%s'.\n"), cmd); \
131 freepaths(); \
132 return(-1); \
133 }
134
135 static int initpaths (char **);
136 static void savepaths (char **);
137 static void freepaths (void);
138 static void tcsh_rcmd (char *);
139 static void icmd (char *, char *);
140 static void iacmd (char *, char *);
141 static void ibcmd (char *, char *);
142 static void incmd (char *, int);
143 static void insert (struct pelem *, int, char *);
144 static void dcmd (char *);
145 static void dncmd (int);
146 static void delete (struct pelem *, int);
147 static void ccmd (char *, char *);
148 static void cncmd (char *, int);
149 static void change (struct pelem *, int, char *);
150 static int locate (struct pelem *, char *);
151
152
153
154 int
setpath(char ** paths,char ** cmds,char * localsyspath,int dosuffix,int printerrors)155 setpath(char **paths, char **cmds, char *localsyspath, int dosuffix,
156 int printerrors)
157 {
158 char *cmd, *cmd1, *cmd2;
159 int ncmd;
160
161 sflag = dosuffix;
162 eflag = printerrors;
163 if (initpaths(paths) < 0)
164 return(-1);
165 if (npaths == 0)
166 return(0);
167 for (ncmd = 0; cmd = cmds[ncmd]; ncmd++) {
168 if (cmd[0] != '-')
169 INVALID;
170 cmd1 = cmds[ncmd+1];
171 cmd2 = cmds[ncmd+2];
172 switch (cmd[1]) {
173 case 'r':
174 if (cmd[2] != '\0')
175 INVALID;
176 tcsh_rcmd(localsyspath);
177 break;
178 case 'i':
179 if (cmd[2] == '\0') {
180 ncmd++;
181 if (cmd1 == NULL) TOOFEW;
182 icmd(cmd1, localsyspath);
183 } else if (isdigit(cmd[2])) {
184 ncmd++;
185 if (cmd1 == NULL) TOOFEW;
186 incmd(cmd1, atoi(cmd+2));
187 } else if (cmd[3] != '\0' || (cmd[2] != 'a' && cmd[2] != 'b')) {
188 INVALID;
189 } else {
190 ncmd += 2;
191 if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
192 if (cmd[2] == 'a')
193 iacmd(cmd1, cmd2);
194 else
195 ibcmd(cmd1, cmd2);
196 }
197 break;
198 case 'd':
199 if (cmd[2] == '\0') {
200 ncmd++;
201 if (cmd1 == NULL) TOOFEW;
202 dcmd(cmd1);
203 } else if (isdigit(cmd[2]))
204 dncmd(atoi(cmd+2));
205 else {
206 INVALID;
207 }
208 break;
209 case 'c':
210 if (cmd[2] == '\0') {
211 ncmd += 2;
212 if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
213 ccmd(cmd1, cmd2);
214 } else if (isdigit(cmd[2])) {
215 ncmd++;
216 if (cmd1 == NULL) TOOFEW;
217 cncmd(cmd1, atoi(cmd+2));
218 } else {
219 INVALID;
220 }
221 break;
222 default:
223 INVALID;
224 }
225 }
226 savepaths(paths);
227 freepaths();
228 return(0);
229 }
230
231 static int
initpaths(char ** paths)232 initpaths(char **paths)
233 {
234 char *path, *val, *p, *q;
235 int i, done;
236 struct pelem *pe, *pathend;
237
238 freepaths();
239 for (npaths = 0; path = paths[npaths]; npaths++) {
240 val = index(path, '=');
241 if (val == NULL) {
242 if (eflag)
243 xprintf(CGETS(10, 3,
244 "setpath: value missing in path '%s'\n"), path);
245 freepaths();
246 return(-1);
247 }
248 *val++ = '\0';
249 pe = xmalloc(sizeof(struct pelem));
250 setzero(pe, sizeof(struct pelem));
251 if (pathhead == NULL)
252 pathhead = pathend = pe;
253 else {
254 pathend->pnext = pe;
255 pathend = pe;
256 }
257 p = strsave(path);
258 pe->pname = p;
259 pe->psuf = "";
260 pe->pdef = "";
261 for (i = 0; syspath[i].name; i++)
262 if (strcmp(pe->pname, syspath[i].name) == 0) {
263 pe->psuf = syspath[i].suffix;
264 pe->pdef = syspath[i].defalt;
265 break;
266 }
267 q = val;
268 for (;;) {
269 q = index(p = q, ':');
270 done = (q == NULL);
271 if (!done)
272 *q++ = '\0';
273 p = strsave(p);
274 pe->pdir[pe->pdirs] = p;
275 pe->pdirs++;
276 if (done)
277 break;
278 }
279 }
280 return(0);
281 }
282
283 static void
savepaths(char ** paths)284 savepaths(char **paths)
285 {
286 char *p, *q;
287 int npath, i, len;
288 struct pelem *pe;
289
290 for (npath = 0, pe = pathhead; pe; npath++, pe = pe->pnext) {
291 len = strlen(pe->pname) + 1;
292 if (pe->pdirs == 0)
293 len++;
294 else for (i = 0; i < pe->pdirs; i++)
295 len += strlen(pe->pdir[i]) + 1;
296 p = xmalloc((unsigned)len);
297 paths[npath] = p;
298 for (q = pe->pname; *p = *q; p++, q++);
299 *p++ = '=';
300 if (pe->pdirs != 0) {
301 for (i = 0; i < pe->pdirs; i++) {
302 for (q = pe->pdir[i]; *p = *q; p++, q++);
303 *p++ = ':';
304 }
305 p--;
306 }
307 *p = '\0';
308 }
309 }
310
311 static void
freepaths(void)312 freepaths(void)
313 {
314 char *p;
315 int i;
316 struct pelem *pe;
317
318 if (npaths == 0 || pathhead == NULL)
319 return;
320 while (pe = pathhead) {
321 if (pe->pname) {
322 for (i = 0; i < pe->pdirs; i++) {
323 if (pe->pdir[i] == NULL)
324 continue;
325 p = pe->pdir[i];
326 pe->pdir[i] = NULL;
327 xfree((ptr_t) p);
328 }
329 pe->pdirs = 0;
330 p = pe->pname;
331 pe->pname = NULL;
332 xfree((ptr_t) p);
333 }
334 pathhead = pe->pnext;
335 xfree((ptr_t) pe);
336 }
337 npaths = 0;
338 }
339
340 /***********************************************
341 *** R E S E T A P A T H N A M E ***
342 ***********************************************/
343
344 static void
tcsh_rcmd(char * localsyspath)345 tcsh_rcmd(char *localsyspath) /* reset path with localsyspath */
346 {
347 int n, done;
348 char *new, *p;
349 struct pelem *pe;
350 char newbuf[MAXPATHLEN+1];/*FIXBUF*/
351
352 for (pe = pathhead; pe; pe = pe->pnext) {
353 new = newbuf;
354 *new = '\0';
355 if (localsyspath != NULL) {
356 *new = ':';
357 (void) strcpy(new + 1, localsyspath);
358 (void) strcat(new, pe->psuf);
359 }
360 (void) strcat(new, pe->pdef);
361 for (n = 0; n < pe->pdirs; n++) {
362 if (pe->pdir[n] == NULL)
363 continue;
364 p = pe->pdir[n];
365 pe->pdir[n] = NULL;
366 xfree((ptr_t) p);
367 }
368 pe->pdirs = 0;
369 for (;;) {
370 new = index(p = new, ':');
371 done = (new == NULL);
372 if (!done)
373 *new++ = '\0';
374 p = strsave(p);
375 pe->pdir[pe->pdirs] = p;
376 pe->pdirs++;
377 if (done)
378 break;
379 }
380 }
381 }
382
383 /***********************************************
384 *** I N S E R T A P A T H N A M E ***
385 ***********************************************/
386
387 static void
icmd(char * path,char * localsyspath)388 icmd(char *path, char *localsyspath) /* insert path before localsyspath */
389 {
390 int n;
391 char *new;
392 struct pelem *pe;
393 char newbuf[MAXPATHLEN+1];/*FIXBUF*/
394
395 for (pe = pathhead; pe; pe = pe->pnext) {
396 if (sflag)
397 new = localsyspath;
398 else {
399 new = newbuf;
400 (void) strcpy(new, localsyspath);
401 (void) strcat(new, pe->psuf);
402 }
403 n = locate(pe, new);
404 if (n >= 0)
405 insert(pe, n, path);
406 else
407 insert(pe, 0, path);
408 }
409 }
410
411 static void
iacmd(char * inpath,char * path)412 iacmd(char *inpath, char *path) /* insert path after inpath */
413 {
414 int n;
415 struct pelem *pe;
416
417 for (pe = pathhead; pe; pe = pe->pnext) {
418 n = locate(pe, inpath);
419 if (n >= 0)
420 insert(pe, n + 1, path);
421 else
422 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
423 inpath, pe->pname);
424 }
425 }
426
427 static void
ibcmd(char * inpath,char * path)428 ibcmd(char *inpath, char *path) /* insert path before inpath */
429 {
430 int n;
431 struct pelem *pe;
432
433 for (pe = pathhead; pe; pe = pe->pnext) {
434 n = locate(pe, inpath);
435 if (n >= 0)
436 insert(pe, n, path);
437 else
438 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
439 inpath, pe->pname);
440 }
441 }
442
443 static void
incmd(char * path,int n)444 incmd(char *path, int n) /* insert path at position n */
445 {
446 struct pelem *pe;
447
448 for (pe = pathhead; pe; pe = pe->pnext)
449 insert(pe, n, path);
450 }
451
452 static void
insert(struct pelem * pe,int loc,char * key)453 insert(struct pelem *pe, int loc, char *key)
454 {
455 int i;
456 char *new;
457 char newbuf[2000];/*FIXBUF*/
458
459 if (sflag) { /* add suffix */
460 new = newbuf;
461 (void) strcpy(new, key);
462 (void) strcat(new, pe->psuf);
463 } else
464 new = key;
465 new = strsave(new);
466 for (i = pe->pdirs; i > loc; --i)
467 pe->pdir[i] = pe->pdir[i-1];
468 if (loc > pe->pdirs)
469 loc = pe->pdirs;
470 pe->pdir[loc] = new;
471 pe->pdirs++;
472 }
473
474 /***********************************************
475 *** D E L E T E A P A T H N A M E ***
476 ***********************************************/
477
478 static void
dcmd(char * path)479 dcmd(char *path) /* delete path */
480 {
481 int n;
482 struct pelem *pe;
483
484 for (pe = pathhead; pe; pe = pe->pnext) {
485 n = locate(pe, path);
486 if (n >= 0)
487 delete(pe, n);
488 else
489 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
490 path, pe->pname);
491 }
492 }
493
494 static void
dncmd(int n)495 dncmd(int n) /* delete at position n */
496 {
497 struct pelem *pe;
498
499 for (pe = pathhead; pe; pe = pe->pnext) {
500 if (n < pe->pdirs)
501 delete(pe, n);
502 else
503 xprintf(CGETS(10, 5,
504 "setpath: %d not valid position in %s\n"),
505 n, pe->pname);
506 }
507 }
508
509 static void
delete(struct pelem * pe,int n)510 delete(struct pelem *pe, int n)
511 {
512 int d;
513
514 xfree((ptr_t) (pe->pdir[n]));
515 for (d = n; d < pe->pdirs - 1; d++)
516 pe->pdir[d] = pe->pdir[d+1];
517 --pe->pdirs;
518 }
519
520 /***********************************************
521 *** C H A N G E A P A T H N A M E ***
522 ***********************************************/
523
524 static void
ccmd(char * inpath,char * path)525 ccmd(char *inpath, char *path) /* change inpath to path */
526 {
527 int n;
528 struct pelem *pe;
529
530 for (pe = pathhead; pe; pe = pe->pnext) {
531 n = locate(pe, inpath);
532 if (n >= 0)
533 change(pe, n, path);
534 else
535 xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
536 inpath, pe->pname);
537 }
538 }
539
540 static void
cncmd(char * path,int n)541 cncmd(char *path, int n) /* change at position n to path */
542 {
543 struct pelem *pe;
544
545 for (pe = pathhead; pe; pe = pe->pnext) {
546 if (n < pe->pdirs)
547 change(pe, n, path);
548 else
549 xprintf(CGETS(10, 5,
550 "setpath: %d not valid position in %s\n"),
551 n, pe->pname);
552 }
553 }
554
555 static void
change(struct pelem * pe,int loc,char * key)556 change(struct pelem *pe, int loc, char *key)
557 {
558 char *new;
559 char newbuf[MAXPATHLEN+1];/*FIXBUF*/
560
561 if (sflag) { /* append suffix */
562 new = newbuf;
563 (void) strcpy(new, key);
564 (void) strcat(new, pe->psuf);
565 } else
566 new = key;
567 new = strsave(new);
568 xfree((ptr_t) (pe->pdir[loc]));
569 pe->pdir[loc] = new;
570 }
571
572 /***************************************
573 *** F I N D P A T H N A M E ***
574 ***************************************/
575
576 static int
locate(struct pelem * pe,char * key)577 locate(struct pelem *pe, char *key)
578 {
579 int i;
580 char *realkey;
581 char keybuf[MAXPATHLEN+1];/*FIXBUF*/
582
583 if (sflag) {
584 realkey = keybuf;
585 (void) strcpy(realkey, key);
586 (void) strcat(realkey, pe->psuf);
587 } else
588 realkey = key;
589 for (i = 0; i < pe->pdirs; i++)
590 if (strcmp(pe->pdir[i], realkey) == 0)
591 break;
592 return((i < pe->pdirs) ? i : -1);
593 }
594 #endif
595