summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2011-12-05 03:46:40 +0100
committerBruno Haible <bruno@clisp.org>2011-12-05 03:46:40 +0100
commitbb052d4a7416accaad0747e84bd2a0accbfcf923 (patch)
treed076481f6841f2620aaa5ed68eb5110534a1ad2e
parentc69114d48295481373ee197c72214877b909414e (diff)
downloadgnulib-bb052d4a7416accaad0747e84bd2a0accbfcf923.tar.gz
sethostname: Port to Windows platforms.
* lib/sethostname.c: Provide an alternate implementation for Windows platforms. * tests/test-sethostname2.c (geteuid): Redefine on Cygwin. (main): Skip the test if sethostname() fails with EPERM. On Windows platforms, don't check the result of gethostname(). 2011-12-04 Bruno Haible <bruno@clisp.org>
-rw-r--r--ChangeLog9
-rw-r--r--lib/sethostname.c78
-rw-r--r--tests/test-sethostname2.c16
3 files changed, 101 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 0cfb578729..1a1fccba9f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
2011-12-04 Bruno Haible <bruno@clisp.org>
+
+ sethostname: Port to Windows platforms.
+ * lib/sethostname.c: Provide an alternate implementation for Windows
+ platforms.
+ * tests/test-sethostname2.c (geteuid): Redefine on Cygwin.
+ (main): Skip the test if sethostname() fails with EPERM. On Windows
+ platforms, don't check the result of gethostname().
+
+2011-12-04 Bruno Haible <bruno@clisp.org>
Jim Meyering <meyering@redhat.com>
tests: Avoid spurious error message on platforms without mktemp program.
diff --git a/lib/sethostname.c b/lib/sethostname.c
index 3c2ec3c0c5..6555921609 100644
--- a/lib/sethostname.c
+++ b/lib/sethostname.c
@@ -19,6 +19,7 @@
#include <config.h>
+#if !((defined _WIN32 || defined __WIN32__) || defined __CYGWIN__)
/* Unix API. */
/* Specification. */
@@ -82,3 +83,80 @@ sethostname (const char *name, size_t len)
return -1;
#endif
}
+
+#else
+/* Native Windows API. Also used on Cygwin. */
+
+/* Ensure that <windows.h> declares SetComputerNameEx. */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x500
+
+#define WIN32_LEAN_AND_MEAN
+
+/* Specification. */
+#include <unistd.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+#include <windows.h>
+/* The mingw header files don't define GetComputerNameEx, SetComputerNameEx. */
+#ifndef GetComputerNameEx
+# define GetComputerNameEx GetComputerNameExA
+#endif
+#ifndef SetComputerNameEx
+# define SetComputerNameEx SetComputerNameExA
+#endif
+
+/* Set up to LEN chars of NAME as system hostname.
+ Return 0 if ok, set errno and return -1 on error. */
+
+int
+sethostname (const char *name, size_t len)
+{
+ char name_asciz[HOST_NAME_MAX + 1];
+ char old_name[HOST_NAME_MAX + 1];
+ DWORD old_name_len;
+
+ /* Ensure the string isn't too long. glibc does allow setting an
+ empty hostname so no point in enforcing a lower bound. */
+ if (len > HOST_NAME_MAX)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Prepare a NUL-terminated copy of name. */
+ memcpy (name_asciz, name, len);
+ name_asciz[len] = '\0';
+
+ /* Save the old NetBIOS name. */
+ old_name_len = sizeof (old_name) - 1;
+ if (! GetComputerNameEx (ComputerNamePhysicalNetBIOS,
+ old_name, &old_name_len))
+ old_name_len = 0;
+
+ /* Set both the NetBIOS and the first part of the IP / DNS name. */
+ if (! SetComputerNameEx (ComputerNamePhysicalNetBIOS, name_asciz))
+ {
+ errno = (GetLastError () == ERROR_ACCESS_DENIED ? EPERM : EINVAL);
+ return -1;
+ }
+ if (! SetComputerNameEx (ComputerNamePhysicalDnsHostname, name_asciz))
+ {
+ errno = (GetLastError () == ERROR_ACCESS_DENIED ? EPERM : EINVAL);
+ /* Restore the old NetBIOS name. */
+ if (old_name_len > 0)
+ {
+ old_name[old_name_len] = '\0';
+ SetComputerNameEx (ComputerNamePhysicalNetBIOS, old_name);
+ }
+ return -1;
+ }
+
+ /* Note that the new host name becomes effective only after a reboot! */
+ return 0;
+}
+
+#endif
diff --git a/tests/test-sethostname2.c b/tests/test-sethostname2.c
index 51f92aeeb1..92c2c03991 100644
--- a/tests/test-sethostname2.c
+++ b/tests/test-sethostname2.c
@@ -31,8 +31,10 @@
#define TESTHOSTNAME "gnulib-hostname"
-/* mingw and MSVC 9 lack geteuid, so setup a dummy value. */
-#if !HAVE_GETEUID
+/* mingw and MSVC 9 lack geteuid, so setup a dummy value.
+ On Cygwin, geteuid() may return non-zero even for user accounts with
+ administrator privileges, so use a dummy value as well. */
+#if !HAVE_GETEUID || defined __CYGWIN__
# define geteuid() 0
#endif
@@ -72,6 +74,11 @@ main (int argc, char *argv[] _GL_UNUSED)
"Skipping test: sethostname is not really implemented.\n");
return 77;
}
+ else if (rcs == -1 && errno == EPERM)
+ {
+ fprintf (stderr, "Skipping test: insufficient permissions.\n");
+ return 77;
+ }
else
{
fprintf (stderr, "error setting valid hostname.\n");
@@ -82,6 +89,10 @@ main (int argc, char *argv[] _GL_UNUSED)
{
ASSERT (gethostname (newname, sizeof (newname)) == 0);
+ /* On Windows, a hostname change becomes effective only after
+ a reboot. */
+#if !((defined _WIN32 || defined __WIN32__) || defined __CYGWIN__)
+
/* if we don't get back what we put in, there is no need to
restore the original name as we will assume it was not
properly changed. */
@@ -90,6 +101,7 @@ main (int argc, char *argv[] _GL_UNUSED)
fprintf (stderr, "set/get comparison failed.\n");
return 1;
}
+#endif
}
/* glibc does allow setting a zero length name, so the lower bound