]>
git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/uuid/gen_uuid.c
2 * gen_uuid.c --- generate a DCE-compatible uuid
4 * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, and the entire permission notice in its entirety,
12 * including the disclaimer of warranties.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
23 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
36 * Force inclusion of SVID stuff since we need it if we're compiling in
42 #define _WIN32_WINNT 0x0500
56 #include <sys/types.h>
57 #ifdef HAVE_SYS_TIME_H
62 #ifdef HAVE_SYS_FILE_H
65 #ifdef HAVE_SYS_IOCTL_H
66 #include <sys/ioctl.h>
68 #ifdef HAVE_SYS_SOCKET_H
69 #include <sys/socket.h>
74 #ifdef HAVE_SYS_SOCKIO_H
75 #include <sys/sockio.h>
80 #ifdef HAVE_NETINET_IN_H
81 #include <netinet/in.h>
83 #ifdef HAVE_NET_IF_DL_H
84 #include <net/if_dl.h>
86 #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
87 #include <sys/syscall.h>
94 #define srand(x) srandom(x)
95 #define rand() random()
99 #define THREAD_LOCAL static TLS
101 #define THREAD_LOCAL static
104 #if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
106 THREAD_LOCAL
unsigned short jrand_seed
[3];
110 static void gettimeofday (struct timeval
*tv
, void *dummy
)
115 GetSystemTimeAsFileTime (&ftime
);
116 n
= (((uint64_t) ftime
.dwHighDateTime
<< 32)
117 + (uint64_t) ftime
.dwLowDateTime
);
120 n
-= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
123 tv
->tv_sec
= n
/ 1000000;
124 tv
->tv_usec
= n
% 1000000;
127 static int getuid (void)
133 static int get_random_fd(void)
140 gettimeofday(&tv
, 0);
142 fd
= open("/dev/urandom", O_RDONLY
);
144 fd
= open("/dev/random", O_RDONLY
| O_NONBLOCK
);
146 i
= fcntl(fd
, F_GETFD
);
148 fcntl(fd
, F_SETFD
, i
| FD_CLOEXEC
);
151 srand((getpid() << 16) ^ getuid() ^ tv
.tv_sec
^ tv
.tv_usec
);
153 jrand_seed
[0] = getpid() ^ (tv
.tv_sec
& 0xFFFF);
154 jrand_seed
[1] = getppid() ^ (tv
.tv_usec
& 0xFFFF);
155 jrand_seed
[2] = (tv
.tv_sec
^ tv
.tv_usec
) >> 16;
158 /* Crank the random number generator a few times */
159 gettimeofday(&tv
, 0);
160 for (i
= (tv
.tv_sec
^ tv
.tv_usec
) & 0x1F; i
> 0; i
--)
167 * Generate a series of random bytes. Use /dev/urandom if possible,
168 * and if not, use srandom/random.
170 static void get_random_bytes(void *buf
, int nbytes
)
172 int i
, n
= nbytes
, fd
= get_random_fd();
173 int lose_counter
= 0;
174 unsigned char *cp
= (unsigned char *) buf
;
175 unsigned short tmp_seed
[3];
181 if (lose_counter
++ > 16)
192 * We do this all the time, but this is the only source of
193 * randomness if /dev/random/urandom is out to lunch.
195 for (cp
= buf
, i
= 0; i
< nbytes
; i
++)
196 *cp
++ ^= (rand() >> 7) & 0xFF;
198 memcpy(tmp_seed
, jrand_seed
, sizeof(tmp_seed
));
199 jrand_seed
[2] = jrand_seed
[2] ^ syscall(__NR_gettid
);
200 for (cp
= buf
, i
= 0; i
< nbytes
; i
++)
201 *cp
++ ^= (jrand48(tmp_seed
) >> 7) & 0xFF;
202 memcpy(jrand_seed
, tmp_seed
,
203 sizeof(jrand_seed
)-sizeof(unsigned short));
210 * Get the ethernet hardware address, if we can find it...
212 * XXX for a windows version, probably should use GetAdaptersInfo:
213 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
214 * commenting out get_node_id just to get gen_uuid to compile under windows
215 * is not the right way to go!
217 static int get_node_id(unsigned char *node_id
)
221 struct ifreq ifr
, *ifrp
;
226 #ifdef HAVE_NET_IF_DL_H
227 struct sockaddr_dl
*sdlp
;
231 * BSD 4.4 defines the size of an ifreq to be
232 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
233 * However, under earlier systems, sa_len isn't present, so the size is
234 * just sizeof(struct ifreq)
238 #define max(a,b) ((a) > (b) ? (a) : (b))
240 #define ifreq_size(i) max(sizeof(struct ifreq),\
241 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
243 #define ifreq_size(i) sizeof(struct ifreq)
244 #endif /* HAVE_SA_LEN*/
246 sd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
250 memset(buf
, 0, sizeof(buf
));
251 ifc
.ifc_len
= sizeof(buf
);
253 if (ioctl (sd
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
258 for (i
= 0; i
< n
; i
+= ifreq_size(*ifrp
) ) {
259 ifrp
= (struct ifreq
*)((char *) ifc
.ifc_buf
+i
);
260 strncpy(ifr
.ifr_name
, ifrp
->ifr_name
, IFNAMSIZ
);
262 if (ioctl(sd
, SIOCGIFHWADDR
, &ifr
) < 0)
264 a
= (unsigned char *) &ifr
.ifr_hwaddr
.sa_data
;
267 if (ioctl(sd
, SIOCGENADDR
, &ifr
) < 0)
269 a
= (unsigned char *) ifr
.ifr_enaddr
;
271 #ifdef HAVE_NET_IF_DL_H
272 sdlp
= (struct sockaddr_dl
*) &ifrp
->ifr_addr
;
273 if ((sdlp
->sdl_family
!= AF_LINK
) || (sdlp
->sdl_alen
!= 6))
275 a
= (unsigned char *) &sdlp
->sdl_data
[sdlp
->sdl_nlen
];
278 * XXX we don't have a way of getting the hardware
283 #endif /* HAVE_NET_IF_DL_H */
284 #endif /* SIOCGENADDR */
285 #endif /* SIOCGIFHWADDR */
286 if (!a
[0] && !a
[1] && !a
[2] && !a
[3] && !a
[4] && !a
[5])
289 memcpy(node_id
, a
, 6);
299 /* Assume that the gettimeofday() has microsecond granularity */
300 #define MAX_ADJUSTMENT 10
302 static int get_clock(uint32_t *clock_high
, uint32_t *clock_low
,
303 uint16_t *ret_clock_seq
, int *num
)
305 THREAD_LOCAL
int adjustment
= 0;
306 THREAD_LOCAL
struct timeval last
= {0, 0};
307 THREAD_LOCAL
int state_fd
= -2;
308 THREAD_LOCAL
FILE *state_f
;
309 THREAD_LOCAL
uint16_t clock_seq
;
315 if (state_fd
== -2) {
316 save_umask
= umask(0);
317 state_fd
= open("/var/lib/libuuid/clock.txt",
318 O_RDWR
|O_CREAT
, 0660);
319 (void) umask(save_umask
);
320 state_f
= fdopen(state_fd
, "r+");
327 fl
.l_whence
= SEEK_SET
;
333 while (fcntl(state_fd
, F_SETLKW
, &fl
) < 0) {
334 if ((errno
== EAGAIN
) || (errno
== EINTR
))
344 unsigned long tv1
, tv2
;
347 if (fscanf(state_f
, "clock: %04x tv: %lu %lu adj: %d\n",
348 &cl
, &tv1
, &tv2
, &a
) == 4) {
349 clock_seq
= cl
& 0x3FFF;
356 if ((last
.tv_sec
== 0) && (last
.tv_usec
== 0)) {
357 get_random_bytes(&clock_seq
, sizeof(clock_seq
));
359 gettimeofday(&last
, 0);
364 gettimeofday(&tv
, 0);
365 if ((tv
.tv_sec
< last
.tv_sec
) ||
366 ((tv
.tv_sec
== last
.tv_sec
) &&
367 (tv
.tv_usec
< last
.tv_usec
))) {
368 clock_seq
= (clock_seq
+1) & 0x3FFF;
371 } else if ((tv
.tv_sec
== last
.tv_sec
) &&
372 (tv
.tv_usec
== last
.tv_usec
)) {
373 if (adjustment
>= MAX_ADJUSTMENT
)
381 clock_reg
= tv
.tv_usec
*10 + adjustment
;
382 clock_reg
+= ((uint64_t) tv
.tv_sec
)*10000000;
383 clock_reg
+= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
385 if (num
&& (*num
> 1)) {
386 adjustment
+= *num
- 1;
387 last
.tv_usec
+= adjustment
/ 10;
388 adjustment
= adjustment
% 10;
389 last
.tv_sec
+= last
.tv_usec
/ 1000000;
390 last
.tv_usec
= last
.tv_usec
% 1000000;
395 ftruncate(state_fd
, 0);
396 fprintf(state_f
, "clock: %04x tv: %lu %lu adj: %d\n",
397 clock_seq
, last
.tv_sec
, last
.tv_usec
, adjustment
);
401 fcntl(state_fd
, F_SETLK
, &fl
);
404 *clock_high
= clock_reg
>> 32;
405 *clock_low
= clock_reg
;
406 *ret_clock_seq
= clock_seq
;
410 static ssize_t
read_all(int fd
, char *buf
, size_t count
)
415 memset(buf
, 0, count
);
417 ret
= read(fd
, buf
, count
);
419 if ((errno
== EAGAIN
) || (errno
== EINTR
))
432 * Try using the uuidd daemon to generate the UUID
434 * Returns 0 on success, non-zero on failure.
436 static int get_uuid_via_daemon(int op
, uuid_t out
, int *num
)
438 #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H)
443 int32_t reply_len
= 0, expected
= 16;
444 struct sockaddr_un srv_addr
;
446 static const char *uuidd_path
= UUIDD_PATH
;
447 static int access_ret
= -2;
448 static int start_attempts
= 0;
450 if ((s
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0)
453 srv_addr
.sun_family
= AF_UNIX
;
454 strcpy(srv_addr
.sun_path
, UUIDD_SOCKET_PATH
);
456 if (connect(s
, (const struct sockaddr
*) &srv_addr
,
457 sizeof(struct sockaddr_un
)) < 0) {
458 if (access_ret
== -2)
459 access_ret
= access(uuidd_path
, X_OK
);
460 if (access_ret
== 0 && start_attempts
++ < 5) {
461 if ((pid
= fork()) == 0) {
462 execl(uuidd_path
, "uuidd", "-qT", "300",
466 (void) waitpid(pid
, 0, 0);
467 if (connect(s
, (const struct sockaddr
*) &srv_addr
,
468 sizeof(struct sockaddr_un
)) < 0)
475 if (op
== UUIDD_OP_BULK_TIME_UUID
) {
476 memcpy(op_buf
+1, num
, sizeof(*num
));
477 op_len
+= sizeof(*num
);
478 expected
+= sizeof(*num
);
481 ret
= write(s
, op_buf
, op_len
);
485 ret
= read_all(s
, (char *) &reply_len
, sizeof(reply_len
));
489 if (reply_len
!= expected
)
492 ret
= read_all(s
, op_buf
, reply_len
);
494 if (op
== UUIDD_OP_BULK_TIME_UUID
)
495 memcpy(op_buf
+16, num
, sizeof(int));
497 memcpy(out
, op_buf
, 16);
500 return ((ret
== expected
) ? 0 : -1);
508 void uuid__generate_time(uuid_t out
, int *num
)
510 static unsigned char node_id
[6];
511 static int has_init
= 0;
516 if (get_node_id(node_id
) <= 0) {
517 get_random_bytes(node_id
, 6);
519 * Set multicast bit, to prevent conflicts
520 * with IEEE 802 addresses obtained from
527 get_clock(&clock_mid
, &uu
.time_low
, &uu
.clock_seq
, num
);
528 uu
.clock_seq
|= 0x8000;
529 uu
.time_mid
= (uint16_t) clock_mid
;
530 uu
.time_hi_and_version
= ((clock_mid
>> 16) & 0x0FFF) | 0x1000;
531 memcpy(uu
.node
, node_id
, 6);
535 void uuid_generate_time(uuid_t out
)
538 THREAD_LOCAL
int num
= 0;
539 THREAD_LOCAL
struct uuid uu
;
540 THREAD_LOCAL
time_t last_time
= 0;
545 if (now
> last_time
+1)
550 if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID
,
553 uuid_unpack(out
, &uu
);
561 if (uu
.time_low
== 0) {
563 if (uu
.time_mid
== 0)
564 uu
.time_hi_and_version
++;
571 if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID
, out
, 0) == 0)
575 uuid__generate_time(out
, 0);
579 void uuid__generate_random(uuid_t out
, int *num
)
590 for (i
= 0; i
< n
; i
++) {
591 get_random_bytes(buf
, sizeof(buf
));
592 uuid_unpack(buf
, &uu
);
594 uu
.clock_seq
= (uu
.clock_seq
& 0x3FFF) | 0x8000;
595 uu
.time_hi_and_version
= (uu
.time_hi_and_version
& 0x0FFF)
598 out
+= sizeof(uuid_t
);
602 void uuid_generate_random(uuid_t out
)
605 /* No real reason to use the daemon for random uuid's -- yet */
607 uuid__generate_random(out
, &num
);
612 * This is the generic front-end to uuid_generate_random and
613 * uuid_generate_time. It uses uuid_generate_random only if
614 * /dev/urandom is available, since otherwise we won't have
615 * high-quality randomness.
617 void uuid_generate(uuid_t out
)
619 if (get_random_fd() >= 0)
620 uuid_generate_random(out
);
622 uuid_generate_time(out
);