Back to index

glibc  2.9
fmtmsg.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997,1999,2000-2003,2005, 2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <fmtmsg.h>
00021 #include <bits/libc-lock.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <sys/syslog.h>
00026 #ifdef USE_IN_LIBIO
00027 # include <wchar.h>
00028 #endif
00029 
00030 
00031 /* We have global data, protect the modification.  */
00032 __libc_lock_define_initialized (static, lock)
00033 
00034 
00035 enum
00036 {
00037   label_mask = 0x01,
00038   severity_mask = 0x02,
00039   text_mask = 0x04,
00040   action_mask = 0x08,
00041   tag_mask = 0x10,
00042   all_mask = label_mask | severity_mask | text_mask | action_mask | tag_mask
00043 };
00044 
00045 static const struct
00046 {
00047   uint32_t len;
00048   /* Adjust the size if new elements are added.  */
00049   const char name[12];
00050 } keywords[] =
00051   {
00052     { 5, "label" },
00053     { 8, "severity" },
00054     { 4, "text" },
00055     { 6, "action"},
00056     { 3, "tag" }
00057   };
00058 #define NKEYWORDS (sizeof( keywords) / sizeof (keywords[0]))
00059 
00060 
00061 struct severity_info
00062 {
00063   int severity;
00064   const char *string;
00065   struct severity_info *next;
00066 };
00067 
00068 
00069 /* List of known severities.  */
00070 static const struct severity_info nosev =
00071 {
00072   MM_NOSEV, "", NULL
00073 };
00074 static const struct severity_info haltsev =
00075 {
00076   MM_HALT, "HALT", (struct severity_info *) &nosev
00077 };
00078 static const struct severity_info errorsev =
00079 {
00080   MM_ERROR, "ERROR", (struct severity_info *) &haltsev
00081 };
00082 static const struct severity_info warningsev =
00083 {
00084   MM_WARNING, "WARNING", (struct severity_info *) &errorsev
00085 };
00086 static const struct severity_info infosev =
00087 {
00088   MM_INFO, "INFO", (struct severity_info *) &warningsev
00089 };
00090 
00091 /* Start of the list.  */
00092 static struct severity_info *severity_list = (struct severity_info *) &infosev;
00093 
00094 /* Mask of values we will print.  */
00095 static int print;
00096 
00097 /* Prototypes for local functions.  */
00098 static void init (void);
00099 static int internal_addseverity (int severity, const char *string)
00100      internal_function;
00101 
00102 
00103 int
00104 fmtmsg (long int classification, const char *label, int severity,
00105        const char *text, const char *action, const char *tag)
00106 {
00107   __libc_once_define (static, once);
00108   int result = MM_OK;
00109   struct severity_info *severity_rec;
00110 
00111   /* Make sure everything is initialized.  */
00112   __libc_once (once, init);
00113 
00114   /* Start the real work.  First check whether the input is ok.  */
00115   if (label != MM_NULLLBL)
00116     {
00117       /* Must be two fields, separated by a colon.  */
00118       const char *cp = strchr (label, ':');
00119       if (cp == NULL)
00120        return MM_NOTOK;
00121 
00122       /* The first field must not contain more then 10 bytes.  */
00123       if (cp - label > 10
00124          /* The second field must not have more then 14 bytes.  */
00125          || strlen (cp + 1) > 14)
00126        return MM_NOTOK;
00127     }
00128 
00129   for (severity_rec = severity_list; severity_rec != NULL;
00130        severity_rec = severity_rec->next)
00131     if (severity == severity_rec->severity)
00132       /* Bingo.  */
00133       break;
00134 
00135   /* If we don't know anything about the severity level return an error.  */
00136   if (severity_rec == NULL)
00137     return MM_NOTOK;
00138 
00139 
00140 #ifdef __libc_ptf_call
00141   /* We do not want this call to be cut short by a thread
00142      cancellation.  Therefore disable cancellation for now.  */
00143   int state = PTHREAD_CANCEL_ENABLE;
00144   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
00145                  0);
00146 #endif
00147 
00148   /* Now we can print.  */
00149   if (classification & MM_PRINT)
00150     {
00151       int do_label = (print & label_mask) && label != MM_NULLLBL;
00152       int do_severity = (print & severity_mask) && severity != MM_NULLSEV;
00153       int do_text = (print & text_mask) && text != MM_NULLTXT;
00154       int do_action = (print & action_mask) && action != MM_NULLACT;
00155       int do_tag = (print & tag_mask) && tag != MM_NULLTAG;
00156 
00157       if (__fxprintf (stderr, "%s%s%s%s%s%s%s%s%s%s\n",
00158                     do_label ? label : "",
00159                     do_label && (do_severity | do_text | do_action | do_tag)
00160                     ? ": " : "",
00161                     do_severity ? severity_rec->string : "",
00162                     do_severity && (do_text | do_action | do_tag)
00163                     ? ": " : "",
00164                     do_text ? text : "",
00165                     do_text && (do_action | do_tag) ? "\n" : "",
00166                     do_action ? "TO FIX: " : "",
00167                     do_action ? action : "",
00168                     do_action && do_tag ? "  " : "",
00169                     do_tag ? tag : "") < 0)
00170        /* Oh, oh.  An error occurred during the output.  */
00171        result = MM_NOMSG;
00172     }
00173 
00174   if (classification & MM_CONSOLE)
00175     {
00176       int do_label = label != MM_NULLLBL;
00177       int do_severity = severity != MM_NULLSEV;
00178       int do_text = text != MM_NULLTXT;
00179       int do_action = action != MM_NULLACT;
00180       int do_tag = tag != MM_NULLTAG;
00181 
00182       syslog (LOG_ERR, "%s%s%s%s%s%s%s%s%s%s\n",
00183              do_label ? label : "",
00184              do_label && (do_severity | do_text | do_action | do_tag)
00185              ? ": " : "",
00186              do_severity ? severity_rec->string : "",
00187              do_severity && (do_text | do_action | do_tag) ? ": " : "",
00188              do_text ? text : "",
00189              do_text && (do_action | do_tag) ? "\n" : "",
00190              do_action ? "TO FIX: " : "",
00191              do_action ? action : "",
00192              do_action && do_tag ? "  " : "",
00193              do_tag ? tag : "");
00194     }
00195 
00196 #ifdef __libc_ptf_call
00197   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
00198 #endif
00199 
00200   return result;
00201 }
00202 
00203 
00204 /* Initialize from environment variable content.  */
00205 static void
00206 init (void)
00207 {
00208   const char *msgverb_var = getenv ("MSGVERB");
00209   const char *sevlevel_var = getenv ("SEV_LEVEL");
00210 
00211   if (msgverb_var != NULL && msgverb_var[0] != '\0')
00212     {
00213       /* Using this extra variable allows us to work without locking.  */
00214       do
00215        {
00216          size_t cnt;
00217 
00218          for (cnt = 0; cnt < NKEYWORDS; ++cnt)
00219            if (memcmp (msgverb_var,
00220                      keywords[cnt].name, keywords[cnt].len) == 0
00221               && (msgverb_var[keywords[cnt].len] == ':'
00222                   || msgverb_var[keywords[cnt].len] == '\0'))
00223              break;
00224 
00225          if (cnt < NKEYWORDS)
00226            {
00227              print |= 1 << cnt;
00228 
00229              msgverb_var += keywords[cnt].len;
00230              if (msgverb_var[0] == ':')
00231               ++msgverb_var;
00232            }
00233          else
00234            {
00235              /* We found an illegal keyword in the environment
00236                variable.  The specifications say that we print all
00237                fields.  */
00238              print = all_mask;
00239              break;
00240            }
00241        }
00242       while (msgverb_var[0] != '\0');
00243     }
00244   else
00245     print = all_mask;
00246 
00247 
00248   if (sevlevel_var != NULL)
00249     {
00250       __libc_lock_lock (lock);
00251 
00252       while (sevlevel_var[0] != '\0')
00253        {
00254          const char *end = __strchrnul (sevlevel_var, ':');
00255          int level;
00256 
00257          /* First field: keyword.  This is not used here but it must be
00258             present.  */
00259          while (sevlevel_var < end)
00260            if (*sevlevel_var++ == ',')
00261              break;
00262 
00263          if (sevlevel_var < end)
00264            {
00265              /* Second field: severity level, a number.  */
00266              char *cp;
00267 
00268              level = strtol (sevlevel_var, &cp, 0);
00269              if (cp != sevlevel_var && cp < end && *cp++ == ','
00270                 && level > MM_INFO)
00271               {
00272                 const char *new_string;
00273 
00274                 new_string = __strndup (cp, end - cp);
00275 
00276                 if (new_string != NULL
00277                     && (internal_addseverity (level, new_string)
00278                        != MM_OK))
00279                   free ((char *) new_string);
00280               }
00281            }
00282 
00283          sevlevel_var = end + (*end == ':' ? 1 : 0);
00284        }
00285     }
00286 }
00287 
00288 
00289 /* Add the new entry to the list.  */
00290 static int
00291 internal_function
00292 internal_addseverity (int severity, const char *string)
00293 {
00294   struct severity_info *runp, *lastp;
00295   int result = MM_OK;
00296 
00297   /* First see if there is already a record for the severity level.  */
00298   for (runp = severity_list, lastp = NULL; runp != NULL; runp = runp->next)
00299     if (runp->severity == severity)
00300       break;
00301     else
00302       lastp = runp;
00303 
00304   if (runp != NULL)
00305     {
00306       if (string != NULL)
00307        /* Change the string.  */
00308        runp->string = string;
00309       else
00310        {
00311          /* Remove the severity class.  */
00312          if (lastp == NULL)
00313            severity_list = runp->next;
00314          else
00315            lastp->next = runp->next;
00316 
00317          free (runp);
00318        }
00319     }
00320   else if (string != NULL)
00321     {
00322       runp = malloc (sizeof (*runp));
00323       if (runp == NULL)
00324        result = MM_NOTOK;
00325       else
00326        {
00327          runp->severity = severity;
00328          runp->next = severity_list;
00329          runp->string = string;
00330          severity_list = runp;
00331        }
00332     }
00333   else
00334     /* We tried to remove a non-existing severity class.  */
00335     result = MM_NOTOK;
00336 
00337   return result;
00338 }
00339 
00340 
00341 /* Add new severity level or remove old one.  */
00342 int
00343 addseverity (int severity, const char *string)
00344 {
00345   int result;
00346 
00347   /* Prevent illegal SEVERITY values.  */
00348   if (severity <= MM_INFO)
00349     return MM_NOTOK;
00350 
00351   /* Protect the global data.  */
00352   __libc_lock_lock (lock);
00353 
00354   /* Do the real work.  */
00355   result = internal_addseverity (severity, string);
00356 
00357   /* Release the lock.  */
00358   __libc_lock_unlock (lock);
00359 
00360   return result;
00361 }
00362 
00363 
00364 libc_freeres_fn (free_mem)
00365 {
00366   struct severity_info *runp = severity_list;
00367 
00368   while (runp != NULL)
00369     if (runp->severity > MM_INFO)
00370       {
00371        /* This is data we have to release.  */
00372        struct severity_info *here = runp;
00373        runp = runp->next;
00374        free (here);
00375       }
00376     else
00377       runp = runp->next;
00378 }