ehandle.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * ehandle.c - error handling
  4. *
  5. * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
  6. *
  7. * This is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2,
  10. * or (at your option) any later version.
  11. *
  12. * This is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with dpkg; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <errno.h>
  25. #include <unistd.h>
  26. #include <stdarg.h>
  27. #include <assert.h>
  28. #include <config.h>
  29. #include <dpkg.h>
  30. #include <dpkg-db.h>
  31. static const char *errmsg; /* points to errmsgbuf or malloc'd */
  32. static char errmsgbuf[4096];
  33. /* 6x255 for inserted strings (%.255s &c in fmt; also %s with limited length arg)
  34. * 1x255 for constant text
  35. * 1x255 for strerror()
  36. * same again just in case.
  37. */
  38. #define NCALLS 2
  39. struct cleanupentry {
  40. struct cleanupentry *next;
  41. struct {
  42. int mask;
  43. void (*call)(int argc, void **argv);
  44. } calls[NCALLS];
  45. int cpmask, cpvalue;
  46. int argc;
  47. void *argv[1];
  48. };
  49. struct errorcontext {
  50. struct errorcontext *next;
  51. jmp_buf *jbufp;
  52. struct cleanupentry *cleanups;
  53. void (*printerror)(const char *emsg, const char *contextstring);
  54. const char *contextstring;
  55. };
  56. static struct errorcontext *volatile econtext= 0;
  57. static struct { struct cleanupentry ce; void *args[20]; } emergency;
  58. void set_error_display(void (*printerror)(const char *, const char *),
  59. const char *contextstring) {
  60. assert(econtext);
  61. econtext->printerror= printerror;
  62. econtext->contextstring= contextstring;
  63. }
  64. void push_error_handler(jmp_buf *jbufp,
  65. void (*printerror)(const char *, const char *),
  66. const char *contextstring) {
  67. struct errorcontext *necp;
  68. necp= malloc(sizeof(struct errorcontext));
  69. if (!necp) {
  70. int e= errno;
  71. strcpy(errmsgbuf, (_("out of memory pushing error handler: ")));
  72. strcat(errmsgbuf, strerror(e)); errmsg= errmsgbuf;
  73. if (econtext) longjmp(*econtext->jbufp,1);
  74. fprintf(stderr, "%s: %s\n", thisname, errmsgbuf); exit(2);
  75. }
  76. necp->next= econtext;
  77. necp->jbufp= jbufp;
  78. necp->cleanups= 0;
  79. necp->printerror= printerror;
  80. necp->contextstring= contextstring;
  81. econtext= necp;
  82. onerr_abort= 0;
  83. }
  84. static void print_error_cleanup(const char *emsg, const char *contextstring) {
  85. fprintf(stderr, _("%s: error while cleaning up:\n %s\n"),thisname,emsg);
  86. }
  87. static void run_cleanups(struct errorcontext *econ, int flagsetin) {
  88. static volatile int preventrecurse= 0;
  89. struct cleanupentry *volatile cep;
  90. struct cleanupentry *ncep;
  91. struct errorcontext recurserr, *oldecontext;
  92. jmp_buf recurejbuf;
  93. volatile int i, flagset;
  94. if (econ->printerror) econ->printerror(errmsg,econ->contextstring);
  95. if (++preventrecurse > 3) {
  96. onerr_abort++;
  97. fprintf(stderr, _("dpkg: too many nested errors during error recovery !!\n"));
  98. flagset= 0;
  99. } else {
  100. flagset= flagsetin;
  101. }
  102. cep= econ->cleanups;
  103. oldecontext= econtext;
  104. while (cep) {
  105. for (i=0; i<NCALLS; i++) {
  106. if (cep->calls[i].call && cep->calls[i].mask & flagset) {
  107. if (setjmp(recurejbuf)) {
  108. run_cleanups(&recurserr, ehflag_bombout | ehflag_recursiveerror);
  109. } else {
  110. recurserr.jbufp= &recurejbuf;
  111. recurserr.cleanups= 0;
  112. recurserr.next= 0;
  113. recurserr.printerror= print_error_cleanup;
  114. recurserr.contextstring= 0;
  115. econtext= &recurserr;
  116. cep->calls[i].call(cep->argc,cep->argv);
  117. }
  118. econtext= oldecontext;
  119. }
  120. }
  121. ncep= cep->next;
  122. if (cep != &emergency.ce) free(cep);
  123. cep= ncep;
  124. }
  125. preventrecurse--;
  126. }
  127. void error_unwind(int flagset) {
  128. struct cleanupentry *cep;
  129. struct errorcontext *tecp;
  130. tecp= econtext;
  131. cep= tecp->cleanups;
  132. econtext= tecp->next;
  133. run_cleanups(tecp,flagset);
  134. free(tecp);
  135. }
  136. void push_checkpoint(int mask, int value) {
  137. /* This will arrange that when error_unwind() is called,
  138. * all previous cleanups will be executed with
  139. * flagset= (original_flagset & mask) | value
  140. * where original_flagset is the argument to error_unwind
  141. * (as modified by any checkpoint which was pushed later).
  142. */
  143. struct cleanupentry *cep;
  144. int i;
  145. cep= m_malloc(sizeof(struct cleanupentry) + sizeof(char*));
  146. for (i=0; i<NCALLS; i++) { cep->calls[i].call=0; cep->calls[i].mask=0; }
  147. cep->cpmask= mask; cep->cpvalue= value;
  148. cep->argc= 0; cep->argv[0]= 0;
  149. cep->next= econtext->cleanups;
  150. econtext->cleanups= cep;
  151. }
  152. void push_cleanup(void (*call1)(int argc, void **argv), int mask1,
  153. void (*call2)(int argc, void **argv), int mask2,
  154. int nargs, ...) {
  155. struct cleanupentry *cep;
  156. void **args;
  157. int e;
  158. va_list al;
  159. onerr_abort++;
  160. cep= malloc(sizeof(struct cleanupentry) + sizeof(char*)*(nargs+1));
  161. if (!cep) {
  162. if (nargs > sizeof(emergency.args)/sizeof(void*))
  163. ohshite(_("out of memory for new cleanup entry with many arguments"));
  164. e= errno; cep= &emergency.ce;
  165. }
  166. cep->calls[0].call= call1; cep->calls[0].mask= mask1;
  167. cep->calls[1].call= call2; cep->calls[1].mask= mask2;
  168. cep->cpmask=~0; cep->cpvalue=0; cep->argc= nargs;
  169. va_start(al,nargs);
  170. args= cep->argv; while (nargs-- >0) *args++= va_arg(al,void*);
  171. *args++= 0;
  172. va_end(al);
  173. cep->next= econtext->cleanups;
  174. econtext->cleanups= cep;
  175. if (cep == &emergency.ce) { e= errno; ohshite(_("out of memory for new cleanup entry")); }
  176. onerr_abort--;
  177. }
  178. void pop_cleanup(int flagset) {
  179. struct cleanupentry *cep;
  180. int i;
  181. cep= econtext->cleanups;
  182. econtext->cleanups= cep->next;
  183. for (i=0; i<NCALLS; i++) {
  184. if (cep->calls[i].call && cep->calls[i].mask & flagset)
  185. cep->calls[i].call(cep->argc,cep->argv);
  186. flagset &= cep->cpmask;
  187. flagset |= cep->cpvalue;
  188. }
  189. if (cep != &emergency.ce) free(cep);
  190. }
  191. void ohshit(const char *fmt, ...) {
  192. va_list al;
  193. va_start(al,fmt);
  194. vsprintf(errmsgbuf,fmt,al);
  195. va_end(al);
  196. errmsg= errmsgbuf;
  197. longjmp(*econtext->jbufp,1);
  198. }
  199. void print_error_fatal(const char *emsg, const char *contextstring) {
  200. fprintf(stderr, "%s: %s\n",thisname,emsg);
  201. }
  202. void ohshitvb(struct varbuf *vb) {
  203. char *m;
  204. varbufaddc(vb,0);
  205. m= m_malloc(strlen(vb->buf));
  206. strcpy(m,vb->buf);
  207. errmsg= m;
  208. longjmp(*econtext->jbufp,1);
  209. }
  210. void ohshitv(const char *fmt, va_list al) {
  211. vsprintf(errmsgbuf,fmt,al);
  212. errmsg= errmsgbuf;
  213. longjmp(*econtext->jbufp,1);
  214. }
  215. void ohshite(const char *fmt, ...) {
  216. int e;
  217. va_list al;
  218. e=errno;
  219. va_start(al,fmt);
  220. vsprintf(errmsgbuf,fmt,al);
  221. va_end(al);
  222. strcat(errmsgbuf,": ");
  223. strcat(errmsgbuf,strerror(e));
  224. errmsg= errmsgbuf;
  225. longjmp(*econtext->jbufp,1);
  226. }
  227. void badusage(const char *fmt, ...) {
  228. va_list al;
  229. va_start(al,fmt);
  230. vsprintf(errmsgbuf,fmt,al);
  231. va_end(al);
  232. strcat(errmsgbuf,"\n\n");
  233. strcat(errmsgbuf,gettext(printforhelp));
  234. errmsg= errmsgbuf;
  235. longjmp(*econtext->jbufp,1);
  236. }
  237. void werr(const char *fn) {
  238. ohshite(_("error writing `%.250s'"),fn);
  239. }
  240. void do_internerr(const char *string, int line, const char *file) {
  241. fprintf(stderr,_("%s:%d: internal error `%s'\n"),file,line,string);
  242. abort();
  243. }