maint: update copyright
[gnulib.git] / lib / sethostname.c
index 3c2ec3c..acd5202 100644 (file)
@@ -1,6 +1,6 @@
 /* sethostname emulation for glibc compliance.
 
-   Copyright (C) 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011-2014 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -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