2002-09-23 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / gethostid.c
1 /* Copyright (C) 1995,1996,1998,1999,2000,2001 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C 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    The GNU C 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 the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <alloca.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <netdb.h>
24
25 #define HOSTIDFILE "/etc/hostid"
26 #define OLD_HOSTIDFILE "/etc/hostid"
27
28 #ifdef SET_PROCEDURE
29 int
30 sethostid (id)
31      long int id;
32 {
33   int fd;
34   ssize_t written;
35
36   /* Test for appropriate rights to set host ID.  */
37   if (__libc_enable_secure)
38     {
39       __set_errno (EPERM);
40       return -1;
41     }
42
43   /* Open file for writing.  Everybody is allowed to read this file.  */
44   fd = __open64 (HOSTIDFILE, O_CREAT|O_WRONLY|O_TRUNC, 0644);
45   if (fd < 0)
46     return -1;
47
48   written = __write (fd, &id, sizeof (id));
49
50   __close (fd);
51
52   return written != sizeof (id) ? -1 : 0;
53 }
54
55 #else
56 # include <string.h>
57 # include <sys/param.h>
58 # include <resolv/netdb.h>
59 # include <netinet/in.h>
60
61 long int
62 gethostid ()
63 {
64   char hostname[MAXHOSTNAMELEN + 1];
65   size_t buflen;
66   char *buffer;
67   struct hostent hostbuf, *hp;
68   unsigned long int id;
69   struct in_addr in;
70   int herr;
71   int fd;
72
73   /* First try to get the ID from a former invocation of sethostid.  */
74   fd = __open64 (HOSTIDFILE, O_RDONLY);
75   if (fd < 0)
76     fd = __open64 (OLD_HOSTIDFILE, O_RDONLY);
77   if (fd >= 0)
78     {
79       ssize_t n = __read (fd, &id, sizeof (id));
80
81       __close (fd);
82
83       if (n == sizeof (id))
84         return id;
85     }
86
87   /* Getting from the file was not successful.  An intelligent guess for
88      a unique number of a host is its IP address.  Return this.  */
89   if (__gethostname (hostname, MAXHOSTNAMELEN) < 0 || hostname[0] == '\0')
90     /* This also fails.  Return and arbitrary value.  */
91     return 0;
92
93   buflen = 1024;
94   buffer = __alloca (buflen);
95
96   /* To get the IP address we need to know the host name.  */
97   while (__gethostbyname_r (hostname, &hostbuf, buffer, buflen, &hp, &herr)
98          != 0
99          || hp == NULL)
100     if (herr != NETDB_INTERNAL || errno != ERANGE)
101       return 0;
102     else
103       {
104         /* Enlarge buffer.  */
105         buflen *= 2;
106         buffer = __alloca (buflen);
107       }
108
109   in.s_addr = 0;
110   memcpy (&in, hp->h_addr,
111           (int) sizeof (in) < hp->h_length ? (int) sizeof (in) : hp->h_length);
112
113   /* For the return value to be not exactly the IP address we do some
114      bit fiddling.  */
115   return in.s_addr << 16 | in.s_addr >> 16;
116 }
117 #endif