diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/afl-cc.c | 7 | ||||
-rw-r--r-- | src/afl-common.c | 46 | ||||
-rw-r--r-- | src/afl-forkserver.c | 7 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 43 | ||||
-rw-r--r-- | src/afl-fuzz-state.c | 4 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 178 | ||||
-rw-r--r-- | src/afl-fuzz.c | 40 | ||||
-rw-r--r-- | src/afl-tmin.c | 34 |
8 files changed, 262 insertions, 97 deletions
diff --git a/src/afl-cc.c b/src/afl-cc.c index faa46103..45fd398b 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1369,6 +1369,13 @@ void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) { } + if (getenv("AFL_LLVM_DICT2FILE") && + (getenv("AFL_LLVM_LAF_SPLIT_SWITCHES") || + getenv("AFL_LLVM_LAF_SPLIT_COMPARES") || + getenv("AFL_LLVM_LAF_SPLIT_FLOATS") || + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) + FATAL("AFL_LLVM_DICT2FILE is incompatible with AFL_LLVM_LAF_*"); + aflcc->cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") || getenv("AFL_GCC_CMPLOG"); diff --git a/src/afl-common.c b/src/afl-common.c index 87003b03..6d915b00 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -34,6 +34,7 @@ #endif #include <string.h> #include <strings.h> +#include <time.h> #include <math.h> #include <sys/mman.h> @@ -58,6 +59,27 @@ u8 last_intr = 0; #define AFL_PATH "/usr/local/lib/afl/" #endif +/* - Some BSD (i.e.: FreeBSD) offer the FAST clock source as + * equivalent to Linux COARSE clock source. Aliasing COARSE to + * FAST on such systems when COARSE is not already defined. + * - macOS has no support of CLOCK_MONOTONIC_COARSE clock type. + */ +#if defined(OS_DARWIN) || defined(OS_SUNOS) || defined(__APPLE__) || \ + defined(__sun) || defined(__NetBSD__) + #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC +#elif defined(OS_FREEBSD) + #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST +#endif + +/* Convert seconds to milliseconds. */ +#define SEC_TO_MS(sec) ((sec) * 1000) +/* Convert seconds to microseconds. */ +#define SEC_TO_US(sec) ((sec) * 1000000) +/* Convert nanoseconds to milliseconds. */ +#define NS_TO_MS(ns) ((ns) / 1000000) +/* Convert nanoseconds to microseconds. */ +#define NS_TO_US(ns) ((ns) / 1000) + void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { @@ -974,12 +996,16 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { inline u64 get_cur_time(void) { - struct timeval tv; - struct timezone tz; + struct timespec ts; + int rc = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + if (rc == -1) { - gettimeofday(&tv, &tz); + PFATAL("Failed to obtain timestamp (errno = %i: %s)\n", errno, + strerror(errno)); - return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); + } + + return SEC_TO_MS((uint64_t)ts.tv_sec) + NS_TO_MS((uint64_t)ts.tv_nsec); } @@ -987,12 +1013,16 @@ inline u64 get_cur_time(void) { u64 get_cur_time_us(void) { - struct timeval tv; - struct timezone tz; + struct timespec ts; + int rc = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + if (rc == -1) { - gettimeofday(&tv, &tz); + PFATAL("Failed to obtain timestamp (errno = %i: %s)\n", errno, + strerror(errno)); + + } - return (tv.tv_sec * 1000000ULL) + tv.tv_usec; + return SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index cf5c511e..f28a2a64 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1111,8 +1111,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if ((status & FS_NEW_OPT_SHDMEM_FUZZ) && fsrv->add_extra_func && - !ignore_autodict) { + if (status & FS_NEW_OPT_SHDMEM_FUZZ) { if (fsrv->support_shmem_fuzz) { @@ -1129,7 +1128,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if ((status & FS_NEW_OPT_AUTODICT)) { + if (status & FS_NEW_OPT_AUTODICT) { // even if we do not need the dictionary we have to read it @@ -1875,7 +1874,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, territory. */ #ifdef __linux__ - if (!fsrv->nyx_mode) { + if (likely(!fsrv->nyx_mode)) { memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index d764952c..edcddc8e 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -409,6 +409,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 use_tmout = afl->fsrv.exec_tmout; u8 *old_sn = afl->stage_name; + u64 calibration_start_us = get_cur_time_us(); if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; } /* Be a bit more generous about timeouts when resuming sessions, or when @@ -504,6 +505,10 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); + // update the time spend in calibration after each execution, as those may + // be slow + update_calibration_time(afl, &calibration_start_us); + /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ @@ -650,6 +655,7 @@ abort_calibration: if (!first_run) { show_stats(afl); } + update_calibration_time(afl, &calibration_start_us); return fault; } @@ -669,11 +675,16 @@ void sync_fuzzers(afl_state_t *afl) { afl->stage_max = afl->stage_cur = 0; afl->cur_depth = 0; + u64 sync_start_us = get_cur_time_us(); /* Look at the entries created for every other fuzzer in the sync directory. */ while ((sd_ent = readdir(sd))) { + // since sync can take substantial amounts of time, update time spend every + // iteration + update_sync_time(afl, &sync_start_us); + u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX]; u32 min_accept = 0, next_min_accept = 0; @@ -811,7 +822,7 @@ void sync_fuzzers(afl_state_t *afl) { /* See what happens. We rely on save_if_interesting() to catch major errors and save the test case. */ - (void)write_to_testcase(afl, (void **)&mem, st.st_size, 1); + u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); @@ -819,7 +830,7 @@ void sync_fuzzers(afl_state_t *afl) { afl->syncing_party = sd_ent->d_name; afl->queued_imported += - save_if_interesting(afl, mem, st.st_size, fault); + save_if_interesting(afl, mem, new_len, fault); afl->syncing_party = 0; munmap(mem, st.st_size); @@ -861,6 +872,9 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); + // add time in sync one last time + update_sync_time(afl, &sync_start_us); + afl->last_sync_time = get_cur_time(); afl->last_sync_cycle = afl->queue_cycle; @@ -872,8 +886,9 @@ void sync_fuzzers(afl_state_t *afl) { u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { + u8 needs_write = 0, fault = 0; u32 orig_len = q->len; - + u64 trim_start_us = get_cur_time_us(); /* Custom mutator trimmer */ if (afl->custom_mutators_count) { @@ -897,11 +912,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } - if (custom_trimmed) return trimmed_case; + if (custom_trimmed) { + + fault = trimmed_case; + goto abort_trimming; + + } } - u8 needs_write = 0, fault = 0; u32 trim_exec = 0; u32 remove_len; u32 len_p2; @@ -912,7 +931,12 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { detected, it will still work to some extent, so we don't check for this. */ - if (unlikely(q->len < 5)) { return 0; } + if (unlikely(q->len < 5)) { + + fault = 0; + goto abort_trimming; + + } afl->stage_name = afl->stage_name_buf; afl->bytes_trim_in += q->len; @@ -946,6 +970,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + update_trim_time(afl, &trim_start_us); + if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } /* Note that we don't keep track of crashes or hangs here; maybe TODO? @@ -972,7 +998,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Let's save a clean trace, which will be needed by update_bitmap_score once we're done with the trimming stuff. */ - if (!needs_write) { needs_write = 1; @@ -987,7 +1012,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } /* Since this can be slow, update the screen every now and then. */ - if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } ++afl->stage_cur; @@ -1039,8 +1063,9 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } abort_trimming: - afl->bytes_trim_out += q->len; + update_trim_time(afl, &trim_start_us); + return fault; } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index ae327117..c61f00bd 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -28,10 +28,6 @@ #include "afl-fuzz.h" #include "envs.h" -s8 interesting_8[] = {INTERESTING_8}; -s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; -s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - char *power_names[POWER_SCHEDULES_NUM] = {"explore", "mmopt", "exploit", "fast", "coe", "lin", "quad", "rare", "seek"}; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index b6900506..7e1a3b92 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -133,6 +133,12 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { } +static bool starts_with(char *key, char *line) { + + return strncmp(key, line, strlen(key)) == 0; + +} + /* load some of the existing stats file when resuming.*/ void load_stats_file(afl_state_t *afl) { @@ -175,58 +181,84 @@ void load_stats_file(afl_state_t *afl) { strcpy(keystring, lstartptr); lptr++; char *nptr; - switch (lineno) { - - case 3: - if (!strcmp(keystring, "run_time ")) - afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10); - break; - case 5: - if (!strcmp(keystring, "cycles_done ")) - afl->queue_cycle = - strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0; - break; - case 7: - if (!strcmp(keystring, "execs_done ")) - afl->fsrv.total_execs = strtoull(lptr, &nptr, 10); - break; - case 10: - if (!strcmp(keystring, "corpus_count ")) { - - u32 corpus_count = strtoul(lptr, &nptr, 10); - if (corpus_count != afl->queued_items) { - - WARNF( - "queue/ has been modified -- things might not work, you're " - "on your own!"); - - } - - } - - break; - case 12: - if (!strcmp(keystring, "corpus_found ")) - afl->queued_discovered = strtoul(lptr, &nptr, 10); - break; - case 13: - if (!strcmp(keystring, "corpus_imported ")) - afl->queued_imported = strtoul(lptr, &nptr, 10); - break; - case 14: - if (!strcmp(keystring, "max_depth ")) - afl->max_depth = strtoul(lptr, &nptr, 10); - break; - case 21: - if (!strcmp(keystring, "saved_crashes ")) - afl->saved_crashes = strtoull(lptr, &nptr, 10); - break; - case 22: - if (!strcmp(keystring, "saved_hangs ")) - afl->saved_hangs = strtoull(lptr, &nptr, 10); - break; - default: - break; + if (starts_with("run_time", keystring)) { + + afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10); + + } + + if (starts_with("cycles_done", keystring)) { + + afl->queue_cycle = + strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0; + + } + + if (starts_with("calibration_time", keystring)) { + + afl->calibration_time_us = strtoull(lptr, &nptr, 10) * 1000000; + + } + + if (starts_with("sync_time", keystring)) { + + afl->sync_time_us = strtoull(lptr, &nptr, 10) * 1000000; + + } + + if (starts_with("trim_time", keystring)) { + + afl->trim_time_us = strtoull(lptr, &nptr, 10) * 1000000; + + } + + if (starts_with("execs_done", keystring)) { + + afl->fsrv.total_execs = strtoull(lptr, &nptr, 10); + + } + + if (starts_with("corpus_count", keystring)) { + + u32 corpus_count = strtoul(lptr, &nptr, 10); + if (corpus_count != afl->queued_items) { + + WARNF( + "queue/ has been modified -- things might not work, you're " + "on your own!"); + sleep(3); + + } + + } + + if (starts_with("corpus_found", keystring)) { + + afl->queued_discovered = strtoul(lptr, &nptr, 10); + + } + + if (starts_with("corpus_imported", keystring)) { + + afl->queued_imported = strtoul(lptr, &nptr, 10); + + } + + if (starts_with("max_depth", keystring)) { + + afl->max_depth = strtoul(lptr, &nptr, 10); + + } + + if (starts_with("saved_crashes", keystring)) { + + afl->saved_crashes = strtoull(lptr, &nptr, 10); + + } + + if (starts_with("saved_hangs", keystring)) { + + afl->saved_hangs = strtoull(lptr, &nptr, 10); } @@ -300,6 +332,10 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, "cycles_done : %llu\n" "cycles_wo_finds : %llu\n" "time_wo_finds : %llu\n" + "fuzz_time : %llu\n" + "calibration_time : %llu\n" + "sync_time : %llu\n" + "trim_time : %llu\n" "execs_done : %llu\n" "execs_per_sec : %0.02f\n" "execs_ps_last_min : %0.02f\n" @@ -337,7 +373,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, "\n" "target_mode : %s%s%s%s%s%s%s%s%s%s\n" "command_line : %s\n", - (afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000, + (afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000, runtime / 1000, (u32)getpid(), afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, afl->longest_find_time > cur_time - afl->last_find_time @@ -345,7 +381,13 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, : ((afl->start_time == 0 || afl->last_find_time == 0) ? 0 : (cur_time - afl->last_find_time) / 1000), - afl->fsrv.total_execs, afl->fsrv.total_execs / ((double)(runtime) / 1000), + (runtime - + (afl->calibration_time_us + afl->sync_time_us + afl->trim_time_us) / + 1000) / + 1000, + afl->calibration_time_us / 1000000, afl->sync_time_us / 1000000, + afl->trim_time_us / 1000000, afl->fsrv.total_execs, + afl->fsrv.total_execs / ((double)(runtime) / 1000), afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored, afl->queued_discovered, afl->queued_imported, afl->queued_variable, afl->max_depth, afl->current_entry, afl->pending_favored, @@ -876,6 +918,10 @@ void show_stats_normal(afl_state_t *afl) { #endif + if (banner_pad) + for (u32 i = 0; i < banner_pad; ++i) + strcat(banner, " "); + } SAYF("\n%s\n", banner); @@ -2435,3 +2481,27 @@ void show_init_stats(afl_state_t *afl) { } +void update_calibration_time(afl_state_t *afl, u64 *time) { + + u64 cur = get_cur_time_us(); + afl->calibration_time_us += cur - *time; + *time = cur; + +} + +void update_trim_time(afl_state_t *afl, u64 *time) { + + u64 cur = get_cur_time_us(); + afl->trim_time_us += cur - *time; + *time = cur; + +} + +void update_sync_time(afl_state_t *afl, u64 *time) { + + u64 cur = get_cur_time_us(); + afl->sync_time_us += cur - *time; + *time = cur; + +} + diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 443d93b0..00d24ab1 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -5,8 +5,9 @@ Originally written by Michal Zalewski Now maintained by Marc Heuse <mh@mh-sec.de>, - Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and - Andrea Fioraldi <andreafioraldi@gmail.com> + Dominik Meier <mail@dmnk.co>, + Andrea Fioraldi <andreafioraldi@gmail.com>, and + Heiko Eissfeldt <heiko.eissfeldt@hexco.de> Copyright 2016, 2017 Google Inc. All rights reserved. Copyright 2019-2024 AFLplusplus Project. All rights reserved. @@ -199,7 +200,8 @@ static void usage(u8 *argv0, int more_help) { "Test settings:\n" " -s seed - use a fixed seed for the RNG\n" - " -V seconds - fuzz for a specified time then terminate\n" + " -V seconds - fuzz for a specified time then terminate (fuzz time " + "only!)\n" " -E execs - fuzz for an approx. no. of total executions then " "terminate\n" " Note: not precise and can have several more " @@ -2073,6 +2075,17 @@ int main(int argc, char **argv_orig, char **envp) { } + /* Simply code if AFL_TMPDIR is used or not */ + if (!afl->afl_env.afl_tmpdir) { + + afl->tmp_dir = afl->out_dir; + + } else { + + afl->tmp_dir = afl->afl_env.afl_tmpdir; + + } + write_setup_file(afl, argc, argv); setup_cmdline_file(afl, argv + optind); @@ -2085,8 +2098,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->timeout_given) { find_timeout(afl); } // only for resumes! - if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL && - !afl->in_place_resume) { + if (afl->afl_env.afl_tmpdir && !afl->in_place_resume) { char tmpfile[PATH_MAX]; @@ -2111,10 +2123,6 @@ int main(int argc, char **argv_orig, char **envp) { } - } else { - - afl->tmp_dir = afl->out_dir; - } /* If we don't have a file name chosen yet, use a safe default. */ @@ -2537,8 +2545,6 @@ int main(int argc, char **argv_orig, char **envp) { } // (void)nice(-20); // does not improve the speed - // real start time, we reset, so this works correctly with -V - afl->start_time = get_cur_time(); #ifdef INTROSPECTION u32 prev_saved_crashes = 0, prev_saved_tmouts = 0; @@ -2559,6 +2565,9 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Writing mutation introspection to '%s'", ifn); #endif + // real start time, we reset, so this works correctly with -V + afl->start_time = get_cur_time(); + while (likely(!afl->stop_soon)) { cull_queue(afl); @@ -2579,6 +2588,13 @@ int main(int argc, char **argv_orig, char **envp) { sync_fuzzers(afl); + if (!afl->queue_cycle && afl->afl_env.afl_import_first) { + + // real start time, we reset, so this works correctly with -V + afl->start_time = get_cur_time(); + + } + } ++afl->queue_cycle; @@ -3068,7 +3084,7 @@ stop_fuzzing: afl_fsrv_deinit(&afl->fsrv); /* remove tmpfile */ - if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { + if (!afl->in_place_resume && afl->fsrv.out_file) { (void)unlink(afl->fsrv.out_file); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 4e5dab41..994174ed 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -82,6 +82,8 @@ static u8 crash_mode, /* Crash-centric mode? */ remove_shm = 1, /* remove shmem on exit? */ debug; /* debug mode */ +static u32 del_len_limit = 1; /* Minimum block deletion length */ + static volatile u8 stop_soon; /* Ctrl-C pressed? */ static afl_forkserver_t *fsrv; @@ -480,7 +482,7 @@ next_del_blksize: } - if (del_len > 1 && in_len >= 1) { + if (del_len > del_len_limit && in_len >= 1) { del_len /= 2; goto next_del_blksize; @@ -796,8 +798,9 @@ static void usage(u8 *argv0) { "Minimization settings:\n" " -e - solve for edge coverage only, ignore hit counts\n" - " -x - treat non-zero exit codes as crashes\n\n" - " -H - minimize a hang (hang mode)\n" + " -l bytes - set minimum block deletion length to speed up minimization\n" + " -x - treat non-zero exit codes as crashes\n" + " -H - minimize a hang (hang mode)\n\n" "For additional tips, please consult %s/README.md.\n\n" @@ -829,8 +832,9 @@ static void usage(u8 *argv0) { int main(int argc, char **argv_orig, char **envp) { - s32 opt; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt; + u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0, + del_limit_given = 0; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); @@ -846,7 +850,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:l:B:xeAOQUWXYHh")) > 0) { switch (opt) { @@ -1055,6 +1059,24 @@ int main(int argc, char **argv_orig, char **envp) { read_bitmap(optarg, mask_bitmap, map_size); break; + case 'l': + if (del_limit_given) { FATAL("Multiple -l options not supported"); } + del_limit_given = 1; + + if (!optarg) { FATAL("Wrong usage of -l"); } + + if (optarg[0] == '-') { FATAL("Dangerously low value of -l"); } + + del_len_limit = atoi(optarg); + + if (del_len_limit < 1 || del_len_limit > TMIN_MAX_FILE) { + + FATAL("Value of -l out of range between 1 and TMIN_MAX_FILE"); + + } + + break; + case 'h': usage(argv[0]); return -1; |