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