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