maint: update copyright
[gnulib.git] / lib / sethostname.c
1 /* sethostname emulation for glibc compliance.
2
3    Copyright (C) 2011-2014 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 /* Ben Walton <bwalton@artsci.utoronto.ca> */
19
20 #include <config.h>
21
22 #if !((defined _WIN32 || defined __WIN32__) || defined __CYGWIN__)
23 /* Unix API.  */
24
25 /* Specification.  */
26 #include <unistd.h>
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <limits.h>
31
32 /* Set up to LEN chars of NAME as system hostname.
33    Return 0 if ok, set errno and return -1 on error. */
34
35 int
36 sethostname (const char *name, size_t len)
37 {
38   /* Ensure the string isn't too long.  glibc does allow setting an
39      empty hostname so no point in enforcing a lower bound. */
40   if (len > HOST_NAME_MAX)
41     {
42       errno = EINVAL;
43       return -1;
44     }
45
46 #ifdef __minix /* Minix */
47   {
48     FILE *hostf;
49     int r = 0;
50
51     /* glibc returns EFAULT, EINVAL, and EPERM on error.  None of
52        these are appropriate for us to set, even if they may match the
53        situation, during failed open/write/close operations, so we
54        leave errno alone and rely on what the system sets up. */
55     hostf = fopen ("/etc/hostname.file", "w");
56     if (hostf == NULL)
57       r = -1;
58     else
59       {
60         fprintf (hostf, "%.*s\n", (int) len, name);
61         if (ferror (hostf))
62           {
63             /* Close hostf, preserving the errno from the fprintf call.  */
64             int saved_errno = errno;
65             fclose (hostf);
66             errno = saved_errno;
67             r = -1;
68           }
69         else
70           {
71             if (fclose (hostf))
72               /* fclose sets errno on failure.  */
73               r = -1;
74           }
75       }
76
77     return r;
78   }
79 #else
80   /* For platforms that we don't have a better option for, simply bail
81      out.  */
82   errno = ENOSYS;
83   return -1;
84 #endif
85 }
86
87 #else
88 /* Native Windows API.  Also used on Cygwin.  */
89
90 /* Ensure that <windows.h> declares SetComputerNameEx.  */
91 #undef _WIN32_WINNT
92 #define _WIN32_WINNT 0x500
93
94 #define WIN32_LEAN_AND_MEAN
95
96 /* Specification.  */
97 #include <unistd.h>
98
99 #include <errno.h>
100 #include <limits.h>
101 #include <string.h>
102
103 #include <windows.h>
104 /* The mingw header files don't define GetComputerNameEx, SetComputerNameEx.  */
105 #ifndef GetComputerNameEx
106 # define GetComputerNameEx GetComputerNameExA
107 #endif
108 #ifndef SetComputerNameEx
109 # define SetComputerNameEx SetComputerNameExA
110 #endif
111
112 /* Set up to LEN chars of NAME as system hostname.
113    Return 0 if ok, set errno and return -1 on error. */
114
115 int
116 sethostname (const char *name, size_t len)
117 {
118   char name_asciz[HOST_NAME_MAX + 1];
119   char old_name[HOST_NAME_MAX + 1];
120   DWORD old_name_len;
121
122   /* Ensure the string isn't too long.  glibc does allow setting an
123      empty hostname so no point in enforcing a lower bound. */
124   if (len > HOST_NAME_MAX)
125     {
126       errno = EINVAL;
127       return -1;
128     }
129
130   /* Prepare a NUL-terminated copy of name.  */
131   memcpy (name_asciz, name, len);
132   name_asciz[len] = '\0';
133
134   /* Save the old NetBIOS name.  */
135   old_name_len = sizeof (old_name) - 1;
136   if (! GetComputerNameEx (ComputerNamePhysicalNetBIOS,
137                            old_name, &old_name_len))
138     old_name_len = 0;
139
140   /* Set both the NetBIOS and the first part of the IP / DNS name.  */
141   if (! SetComputerNameEx (ComputerNamePhysicalNetBIOS, name_asciz))
142     {
143       errno = (GetLastError () == ERROR_ACCESS_DENIED ? EPERM : EINVAL);
144       return -1;
145     }
146   if (! SetComputerNameEx (ComputerNamePhysicalDnsHostname, name_asciz))
147     {
148       errno = (GetLastError () == ERROR_ACCESS_DENIED ? EPERM : EINVAL);
149       /* Restore the old NetBIOS name.  */
150       if (old_name_len > 0)
151         {
152           old_name[old_name_len] = '\0';
153           SetComputerNameEx (ComputerNamePhysicalNetBIOS, old_name);
154         }
155       return -1;
156     }
157
158   /* Note that the new host name becomes effective only after a reboot!  */
159   return 0;
160 }
161
162 #endif