toybox/toys/lsb/mktemp.c
<<
>>
Prefs
   1/* mktemp.c - Create a temporary file or directory.
   2 *
   3 * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
   4 *
   5 * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mktemp.html
   6
   7USE_MKTEMP(NEWTOY(mktemp, ">1(tmpdir);:uqd(directory)p:t", TOYFLAG_BIN))
   8
   9config MKTEMP
  10  bool "mktemp"
  11  default y
  12  help
  13    usage: mktemp [-dqu] [-p DIR] [TEMPLATE]
  14
  15    Safely create a new file "DIR/TEMPLATE" and print its name.
  16
  17    -d  Create directory instead of file (--directory)
  18    -p  Put new file in DIR (--tmpdir)
  19    -q  Quiet, no error messages
  20    -t  Prefer $TMPDIR > DIR > /tmp (default DIR > $TMPDIR > /tmp)
  21    -u  Don't create anything, just print what would be created
  22
  23    Each X in TEMPLATE is replaced with a random printable character. The
  24    default TEMPLATE is tmp.XXXXXXXXXX.
  25*/
  26
  27#define FOR_mktemp
  28#include "toys.h"
  29
  30GLOBALS(
  31  char *p, *tmpdir;
  32)
  33
  34void mktemp_main(void)
  35{
  36  char *template = *toys.optargs, *dir, *te = getenv("TMPDIR");
  37  int len;
  38
  39  // --tmpdir's argument is optional's but -p is mandatory, so can't combine
  40  if (!TT.p && FLAG(tmpdir)) {
  41    TT.p = TT.tmpdir ? TT.tmpdir : "";
  42    toys.optflags |= FLAG_p;
  43  }
  44  dir = TT.p;
  45  // if template, no prefix unless -pt. if !template, always prefix
  46  if (!dir || !*dir || (FLAG(t) && te && *te)) dir = te;
  47  if (!dir || !*dir) dir = "/tmp";
  48  if (!template) template = "tmp.XXXXXXXXXX";
  49  else {
  50    if (*template == '/' && TT.p && *TT.p) perror_exit("-p + /template");
  51    if (!FLAG(p)&&!FLAG(t)) dir = 0;
  52  }
  53
  54  // TODO: coreutils cleans paths, so -p /t/// would result in /t/xxx...
  55  template = dir ? xmprintf("%s/%s", dir, template) : xstrdup(template);
  56  len = strlen(template);
  57  if (len<3 || strcmp(template+len-3, "XXX")) perror_exit("need XXX");
  58
  59  // In theory you just xputs(mktemp(template)) for -u, in practice there's
  60  // link-time deprecation warnings if you do that. So we fake up our own:
  61  if (FLAG(u)) {
  62    long long rr;
  63    char *s = template+len;
  64
  65    // Fall back to random-ish if xgetrandom fails.
  66    if (!xgetrandom(&rr, sizeof(rr), WARN_ONLY)) {
  67      struct timespec ts;
  68
  69      clock_gettime(CLOCK_REALTIME, &ts);
  70      rr = ts.tv_nsec*65537+(long)template+getpid()+(long)&template;
  71    }
  72    // Replace X with 64 chars from posix portable character set (all but "_").
  73    while (--s>template) {
  74      if (*s != 'X') break;
  75      *s = '-'+(rr&63);
  76      if (*s>'.') ++*s;
  77      if (*s>'9') (*s) += 7;
  78      if (*s>'Z') (*s) += 6;
  79      rr>>=6;
  80    }
  81  } else if (FLAG(d) ? !mkdtemp(template) : mkstemp(template) == -1) {
  82    if (FLAG(q)) {
  83      toys.exitval = 1;
  84      return;
  85    } else perror_exit("Failed to create %s %s",
  86        FLAG(d) ? "directory" : "file", template);
  87  }
  88
  89  xputs(template);
  90  if (CFG_TOYBOX_FREE) free(template);
  91}
  92