library.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. #ifndef lint
  2. static char sccsid[] = "@(#)library.c 1.4 (Berkeley) 8/13/83";
  3. #endif
  4. /* Copyright (c) 1982 Regents of the University of California */
  5. /*
  6. * General purpose routines.
  7. */
  8. #include <stdio.h>
  9. #include <errno.h>
  10. #include <signal.h>
  11. #define public
  12. #define private static
  13. #define and &&
  14. #define or ||
  15. #define not !
  16. #define ord(enumcon) ((int) enumcon)
  17. #define nil(type) ((type) 0)
  18. typedef enum { FALSE, TRUE } Boolean;
  19. typedef char *String;
  20. typedef FILE *File;
  21. typedef String Filename;
  22. #undef FILE
  23. /*
  24. * Definitions of standard C library routines that aren't in the
  25. * standard I/O library, but which are generally useful.
  26. */
  27. extern long atol(); /* ascii to long */
  28. extern double atof(); /* ascii to floating point */
  29. extern char *mktemp(); /* make a temporary file name */
  30. String cmdname; /* name of command for error messages */
  31. Filename errfilename; /* current file associated with error */
  32. short errlineno; /* line number associated with error */
  33. /*
  34. * Definitions for doing memory allocation.
  35. */
  36. extern char *malloc();
  37. #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))
  38. #define dispose(p) { free((char *) p); p = 0; }
  39. /*
  40. * Macros for doing freads + fwrites.
  41. */
  42. #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp)
  43. #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp)
  44. /*
  45. * String definitions.
  46. */
  47. extern String strcpy(), index(), rindex();
  48. extern int strlen();
  49. #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)
  50. #define streq(s1, s2) (strcmp(s1, s2) == 0)
  51. typedef int INTFUNC();
  52. typedef struct {
  53. INTFUNC *func;
  54. } ERRINFO;
  55. #define ERR_IGNORE ((INTFUNC *) 0)
  56. #define ERR_CATCH ((INTFUNC *) 1)
  57. /*
  58. * Call a program.
  59. *
  60. * Four entries:
  61. *
  62. * call, callv - call a program and wait for it, returning status
  63. * back, backv - call a program and don't wait, returning process id
  64. *
  65. * The command's standard input and output are passed as FILE's.
  66. */
  67. #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */
  68. #define BADEXEC 127 /* exec fails */
  69. #define ischild(pid) ((pid) == 0)
  70. /* VARARGS3 */
  71. public int call(name, in, out, args)
  72. String name;
  73. File in;
  74. File out;
  75. String args;
  76. {
  77. String *ap, *argp;
  78. String argv[MAXNARGS];
  79. argp = &argv[0];
  80. *argp++ = name;
  81. ap = &args;
  82. while (*ap != nil(String)) {
  83. *argp++ = *ap++;
  84. }
  85. *argp = nil(String);
  86. return callv(name, in, out, argv);
  87. }
  88. /* VARARGS3 */
  89. public int back(name, in, out, args)
  90. String name;
  91. File in;
  92. File out;
  93. String args;
  94. {
  95. String *ap, *argp;
  96. String argv[MAXNARGS];
  97. argp = &argv[0];
  98. *argp++ = name;
  99. ap = &args;
  100. while (*ap != nil(String)) {
  101. *argp++ = *ap++;
  102. }
  103. *argp = nil(String);
  104. return backv(name, in, out, argv);
  105. }
  106. public int callv(name, in, out, argv)
  107. String name;
  108. File in;
  109. File out;
  110. String *argv;
  111. {
  112. int pid, status;
  113. pid = backv(name, in, out, argv);
  114. pwait(pid, &status);
  115. return status;
  116. }
  117. public int backv(name, in, out, argv)
  118. String name;
  119. File in;
  120. File out;
  121. String *argv;
  122. {
  123. int pid;
  124. fflush(stdout);
  125. if (ischild(pid = fork())) {
  126. fswap(0, fileno(in));
  127. fswap(1, fileno(out));
  128. onsyserr(EACCES, ERR_IGNORE);
  129. execvp(name, argv);
  130. _exit(BADEXEC);
  131. }
  132. return pid;
  133. }
  134. /*
  135. * Swap file numbers so as to redirect standard input and output.
  136. */
  137. private fswap(oldfd, newfd)
  138. int oldfd;
  139. int newfd;
  140. {
  141. if (oldfd != newfd) {
  142. close(oldfd);
  143. dup(newfd);
  144. close(newfd);
  145. }
  146. }
  147. /*
  148. * Invoke a shell on a command line.
  149. */
  150. #define DEF_SHELL "csh"
  151. public shell(s)
  152. String s;
  153. {
  154. extern String getenv();
  155. String sh;
  156. if ((sh = getenv("SHELL")) == nil(String)) {
  157. sh = DEF_SHELL;
  158. }
  159. if (s != nil(String) and *s != '\0') {
  160. call(sh, stdin, stdout, "-c", s, 0);
  161. } else {
  162. call(sh, stdin, stdout, 0);
  163. }
  164. }
  165. /*
  166. * Wait for a process the right way. We wait for a particular
  167. * process and if any others come along in between, we remember them
  168. * in case they are eventually waited for.
  169. *
  170. * This routine is not very efficient when the number of processes
  171. * to be remembered is large.
  172. *
  173. * To deal with a kernel idiosyncrasy, we keep a list on the side
  174. * of "traced" processes, and do not notice them when waiting for
  175. * another process.
  176. */
  177. typedef struct pidlist {
  178. int pid;
  179. int status;
  180. struct pidlist *next;
  181. } Pidlist;
  182. private Pidlist *pidlist, *ptrclist, *pfind();
  183. public ptraced(pid)
  184. int pid;
  185. {
  186. Pidlist *p;
  187. p = alloc(1, Pidlist);
  188. p->pid = pid;
  189. p->next = ptrclist;
  190. ptrclist = p;
  191. }
  192. public unptraced(pid)
  193. int pid;
  194. {
  195. register Pidlist *p, *prev;
  196. prev = nil(Pidlist *);
  197. p = ptrclist;
  198. while (p != nil(Pidlist *) and p->pid != pid) {
  199. prev = p;
  200. p = p->next;
  201. }
  202. if (p != nil(Pidlist *)) {
  203. if (prev == nil(Pidlist *)) {
  204. ptrclist = p->next;
  205. } else {
  206. prev->next = p->next;
  207. }
  208. dispose(p);
  209. }
  210. }
  211. private Boolean isptraced(pid)
  212. int pid;
  213. {
  214. register Pidlist *p;
  215. p = ptrclist;
  216. while (p != nil(Pidlist *) and p->pid != pid) {
  217. p = p->next;
  218. }
  219. return (Boolean) (p != nil(Pidlist *));
  220. }
  221. public pwait(pid, statusp)
  222. int pid, *statusp;
  223. {
  224. Pidlist *p;
  225. int pnum, status;
  226. p = pfind(pid);
  227. if (p != nil(Pidlist *)) {
  228. *statusp = p->status;
  229. dispose(p);
  230. } else {
  231. pnum = wait(&status);
  232. while (pnum != pid and pnum >= 0) {
  233. if (not isptraced(pnum)) {
  234. p = alloc(1, Pidlist);
  235. p->pid = pnum;
  236. p->status = status;
  237. p->next = pidlist;
  238. pidlist = p;
  239. }
  240. pnum = wait(&status);
  241. }
  242. if (pnum < 0) {
  243. p = pfind(pid);
  244. if (p == nil(Pidlist *)) {
  245. panic("pwait: pid %d not found", pid);
  246. }
  247. *statusp = p->status;
  248. dispose(p);
  249. } else {
  250. *statusp = status;
  251. }
  252. }
  253. }
  254. /*
  255. * Look for the given process id on the pidlist.
  256. *
  257. * Unlink it from list if found.
  258. */
  259. private Pidlist *pfind(pid)
  260. int pid;
  261. {
  262. register Pidlist *p, *prev;
  263. prev = nil(Pidlist *);
  264. for (p = pidlist; p != nil(Pidlist *); p = p->next) {
  265. if (p->pid == pid) {
  266. break;
  267. }
  268. prev = p;
  269. }
  270. if (p != nil(Pidlist *)) {
  271. if (prev == nil(Pidlist *)) {
  272. pidlist = p->next;
  273. } else {
  274. prev->next = p->next;
  275. }
  276. }
  277. return p;
  278. }
  279. /*
  280. * System call error handler.
  281. *
  282. * The syserr routine is called when a system call is about to
  283. * set the c-bit to report an error. Certain errors are caught
  284. * and cause the process to print a message and immediately exit.
  285. */
  286. extern int sys_nerr;
  287. extern char *sys_errlist[];
  288. /*
  289. * Before calling syserr, the integer errno is set to contain the
  290. * number of the error. The routine "_mycerror" is a dummy which
  291. * is used to force the loader to get my version of cerror rather
  292. * than the usual one.
  293. */
  294. extern int errno;
  295. extern _mycerror();
  296. /*
  297. * Default error handling.
  298. */
  299. private ERRINFO errinfo[] ={
  300. /* no error */ ERR_IGNORE,
  301. /* EPERM */ ERR_IGNORE,
  302. /* ENOENT */ ERR_IGNORE,
  303. /* ESRCH */ ERR_IGNORE,
  304. /* EINTR */ ERR_CATCH,
  305. /* EIO */ ERR_CATCH,
  306. /* ENXIO */ ERR_CATCH,
  307. /* E2BIG */ ERR_CATCH,
  308. /* ENOEXEC */ ERR_CATCH,
  309. /* EBADF */ ERR_IGNORE,
  310. /* ECHILD */ ERR_CATCH,
  311. /* EAGAIN */ ERR_CATCH,
  312. /* ENOMEM */ ERR_CATCH,
  313. /* EACCES */ ERR_CATCH,
  314. /* EFAULT */ ERR_CATCH,
  315. /* ENOTBLK */ ERR_CATCH,
  316. /* EBUSY */ ERR_CATCH,
  317. /* EEXIST */ ERR_CATCH,
  318. /* EXDEV */ ERR_CATCH,
  319. /* ENODEV */ ERR_CATCH,
  320. /* ENOTDIR */ ERR_CATCH,
  321. /* EISDIR */ ERR_CATCH,
  322. /* EINVAL */ ERR_CATCH,
  323. /* ENFILE */ ERR_CATCH,
  324. /* EMFILE */ ERR_CATCH,
  325. /* ENOTTY */ ERR_IGNORE,
  326. /* ETXTBSY */ ERR_CATCH,
  327. /* EFBIG */ ERR_CATCH,
  328. /* ENOSPC */ ERR_CATCH,
  329. /* ESPIPE */ ERR_CATCH,
  330. /* EROFS */ ERR_CATCH,
  331. /* EMLINK */ ERR_CATCH,
  332. /* EPIPE */ ERR_CATCH,
  333. /* EDOM */ ERR_CATCH,
  334. /* ERANGE */ ERR_CATCH,
  335. /* EQUOT */ ERR_CATCH,
  336. };
  337. public syserr()
  338. {
  339. ERRINFO *e;
  340. e = &errinfo[errno];
  341. if (e->func == ERR_CATCH) {
  342. if (errno < sys_nerr) {
  343. fatal(sys_errlist[errno]);
  344. } else {
  345. fatal("errno %d", errno);
  346. }
  347. } else if (e->func != ERR_IGNORE) {
  348. (*e->func)();
  349. }
  350. }
  351. /*
  352. * Catcherrs only purpose is to get this module loaded and make
  353. * sure my cerror is loaded (only applicable when this is in a library).
  354. */
  355. public catcherrs()
  356. {
  357. _mycerror();
  358. }
  359. /*
  360. * Change the action on receipt of an error.
  361. */
  362. public onsyserr(n, f)
  363. int n;
  364. INTFUNC *f;
  365. {
  366. errinfo[n].func = f;
  367. }
  368. /*
  369. * Print the message associated with the given signal.
  370. * Like a "perror" for signals.
  371. */
  372. public int sys_nsig = NSIG;
  373. public String sys_siglist[] = {
  374. "no signal",
  375. "hangup",
  376. "interrupt",
  377. "quit",
  378. "illegal instruction",
  379. "trace trap",
  380. "IOT instruction",
  381. "EMT instruction",
  382. "floating point exception",
  383. "kill",
  384. "bus error",
  385. "segmentation violation",
  386. "bad argument to system call",
  387. "broken pipe",
  388. "alarm clock",
  389. "soft kill",
  390. "urgent I/O condition",
  391. "stop signal not from tty",
  392. "stop signal from tty",
  393. "continue",
  394. "child termination",
  395. "stop (tty input)",
  396. "stop (tty output)",
  397. "possible input/output",
  398. "exceeded CPU time limit",
  399. "exceeded file size limit",
  400. nil(String)
  401. };
  402. public psig(s)
  403. String s;
  404. {
  405. String c;
  406. int n;
  407. c = "Unknown signal";
  408. if (errno < sys_nsig) {
  409. c = sys_errlist[errno];
  410. }
  411. n = strlen(s);
  412. if (n > 0) {
  413. write(2, s, n);
  414. write(2, ": ", 2);
  415. }
  416. write(2, c, strlen(c));
  417. write(2, "\n", 1);
  418. }
  419. /*
  420. * Standard error handling routines.
  421. */
  422. private short nerrs;
  423. private short nwarnings;
  424. /*
  425. * Main driver of error message reporting.
  426. */
  427. /* VARARGS2 */
  428. private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
  429. String errname;
  430. Boolean shouldquit;
  431. String s;
  432. {
  433. fflush(stdout);
  434. if (shouldquit and cmdname != nil(String)) {
  435. fprintf(stderr, "%s: ", cmdname);
  436. }
  437. if (errfilename != nil(Filename)) {
  438. fprintf(stderr, "%s: ", errfilename);
  439. }
  440. if (errlineno > 0) {
  441. fprintf(stderr, "%d: ", errlineno);
  442. }
  443. if (errname != nil(String)) {
  444. fprintf(stderr, "%s: ", errname);
  445. }
  446. fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
  447. putc('\n', stderr);
  448. if (shouldquit) {
  449. quit(1);
  450. }
  451. }
  452. /*
  453. * For when printf isn't sufficient for printing the error message ...
  454. */
  455. public beginerrmsg()
  456. {
  457. fflush(stdout);
  458. if (errfilename != nil(String)) {
  459. fprintf(stderr, "%s: ", errfilename);
  460. }
  461. if (errlineno > 0) {
  462. fprintf(stderr, "%d: ", errlineno);
  463. }
  464. }
  465. public enderrmsg()
  466. {
  467. putc('\n', stderr);
  468. erecover();
  469. }
  470. /*
  471. * The messages are listed in increasing order of seriousness.
  472. *
  473. * First are warnings.
  474. */
  475. /* VARARGS1 */
  476. public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
  477. String s;
  478. {
  479. nwarnings++;
  480. errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
  481. }
  482. /*
  483. * Errors are a little worse, they mean something is wrong,
  484. * but not so bad that processing can't continue.
  485. *
  486. * The routine "erecover" is called to recover from the error,
  487. * a default routine is provided that does nothing.
  488. */
  489. /* VARARGS1 */
  490. public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
  491. String s;
  492. {
  493. extern erecover();
  494. nerrs++;
  495. errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
  496. erecover();
  497. }
  498. /*
  499. * Non-recoverable user error.
  500. */
  501. /* VARARGS1 */
  502. public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
  503. String s;
  504. {
  505. errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
  506. }
  507. /*
  508. * Panics indicate an internal program error.
  509. */
  510. /* VARARGS1 */
  511. public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
  512. String s;
  513. {
  514. errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
  515. }
  516. short numerrors()
  517. {
  518. short r;
  519. r = nerrs;
  520. nerrs = 0;
  521. return r;
  522. }
  523. short numwarnings()
  524. {
  525. short r;
  526. r = nwarnings;
  527. nwarnings = 0;
  528. return r;
  529. }
  530. /*
  531. * Recover from an error.
  532. *
  533. * This is the default routine which we aren't using since we have our own.
  534. *
  535. public erecover()
  536. {
  537. }
  538. *
  539. */
  540. /*
  541. * Default way to quit from a program is just to exit.
  542. *
  543. public quit(r)
  544. int r;
  545. {
  546. exit(r);
  547. }
  548. *
  549. */
  550. /*
  551. * Compare n-byte areas pointed to by s1 and s2
  552. * if n is 0 then compare up until one has a null byte.
  553. */
  554. public int cmp(s1, s2, n)
  555. register char *s1, *s2;
  556. register unsigned int n;
  557. {
  558. if (s1 == nil(char *) || s2 == nil(char *)) {
  559. panic("cmp: nil pointer");
  560. }
  561. if (n == 0) {
  562. while (*s1 == *s2++) {
  563. if (*s1++ == '\0') {
  564. return(0);
  565. }
  566. }
  567. return(*s1 - *(s2-1));
  568. } else {
  569. for (; n != 0; n--) {
  570. if (*s1++ != *s2++) {
  571. return(*(s1-1) - *(s2-1));
  572. }
  573. }
  574. return(0);
  575. }
  576. }
  577. /*
  578. * Move n bytes from src to dest.
  579. * If n is 0 move until a null is found.
  580. */
  581. public mov(src, dest, n)
  582. register char *src, *dest;
  583. register unsigned int n;
  584. {
  585. if (src == nil(char *))
  586. panic("mov: nil source");
  587. if (dest == nil(char *))
  588. panic("mov: nil destination");
  589. if (n != 0) {
  590. for (; n != 0; n--) {
  591. *dest++ = *src++;
  592. }
  593. } else {
  594. while ((*dest++ = *src++) != '\0');
  595. }
  596. }