mktemp.c 2.7 KB

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