source: zzuf/trunk/src/zzuf.c @ 4106

Last change on this file since 4106 was 4106, checked in by Sam Hocevar, 10 years ago

Fix memory leaks and infinite loops in the Win32 launcher.

  • Property svn:keywords set to Id
File size: 37.5 KB
RevLine 
[1464]1/*
2 *  zzuf - general purpose fuzzer
[3635]3 *  Copyright (c) 2002, 2007-2009 Sam Hocevar <sam@hocevar.net>
[1464]4 *                All Rights Reserved
5 *
6 *  $Id: zzuf.c 4106 2009-12-07 18:34:21Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  main.c: main program
17 */
18
19#include "config.h"
20
[2530]21/* Needed for STDERR_FILENO on HP-UX */
22#define _INCLUDE_POSIX_SOURCE
23
[1464]24#if defined HAVE_STDINT_H
25#   include <stdint.h>
26#elif defined HAVE_INTTYPES_H
27#   include <inttypes.h>
28#endif
[1733]29#if !defined HAVE_GETOPT_LONG
30#   include "mygetopt.h"
31#elif defined HAVE_GETOPT_H
[1464]32#   include <getopt.h>
33#endif
34#include <stdio.h>
35#include <stdlib.h>
[1728]36#if defined HAVE_UNISTD_H
37#   include <unistd.h>
38#endif
[1695]39#if defined HAVE_REGEX_H
40#   include <regex.h>
41#endif
[1729]42#if defined HAVE_WINSOCK2_H
43#   include <winsock2.h>
44#endif
[1701]45#if defined HAVE_WINDOWS_H
46#   include <windows.h>
47#endif
[1702]48#if defined HAVE_IO_H
[1701]49#   include <io.h>
[1699]50#endif
[1470]51#include <string.h>
[1702]52#include <fcntl.h>
[1505]53#include <errno.h>
[1578]54#include <signal.h>
[2530]55#if defined HAVE_SYS_TIME_H
56#   include <sys/time.h>
57#endif
[1695]58#if defined HAVE_SYS_WAIT_H
59#   include <sys/wait.h>
60#endif
61#if defined HAVE_SYS_RESOURCE_H
62#   include <sys/resource.h>
63#endif
[1464]64
[1613]65#include "libzzuf.h"
[1692]66#include "opts.h"
[1464]67#include "random.h"
[1613]68#include "fd.h"
69#include "fuzz.h"
[1623]70#include "md5.h"
[1657]71#include "timer.h"
[1464]72
[1733]73#if defined HAVE_GETOPT_LONG
74#   define mygetopt getopt_long
75#   define myoptind optind
76#   define myoptarg optarg
77#   define myoption option
78#endif
79
[1695]80#if !defined SIGKILL
81#   define SIGKILL 9
82#endif
83
[3636]84/* Handle old libtool versions */
85#if !defined LT_OBJDIR
[3637]86#   define LT_OBJDIR ".libs/"
[3636]87#endif
88
[1740]89#if defined RLIMIT_AS
[1799]90#   define ZZUF_RLIMIT_MEM RLIMIT_AS
[1740]91#elif defined RLIMIT_VMEM
[1799]92#   define ZZUF_RLIMIT_MEM RLIMIT_VMEM
[1741]93#elif defined RLIMIT_DATA
[1799]94#   define ZZUF_RLIMIT_MEM RLIMIT_DATA
[1740]95#else
[1799]96#   undef ZZUF_RLIMIT_MEM
[1740]97#endif
98
[1799]99#if defined RLIMIT_CPU
100#   define ZZUF_RLIMIT_CPU RLIMIT_CPU
101#else
102#   undef ZZUF_RLIMIT_CPU
103#endif
104
[1718]105/* We use file descriptor 17 as the debug channel */
106#define DEBUG_FILENO 17
107#define DEBUG_FILENO_STR "17"
108
[1702]109static void loop_stdin(struct opts *);
[1743]110static int run_process(struct opts *, int[][2]);
[1659]111
[1702]112static void spawn_children(struct opts *);
113static void clean_children(struct opts *);
114static void read_children(struct opts *);
[1546]115
[1704]116#if !defined HAVE_SETENV
[1702]117static void setenv(char const *, char const *, int);
118#endif
119#if defined HAVE_WAITPID
[2555]120static char const *sig2name(int);
[1702]121#endif
122#if defined HAVE_WINDOWS_H
123static int dll_inject(void *, void *);
124static void *get_entry(char const *);
125#endif
[1710]126static void finfo(FILE *, struct opts *, uint32_t);
[1695]127#if defined HAVE_REGEX_H
[1529]128static char *merge_regex(char *, char *);
129static char *merge_file(char *, char *);
[1695]130#endif
[1464]131static void version(void);
132static void usage(void);
133
[1702]134#if defined HAVE_WINDOWS_H
135static inline void addcpy(void *buf, void *x)
136{
137    memcpy(buf, &x, 4);
138}
139#endif
140
[1506]141#define ZZUF_FD_SET(fd, p_fdset, maxfd) \
142    if(fd >= 0) \
143    { \
[1702]144        FD_SET((unsigned int)fd, p_fdset); \
[1506]145        if(fd > maxfd) \
146            maxfd = fd; \
147    }
148
149#define ZZUF_FD_ISSET(fd, p_fdset) \
150    ((fd >= 0) && (FD_ISSET(fd, p_fdset)))
151
[1464]152int main(int argc, char *argv[])
153{
[1692]154    struct opts _opts, *opts = &_opts;
[1695]155    char *tmp;
156#if defined HAVE_REGEX_H
157    char *include = NULL, *exclude = NULL;
158    int cmdline = 0;
159#endif
[4009]160    int debug = 0, network = 0;
[1695]161    int i;
[1464]162
[1692]163    _zz_opts_init(opts);
164
[1464]165    for(;;)
166    {
[1733]167#if defined HAVE_REGEX_H
[1742]168#   define OPTSTR_REGEX "cE:I:"
[1733]169#else
[1742]170#   define OPTSTR_REGEX ""
[1733]171#endif
[1799]172#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
173#   define OPTSTR_RLIMIT_MEM "M:"
[1742]174#else
[1799]175#   define OPTSTR_RLIMIT_MEM ""
[1742]176#endif
[1801]177#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_CPU
178#   define OPTSTR_RLIMIT_CPU "T:"
179#else
180#   define OPTSTR_RLIMIT_CPU ""
181#endif
[2327]182#define OPTSTR "+" OPTSTR_REGEX OPTSTR_RLIMIT_MEM OPTSTR_RLIMIT_CPU \
[3635]183                "a:Ab:B:C:dD:e:f:F:ij:l:mnp:P:qr:R:s:St:vxhV"
[1733]184#define MOREINFO "Try `%s --help' for more information.\n"
[1464]185        int option_index = 0;
[1733]186        static struct myoption long_options[] =
[1503]187        {
188            /* Long option, needs arg, flag, short option */
[3635]189            { "allow",      1, NULL, 'a' },
[1663]190            { "autoinc",     0, NULL, 'A' },
[1705]191            { "bytes",       1, NULL, 'b' },
[1633]192            { "max-bytes",   1, NULL, 'B' },
[1695]193#if defined HAVE_REGEX_H
[1573]194            { "cmdline",     0, NULL, 'c' },
[1695]195#endif
[1573]196            { "max-crashes", 1, NULL, 'C' },
197            { "debug",       0, NULL, 'd' },
[1660]198            { "delay",       1, NULL, 'D' },
[3635]199            { "deny",        1, NULL, 'e' },
[1695]200#if defined HAVE_REGEX_H
[1573]201            { "exclude",     1, NULL, 'E' },
[1695]202#endif
[1720]203            { "fuzzing",     1, NULL, 'f' },
[1573]204            { "stdin",       0, NULL, 'i' },
[1695]205#if defined HAVE_REGEX_H
[1573]206            { "include",     1, NULL, 'I' },
[1695]207#endif
[2344]208            { "jobs",        1, NULL, 'j' },
[1858]209            { "list",        1, NULL, 'l' },
[1640]210            { "md5",         0, NULL, 'm' },
[1641]211            { "max-memory",  1, NULL, 'M' },
[1573]212            { "network",     0, NULL, 'n' },
[1858]213            { "ports",       1, NULL, 'p' },
[1573]214            { "protect",     1, NULL, 'P' },
215            { "quiet",       0, NULL, 'q' },
216            { "ratio",       1, NULL, 'r' },
217            { "refuse",      1, NULL, 'R' },
218            { "seed",        1, NULL, 's' },
219            { "signal",      0, NULL, 'S' },
[1800]220            { "max-time",    1, NULL, 't' },
[3001]221            { "max-cputime", 1, NULL, 'T' },
[1667]222            { "verbose",     0, NULL, 'v' },
[1634]223            { "check-exit",  0, NULL, 'x' },
[1574]224            { "help",        0, NULL, 'h' },
[1666]225            { "version",     0, NULL, 'V' },
[1681]226            { NULL,          0, NULL,  0  }
[1503]227        };
[1733]228        int c = mygetopt(argc, argv, OPTSTR, long_options, &option_index);
229
[1464]230        if(c == -1)
231            break;
232
233        switch(c)
234        {
[3635]235        case 'a': /* --allow */
236            opts->allow = myoptarg;
237            break;
[1663]238        case 'A': /* --autoinc */
239            setenv("ZZUF_AUTOINC", "1", 1);
240            break;
[1705]241        case 'b': /* --bytes */
[1733]242            opts->bytes = myoptarg;
[1705]243            break;
[1633]244        case 'B': /* --max-bytes */
[2817]245            if(myoptarg[0] == '=')
246                myoptarg++;
[1733]247            opts->maxbytes = atoi(myoptarg);
[1633]248            break;
[1695]249#if defined HAVE_REGEX_H
[1574]250        case 'c': /* --cmdline */
251            cmdline = 1;
252            break;
[1695]253#endif
[1574]254        case 'C': /* --max-crashes */
[2817]255            if(myoptarg[0] == '=')
256                myoptarg++;
[1733]257            opts->maxcrashes = atoi(myoptarg);
[1692]258            if(opts->maxcrashes <= 0)
259                opts->maxcrashes = 0;
[1574]260            break;
261        case 'd': /* --debug */
[4009]262            debug++;
[1574]263            break;
[1660]264        case 'D': /* --delay */
[2817]265            if(myoptarg[0] == '=')
266                myoptarg++;
[1733]267            opts->delay = (int64_t)(atof(myoptarg) * 1000000.0);
[1660]268            break;
[3635]269        case 'e': /* --deny */
270            opts->deny = myoptarg;
271            break;
[1695]272#if defined HAVE_REGEX_H
[1525]273        case 'E': /* --exclude */
[1733]274            exclude = merge_regex(exclude, myoptarg);
[1529]275            if(!exclude)
[1528]276            {
[1733]277                fprintf(stderr, "%s: invalid regex -- `%s'\n",
278                        argv[0], myoptarg);
[1692]279                _zz_opts_fini(opts);
[1528]280                return EXIT_FAILURE;
281            }
[1472]282            break;
[1695]283#endif
[1720]284        case 'f': /* --fuzzing */
[1733]285            opts->fuzzing = myoptarg;
[1720]286            break;
[2344]287        case 'F':
288            fprintf(stderr, "%s: `-F' is deprecated, use `-j'\n", argv[0]);
289            return EXIT_FAILURE;
[1526]290        case 'i': /* --stdin */
291            setenv("ZZUF_STDIN", "1", 1);
292            break;
[1695]293#if defined HAVE_REGEX_H
[1574]294        case 'I': /* --include */
[1733]295            include = merge_regex(include, myoptarg);
[1574]296            if(!include)
297            {
[1733]298                fprintf(stderr, "%s: invalid regex -- `%s'\n",
299                        argv[0], myoptarg);
[1692]300                _zz_opts_fini(opts);
[1574]301                return EXIT_FAILURE;
302            }
303            break;
[1695]304#endif
[2344]305        case 'j': /* --jobs */
[2817]306            if(myoptarg[0] == '=')
307                myoptarg++;
[2344]308            opts->maxchild = atoi(myoptarg) > 1 ? atoi(myoptarg) : 1;
309            break;
[1858]310        case 'l': /* --list */
311            opts->list = myoptarg;
312            break;
[1640]313        case 'm': /* --md5 */
[1692]314            opts->md5 = 1;
[1623]315            break;
[1799]316#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
[1641]317        case 'M': /* --max-memory */
318            setenv("ZZUF_MEMORY", "1", 1);
[2817]319            if(myoptarg[0] == '=')
320                myoptarg++;
[1733]321            opts->maxmem = atoi(myoptarg);
[1641]322            break;
[1702]323#endif
[1562]324        case 'n': /* --network */
[1560]325            setenv("ZZUF_NETWORK", "1", 1);
[1858]326            network = 1;
[1560]327            break;
[1858]328        case 'p': /* --ports */
329            opts->ports = myoptarg;
[1791]330            break;
[1574]331        case 'P': /* --protect */
[1733]332            opts->protect = myoptarg;
[1464]333            break;
[1574]334        case 'q': /* --quiet */
[1692]335            opts->quiet = 1;
[1574]336            break;
[1486]337        case 'r': /* --ratio */
[2817]338            if(myoptarg[0] == '=')
339                myoptarg++;
[1733]340            tmp = strchr(myoptarg, ':');
341            opts->minratio = atof(myoptarg);
[1692]342            opts->maxratio = tmp ? atof(tmp + 1) : opts->minratio;
[1464]343            break;
[1555]344        case 'R': /* --refuse */
[1733]345            opts->refuse = myoptarg;
[1555]346            break;
[1574]347        case 's': /* --seed */
[2817]348            if(myoptarg[0] == '=')
349                myoptarg++;
[1733]350            tmp = strchr(myoptarg, ':');
351            opts->seed = atol(myoptarg);
[2818]352            opts->endseed = tmp ? tmp[1] ? (uint32_t)atol(tmp + 1)
[4100]353                                         : (uint32_t)-1L
[2343]354                                : opts->seed + 1;
[1505]355            break;
[1532]356        case 'S': /* --signal */
357            setenv("ZZUF_SIGNAL", "1", 1);
358            break;
[1800]359        case 't': /* --max-time */
[2817]360            if(myoptarg[0] == '=')
361                myoptarg++;
[1733]362            opts->maxtime = (int64_t)(atof(myoptarg) * 1000000.0);
[1474]363            break;
[1801]364#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_CPU
[3001]365        case 'T': /* --max-cputime */
[2817]366            if(myoptarg[0] == '=')
367                myoptarg++;
[1801]368            opts->maxcpu = (int)(atof(myoptarg) + 0.5);
369            break;
370#endif
[1634]371        case 'x': /* --check-exit */
[1692]372            opts->checkexit = 1;
[1634]373            break;
[1667]374        case 'v': /* --verbose */
[1692]375            opts->verbose = 1;
[1667]376            break;
[1464]377        case 'h': /* --help */
378            usage();
[1692]379            _zz_opts_fini(opts);
[1464]380            return 0;
[1666]381        case 'V': /* --version */
[1464]382            version();
[1692]383            _zz_opts_fini(opts);
[1464]384            return 0;
385        default:
[1733]386            fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
[1464]387            printf(MOREINFO, argv[0]);
[1692]388            _zz_opts_fini(opts);
[1528]389            return EXIT_FAILURE;
[1464]390        }
391    }
392
[1858]393    if(opts->ports && !network)
394    {
395        fprintf(stderr, "%s: port option (-p) requires network fuzzing (-n)\n",
396                argv[0]);
397        printf(MOREINFO, argv[0]);
398        _zz_opts_fini(opts);
399        return EXIT_FAILURE;
400    }
401
[3635]402    if (opts->allow && !network)
403    {
404        fprintf(stderr, "%s: allow option (-a) requires network fuzzing (-n)\n",
405                argv[0]);
406        printf(MOREINFO, argv[0]);
407        _zz_opts_fini(opts);
408        return EXIT_FAILURE;
409    }
410
411    if (opts->deny && !network)
412    {
413        fprintf(stderr, "%s: deny option (-e) requires network fuzzing (-n)\n",
414                argv[0]);
415        printf(MOREINFO, argv[0]);
416        _zz_opts_fini(opts);
417        return EXIT_FAILURE;
418    }
419
[1692]420    _zz_setratio(opts->minratio, opts->maxratio);
421    _zz_setseed(opts->seed);
[1672]422
[1613]423    /* If asked to read from the standard input */
[1733]424    if(myoptind >= argc)
[1464]425    {
[1743]426        if(opts->verbose)
427        {
428            finfo(stderr, opts, opts->seed);
429            fprintf(stderr, "reading from stdin\n");
430        }
431
[1692]432        if(opts->endseed != opts->seed + 1)
[1613]433        {
[1733]434            fprintf(stderr, "%s: seed ranges are incompatible with "
435                            "stdin fuzzing\n", argv[0]);
[1613]436            printf(MOREINFO, argv[0]);
[1692]437            _zz_opts_fini(opts);
[1613]438            return EXIT_FAILURE;
439        }
440
[1692]441        loop_stdin(opts);
[1613]442
[1692]443        _zz_opts_fini(opts);
[1613]444        return EXIT_SUCCESS;
[1464]445    }
446
[1659]447    /* If asked to launch programs */
[1695]448#if defined HAVE_REGEX_H
[1529]449    if(cmdline)
450    {
451        int dashdash = 0;
452
[1733]453        for(i = myoptind + 1; i < argc; i++)
[1529]454        {
455            if(dashdash)
456                include = merge_file(include, argv[i]);
457            else if(!strcmp("--", argv[i]))
458                dashdash = 1;
459            else if(argv[i][0] != '-')
460                include = merge_file(include, argv[i]);
461        }
462    }
463
464    if(include)
465        setenv("ZZUF_INCLUDE", include, 1);
466    if(exclude)
467        setenv("ZZUF_EXCLUDE", exclude, 1);
[1695]468#endif
469
[4009]470    setenv("ZZUF_DEBUG", debug ? debug > 1 ? "2" : "1" : "0", 1);
471    setenv("ZZUF_DEBUGFD", DEBUG_FILENO_STR, 1);
472
[1720]473    if(opts->fuzzing)
474        setenv("ZZUF_FUZZING", opts->fuzzing, 1);
[1705]475    if(opts->bytes)
476        setenv("ZZUF_BYTES", opts->bytes, 1);
[1858]477    if(opts->list)
478        setenv("ZZUF_LIST", opts->list, 1);
479    if(opts->ports)
480        setenv("ZZUF_PORTS", opts->ports, 1);
[3635]481    if(opts->allow)
482        setenv("ZZUF_ALLOW", opts->allow, 1);
483    if(opts->deny)
484        setenv("ZZUF_DENY", opts->deny, 1);
[1692]485    if(opts->protect)
486        setenv("ZZUF_PROTECT", opts->protect, 1);
487    if(opts->refuse)
488        setenv("ZZUF_REFUSE", opts->refuse, 1);
[1529]489
[1505]490    /* Allocate memory for children handling */
[1692]491    opts->child = malloc(opts->maxchild * sizeof(struct child));
492    for(i = 0; i < opts->maxchild; i++)
493        opts->child[i].status = STATUS_FREE;
494    opts->nchild = 0;
[1505]495
[1470]496    /* Create new argv */
[1707]497    opts->oldargv = argv;
[1733]498    opts->newargv = malloc((argc - myoptind + 1) * sizeof(char *));
499    memcpy(opts->newargv, argv + myoptind, (argc - myoptind) * sizeof(char *));
500    opts->newargv[argc - myoptind] = (char *)NULL;
[1464]501
[1505]502    /* Main loop */
[1692]503    while(opts->nchild || opts->seed < opts->endseed)
[1505]504    {
[1659]505        /* Spawn new children, if necessary */
[1692]506        spawn_children(opts);
[1505]507
[1546]508        /* Cleanup dead or dying children */
[1692]509        clean_children(opts);
[1506]510
[1546]511        /* Read data from children */
[1692]512        read_children(opts);
[1573]513
[1692]514        if(opts->maxcrashes && opts->crashes >= opts->maxcrashes
515            && opts->nchild == 0)
[1573]516            break;
[1505]517    }
518
[1528]519    /* Clean up */
[1692]520    _zz_opts_fini(opts);
[1528]521
[2326]522    return opts->crashes ? EXIT_FAILURE : EXIT_SUCCESS;
[1505]523}
524
[1692]525static void loop_stdin(struct opts *opts)
[1659]526{
527    uint8_t md5sum[16];
528    struct md5 *ctx = NULL;
[2583]529    int total = 0;
[1659]530
[1692]531    if(opts->md5)
[1659]532        ctx = _zz_md5_init();
533
[1720]534    if(opts->fuzzing)
535        _zz_fuzzing(opts->fuzzing);
[1706]536    if(opts->bytes)
537        _zz_bytes(opts->bytes);
[1858]538    if(opts->list)
539        _zz_list(opts->list);
[1692]540    if(opts->protect)
541        _zz_protect(opts->protect);
542    if(opts->refuse)
543        _zz_refuse(opts->refuse);
[1659]544
545    _zz_fd_init();
546    _zz_register(0);
547
548    for(;;)
549    {
550        uint8_t buf[BUFSIZ];
[2583]551        int ret, toread = BUFSIZ, off = 0, nw = 0;
[1659]552
[2583]553        if(opts->maxbytes >= 0)
554        {
555            if(total >= opts->maxbytes)
556                break;
557            if(total + BUFSIZ >= opts->maxbytes)
558                toread = opts->maxbytes - total;
559        }
560
561        ret = read(0, buf, toread);
[1659]562        if(ret <= 0)
563            break;
564
[2583]565        total += ret;
566
[1659]567        _zz_fuzz(0, buf, ret);
568        _zz_addpos(0, ret);
569
[1692]570        if(opts->md5)
[1659]571            _zz_md5_add(ctx, buf, ret);
572        else while(ret)
573        {
[1736]574            if((nw = write(1, buf + off, (unsigned int)ret)) < 0)
[1659]575                break;
576            ret -= nw;
577            off += nw;
578        }
579    }
580
[1692]581    if(opts->md5)
[1659]582    {
583        _zz_md5_fini(md5sum, ctx);
[1710]584        finfo(stdout, opts, opts->seed);
[1709]585        fprintf(stdout, "%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x"
586                "%.02x%.02x%.02x%.02x%.02x%.02x\n", md5sum[0], md5sum[1],
587                md5sum[2], md5sum[3], md5sum[4], md5sum[5], md5sum[6],
588                md5sum[7], md5sum[8], md5sum[9], md5sum[10], md5sum[11],
589                md5sum[12], md5sum[13], md5sum[14], md5sum[15]);
[1680]590        fflush(stdout);
[1659]591    }
592
593    _zz_unregister(0);
594    _zz_fd_fini();
595}
596
[1710]597static void finfo(FILE *fp, struct opts *opts, uint32_t seed)
[1709]598{
599    if(opts->minratio == opts->maxratio)
[1710]600        fprintf(fp, "zzuf[s=%i,r=%g]: ", seed, opts->minratio);
[1709]601    else
[1710]602        fprintf(fp, "zzuf[s=%i,r=%g:%g]: ", seed,
[1709]603                opts->minratio, opts->maxratio);
604}
605
[1695]606#if defined HAVE_REGEX_H
[1529]607static char *merge_file(char *regex, char *file)
608{
[1661]609    char *newfile = malloc(5 + 2 * strlen(file) + 1 + 1), *tmp = newfile;
[1529]610
[1661]611    *tmp++ = '(';
[1529]612    *tmp++ = '^';
[1661]613    *tmp++ = '|';
614    *tmp++ = '/';
615    *tmp++ = ')';
[1529]616    while(*file)
617    {
618        if(strchr("^.[$()|*+?{\\", *file))
619            *tmp++ = '\\';
620        *tmp++ = *file++;
621    }
622    *tmp++ = '$';
623    *tmp++ = '\0';
624
625    tmp = merge_regex(regex, newfile);
626    free(newfile);
627    return tmp;
628}
629
630static char *merge_regex(char *regex, char *string)
631{
632    regex_t optre;
633
634    if(regex)
635    {
636        regex = realloc(regex, strlen(regex) + strlen(string) + 1 + 1);
637        sprintf(regex + strlen(regex) - 1, "|%s)", string);
638    }
639    else
640    {
641        regex = malloc(1 + strlen(string) + 1 + 1);
642        sprintf(regex, "(%s)", string);
643    }
644
645    if(regcomp(&optre, regex, REG_EXTENDED) != 0)
646    {
647        free(regex);
648        return NULL;
649    }
650    regfree(&optre);
651
652    return regex;
653}
[1695]654#endif
[1529]655
[1692]656static void spawn_children(struct opts *opts)
[1505]657{
[1758]658    int pipes[3][2];
[1660]659    int64_t now = _zz_time();
[1505]660    pid_t pid;
[1535]661    int i, j;
[1505]662
[1692]663    if(opts->nchild == opts->maxchild)
[1659]664        return; /* no slot */
665
[1692]666    if(opts->seed == opts->endseed)
[1659]667        return; /* job finished */
668
[1692]669    if(opts->maxcrashes && opts->crashes >= opts->maxcrashes)
[1659]670        return; /* all jobs crashed */
671
[1692]672    if(opts->delay > 0 && opts->lastlaunch + opts->delay > now)
[1660]673        return; /* too early */
674
[1623]675    /* Find the empty slot */
[1692]676    for(i = 0; i < opts->maxchild; i++)
677        if(opts->child[i].status == STATUS_FREE)
[1505]678            break;
679
[1503]680    /* Prepare communication pipe */
[1535]681    for(j = 0; j < 3; j++)
[1702]682    {
683        int ret;
684#if defined HAVE_PIPE
[1758]685        ret = pipe(pipes[j]);
[1702]686#elif defined HAVE__PIPE
[1758]687        ret = _pipe(pipes[j], 512, _O_BINARY | O_NOINHERIT);
[1702]688#endif
689        if(ret < 0)
[1535]690        {
691            perror("pipe");
[4106]692            opts->seed++;
[1535]693            return;
694        }
[1702]695    }
[1464]696
[1758]697    pid = run_process(opts, pipes);
[1743]698    if(pid < 0)
[4106]699    {
700        fprintf(stderr, "error launching `%s'\n", opts->newargv[0]);
701        opts->seed++;
[1702]702        return;
[4106]703    }
[1641]704
[1623]705    /* We’re the parent, acknowledge spawn */
[1692]706    opts->child[i].date = now;
707    opts->child[i].pid = pid;
[1623]708    for(j = 0; j < 3; j++)
709    {
[1758]710        close(pipes[j][1]);
711        opts->child[i].fd[j] = pipes[j][0];
[1623]712    }
[1692]713    opts->child[i].bytes = 0;
714    opts->child[i].seed = opts->seed;
715    opts->child[i].ratio = _zz_getratio();
716    opts->child[i].status = STATUS_RUNNING;
717    if(opts->md5)
718        opts->child[i].ctx = _zz_md5_init();
[1659]719
[1692]720    if(opts->verbose)
[1709]721    {
[1710]722        finfo(stderr, opts, opts->child[i].seed);
[2333]723        fprintf(stderr, "launched `%s'\n", opts->newargv[0]);
[1709]724    }
[1672]725
[1692]726    opts->lastlaunch = now;
727    opts->nchild++;
728    opts->seed++;
[1672]729
[1692]730    _zz_setseed(opts->seed);
[1470]731}
732
[1692]733static void clean_children(struct opts *opts)
[1546]734{
[1702]735#if defined HAVE_KILL
[1657]736    int64_t now = _zz_time();
[1702]737#endif
[1546]738    int i, j;
739
[1702]740#if defined HAVE_KILL
[1546]741    /* Terminate children if necessary */
[1692]742    for(i = 0; i < opts->maxchild; i++)
[1546]743    {
[1692]744        if(opts->child[i].status == STATUS_RUNNING
745            && opts->maxbytes >= 0
746            && opts->child[i].bytes > opts->maxbytes)
[1546]747        {
[1692]748            if(opts->verbose)
[1709]749            {
[1710]750                finfo(stderr, opts, opts->child[i].seed);
[1709]751                fprintf(stderr, "data output exceeded, sending SIGTERM\n");
752            }
[1692]753            kill(opts->child[i].pid, SIGTERM);
754            opts->child[i].date = now;
755            opts->child[i].status = STATUS_SIGTERM;
[1546]756        }
757
[1692]758        if(opts->child[i].status == STATUS_RUNNING
759            && opts->maxtime >= 0
760            && now > opts->child[i].date + opts->maxtime)
[1546]761        {
[1692]762            if(opts->verbose)
[1709]763            {
[1710]764                finfo(stderr, opts, opts->child[i].seed);
[1709]765                fprintf(stderr, "running time exceeded, sending SIGTERM\n");
766            }
[1692]767            kill(opts->child[i].pid, SIGTERM);
768            opts->child[i].date = now;
769            opts->child[i].status = STATUS_SIGTERM;
[1546]770        }
771    }
772
[1657]773    /* Kill children if necessary (still there after 2 seconds) */
[1692]774    for(i = 0; i < opts->maxchild; i++)
[1546]775    {
[1692]776        if(opts->child[i].status == STATUS_SIGTERM
777            && now > opts->child[i].date + 2000000)
[1546]778        {
[1692]779            if(opts->verbose)
[1709]780            {
[1710]781                finfo(stderr, opts, opts->child[i].seed);
[1709]782                fprintf(stderr, "not responding, sending SIGKILL\n");
783            }
[1692]784            kill(opts->child[i].pid, SIGKILL);
785            opts->child[i].status = STATUS_SIGKILL;
[1546]786        }
787    }
[1702]788#endif
[1546]789
790    /* Collect dead children */
[1692]791    for(i = 0; i < opts->maxchild; i++)
[1546]792    {
[1623]793        uint8_t md5sum[16];
[1702]794#if defined HAVE_WAITPID
[1546]795        int status;
796        pid_t pid;
[1702]797#endif
[1546]798
[1692]799        if(opts->child[i].status != STATUS_SIGKILL
800            && opts->child[i].status != STATUS_SIGTERM
801            && opts->child[i].status != STATUS_EOF)
[1546]802            continue;
803
[1702]804#if defined HAVE_WAITPID
[1692]805        pid = waitpid(opts->child[i].pid, &status, WNOHANG);
[1546]806        if(pid <= 0)
807            continue;
808
[1692]809        if(opts->checkexit && WIFEXITED(status) && WEXITSTATUS(status))
[1573]810        {
[1710]811            finfo(stderr, opts, opts->child[i].seed);
[1709]812            fprintf(stderr, "exit %i\n", WEXITSTATUS(status));
[1692]813            opts->crashes++;
[1573]814        }
[1650]815        else if(WIFSIGNALED(status)
816                 && !(WTERMSIG(status) == SIGTERM
[1692]817                       && opts->child[i].status == STATUS_SIGTERM))
[1573]818        {
[1801]819            char const *message = "";
820
821            if(WTERMSIG(status) == SIGKILL && opts->maxmem >= 0)
822                message = " (memory exceeded?)";
823#   if defined SIGXCPU
824            else if(WTERMSIG(status) == SIGXCPU && opts->maxcpu >= 0)
825                message = " (CPU time exceeded?)";
826#   endif
827            else if(WTERMSIG(status) == SIGKILL && opts->maxcpu >= 0)
828                message = " (CPU time exceeded?)";
829
[1710]830            finfo(stderr, opts, opts->child[i].seed);
[1709]831            fprintf(stderr, "signal %i%s%s\n",
[2555]832                    WTERMSIG(status), sig2name(WTERMSIG(status)), message);
[1692]833            opts->crashes++;
[1573]834        }
[1702]835#endif
[1546]836
837        for(j = 0; j < 3; j++)
[1692]838            if(opts->child[i].fd[j] >= 0)
839                close(opts->child[i].fd[j]);
[1546]840
[1692]841        if(opts->md5)
[1623]842        {
[1692]843            _zz_md5_fini(md5sum, opts->child[i].ctx);
[1710]844            finfo(stdout, opts, opts->child[i].seed);
[1709]845            fprintf(stdout, "%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x"
846                    "%.02x%.02x%.02x%.02x%.02x%.02x%.02x\n", md5sum[0],
847                    md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5],
848                    md5sum[6], md5sum[7], md5sum[8], md5sum[9], md5sum[10],
849                    md5sum[11], md5sum[12], md5sum[13], md5sum[14], md5sum[15]);
[1680]850            fflush(stdout);
[1623]851        }
[1692]852        opts->child[i].status = STATUS_FREE;
853        opts->nchild--;
[1546]854    }
855}
856
[1692]857static void read_children(struct opts *opts)
[1546]858{
859    struct timeval tv;
860    fd_set fdset;
861    int i, j, ret, maxfd = 0;
862
863    /* Read data from all sockets */
864    FD_ZERO(&fdset);
[1692]865    for(i = 0; i < opts->maxchild; i++)
[1546]866    {
[1692]867        if(opts->child[i].status != STATUS_RUNNING)
[1546]868            continue;
869
870        for(j = 0; j < 3; j++)
[1692]871            ZZUF_FD_SET(opts->child[i].fd[j], &fdset, maxfd);
[1546]872    }
873    tv.tv_sec = 0;
874    tv.tv_usec = 1000;
875
876    ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
[1702]877    if(ret < 0 && errno)
[1546]878        perror("select");
879    if(ret <= 0)
880        return;
881
882    /* XXX: cute (i, j) iterating hack */
[1692]883    for(i = 0, j = 0; i < opts->maxchild; i += (j == 2), j = (j + 1) % 3)
[1546]884    {
[1623]885        uint8_t buf[BUFSIZ];
[1546]886
[1692]887        if(opts->child[i].status != STATUS_RUNNING)
[1546]888            continue;
889
[1692]890        if(!ZZUF_FD_ISSET(opts->child[i].fd[j], &fdset))
[1546]891            continue;
892
[1692]893        ret = read(opts->child[i].fd[j], buf, BUFSIZ - 1);
[1546]894        if(ret > 0)
895        {
896            /* We got data */
897            if(j != 0)
[1692]898                opts->child[i].bytes += ret;
[1623]899
[1692]900            if(opts->md5 && j == 2)
901                _zz_md5_add(opts->child[i].ctx, buf, ret);
902            else if(!opts->quiet || j == 0)
[1546]903                write((j < 2) ? STDERR_FILENO : STDOUT_FILENO, buf, ret);
904        }
905        else if(ret == 0)
906        {
907            /* End of file reached */
[1692]908            close(opts->child[i].fd[j]);
909            opts->child[i].fd[j] = -1;
[1546]910
[1692]911            if(opts->child[i].fd[0] == -1
912                && opts->child[i].fd[1] == -1
913                && opts->child[i].fd[2] == -1)
914                opts->child[i].status = STATUS_EOF;
[1546]915        }
916    }
917}
918
[1704]919#if !defined HAVE_SETENV
[1702]920static void setenv(char const *name, char const *value, int overwrite)
921{
922    char *str;
923
924    if(!overwrite && getenv(name))
925        return;
926
927    str = malloc(strlen(name) + 1 + strlen(value) + 1);
928    sprintf(str, "%s=%s", name, value);
929    putenv(str);
930}
931#endif
932
933#if defined HAVE_WAITPID
[2555]934static char const *sig2name(int signum)
[1665]935{
936    switch(signum)
937    {
[1702]938#ifdef SIGQUIT
[2341]939        case SIGQUIT:  return " (SIGQUIT)"; /* 3 */
[1702]940#endif
[2341]941        case SIGILL:   return " (SIGILL)";  /* 4 */
[1702]942#ifdef SIGTRAP
[2341]943        case SIGTRAP:  return " (SIGTRAP)"; /* 5 */
[1702]944#endif
[2341]945        case SIGABRT:  return " (SIGABRT)"; /* 6 */
946#ifdef SIGBUS
947        case SIGBUS:   return " (SIGBUS)";  /* 7 */
[1665]948#endif
[2341]949        case SIGFPE:   return " (SIGFPE)";  /* 8 */
950        case SIGSEGV:  return " (SIGSEGV)"; /* 11 */
951        case SIGPIPE:  return " (SIGPIPE)"; /* 13 */
[1665]952#ifdef SIGEMT
[2341]953        case SIGEMT:   return " (SIGEMT)";  /* ? */
[1665]954#endif
955#ifdef SIGXCPU
[2341]956        case SIGXCPU:  return " (SIGXCPU)"; /* 24 */
[1665]957#endif
958#ifdef SIGXFSZ
[2341]959        case SIGXFSZ:  return " (SIGXFSZ)"; /* 25 */
[1665]960#endif
[2341]961#ifdef SIGSYS
962        case SIGSYS:   return " (SIGSYS)";  /* 31 */
963#endif
[1665]964    }
965
966    return "";
967}
[1702]968#endif
[1665]969
[1758]970static int run_process(struct opts *opts, int pipes[][2])
[1470]971{
[1743]972    char buf[64];
[1702]973#if defined HAVE_FORK
[1743]974    static int const files[] = { DEBUG_FILENO, STDERR_FILENO, STDOUT_FILENO };
[1470]975    char *libpath, *tmp;
[1743]976    int pid, j, len = strlen(opts->oldargv[0]);
[1702]977#   if defined __APPLE__
978#       define EXTRAINFO ""
979#       define PRELOAD "DYLD_INSERT_LIBRARIES"
[1543]980    setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
[1702]981#   elif defined __osf__
982#       define EXTRAINFO ":DEFAULT"
983#       define PRELOAD "_RLD_LIST"
984#   else
985#       define EXTRAINFO ""
986#       define PRELOAD "LD_PRELOAD"
987#   endif
[1743]988#elif HAVE_WINDOWS_H
989    PROCESS_INFORMATION pinfo;
990    STARTUPINFO sinfo;
991    HANDLE pid;
992    void *epaddr;
[2461]993    int ret;
[1743]994#endif
[1470]995
[1743]996#if defined HAVE_FORK
997    /* Fork and launch child */
998    pid = fork();
999    if(pid < -1)
1000        perror("fork");
1001    if(pid != 0)
1002        return pid;
1003
1004    /* We loop in reverse order so that files[0] is done last,
1005     * just in case one of the other dup2()ed fds had the value */
1006    for(j = 3; j--; )
1007    {
[1758]1008        close(pipes[j][0]);
1009        if(pipes[j][1] != files[j])
[1743]1010        {
[1758]1011            dup2(pipes[j][1], files[j]);
1012            close(pipes[j][1]);
[1743]1013        }
1014    }
1015#endif
1016
[1799]1017#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
[1743]1018    if(opts->maxmem >= 0)
1019    {
1020        struct rlimit rlim;
1021        rlim.rlim_cur = opts->maxmem * 1000000;
1022        rlim.rlim_max = opts->maxmem * 1000000;
[1799]1023        setrlimit(ZZUF_RLIMIT_MEM, &rlim);
[1743]1024    }
1025#endif
1026
[1801]1027#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_CPU
1028    if(opts->maxcpu >= 0)
1029    {
1030        struct rlimit rlim;
1031        rlim.rlim_cur = opts->maxcpu;
1032        rlim.rlim_max = opts->maxcpu + 5;
1033        setrlimit(ZZUF_RLIMIT_CPU, &rlim);
1034    }
1035#endif
1036
[1743]1037    /* Set environment variables */
1038    sprintf(buf, "%i", opts->seed);
1039    setenv("ZZUF_SEED", buf, 1);
1040    sprintf(buf, "%g", opts->minratio);
1041    setenv("ZZUF_MINRATIO", buf, 1);
1042    sprintf(buf, "%g", opts->maxratio);
1043    setenv("ZZUF_MAXRATIO", buf, 1);
1044
1045#if defined HAVE_FORK
[2461]1046    /* Make sure there is space for everything we might do. */
[3631]1047    libpath = malloc(len + strlen(LIBDIR "/" LT_OBJDIR SONAME EXTRAINFO) + 1);
[1743]1048    strcpy(libpath, opts->oldargv[0]);
[1629]1049
[2461]1050    /* If the binary name contains a '/', we look for a libzzuf in the
1051     * same directory. Otherwise, we only look into the system directory
1052     * to avoid shared library attacks. Write the result in libpath. */
[1470]1053    tmp = strrchr(libpath, '/');
[2461]1054    if(tmp)
1055    {
[3631]1056        strcpy(tmp + 1, LT_OBJDIR SONAME);
[2461]1057        if(access(libpath, R_OK) < 0)
[2534]1058            strcpy(libpath, LIBDIR "/" SONAME);
[2461]1059    }
1060    else
[2534]1061        strcpy(libpath, LIBDIR "/" SONAME);
[1629]1062
[1796]1063    /* OSF1 only */
1064    strcat(libpath, EXTRAINFO);
1065
1066    /* Do not clobber previous LD_PRELOAD values */
1067    tmp = getenv(PRELOAD);
1068    if(tmp && *tmp)
1069    {
1070        char *bigbuf = malloc(strlen(tmp) + strlen(libpath) + 2);
1071        sprintf(bigbuf, "%s:%s", tmp, libpath);
1072        free(libpath);
1073        libpath = bigbuf;
1074    }
1075
1076    setenv(PRELOAD, libpath, 1);
[1470]1077    free(libpath);
[1702]1078
[1743]1079    if(execvp(opts->newargv[0], opts->newargv))
[1702]1080    {
[1743]1081        perror(opts->newargv[0]);
1082        exit(EXIT_FAILURE);
[1702]1083    }
1084
[1743]1085    exit(EXIT_SUCCESS);
1086    /* no return */
[1702]1087    return 0;
1088#elif HAVE_WINDOWS_H
[1743]1089    pid = GetCurrentProcess();
[1702]1090
1091    /* Get entry point */
[1743]1092    epaddr = get_entry(opts->newargv[0]);
[1702]1093    if(!epaddr)
1094        return -1;
[2326]1095
[1702]1096    memset(&sinfo, 0, sizeof(sinfo));
1097    sinfo.cb = sizeof(sinfo);
[1758]1098    DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[0][1]), pid,
[1743]1099        /* FIXME */ &sinfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
[1758]1100    DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[1][1]), pid,
[1743]1101                    &sinfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
[1758]1102    DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[2][1]), pid,
[1743]1103                    &sinfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
[1744]1104    sinfo.dwFlags = STARTF_USESTDHANDLES;
[1743]1105    ret = CreateProcess(NULL, opts->newargv[0], NULL, NULL, FALSE,
[1702]1106                        CREATE_SUSPENDED, NULL, NULL, &sinfo, &pinfo);
1107    if(!ret)
1108        return -1;
1109
1110    /* Insert the replacement code */
1111    ret = dll_inject(pinfo.hProcess, epaddr);
1112    if(ret < 0)
1113    {
1114        TerminateProcess(pinfo.hProcess, -1);
1115        return -1;
1116    }
1117
1118    ret = ResumeThread(pinfo.hThread);
1119    if(ret < 0)
1120    {
1121        TerminateProcess(pinfo.hProcess, -1);
1122        return -1;
1123    }
1124
[1743]1125    return (long int)pinfo.hProcess;
[1702]1126#endif
[1464]1127}
1128
[1702]1129#if defined HAVE_WINDOWS_H
1130static int dll_inject(void *process, void *epaddr)
1131{
1132    uint8_t old_ep[7];
1133    uint8_t new_ep[] = "\xb8<01>\xff\xe0";
1134    uint8_t loader[] = "libzzuf.dll\0<0000c>\xb8<14>\x50\xb8<1a>\xff\xd0"
1135                       "\xb8\0\0\0\0\x50\xb8\x07\x00\x00\x00\x50\xb8<2d>"
1136                       "\x50\xb8<33>\x50\xb8<39>\xff\xd0\x50\xb8<41>\xff"
1137                       "\xd0\xb8<48>\xff\xe0";
1138    void *lib;
1139    uint8_t *loaderaddr;
1140    DWORD tmp;
1141
1142    /* Save the old entry-point code */
1143    ReadProcessMemory(process, epaddr, old_ep, 7, &tmp);
1144    if(tmp != 7)
1145        return -1;
1146
1147    loaderaddr = VirtualAllocEx(process, NULL, 78, MEM_COMMIT,
1148                                PAGE_EXECUTE_READWRITE);
1149    if(!loaderaddr)
1150        return -1;
1151
1152    addcpy(new_ep + 0x01, loaderaddr + 0x0c + 7);
1153    WriteProcessMemory(process, epaddr, new_ep, 7, &tmp);
1154    if(tmp != 7)
1155        return -1;
1156
1157    lib = LoadLibrary("kernel32.dll");
1158    if(!lib)
1159        return -1;
1160
1161    memcpy(loader + 0x0c, old_ep, 7);
1162    addcpy(loader + 0x14, loaderaddr + 0x00); /* offset for dll string */
1163    addcpy(loader + 0x1a, GetProcAddress(lib, "LoadLibraryA"));
1164    addcpy(loader + 0x2d, loaderaddr + 0x0c);
1165    addcpy(loader + 0x33, epaddr);
1166    addcpy(loader + 0x39, GetProcAddress(lib, "GetCurrentProcess"));
1167    addcpy(loader + 0x41, GetProcAddress(lib, "WriteProcessMemory"));
1168    addcpy(loader + 0x48, epaddr);
1169    FreeLibrary(lib);
1170
1171    WriteProcessMemory(process, loaderaddr, loader, 78, &tmp);
1172    if(tmp != 78)
1173        return -1;
1174
1175    return 0;
1176}
1177
1178static void *get_entry(char const *name)
1179{
1180    PIMAGE_DOS_HEADER dos;
1181    PIMAGE_NT_HEADERS nt;
[4106]1182    void *file, *map, *base, *ret = NULL;
[1702]1183
1184    file = CreateFile(name, GENERIC_READ, FILE_SHARE_READ,
1185                      NULL, OPEN_EXISTING, 0, NULL);
1186    if(file == INVALID_HANDLE_VALUE)
[4106]1187        return ret;
[1702]1188
1189    map = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
1190    if(!map)
1191    {
1192        CloseHandle(file);
[4106]1193        return ret;
[1702]1194    }
1195
1196    base = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
1197    if(!base)
1198    {
1199        CloseHandle(map);
1200        CloseHandle(file);
[4106]1201        return ret;
[1702]1202    }
1203
1204    /* Sanity checks */
1205    dos = (PIMAGE_DOS_HEADER)base;
1206    nt = (PIMAGE_NT_HEADERS)((char *)base + dos->e_lfanew);
[4106]1207    if(dos->e_magic == IMAGE_DOS_SIGNATURE /* 0x5A4D */
1208      && nt->Signature == IMAGE_NT_SIGNATURE /* 0x00004550 */
1209      && nt->FileHeader.Machine == IMAGE_FILE_MACHINE_I386
1210      && nt->OptionalHeader.Magic == 0x10b /* IMAGE_NT_OPTIONAL_HDR32_MAGIC */)
[1702]1211    {
[4106]1212        ret = (void *)(uintptr_t)(nt->OptionalHeader.ImageBase +
1213                                  nt->OptionalHeader.AddressOfEntryPoint);
[1702]1214    }
1215
[4106]1216    UnmapViewOfFile(base);
1217    CloseHandle(map);
1218    CloseHandle(file);
1219
1220    return ret;
[1702]1221}
1222#endif
1223
[1464]1224static void version(void)
1225{
[2319]1226    printf("zzuf %s\n", PACKAGE_VERSION);
[3635]1227    printf("Copyright (C) 2002, 2007-2009 Sam Hocevar <sam@hocevar.net>\n");
[2525]1228    printf("This program is free software. It comes without any warranty, to the extent\n");
1229    printf("permitted by applicable law. You can redistribute it and/or modify it under\n");
1230    printf("the terms of the Do What The Fuck You Want To Public License, Version 2, as\n");
1231    printf("published by Sam Hocevar. See <http://sam.zoy.org/wtfpl/> for more details.\n");
[1502]1232    printf("\n");
[3635]1233    printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
[1464]1234}
1235
1236static void usage(void)
1237{
[1695]1238#if defined HAVE_REGEX_H
[1698]1239    printf("Usage: zzuf [-AcdimnqSvx] [-s seed|-s start:stop] [-r ratio|-r min:max]\n");
[1695]1240#else
[1698]1241    printf("Usage: zzuf [-AdimnqSvx] [-s seed|-s start:stop] [-r ratio|-r min:max]\n");
[1695]1242#endif
[2344]1243    printf("              [-f fuzzing] [-D delay] [-j jobs] [-C crashes] [-B bytes]\n");
[1801]1244    printf("              [-t seconds] ");
1245#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_CPU
1246    printf(                           "[-T seconds] ");
1247#endif
[1799]1248#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
[2345]1249    printf(                                        "[-M mebibytes] ");
[1742]1250#endif
[1858]1251    printf(                                                       "[-b ranges] [-p ports]\n");
1252    printf("              [-P protect] [-R refuse] [-l list]");
[1705]1253#if defined HAVE_REGEX_H
[1802]1254    printf(                                                " [-I include] [-E exclude]");
[1705]1255#endif
[1802]1256    printf("\n");
1257    printf("              [PROGRAM [--] [ARGS]...]\n");
[1577]1258    printf("       zzuf -h | --help\n");
[1666]1259    printf("       zzuf -V | --version\n");
[1658]1260    printf("Run PROGRAM with optional arguments ARGS and fuzz its input.\n");
[1502]1261    printf("\n");
1262    printf("Mandatory arguments to long options are mandatory for short options too.\n");
[3635]1263    printf("  -a, --allow <list>        only fuzz network input for IPs in <list>\n");
[1672]1264    printf("  -A, --autoinc             increment seed each time a new file is opened\n");
[1705]1265    printf("  -b, --bytes <ranges>      only fuzz bytes at offsets within <ranges>\n");
[1672]1266    printf("  -B, --max-bytes <n>       kill children that output more than <n> bytes\n");
[1695]1267#if defined HAVE_REGEX_H
[1672]1268    printf("  -c, --cmdline             only fuzz files specified in the command line\n");
[1695]1269#endif
[1672]1270    printf("  -C, --max-crashes <n>     stop after <n> children have crashed (default 1)\n");
1271    printf("  -d, --debug               print debug messages\n");
1272    printf("  -D, --delay               delay between forks\n");
[3635]1273    printf("  -e, --deny <list>         do not fuzz network input for IPs in <list>\n");
[1695]1274#if defined HAVE_REGEX_H
[1672]1275    printf("  -E, --exclude <regex>     do not fuzz files matching <regex>\n");
[1695]1276#endif
[1720]1277    printf("  -f, --fuzzing <mode>      use fuzzing mode <mode> ([xor] set unset)\n");
[1672]1278    printf("  -i, --stdin               fuzz standard input\n");
[1695]1279#if defined HAVE_REGEX_H
[1672]1280    printf("  -I, --include <regex>     only fuzz files matching <regex>\n");
[1695]1281#endif
[2344]1282    printf("  -j, --jobs <n>            number of simultaneous jobs (default 1)\n");
[1858]1283    printf("  -l, --list <list>         only fuzz Nth descriptor with N in <list>\n");
[1672]1284    printf("  -m, --md5                 compute the output's MD5 hash\n");
[1799]1285#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
[2521]1286    printf("  -M, --max-memory <n>      maximum child virtual memory in MiB (default %u)\n", DEFAULT_MEM);
[1702]1287#endif
[1672]1288    printf("  -n, --network             fuzz network input\n");
[1858]1289    printf("  -p, --ports <list>        only fuzz network destination ports in <list>\n");
[1672]1290    printf("  -P, --protect <list>      protect bytes and characters in <list>\n");
1291    printf("  -q, --quiet               do not print children's messages\n");
1292    printf("  -r, --ratio <ratio>       bit fuzzing ratio (default %g)\n", DEFAULT_RATIO);
1293    printf("      --ratio <start:stop>  specify a ratio range\n");
1294    printf("  -R, --refuse <list>       refuse bytes and characters in <list>\n");
1295    printf("  -s, --seed <seed>         random seed (default %i)\n", DEFAULT_SEED);
1296    printf("      --seed <start:stop>   specify a seed range\n");
1297    printf("  -S, --signal              prevent children from diverting crashing signals\n");
[1800]1298    printf("  -t, --max-time <n>        kill children that run for more than <n> seconds\n");
[3001]1299    printf("  -T, --max-cputime <n>     kill children that use more than <n> CPU seconds\n");
[1672]1300    printf("  -v, --verbose             print information during the run\n");
1301    printf("  -x, --check-exit          report processes that exit with a non-zero status\n");
1302    printf("  -h, --help                display this help and exit\n");
1303    printf("  -V, --version             output version information and exit\n");
[1502]1304    printf("\n");
[3635]1305    printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n");
[1464]1306}
1307
Note: See TracBrowser for help on using the repository browser.