PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/cvs-1.12/src/error.c

http://github.com/davshao/dflygsocdrm
C | 267 lines | 99 code | 35 blank | 133 comment | 16 complexity | 346239fe690e4a1d17dcd2a69eb80fe0 MD5 | raw file
Possible License(s): AGPL-1.0, CC-BY-SA-3.0, LGPL-2.0, GPL-3.0, LGPL-2.1, LGPL-3.0, MPL-2.0-no-copyleft-exception, 0BSD, BSD-3-Clause, GPL-2.0
  1. /* error.c -- error handler for noninteractive utilities
  2. Copyright (C) 1990-1992 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details. */
  11. /* David MacKenzie */
  12. /* Brian Berliner added support for CVS */
  13. #include "cvs.h"
  14. #include "vasnprintf.h"
  15. /* Out of memory errors which could not be forwarded to the client are sent to
  16. * the syslog when it is available.
  17. */
  18. #ifdef HAVE_SYSLOG_H
  19. # include <syslog.h>
  20. # ifndef LOG_DAEMON /* for ancient syslogs */
  21. # define LOG_DAEMON 0
  22. # endif
  23. #endif /* HAVE_SYSLOG_H */
  24. /* If non-zero, error will use the CVS protocol to stdout to report error
  25. * messages. This will only be set in the CVS server parent process.
  26. *
  27. * Most other code is run via do_cvs_command, which forks off a child
  28. * process and packages up its stderr in the protocol.
  29. */
  30. int error_use_protocol;
  31. #ifndef strerror
  32. extern char *strerror (int);
  33. #endif
  34. /* Print the program name and error message MESSAGE, which is a printf-style
  35. * format string with optional args, like:
  36. *
  37. * PROGRAM_NAME CVS_CMD_NAME: MESSAGE: ERRNUM
  38. *
  39. * or, when STATUS is non-zero:
  40. *
  41. * PROGRAM_NAME [CVS_CMD_NAME aborted]: MESSAGE: ERRNUM
  42. *
  43. * CVS_CMD_NAME & ERRMSG may or may not appear in the output (the `:' before
  44. * ERRMSG will disappear as well when ERRNUM is not present). ERRMSG
  45. * represents the system dependent message returned by strerror (ERRNUM), when
  46. * ERRNUM is non-zero.
  47. *
  48. * Exit with status EXIT_FAILURE if STATUS is nonzero.
  49. *
  50. * If this function fails to get any memory it might request, it attempts to
  51. * log a "memory exhausted" message to the syslog, when syslog is available,
  52. * without any further attempts to allocate memory, before exiting. See NOTES
  53. * below for more information on this functions memory allocation.
  54. *
  55. * INPUTS
  56. * status When non-zero, exit with EXIT_FAILURE rather than returning.
  57. * errnum When non-zero, interpret as global ERRNO for the purpose of
  58. * generating additional error text.
  59. * message A printf style format string.
  60. * ... Variable number of args, as printf.
  61. *
  62. * GLOBALS
  63. * program_name The name of this executable, for the output message.
  64. * cvs_cmd_name Output in the error message, when it exists.
  65. * errno Accessed simply to save and restore it before
  66. * returning.
  67. *
  68. * NOTES
  69. * This function goes to fairly great lengths to avoid allocating memory so
  70. * that it can relay out-of-memory error messages to the client. Any error
  71. * messages which fit in under 256 characters (after expanding MESSAGE with
  72. * ARGS but before adding any ERRNUM text) should not require memory
  73. * allocation before they are sent on to cvs_outerr(). Unfortunately,
  74. * cvs_outerr() and the buffer functions it uses to send messages to the
  75. * client still don't make this same sort of effort, so in local mode
  76. * out-of-memory errors will probably get printed properly to stderr but if a
  77. * memory outage happens on the server, the admin will need to consult the
  78. * syslog to find out what went wrong.
  79. *
  80. * I think this is largely cleaned up to the point where it does the right
  81. * thing for the server, whether the normal server_active (child process)
  82. * case or the error_use_protocol (parent process) case. The one exception
  83. * is that STATUS nonzero for error_use_protocol probably doesn't work yet;
  84. * in that case still need to use the pending_error machinery in server.c.
  85. *
  86. * error() does not molest errno; some code (e.g. Entries_Open) depends
  87. * on being able to say something like:
  88. *
  89. * error (0, 0, "foo");
  90. * error (0, errno, "bar");
  91. *
  92. * RETURNS
  93. * Sometimes. ;)
  94. */
  95. void
  96. error (int status, int errnum, const char *message, ...)
  97. {
  98. va_list args;
  99. int save_errno = errno;
  100. /* Various buffers we attempt to use to generate the error message. */
  101. char statbuf[256];
  102. char *buf;
  103. size_t length;
  104. char statbuf2[384];
  105. char *buf2;
  106. char statcmdbuf[32];
  107. char *cmdbuf;
  108. char *emptybuf = "";
  109. static const char *last_message = NULL;
  110. static int last_status;
  111. static int last_errnum;
  112. /* Initialize these to avoid a lot of special case error handling. */
  113. buf = statbuf;
  114. buf2 = statbuf2;
  115. cmdbuf = emptybuf;
  116. /* Expand the message the user passed us. */
  117. length = sizeof (statbuf);
  118. va_start (args, message);
  119. buf = vasnprintf (statbuf, &length, message, args);
  120. va_end (args);
  121. if (!buf) goto memerror;
  122. /* Expand the cvs commmand name to <cmd> or [<cmd> aborted].
  123. *
  124. * I could squeeze this into the buf2 printf below, but this makes the code
  125. * easier to read and I don't think error messages are printed often enough
  126. * to make this a major performance hit. I think the memory cost is about
  127. * 40 bytes.
  128. */
  129. if (cvs_cmd_name)
  130. {
  131. length = sizeof (statcmdbuf);
  132. cmdbuf = asnprintf (statcmdbuf, &length, " %s%s%s",
  133. status ? "[" : "",
  134. cvs_cmd_name,
  135. status ? " aborted]" : "");
  136. /* Else cmdbuf still = emptybuf. */
  137. if (!cmdbuf) goto memerror;
  138. }
  139. /* Else cmdbuf still = emptybuf. */
  140. /* Now put it all together. */
  141. length = sizeof (statbuf2);
  142. buf2 = asnprintf (statbuf2, &length, "%s%s: %s%s%s\n",
  143. program_name, cmdbuf, buf,
  144. errnum ? ": " : "", errnum ? strerror (errnum) : "");
  145. if (!buf2) goto memerror;
  146. /* Send the final message to the client or log it.
  147. *
  148. * Set this recursion block first since this is the only function called
  149. * here which can cause error() to be called a second time.
  150. */
  151. if (last_message) goto recursion_error;
  152. last_message = buf2;
  153. last_status = status;
  154. last_errnum = errnum;
  155. cvs_outerr (buf2, length);
  156. /* Reset our recursion lock. This needs to be done before the call to
  157. * exit() to allow the exit handlers to make calls to error().
  158. */
  159. last_message = NULL;
  160. /* Done, if we're exiting. */
  161. if (status)
  162. exit (EXIT_FAILURE);
  163. /* Free anything we may have allocated. */
  164. if (buf != statbuf) free (buf);
  165. if (buf2 != statbuf2) free (buf2);
  166. if (cmdbuf != statcmdbuf && cmdbuf != emptybuf) free (cmdbuf);
  167. /* Restore errno per our charter. */
  168. errno = save_errno;
  169. /* Done. */
  170. return;
  171. memerror:
  172. /* Make one last attempt to log the problem in the syslog since that
  173. * should not require new memory, then abort.
  174. *
  175. * No second attempt is made to send the information to the client - if we
  176. * got here then that already failed once and this prevents us from
  177. * entering an infinite loop.
  178. *
  179. * FIXME
  180. * If the buffer routines can be altered in such a way that a single,
  181. * short, statically allocated message could be sent without needing to
  182. * allocate new memory, then it would still be safe to call cvs_outerr
  183. * with the message here.
  184. */
  185. #if HAVE_SYSLOG_H
  186. syslog (LOG_DAEMON | LOG_EMERG, "Memory exhausted. Aborting.");
  187. #endif /* HAVE_SYSLOG_H */
  188. goto sidestep_done;
  189. recursion_error:
  190. #if HAVE_SYSLOG_H
  191. /* Syslog the problem since recursion probably means that we encountered an
  192. * error while attempting to send the last error message to the client.
  193. */
  194. syslog (LOG_DAEMON | LOG_EMERG,
  195. "error (%d, %d) called recursively. Original message was:",
  196. last_status, last_errnum);
  197. syslog (LOG_DAEMON | LOG_EMERG, "%s", last_message);
  198. syslog (LOG_DAEMON | LOG_EMERG,
  199. "error (%d, %d) called recursively. Second message was:",
  200. status, errnum);
  201. syslog (LOG_DAEMON | LOG_EMERG, "%s", buf2);
  202. syslog (LOG_DAEMON | LOG_EMERG, "Aborting.");
  203. #endif /* HAVE_SYSLOG_H */
  204. sidestep_done:
  205. /* Reset our recursion lock. This needs to be done before the call to
  206. * exit() to allow the exit handlers to make calls to error().
  207. */
  208. last_message = NULL;
  209. exit (EXIT_FAILURE);
  210. }
  211. /* Print the program name and error message MESSAGE, which is a printf-style
  212. format string with optional args to the file specified by FP.
  213. If ERRNUM is nonzero, print its corresponding system error message.
  214. Exit with status EXIT_FAILURE if STATUS is nonzero. */
  215. /* VARARGS */
  216. void
  217. fperrmsg (FILE *fp, int status, int errnum, char *message, ...)
  218. {
  219. va_list args;
  220. fprintf (fp, "%s: ", program_name);
  221. va_start (args, message);
  222. vfprintf (fp, message, args);
  223. va_end (args);
  224. if (errnum)
  225. fprintf (fp, ": %s", strerror (errnum));
  226. putc ('\n', fp);
  227. fflush (fp);
  228. if (status)
  229. exit (EXIT_FAILURE);
  230. }