Home | History | Annotate | Download | only in make-3.81
      1 /* GNU Make remote job exportation interface to the Customs daemon.
      2    THIS CODE IS NOT SUPPORTED BY THE GNU PROJECT.
      3    Please do not send bug reports or questions about it to
      4    the Make maintainers.
      5 
      6 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
      7 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
      8 Foundation, Inc.
      9 This file is part of GNU Make.
     10 
     11 GNU Make is free software; you can redistribute it and/or modify it under the
     12 terms of the GNU General Public License as published by the Free Software
     13 Foundation; either version 2, or (at your option) any later version.
     14 
     15 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
     16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     17 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License along with
     20 GNU Make; see the file COPYING.  If not, write to the Free Software
     21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
     22 
     23 #include "make.h"
     24 #include "job.h"
     25 #include "filedef.h"
     26 #include "commands.h"
     27 #include "job.h"
     28 #include "debug.h"
     29 
     30 #include <sys/time.h>
     31 #include <netdb.h>
     32 
     33 #include "customs.h"
     34 
     35 char *remote_description = "Customs";
     36 
     37 /* File name of the Customs `export' client command.
     38    A full path name can be used to avoid some path-searching overhead.  */
     39 #define	EXPORT_COMMAND	"/usr/local/bin/export"
     40 
     41 /* ExportPermit gotten by start_remote_job_p, and used by start_remote_job.  */
     42 static ExportPermit permit;
     43 
     44 /* Normalized path name of the current directory.  */
     45 static char *normalized_cwd;
     46 
     47 /* Call once at startup even if no commands are run.  */
     48 
     49 void
     50 remote_setup (void)
     51 {
     52 }
     53 
     54 /* Called before exit.  */
     55 
     56 void
     57 remote_cleanup (void)
     58 {
     59 }
     60 
     61 /* Return nonzero if the next job should be done remotely.  */
     63 
     64 int
     65 start_remote_job_p (int first_p)
     66 {
     67   static int inited = 0;
     68   int status;
     69   int njobs;
     70 
     71   if (!inited)
     72     {
     73       /* Allow the user to turn off job exportation (useful while he is
     74          debugging Customs, for example).  */
     75       if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0)
     76         {
     77           inited = -1;
     78           return 0;
     79         }
     80 
     81       /* For secure Customs, make is installed setuid root and
     82 	 Customs requires a privileged source port be used.  */
     83       make_access ();
     84 
     85       if (ISDB (DB_JOBS))
     86         Rpc_Debug(1);
     87 
     88       /* Ping the daemon once to see if it is there.  */
     89       inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1;
     90 
     91       /* Return to normal user access.  */
     92       user_access ();
     93 
     94       if (starting_directory == 0)
     95 	/* main couldn't figure it out.  */
     96 	inited = -1;
     97       else
     98 	{
     99 	  /* Normalize the current directory path name to something
    100 	     that should work on all machines exported to.  */
    101 
    102 	  normalized_cwd = (char *) xmalloc (GET_PATH_MAX);
    103 	  strcpy (normalized_cwd, starting_directory);
    104 	  if (Customs_NormPath (normalized_cwd, GET_PATH_MAX) < 0)
    105 	    /* Path normalization failure means using Customs
    106 	       won't work, but it's not really an error.  */
    107 	    inited = -1;
    108 	}
    109     }
    110 
    111   if (inited < 0)
    112     return 0;
    113 
    114   njobs = job_slots_used;
    115   if (!first_p)
    116     njobs -= 1;		/* correction for being called from reap_children() */
    117 
    118   /* the first job should run locally, or, if the -l flag is given, we use
    119      that as clue as to how many local jobs should be scheduled locally */
    120   if (max_load_average < 0 && njobs == 0 || njobs < max_load_average)
    121      return 0;
    122 
    123   status = Customs_Host (EXPORT_SAME, &permit);
    124   if (status != RPC_SUCCESS)
    125     {
    126       DB (DB_JOBS, (_("Customs won't export: %s\n"),
    127                     Rpc_ErrorMessage (status)));
    128       return 0;
    129     }
    130 
    131   return !CUSTOMS_FAIL (&permit.addr);
    132 }
    133 
    134 /* Start a remote job running the command in ARGV, with environment from
    136    ENVP.  It gets standard input from STDIN_FD.  On failure, return
    137    nonzero.  On success, return zero, and set *USED_STDIN to nonzero if it
    138    will actually use STDIN_FD, zero if not, set *ID_PTR to a unique
    139    identification, and set *IS_REMOTE to nonzero if the job is remote, zero
    140    if it is local (meaning *ID_PTR is a process ID).  */
    141 
    142 int
    143 start_remote_job (char **argv, char **envp, int stdin_fd,
    144                   int *is_remote, int *id_ptr, int *used_stdin)
    145 {
    146   char waybill[MAX_DATA_SIZE], msg[128];
    147   struct hostent *host;
    148   struct timeval timeout;
    149   struct sockaddr_in sin;
    150   int len;
    151   int retsock, retport, sock;
    152   Rpc_Stat status;
    153   int pid;
    154 
    155   /* Create the return socket.  */
    156   retsock = Rpc_UdpCreate (True, 0);
    157   if (retsock < 0)
    158     {
    159       error (NILF, "exporting: Couldn't create return socket.");
    160       return 1;
    161     }
    162 
    163   /* Get the return socket's port number.  */
    164   len = sizeof (sin);
    165   if (getsockname (retsock, (struct sockaddr *) &sin, &len) < 0)
    166     {
    167       (void) close (retsock);
    168       perror_with_name ("exporting: ", "getsockname");
    169       return 1;
    170     }
    171   retport = sin.sin_port;
    172 
    173   /* Create the TCP socket for talking to the remote child.  */
    174   sock = Rpc_TcpCreate (False, 0);
    175 
    176   /* Create a WayBill to give to the server.  */
    177   len = Customs_MakeWayBill (&permit, normalized_cwd, argv[0], argv,
    178 			     envp, retport, waybill);
    179 
    180   /* Modify the waybill as if the remote child had done `child_access ()'.  */
    181   {
    182     WayBill *wb = (WayBill *) waybill;
    183     wb->ruid = wb->euid;
    184     wb->rgid = wb->egid;
    185   }
    186 
    187   /* Send the request to the server, timing out in 20 seconds.  */
    188   timeout.tv_usec = 0;
    189   timeout.tv_sec = 20;
    190   sin.sin_family = AF_INET;
    191   sin.sin_port = htons (Customs_Port ());
    192   sin.sin_addr = permit.addr;
    193   status = Rpc_Call (sock, &sin, (Rpc_Proc) CUSTOMS_IMPORT,
    194 		     len, (Rpc_Opaque) waybill,
    195 		     sizeof(msg), (Rpc_Opaque) msg,
    196 		     1, &timeout);
    197 
    198   host = gethostbyaddr((char *)&permit.addr, sizeof(permit.addr), AF_INET);
    199 
    200   if (status != RPC_SUCCESS)
    201     {
    202       (void) close (retsock);
    203       (void) close (sock);
    204       error (NILF, "exporting to %s: %s",
    205              host ? host->h_name : inet_ntoa (permit.addr),
    206              Rpc_ErrorMessage (status));
    207       return 1;
    208     }
    209   else if (msg[0] != 'O' || msg[1] != 'k' || msg[2] != '\0')
    210     {
    211       (void) close (retsock);
    212       (void) close (sock);
    213       error (NILF, "exporting to %s: %s",
    214              host ? host->h_name : inet_ntoa (permit.addr),
    215              msg);
    216       return 1;
    217     }
    218   else
    219     {
    220       error (NILF, "*** exported to %s (id %u)",
    221 	      host ? host->h_name : inet_ntoa (permit.addr),
    222 	      permit.id);
    223     }
    224 
    225   fflush (stdout);
    226   fflush (stderr);
    227 
    228   pid = vfork ();
    229   if (pid < 0)
    230     {
    231       /* The fork failed!  */
    232       perror_with_name ("vfork", "");
    233       return 1;
    234     }
    235   else if (pid == 0)
    236     {
    237       /* Child side.  Run `export' to handle the connection.  */
    238       static char sock_buf[20], retsock_buf[20], id_buf[20];
    239       static char *new_argv[6] =
    240 	{ EXPORT_COMMAND, "-id", sock_buf, retsock_buf, id_buf, 0 };
    241 
    242       /* Set up the arguments.  */
    243       (void) sprintf (sock_buf, "%d", sock);
    244       (void) sprintf (retsock_buf, "%d", retsock);
    245       (void) sprintf (id_buf, "%x", permit.id);
    246 
    247       /* Get the right stdin.  */
    248       if (stdin_fd != 0)
    249 	(void) dup2 (stdin_fd, 0);
    250 
    251       /* Unblock signals in the child.  */
    252       unblock_sigs ();
    253 
    254       /* Run the command.  */
    255       exec_command (new_argv, envp);
    256     }
    257 
    258   /* Parent side.  Return the `export' process's ID.  */
    259   (void) close (retsock);
    260   (void) close (sock);
    261   *is_remote = 0;
    262   *id_ptr = pid;
    263   *used_stdin = 1;
    264   return 0;
    265 }
    266 
    267 /* Get the status of a dead remote child.  Block waiting for one to die
    269    if BLOCK is nonzero.  Set *EXIT_CODE_PTR to the exit status, *SIGNAL_PTR
    270    to the termination signal or zero if it exited normally, and *COREDUMP_PTR
    271    nonzero if it dumped core.  Return the ID of the child that died,
    272    0 if we would have to block and !BLOCK, or < 0 if there were none.  */
    273 
    274 int
    275 remote_status (int *exit_code_ptr, int *signal_ptr, int *coredump_ptr,
    276                int block)
    277 {
    278   return -1;
    279 }
    280 
    281 /* Block asynchronous notification of remote child death.
    282    If this notification is done by raising the child termination
    283    signal, do not block that signal.  */
    284 void
    285 block_remote_children (void)
    286 {
    287   return;
    288 }
    289 
    290 /* Restore asynchronous notification of remote child death.
    291    If this is done by raising the child termination signal,
    292    do not unblock that signal.  */
    293 void
    294 unblock_remote_children (void)
    295 {
    296   return;
    297 }
    298 
    299 /* Send signal SIG to child ID.  Return 0 if successful, -1 if not.  */
    300 int
    301 remote_kill (int id, int sig)
    302 {
    303   return -1;
    304 }
    305