
Customs support: GNU make 3.75 can use the ICSI version of Customs
*almost* out of the box.  Alas, there remains one small, but fatal bug in
remote-cstms.c, having to do with right assignment of uid/euid for the
exported job.  Also, I retrofitted the code from an earlier patch that
allows the -l option to implicitly control the number of jobs run
locally before resorting to exportation (since exported jobs have an
overhead that is only worth it if more than one job can run in
parallel).  -l 0 forces exportation of all jobs, so the old behavior is
still available.

Finally, I couldn't get configure --with-customs to do the right
thing.  So I patched the Makefile by hand. This will require further
hand-editing of the CUSTOMSSRC path.

Included below is a patch to misc.c to allow setuid/setgid operation
of gnumake in SunOS5.x. Also, remake.c has been patched to deal with
systems that have only the SVR4 shared (.so) versions of system libraries,
but not the corresponding static libraries.

On NeXT's (with 2.1 software at least) config.h contains an incorrect
#define DIRENT 1.  This should be #define SYSDIR 1.

Finally, with newer versions of gnumake, make sure config.h contains
#define GETLOADAVG_PRIVILEGED 1
(not the default on NeXT and OSF1 systems).
This ensures that gnumake can switch between root and user id when
working with customs priviledged ports.

*** Makefile.in.orig	Wed Aug 28 14:13:09 1996
--- Makefile.in	Fri Aug 30 14:45:57 1996
***************
*** 46,52 ****
  
  # Which flavor of remote job execution support to use.
  # The code is found in `remote-$(REMOTE).c'.
! REMOTE = @REMOTE@
  
  # If your system doesn't have alloca, or the one provided is bad, define this.
  ALLOCA = @ALLOCA@
--- 46,53 ----
  
  # Which flavor of remote job execution support to use.
  # The code is found in `remote-$(REMOTE).c'.
! #REMOTE = @REMOTE@
! REMOTE = cstms
  
  # If your system doesn't have alloca, or the one provided is bad, define this.
  ALLOCA = @ALLOCA@
***************
*** 61,66 ****
--- 62,72 ----
  # Any extra object files your system needs.
  extras = @LIBOBJS@
  
+ CFLAGS += -I/usr/local/include/customs
+   
+   # Any extra object files your system needs.
+ LOADLIBES += -L/usr/local/lib -lcustoms
+ 
  # Common prefix for machine-independent installed files.
  prefix = @prefix@
  # Common prefix for machine-dependent installed files.
***************
*** 87,95 ****
  # The value should be either `true' or `false'.
  # On many systems, the getloadavg function (used to implement the `-l'
  # switch) will not work unless make is installed setgid kmem.
! install_setgid = @NEED_SETGID@
  # Install make setgid to this group so it can read /dev/kmem.
  group = @KMEM_GROUP@
  
  # Program to install `make'.
  INSTALL_PROGRAM = @INSTALL_PROGRAM@
--- 93,105 ----
  # The value should be either `true' or `false'.
  # On many systems, the getloadavg function (used to implement the `-l'
  # switch) will not work unless make is installed setgid kmem.
! #install_setgid = @NEED_SETGID@
! install_setgid = false
  # Install make setgid to this group so it can read /dev/kmem.
  group = @KMEM_GROUP@
+ # Install make suid root so it can use customs securely
+ install_setuid = true
+ user = root
  
  # Program to install `make'.
  INSTALL_PROGRAM = @INSTALL_PROGRAM@
***************
*** 178,183 ****
--- 188,202 ----
  
  $(bindir)/$(binprefix)make: make
  	$(INSTALL_PROGRAM) make $@.new
+ 	@if $(install_setuid); then \
+ 	   if chown $(user) $@.new && chmod u+s $@.new; then \
+ 	     echo "chown $(user) $@.new && chmod u+s $@.new"; \
+ 	   else \
+ 	     echo "$@ needs to be owned by user $(user) and setuid;"; \
+ 	     echo "otherwise remote job execution will probably not work."; \
+ 	     echo "You will need special priveleges to install $@."; \
+ 	   fi; \
+ 	 else true; fi
  	@if $(install_setgid); then \
  	   if chgrp $(group) $@.new && chmod g+s $@.new; then \
  	     echo "chgrp $(group) $@.new && chmod g+s $@.new"; \
*** job.c.orig	Sun Jul 14 12:57:14 1996
--- job.c	Fri Aug 30 14:54:02 1996
***************
*** 162,168 ****
  extern int getloadavg PARAMS ((double loadavg[], int nelem));
  extern int start_remote_job PARAMS ((char **argv, char **envp, int stdin_fd,
  		int *is_remote, int *id_ptr, int *used_stdin));
! extern int start_remote_job_p PARAMS ((void));
  extern int remote_status PARAMS ((int *exit_code_ptr, int *signal_ptr,
  		int *coredump_ptr, int block));
  
--- 162,168 ----
  extern int getloadavg PARAMS ((double loadavg[], int nelem));
  extern int start_remote_job PARAMS ((char **argv, char **envp, int stdin_fd,
  		int *is_remote, int *id_ptr, int *used_stdin));
! extern int start_remote_job_p PARAMS ((int));
  extern int remote_status PARAMS ((int *exit_code_ptr, int *signal_ptr,
  		int *coredump_ptr, int block));
  
***************
*** 537,543 ****
  			 Whether or not we want to changes over time.
  			 Also, start_remote_job may need state set up
  			 by start_remote_job_p.  */
! 		      c->remote = start_remote_job_p ();
  		      start_job_command (c);
  		      /* Fatal signals are left blocked in case we were
  			 about to put that child on the chain.  But it is
--- 537,543 ----
  			 Whether or not we want to changes over time.
  			 Also, start_remote_job may need state set up
  			 by start_remote_job_p.  */
! 		      c->remote = start_remote_job_p (0);
  		      start_job_command (c);
  		      /* Fatal signals are left blocked in case we were
  			 about to put that child on the chain.  But it is
***************
*** 866,872 ****
        if (start_remote_job (argv, child->environment,
  			    child->good_stdin ? 0 : bad_stdin,
  			    &is_remote, &id, &used_stdin))
! 	goto error;
        else
  	{
  	  if (child->good_stdin && !used_stdin)
--- 866,877 ----
        if (start_remote_job (argv, child->environment,
  			    child->good_stdin ? 0 : bad_stdin,
  			    &is_remote, &id, &used_stdin))
! 	/* Don't just give up here, since remote execution with customs
! 	 * may fail for all kinds of accidental reasons even after
! 	 * start_remote_job_p() has agreed to export the job.
! 	 * No big deal, just run the thing locally. */
! 	/* goto error; */
! 	goto start_local;
        else
  	{
  	  if (child->good_stdin && !used_stdin)
***************
*** 885,890 ****
--- 890,896 ----
  
        char **parent_environ;
  
+ start_local:
        block_sigs ();
  
        child->remote = 0;
***************
*** 1010,1016 ****
       the local load average.  We record that the job should be started
       remotely in C->remote for start_job_command to test.  */
  
!   c->remote = start_remote_job_p ();
  
    /* If this job is to be started locally, and we are already running
       some jobs, make this one wait if the load average is too high.  */
--- 1016,1022 ----
       the local load average.  We record that the job should be started
       remotely in C->remote for start_job_command to test.  */
  
!   c->remote = start_remote_job_p (1);
  
    /* If this job is to be started locally, and we are already running
       some jobs, make this one wait if the load average is too high.  */
*** make.h.orig	Sun Jul 14 09:30:11 1996
--- make.h	Fri Aug 30 15:03:38 1996
***************
*** 178,186 ****
--- 178,190 ----
  #include <memory.h>
  #endif
  
+ #if 0
  extern char *malloc PARAMS ((int));
  extern char *realloc PARAMS ((char *, int));
  extern void free PARAMS ((char *));
+ #else
+ #include <malloc.h>
+ #endif
  
  extern void abort PARAMS ((void));
  extern void exit PARAMS ((int));
*** misc.c.orig	Sat Jun 22 12:26:58 1996
--- misc.c	Fri Aug 30 13:13:51 1996
***************
*** 729,734 ****
--- 729,744 ----
    /* Set both the real and effective UID and GID to the user's.
       They cannot be changed back to make's.  */
  
+ #ifdef HAVE_SETEUID
+   /* Actually, to set the saved uid/gid as well we need to be root.
+      Normally this wouldn't matter since the exec clears the saved ids,
+      but it so happens that SunOS5.x has a bug that prevents exec-ing
+      csh-scripts unless the three ids are identical.  Note this
+      effectively forces make to be setuid root where setgid would have
+      been sufficient. */
+   (void)seteuid(0);
+ #endif /* HAVE_SETEUID */
+ 
  #ifndef	HAVE_SETREUID
    if (setuid (user_uid) < 0)
      pfatal_with_name ("child_access: setuid");
*** remake.c.orig	Sat Jul 20 04:06:40 1996
--- remake.c	Fri Aug 30 13:15:11 1996
***************
*** 1114,1120 ****
    time_t mtime;
  
    /* Buffer to construct possible names in.  */
!   char *buf = xmalloc (sizeof (LIBDIR) + 8 + strlen (libname) + 4 + 2 + 1);
    char *file, **dp;
  
    /* Look first for `libNAME.a' in the current directory.  */
--- 1114,1120 ----
    time_t mtime;
  
    /* Buffer to construct possible names in.  */
!   char *buf = xmalloc (sizeof (LIBDIR) + 8 + strlen (libname) + 4 + 3 + 1);
    char *file, **dp;
  
    /* Look first for `libNAME.a' in the current directory.  */
***************
*** 1125,1130 ****
--- 1125,1135 ----
    sprintf (buf, "%s.lib", libname);
  #endif
    mtime = name_mtime (buf);
+   if (mtime == (time_t) -1)
+     {
+       sprintf (buf, "lib%s.so", libname);
+       mtime = name_mtime (buf);
+     }
    if (mtime != (time_t) -1)
      {
        *lib = buf;
***************
*** 1135,1140 ****
--- 1140,1146 ----
  
    /* Now try VPATH search on that.  */
  
+   sprintf (buf, "lib%s.a", libname);
    file = buf;
    if (vpath_search (&file, mtime_ptr))
      {
***************
*** 1153,1158 ****
--- 1159,1169 ----
        sprintf (buf, "%s/%s.lib", *dp, libname);
  #endif
        mtime = name_mtime (buf);
+       if (mtime == (time_t) -1)
+ 	{
+           sprintf (buf, "%s/lib%s.so", *dp, libname);
+           mtime = name_mtime (buf);
+ 	}
        if (mtime != (time_t) -1)
  	{
  	  *lib = buf;
*** remote-cstms.c.orig	Wed Mar 23 06:14:17 1994
--- remote-cstms.c	Fri Aug 30 15:11:55 1996
***************
*** 26,35 ****
  #include <sys/time.h>
  #include <netdb.h>
  
- #define __STRICT_BSD__		/* Don't make conflicting declarations.  */
  #include "customs.h"
  
- 
  char *remote_description = "Customs";
  
  /* File name of the Customs `export' client command.
--- 26,33 ----
***************
*** 42,66 ****
  /* Normalized path name of the current directory.  */
  static char *normalized_cwd;
  
  /* Return nonzero if the next job should be done remotely.  */
  
  int
! start_remote_job_p ()
  {
    static int inited = 0;
    int status;
  
-   /* Allow the user to turn off job exportation
-      (useful while he is debugging Customs, for example).  */
-   if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0)
-     return 0;
- 
    if (!inited)
      {
        /* For secure Customs, make is installed setuid root and
  	 Customs requires a privileged source port be used.  */
        make_access ();
  
        /* Ping the daemon once to see if it is there.  */
        inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1;
  
--- 40,85 ----
  /* Normalized path name of the current directory.  */
  static char *normalized_cwd;
  
+ /* Call once at startup even if no commands are run.  */
+ 
+ void
+ remote_setup ()
+ {
+ }
+ 
+ /* Called before exit.  */
+ 
+ void
+ remote_cleanup ()
+ {
+ }
+ 
  /* Return nonzero if the next job should be done remotely.  */
  
  int
! start_remote_job_p (first_p)
!   int first_p;		/* is true if this the first command for a target */
  {
    static int inited = 0;
    int status;
+   int njobs;
  
    if (!inited)
      {
+       /* Allow the user to turn off job exportation
+ 	 (useful while he is debugging Customs, for example).  */
+       if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0) {
+ 	inited = -1;
+ 	return 0;
+       }
+ 
        /* For secure Customs, make is installed setuid root and
  	 Customs requires a privileged source port be used.  */
        make_access ();
  
+       if (debug_flag)
+ 	Rpc_Debug(1);
+ 
        /* Ping the daemon once to see if it is there.  */
        inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1;
  
***************
*** 87,92 ****
--- 106,120 ----
    if (inited < 0)
      return 0;
  
+   njobs = job_slots_used;
+   if (!first_p)
+     njobs -= 1;		/* correction for being called from reap_children() */
+ 
+   /* the first job should run locally, or, if the -l flag is given, we use
+      that as clue as to how many local jobs should be scheduled locally */
+   if (max_load_average < 0 && njobs == 0 || njobs < max_load_average)
+      return 0;
+ 
    status = Customs_Host (EXPORT_SAME, &permit);
    if (status != RPC_SUCCESS)
      {
***************
*** 113,120 ****
       int *id_ptr;
       int *used_stdin;
  {
-   extern int vfork (), execve ();
    char waybill[MAX_DATA_SIZE], msg[128];
    struct timeval timeout;
    struct sockaddr_in sin;
    int len;
--- 141,148 ----
       int *id_ptr;
       int *used_stdin;
  {
    char waybill[MAX_DATA_SIZE], msg[128];
+   struct hostent *host;
    struct timeval timeout;
    struct sockaddr_in sin;
    int len;
***************
*** 150,157 ****
    /* Modify the waybill as if the remote child had done `child_access ()'.  */
    {
      WayBill *wb = (WayBill *) waybill;
!     wb->euid = wb->ruid;
!     wb->rgid = wb->rgid;
    }
  
    /* Send the request to the server, timing out in 20 seconds.  */
--- 178,185 ----
    /* Modify the waybill as if the remote child had done `child_access ()'.  */
    {
      WayBill *wb = (WayBill *) waybill;
!     wb->ruid = wb->euid;
!     wb->rgid = wb->egid;
    }
  
    /* Send the request to the server, timing out in 20 seconds.  */
***************
*** 164,188 ****
  		     len, (Rpc_Opaque) waybill,
  		     sizeof(msg), (Rpc_Opaque) msg,
  		     1, &timeout);
    if (status != RPC_SUCCESS)
      {
        (void) close (retsock);
        (void) close (sock);
!       error ("exporting: %s", Rpc_ErrorMessage (status));
        return 1;
      }
    else if (msg[0] != 'O' || msg[1] != 'k' || msg[2] != '\0')
      {
        (void) close (retsock);
        (void) close (sock);
!       error ("CUSTOMS_IMPORT: %s", msg);
        return 1;
      }
!   else if (debug_flag)
      {
!       struct hostent *host = gethostbyaddr (&permit.addr, sizeof (permit.addr),
! 					    AF_INET);
!       printf ("Job exported to %s ID %u\n",
  	      host == 0 ? inet_ntoa (permit.addr) : host->h_name,
  	      permit.id);
      }
--- 192,222 ----
  		     len, (Rpc_Opaque) waybill,
  		     sizeof(msg), (Rpc_Opaque) msg,
  		     1, &timeout);
+ 
    if (status != RPC_SUCCESS)
      {
+       host = gethostbyaddr ((char *)&permit.addr, sizeof(permit.addr), AF_INET);
        (void) close (retsock);
        (void) close (sock);
!       error ("exporting to %s: %s",
! 	     host == 0 ? inet_ntoa (permit.addr) : host->h_name,
!              Rpc_ErrorMessage (status));
        return 1;
      }
    else if (msg[0] != 'O' || msg[1] != 'k' || msg[2] != '\0')
      {
+       host = gethostbyaddr ((char *)&permit.addr, sizeof(permit.addr), AF_INET);
        (void) close (retsock);
        (void) close (sock);
!       error ("exporting to %s: %s",
! 	     host == 0 ? inet_ntoa (permit.addr) : host->h_name,
! 	     msg);
        return 1;
      }
!   else 
      {
!       host = gethostbyaddr ((char *)&permit.addr, sizeof(permit.addr), AF_INET);
!       error ("*** exported to %s (id %u)",
  	      host == 0 ? inet_ntoa (permit.addr) : host->h_name,
  	      permit.id);
      }
***************
*** 225,230 ****
--- 259,265 ----
    (void) close (sock);
    *is_remote = 0;
    *id_ptr = pid;
+   *used_stdin = 1;
    return 0;
  }
  
