fmtmsg.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /* Copyright (C) 1997-2019 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <fmtmsg.h>
  16. #include <libc-lock.h>
  17. #include <stdio.h>
  18. #include <stdint.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/syslog.h>
  22. #include <wchar.h>
  23. /* We have global data, protect the modification. */
  24. __libc_lock_define_initialized (static, lock)
  25. enum
  26. {
  27. label_mask = 0x01,
  28. severity_mask = 0x02,
  29. text_mask = 0x04,
  30. action_mask = 0x08,
  31. tag_mask = 0x10,
  32. all_mask = label_mask | severity_mask | text_mask | action_mask | tag_mask
  33. };
  34. static const struct
  35. {
  36. uint32_t len;
  37. /* Adjust the size if new elements are added. */
  38. const char name[12];
  39. } keywords[] =
  40. {
  41. { 5, "label" },
  42. { 8, "severity" },
  43. { 4, "text" },
  44. { 6, "action"},
  45. { 3, "tag" }
  46. };
  47. #define NKEYWORDS (sizeof( keywords) / sizeof (keywords[0]))
  48. struct severity_info
  49. {
  50. int severity;
  51. const char *string;
  52. struct severity_info *next;
  53. };
  54. /* List of known severities. */
  55. static const struct severity_info nosev =
  56. {
  57. MM_NOSEV, "", NULL
  58. };
  59. static const struct severity_info haltsev =
  60. {
  61. MM_HALT, "HALT", (struct severity_info *) &nosev
  62. };
  63. static const struct severity_info errorsev =
  64. {
  65. MM_ERROR, "ERROR", (struct severity_info *) &haltsev
  66. };
  67. static const struct severity_info warningsev =
  68. {
  69. MM_WARNING, "WARNING", (struct severity_info *) &errorsev
  70. };
  71. static const struct severity_info infosev =
  72. {
  73. MM_INFO, "INFO", (struct severity_info *) &warningsev
  74. };
  75. /* Start of the list. */
  76. static struct severity_info *severity_list = (struct severity_info *) &infosev;
  77. /* Mask of values we will print. */
  78. static int print;
  79. /* Prototypes for local functions. */
  80. static void init (void);
  81. static int internal_addseverity (int severity, const char *string);
  82. int
  83. fmtmsg (long int classification, const char *label, int severity,
  84. const char *text, const char *action, const char *tag)
  85. {
  86. __libc_once_define (static, once);
  87. struct severity_info *severity_rec;
  88. /* Make sure everything is initialized. */
  89. __libc_once (once, init);
  90. /* Start the real work. First check whether the input is ok. */
  91. if (label != MM_NULLLBL)
  92. {
  93. /* Must be two fields, separated by a colon. */
  94. const char *cp = strchr (label, ':');
  95. if (cp == NULL)
  96. return MM_NOTOK;
  97. /* The first field must not contain more than 10 bytes. */
  98. if (cp - label > 10
  99. /* The second field must not have more than 14 bytes. */
  100. || strlen (cp + 1) > 14)
  101. return MM_NOTOK;
  102. }
  103. #ifdef __libc_ptf_call
  104. /* We do not want this call to be cut short by a thread
  105. cancellation. Therefore disable cancellation for now. */
  106. int state = PTHREAD_CANCEL_ENABLE;
  107. __libc_ptf_call (__pthread_setcancelstate,
  108. (PTHREAD_CANCEL_DISABLE, &state), 0);
  109. #endif
  110. __libc_lock_lock (lock);
  111. for (severity_rec = severity_list; severity_rec != NULL;
  112. severity_rec = severity_rec->next)
  113. if (severity == severity_rec->severity)
  114. /* Bingo. */
  115. break;
  116. /* If we don't know anything about the severity level return an error. */
  117. int result = MM_NOTOK;
  118. if (severity_rec != NULL)
  119. {
  120. result = MM_OK;
  121. /* Now we can print. */
  122. if (classification & MM_PRINT)
  123. {
  124. int do_label = (print & label_mask) && label != MM_NULLLBL;
  125. int do_severity = (print & severity_mask) && severity != MM_NULLSEV;
  126. int do_text = (print & text_mask) && text != MM_NULLTXT;
  127. int do_action = (print & action_mask) && action != MM_NULLACT;
  128. int do_tag = (print & tag_mask) && tag != MM_NULLTAG;
  129. int need_colon = (do_label
  130. && (do_severity | do_text | do_action | do_tag));
  131. if (__fxprintf (stderr, "%s%s%s%s%s%s%s%s%s%s\n",
  132. do_label ? label : "",
  133. need_colon ? ": " : "",
  134. do_severity ? severity_rec->string : "",
  135. do_severity && (do_text | do_action | do_tag)
  136. ? ": " : "",
  137. do_text ? text : "",
  138. do_text && (do_action | do_tag) ? "\n" : "",
  139. do_action ? "TO FIX: " : "",
  140. do_action ? action : "",
  141. do_action && do_tag ? " " : "",
  142. do_tag ? tag : "") < 0)
  143. /* Oh, oh. An error occurred during the output. */
  144. result = MM_NOMSG;
  145. }
  146. if (classification & MM_CONSOLE)
  147. {
  148. int do_label = label != MM_NULLLBL;
  149. int do_severity = severity != MM_NULLSEV;
  150. int do_text = text != MM_NULLTXT;
  151. int do_action = action != MM_NULLACT;
  152. int do_tag = tag != MM_NULLTAG;
  153. int need_colon = (do_label
  154. && (do_severity | do_text | do_action | do_tag));
  155. syslog (LOG_ERR, "%s%s%s%s%s%s%s%s%s%s\n",
  156. do_label ? label : "",
  157. need_colon ? ": " : "",
  158. do_severity ? severity_rec->string : "",
  159. do_severity && (do_text | do_action | do_tag) ? ": " : "",
  160. do_text ? text : "",
  161. do_text && (do_action | do_tag) ? "\n" : "",
  162. do_action ? "TO FIX: " : "",
  163. do_action ? action : "",
  164. do_action && do_tag ? " " : "",
  165. do_tag ? tag : "");
  166. }
  167. }
  168. __libc_lock_unlock (lock);
  169. #ifdef __libc_ptf_call
  170. __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
  171. #endif
  172. return result;
  173. }
  174. /* Initialize from environment variable content. */
  175. static void
  176. init (void)
  177. {
  178. const char *msgverb_var = getenv ("MSGVERB");
  179. const char *sevlevel_var = getenv ("SEV_LEVEL");
  180. if (msgverb_var != NULL && msgverb_var[0] != '\0')
  181. {
  182. /* Using this extra variable allows us to work without locking. */
  183. do
  184. {
  185. size_t cnt;
  186. for (cnt = 0; cnt < NKEYWORDS; ++cnt)
  187. if (memcmp (msgverb_var,
  188. keywords[cnt].name, keywords[cnt].len) == 0
  189. && (msgverb_var[keywords[cnt].len] == ':'
  190. || msgverb_var[keywords[cnt].len] == '\0'))
  191. break;
  192. if (cnt < NKEYWORDS)
  193. {
  194. print |= 1 << cnt;
  195. msgverb_var += keywords[cnt].len;
  196. if (msgverb_var[0] == ':')
  197. ++msgverb_var;
  198. }
  199. else
  200. {
  201. /* We found an illegal keyword in the environment
  202. variable. The specifications say that we print all
  203. fields. */
  204. print = all_mask;
  205. break;
  206. }
  207. }
  208. while (msgverb_var[0] != '\0');
  209. }
  210. else
  211. print = all_mask;
  212. if (sevlevel_var != NULL)
  213. {
  214. __libc_lock_lock (lock);
  215. while (sevlevel_var[0] != '\0')
  216. {
  217. const char *end = __strchrnul (sevlevel_var, ':');
  218. int level;
  219. /* First field: keyword. This is not used here but it must be
  220. present. */
  221. while (sevlevel_var < end)
  222. if (*sevlevel_var++ == ',')
  223. break;
  224. if (sevlevel_var < end)
  225. {
  226. /* Second field: severity level, a number. */
  227. char *cp;
  228. level = strtol (sevlevel_var, &cp, 0);
  229. if (cp != sevlevel_var && cp < end && *cp++ == ','
  230. && level > MM_INFO)
  231. {
  232. const char *new_string;
  233. new_string = __strndup (cp, end - cp);
  234. if (new_string != NULL
  235. && (internal_addseverity (level, new_string)
  236. != MM_OK))
  237. free ((char *) new_string);
  238. }
  239. }
  240. sevlevel_var = end + (*end == ':' ? 1 : 0);
  241. }
  242. __libc_lock_unlock (lock);
  243. }
  244. }
  245. /* Add the new entry to the list. */
  246. static int
  247. internal_addseverity (int severity, const char *string)
  248. {
  249. struct severity_info *runp, *lastp;
  250. int result = MM_OK;
  251. /* First see if there is already a record for the severity level. */
  252. for (runp = severity_list, lastp = NULL; runp != NULL; runp = runp->next)
  253. if (runp->severity == severity)
  254. break;
  255. else
  256. lastp = runp;
  257. if (runp != NULL)
  258. {
  259. if (string != NULL)
  260. /* Change the string. */
  261. runp->string = string;
  262. else
  263. {
  264. /* Remove the severity class. */
  265. if (lastp == NULL)
  266. severity_list = runp->next;
  267. else
  268. lastp->next = runp->next;
  269. free (runp);
  270. }
  271. }
  272. else if (string != NULL)
  273. {
  274. runp = malloc (sizeof (*runp));
  275. if (runp == NULL)
  276. result = MM_NOTOK;
  277. else
  278. {
  279. runp->severity = severity;
  280. runp->next = severity_list;
  281. runp->string = string;
  282. severity_list = runp;
  283. }
  284. }
  285. else
  286. /* We tried to remove a non-existing severity class. */
  287. result = MM_NOTOK;
  288. return result;
  289. }
  290. /* Add new severity level or remove old one. */
  291. int
  292. __addseverity (int severity, const char *string)
  293. {
  294. int result;
  295. /* Prevent illegal SEVERITY values. */
  296. if (severity <= MM_INFO)
  297. return MM_NOTOK;
  298. /* Protect the global data. */
  299. __libc_lock_lock (lock);
  300. /* Do the real work. */
  301. result = internal_addseverity (severity, string);
  302. /* Release the lock. */
  303. __libc_lock_unlock (lock);
  304. return result;
  305. }
  306. weak_alias (__addseverity, addseverity)
  307. libc_freeres_fn (free_mem)
  308. {
  309. struct severity_info *runp = severity_list;
  310. while (runp != NULL)
  311. if (runp->severity > MM_INFO)
  312. {
  313. /* This is data we have to release. */
  314. struct severity_info *here = runp;
  315. runp = runp->next;
  316. free (here);
  317. }
  318. else
  319. runp = runp->next;
  320. }