int main (int argc, char **argv) { randint i; randint n = strtoumax (argv[1], NULL, 10); randint choices = strtoumax (argv[2], NULL, 10); char const *name = argv[3]; struct randint_source *ints = randint_all_new (name, SIZE_MAX); for (i = 0; i < n; i++) printf ("%"PRIuMAX"\n", randint_choose (ints, choices)); return (randint_all_free (ints) == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
/* Generate a temporary file name based on TMPL. TMPL must match the rules for mk[s]temp (i.e. end in at least X_SUFFIX_LEN "X"s, possibly with a suffix). The name constructed does not exist at the time of the call to this function. TMPL is overwritten with the result. KIND may be one of: __GT_NOCREATE: simply verify that the name does not exist at the time of the call. __GT_FILE: create the file using open(O_CREAT|O_EXCL) and return a read-write fd. The file is mode 0600. __GT_DIR: create a directory, which will be mode 0700. We use a clever algorithm to get hard-to-predict names. */ int gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind, size_t x_suffix_len) { size_t len; char *XXXXXX; unsigned int count; int fd = -1; int save_errno = errno; struct_stat64 st; struct randint_source *rand_src; /* A lower bound on the number of temporary files to attempt to generate. The maximum total number of temporary file names that can exist for a given template is 62**6. It should never be necessary to try all these combinations. Instead if a reasonable number of names is tried (we define reasonable as 62**3) fail to give the system administrator the chance to remove the problems. This value requires that X_SUFFIX_LEN be at least 3. */ #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX unsigned int attempts = TMP_MAX; #else unsigned int attempts = ATTEMPTS_MIN; #endif len = strlen (tmpl); if (len < x_suffix_len + suffixlen || ! check_x_suffix (&tmpl[len - x_suffix_len - suffixlen], x_suffix_len)) { __set_errno (EINVAL); return -1; } /* This is where the Xs start. */ XXXXXX = &tmpl[len - x_suffix_len - suffixlen]; /* Get some more or less random data. */ rand_src = randint_all_new (NULL, x_suffix_len); if (! rand_src) return -1; for (count = 0; count < attempts; ++count) { size_t i; for (i = 0; i < x_suffix_len; i++) XXXXXX[i] = letters[randint_genmax (rand_src, sizeof letters - 2)]; switch (kind) { case __GT_FILE: fd = __open (tmpl, (flags & ~O_ACCMODE) | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); break; case __GT_DIR: fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); break; case __GT_NOCREATE: /* This case is backward from the other three. This function succeeds if __xstat fails because the name does not exist. Note the continue to bypass the common logic at the bottom of the loop. */ if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) { if (errno == ENOENT) { __set_errno (save_errno); fd = 0; goto done; } else { /* Give up now. */ fd = -1; goto done; } } continue; default: assert (! "invalid KIND in __gen_tempname"); abort (); } if (fd >= 0) { __set_errno (save_errno); goto done; } else if (errno != EEXIST) { fd = -1; goto done; } } randint_all_free (rand_src); /* We got out of the loop because we ran out of combinations to try. */ __set_errno (EEXIST); return -1; done: { int saved_errno = errno; randint_all_free (rand_src); __set_errno (saved_errno); } return fd; }