logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

truncate.c (2735B)


  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 "../lib/bitmasks.h" // FIELD_CLR
  6. #include "../lib/truncation.h" // parse_size
  7. #include <errno.h>
  8. #include <fcntl.h> // open
  9. #include <stdbool.h>
  10. #include <stdio.h> // fprintf
  11. #include <stdlib.h> // abort
  12. #include <string.h> // strerror
  13. #include <sys/stat.h>
  14. #include <unistd.h> // getopt
  15. const char *argv0 = "truncate";
  16. static void
  17. usage(void)
  18. {
  19. fprintf(stderr, "Usage: truncate [-co] [-r ref_file] [-s size] file...\n");
  20. }
  21. int
  22. main(int argc, char *argv[])
  23. {
  24. int open_flags = O_WRONLY | O_CREAT | O_NONBLOCK;
  25. bool size_set = false;
  26. struct truncation tr = {
  27. .op = OP_SET,
  28. .size = 0,
  29. };
  30. char *ref_file = NULL;
  31. int c = -1;
  32. while((c = getopt(argc, argv, ":cr:s:")) != -1)
  33. {
  34. switch(c)
  35. {
  36. case 'c':
  37. FIELD_CLR(open_flags, O_CREAT);
  38. break;
  39. case 'r':
  40. if(size_set)
  41. {
  42. fprintf(stderr, "truncate: error: Truncation size can only be set once\n");
  43. usage();
  44. return 1;
  45. }
  46. ref_file = optarg;
  47. size_set = true;
  48. break;
  49. case 's':
  50. if(size_set)
  51. {
  52. fprintf(stderr, "truncate: error: Truncation size can only be set once\n");
  53. usage();
  54. return 1;
  55. }
  56. if(parse_size(optarg, &tr) < 0)
  57. {
  58. usage();
  59. return 1;
  60. }
  61. size_set = true;
  62. break;
  63. case ':':
  64. fprintf(stderr, "truncate: error: Missing operand for option: '-%c'\n", optopt);
  65. usage();
  66. return 1;
  67. case '?':
  68. fprintf(stderr, "truncate: error: Unrecognised option: '-%c'\n", optopt);
  69. usage();
  70. return 1;
  71. default:
  72. abort();
  73. }
  74. }
  75. argc -= optind;
  76. argv += optind;
  77. if(argc < 1) usage();
  78. if(!size_set)
  79. {
  80. fprintf(stderr,
  81. "truncate: error: target size wasn't set, you need to pass one of -d / -r / -s\n");
  82. return 1;
  83. }
  84. if(ref_file != NULL)
  85. {
  86. struct stat ref_stats;
  87. if(stat(optarg, &ref_stats) < 0)
  88. {
  89. fprintf(stderr,
  90. "truncate: error: Couldn't get status for file '%s': %s\n",
  91. optarg,
  92. strerror(errno));
  93. return 1;
  94. }
  95. tr.op = OP_SET;
  96. tr.size = ref_stats.st_size;
  97. }
  98. for(int argi = 0; argi < argc; argi++)
  99. {
  100. char *arg = argv[argi];
  101. // same flags to open as touch(1)
  102. int fd = open(arg, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  103. if(fd < 0)
  104. {
  105. fprintf(stderr, "truncate: error: Failed to open '%s': %s\n", arg, strerror(errno));
  106. return 1;
  107. }
  108. if(apply_truncation(fd, tr, arg) < 0) return 1;
  109. if(close(fd) < 0)
  110. {
  111. fprintf(stderr, "truncate: error: Failed closing fd for '%s': %s\n", arg, strerror(errno));
  112. return 1;
  113. }
  114. }
  115. return 0;
  116. }