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