Mostly indendation changes. Completed the Manifest.
[libgcrypt.git] / cipher / rndlinux.c
1 /* rndlinux.c  -  raw random number for OSes with /dev/random
2  * Copyright (C) 1998, 2001, 2002, 2003  Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #ifdef HAVE_GETTIMEOFDAY
31 # include <sys/times.h>
32 #endif
33 #include <string.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include "types.h"
37 #include "g10lib.h"
38 #include "rand-internal.h"
39
40 static int open_device( const char *name, int minor );
41 int _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, int),
42                                   int requester,
43                                   size_t length, int level );
44
45 /*
46  * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)).
47  */
48 static int
49 open_device( const char *name, int minor )
50 {
51   int fd;
52
53   fd = open( name, O_RDONLY );
54   if( fd == -1 )
55     log_fatal ("can't open %s: %s\n", name, strerror(errno) );
56
57   /* We used to do the follwing check, however it turned out that this
58      is not portable since more OSes provide a random device which is
59      sometimes implemented as anoteher device type. 
60      
61      struct stat sb;
62
63      if( fstat( fd, &sb ) )
64         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
65      if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
66         log_fatal("invalid random device!\n" );
67   */
68   return fd;
69 }
70
71
72 int
73 _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, int),
74                               int requester,
75                               size_t length, int level )
76 {
77   static int fd_urandom = -1;
78   static int fd_random = -1;
79   int fd;
80   int n;
81   int warn=0;
82   byte buffer[768];
83
84   if( level >= 2 )
85     {
86       if( fd_random == -1 )
87         fd_random = open_device( NAME_OF_DEV_RANDOM, 8 );
88       fd = fd_random;
89     }
90   else
91     {
92       if( fd_urandom == -1 )
93         fd_urandom = open_device( NAME_OF_DEV_URANDOM, 9 );
94       fd = fd_urandom;
95     }
96
97   while (length)
98     {
99       fd_set rfds;
100       struct timeval tv;
101       int rc;
102       
103       FD_ZERO(&rfds);
104       FD_SET(fd, &rfds);
105       tv.tv_sec = 3;
106       tv.tv_usec = 0;
107       if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
108         {
109           if( !warn )
110             {
111               _gcry_random_progress ("need_entropy", 'X', 0, (int)length);
112               warn = 1;
113             }
114           continue;
115         }
116         else if( rc == -1 )
117           {
118             log_error ("select() error: %s\n", strerror(errno));
119             continue;
120           }
121
122         do 
123           {
124             int nbytes = length < sizeof(buffer)? length : sizeof(buffer);
125             n = read(fd, buffer, nbytes );
126             if( n >= 0 && n > nbytes ) 
127               {
128                 log_error("bogus read from random device (n=%d)\n", n );
129                 n = nbytes;
130               }
131           } 
132         while( n == -1 && errno == EINTR );
133         if( n == -1 )
134           log_fatal("read error on random device: %s\n", strerror(errno));
135         (*add)( buffer, n, requester );
136         length -= n;
137     }
138   memset(buffer, 0, sizeof(buffer) );
139
140   return 0; /* success */
141 }