PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/libast/common/misc/error.c

https://bitbucket.org/a3217055/illumos-2
C | 659 lines | 556 code | 39 blank | 64 comment | 131 complexity | 67ae7b529cf996fb22130da833f3055d MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, AGPL-3.0, BSD-3-Clause, LGPL-2.0, 0BSD, BSD-2-Clause, BSD-3-Clause-No-Nuclear-License-2014, AGPL-1.0, GPL-2.0
  1. /***********************************************************************
  2. * *
  3. * This software is part of the ast package *
  4. * Copyright (c) 1985-2010 AT&T Intellectual Property *
  5. * and is licensed under the *
  6. * Common Public License, Version 1.0 *
  7. * by AT&T Intellectual Property *
  8. * *
  9. * A copy of the License is available at *
  10. * http://www.opensource.org/licenses/cpl1.0.txt *
  11. * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
  12. * *
  13. * Information and Software Systems Research *
  14. * AT&T Research *
  15. * Florham Park NJ *
  16. * *
  17. * Glenn Fowler <gsf@research.att.com> *
  18. * David Korn <dgk@research.att.com> *
  19. * Phong Vo <kpv@research.att.com> *
  20. * *
  21. ***********************************************************************/
  22. #pragma prototyped
  23. /*
  24. * Glenn Fowler
  25. * AT&T Research
  26. *
  27. * error and message formatter
  28. *
  29. * level is the error level
  30. * level >= error_info.core!=0 dumps core
  31. * level >= ERROR_FATAL calls error_info.exit
  32. * level < 0 is for debug tracing
  33. *
  34. * NOTE: id && ERROR_NOID && !ERROR_USAGE implies format=id for errmsg()
  35. */
  36. #include "lclib.h"
  37. #include <ctype.h>
  38. #include <ccode.h>
  39. #include <namval.h>
  40. #include <sig.h>
  41. #include <stk.h>
  42. #include <times.h>
  43. #include <regex.h>
  44. /*
  45. * 2007-03-19 move error_info from _error_info_ to (*_error_infop_)
  46. * to allow future Error_info_t growth
  47. * by 2009 _error_info_ can be static
  48. */
  49. #if _BLD_ast && defined(__EXPORT__)
  50. #define extern extern __EXPORT__
  51. #endif
  52. extern Error_info_t _error_info_;
  53. Error_info_t _error_info_ =
  54. {
  55. 2, exit, write,
  56. 0,0,0,0,0,0,0,0,
  57. 0, /* version */
  58. 0, /* auxilliary */
  59. 0,0,0,0,0,0,0, /* top of old context stack */
  60. 0,0,0,0,0,0,0, /* old empty context */
  61. 0, /* time */
  62. translate,
  63. 0 /* catalog */
  64. };
  65. #undef extern
  66. __EXTERN__(Error_info_t, _error_info_);
  67. __EXTERN__(Error_info_t*, _error_infop_);
  68. Error_info_t* _error_infop_ = &_error_info_;
  69. /*
  70. * these should probably be in error_info
  71. */
  72. static struct State_s
  73. {
  74. char* prefix;
  75. Sfio_t* tty;
  76. unsigned long count;
  77. int breakpoint;
  78. regex_t* match;
  79. } error_state;
  80. #undef ERROR_CATALOG
  81. #define ERROR_CATALOG (ERROR_LIBRARY<<1)
  82. #define OPT_BREAK 1
  83. #define OPT_CATALOG 2
  84. #define OPT_CORE 3
  85. #define OPT_COUNT 4
  86. #define OPT_FD 5
  87. #define OPT_LIBRARY 6
  88. #define OPT_MASK 7
  89. #define OPT_MATCH 8
  90. #define OPT_PREFIX 9
  91. #define OPT_SYSTEM 10
  92. #define OPT_TIME 11
  93. #define OPT_TRACE 12
  94. static const Namval_t options[] =
  95. {
  96. "break", OPT_BREAK,
  97. "catalog", OPT_CATALOG,
  98. "core", OPT_CORE,
  99. "count", OPT_COUNT,
  100. "debug", OPT_TRACE,
  101. "fd", OPT_FD,
  102. "library", OPT_LIBRARY,
  103. "mask", OPT_MASK,
  104. "match", OPT_MATCH,
  105. "prefix", OPT_PREFIX,
  106. "system", OPT_SYSTEM,
  107. "time", OPT_TIME,
  108. "trace", OPT_TRACE,
  109. 0, 0
  110. };
  111. /*
  112. * called by stropt() to set options
  113. */
  114. static int
  115. setopt(void* a, const void* p, register int n, register const char* v)
  116. {
  117. NoP(a);
  118. if (p)
  119. switch (((Namval_t*)p)->value)
  120. {
  121. case OPT_BREAK:
  122. case OPT_CORE:
  123. if (n)
  124. switch (*v)
  125. {
  126. case 'e':
  127. case 'E':
  128. error_state.breakpoint = ERROR_ERROR;
  129. break;
  130. case 'f':
  131. case 'F':
  132. error_state.breakpoint = ERROR_FATAL;
  133. break;
  134. case 'p':
  135. case 'P':
  136. error_state.breakpoint = ERROR_PANIC;
  137. break;
  138. default:
  139. error_state.breakpoint = strtol(v, NiL, 0);
  140. break;
  141. }
  142. else
  143. error_state.breakpoint = 0;
  144. if (((Namval_t*)p)->value == OPT_CORE)
  145. error_info.core = error_state.breakpoint;
  146. break;
  147. case OPT_CATALOG:
  148. if (n)
  149. error_info.set |= ERROR_CATALOG;
  150. else
  151. error_info.clear |= ERROR_CATALOG;
  152. break;
  153. case OPT_COUNT:
  154. if (n)
  155. error_state.count = strtol(v, NiL, 0);
  156. else
  157. error_state.count = 0;
  158. break;
  159. case OPT_FD:
  160. error_info.fd = n ? strtol(v, NiL, 0) : -1;
  161. break;
  162. case OPT_LIBRARY:
  163. if (n)
  164. error_info.set |= ERROR_LIBRARY;
  165. else
  166. error_info.clear |= ERROR_LIBRARY;
  167. break;
  168. case OPT_MASK:
  169. if (n)
  170. error_info.mask = strtol(v, NiL, 0);
  171. else
  172. error_info.mask = 0;
  173. break;
  174. case OPT_MATCH:
  175. if (error_state.match)
  176. regfree(error_state.match);
  177. if (n)
  178. {
  179. if ((error_state.match || (error_state.match = newof(0, regex_t, 1, 0))) && regcomp(error_state.match, v, REG_EXTENDED|REG_LENIENT))
  180. {
  181. free(error_state.match);
  182. error_state.match = 0;
  183. }
  184. }
  185. else if (error_state.match)
  186. {
  187. free(error_state.match);
  188. error_state.match = 0;
  189. }
  190. break;
  191. case OPT_PREFIX:
  192. if (n)
  193. error_state.prefix = strdup(v);
  194. else if (error_state.prefix)
  195. {
  196. free(error_state.prefix);
  197. error_state.prefix = 0;
  198. }
  199. break;
  200. case OPT_SYSTEM:
  201. if (n)
  202. error_info.set |= ERROR_SYSTEM;
  203. else
  204. error_info.clear |= ERROR_SYSTEM;
  205. break;
  206. case OPT_TIME:
  207. error_info.time = n ? 1 : 0;
  208. break;
  209. case OPT_TRACE:
  210. if (n)
  211. error_info.trace = -strtol(v, NiL, 0);
  212. else
  213. error_info.trace = 0;
  214. break;
  215. }
  216. return 0;
  217. }
  218. /*
  219. * print a name with optional delimiter, converting unprintable chars
  220. */
  221. static void
  222. print(register Sfio_t* sp, register char* name, char* delim)
  223. {
  224. if (mbwide())
  225. sfputr(sp, name, -1);
  226. else
  227. {
  228. #if CC_NATIVE != CC_ASCII
  229. register int c;
  230. register unsigned char* n2a;
  231. register unsigned char* a2n;
  232. register int aa;
  233. register int as;
  234. n2a = ccmap(CC_NATIVE, CC_ASCII);
  235. a2n = ccmap(CC_ASCII, CC_NATIVE);
  236. aa = n2a['A'];
  237. as = n2a[' '];
  238. while (c = *name++)
  239. {
  240. c = n2a[c];
  241. if (c & 0200)
  242. {
  243. c &= 0177;
  244. sfputc(sp, '?');
  245. }
  246. if (c < as)
  247. {
  248. c += aa - 1;
  249. sfputc(sp, '^');
  250. }
  251. c = a2n[c];
  252. sfputc(sp, c);
  253. }
  254. #else
  255. register int c;
  256. while (c = *name++)
  257. {
  258. if (c & 0200)
  259. {
  260. c &= 0177;
  261. sfputc(sp, '?');
  262. }
  263. if (c < ' ')
  264. {
  265. c += 'A' - 1;
  266. sfputc(sp, '^');
  267. }
  268. sfputc(sp, c);
  269. }
  270. #endif
  271. }
  272. if (delim)
  273. sfputr(sp, delim, -1);
  274. }
  275. /*
  276. * print error context FIFO stack
  277. */
  278. #define CONTEXT(f,p) (((f)&ERROR_PUSH)?((Error_context_t*)&(p)->context->context):((Error_context_t*)(p)))
  279. static void
  280. context(register Sfio_t* sp, register Error_context_t* cp)
  281. {
  282. if (cp->context)
  283. context(sp, CONTEXT(cp->flags, cp->context));
  284. if (!(cp->flags & ERROR_SILENT))
  285. {
  286. if (cp->id)
  287. print(sp, cp->id, NiL);
  288. if (cp->line > ((cp->flags & ERROR_INTERACTIVE) != 0))
  289. {
  290. if (cp->file)
  291. sfprintf(sp, ": \"%s\", %s %d", cp->file, ERROR_translate(NiL, NiL, ast.id, "line"), cp->line);
  292. else
  293. sfprintf(sp, "[%d]", cp->line);
  294. }
  295. sfputr(sp, ": ", -1);
  296. }
  297. }
  298. /*
  299. * debugging breakpoint
  300. */
  301. extern void
  302. error_break(void)
  303. {
  304. char* s;
  305. if (error_state.tty || (error_state.tty = sfopen(NiL, "/dev/tty", "r+")))
  306. {
  307. sfprintf(error_state.tty, "error breakpoint: ");
  308. if (s = sfgetr(error_state.tty, '\n', 1))
  309. {
  310. if (streq(s, "q") || streq(s, "quit"))
  311. exit(0);
  312. stropt(s, options, sizeof(*options), setopt, NiL);
  313. }
  314. }
  315. }
  316. void
  317. error(int level, ...)
  318. {
  319. va_list ap;
  320. va_start(ap, level);
  321. errorv(NiL, level, ap);
  322. va_end(ap);
  323. }
  324. void
  325. errorv(const char* id, int level, va_list ap)
  326. {
  327. register int n;
  328. int fd;
  329. int flags;
  330. char* s;
  331. char* t;
  332. char* format;
  333. char* library;
  334. const char* catalog;
  335. int line;
  336. char* file;
  337. #if !_PACKAGE_astsa
  338. unsigned long d;
  339. struct tms us;
  340. #endif
  341. if (!error_info.init)
  342. {
  343. error_info.init = 1;
  344. stropt(getenv("ERROR_OPTIONS"), options, sizeof(*options), setopt, NiL);
  345. }
  346. if (level > 0)
  347. {
  348. flags = level & ~ERROR_LEVEL;
  349. level &= ERROR_LEVEL;
  350. }
  351. else
  352. flags = 0;
  353. if ((flags & (ERROR_USAGE|ERROR_NOID)) == ERROR_NOID)
  354. {
  355. format = (char*)id;
  356. id = 0;
  357. }
  358. else
  359. format = 0;
  360. if (id)
  361. {
  362. catalog = (char*)id;
  363. if (!*catalog || *catalog == ':')
  364. {
  365. catalog = 0;
  366. library = 0;
  367. }
  368. else if ((library = strchr(catalog, ':')) && !*++library)
  369. library = 0;
  370. }
  371. else
  372. {
  373. catalog = 0;
  374. library = 0;
  375. }
  376. if (catalog)
  377. id = 0;
  378. else
  379. {
  380. id = (const char*)error_info.id;
  381. catalog = error_info.catalog;
  382. }
  383. if (level < error_info.trace || (flags & ERROR_LIBRARY) && !(((error_info.set | error_info.flags) ^ error_info.clear) & ERROR_LIBRARY) || level < 0 && error_info.mask && !(error_info.mask & (1<<(-level - 1))))
  384. {
  385. if (level >= ERROR_FATAL)
  386. (*error_info.exit)(level - 1);
  387. return;
  388. }
  389. if (error_info.trace < 0)
  390. flags |= ERROR_LIBRARY|ERROR_SYSTEM;
  391. flags |= error_info.set | error_info.flags;
  392. flags &= ~error_info.clear;
  393. if (!library)
  394. flags &= ~ERROR_LIBRARY;
  395. fd = (flags & ERROR_OUTPUT) ? va_arg(ap, int) : error_info.fd;
  396. if (error_info.write)
  397. {
  398. long off;
  399. char* bas;
  400. bas = stkptr(stkstd, 0);
  401. if (off = stktell(stkstd))
  402. stkfreeze(stkstd, 0);
  403. file = error_info.id;
  404. if (error_state.prefix)
  405. sfprintf(stkstd, "%s: ", error_state.prefix);
  406. if (flags & ERROR_USAGE)
  407. {
  408. if (flags & ERROR_NOID)
  409. sfprintf(stkstd, " ");
  410. else
  411. sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "Usage"));
  412. if (file || opt_info.argv && (file = opt_info.argv[0]))
  413. print(stkstd, file, " ");
  414. }
  415. else
  416. {
  417. if (level && !(flags & ERROR_NOID))
  418. {
  419. if (error_info.context && level > 0)
  420. context(stkstd, CONTEXT(error_info.flags, error_info.context));
  421. if (file)
  422. print(stkstd, file, (flags & ERROR_LIBRARY) ? " " : ": ");
  423. if (flags & (ERROR_CATALOG|ERROR_LIBRARY))
  424. {
  425. sfprintf(stkstd, "[");
  426. if (flags & ERROR_CATALOG)
  427. sfprintf(stkstd, "%s %s%s",
  428. catalog ? catalog : ERROR_translate(NiL, NiL, ast.id, "DEFAULT"),
  429. ERROR_translate(NiL, NiL, ast.id, "catalog"),
  430. (flags & ERROR_LIBRARY) ? ", " : "");
  431. if (flags & ERROR_LIBRARY)
  432. sfprintf(stkstd, "%s %s",
  433. library,
  434. ERROR_translate(NiL, NiL, ast.id, "library"));
  435. sfprintf(stkstd, "]: ");
  436. }
  437. }
  438. if (level > 0 && error_info.line > ((flags & ERROR_INTERACTIVE) != 0))
  439. {
  440. if (error_info.file && *error_info.file)
  441. sfprintf(stkstd, "\"%s\", ", error_info.file);
  442. sfprintf(stkstd, "%s %d: ", ERROR_translate(NiL, NiL, ast.id, "line"), error_info.line);
  443. }
  444. }
  445. #if !_PACKAGE_astsa
  446. if (error_info.time)
  447. {
  448. if ((d = times(&us)) < error_info.time || error_info.time == 1)
  449. error_info.time = d;
  450. sfprintf(stkstd, " %05lu.%05lu.%05lu ", d - error_info.time, (unsigned long)us.tms_utime, (unsigned long)us.tms_stime);
  451. }
  452. #endif
  453. switch (level)
  454. {
  455. case 0:
  456. flags &= ~ERROR_SYSTEM;
  457. break;
  458. case ERROR_WARNING:
  459. sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "warning"));
  460. break;
  461. case ERROR_PANIC:
  462. sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "panic"));
  463. break;
  464. default:
  465. if (level < 0)
  466. {
  467. s = ERROR_translate(NiL, NiL, ast.id, "debug");
  468. if (error_info.trace < -1)
  469. sfprintf(stkstd, "%s%d:%s", s, level, level > -10 ? " " : "");
  470. else
  471. sfprintf(stkstd, "%s: ", s);
  472. for (n = 0; n < error_info.indent; n++)
  473. {
  474. sfputc(stkstd, ' ');
  475. sfputc(stkstd, ' ');
  476. }
  477. }
  478. break;
  479. }
  480. if (flags & ERROR_SOURCE)
  481. {
  482. /*
  483. * source ([version], file, line) message
  484. */
  485. file = va_arg(ap, char*);
  486. line = va_arg(ap, int);
  487. s = ERROR_translate(NiL, NiL, ast.id, "line");
  488. if (error_info.version)
  489. sfprintf(stkstd, "(%s: \"%s\", %s %d) ", error_info.version, file, s, line);
  490. else
  491. sfprintf(stkstd, "(\"%s\", %s %d) ", file, s, line);
  492. }
  493. if (format || (format = va_arg(ap, char*)))
  494. {
  495. if (!(flags & ERROR_USAGE))
  496. format = ERROR_translate(NiL, id, catalog, format);
  497. sfvprintf(stkstd, format, ap);
  498. }
  499. if (!(flags & ERROR_PROMPT))
  500. {
  501. /*
  502. * level&ERROR_OUTPUT on return means message
  503. * already output
  504. */
  505. if ((flags & ERROR_SYSTEM) && errno && errno != error_info.last_errno)
  506. {
  507. sfprintf(stkstd, " [%s]", fmterror(errno));
  508. if (error_info.set & ERROR_SYSTEM)
  509. errno = 0;
  510. error_info.last_errno = (level >= 0) ? 0 : errno;
  511. }
  512. if (error_info.auxilliary && level >= 0)
  513. level = (*error_info.auxilliary)(stkstd, level, flags);
  514. sfputc(stkstd, '\n');
  515. }
  516. if (level > 0)
  517. {
  518. if ((level & ~ERROR_OUTPUT) > 1)
  519. error_info.errors++;
  520. else
  521. error_info.warnings++;
  522. }
  523. if (level < 0 || !(level & ERROR_OUTPUT))
  524. {
  525. n = stktell(stkstd);
  526. s = stkptr(stkstd, 0);
  527. if (t = memchr(s, '\f', n))
  528. {
  529. n -= ++t - s;
  530. s = t;
  531. }
  532. #if HUH_19980401 /* nasty problems if sfgetr() is in effect! */
  533. sfsync(sfstdin);
  534. #endif
  535. sfsync(sfstdout);
  536. sfsync(sfstderr);
  537. if (fd == sffileno(sfstderr) && error_info.write == write)
  538. {
  539. sfwrite(sfstderr, s, n);
  540. sfsync(sfstderr);
  541. }
  542. else
  543. (*error_info.write)(fd, s, n);
  544. }
  545. else
  546. {
  547. s = 0;
  548. level &= ERROR_LEVEL;
  549. }
  550. stkset(stkstd, bas, off);
  551. }
  552. else
  553. s = 0;
  554. if (level >= error_state.breakpoint && error_state.breakpoint && (!error_state.match || !regexec(error_state.match, s ? s : format, 0, NiL, 0)) && (!error_state.count || !--error_state.count))
  555. {
  556. if (error_info.core)
  557. {
  558. #ifndef SIGABRT
  559. #ifdef SIGQUIT
  560. #define SIGABRT SIGQUIT
  561. #else
  562. #ifdef SIGIOT
  563. #define SIGABRT SIGIOT
  564. #endif
  565. #endif
  566. #endif
  567. #ifdef SIGABRT
  568. signal(SIGABRT, SIG_DFL);
  569. kill(getpid(), SIGABRT);
  570. pause();
  571. #else
  572. abort();
  573. #endif
  574. }
  575. else
  576. error_break();
  577. }
  578. if (level >= ERROR_FATAL)
  579. (*error_info.exit)(level - ERROR_FATAL + 1);
  580. }
  581. /*
  582. * error_info context control
  583. */
  584. static Error_info_t* freecontext;
  585. Error_info_t*
  586. errorctx(Error_info_t* p, int op, int flags)
  587. {
  588. if (op & ERROR_POP)
  589. {
  590. if (!(_error_infop_ = p->context))
  591. _error_infop_ = &_error_info_;
  592. if (op & ERROR_FREE)
  593. {
  594. p->context = freecontext;
  595. freecontext = p;
  596. }
  597. p = _error_infop_;
  598. }
  599. else
  600. {
  601. if (!p)
  602. {
  603. if (p = freecontext)
  604. freecontext = freecontext->context;
  605. else if (!(p = newof(0, Error_info_t, 1, 0)))
  606. return 0;
  607. *p = *_error_infop_;
  608. p->errors = p->flags = p->line = p->warnings = 0;
  609. p->catalog = p->file = 0;
  610. }
  611. if (op & ERROR_PUSH)
  612. {
  613. p->flags = flags;
  614. p->context = _error_infop_;
  615. _error_infop_ = p;
  616. }
  617. p->flags |= ERROR_PUSH;
  618. }
  619. return p;
  620. }