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