* eval.c, filesys.c, fluids.c, gc.c, gh_data.c, init.c, kw.c,
[bpt/guile.git] / libguile / net_db.c
index bb73295..71121a1 100644 (file)
@@ -1,5 +1,5 @@
 /* "net_db.c" network database support
- *     Copyright (C) 1995,1996 Free Software Foundation, Inc.
+ *     Copyright (C) 1995,1996,1997 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
@@ -13,7 +13,8 @@
  * 
  * You should have received a copy of the GNU General Public License
  * along with this software; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
  *
  * As a special exception, the Free Software Foundation gives permission
  * for additional uses of the text contained in its release of GUILE.
@@ -37,8 +38,7 @@
  *
  * If you write modifications of your own for GUILE, it is your choice
  * whether to permit this exception to apply to your modifications.
- * If you do not wish that, delete this exception notice.  
- */
+ * If you do not wish that, delete this exception notice.  */
 
 /* Written in 1994 by Aubrey Jaffer.
  * Thanks to Hallvard.Tretteberg@si.sintef.no for inspiration and discussion.
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+/* Some systems do not declare this.  It seems unlikely to produce a
+   conflict.  */
+extern int h_errno;
+
 \f
 
 #ifndef STDC_HEADERS
@@ -105,6 +109,7 @@ scm_inet_ntoa (inetid)
   return answer;
 }
 
+#ifdef HAVE_INET_NETOF
 SCM_PROC (s_inet_netof, "inet-netof", 1, 0, 0, scm_inet_netof);
 
 SCM 
@@ -115,7 +120,9 @@ scm_inet_netof (address)
   addr.s_addr = htonl (scm_num2ulong (address, (char *) SCM_ARG1, s_inet_netof));
   return scm_ulong2num ((unsigned long) inet_netof (addr));
 }
+#endif
 
+#ifdef HAVE_INET_LNAOF
 SCM_PROC (s_lnaof, "inet-lnaof", 1, 0, 0, scm_lnaof);
 
 SCM 
@@ -126,8 +133,9 @@ scm_lnaof (address)
   addr.s_addr = htonl (scm_num2ulong (address, (char *) SCM_ARG1, s_lnaof));
   return scm_ulong2num ((unsigned long) inet_lnaof (addr));
 }
+#endif
 
-
+#ifdef HAVE_INET_MAKEADDR
 SCM_PROC (s_inet_makeaddr, "inet-makeaddr", 2, 0, 0, scm_inet_makeaddr);
 
 SCM 
@@ -144,6 +152,7 @@ scm_inet_makeaddr (net, lna)
   addr = inet_makeaddr (netnum, lnanum);
   return scm_ulong2num (ntohl (addr.s_addr));
 }
+#endif
 
 
 /* !!! Doesn't take address format.
@@ -156,7 +165,7 @@ SCM
 scm_gethost (name)
      SCM name;
 {
-  SCM ans = scm_make_vector (SCM_MAKINUM (5), SCM_UNSPECIFIED, SCM_BOOL_F);
+  SCM ans = scm_make_vector (SCM_MAKINUM (5), SCM_UNSPECIFIED);
   SCM *ve = SCM_VELTS (ans);
   SCM lst = SCM_EOL;
   struct hostent *entry;
@@ -171,9 +180,21 @@ scm_gethost (name)
 #else
       entry = NULL;
 #endif
+      if (! entry)
+       {
+         /* As far as I can tell, there's no good way to tell whether
+             zero means an error or end-of-file.  The trick of
+             clearing errno before calling gethostent and checking it
+             afterwards doesn't cut it, because, on Linux, it seems to
+             try to contact some other server (YP?) and fails, which
+             is a benign failure.  */
+         SCM_ALLOW_INTS;
+         return SCM_BOOL_F;
+       }
     }
   else if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
     {
+      SCM_COERCE_SUBSTR (name);
       SCM_DEFER_INTS;
       entry = gethostbyname (SCM_ROCHARS (name));
     }
@@ -185,7 +206,20 @@ scm_gethost (name)
     }
   SCM_ALLOW_INTS;
   if (!entry)
-    scm_syserror (s_gethost);
+    {
+      char *errmsg;
+      SCM args;
+      args = scm_listify (name, SCM_UNDEFINED);
+      switch (h_errno)
+       {
+       case HOST_NOT_FOUND: errmsg = "host %s not found"; break;
+       case TRY_AGAIN:      errmsg = "nameserver failure (try later)"; break;
+       case NO_RECOVERY:    errmsg = "non-recoverable error"; break;
+       case NO_DATA:        errmsg = "no address associated with %s"; break;
+       default:             errmsg = "undefined error"; break;
+       }
+      scm_syserror_msg (s_gethost, errmsg, args, h_errno);
+    }
   ve[0] = scm_makfromstr (entry->h_name, (scm_sizet) strlen (entry->h_name), 0);
   ve[1] = scm_makfromstrs (-1, entry->h_aliases);
   ve[2] = SCM_MAKINUM (entry->h_addrtype + 0L);
@@ -206,6 +240,16 @@ scm_gethost (name)
 }
 
 
+/* In all subsequent getMUMBLE functions, when we're called with no
+   arguments, we're supposed to traverse the tables entry by entry.
+   However, there doesn't seem to be any documented way to distinguish
+   between end-of-table and an error; in both cases the functions
+   return zero.  Gotta love Unix.  For the time being, we clear errno,
+   and if we get a zero and errno is set, we signal an error.  This
+   doesn't seem quite right (what if errno gets set as part of healthy
+   operation?), but it seems to work okay.  We'll see.  */
+
+#if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
 SCM_PROC (s_getnet, "getnet", 0, 1, 0, scm_getnet);
 
 SCM 
@@ -216,15 +260,25 @@ scm_getnet (name)
   SCM *ve;
   struct netent *entry;
 
-  ans = scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED, SCM_BOOL_F);
+  ans = scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED);
   ve = SCM_VELTS (ans);
   if (SCM_UNBNDP (name))
     {
       SCM_DEFER_INTS;
+      errno = 0;
       entry = getnetent ();
+      if (! entry)
+       {
+         SCM_ALLOW_INTS;
+         if (errno)
+           scm_syserror (s_getnet);
+         else 
+           return SCM_BOOL_F;
+       }
     }
   else if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
     {
+      SCM_COERCE_SUBSTR (name);
       SCM_DEFER_INTS;
       entry = getnetbyname (SCM_ROCHARS (name));
     }
@@ -237,14 +291,17 @@ scm_getnet (name)
     }
   SCM_ALLOW_INTS;
   if (!entry)
-    scm_syserror (s_getnet);
+    scm_syserror_msg (s_getnet, "no such network %s",
+                     scm_listify (name, SCM_UNDEFINED), errno);
   ve[0] = scm_makfromstr (entry->n_name, (scm_sizet) strlen (entry->n_name), 0);
   ve[1] = scm_makfromstrs (-1, entry->n_aliases);
   ve[2] = SCM_MAKINUM (entry->n_addrtype + 0L);
   ve[3] = scm_ulong2num (entry->n_net + 0L);
   return ans;
 }
+#endif
 
+#ifdef HAVE_GETPROTOENT
 SCM_PROC (s_getproto, "getproto", 0, 1, 0, scm_getproto);
 
 SCM 
@@ -255,15 +312,25 @@ scm_getproto (name)
   SCM *ve;
   struct protoent *entry;
 
-  ans = scm_make_vector (SCM_MAKINUM (3), SCM_UNSPECIFIED, SCM_BOOL_F);
+  ans = scm_make_vector (SCM_MAKINUM (3), SCM_UNSPECIFIED);
   ve = SCM_VELTS (ans);
   if (SCM_UNBNDP (name))
     {
       SCM_DEFER_INTS;
+      errno = 0;
       entry = getprotoent ();
+      if (! entry)
+       {
+         SCM_ALLOW_INTS;
+         if (errno)
+           scm_syserror (s_getproto);
+         else
+           return SCM_BOOL_F;
+       }
     }
   else if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
     {
+      SCM_COERCE_SUBSTR (name);
       SCM_DEFER_INTS;
       entry = getprotobyname (SCM_ROCHARS (name));
     }
@@ -276,13 +343,14 @@ scm_getproto (name)
     }
   SCM_ALLOW_INTS;
   if (!entry)
-    scm_syserror (s_getproto);
+    scm_syserror_msg (s_getproto, "no such protocol %s",
+                     scm_listify (name, SCM_UNDEFINED), errno);
   ve[0] = scm_makfromstr (entry->p_name, (scm_sizet) strlen (entry->p_name), 0);
   ve[1] = scm_makfromstrs (-1, entry->p_aliases);
   ve[2] = SCM_MAKINUM (entry->p_proto + 0L);
   return ans;
 }
-
+#endif
 
 static SCM scm_return_entry SCM_P ((struct servent *entry));
 
@@ -293,7 +361,7 @@ scm_return_entry (entry)
   SCM ans;
   SCM *ve;
 
-  ans = scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED, SCM_BOOL_F);
+  ans = scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED);
   ve = SCM_VELTS (ans);
   ve[0] = scm_makfromstr (entry->s_name, (scm_sizet) strlen (entry->s_name), 0);
   ve[1] = scm_makfromstrs (-1, entry->s_aliases);
@@ -303,6 +371,7 @@ scm_return_entry (entry)
   return ans;
 }
 
+#ifdef HAVE_GETSERVENT
 SCM_PROC (s_getserv, "getserv", 0, 2, 0, scm_getserv);
 
 SCM 
@@ -314,15 +383,23 @@ scm_getserv (name, proto)
   if (SCM_UNBNDP (name))
     {
       SCM_DEFER_INTS;
+      errno = 0;
       entry = getservent ();
-      if (!entry)
-       scm_syserror (s_getserv);
       SCM_ALLOW_INTS;
+      if (!entry)
+       {
+         if (errno)
+           scm_syserror (s_getserv);
+         else
+           return SCM_BOOL_F;
+       }
       return scm_return_entry (entry);
     }
   SCM_ASSERT (SCM_NIMP (proto) && SCM_ROSTRINGP (proto), proto, SCM_ARG2, s_getserv);
+  SCM_COERCE_SUBSTR (proto);
   if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
     {
+      SCM_COERCE_SUBSTR (name);
       SCM_DEFER_INTS;
       entry = getservbyname (SCM_ROCHARS (name), SCM_ROCHARS (proto));
     }
@@ -333,11 +410,14 @@ scm_getserv (name, proto)
       entry = getservbyport (htons (SCM_INUM (name)), SCM_ROCHARS (proto));
     }
   if (!entry)
-    scm_syserror (s_getserv);
+    scm_syserror_msg (s_getserv, "no such service %s",
+                     scm_listify (name, SCM_UNDEFINED), errno);
   SCM_ALLOW_INTS;
   return scm_return_entry (entry);
 }
+#endif
 
+#if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
 SCM_PROC (s_sethost, "sethost", 0, 1, 0, scm_sethost);
 
 SCM 
@@ -350,7 +430,9 @@ scm_sethost (arg)
     sethostent (SCM_NFALSEP (arg));
   return SCM_UNSPECIFIED;
 }
+#endif
 
+#if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT) 
 SCM_PROC (s_setnet, "setnet", 0, 1, 0, scm_setnet);
 
 SCM 
@@ -363,7 +445,9 @@ scm_setnet (arg)
     setnetent (SCM_NFALSEP (arg));
   return SCM_UNSPECIFIED;
 }
+#endif
 
+#if defined(HAVE_SETPROTOENT) && defined(HAVE_ENDPROTOENT)
 SCM_PROC (s_setproto, "setproto", 0, 1, 0, scm_setproto);
 
 SCM 
@@ -376,7 +460,9 @@ scm_setproto (arg)
     setprotoent (SCM_NFALSEP (arg));
   return SCM_UNSPECIFIED;
 }
+#endif
 
+#if defined(HAVE_SETSERVENT) && defined(HAVE_ENDSERVENT)
 SCM_PROC (s_setserv, "setserv", 0, 1, 0, scm_setserv);
 
 SCM 
@@ -389,6 +475,7 @@ scm_setserv (arg)
     setservent (SCM_NFALSEP (arg));
   return SCM_UNSPECIFIED;
 }
+#endif
 
 
 void 
@@ -410,5 +497,3 @@ scm_init_net_db ()
   scm_add_feature ("net-db");
 #include "net_db.x"
 }
-
-