VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fuzz/fuzzmastercmd.cpp@ 72602

Last change on this file since 72602 was 72578, checked in by vboxsync, 7 years ago

fuzzmastercmd.cpp: Try make gcc happy.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.8 KB
Line 
1/* $Id: fuzzmastercmd.cpp 72578 2018-06-16 14:31:52Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, master command.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/fuzz.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/base64.h>
37#include <iprt/buildconfig.h>
38#include <iprt/ctype.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/getopt.h>
42#include <iprt/json.h>
43#include <iprt/list.h>
44#include <iprt/mem.h>
45#include <iprt/message.h>
46#include <iprt/path.h>
47#include <iprt/process.h>
48#include <iprt/stream.h>
49#include <iprt/string.h>
50#include <iprt/tcp.h>
51#include <iprt/thread.h>
52#include <iprt/vfs.h>
53#include <iprt/zip.h>
54
55
56/**
57 * A running fuzzer state.
58 */
59typedef struct RTFUZZRUN
60{
61 /** List node. */
62 RTLISTNODE NdFuzzed;
63 /** Identifier. */
64 char *pszId;
65 /** Number of processes. */
66 uint32_t cProcs;
67 /** Maximum input size to generate. */
68 size_t cbInputMax;
69 /** The fuzzing observer state handle. */
70 RTFUZZOBS hFuzzObs;
71} RTFUZZRUN;
72/** Pointer to a running fuzzer state. */
73typedef RTFUZZRUN *PRTFUZZRUN;
74
75
76/**
77 * Fuzzing master command state.
78 */
79typedef struct RTFUZZCMDMASTER
80{
81 /** List of running fuzzers. */
82 RTLISTANCHOR LstFuzzed;
83 /** The port to listen on. */
84 uint16_t uPort;
85 /** The TCP server for requests. */
86 PRTTCPSERVER hTcpSrv;
87 /** The root temp directory. */
88 const char *pszTmpDir;
89 /** The root results directory. */
90 const char *pszResultsDir;
91 /** Flag whether to shutdown. */
92 bool fShutdown;
93} RTFUZZCMDMASTER;
94/** Pointer to a fuzzing master command state. */
95typedef RTFUZZCMDMASTER *PRTFUZZCMDMASTER;
96
97
98/**
99 * Wrapper around RTErrInfoSetV / RTMsgErrorV.
100 *
101 * @returns @a rc
102 * @param pErrInfo Extended error info.
103 * @param rc The return code.
104 * @param pszFormat The message format.
105 * @param ... The message format arguments.
106 */
107static int rtFuzzCmdMasterErrorRc(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...)
108{
109 va_list va;
110 va_start(va, pszFormat);
111 if (pErrInfo)
112 RTErrInfoSetV(pErrInfo, rc, pszFormat, va);
113 else
114 RTMsgErrorV(pszFormat, va);
115 va_end(va);
116 return rc;
117}
118
119
120/**
121 * Returns a running fuzzer state by the given ID.
122 *
123 * @returns Pointer to the running fuzzer state or NULL if not found.
124 * @param pThis The fuzzing master command state.
125 * @param pszId The ID to look for.
126 */
127static PRTFUZZRUN rtFuzzCmdMasterGetFuzzerById(PRTFUZZCMDMASTER pThis, const char *pszId)
128{
129 PRTFUZZRUN pIt = NULL;
130 RTListForEach(&pThis->LstFuzzed, pIt, RTFUZZRUN, NdFuzzed)
131 {
132 if (!RTStrCmp(pIt->pszId, pszId))
133 return pIt;
134 }
135
136 return NULL;
137}
138
139
140#if 0 /* unused */
141/**
142 * Processes and returns the value of the given config item in the JSON request.
143 *
144 * @returns IPRT status code.
145 * @param ppszStr Where to store the pointer to the string on success.
146 * @param pszCfgItem The config item to resolve.
147 * @param hJsonCfg The JSON object containing the item.
148 * @param pErrInfo Where to store the error information on failure, optional.
149 */
150static int rtFuzzCmdMasterFuzzRunProcessCfgString(char **ppszStr, const char *pszCfgItem, RTJSONVAL hJsonCfg, PRTERRINFO pErrInfo)
151{
152 int rc = RTJsonValueQueryStringByName(hJsonCfg, pszCfgItem, ppszStr);
153 if (RT_FAILURE(rc))
154 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query string value of \"%s\"", pszCfgItem);
155
156 return rc;
157}
158
159
160/**
161 * Processes and returns the value of the given config item in the JSON request.
162 *
163 * @returns IPRT status code.
164 * @param pfVal Where to store the config value on success.
165 * @param pszCfgItem The config item to resolve.
166 * @param hJsonCfg The JSON object containing the item.
167 * @param pErrInfo Where to store the error information on failure, optional.
168 */
169static int rtFuzzCmdMasterFuzzRunProcessCfgBool(bool *pfVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, PRTERRINFO pErrInfo)
170{
171 int rc = RTJsonValueQueryBooleanByName(hJsonCfg, pszCfgItem, pfVal);
172 if (RT_FAILURE(rc))
173 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query boolean value of \"%s\"", pszCfgItem);
174
175 return rc;
176}
177#endif
178
179
180/**
181 * Processes and returns the value of the given config item in the JSON request.
182 *
183 * @returns IPRT status code.
184 * @param pfVal Where to store the config value on success.
185 * @param pszCfgItem The config item to resolve.
186 * @param hJsonCfg The JSON object containing the item.
187 * @param fDef Default value if the item wasn't found.
188 * @param pErrInfo Where to store the error information on failure, optional.
189 */
190static int rtFuzzCmdMasterFuzzRunProcessCfgBoolDef(bool *pfVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, bool fDef, PRTERRINFO pErrInfo)
191{
192 int rc = RTJsonValueQueryBooleanByName(hJsonCfg, pszCfgItem, pfVal);
193 if (rc == VERR_NOT_FOUND)
194 {
195 *pfVal = fDef;
196 rc = VINF_SUCCESS;
197 }
198 else if (RT_FAILURE(rc))
199 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query boolean value of \"%s\"", pszCfgItem);
200
201 return rc;
202}
203
204
205/**
206 * Processes and returns the value of the given config item in the JSON request.
207 *
208 * @returns IPRT status code.
209 * @param pcbVal Where to store the config value on success.
210 * @param pszCfgItem The config item to resolve.
211 * @param hJsonCfg The JSON object containing the item.
212 * @param cbDef Default value if the item wasn't found.
213 * @param pErrInfo Where to store the error information on failure, optional.
214 */
215static int rtFuzzCmdMasterFuzzRunProcessCfgSizeDef(size_t *pcbVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, size_t cbDef, PRTERRINFO pErrInfo)
216{
217 *pcbVal = cbDef; /* Make GCC 6.3.0 happy. */
218
219 int64_t i64Val = 0;
220 int rc = RTJsonValueQueryIntegerByName(hJsonCfg, pszCfgItem, &i64Val);
221 if (rc == VERR_NOT_FOUND)
222 rc = VINF_SUCCESS;
223 else if (RT_FAILURE(rc))
224 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query size_t value of \"%s\"", pszCfgItem);
225 else if (i64Val < 0 || (size_t)i64Val != (uint64_t)i64Val)
226 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_OUT_OF_RANGE, "JSON request malformed: Integer \"%s\" is out of range", pszCfgItem);
227 else
228 *pcbVal = (size_t)i64Val;
229
230 return rc;
231}
232
233
234/**
235 * Processes and returns the value of the given config item in the JSON request.
236 *
237 * @returns IPRT status code.
238 * @param pcbVal Where to store the config value on success.
239 * @param pszCfgItem The config item to resolve.
240 * @param hJsonCfg The JSON object containing the item.
241 * @param cbDef Default value if the item wasn't found.
242 * @param pErrInfo Where to store the error information on failure, optional.
243 */
244static int rtFuzzCmdMasterFuzzRunProcessCfgU32Def(uint32_t *pu32Val, const char *pszCfgItem, RTJSONVAL hJsonCfg, uint32_t u32Def, PRTERRINFO pErrInfo)
245{
246 int64_t i64Val = 0;
247 int rc = RTJsonValueQueryIntegerByName(hJsonCfg, pszCfgItem, &i64Val);
248 if (rc == VERR_NOT_FOUND)
249 {
250 *pu32Val = u32Def;
251 rc = VINF_SUCCESS;
252 }
253 else if (RT_FAILURE(rc))
254 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query uint32_t value of \"%s\"", pszCfgItem);
255 else if (i64Val < 0 || (uint32_t)i64Val != (uint64_t)i64Val)
256 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_OUT_OF_RANGE, "JSON request malformed: Integer \"%s\" is out of range", pszCfgItem);
257 else
258 *pu32Val = (uint32_t)i64Val;
259
260 return rc;
261}
262
263
264/**
265 * Processes binary related configs for the given fuzzing run.
266 *
267 * @returns IPRT status code.
268 * @param pFuzzRun The fuzzing run.
269 * @param hJsonRoot The root node of the JSON request.
270 * @param pErrInfo Where to store the error information on failure, optional.
271 */
272static int rtFuzzCmdMasterFuzzRunProcessBinaryCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
273{
274 RTJSONVAL hJsonVal;
275 int rc = RTJsonValueQueryByName(hJsonRoot, "BinaryPath", &hJsonVal);
276 if (RT_SUCCESS(rc))
277 {
278 const char *pszBinary = RTJsonValueGetString(hJsonVal);
279 if (RT_LIKELY(pszBinary))
280 {
281 bool fFileInput = false;
282 rc = rtFuzzCmdMasterFuzzRunProcessCfgBoolDef(&fFileInput, "FileInput", hJsonRoot, false, pErrInfo);
283 if (RT_SUCCESS(rc))
284 {
285 uint32_t fFlags = 0;
286 if (fFileInput)
287 fFlags |= RTFUZZ_OBS_BINARY_F_INPUT_FILE;
288 rc = RTFuzzObsSetTestBinary(pFuzzRun->hFuzzObs, pszBinary, fFlags);
289 if (RT_FAILURE(rc))
290 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to add the binary path for the fuzzing run");
291 }
292 }
293 else
294 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"BinaryPath\" is not a string");
295 RTJsonValueRelease(hJsonVal);
296 }
297 else
298 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query value of \"BinaryPath\"");
299
300 return rc;
301}
302
303
304/**
305 * Processes argument related configs for the given fuzzing run.
306 *
307 * @returns IPRT status code.
308 * @param pFuzzRun The fuzzing run.
309 * @param hJsonRoot The root node of the JSON request.
310 * @param pErrInfo Where to store the error information on failure, optional.
311 */
312static int rtFuzzCmdMasterFuzzRunProcessArgCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
313{
314 RTJSONVAL hJsonValArgArray;
315 int rc = RTJsonValueQueryByName(hJsonRoot, "Arguments", &hJsonValArgArray);
316 if (RT_SUCCESS(rc))
317 {
318 unsigned cArgs = 0;
319 rc = RTJsonValueQueryArraySize(hJsonValArgArray, &cArgs);
320 if (RT_SUCCESS(rc))
321 {
322 if (cArgs > 0)
323 {
324 const char **papszArgs = (const char **)RTMemAllocZ(cArgs * sizeof(const char *));
325 RTJSONVAL *pahJsonVal = (RTJSONVAL *)RTMemAllocZ(cArgs * sizeof(RTJSONVAL));
326 if (RT_LIKELY(papszArgs && pahJsonVal))
327 {
328 unsigned idx = 0;
329
330 for (idx = 0; idx < cArgs && RT_SUCCESS(rc); idx++)
331 {
332 rc = RTJsonValueQueryByIndex(hJsonValArgArray, idx, &pahJsonVal[idx]);
333 if (RT_SUCCESS(rc))
334 {
335 papszArgs[idx] = RTJsonValueGetString(pahJsonVal[idx]);
336 if (RT_UNLIKELY(!papszArgs[idx]))
337 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Argument %u is not a string", idx);
338 }
339 }
340
341 if (RT_SUCCESS(rc))
342 {
343 rc = RTFuzzObsSetTestBinaryArgs(pFuzzRun->hFuzzObs, papszArgs, cArgs);
344 if (RT_FAILURE(rc))
345 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to set arguments for the fuzzing run");
346 }
347
348 /* Release queried values. */
349 while (idx > 0)
350 {
351 RTJsonValueRelease(pahJsonVal[idx - 1]);
352 idx--;
353 }
354 }
355 else
356 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Out of memory allocating memory for the argument vector");
357
358 if (papszArgs)
359 RTMemFree(papszArgs);
360 if (pahJsonVal)
361 RTMemFree(pahJsonVal);
362 }
363 }
364 else
365 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: \"Arguments\" is not an array");
366 RTJsonValueRelease(hJsonValArgArray);
367 }
368
369 return rc;
370}
371
372
373/**
374 * Processes the given seed and adds it to the input corpus.
375 *
376 * @returns IPRT status code.
377 * @param hFuzzCtx The fuzzing context handle.
378 * @param pszCompression Compression used for the seed.
379 * @param pszSeed The seed as a base64 encoded string.
380 * @param pErrInfo Where to store the error information on failure, optional.
381 */
382static int rtFuzzCmdMasterFuzzRunProcessSeed(RTFUZZCTX hFuzzCtx, const char *pszCompression, const char *pszSeed, PRTERRINFO pErrInfo)
383{
384 int rc = VINF_SUCCESS;
385 ssize_t cbSeedDecoded = RTBase64DecodedSize(pszSeed, NULL);
386 if (cbSeedDecoded > 0)
387 {
388 uint8_t *pbSeedDecoded = (uint8_t *)RTMemAllocZ(cbSeedDecoded);
389 if (RT_LIKELY(pbSeedDecoded))
390 {
391 rc = RTBase64Decode(pszSeed, pbSeedDecoded, cbSeedDecoded, NULL, NULL);
392 if (RT_SUCCESS(rc))
393 {
394 /* Decompress if applicable. */
395 if (!RTStrICmp(pszCompression, "None"))
396 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pbSeedDecoded, cbSeedDecoded);
397 else
398 {
399 RTVFSIOSTREAM hVfsIosSeed;
400 rc = RTVfsIoStrmFromBuffer(RTFILE_O_READ, pbSeedDecoded, cbSeedDecoded, &hVfsIosSeed);
401 if (RT_SUCCESS(rc))
402 {
403 RTVFSIOSTREAM hVfsDecomp = NIL_RTVFSIOSTREAM;
404
405 if (!RTStrICmp(pszCompression, "Gzip"))
406 rc = RTZipGzipDecompressIoStream(hVfsIosSeed, RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR, &hVfsDecomp);
407 else
408 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Compression \"%s\" is not known", pszCompression);
409
410 if (RT_SUCCESS(rc))
411 {
412 RTVFSFILE hVfsFile;
413 rc = RTVfsMemFileCreate(hVfsDecomp, 2 * _1M, &hVfsFile);
414 if (RT_SUCCESS(rc))
415 {
416 rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
417 if (RT_SUCCESS(rc))
418 {
419 /* The VFS file contains the buffer for the seed now. */
420 rc = RTFuzzCtxCorpusInputAddFromVfsFile(hFuzzCtx, hVfsFile);
421 if (RT_FAILURE(rc))
422 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to add input seed");
423 RTVfsFileRelease(hVfsFile);
424 }
425 else
426 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Failed to seek to the beginning of the seed");
427 }
428 else
429 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Failed to decompress input seed");
430
431 RTVfsIoStrmRelease(hVfsDecomp);
432 }
433
434 RTVfsIoStrmRelease(hVfsIosSeed);
435 }
436 else
437 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create I/O stream from seed buffer");
438 }
439 }
440 else
441 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to decode the seed string");
442
443 RTMemFree(pbSeedDecoded);
444 }
445 else
446 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Request error: Failed to allocate %zd bytes of memory for the seed", cbSeedDecoded);
447 }
448 else
449 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: Couldn't find \"Seed\" doesn't contain a base64 encoded value");
450
451 return rc;
452}
453
454
455/**
456 * Processes a signle input seed for the given fuzzing run.
457 *
458 * @returns IPRT status code.
459 * @param pFuzzRun The fuzzing run.
460 * @param hJsonSeed The seed node of the JSON request.
461 * @param pErrInfo Where to store the error information on failure, optional.
462 */
463static int rtFuzzCmdMasterFuzzRunProcessInputSeedSingle(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonSeed, PRTERRINFO pErrInfo)
464{
465 RTFUZZCTX hFuzzCtx;
466 int rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx);
467 if (RT_SUCCESS(rc))
468 {
469 RTJSONVAL hJsonValComp;
470 rc = RTJsonValueQueryByName(hJsonSeed, "Compression", &hJsonValComp);
471 if (RT_SUCCESS(rc))
472 {
473 const char *pszCompression = RTJsonValueGetString(hJsonValComp);
474 if (RT_LIKELY(pszCompression))
475 {
476 RTJSONVAL hJsonValSeed;
477 rc = RTJsonValueQueryByName(hJsonSeed, "Seed", &hJsonValSeed);
478 if (RT_SUCCESS(rc))
479 {
480 const char *pszSeed = RTJsonValueGetString(hJsonValSeed);
481 if (RT_LIKELY(pszSeed))
482 rc = rtFuzzCmdMasterFuzzRunProcessSeed(hFuzzCtx, pszCompression, pszSeed, pErrInfo);
483 else
484 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"Seed\" value is not a string");
485
486 RTJsonValueRelease(hJsonValSeed);
487 }
488 else
489 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Seed\" value");
490 }
491 else
492 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"Compression\" value is not a string");
493
494 RTJsonValueRelease(hJsonValComp);
495 }
496 else
497 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Compression\" value");
498
499 RTFuzzCtxRelease(hFuzzCtx);
500 }
501 else
502 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to query fuzzing context from observer");
503
504 return rc;
505}
506
507
508/**
509 * Processes input seed related configs for the given fuzzing run.
510 *
511 * @returns IPRT status code.
512 * @param pFuzzRun The fuzzing run.
513 * @param hJsonRoot The root node of the JSON request.
514 * @param pErrInfo Where to store the error information on failure, optional.
515 */
516static int rtFuzzCmdMasterFuzzRunProcessInputSeeds(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
517{
518 RTJSONVAL hJsonValSeedArray;
519 int rc = RTJsonValueQueryByName(hJsonRoot, "InputSeeds", &hJsonValSeedArray);
520 if (RT_SUCCESS(rc))
521 {
522 RTJSONIT hIt;
523 rc = RTJsonIteratorBegin(hJsonValSeedArray, &hIt);
524 if (RT_SUCCESS(rc))
525 {
526 RTJSONVAL hJsonInpSeed;
527 while ( RT_SUCCESS(rc)
528 && RTJsonIteratorQueryValue(hIt, &hJsonInpSeed, NULL) != VERR_JSON_ITERATOR_END)
529 {
530 rc = rtFuzzCmdMasterFuzzRunProcessInputSeedSingle(pFuzzRun, hJsonInpSeed, pErrInfo);
531 RTJsonValueRelease(hJsonInpSeed);
532 if (RT_FAILURE(rc))
533 break;
534 rc = RTJsonIteratorNext(hIt);
535 }
536
537 if (rc == VERR_JSON_ITERATOR_END)
538 rc = VINF_SUCCESS;
539 }
540 else
541 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to create array iterator");
542
543 RTJsonValueRelease(hJsonValSeedArray);
544 }
545
546 return rc;
547}
548
549
550/**
551 * Processes miscellaneous config items.
552 *
553 * @returns IPRT status code.
554 * @param pFuzzRun The fuzzing run.
555 * @param hJsonRoot The root node of the JSON request.
556 * @param pErrInfo Where to store the error information on failure, optional.
557 */
558static int rtFuzzCmdMasterFuzzRunProcessMiscCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
559{
560 size_t cbTmp;
561 int rc = rtFuzzCmdMasterFuzzRunProcessCfgSizeDef(&cbTmp, "InputSeedMax", hJsonRoot, 0, pErrInfo);
562 if (RT_SUCCESS(rc))
563 {
564 RTFUZZCTX hFuzzCtx;
565 rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx);
566 AssertRC(rc);
567
568 rc = RTFuzzCtxCfgSetInputSeedMaximum(hFuzzCtx, cbTmp);
569 if (RT_FAILURE(rc))
570 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set maximum input seed size to %zu", cbTmp);
571 }
572
573 if (RT_SUCCESS(rc))
574 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&pFuzzRun->cProcs, "FuzzingProcs", hJsonRoot, 0, pErrInfo);
575
576 return rc;
577}
578
579
580/**
581 * Creates a new fuzzing run with the given ID.
582 *
583 * @returns IPRT status code.
584 * @param pThis The fuzzing master command state.
585 * @param pszId The ID to use.
586 * @param hJsonRoot The root node of the JSON request.
587 * @param pErrInfo Where to store the error information on failure, optional.
588 */
589static int rtFuzzCmdMasterCreateFuzzRunWithId(PRTFUZZCMDMASTER pThis, const char *pszId, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
590{
591 int rc = VINF_SUCCESS;
592 PRTFUZZRUN pFuzzRun = (PRTFUZZRUN)RTMemAllocZ(sizeof(*pFuzzRun));
593 if (RT_LIKELY(pFuzzRun))
594 {
595 pFuzzRun->pszId = RTStrDup(pszId);
596 if (RT_LIKELY(pFuzzRun->pszId))
597 {
598 rc = RTFuzzObsCreate(&pFuzzRun->hFuzzObs);
599 if (RT_SUCCESS(rc))
600 {
601 rc = rtFuzzCmdMasterFuzzRunProcessBinaryCfg(pFuzzRun, hJsonRoot, pErrInfo);
602 if (RT_SUCCESS(rc))
603 rc = rtFuzzCmdMasterFuzzRunProcessArgCfg(pFuzzRun, hJsonRoot, pErrInfo);
604 if (RT_SUCCESS(rc))
605 rc = rtFuzzCmdMasterFuzzRunProcessInputSeeds(pFuzzRun, hJsonRoot, pErrInfo);
606 if (RT_SUCCESS(rc))
607 rc = rtFuzzCmdMasterFuzzRunProcessMiscCfg(pFuzzRun, hJsonRoot, pErrInfo);
608 if (RT_SUCCESS(rc))
609 {
610 /* Create temp directories. */
611 char szTmpDir[RTPATH_MAX];
612 rc = RTPathJoin(&szTmpDir[0], sizeof(szTmpDir), pThis->pszTmpDir, pFuzzRun->pszId);
613 AssertRC(rc);
614 rc = RTDirCreate(szTmpDir, 0700, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET
615 | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
616 if (RT_SUCCESS(rc))
617 {
618 rc = RTFuzzObsSetTmpDirectory(pFuzzRun->hFuzzObs, szTmpDir);
619 if (RT_SUCCESS(rc))
620 {
621 rc = RTPathJoin(&szTmpDir[0], sizeof(szTmpDir), pThis->pszResultsDir, pFuzzRun->pszId);
622 AssertRC(rc);
623 rc = RTDirCreate(szTmpDir, 0700, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET
624 | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
625 if (RT_SUCCESS(rc))
626 {
627 rc = RTFuzzObsSetResultDirectory(pFuzzRun->hFuzzObs, szTmpDir);
628 if (RT_SUCCESS(rc))
629 {
630 /* Start fuzzing. */
631 RTListAppend(&pThis->LstFuzzed, &pFuzzRun->NdFuzzed);
632 rc = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs);
633 if (RT_FAILURE(rc))
634 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to start fuzzing with %Rrc", rc);
635 }
636 else
637 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set results directory to %s", szTmpDir);
638 }
639 else
640 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create results directory %s", szTmpDir);
641 }
642 else
643 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set temporary directory to %s", szTmpDir);
644 }
645 else
646 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create temporary directory %s", szTmpDir);
647 }
648 }
649 }
650 else
651 rc = VERR_NO_STR_MEMORY;
652 }
653 else
654 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Request error: Out of memory allocating the fuzzer state");
655
656 return rc;
657}
658
659
660/**
661 * Resolves the fuzzing run from the given ID config item and the given JSON request.
662 *
663 * @returns IPRT status code.
664 * @param pThis The fuzzing master command state.
665 * @param hJsonRoot The root node of the JSON request.
666 * @param pszIdItem The JSON item which contains the ID of the fuzzing run.
667 * @param ppFuzzRun Where to store the pointer to the fuzzing run on success.
668 */
669static int rtFuzzCmdMasterQueryFuzzRunFromJson(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, const char *pszIdItem, PRTERRINFO pErrInfo,
670 PRTFUZZRUN *ppFuzzRun)
671{
672 RTJSONVAL hJsonValId;
673 int rc = RTJsonValueQueryByName(hJsonRoot, pszIdItem, &hJsonValId);
674 if (RT_SUCCESS(rc))
675 {
676 const char *pszId = RTJsonValueGetString(hJsonValId);
677 if (pszId)
678 {
679 PRTFUZZRUN pFuzzRun = rtFuzzCmdMasterGetFuzzerById(pThis, pszId);
680 if (pFuzzRun)
681 *ppFuzzRun = pFuzzRun;
682 else
683 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NOT_FOUND, "Request error: The ID \"%s\" wasn't found", pszId);
684 }
685 else
686 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Id\" is not a string value");
687
688 RTJsonValueRelease(hJsonValId);
689 }
690 else
691 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Id\" value");
692 return rc;
693}
694
695
696/**
697 * Processes the "StartFuzzing" request.
698 *
699 * @returns IPRT status code.
700 * @param pThis The fuzzing master command state.
701 * @param hJsonRoot The root node of the JSON request.
702 * @param pErrInfo Where to store the error information on failure, optional.
703 */
704static int rtFuzzCmdMasterProcessJsonReqStart(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
705{
706 RTJSONVAL hJsonValId;
707 int rc = RTJsonValueQueryByName(hJsonRoot, "Id", &hJsonValId);
708 if (RT_SUCCESS(rc))
709 {
710 const char *pszId = RTJsonValueGetString(hJsonValId);
711 if (pszId)
712 {
713 PRTFUZZRUN pFuzzRun = rtFuzzCmdMasterGetFuzzerById(pThis, pszId);
714 if (!pFuzzRun)
715 rc = rtFuzzCmdMasterCreateFuzzRunWithId(pThis, pszId, hJsonRoot, pErrInfo);
716 else
717 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_ALREADY_EXISTS, "Request error: The ID \"%s\" is already registered", pszId);
718 }
719 else
720 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Id\" is not a string value");
721
722 RTJsonValueRelease(hJsonValId);
723 }
724 else
725 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Id\" value");
726 return rc;
727}
728
729
730/**
731 * Processes the "StopFuzzing" request.
732 *
733 * @returns IPRT status code.
734 * @param pThis The fuzzing master command state.
735 * @param hJsonValRoot The root node of the JSON request.
736 * @param pErrInfo Where to store the error information on failure, optional.
737 */
738static int rtFuzzCmdMasterProcessJsonReqStop(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
739{
740 PRTFUZZRUN pFuzzRun;
741 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
742 if (RT_SUCCESS(rc))
743 {
744 RTListNodeRemove(&pFuzzRun->NdFuzzed);
745 RTFuzzObsExecStop(pFuzzRun->hFuzzObs);
746 RTFuzzObsDestroy(pFuzzRun->hFuzzObs);
747 RTStrFree(pFuzzRun->pszId);
748 RTMemFree(pFuzzRun);
749 }
750
751 return rc;
752}
753
754
755/**
756 * Processes the "SuspendFuzzing" request.
757 *
758 * @returns IPRT status code.
759 * @param pThis The fuzzing master command state.
760 * @param hJsonValRoot The root node of the JSON request.
761 * @param pErrInfo Where to store the error information on failure, optional.
762 */
763static int rtFuzzCmdMasterProcessJsonReqSuspend(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
764{
765 PRTFUZZRUN pFuzzRun;
766 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
767 if (RT_SUCCESS(rc))
768 {
769 rc = RTFuzzObsExecStop(pFuzzRun->hFuzzObs);
770 if (RT_FAILURE(rc))
771 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Suspending the fuzzing process failed");
772 }
773
774 return rc;
775}
776
777
778/**
779 * Processes the "ResumeFuzzing" request.
780 *
781 * @returns IPRT status code.
782 * @param pThis The fuzzing master command state.
783 * @param hJsonValRoot The root node of the JSON request.
784 * @param pErrInfo Where to store the error information on failure, optional.
785 */
786static int rtFuzzCmdMasterProcessJsonReqResume(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
787{
788 PRTFUZZRUN pFuzzRun;
789 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
790 if (RT_SUCCESS(rc))
791 {
792 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&pFuzzRun->cProcs, "FuzzingProcs", hJsonRoot, pFuzzRun->cProcs, pErrInfo);
793 if (RT_SUCCESS(rc))
794 {
795 rc = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs);
796 if (RT_FAILURE(rc))
797 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Resuming the fuzzing process failed");
798 }
799 }
800
801 return rc;
802}
803
804
805/**
806 * Processes the "QueryStats" request.
807 *
808 * @returns IPRT status code.
809 * @param pThis The fuzzing master command state.
810 * @param hJsonValRoot The root node of the JSON request.
811 * @param pErrInfo Where to store the error information on failure, optional.
812 */
813static int rtFuzzCmdMasterProcessJsonReqQueryStats(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
814{
815 RT_NOREF(pThis, hJsonRoot, pErrInfo);
816 return VERR_NOT_IMPLEMENTED;
817}
818
819
820/**
821 * Processes a JSON request.
822 *
823 * @returns IPRT status code.
824 * @param pThis The fuzzing master command state.
825 * @param hJsonValRoot The root node of the JSON request.
826 * @param pErrInfo Where to store the error information on failure, optional.
827 */
828static int rtFuzzCmdMasterProcessJsonReq(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
829{
830 RTJSONVAL hJsonValReq;
831 int rc = RTJsonValueQueryByName(hJsonRoot, "Request", &hJsonValReq);
832 if (RT_SUCCESS(rc))
833 {
834 const char *pszReq = RTJsonValueGetString(hJsonValReq);
835 if (pszReq)
836 {
837 if (!RTStrCmp(pszReq, "StartFuzzing"))
838 rc = rtFuzzCmdMasterProcessJsonReqStart(pThis, hJsonRoot, pErrInfo);
839 else if (!RTStrCmp(pszReq, "StopFuzzing"))
840 rc = rtFuzzCmdMasterProcessJsonReqStop(pThis, hJsonRoot, pErrInfo);
841 else if (!RTStrCmp(pszReq, "SuspendFuzzing"))
842 rc = rtFuzzCmdMasterProcessJsonReqSuspend(pThis, hJsonRoot, pErrInfo);
843 else if (!RTStrCmp(pszReq, "ResumeFuzzing"))
844 rc = rtFuzzCmdMasterProcessJsonReqResume(pThis, hJsonRoot, pErrInfo);
845 else if (!RTStrCmp(pszReq, "QueryStats"))
846 rc = rtFuzzCmdMasterProcessJsonReqQueryStats(pThis, hJsonRoot, pErrInfo);
847 else if (!RTStrCmp(pszReq, "Shutdown"))
848 pThis->fShutdown = true;
849 else
850 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Request\" contains unknown value \"%s\"", pszReq);
851 }
852 else
853 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Request\" is not a string value");
854
855 RTJsonValueRelease(hJsonValReq);
856 }
857 else
858 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Request\" value");
859
860 return rc;
861}
862
863
864/**
865 * Loads a fuzzing configuration for immediate startup from the given file.
866 *
867 * @returns IPRT status code.
868 * @param pThis The fuzzing master command state.
869 * @param pszFuzzCfg The fuzzing config to load.
870 */
871static int rtFuzzCmdMasterFuzzCfgLoadFromFile(PRTFUZZCMDMASTER pThis, const char *pszFuzzCfg)
872{
873 RTJSONVAL hJsonRoot;
874 int rc = RTJsonParseFromFile(&hJsonRoot, pszFuzzCfg, NULL);
875 if (RT_SUCCESS(rc))
876 {
877 rc = rtFuzzCmdMasterProcessJsonReqStart(pThis, hJsonRoot, NULL);
878 RTJsonValueRelease(hJsonRoot);
879 }
880 else
881 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "JSON request malformed: Couldn't load file \"%s\"", pszFuzzCfg);
882
883 return rc;
884}
885
886
887/**
888 * Destroys all running fuzzers for the given master state.
889 *
890 * @returns nothing.
891 * @param pThis The fuzzing master command state.
892 */
893static void rtFuzzCmdMasterDestroy(PRTFUZZCMDMASTER pThis)
894{
895 RT_NOREF(pThis);
896}
897
898
899/**
900 * Sends an ACK response to the client.
901 *
902 * @returns nothing.
903 * @param hSocket The socket handle to send the ACK to.
904 */
905static void rtFuzzCmdMasterTcpSendAck(RTSOCKET hSocket)
906{
907 const char s_szSucc[] = "{ \"Status\": \"ACK\" }\n";
908 RTTcpWrite(hSocket, s_szSucc, sizeof(s_szSucc));
909}
910
911
912/**
913 * Sends an NACK response to the client.
914 *
915 * @returns nothing.
916 * @param hSocket The socket handle to send the ACK to.
917 * @param pErrInfo Optional error information to send along.
918 */
919static void rtFuzzCmdMasterTcpSendNAck(RTSOCKET hSocket, PRTERRINFO pErrInfo)
920{
921 const char s_szFail[] = "{ \"Status\": \"NACK\" }\n";
922 const char s_szFailInfo[] = "{ \"Status\": \"NACK\"\n \"Information\": \"%s\" }\n";
923
924 if (pErrInfo)
925 {
926 char szTmp[1024];
927 ssize_t cchResp = RTStrPrintf2(szTmp, sizeof(szTmp), s_szFailInfo, pErrInfo->pszMsg);
928 if (cchResp > 0)
929 RTTcpWrite(hSocket, szTmp, cchResp);
930 else
931 RTTcpWrite(hSocket, s_szFail, strlen(s_szFail));
932 }
933 else
934 RTTcpWrite(hSocket, s_szFail, strlen(s_szFail));
935}
936
937
938/**
939 * TCP server serving callback for a single connection.
940 *
941 * @returns IPRT status code.
942 * @param hSocket The socket handle of the connection.
943 * @param pvUser Opaque user data.
944 */
945static DECLCALLBACK(int) rtFuzzCmdMasterTcpServe(RTSOCKET hSocket, void *pvUser)
946{
947 PRTFUZZCMDMASTER pThis = (PRTFUZZCMDMASTER)pvUser;
948 size_t cbReqMax = _32K;
949 size_t cbReq = 0;
950 uint8_t *pbReq = (uint8_t *)RTMemAllocZ(cbReqMax);
951
952 if (RT_LIKELY(pbReq))
953 {
954 uint8_t *pbCur = pbReq;
955
956 for (;;)
957 {
958 size_t cbThisRead = cbReqMax - cbReq;
959 int rc = RTTcpRead(hSocket, pbCur, cbThisRead, &cbThisRead);
960 if (RT_SUCCESS(rc))
961 {
962 cbReq += cbThisRead;
963
964 /* Check for a zero terminator marking the end of the request. */
965 uint8_t *pbEnd = (uint8_t *)memchr(pbCur, 0, cbThisRead);
966 if (pbEnd)
967 {
968 /* Adjust request size, data coming after the zero terminiator is ignored right now. */
969 cbReq -= cbThisRead - (pbEnd - pbCur) + 1;
970
971 RTJSONVAL hJsonReq;
972 RTERRINFOSTATIC ErrInfo;
973 RTErrInfoInitStatic(&ErrInfo);
974
975 rc = RTJsonParseFromBuf(&hJsonReq, pbReq, cbReq, &ErrInfo.Core);
976 if (RT_SUCCESS(rc))
977 {
978 rc = rtFuzzCmdMasterProcessJsonReq(pThis, hJsonReq, &ErrInfo.Core);
979 if (RT_SUCCESS(rc))
980 rtFuzzCmdMasterTcpSendAck(hSocket);
981 else
982 rtFuzzCmdMasterTcpSendNAck(hSocket, &ErrInfo.Core);
983 RTJsonValueRelease(hJsonReq);
984 }
985 else
986 rtFuzzCmdMasterTcpSendNAck(hSocket, &ErrInfo.Core);
987 break;
988 }
989 else if (cbReq == cbReqMax)
990 {
991 /* Try to increase the buffer. */
992 uint8_t *pbReqNew = (uint8_t *)RTMemRealloc(pbReq, cbReqMax + _32K);
993 if (RT_LIKELY(pbReqNew))
994 {
995 cbReqMax += _32K;
996 pbReq = pbReqNew;
997 pbCur = pbReq + cbReq;
998 }
999 else
1000 rtFuzzCmdMasterTcpSendNAck(hSocket, NULL);
1001 }
1002 else
1003 pbCur += cbThisRead;
1004 }
1005 else
1006 break;
1007 }
1008 }
1009 else
1010 rtFuzzCmdMasterTcpSendNAck(hSocket, NULL);
1011
1012 if (pbReq)
1013 RTMemFree(pbReq);
1014
1015 return pThis->fShutdown ? VERR_TCP_SERVER_STOP : VINF_SUCCESS;
1016}
1017
1018
1019/**
1020 * Mainloop for the fuzzing master.
1021 *
1022 * @returns Process exit code.
1023 * @param pThis The fuzzing master command state.
1024 * @param pszLoadCfg Initial config to load.
1025 */
1026static RTEXITCODE rtFuzzCmdMasterRun(PRTFUZZCMDMASTER pThis, const char *pszLoadCfg)
1027{
1028 if (pszLoadCfg)
1029 {
1030 int rc = rtFuzzCmdMasterFuzzCfgLoadFromFile(pThis, pszLoadCfg);
1031 if (RT_FAILURE(rc))
1032 return RTEXITCODE_FAILURE;
1033 }
1034
1035 /* Start up the control server. */
1036 int rc = RTTcpServerCreateEx(NULL, pThis->uPort, &pThis->hTcpSrv);
1037 if (RT_SUCCESS(rc))
1038 {
1039 do
1040 {
1041 rc = RTTcpServerListen(pThis->hTcpSrv, rtFuzzCmdMasterTcpServe, pThis);
1042 } while (rc != VERR_TCP_SERVER_STOP);
1043 }
1044
1045 RTTcpServerDestroy(pThis->hTcpSrv);
1046 rtFuzzCmdMasterDestroy(pThis);
1047 return RTEXITCODE_SUCCESS;
1048}
1049
1050
1051RTR3DECL(RTEXITCODE) RTFuzzCmdMaster(unsigned cArgs, char **papszArgs)
1052{
1053 /*
1054 * Parse the command line.
1055 */
1056 static const RTGETOPTDEF s_aOptions[] =
1057 {
1058 { "--fuzz-config", 'c', RTGETOPT_REQ_STRING },
1059 { "--temp-dir", 't', RTGETOPT_REQ_STRING },
1060 { "--results-dir", 'r', RTGETOPT_REQ_STRING },
1061 { "--listen-port", 'p', RTGETOPT_REQ_UINT16 },
1062 { "--daemonize", 'd', RTGETOPT_REQ_NOTHING },
1063 { "--daemonized", 'Z', RTGETOPT_REQ_NOTHING },
1064 { "--help", 'h', RTGETOPT_REQ_NOTHING },
1065 { "--version", 'V', RTGETOPT_REQ_NOTHING },
1066 };
1067
1068 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
1069 RTGETOPTSTATE GetState;
1070 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
1071 RTGETOPTINIT_FLAGS_OPTS_FIRST);
1072 if (RT_SUCCESS(rc))
1073 {
1074 /* Option variables: */
1075 bool fDaemonize = false;
1076 bool fDaemonized = false;
1077 const char *pszLoadCfg = NULL;
1078 RTFUZZCMDMASTER This;
1079
1080 RTListInit(&This.LstFuzzed);
1081 This.hTcpSrv = NIL_RTTCPSERVER;
1082 This.uPort = 4242;
1083 This.pszTmpDir = NULL;
1084 This.pszResultsDir = NULL;
1085 This.fShutdown = false;
1086
1087 /* Argument parsing loop. */
1088 bool fContinue = true;
1089 do
1090 {
1091 RTGETOPTUNION ValueUnion;
1092 int chOpt = RTGetOpt(&GetState, &ValueUnion);
1093 switch (chOpt)
1094 {
1095 case 0:
1096 fContinue = false;
1097 break;
1098
1099 case 'c':
1100 pszLoadCfg = ValueUnion.psz;
1101 break;
1102
1103 case 'p':
1104 This.uPort = ValueUnion.u16;
1105 break;
1106
1107 case 't':
1108 This.pszTmpDir = ValueUnion.psz;
1109 break;
1110
1111 case 'r':
1112 This.pszResultsDir = ValueUnion.psz;
1113 break;
1114
1115 case 'd':
1116 fDaemonize = true;
1117 break;
1118
1119 case 'Z':
1120 fDaemonized = true;
1121 fDaemonize = false;
1122 break;
1123
1124 case 'h':
1125 RTPrintf("Usage: to be written\nOption dump:\n");
1126 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
1127 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
1128 fContinue = false;
1129 break;
1130
1131 case 'V':
1132 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
1133 fContinue = false;
1134 break;
1135
1136 default:
1137 rcExit = RTGetOptPrintError(chOpt, &ValueUnion);
1138 fContinue = false;
1139 break;
1140 }
1141 } while (fContinue);
1142
1143 if (rcExit == RTEXITCODE_SUCCESS)
1144 {
1145 /*
1146 * Daemonize ourselves if asked to.
1147 */
1148 if (fDaemonize)
1149 {
1150 rc = RTProcDaemonize(papszArgs, "--daemonized");
1151 if (RT_FAILURE(rc))
1152 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcDaemonize: %Rrc\n", rc);
1153 }
1154 else
1155 rcExit = rtFuzzCmdMasterRun(&This, pszLoadCfg);
1156 }
1157 }
1158 else
1159 rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
1160 return rcExit;
1161}
1162
Note: See TracBrowser for help on using the repository browser.

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