logo

utils-std

Collection of commonly available Unix tools

nohup.c (2545B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <assert.h>
  6. #include <errno.h>
  7. #include <fcntl.h> // open
  8. #include <limits.h> // PATH_MAX
  9. #include <signal.h>
  10. #include <stdbool.h>
  11. #include <stdio.h> // fprintf
  12. #include <stdlib.h> // getenv
  13. #include <string.h> // strerror
  14. #include <sys/stat.h> // S_IRUSR, S_IWUSR
  15. #include <unistd.h> // isatty
  16. static void
  17. usage()
  18. {
  19. fprintf(stderr, "Usage: nohup command [args ...]\n");
  20. }
  21. int
  22. main(int argc, char *argv[])
  23. {
  24. int nohup_fd = -1;
  25. if(argc <= 1)
  26. {
  27. usage();
  28. return 127;
  29. }
  30. if(signal(SIGHUP, SIG_IGN) == SIG_ERR)
  31. {
  32. fprintf(stderr, "nohup: Failed to set SIGHUP as ignored: %s\n", strerror(errno));
  33. return 127;
  34. }
  35. assert(errno == 0);
  36. if(isatty(1))
  37. {
  38. assert(errno == 0);
  39. nohup_fd = open("nohup.out", O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
  40. if(nohup_fd < 0)
  41. {
  42. fprintf(stderr,
  43. "nohup: Warning: Failed opening ./nohup.out (%s), fallbacking to ~/nohup.out\n",
  44. strerror(errno));
  45. char *home = getenv("HOME");
  46. if(!home)
  47. {
  48. fprintf(
  49. stderr,
  50. "nohup: $HOME is undefined, can't fallback writing from ./nohup.out to ~/nohup.out\n");
  51. return 127;
  52. }
  53. char home_nohup[PATH_MAX];
  54. if(snprintf(home_nohup, sizeof(home_nohup), "%s/nohup.out", home) < 0)
  55. {
  56. fprintf(
  57. stderr, "nohup: Failed concatenating $HOME and '/nohup.out': %s\n", strerror(errno));
  58. return 127;
  59. }
  60. nohup_fd = open(home_nohup, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
  61. if(nohup_fd < 0)
  62. {
  63. fprintf(stderr, "nohup: Error: Failed opening ~/nohup.out: %s\n", strerror(errno));
  64. return 127;
  65. }
  66. }
  67. if(dup2(nohup_fd, 1) < 0)
  68. {
  69. fprintf(
  70. stderr, "nohup: Error: Failed assigning 'nohup.out' to stdout: %s\n", strerror(errno));
  71. return 127;
  72. }
  73. if(isatty(2))
  74. {
  75. assert(errno == 0);
  76. if(dup2(1, 2))
  77. {
  78. fprintf(stderr, "nohup: Error: Failed assigning stdout to stderr: %s\n", strerror(errno));
  79. return 127;
  80. }
  81. }
  82. else
  83. errno = 0; // isatty sets errno on returning false
  84. }
  85. else
  86. errno = 0; // isatty sets errno on returning false
  87. argc -= 1;
  88. argv += 1;
  89. (void)argc;
  90. assert(argv[0]);
  91. assert(errno == 0);
  92. if(execvp(argv[0], argv) < 0)
  93. {
  94. fprintf(stderr, "nohup: execvp(\"%s\", ...): %s\n", argv[0], strerror(errno));
  95. return (errno == ENOENT) ? 127 : 126;
  96. }
  97. assert(false);
  98. }