Try at first if last client handle works.
authordrepper <drepper>
Tue, 28 Jul 1998 13:52:32 +0000 (13:52 +0000)
committerdrepper <drepper>
Tue, 28 Jul 1998 13:52:32 +0000 (13:52 +0000)
nis/nis_lookup.c
nis/nis_table.c

index 6a2198a..df16cce 100644 (file)
 nis_result *
 nis_lookup (const_nis_name name, const u_long flags)
 {
-  nis_result *res;
+  nis_result *res = calloc (1, sizeof (nis_result));
   struct ns_request req;
   nis_name *names;
   nis_error status;
+  int link_first_try = 0;
   int count_links = 0;  /* We will follow only 16 links in the deep */
   int done = 0;
   int name_nr = 0;
   nis_name namebuf[2] = {NULL, NULL};
 
-  res = calloc (1, sizeof (nis_result));
   if (res == NULL)
     return NULL;
 
-  if (flags & EXPAND_NAME)
+  if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.'))
     {
       names = nis_getnames (name);
       if (names == NULL)
@@ -56,51 +56,141 @@ nis_lookup (const_nis_name name, const u_long flags)
   req.ns_name = names[0];
   while (!done)
     {
+      dir_binding bptr;
+      directory_obj *dir = NULL;
       req.ns_object.ns_object_len = 0;
       req.ns_object.ns_object_val = NULL;
-      memset (res, '\0', sizeof (nis_result));
 
-      status = __do_niscall (req.ns_name, NIS_LOOKUP,
-                            (xdrproc_t) _xdr_ns_request,
-                            (caddr_t) & req,
-                            (xdrproc_t) _xdr_nis_result,
-                            (caddr_t) res, flags, NULL);
+      status = __nisfind_server (req.ns_name, &dir);
       if (status != NIS_SUCCESS)
-       NIS_RES_STATUS (res) = status;
+       {
+         NIS_RES_STATUS (res) = status;
+         return res;
+       }
 
-      switch (NIS_RES_STATUS (res))
+      status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+                                dir->do_servers.do_servers_len, flags);
+      if (status != NIS_SUCCESS)
        {
-       case NIS_PARTIAL:
-       case NIS_SUCCESS:
-       case NIS_S_SUCCESS:
-         if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
-             flags & FOLLOW_LINKS) /* We are following links */
+         NIS_RES_STATUS (res) = status;
+         nis_free_directory (dir);
+         return res;
+       }
+
+      while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+       {
+         if (__nisbind_next (&bptr) != NIS_SUCCESS)
+           {
+             __nisbind_destroy (&bptr);
+             nis_free_directory (dir);
+             NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+             return res;
+           }
+       }
+
+      do
+       {
+         static struct timeval RPCTIMEOUT = {10, 0};
+         enum clnt_stat result;
+
+       again:
+         result = clnt_call (bptr.clnt, NIS_LOOKUP,
+                             (xdrproc_t) _xdr_ns_request,
+                             (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
+                             (caddr_t) res, RPCTIMEOUT);
+
+         if (result != RPC_SUCCESS)
+           status = NIS_RPCERROR;
+         else
            {
-             /* if we hit the link limit, bail */
-             if (count_links > NIS_MAXLINKS)
+             if (NIS_RES_STATUS (res) == NIS_SUCCESS)
                {
-                 NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
-                 ++done;
-                 break;
+                   if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
+                       flags & FOLLOW_LINKS) /* We are following links */
+                     {
+                       if (count_links)
+                         free (req.ns_name);
+                       /* if we hit the link limit, bail */
+                       if (count_links > NIS_MAXLINKS)
+                         {
+                           NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+                           break;
+                         }
+                       ++count_links;
+                       req.ns_name =
+                         strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+                       nis_freeresult (res);
+                       res = calloc (1, sizeof (nis_result));
+                       if (res == NULL)
+                         {
+                           __nisbind_destroy (&bptr);
+                           nis_free_directory (dir);
+                           return NULL;
+                         }
+                       link_first_try = 1; /* Try at first the old binding */
+                       goto again;
+                     }
                }
-             if (count_links)
-               free (req.ns_name);
-             ++count_links;
-             req.ns_name = strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
-             nis_freeresult (res);
-             res = calloc (1, sizeof (nis_result));
-             if (res == NULL)
-               return NULL;
+             else
+               if ((NIS_RES_STATUS (res) == NIS_SYSTEMERROR) ||
+                   (NIS_RES_STATUS (res) == NIS_NOSUCHNAME) ||
+                   (NIS_RES_STATUS (res) == NIS_NOT_ME))
+                 {
+                   if (link_first_try)
+                     {
+                       __nisbind_destroy (&bptr);
+                       nis_free_directory (dir);
+
+                       if (__nisfind_server (req.ns_name, &dir) != NIS_SUCCESS)
+                         return res;
+
+                       if (__nisbind_create (&bptr,
+                                             dir->do_servers.do_servers_val,
+                                             dir->do_servers.do_servers_len,
+                                             flags) != NIS_SUCCESS)
+                         {
+                           nis_free_directory (dir);
+                           return res;
+                         }
+                     }
+                   else
+                     if (__nisbind_next (&bptr) != NIS_SUCCESS)
+                       break; /* No more servers to search */
+
+                   while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+                     {
+                       if (__nisbind_next (&bptr) != NIS_SUCCESS)
+                         {
+                           __nisbind_destroy (&bptr);
+                           nis_free_directory (dir);
+                           return res;
+                         }
+                     }
+                   goto again;
+                 }
+             break;
            }
-         else
-           ++done;
-         break;
-       case NIS_CBRESULTS:
-         /* The callback is handled in __do_niscall2 */
-         ++done;
-         break;
-       case NIS_UNAVAIL:
-         /* NIS+ is not installed, or all servers are down */
+         link_first_try = 0; /* Set it back */
+         status= NIS_SUCCESS;
+       }
+      while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR);
+
+      __nisbind_destroy (&bptr);
+      nis_free_directory (dir);
+
+      if (status != NIS_SUCCESS)
+       {
+         NIS_RES_STATUS (res) = status;
+         return res;
+       }
+
+      switch (NIS_RES_STATUS (res))
+       {
+       case NIS_PARTIAL:
+       case NIS_SUCCESS:
+       case NIS_S_SUCCESS:
+       case NIS_LINKNAMEERROR: /* We follow to max links */
+       case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */
          ++done;
          break;
        default:
index ed4b374..e0885ca 100644 (file)
@@ -110,6 +110,40 @@ __create_ib_request (const_nis_name name, u_long flags)
   return ibreq;
 }
 
+static struct timeval RPCTIMEOUT = {10, 0};
+
+static char *
+__get_tablepath (char *name, dir_binding *bptr)
+{
+  enum clnt_stat result;
+  nis_result *res = calloc (1, sizeof (nis_result));
+  struct ns_request req;
+
+  if (res == NULL)
+    return NULL;
+
+  req.ns_name = name;
+  req.ns_object.ns_object_len = 0;
+  req.ns_object.ns_object_val = NULL;
+
+  result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
+                     (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
+                     (caddr_t) res, RPCTIMEOUT);
+
+  if (result == RPC_SUCCESS && NIS_RES_STATUS (res) == NIS_SUCCESS &&
+      __type_of (NIS_RES_OBJECT (res)) == NIS_TABLE_OBJ)
+    {
+      char *cptr = strdup (NIS_RES_OBJECT (res)->TA_data.ta_path);
+      nis_freeresult (res);
+      return cptr;
+    }
+  else
+    {
+      nis_freeresult (res);
+      return strdup ("");
+    }
+}
+
 nis_result *
 nis_list (const_nis_name name, u_long flags,
          int (*callback) (const_nis_name name,
@@ -120,12 +154,16 @@ nis_list (const_nis_name name, u_long flags,
   nis_result *res = NULL;
   ib_request *ibreq;
   int status;
+  enum clnt_stat clnt_status;
   int count_links = 0;         /* We will only follow NIS_MAXLINKS links! */
   int done = 0;
   nis_name *names;
   nis_name namebuf[2] = {NULL, NULL};
   int name_nr = 0;
   nis_cb *cb = NULL;
+  char *tableptr, *tablepath = NULL;
+  int have_tablepath = 0;
+  int first_try = 0; /* Do we try the old binding at first ? */
 
   res = calloc (1, sizeof (nis_result));
   if (res == NULL)
@@ -164,189 +202,230 @@ nis_list (const_nis_name name, u_long flags,
 
   cb = NULL;
 
-  if (flags & FOLLOW_PATH || flags & ALL_RESULTS)
+  while (!done)
     {
-      nis_result *lres;
-      u_long newflags = flags & ~FOLLOW_PATH & ~ALL_RESULTS;
-      char table_path[NIS_MAXPATH + 3];
-      char *ntable, *p;
-      u_long done = 0, failures = 0;
-
-      while (names[name_nr] != NULL && !done)
-       {
-         lres = nis_lookup (names[name_nr], newflags | NO_AUTHINFO);
-         if (lres == NULL || NIS_RES_STATUS (lres) != NIS_SUCCESS)
-           {
-             NIS_RES_STATUS (res) = NIS_RES_STATUS (lres);
-             nis_freeresult (lres);
-             ++name_nr;
-             continue;
-           }
-
-         /* nis_lookup handles FOLLOW_LINKS,
-            so we must have a table object.*/
-         if (__type_of (NIS_RES_OBJECT (lres)) != NIS_TABLE_OBJ)
-           {
-             nis_freeresult (lres);
-             NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
-             break;
-           }
+      dir_binding bptr;
+      directory_obj *dir = NULL;
 
-         /* Save the path, discard everything else.  */
-         p = __stpncpy (table_path, names[name_nr], NIS_MAXPATH);
-         *p++ = ':';
-         p = __stpncpy (p, NIS_RES_OBJECT (lres)->TA_data.ta_path,
-                        NIS_MAXPATH - (p - table_path));
-         *p = '\0';
-         nis_freeresult (lres);
-         free (res);
-         res = NULL;
+      memset (res, '\0', sizeof (nis_result));
 
-         p = table_path;
+      status = __nisfind_server (ibreq->ibr_name, &dir);
+      if (status != NIS_SUCCESS)
+        {
+          NIS_RES_STATUS (res) = status;
+          return res;
+        }
 
-         while (((ntable = strsep (&p, ":")) != NULL) && !done)
-           {
-             char *c;
+      status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+                                 dir->do_servers.do_servers_len, flags);
+      if (status != NIS_SUCCESS)
+        {
+          NIS_RES_STATUS (res) = status;
+          nis_free_directory (dir);
+          return res;
+        }
 
-             if (res != NULL)
-               nis_freeresult (res);
+      while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+       if (__nisbind_next (&bptr) != NIS_SUCCESS)
+         {
+           __nisbind_destroy (&bptr);
+           nis_free_directory (dir);
+           NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+           return res;
+         }
 
-             /* Do the job recursive here!  */
-             if ((c = strchr(name, ']')) != NULL)
-               {
-                 /* Have indexed name ! */
-                 int index_len = c - name + 2;
-                 char buf[index_len + strlen (ntable) + 1];
-
-                 c = __stpncpy (buf, name, index_len);
-                 strcpy (c, ntable);
-                 res = nis_list (buf, newflags, callback,userdata);
-               }
-             else
-               res = nis_list (ntable, newflags, callback, userdata);
-             if (res == NULL)
-               return NULL;
-             switch (NIS_RES_STATUS (res))
-               {
-               case NIS_SUCCESS:
-               case NIS_CBRESULTS:
-                 if (!(flags & ALL_RESULTS))
-                   done = 1;
-                 break;
-               case NIS_PARTIAL: /* The table is correct, we doesn't found
-                                    the entry */
-                 break;
-               default:
-                 if (flags & ALL_RESULTS)
-                   ++failures;
-                 else
-                   done = 1;
-                 break;
-               }
-           }
-         if (NIS_RES_STATUS (res) == NIS_SUCCESS && failures)
-           NIS_RES_STATUS (res) = NIS_S_SUCCESS;
-         if (NIS_RES_STATUS (res) == NIS_NOTFOUND && failures)
-           NIS_RES_STATUS (res) = NIS_S_NOTFOUND;
-         break;
-       }
-    }
-  else
-    {
       if (callback != NULL)
        {
          cb = __nis_create_callback (callback, userdata, flags);
          ibreq->ibr_cbhost.ibr_cbhost_len = 1;
          ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
-         }
-
-      while (!done)
-       {
-         memset (res, '\0', sizeof (nis_result));
-
-         status = __do_niscall (ibreq->ibr_name, NIS_IBLIST,
-                                (xdrproc_t) _xdr_ib_request,
-                                (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
-                                (caddr_t) res, flags, cb);
-         if (status != NIS_SUCCESS)
-           NIS_RES_STATUS (res) = status;
+       }
 
-         switch (NIS_RES_STATUS (res))
-           {
-           case NIS_PARTIAL:
-           case NIS_SUCCESS:
-           case NIS_S_SUCCESS:
-             if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
-                 flags & FOLLOW_LINKS)         /* We are following links.  */
-               {
-                 /* If we hit the link limit, bail.  */
-                 if (count_links > NIS_MAXLINKS)
+    again:
+      clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
+                              (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
+                              (xdrproc_t) _xdr_nis_result,
+                              (caddr_t) res, RPCTIMEOUT);
+
+      if (clnt_status != RPC_SUCCESS)
+       NIS_RES_STATUS (res) = NIS_RPCERROR;
+      else
+       switch (NIS_RES_STATUS (res))
+         { /* start switch */
+         case NIS_PARTIAL:
+         case NIS_SUCCESS:
+         case NIS_S_SUCCESS:
+           if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
+               flags & FOLLOW_LINKS)           /* We are following links.  */
+             {
+               free (ibreq->ibr_name);
+               /* If we hit the link limit, bail.  */
+               if (count_links > NIS_MAXLINKS)
+                 {
+                   NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+                   ++done;
+                   break;
+                 }
+               ++count_links;
+               ibreq->ibr_name =
+                 strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+               if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
+                 if (ibreq->ibr_srch.ibr_srch_len == 0)
                    {
-                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
-                     ++done;
-                     break;
+                     ibreq->ibr_srch.ibr_srch_len =
+                       NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
+                     ibreq->ibr_srch.ibr_srch_val =
+                       NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
                    }
-                 if (count_links)
-                   free (ibreq->ibr_name);
-                 ++count_links;
-                 free (ibreq->ibr_name);
-                 ibreq->ibr_name =
-                   strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
-                 if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
-                   if (ibreq->ibr_srch.ibr_srch_len == 0)
+               nis_freeresult (res);
+               res = calloc (1, sizeof (nis_result));
+               if (res == NULL)
+                 {
+                   if (have_tablepath)
+                     free (tablepath);
+                   __nisbind_destroy (&bptr);
+                   nis_free_directory (dir);
+                   return NULL;
+                 }
+               first_try = 1; /* Try at first the old binding */
+               goto again;
+             }
+           else if ((flags & FOLLOW_PATH) &&
+                    NIS_RES_STATUS (res) == NIS_PARTIAL)
+             {
+               if (!have_tablepath)
+                 {
+                   tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
+                   tableptr = tablepath;
+                   have_tablepath = 1;
+                 }
+               if (tableptr == NULL)
+                 {
+                   ++done;
+                   break;
+                 }
+               free (ibreq->ibr_name);
+               ibreq->ibr_name = strsep (&tableptr, ":");
+               if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
+                 {
+                   ibreq->ibr_name = strdup ("");
+                   ++done;
+                 }
+               else
+                 {
+                   ibreq->ibr_name = strdup (ibreq->ibr_name);
+                   nis_freeresult (res);
+                   res = calloc (1, sizeof (nis_result));
+                   if (res == NULL)
                      {
-                       ibreq->ibr_srch.ibr_srch_len =
-                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
-                       ibreq->ibr_srch.ibr_srch_val =
-                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
+                       if (have_tablepath)
+                         free (tablepath);
+                       __nisbind_destroy (&bptr);
+                       nis_free_directory (dir);
+                       return NULL;
                      }
-                 nis_freeresult (res);
-                 res = calloc (1, sizeof (nis_result));
-               }
-             else
-               ++done;
-             break;
-           case NIS_CBRESULTS:
-             /* Calback is handled in nis_call.c (__do_niscall2),
-                but we have to change the error code */
-             NIS_RES_STATUS (res) = cb->result;
+                   first_try = 1;
+                   goto again;
+                 }
+             }
+           else
              ++done;
-             break;
-           case NIS_UNAVAIL:
-             /* NIS+ is not installed, or all servers are down.  */
-             ++done;
-             break;
-           default:
-             /* Try the next domainname if we don't follow a link.  */
-             if (count_links)
-               {
-                 free (ibreq->ibr_name);
-                 NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
-                 ++done;
-                 break;
-               }
-             ++name_nr;
-             if (names[name_nr] == NULL)
-               {
+           break;
+         case NIS_CBRESULTS:
+           if (cb != NULL)
+             {
+               __nis_do_callback (&bptr, &res->cookie, cb);
+               NIS_RES_STATUS (res) = cb->result;
+
+               if (!(flags & ALL_RESULTS))
                  ++done;
-                 break;
-               }
-             ibreq->ibr_name = names[name_nr];
-             break;
-           }
+               else
+                 {
+                   if (!have_tablepath)
+                     {
+                       tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
+                       tableptr = tablepath;
+                       have_tablepath = 1;
+                     }
+                   if (tableptr == NULL)
+                     {
+                       ++done;
+                       break;
+                     }
+                   free (ibreq->ibr_name);
+                   ibreq->ibr_name = strsep (&tableptr, ":");
+                   if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
+                     {
+                       ibreq->ibr_name = strdup ("");
+                       ++done;
+                     }
+                   else
+                     ibreq->ibr_name = strdup (ibreq->ibr_name);
+                 }
+             }
+           break;
+         case NIS_SYSTEMERROR:
+         case NIS_NOSUCHNAME:
+         case NIS_NOT_ME:
+           /* If we had first tried the old binding, do nothing, but
+              get a new binding */
+           if (!first_try)
+             {
+               if (__nisbind_next (&bptr) != NIS_SUCCESS)
+                 {
+                   ++done;
+                   break; /* No more servers to search */
+                 }
+               while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+                 {
+                   if (__nisbind_next (&bptr) != NIS_SUCCESS)
+                     {
+                       ++done;
+                       break; /* No more servers to search */
+                     }
+                 }
+               goto again;
+             }
+           break;
+         default:
+           if (!first_try)
+             {
+               /* Try the next domainname if we don't follow a link.  */
+               if (count_links)
+                 {
+                   free (ibreq->ibr_name);
+                   NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+                   ++done;
+                   break;
+                 }
+               ++name_nr;
+               if (names[name_nr] == NULL)
+                 {
+                   ++done;
+                   break;
+                 }
+               ibreq->ibr_name = names[name_nr];
+               first_try = 1; /* Try old binding at first */
+               goto again;
+             }
+           break;
+         }
+      first_try = 0;
+
+      if (cb)
+       {
+         __nis_destroy_callback (cb);
+         ibreq->ibr_cbhost.ibr_cbhost_len = 0;
+         ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
        }
-    }                          /* End of not FOLLOW_PATH.  */
+
+      __nisbind_destroy (&bptr);
+      nis_free_directory (dir);
+    }
 
   if (names != namebuf)
     nis_freenames (names);
 
-  if (cb)
-    {
-      __nis_destroy_callback (cb);
-      ibreq->ibr_cbhost.ibr_cbhost_len = 0;
-      ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
-    }
-
   nis_free_request (ibreq);
 
   return res;