VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/submit.c@ 2840

Last change on this file since 2840 was 2840, checked in by bird, 9 years ago

work in progress

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.4 KB
Line 
1/* $Id: submit.c 2840 2016-08-25 21:47:04Z bird $ */
2/** @file
3 * kMk Builtin command - submit job to a kWorker.
4 */
5
6/*
7 * Copyright (c) 2007-2016 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#ifdef __APPLE__
30# define _POSIX_C_SOURCE 1 /* 10.4 sdk and unsetenv */
31#endif
32#include "make.h"
33#include "job.h"
34#include "variable.h"
35#include "pathstuff.h"
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <errno.h>
40#ifdef HAVE_ALLOCA_H
41# include <alloca.h>
42#endif
43#if defined(_MSC_VER)
44# include <ctype.h>
45# include <io.h>
46# include <direct.h>
47# include <process.h>
48#else
49# include <unistd.h>
50#endif
51
52#include "kmkbuiltin.h"
53#include "err.h"
54
55#ifdef __OS2__
56# define INCL_BASE
57# include <os2.h>
58# ifndef LIBPATHSTRICT
59# define LIBPATHSTRICT 3
60# endif
61#endif
62
63/*********************************************************************************************************************************
64* Structures and Typedefs *
65*********************************************************************************************************************************/
66typedef struct WORKERINSTANCE *PWORKERINSTANCE;
67typedef struct WORKERINSTANCE
68{
69 /** Pointer to the next worker instance. */
70 PWORKERINSTANCE pNext;
71 /** Pointer to the previous worker instance. */
72 PWORKERINSTANCE pPrev;
73 /** 32 or 64. */
74 unsigned cBits;
75 /** The process handle. */
76 HANDLE hProcess;
77
78} WORKERINSTANCE;
79
80
81/*********************************************************************************************************************************
82* Global Variables *
83*********************************************************************************************************************************/
84static PWORKERINSTANCE g_pIdleHead;
85static PWORKERINSTANCE g_pIdleTail;
86
87
88
89static int usage(FILE *pOut, const char *argv0)
90{
91 fprintf(pOut,
92 "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
93 " [-C|--chdir <dir>] [--wcc-brain-damage]\n"
94 " [-3|--32-bit] [-6|--64-bit] [-v] -- <program> [args]\n"
95 " or: %s --help\n"
96 " or: %s --version\n"
97 "\n"
98 "Options:\n"
99 " -Z, --zap-env, -i, --ignore-environment\n"
100 " Zaps the environment. Position dependent.\n"
101 " -E, --set <var>=[value]\n"
102 " Sets an enviornment variable putenv fashion. Position dependent.\n"
103 " -U, --unset <var>\n"
104 " Removes an environment variable. Position dependent.\n"
105 " -C, --chdir <dir>\n"
106 " Specifies the current directory for the program. Relative paths\n"
107 " are relative to the previous -C option. Default is getcwd value.\n"
108 " -3, --32-bit\n"
109 " Selects a 32-bit kWorker process. Default: kmk bit count\n"
110 " -6, --64-bit\n"
111 " Selects a 64-bit kWorker process. Default: kmk bit count\n"
112 " --wcc-brain-damage\n"
113 " Works around wcc and wcc386 (Open Watcom) not following normal\n"
114 " quoting conventions on Windows, OS/2, and DOS.\n"
115 " -v,--verbose\n"
116 " More verbose execution.\n"
117 " -V,--version\n"
118 " Show the version number.\n"
119 " -h,--help\n"
120 " Show this usage information.\n"
121 "\n"
122 ,
123 argv0, argv0, argv0);
124 return 1;
125}
126
127
128int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild)
129{
130 int rcExit = 0;
131 int iArg;
132 unsigned cAllocatedEnvVars;
133 unsigned iEnvVar;
134 unsigned cEnvVars;
135 char **papszEnv = NULL;
136 const char *pszCwd = NULL;
137 unsigned cBitsWorker = 0;
138 int fWatcomBrainDamage = 0;
139 int cVerbosity = 0;
140 size_t const cbCwdBuf = GET_PATH_MAX;
141 PATH_VAR(szCwd);
142
143 g_progname = argv[0];
144
145 /*
146 * Create default program environment.
147 */
148 if (getcwd_fs(szCwd, cbCwdBuf) != NULL)
149 { /* likely */ }
150 else
151 return err(1, "getcwd_fs failed\n");
152
153 papszEnv = pChild->environment;
154 if (papszEnv)
155 pChild->environment = papszEnv = target_environment(pChild->file);
156 cEnvVars = 0;
157 while (papszEnv[cEnvVars] != NULL)
158 cEnvVars++;
159 cAllocatedEnvVars = cEnvVars;
160
161 /*
162 * Parse the command line.
163 */
164 for (iArg = 1; iArg < argc; iArg++)
165 {
166 const char *pszArg = argv[iArg];
167 if (*pszArg == '-')
168 {
169 char chOpt = *++pszArg;
170 if (chOpt != '-')
171 {
172 if (chOpt != '\0')
173 { /* likely */ }
174 else
175 {
176 errx(1, "Incomplete option: '-'");
177 return usage(stderr, argv[0]);
178 }
179 }
180 else
181 {
182 pszArg++;
183
184 /* '--' indicates where the bits to execute start. */
185 if (*pszArg == '\0')
186 {
187 iArg++;
188 break;
189 }
190
191 if (strcmp(pszArg, "watcom-brain-damage") == 0)
192 {
193 fWatcomBrainDamage = 1;
194 continue;
195 }
196
197 /* convert to short. */
198 if (strcmp(pszArg, "help") == 0)
199 chOpt = 'h';
200 else if (strcmp(pszArg, "version") == 0)
201 chOpt = 'V';
202 else if (strcmp(pszArg, "set") == 0)
203 chOpt = 'E';
204 else if (strcmp(pszArg, "unset") == 0)
205 chOpt = 'U';
206 else if ( strcmp(pszArg, "zap-env") == 0
207 || strcmp(pszArg, "ignore-environment") == 0 /* GNU env compatibility. */ )
208 chOpt = 'Z';
209 else if (strcmp(pszArg, "chdir") == 0)
210 chOpt = 'C';
211 else if (strcmp(pszArg, "32-bit") == 0)
212 chOpt = '3';
213 else if (strcmp(pszArg, "64-bit") == 0)
214 chOpt = '6';
215 else if (strcmp(pszArg, "verbose") == 0)
216 chOpt = 'v';
217 else
218 {
219 errx(1, "Unknown option: '%s'", pszArg - 2);
220 return usage(stderr, argv[0]);
221 }
222 pszArg = "";
223 }
224
225 do
226 {
227 /* Get option value first, if the option takes one. */
228 const char *pszValue = NULL;
229 switch (chOpt)
230 {
231 case 'E':
232 case 'U':
233 case 'C':
234 if (*pszArg != '\0')
235 pszValue = pszArg + (*pszArg == ':' || *pszArg == '=');
236 else if (++iArg < argc)
237 pszValue = argv[iArg];
238 else
239 {
240 errx(1, "Option -%c requires an value!", chOpt);
241 return usage(stderr, argv[0]);
242 }
243 break;
244 }
245
246 switch (chOpt)
247 {
248 case 'Z':
249 case 'i': /* GNU env compatibility. */
250 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
251 free(papszEnv[iEnvVar]);
252 papszEnv[0] = NULL;
253 cEnvVars = 0;
254 break;
255
256 case 'E':
257 {
258 const char *pszEqual = strchr(pszValue, '=');
259 if (pszEqual)
260 {
261 size_t const cchVar = pszValue - pszEqual;
262 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
263 if ( strncmp(papszEnv[iEnvVar], pszValue, cchVar) == 0
264 && papszEnv[iEnvVar][cchVar] == '=')
265 {
266 if (cVerbosity > 0)
267 fprintf(stderr, "kSubmit: replacing '%s' with '%s'\n", papszEnv[iEnvVar], pszValue);
268 free(papszEnv[iEnvVar]);
269 papszEnv[iEnvVar] = xstrdup(pszValue);
270 break;
271 }
272 if (iEnvVar == cEnvVars)
273 {
274 /* Append new variable. We probably need to resize the vector. */
275 if ((cEnvVars + 2) > cAllocatedEnvVars)
276 {
277 cAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
278 pChild->environment = papszEnv = (char **)xrealloc(papszEnv,
279 cAllocatedEnvVars * sizeof(papszEnv[0]));
280 }
281 papszEnv[cEnvVars++] = xstrdup(pszValue);
282 papszEnv[cEnvVars] = NULL;
283 if (cVerbosity > 0)
284 fprintf(stderr, "kSubmit: added '%s'\n", papszEnv[iEnvVar]);
285 }
286 else
287 {
288 /* Check for duplicates. */
289 for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
290 if ( strncmp(papszEnv[iEnvVar], pszValue, cchVar) == 0
291 && papszEnv[iEnvVar][cchVar] == '=')
292 {
293 if (cVerbosity > 0)
294 fprintf(stderr, "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
295 free(papszEnv[iEnvVar]);
296 cEnvVars--;
297 if (iEnvVar != cEnvVars)
298 papszEnv[iEnvVar] = papszEnv[cEnvVars];
299 papszEnv[cEnvVars] = NULL;
300 iEnvVar--;
301 }
302 }
303 }
304 else
305 return errx(1, "Missing '=': -E %s", pszValue);
306 break;
307 }
308
309 case 'U':
310 {
311 if (strchr(pszValue, '=') == NULL)
312 {
313 unsigned cRemoved = 0;
314 size_t const cchVar = strlen(pszValue);
315 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
316 if ( strncmp(papszEnv[iEnvVar], pszValue, cchVar) == 0
317 && papszEnv[iEnvVar][cchVar] == '=')
318 {
319 if (cVerbosity > 0)
320 fprintf(stderr, !cRemoved ? "kSubmit: removing '%s'\n"
321 : "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
322 free(papszEnv[iEnvVar]);
323 cEnvVars--;
324 if (iEnvVar != cEnvVars)
325 papszEnv[iEnvVar] = papszEnv[cEnvVars];
326 papszEnv[cEnvVars] = NULL;
327 cRemoved++;
328 iEnvVar--;
329 }
330 if (cVerbosity > 0 && !cRemoved)
331 fprintf(stderr, "kSubmit: not found '%s'\n", pszValue);
332 }
333 else
334 return errx(1, "Found invalid variable name character '=' in: -U %s", pszValue);
335 break;
336 }
337
338 case 'C':
339 {
340 size_t cchNewCwd = strlen(pszValue);
341 size_t offDst;
342 if (cchNewCwd)
343 {
344#ifdef HAVE_DOS_PATHS
345 if (*pszValue == '/' || *pszValue == '\\')
346 {
347 if (pszValue[1] == '/' || pszValue[1] == '\\')
348 offDst = 0; /* UNC */
349 else if (szCwd[1] == ':' && isalpha(szCwd[0]))
350 offDst = 2; /* Take drive letter from CWD. */
351 else
352 return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", szCwd, pszValue);
353 }
354 else if ( pszValue[1] == ':'
355 && isalpha(pszValue[0]))
356 {
357 if (pszValue[2] == '/'|| pszValue[2] == '\\')
358 offDst = 0; /* DOS style absolute path. */
359 else if ( szCwd[1] == ':'
360 && tolower(szCwd[0]) == tolower(pszValue[0]) )
361 {
362 pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
363 cchNewCwd -= 2;
364 offDst = strlen(szCwd);
365 }
366 else
367 {
368 /* Get current CWD on the specified drive and append value. */
369 int iDrive = tolower(pszValue[0]) - 'a' + 1;
370 if (!_getdcwd(iDrive, szCwd, cbCwdBuf))
371 return err(1, "_getdcwd(%d,,) failed", iDrive);
372 pszValue += 2;
373 cchNewCwd -= 2;
374 }
375 }
376#else
377 if (*pszValue == '/')
378 offDst = 0;
379#endif
380 else
381 offDst = strlen(szCwd); /* Relative path, append to the existing CWD value. */
382
383 /* Do the copying. */
384#ifdef HAVE_DOS_PATHS
385 if (offDst > 0 && szCwd[offDst - 1] != '/' && szCwd[offDst - 1] != '\\')
386#else
387 if (offDst > 0 && szCwd[offDst - 1] != '/')
388#endif
389 szCwd[offDst++] = '/';
390 if (offDst + cchNewCwd >= cbCwdBuf)
391 return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, szCwd, pszValue);
392 memcpy(&szCwd[offDst], pszValue, cchNewCwd + 1);
393 }
394 /* else: relative, no change - quitely ignore. */
395 break;
396 }
397
398 case '3':
399 cBitsWorker = 32;
400 break;
401
402 case '6':
403 cBitsWorker = 64;
404 break;
405
406 case 'v':
407 cVerbosity++;
408 break;
409
410 case 'h':
411 usage(stdout, argv[0]);
412 return 0;
413
414 case 'V':
415 printf("kmk_submit - kBuild version %d.%d.%d (r%u)\n"
416 "Copyright (C) 2007-2016 knut st. osmundsen\n",
417 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
418 KBUILD_SVN_REV);
419 return 0;
420 }
421 } while ((chOpt = *pszArg++) != '\0');
422 }
423 else
424 {
425 errx(1, "Unknown argument: '%s'", pszArg);
426 return usage(stderr, argv[0]);
427 }
428 }
429
430 /*
431 * Check that we've got something to execute.
432 */
433 if (iArg < argc)
434 {
435
436 }
437 else
438 {
439 errx(1, "Nothing to executed!");
440 rcExit = usage(stderr, argv[0]);
441 }
442
443 return rcExit;
444}
445
446
447
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette