root/replace/uuid_parse.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uuid_pack
  2. uuid_unpack
  3. uuid_clear
  4. uuid_compare
  5. uuid_copy
  6. uuid_is_null
  7. uuid_parse
  8. uuid_unparse
  9. get_random_fd
  10. get_random_bytes
  11. get_node_id
  12. get_clock
  13. uuid_generate_random
  14. uuid_generate_time
  15. uuid_generate

   1 /*
   2  * uuid: emulation of e2fsprogs interface if implementation lacking.
   3  *
   4  * This 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  * 
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  *
  18  * Original uuid implementation: copyright (C) Theodore Ts'o
  19  *
  20  * This importation into heartbeat:
  21  *      Copyright (C) 2004 David Lee <t.d.lee@durham.ac.uk>
  22  *
  23  */
  24 
  25 #include <crm_internal.h>
  26 #include <stdio.h>
  27 #ifdef HAVE_UNISTD_H
  28 #  include <unistd.h>
  29 #endif
  30 #ifdef HAVE_STDLIB_H
  31 #  include <stdlib.h>
  32 #endif
  33 #include <string.h>
  34 #include <ctype.h>
  35 
  36 #include <replace_uuid.h>
  37 
  38 /*
  39  * Local "replace" implementation of uuid functions.
  40  */
  41 
  42 #include <sys/types.h>
  43 #include <sys/time.h>
  44 #include <time.h>
  45 
  46 /* UUID Variant definitions */
  47 #define UUID_VARIANT_NCS        0
  48 #define UUID_VARIANT_DCE        1
  49 #define UUID_VARIANT_MICROSOFT  2
  50 #define UUID_VARIANT_OTHER      3
  51 
  52 /* UUID Type definitions */
  53 #define UUID_TYPE_DCE_TIME      1
  54 #define UUID_TYPE_DCE_RANDOM    4
  55 
  56 /* For uuid_compare() */
  57 #define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
  58 
  59 /************************************
  60  * Private types
  61  ************************************/
  62 
  63 #define longlong long long
  64 
  65 /*
  66  * Offset between 15-Oct-1582 and 1-Jan-70
  67  */
  68 #define TIME_OFFSET_HIGH 0x01B21DD2
  69 #define TIME_OFFSET_LOW  0x13814000
  70 
  71 #if (SIZEOF_INT == 4)
  72 typedef unsigned int __u32;
  73 #elif (SIZEOF_LONG == 4)
  74 typedef unsigned long __u32;
  75 #endif
  76 
  77 #if (SIZEOF_INT == 2)
  78 typedef int __s16;
  79 typedef unsigned int __u16;
  80 #elif (SIZEOF_SHORT == 2)
  81 typedef short __s16;
  82 typedef unsigned short __u16;
  83 #endif
  84 
  85 typedef unsigned char __u8;
  86 
  87 struct uuid {
  88     __u32 time_low;
  89     __u16 time_mid;
  90     __u16 time_hi_and_version;
  91     __u16 clock_seq;
  92     __u8 node[6];
  93 };
  94 
  95 /************************************
  96  * internal routines
  97  ************************************/
  98 static void
  99 uuid_pack(const struct uuid *uu, uuid_t ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101     __u32 tmp;
 102     unsigned char *out = ptr;
 103 
 104     tmp = uu->time_low;
 105     out[3] = (unsigned char)tmp;
 106     tmp >>= 8;
 107     out[2] = (unsigned char)tmp;
 108     tmp >>= 8;
 109     out[1] = (unsigned char)tmp;
 110     tmp >>= 8;
 111     out[0] = (unsigned char)tmp;
 112 
 113     tmp = uu->time_mid;
 114     out[5] = (unsigned char)tmp;
 115     tmp >>= 8;
 116     out[4] = (unsigned char)tmp;
 117 
 118     tmp = uu->time_hi_and_version;
 119     out[7] = (unsigned char)tmp;
 120     tmp >>= 8;
 121     out[6] = (unsigned char)tmp;
 122 
 123     tmp = uu->clock_seq;
 124     out[9] = (unsigned char)tmp;
 125     tmp >>= 8;
 126     out[8] = (unsigned char)tmp;
 127 
 128     memcpy(out + 10, uu->node, 6);
 129 }
 130 
 131 static void
 132 uuid_unpack(const uuid_t in, struct uuid *uu)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     const __u8 *ptr = in;
 135     __u32 tmp;
 136 
 137     tmp = *ptr++;
 138     tmp = (tmp << 8) | *ptr++;
 139     tmp = (tmp << 8) | *ptr++;
 140     tmp = (tmp << 8) | *ptr++;
 141     uu->time_low = tmp;
 142 
 143     tmp = *ptr++;
 144     tmp = (tmp << 8) | *ptr++;
 145     uu->time_mid = tmp;
 146 
 147     tmp = *ptr++;
 148     tmp = (tmp << 8) | *ptr++;
 149     uu->time_hi_and_version = tmp;
 150 
 151     tmp = *ptr++;
 152     tmp = (tmp << 8) | *ptr++;
 153     uu->clock_seq = tmp;
 154 
 155     memcpy(uu->node, ptr, 6);
 156 }
 157 
 158 /************************************
 159  * Main routines, except uuid_generate*()
 160  ************************************/
 161 void
 162 uuid_clear(uuid_t uu)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164     memset(uu, 0, 16);
 165 }
 166 
 167 int
 168 uuid_compare(const uuid_t uu1, const uuid_t uu2)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170     struct uuid uuid1, uuid2;
 171 
 172     uuid_unpack(uu1, &uuid1);
 173     uuid_unpack(uu2, &uuid2);
 174 
 175     UUCMP(uuid1.time_low, uuid2.time_low);
 176     UUCMP(uuid1.time_mid, uuid2.time_mid);
 177     UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
 178     UUCMP(uuid1.clock_seq, uuid2.clock_seq);
 179     return memcmp(uuid1.node, uuid2.node, 6);
 180 }
 181 
 182 void
 183 uuid_copy(uuid_t dst, const uuid_t src)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185     unsigned char *cp1;
 186     const unsigned char *cp2;
 187     int i;
 188 
 189     for (i = 0, cp1 = dst, cp2 = src; i < 16; i++)
 190         *cp1++ = *cp2++;
 191 }
 192 
 193 /* if uu is the null uuid, return 1 else 0 */
 194 int
 195 uuid_is_null(const uuid_t uu)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197     const unsigned char *cp;
 198     int i;
 199 
 200     for (i = 0, cp = uu; i < 16; i++)
 201         if (*cp++)
 202             return 0;
 203     return 1;
 204 }
 205 
 206 /* 36byte-string=>uuid */
 207 int
 208 uuid_parse(const char *in, uuid_t uu)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     struct uuid uuid;
 211     int i;
 212     const char *cp;
 213     char buf[3];
 214 
 215     if (strlen(in) != 36)
 216         return -1;
 217     for (i = 0, cp = in; i <= 36; i++, cp++) {
 218         if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
 219             if (*cp == '-')
 220                 continue;
 221             else
 222                 return -1;
 223         }
 224         if (i == 36)
 225             if (*cp == 0)
 226                 continue;
 227         if (!isxdigit((int)*cp))
 228             return -1;
 229     }
 230     uuid.time_low = strtoul(in, NULL, 16);
 231     uuid.time_mid = strtoul(in + 9, NULL, 16);
 232     uuid.time_hi_and_version = strtoul(in + 14, NULL, 16);
 233     uuid.clock_seq = strtoul(in + 19, NULL, 16);
 234     cp = in + 24;
 235     buf[2] = 0;
 236     for (i = 0; i < 6; i++) {
 237         buf[0] = *cp++;
 238         buf[1] = *cp++;
 239         uuid.node[i] = strtoul(buf, NULL, 16);
 240     }
 241 
 242     uuid_pack(&uuid, uu);
 243     return 0;
 244 }
 245 
 246 /* uuid=>36byte-string-with-null */
 247 void
 248 uuid_unparse(const uuid_t uu, char *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250     struct uuid uuid;
 251 
 252     uuid_unpack(uu, &uuid);
 253     sprintf(out,
 254             "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
 255             uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
 256             uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
 257             uuid.node[0], uuid.node[1], uuid.node[2], uuid.node[3], uuid.node[4], uuid.node[5]);
 258 }
 259 
 260 /************************************
 261  * Main routines: uuid_generate*()
 262  ************************************/
 263 
 264 #include <fcntl.h>
 265 #include <sys/types.h>
 266 #include <sys/stat.h>
 267 
 268 #ifdef HAVE_SYS_IOCTL_H
 269 #  include <sys/ioctl.h>
 270 #endif
 271 #ifdef HAVE_SYS_SOCKET_H
 272 #  include <sys/socket.h>
 273 #endif
 274 #ifdef HAVE_SYS_SOCKIO_H
 275 #  include <sys/sockio.h>
 276 #endif
 277 #ifdef HAVE_NET_IF_H
 278 #  include <net/if.h>
 279 #endif
 280 #ifdef HAVE_NETINET_IN_H
 281 #  include <netinet/in.h>
 282 #endif
 283 
 284 #ifdef HAVE_SRANDOM
 285 #  define srand(x)      srandom(x)
 286 #  define rand()                random()
 287 #endif
 288 
 289 static int
 290 get_random_fd(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292     struct timeval tv;
 293     static int fd = -2;
 294     int i;
 295 
 296     if (fd == -2) {
 297         gettimeofday(&tv, 0);
 298         fd = open("/dev/urandom", O_RDONLY);
 299         if (fd == -1)
 300             fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
 301         srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
 302     }
 303     /* Crank the random number generator a few times */
 304     gettimeofday(&tv, 0);
 305     for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
 306         rand();
 307     return fd;
 308 }
 309 
 310 /*
 311  * Generate a series of random bytes.  Use /dev/urandom if possible,
 312  * and if not, use srandom/random.
 313  */
 314 static void
 315 get_random_bytes(void *buf, int nbytes)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317     int i, n = nbytes, fd = get_random_fd();
 318     int lose_counter = 0;
 319     unsigned char *cp = (unsigned char *)buf;
 320 
 321     if (fd >= 0) {
 322         while (n > 0) {
 323             i = read(fd, cp, n);
 324             if (i <= 0) {
 325                 if (lose_counter++ > 16)
 326                     break;
 327                 continue;
 328             }
 329             n -= i;
 330             cp += i;
 331             lose_counter = 0;
 332         }
 333     }
 334 
 335     /*
 336      * We do this all the time, but this is the only source of
 337      * randomness if /dev/random/urandom is out to lunch.
 338      */
 339     for (cp = buf, i = 0; i < nbytes; i++)
 340         *cp++ ^= (rand() >> 7) & 0xFF;
 341     return;
 342 }
 343 
 344 /*
 345  * Get the ethernet hardware address, if we can find it...
 346  */
 347 static int
 348 get_node_id(unsigned char *node_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {
 350 #ifdef HAVE_NET_IF_H
 351     int sd;
 352     struct ifreq ifr, *ifrp;
 353     struct ifconf ifc;
 354     char buf[1024];
 355     int n, i;
 356     unsigned char *a;
 357 
 358 /*
 359  * BSD 4.4 defines the size of an ifreq to be
 360  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
 361  * However, under earlier systems, sa_len isn't present, so the size is 
 362  * just sizeof(struct ifreq)
 363  */
 364 #  ifdef HAVE_SA_LEN
 365 #    ifndef max
 366 #      define max(a,b) ((a) > (b) ? (a) : (b))
 367 #    endif
 368 #    define ifreq_size(i) max(sizeof(struct ifreq),\
 369      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
 370 #  else
 371 #    define ifreq_size(i) sizeof(struct ifreq)
 372 #  endif                        /* HAVE_SA_LEN */
 373 
 374     sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 375     if (sd < 0) {
 376         return -1;
 377     }
 378     memset(buf, 0, sizeof(buf));
 379     ifc.ifc_len = sizeof(buf);
 380     ifc.ifc_buf = buf;
 381     if (ioctl(sd, SIOCGIFCONF, (char *)&ifc) < 0) {
 382         close(sd);
 383         return -1;
 384     }
 385     n = ifc.ifc_len;
 386     for (i = 0; i < n; i += ifreq_size(*ifr)) {
 387         ifrp = (struct ifreq *)((char *)ifc.ifc_buf + i);
 388         strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
 389 #  ifdef SIOCGIFHWADDR
 390         if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
 391             continue;
 392         a = (unsigned char *)&ifr.ifr_hwaddr.sa_data;
 393 #  else
 394 #    ifdef SIOCGENADDR
 395         if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
 396             continue;
 397         a = (unsigned char *)ifr.ifr_enaddr;
 398 #    else
 399         /*
 400          * XXX we don't have a way of getting the hardware
 401          * address
 402          */
 403         close(sd);
 404         return 0;
 405 #    endif                      /* SIOCGENADDR */
 406 #  endif                        /* SIOCGIFHWADDR */
 407         if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
 408             continue;
 409         if (node_id) {
 410             memcpy(node_id, a, 6);
 411             close(sd);
 412             return 1;
 413         }
 414     }
 415     close(sd);
 416 #endif
 417     return 0;
 418 }
 419 
 420 /* Assume that the gettimeofday() has microsecond granularity */
 421 #define MAX_ADJUSTMENT 10
 422 
 423 static int
 424 get_clock(__u32 * clock_high, __u32 * clock_low, __u16 * ret_clock_seq)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426     static int adjustment = 0;
 427     static struct timeval last = { 0, 0 };
 428     static __u16 clock_seq;
 429     struct timeval tv;
 430     unsigned longlong clock_reg;
 431 
 432   try_again:
 433     gettimeofday(&tv, 0);
 434     if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
 435         get_random_bytes(&clock_seq, sizeof(clock_seq));
 436         clock_seq &= 0x1FFF;
 437         last = tv;
 438         last.tv_sec--;
 439     }
 440     if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) {
 441         clock_seq = (clock_seq + 1) & 0x1FFF;
 442         adjustment = 0;
 443         last = tv;
 444     } else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) {
 445         if (adjustment >= MAX_ADJUSTMENT)
 446             goto try_again;
 447         adjustment++;
 448     } else {
 449         adjustment = 0;
 450         last = tv;
 451     }
 452 
 453     clock_reg = tv.tv_usec * 10 + adjustment;
 454     clock_reg += ((unsigned longlong)tv.tv_sec) * 10000000;
 455     clock_reg += (((unsigned longlong)0x01B21DD2) << 32) + 0x13814000;
 456 
 457     *clock_high = clock_reg >> 32;
 458     *clock_low = clock_reg;
 459     *ret_clock_seq = clock_seq;
 460     return 0;
 461 }
 462 
 463 /* create a new uuid, based on randomness */
 464 void
 465 uuid_generate_random(uuid_t out)
     /* [previous][next][first][last][top][bottom][index][help] */
 466 {
 467     uuid_t buf;
 468     struct uuid uu;
 469 
 470     get_random_bytes(buf, sizeof(buf));
 471     uuid_unpack(buf, &uu);
 472 
 473     uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
 474     uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
 475     uuid_pack(&uu, out);
 476 }
 477 
 478 /* create a new uuid, based on time */
 479 static void
 480 uuid_generate_time(uuid_t out)
     /* [previous][next][first][last][top][bottom][index][help] */
 481 {
 482     static unsigned char node_id[6];
 483     static int has_init = 0;
 484     struct uuid uu;
 485     __u32 clock_mid;
 486 
 487     if (!has_init) {
 488         if (get_node_id(node_id) <= 0) {
 489             get_random_bytes(node_id, 6);
 490             /*
 491              * Set multicast bit, to prevent conflicts
 492              * with IEEE 802 addresses obtained from
 493              * network cards
 494              */
 495             node_id[0] |= 0x80;
 496         }
 497         has_init = 1;
 498     }
 499     get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
 500     uu.clock_seq |= 0x8000;
 501     uu.time_mid = (__u16) clock_mid;
 502     uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
 503     memcpy(uu.node, node_id, 6);
 504     uuid_pack(&uu, out);
 505 }
 506 
 507 void
 508 uuid_generate(uuid_t out)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510     if (get_random_fd() >= 0) {
 511         uuid_generate_random(out);
 512     } else {
 513         uuid_generate_time(out);
 514     }
 515 }

/* [previous][next][first][last][top][bottom][index][help] */