LCOV - code coverage report
Current view: top level - libsystemd/sd-id128 - sd-id128.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 86 98 87.8 %
Date: 2015-07-29 18:47:03 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2011 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <fcntl.h>
      24             : #include <unistd.h>
      25             : 
      26             : #include "util.h"
      27             : #include "macro.h"
      28             : #include "sd-id128.h"
      29             : #include "random-util.h"
      30             : 
      31        1181 : _public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
      32             :         unsigned n;
      33             : 
      34        1181 :         assert_return(s, NULL);
      35             : 
      36       20077 :         for (n = 0; n < 16; n++) {
      37       18896 :                 s[n*2] = hexchar(id.bytes[n] >> 4);
      38       18896 :                 s[n*2+1] = hexchar(id.bytes[n] & 0xF);
      39             :         }
      40             : 
      41        1181 :         s[32] = 0;
      42             : 
      43        1181 :         return s;
      44             : }
      45             : 
      46        1528 : _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
      47             :         unsigned n, i;
      48             :         sd_id128_t t;
      49        1528 :         bool is_guid = false;
      50             : 
      51        1528 :         assert_return(s, -EINVAL);
      52        1528 :         assert_return(ret, -EINVAL);
      53             : 
      54       20710 :         for (n = 0, i = 0; n < 16;) {
      55             :                 int a, b;
      56             : 
      57       18080 :                 if (s[i] == '-') {
      58             :                         /* Is this a GUID? Then be nice, and skip over
      59             :                          * the dashes */
      60             : 
      61          16 :                         if (i == 8)
      62           4 :                                 is_guid = true;
      63          12 :                         else if (i == 13 || i == 18 || i == 23) {
      64          22 :                                 if (!is_guid)
      65           0 :                                         return -EINVAL;
      66             :                         } else
      67           1 :                                 return -EINVAL;
      68             : 
      69          15 :                         i++;
      70          15 :                         continue;
      71             :                 }
      72             : 
      73       18064 :                 a = unhexchar(s[i++]);
      74       18064 :                 if (a < 0)
      75         425 :                         return -EINVAL;
      76             : 
      77       17639 :                 b = unhexchar(s[i++]);
      78       17639 :                 if (b < 0)
      79           0 :                         return -EINVAL;
      80             : 
      81       17639 :                 t.bytes[n++] = (a << 4) | b;
      82             :         }
      83             : 
      84        1102 :         if (i != (is_guid ? 36 : 32))
      85           1 :                 return -EINVAL;
      86             : 
      87        1101 :         if (s[i] != 0)
      88           2 :                 return -EINVAL;
      89             : 
      90        1099 :         *ret = t;
      91        1099 :         return 0;
      92             : }
      93             : 
      94          27 : static sd_id128_t make_v4_uuid(sd_id128_t id) {
      95             :         /* Stolen from generate_random_uuid() of drivers/char/random.c
      96             :          * in the kernel sources */
      97             : 
      98             :         /* Set UUID version to 4 --- truly random generation */
      99          27 :         id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
     100             : 
     101             :         /* Set the UUID variant to DCE */
     102          27 :         id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
     103             : 
     104          27 :         return id;
     105             : }
     106             : 
     107         143 : _public_ int sd_id128_get_machine(sd_id128_t *ret) {
     108             :         static thread_local sd_id128_t saved_machine_id;
     109             :         static thread_local bool saved_machine_id_valid = false;
     110         286 :         _cleanup_close_ int fd = -1;
     111             :         char buf[33];
     112             :         unsigned j;
     113             :         sd_id128_t t;
     114             :         int r;
     115             : 
     116         143 :         assert_return(ret, -EINVAL);
     117             : 
     118         143 :         if (saved_machine_id_valid) {
     119         129 :                 *ret = saved_machine_id;
     120         129 :                 return 0;
     121             :         }
     122             : 
     123          14 :         fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
     124          14 :         if (fd < 0)
     125           0 :                 return -errno;
     126             : 
     127          14 :         r = loop_read_exact(fd, buf, 33, false);
     128          14 :         if (r < 0)
     129           0 :                 return r;
     130          14 :         if (buf[32] !='\n')
     131           0 :                 return -EIO;
     132             : 
     133         238 :         for (j = 0; j < 16; j++) {
     134             :                 int a, b;
     135             : 
     136         224 :                 a = unhexchar(buf[j*2]);
     137         224 :                 b = unhexchar(buf[j*2+1]);
     138             : 
     139         224 :                 if (a < 0 || b < 0)
     140           0 :                         return -EIO;
     141             : 
     142         224 :                 t.bytes[j] = a << 4 | b;
     143             :         }
     144             : 
     145          14 :         saved_machine_id = t;
     146          14 :         saved_machine_id_valid = true;
     147             : 
     148          14 :         *ret = t;
     149          14 :         return 0;
     150             : }
     151             : 
     152          39 : _public_ int sd_id128_get_boot(sd_id128_t *ret) {
     153             :         static thread_local sd_id128_t saved_boot_id;
     154             :         static thread_local bool saved_boot_id_valid = false;
     155          78 :         _cleanup_close_ int fd = -1;
     156             :         char buf[36];
     157             :         unsigned j;
     158             :         sd_id128_t t;
     159             :         char *p;
     160             :         int r;
     161             : 
     162          39 :         assert_return(ret, -EINVAL);
     163             : 
     164          39 :         if (saved_boot_id_valid) {
     165          23 :                 *ret = saved_boot_id;
     166          23 :                 return 0;
     167             :         }
     168             : 
     169          16 :         fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
     170          16 :         if (fd < 0)
     171           0 :                 return -errno;
     172             : 
     173          16 :         r = loop_read_exact(fd, buf, 36, false);
     174          16 :         if (r < 0)
     175           0 :                 return r;
     176             : 
     177         272 :         for (j = 0, p = buf; j < 16; j++) {
     178             :                 int a, b;
     179             : 
     180         256 :                 if (p >= buf + 35)
     181           0 :                         return -EIO;
     182             : 
     183         256 :                 if (*p == '-') {
     184          64 :                         p++;
     185          64 :                         if (p >= buf + 35)
     186           0 :                                 return -EIO;
     187             :                 }
     188             : 
     189         256 :                 a = unhexchar(p[0]);
     190         256 :                 b = unhexchar(p[1]);
     191             : 
     192         256 :                 if (a < 0 || b < 0)
     193           0 :                         return -EIO;
     194             : 
     195         256 :                 t.bytes[j] = a << 4 | b;
     196             : 
     197         256 :                 p += 2;
     198             :         }
     199             : 
     200          16 :         saved_boot_id = t;
     201          16 :         saved_boot_id_valid = true;
     202             : 
     203          16 :         *ret = t;
     204          16 :         return 0;
     205             : }
     206             : 
     207          27 : _public_ int sd_id128_randomize(sd_id128_t *ret) {
     208             :         sd_id128_t t;
     209             :         int r;
     210             : 
     211          27 :         assert_return(ret, -EINVAL);
     212             : 
     213          27 :         r = dev_urandom(&t, sizeof(t));
     214          27 :         if (r < 0)
     215           0 :                 return r;
     216             : 
     217             :         /* Turn this into a valid v4 UUID, to be nice. Note that we
     218             :          * only guarantee this for newly generated UUIDs, not for
     219             :          * pre-existing ones. */
     220             : 
     221          27 :         *ret = make_v4_uuid(t);
     222          27 :         return 0;
     223             : }

Generated by: LCOV version 1.11