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. */ 62 63 int 64 start_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 140 int 141 start_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 271 int 272 remote_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. */ 281 void 282 block_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. */ 290 void 291 unblock_remote_children (void) 292 { 293 return; 294 } 295 296 /* Send signal SIG to child ID. Return 0 if successful, -1 if not. */ 297 int 298 remote_kill (int id, int sig) 299 { 300 return -1; 301 } 302