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