dbus-sysdeps.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation)
00003  * 
00004  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
00005  * Copyright (C) 2003 CodeFactory AB
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "dbus-internals.h"
00026 #include "dbus-sysdeps.h"
00027 #include "dbus-threads.h"
00028 #include "dbus-protocol.h"
00029 #include "dbus-string.h"
00030 
00031 /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
00032  * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
00033  *
00034  * These are the standard ANSI C headers...
00035  */
00036 #include <locale.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <stdio.h>
00040 
00041 /* This is UNIX-specific (on windows it's just in stdlib.h I believe)
00042  * but OK since the same stuff does exist on Windows in stdlib.h
00043  * and covered by a configure check.
00044  */
00045 #ifdef HAVE_ERRNO_H
00046 #include <errno.h>
00047 #endif
00048 
00049 _DBUS_DEFINE_GLOBAL_LOCK (win_fds);
00050 _DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache);
00051 
00069 void
00070 _dbus_abort (void)
00071 {
00072   const char *s;
00073   
00074   _dbus_print_backtrace ();
00075   
00076   s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
00077   if (s && *s)
00078     {
00079       /* don't use _dbus_warn here since it can _dbus_abort() */
00080       fprintf (stderr, "  Process %lu sleeping for gdb attach\n", (unsigned long) _dbus_getpid());
00081       _dbus_sleep_milliseconds (1000 * 180);
00082     }
00083   
00084   abort ();
00085   _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
00086 }
00087 
00101 dbus_bool_t
00102 _dbus_setenv (const char *varname,
00103               const char *value)
00104 {
00105   _dbus_assert (varname != NULL);
00106   
00107   if (value == NULL)
00108     {
00109 #ifdef HAVE_UNSETENV
00110       unsetenv (varname);
00111       return TRUE;
00112 #else
00113       char *putenv_value;
00114       size_t len;
00115 
00116       len = strlen (varname);
00117 
00118       /* Use system malloc to avoid memleaks that dbus_malloc
00119        * will get upset about.
00120        */
00121       
00122       putenv_value = malloc (len + 1);
00123       if (putenv_value == NULL)
00124         return FALSE;
00125 
00126       strcpy (putenv_value, varname);
00127       
00128       return (putenv (putenv_value) == 0);
00129 #endif
00130     }
00131   else
00132     {
00133 #ifdef HAVE_SETENV
00134       return (setenv (varname, value, TRUE) == 0);
00135 #else
00136       char *putenv_value;
00137       size_t len;
00138       size_t varname_len;
00139       size_t value_len;
00140 
00141       varname_len = strlen (varname);
00142       value_len = strlen (value);
00143       
00144       len = varname_len + value_len + 1 /* '=' */ ;
00145 
00146       /* Use system malloc to avoid memleaks that dbus_malloc
00147        * will get upset about.
00148        */
00149       
00150       putenv_value = malloc (len + 1);
00151       if (putenv_value == NULL)
00152         return FALSE;
00153 
00154       strcpy (putenv_value, varname);
00155       strcpy (putenv_value + varname_len, "=");
00156       strcpy (putenv_value + varname_len + 1, value);
00157       
00158       return (putenv (putenv_value) == 0);
00159 #endif
00160     }
00161 }
00162 
00169 const char*
00170 _dbus_getenv (const char *varname)
00171 {  
00172   /* Don't respect any environment variables if the current process is
00173    * setuid.  This is the equivalent of glibc's __secure_getenv().
00174    */
00175   if (_dbus_check_setuid ())
00176     return NULL;
00177   return getenv (varname);
00178 }
00179 
00194 dbus_bool_t
00195 _dbus_string_append_int (DBusString *str,
00196                          long        value)
00197 {
00198   /* this calculation is from comp.lang.c faq */
00199 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
00200   int orig_len;
00201   int i;
00202   char *buf;
00203   
00204   orig_len = _dbus_string_get_length (str);
00205 
00206   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
00207     return FALSE;
00208 
00209   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
00210 
00211   snprintf (buf, MAX_LONG_LEN, "%ld", value);
00212 
00213   i = 0;
00214   while (*buf)
00215     {
00216       ++buf;
00217       ++i;
00218     }
00219   
00220   _dbus_string_shorten (str, MAX_LONG_LEN - i);
00221   
00222   return TRUE;
00223 }
00224 
00232 dbus_bool_t
00233 _dbus_string_append_uint (DBusString    *str,
00234                           unsigned long  value)
00235 {
00236   /* this is wrong, but definitely on the high side. */
00237 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
00238   int orig_len;
00239   int i;
00240   char *buf;
00241   
00242   orig_len = _dbus_string_get_length (str);
00243 
00244   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
00245     return FALSE;
00246 
00247   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
00248 
00249   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
00250 
00251   i = 0;
00252   while (*buf)
00253     {
00254       ++buf;
00255       ++i;
00256     }
00257   
00258   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
00259   
00260   return TRUE;
00261 }
00262 
00263 #ifdef DBUS_BUILD_TESTS
00264 
00271 dbus_bool_t
00272 _dbus_string_append_double (DBusString *str,
00273                             double      value)
00274 {
00275 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
00276   int orig_len;
00277   char *buf;
00278   int i;
00279   
00280   orig_len = _dbus_string_get_length (str);
00281 
00282   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
00283     return FALSE;
00284 
00285   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
00286 
00287   snprintf (buf, MAX_LONG_LEN, "%g", value);
00288 
00289   i = 0;
00290   while (*buf)
00291     {
00292       ++buf;
00293       ++i;
00294     }
00295   
00296   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
00297   
00298   return TRUE;
00299 }
00300 #endif /* DBUS_BUILD_TESTS */
00301 
00314 dbus_bool_t
00315 _dbus_string_parse_int (const DBusString *str,
00316                         int               start,
00317                         long             *value_return,
00318                         int              *end_return)
00319 {
00320   long v;
00321   const char *p;
00322   char *end;
00323 
00324   p = _dbus_string_get_const_data_len (str, start,
00325                                        _dbus_string_get_length (str) - start);
00326 
00327   end = NULL;
00328   errno = 0;
00329   v = strtol (p, &end, 0);
00330   if (end == NULL || end == p || errno != 0)
00331     return FALSE;
00332 
00333   if (value_return)
00334     *value_return = v;
00335   if (end_return)
00336     *end_return = start + (end - p);
00337 
00338   return TRUE;
00339 }
00340 
00353 dbus_bool_t
00354 _dbus_string_parse_uint (const DBusString *str,
00355                          int               start,
00356                          unsigned long    *value_return,
00357                          int              *end_return)
00358 {
00359   unsigned long v;
00360   const char *p;
00361   char *end;
00362 
00363   p = _dbus_string_get_const_data_len (str, start,
00364                                        _dbus_string_get_length (str) - start);
00365 
00366   end = NULL;
00367   errno = 0;
00368   v = strtoul (p, &end, 0);
00369   if (end == NULL || end == p || errno != 0)
00370     return FALSE;
00371 
00372   if (value_return)
00373     *value_return = v;
00374   if (end_return)
00375     *end_return = start + (end - p);
00376 
00377   return TRUE;
00378 }
00379 
00380 #ifdef DBUS_BUILD_TESTS
00381 static dbus_bool_t
00382 ascii_isspace (char c)
00383 {
00384   return (c == ' ' ||
00385           c == '\f' ||
00386           c == '\n' ||
00387           c == '\r' ||
00388           c == '\t' ||
00389           c == '\v');
00390 }
00391 #endif /* DBUS_BUILD_TESTS */
00392 
00393 #ifdef DBUS_BUILD_TESTS
00394 static dbus_bool_t
00395 ascii_isdigit (char c)
00396 {
00397   return c >= '0' && c <= '9';
00398 }
00399 #endif /* DBUS_BUILD_TESTS */
00400 
00401 #ifdef DBUS_BUILD_TESTS
00402 static dbus_bool_t
00403 ascii_isxdigit (char c)
00404 {
00405   return (ascii_isdigit (c) ||
00406           (c >= 'a' && c <= 'f') ||
00407           (c >= 'A' && c <= 'F'));
00408 }
00409 #endif /* DBUS_BUILD_TESTS */
00410 
00411 #ifdef DBUS_BUILD_TESTS
00412 /* Calls strtod in a locale-independent fashion, by looking at
00413  * the locale data and patching the decimal comma to a point.
00414  *
00415  * Relicensed from glib.
00416  */
00417 static double
00418 ascii_strtod (const char *nptr,
00419               char      **endptr)
00420 {
00421   char *fail_pos;
00422   double val;
00423   struct lconv *locale_data;
00424   const char *decimal_point;
00425   int decimal_point_len;
00426   const char *p, *decimal_point_pos;
00427   const char *end = NULL; /* Silence gcc */
00428 
00429   fail_pos = NULL;
00430 
00431   locale_data = localeconv ();
00432   decimal_point = locale_data->decimal_point;
00433   decimal_point_len = strlen (decimal_point);
00434 
00435   _dbus_assert (decimal_point_len != 0);
00436   
00437   decimal_point_pos = NULL;
00438   if (decimal_point[0] != '.' ||
00439       decimal_point[1] != 0)
00440     {
00441       p = nptr;
00442       /* Skip leading space */
00443       while (ascii_isspace (*p))
00444         p++;
00445       
00446       /* Skip leading optional sign */
00447       if (*p == '+' || *p == '-')
00448         p++;
00449       
00450       if (p[0] == '0' &&
00451           (p[1] == 'x' || p[1] == 'X'))
00452         {
00453           p += 2;
00454           /* HEX - find the (optional) decimal point */
00455           
00456           while (ascii_isxdigit (*p))
00457             p++;
00458           
00459           if (*p == '.')
00460             {
00461               decimal_point_pos = p++;
00462               
00463               while (ascii_isxdigit (*p))
00464                 p++;
00465               
00466               if (*p == 'p' || *p == 'P')
00467                 p++;
00468               if (*p == '+' || *p == '-')
00469                 p++;
00470               while (ascii_isdigit (*p))
00471                 p++;
00472               end = p;
00473             }
00474         }
00475       else
00476         {
00477           while (ascii_isdigit (*p))
00478             p++;
00479           
00480           if (*p == '.')
00481             {
00482               decimal_point_pos = p++;
00483               
00484               while (ascii_isdigit (*p))
00485                 p++;
00486               
00487               if (*p == 'e' || *p == 'E')
00488                 p++;
00489               if (*p == '+' || *p == '-')
00490                 p++;
00491               while (ascii_isdigit (*p))
00492                 p++;
00493               end = p;
00494             }
00495         }
00496       /* For the other cases, we need not convert the decimal point */
00497     }
00498 
00499   /* Set errno to zero, so that we can distinguish zero results
00500      and underflows */
00501   errno = 0;
00502   
00503   if (decimal_point_pos)
00504     {
00505       char *copy, *c;
00506 
00507       /* We need to convert the '.' to the locale specific decimal point */
00508       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
00509       
00510       c = copy;
00511       memcpy (c, nptr, decimal_point_pos - nptr);
00512       c += decimal_point_pos - nptr;
00513       memcpy (c, decimal_point, decimal_point_len);
00514       c += decimal_point_len;
00515       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
00516       c += end - (decimal_point_pos + 1);
00517       *c = 0;
00518 
00519       val = strtod (copy, &fail_pos);
00520 
00521       if (fail_pos)
00522         {
00523           if (fail_pos > decimal_point_pos)
00524             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
00525           else
00526             fail_pos = (char *)nptr + (fail_pos - copy);
00527         }
00528       
00529       dbus_free (copy);
00530           
00531     }
00532   else
00533     val = strtod (nptr, &fail_pos);
00534 
00535   if (endptr)
00536     *endptr = fail_pos;
00537   
00538   return val;
00539 }
00540 #endif /* DBUS_BUILD_TESTS */
00541 
00542 #ifdef DBUS_BUILD_TESTS
00543 
00555 dbus_bool_t
00556 _dbus_string_parse_double (const DBusString *str,
00557                            int               start,
00558                            double           *value_return,
00559                            int              *end_return)
00560 {
00561   double v;
00562   const char *p;
00563   char *end;
00564 
00565   p = _dbus_string_get_const_data_len (str, start,
00566                                        _dbus_string_get_length (str) - start);
00567 
00568   end = NULL;
00569   errno = 0;
00570   v = ascii_strtod (p, &end);
00571   if (end == NULL || end == p || errno != 0)
00572     return FALSE;
00573 
00574   if (value_return)
00575     *value_return = v;
00576   if (end_return)
00577     *end_return = start + (end - p);
00578 
00579   return TRUE;
00580 }
00581 #endif /* DBUS_BUILD_TESTS */
00582  /* DBusString group */
00584 
00595 void
00596 _dbus_user_info_free (DBusUserInfo *info)
00597 {
00598   dbus_free (info->group_ids);
00599   dbus_free (info->username);
00600   dbus_free (info->homedir);
00601 }
00602 
00608 void
00609 _dbus_group_info_free (DBusGroupInfo    *info)
00610 {
00611   dbus_free (info->groupname);
00612 }
00613 
00620 void
00621 _dbus_credentials_clear (DBusCredentials *credentials)
00622 {
00623   credentials->pid = DBUS_PID_UNSET;
00624   credentials->uid = DBUS_UID_UNSET;
00625   credentials->gid = DBUS_GID_UNSET;
00626 }
00627 
00636 dbus_bool_t
00637 _dbus_credentials_match (const DBusCredentials *expected_credentials,
00638                          const DBusCredentials *provided_credentials)
00639 {
00640   if (provided_credentials->uid == DBUS_UID_UNSET)
00641     return FALSE;
00642   else if (expected_credentials->uid == DBUS_UID_UNSET)
00643     return FALSE;
00644   else if (provided_credentials->uid == 0)
00645     return TRUE;
00646   else if (provided_credentials->uid == expected_credentials->uid)
00647     return TRUE;
00648   else
00649     return FALSE;
00650 }
00651 
00652 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
00653 
00654 #ifdef DBUS_USE_ATOMIC_INT_486
00655 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
00656 /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
00657 static inline dbus_int32_t
00658 atomic_exchange_and_add (DBusAtomic            *atomic,
00659                          volatile dbus_int32_t  val)
00660 {
00661   register dbus_int32_t result;
00662 
00663   __asm__ __volatile__ ("lock; xaddl %0,%1"
00664                         : "=r" (result), "=m" (atomic->value)
00665                         : "0" (val), "m" (atomic->value));
00666   return result;
00667 }
00668 #endif
00669 
00678 dbus_int32_t
00679 _dbus_atomic_inc (DBusAtomic *atomic)
00680 {
00681 #ifdef DBUS_USE_ATOMIC_INT_486
00682   return atomic_exchange_and_add (atomic, 1);
00683 #else
00684   dbus_int32_t res;
00685   _DBUS_LOCK (atomic);
00686   res = atomic->value;
00687   atomic->value += 1;
00688   _DBUS_UNLOCK (atomic);
00689   return res;
00690 #endif
00691 }
00692 
00701 dbus_int32_t
00702 _dbus_atomic_dec (DBusAtomic *atomic)
00703 {
00704 #ifdef DBUS_USE_ATOMIC_INT_486
00705   return atomic_exchange_and_add (atomic, -1);
00706 #else
00707   dbus_int32_t res;
00708   
00709   _DBUS_LOCK (atomic);
00710   res = atomic->value;
00711   atomic->value -= 1;
00712   _DBUS_UNLOCK (atomic);
00713   return res;
00714 #endif
00715 }
00716 
00717 void
00718 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
00719                                           int   n_bytes)
00720 {
00721   long tv_usec;
00722   int i;
00723   
00724   /* fall back to pseudorandom */
00725   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
00726                  n_bytes);
00727   
00728   _dbus_get_current_time (NULL, &tv_usec);
00729   srand (tv_usec);
00730   
00731   i = 0;
00732   while (i < n_bytes)
00733     {
00734       double r;
00735       unsigned int b;
00736           
00737       r = rand ();
00738       b = (r / (double) RAND_MAX) * 255.0;
00739 
00740       buffer[i] = b;
00741 
00742       ++i;
00743     }
00744 }
00745 
00752 void
00753 _dbus_generate_random_bytes_buffer (char *buffer,
00754                                     int   n_bytes)
00755 {
00756   DBusString str;
00757 
00758   if (!_dbus_string_init (&str))
00759     {
00760       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00761       return;
00762     }
00763 
00764   if (!_dbus_generate_random_bytes (&str, n_bytes))
00765     {
00766       _dbus_string_free (&str);
00767       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00768       return;
00769     }
00770 
00771   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
00772 
00773   _dbus_string_free (&str);
00774 }
00775 
00784 dbus_bool_t
00785 _dbus_generate_random_ascii (DBusString *str,
00786                              int         n_bytes)
00787 {
00788   static const char letters[] =
00789     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
00790   int i;
00791   int len;
00792   
00793   if (!_dbus_generate_random_bytes (str, n_bytes))
00794     return FALSE;
00795   
00796   len = _dbus_string_get_length (str);
00797   i = len - n_bytes;
00798   while (i < len)
00799     {
00800       _dbus_string_set_byte (str, i,
00801                              letters[_dbus_string_get_byte (str, i) %
00802                                      (sizeof (letters) - 1)]);
00803 
00804       ++i;
00805     }
00806 
00807   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
00808                                              n_bytes));
00809 
00810   return TRUE;
00811 }
00812 
00820 dbus_bool_t
00821 _dbus_parse_uid (const DBusString      *uid_str,
00822                  dbus_uid_t            *uid)
00823 {
00824   int end;
00825   long val;
00826   
00827   if (_dbus_string_get_length (uid_str) == 0)
00828     {
00829       _dbus_verbose ("UID string was zero length\n");
00830       return FALSE;
00831     }
00832 
00833   val = -1;
00834   end = 0;
00835   if (!_dbus_string_parse_int (uid_str, 0, &val,
00836                                &end))
00837     {
00838       _dbus_verbose ("could not parse string as a UID\n");
00839       return FALSE;
00840     }
00841   
00842   if (end != _dbus_string_get_length (uid_str))
00843     {
00844       _dbus_verbose ("string contained trailing stuff after UID\n");
00845       return FALSE;
00846     }
00847 
00848   *uid = val;
00849 
00850   return TRUE;
00851 }
00852 
00863 const char*
00864 _dbus_error_from_errno (int error_number)
00865 {
00866   switch (error_number)
00867     {
00868     case 0:
00869       return DBUS_ERROR_FAILED;
00870       
00871 #ifdef EPROTONOSUPPORT
00872     case EPROTONOSUPPORT:
00873       return DBUS_ERROR_NOT_SUPPORTED;
00874 #endif
00875 #ifdef EAFNOSUPPORT
00876     case EAFNOSUPPORT:
00877       return DBUS_ERROR_NOT_SUPPORTED;
00878 #endif
00879 #ifdef ENFILE
00880     case ENFILE:
00881       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
00882 #endif
00883 #ifdef EMFILE
00884     case EMFILE:
00885       return DBUS_ERROR_LIMITS_EXCEEDED;
00886 #endif
00887 #ifdef EACCES
00888     case EACCES:
00889       return DBUS_ERROR_ACCESS_DENIED;
00890 #endif
00891 #ifdef EPERM
00892     case EPERM:
00893       return DBUS_ERROR_ACCESS_DENIED;
00894 #endif
00895 #ifdef ENOBUFS
00896     case ENOBUFS:
00897       return DBUS_ERROR_NO_MEMORY;
00898 #endif
00899 #ifdef ENOMEM
00900     case ENOMEM:
00901       return DBUS_ERROR_NO_MEMORY;
00902 #endif
00903 #ifdef EINVAL
00904     case EINVAL:
00905       return DBUS_ERROR_FAILED;
00906 #endif
00907 #ifdef EBADF
00908     case EBADF:
00909       return DBUS_ERROR_FAILED;
00910 #endif
00911 #ifdef EFAULT
00912     case EFAULT:
00913       return DBUS_ERROR_FAILED;
00914 #endif
00915 #ifdef ENOTSOCK
00916     case ENOTSOCK:
00917       return DBUS_ERROR_FAILED;
00918 #endif
00919 #ifdef EISCONN
00920     case EISCONN:
00921       return DBUS_ERROR_FAILED;
00922 #endif
00923 #ifdef ECONNREFUSED
00924     case ECONNREFUSED:
00925       return DBUS_ERROR_NO_SERVER;
00926 #endif
00927 #ifdef ETIMEDOUT
00928     case ETIMEDOUT:
00929       return DBUS_ERROR_TIMEOUT;
00930 #endif
00931 #ifdef ENETUNREACH
00932     case ENETUNREACH:
00933       return DBUS_ERROR_NO_NETWORK;
00934 #endif
00935 #ifdef EADDRINUSE
00936     case EADDRINUSE:
00937       return DBUS_ERROR_ADDRESS_IN_USE;
00938 #endif
00939 #ifdef EEXIST
00940     case EEXIST:
00941       return DBUS_ERROR_FILE_EXISTS;
00942 #endif
00943 #ifdef ENOENT
00944     case ENOENT:
00945       return DBUS_ERROR_FILE_NOT_FOUND;
00946 #endif
00947     }
00948 
00949   return DBUS_ERROR_FAILED;
00950 }
00951 
00954 /* tests in dbus-sysdeps-util.c */

Generated on Wed Nov 7 15:11:42 2012 for D-Bus by  doxygen 1.5.1