]>
git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/uuid/gen_uuid.c
01983634256cf30ec6a0cda1fa1ace5a05144e51
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
40 #define _DEFAULT_SOURCE /* since glibc 2.20 _SVID_SOURCE is deprecated */
45 #define _WIN32_WINNT 0x0500
59 #include <sys/types.h>
60 #ifdef HAVE_SYS_TIME_H
63 #ifdef HAVE_SYS_WAIT_H
67 #ifdef HAVE_SYS_FILE_H
70 #ifdef HAVE_SYS_IOCTL_H
71 #include <sys/ioctl.h>
73 #ifdef HAVE_SYS_SOCKET_H
74 #include <sys/socket.h>
79 #ifdef HAVE_SYS_SOCKIO_H
80 #include <sys/sockio.h>
85 #ifdef HAVE_NETINET_IN_H
86 #include <netinet/in.h>
88 #ifdef HAVE_NET_IF_DL_H
89 #include <net/if_dl.h>
91 #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
92 #include <sys/syscall.h>
94 #ifdef HAVE_SYS_RESOURCE_H
95 #include <sys/resource.h>
102 #define srand(x) srandom(x)
103 #define rand() random()
107 #define THREAD_LOCAL static TLS
109 #define THREAD_LOCAL static
112 #if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
114 THREAD_LOCAL
unsigned short jrand_seed
[3];
119 static void gettimeofday (struct timeval
*tv
, void *dummy
)
124 GetSystemTimeAsFileTime (&ftime
);
125 n
= (((uint64_t) ftime
.dwHighDateTime
<< 32)
126 + (uint64_t) ftime
.dwLowDateTime
);
129 n
-= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
132 tv
->tv_sec
= n
/ 1000000;
133 tv
->tv_usec
= n
% 1000000;
138 static int get_random_fd(void)
145 gettimeofday(&tv
, 0);
147 fd
= open("/dev/urandom", O_RDONLY
);
149 fd
= open("/dev/random", O_RDONLY
| O_NONBLOCK
);
151 i
= fcntl(fd
, F_GETFD
);
153 fcntl(fd
, F_SETFD
, i
| FD_CLOEXEC
);
156 srand(((unsigned)getpid() << 16) ^ getuid() ^ tv
.tv_sec
^ tv
.tv_usec
);
158 jrand_seed
[0] = getpid() ^ (tv
.tv_sec
& 0xFFFF);
159 jrand_seed
[1] = getppid() ^ (tv
.tv_usec
& 0xFFFF);
160 jrand_seed
[2] = (tv
.tv_sec
^ tv
.tv_usec
) >> 16;
163 /* Crank the random number generator a few times */
164 gettimeofday(&tv
, 0);
165 for (i
= (tv
.tv_sec
^ tv
.tv_usec
) & 0x1F; i
> 0; i
--)
172 * Generate a series of random bytes. Use /dev/urandom if possible,
173 * and if not, use srandom/random.
175 static void get_random_bytes(void *buf
, int nbytes
)
177 int i
, n
= nbytes
, fd
= get_random_fd();
178 int lose_counter
= 0;
179 unsigned char *cp
= buf
;
185 if (lose_counter
++ > 16)
196 * We do this all the time, but this is the only source of
197 * randomness if /dev/random/urandom is out to lunch.
199 for (cp
= buf
, i
= 0; i
< nbytes
; i
++)
200 *cp
++ ^= (rand() >> 7) & 0xFF;
203 unsigned short tmp_seed
[3];
205 memcpy(tmp_seed
, jrand_seed
, sizeof(tmp_seed
));
206 jrand_seed
[2] = jrand_seed
[2] ^ syscall(__NR_gettid
);
207 for (cp
= buf
, i
= 0; i
< nbytes
; i
++)
208 *cp
++ ^= (jrand48(tmp_seed
) >> 7) & 0xFF;
209 memcpy(jrand_seed
, tmp_seed
,
210 sizeof(jrand_seed
) - sizeof(unsigned short));
218 * Get the ethernet hardware address, if we can find it...
220 * XXX for a windows version, probably should use GetAdaptersInfo:
221 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
222 * commenting out get_node_id just to get gen_uuid to compile under windows
223 * is not the right way to go!
225 static int get_node_id(unsigned char *node_id
)
229 struct ifreq ifr
, *ifrp
;
234 #ifdef HAVE_NET_IF_DL_H
235 struct sockaddr_dl
*sdlp
;
239 * BSD 4.4 defines the size of an ifreq to be
240 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
241 * However, under earlier systems, sa_len isn't present, so the size is
242 * just sizeof(struct ifreq)
246 #define max(a,b) ((a) > (b) ? (a) : (b))
248 #define ifreq_size(i) max(sizeof(struct ifreq),\
249 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
251 #define ifreq_size(i) sizeof(struct ifreq)
252 #endif /* HAVE_SA_LEN*/
254 sd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
258 memset(buf
, 0, sizeof(buf
));
259 ifc
.ifc_len
= sizeof(buf
);
261 if (ioctl (sd
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
266 for (i
= 0; i
< n
; i
+= ifreq_size(*ifrp
) ) {
267 ifrp
= (struct ifreq
*)((char *) ifc
.ifc_buf
+i
);
268 strncpy(ifr
.ifr_name
, ifrp
->ifr_name
, IFNAMSIZ
);
270 if (ioctl(sd
, SIOCGIFHWADDR
, &ifr
) < 0)
272 a
= (unsigned char *) &ifr
.ifr_hwaddr
.sa_data
;
275 if (ioctl(sd
, SIOCGENADDR
, &ifr
) < 0)
277 a
= (unsigned char *) ifr
.ifr_enaddr
;
279 #ifdef HAVE_NET_IF_DL_H
280 sdlp
= (struct sockaddr_dl
*) &ifrp
->ifr_addr
;
281 if ((sdlp
->sdl_family
!= AF_LINK
) || (sdlp
->sdl_alen
!= 6))
283 a
= (unsigned char *) &sdlp
->sdl_data
[sdlp
->sdl_nlen
];
286 * XXX we don't have a way of getting the hardware
291 #endif /* HAVE_NET_IF_DL_H */
292 #endif /* SIOCGENADDR */
293 #endif /* SIOCGIFHWADDR */
294 if (!a
[0] && !a
[1] && !a
[2] && !a
[3] && !a
[4] && !a
[5])
297 memcpy(node_id
, a
, 6);
307 /* Assume that the gettimeofday() has microsecond granularity */
308 #define MAX_ADJUSTMENT 10
310 static int get_clock(uint32_t *clock_high
, uint32_t *clock_low
,
311 uint16_t *ret_clock_seq
, int *num
)
313 THREAD_LOCAL
int adjustment
= 0;
314 THREAD_LOCAL
struct timeval last
= {0, 0};
315 THREAD_LOCAL
int state_fd
= -2;
316 THREAD_LOCAL
FILE *state_f
;
317 THREAD_LOCAL
uint16_t clock_seq
;
326 if (state_fd
== -2) {
327 save_umask
= umask(0);
328 state_fd
= open("/var/lib/libuuid/clock.txt",
329 O_RDWR
|O_CREAT
, 0660);
330 (void) umask(save_umask
);
332 state_f
= fdopen(state_fd
, "r+");
341 fl
.l_whence
= SEEK_SET
;
347 while (fcntl(state_fd
, F_SETLKW
, &fl
) < 0) {
348 if ((errno
== EAGAIN
) || (errno
== EINTR
))
358 unsigned long tv1
, tv2
;
361 if (fscanf(state_f
, "clock: %04x tv: %lu %lu adj: %d\n",
362 &cl
, &tv1
, &tv2
, &a
) == 4) {
363 clock_seq
= cl
& 0x3FFF;
370 if ((last
.tv_sec
== 0) && (last
.tv_usec
== 0)) {
371 get_random_bytes(&clock_seq
, sizeof(clock_seq
));
373 gettimeofday(&last
, 0);
378 gettimeofday(&tv
, 0);
379 if ((tv
.tv_sec
< last
.tv_sec
) ||
380 ((tv
.tv_sec
== last
.tv_sec
) &&
381 (tv
.tv_usec
< last
.tv_usec
))) {
382 clock_seq
= (clock_seq
+1) & 0x3FFF;
385 } else if ((tv
.tv_sec
== last
.tv_sec
) &&
386 (tv
.tv_usec
== last
.tv_usec
)) {
387 if (adjustment
>= MAX_ADJUSTMENT
)
395 clock_reg
= tv
.tv_usec
*10 + adjustment
;
396 clock_reg
+= ((uint64_t) tv
.tv_sec
)*10000000;
397 clock_reg
+= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
399 if (num
&& (*num
> 1)) {
400 adjustment
+= *num
- 1;
401 last
.tv_usec
+= adjustment
/ 10;
402 adjustment
= adjustment
% 10;
403 last
.tv_sec
+= last
.tv_usec
/ 1000000;
404 last
.tv_usec
= last
.tv_usec
% 1000000;
409 len
= fprintf(state_f
,
410 "clock: %04x tv: %016lu %08lu adj: %08d\n",
411 clock_seq
, last
.tv_sec
, (long)last
.tv_usec
,
414 if (ftruncate(state_fd
, len
) < 0) {
415 fprintf(state_f
, " \n");
421 if (fcntl(state_fd
, F_SETLK
, &fl
) < 0) {
428 *clock_high
= clock_reg
>> 32;
429 *clock_low
= clock_reg
;
430 *ret_clock_seq
= clock_seq
;
434 #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H)
435 static ssize_t
read_all(int fd
, char *buf
, size_t count
)
441 memset(buf
, 0, count
);
443 ret
= read(fd
, buf
, count
);
445 if ((errno
== EAGAIN
|| errno
== EINTR
|| ret
== 0) &&
460 * Close all file descriptors
462 static void close_all_fds(void)
466 #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
467 max
= sysconf(_SC_OPEN_MAX
);
468 #elif defined(HAVE_GETDTABLESIZE)
469 max
= getdtablesize();
470 #elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
473 getrlimit(RLIMIT_NOFILE
, &rl
);
479 for (i
=0; i
< max
; i
++) {
482 open("/dev/null", O_RDWR
);
485 #endif /* defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) */
487 #if __GNUC_PREREQ (4, 6)
488 #pragma GCC diagnostic push
489 #if !defined(USE_UUIDD) || !defined(HAVE_SYS_UN_H)
490 #pragma GCC diagnostic ignored "-Wunused-parameter"
494 * Try using the uuidd daemon to generate the UUID
496 * Returns 0 on success, non-zero on failure.
498 static int get_uuid_via_daemon(int op
, uuid_t out
, int *num
)
500 #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H)
505 int32_t reply_len
= 0, expected
= 16;
506 struct sockaddr_un srv_addr
;
509 static const char *uuidd_path
= UUIDD_PATH
;
510 static int access_ret
= -2;
511 static int start_attempts
= 0;
513 if ((s
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0)
516 srv_addr
.sun_family
= AF_UNIX
;
517 strcpy(srv_addr
.sun_path
, UUIDD_SOCKET_PATH
);
519 if (connect(s
, (const struct sockaddr
*) &srv_addr
,
520 sizeof(struct sockaddr_un
)) < 0) {
521 if (access_ret
== -2)
522 access_ret
= access(uuidd_path
, X_OK
);
524 access_ret
= stat(uuidd_path
, &st
);
525 if (access_ret
== 0 && (st
.st_mode
& (S_ISUID
| S_ISGID
)) == 0)
526 access_ret
= access(UUIDD_DIR
, W_OK
);
527 if (access_ret
== 0 && start_attempts
++ < 5) {
528 if ((pid
= fork()) == 0) {
530 execl(uuidd_path
, "uuidd", "-qT", "300",
534 (void) waitpid(pid
, 0, 0);
535 if (connect(s
, (const struct sockaddr
*) &srv_addr
,
536 sizeof(struct sockaddr_un
)) < 0)
543 if (op
== UUIDD_OP_BULK_TIME_UUID
) {
544 memcpy(op_buf
+1, num
, sizeof(*num
));
545 op_len
+= sizeof(*num
);
546 expected
+= sizeof(*num
);
549 ret
= write(s
, op_buf
, op_len
);
553 ret
= read_all(s
, (char *) &reply_len
, sizeof(reply_len
));
557 if (reply_len
!= expected
)
560 ret
= read_all(s
, op_buf
, reply_len
);
562 if (op
== UUIDD_OP_BULK_TIME_UUID
)
563 memcpy(op_buf
+16, num
, sizeof(int));
565 memcpy(out
, op_buf
, 16);
568 return ((ret
== expected
) ? 0 : -1);
575 #if __GNUC_PREREQ (4, 6)
576 #pragma GCC diagnostic pop
579 void uuid__generate_time(uuid_t out
, int *num
)
581 static unsigned char node_id
[6];
582 static int has_init
= 0;
587 if (get_node_id(node_id
) <= 0) {
588 get_random_bytes(node_id
, 6);
590 * Set multicast bit, to prevent conflicts
591 * with IEEE 802 addresses obtained from
598 get_clock(&clock_mid
, &uu
.time_low
, &uu
.clock_seq
, num
);
599 uu
.clock_seq
|= 0x8000;
600 uu
.time_mid
= (uint16_t) clock_mid
;
601 uu
.time_hi_and_version
= ((clock_mid
>> 16) & 0x0FFF) | 0x1000;
602 memcpy(uu
.node
, node_id
, 6);
606 void uuid_generate_time(uuid_t out
)
609 THREAD_LOCAL
int num
= 0;
610 THREAD_LOCAL
struct uuid uu
;
611 THREAD_LOCAL
time_t last_time
= 0;
616 if (now
> last_time
+1)
621 if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID
,
624 uuid_unpack(out
, &uu
);
632 if (uu
.time_low
== 0) {
634 if (uu
.time_mid
== 0)
635 uu
.time_hi_and_version
++;
642 if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID
, out
, 0) == 0)
646 uuid__generate_time(out
, 0);
650 void uuid__generate_random(uuid_t out
, int *num
)
661 for (i
= 0; i
< n
; i
++) {
662 get_random_bytes(buf
, sizeof(buf
));
663 uuid_unpack(buf
, &uu
);
665 uu
.clock_seq
= (uu
.clock_seq
& 0x3FFF) | 0x8000;
666 uu
.time_hi_and_version
= (uu
.time_hi_and_version
& 0x0FFF)
669 out
+= sizeof(uuid_t
);
673 void uuid_generate_random(uuid_t out
)
676 /* No real reason to use the daemon for random uuid's -- yet */
678 uuid__generate_random(out
, &num
);
683 * This is the generic front-end to uuid_generate_random and
684 * uuid_generate_time. It uses uuid_generate_random only if
685 * /dev/urandom is available, since otherwise we won't have
686 * high-quality randomness.
688 void uuid_generate(uuid_t out
)
690 if (get_random_fd() >= 0)
691 uuid_generate_random(out
);
693 uuid_generate_time(out
);