chmod.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * chmod - change file permissions
  7. *
  8. * Note: This implementation is likely non-compliant, though it does
  9. * attempt to look similar to the standard POSIX syntax,
  10. * supporting both octal mode setings and +/-rwx flavors.
  11. */
  12. #include <unistd.h>
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <sys/stat.h>
  16. enum mode_set {
  17. MODE_SET,
  18. MODE_ADD,
  19. MODE_REMOVE,
  20. };
  21. static int calc(int mode, int users) {
  22. int out = 0;
  23. if (users & 1) {
  24. out |= (mode << 6);
  25. }
  26. if (users & 2) {
  27. out |= (mode << 3);
  28. }
  29. if (users & 4) {
  30. out |= (mode << 0);
  31. }
  32. return out;
  33. }
  34. int main(int argc, char * argv[]) {
  35. if (argc < 3) {
  36. fprintf(stderr, "usage: %s OCTAL-MODE FILE...\n", argv[0]);
  37. return 1;
  38. }
  39. /* Parse mode */
  40. int mode = 0;
  41. enum mode_set mode_set = MODE_SET;
  42. char * c = argv[1];
  43. int user_modes = 0;
  44. int all_users = 7;
  45. while (*c) {
  46. switch (*c) {
  47. case '0':
  48. c++; /* 0 */
  49. while (*c >= '0' || *c <= '7') {
  50. mode *= 8;
  51. mode += (*c - '0');
  52. c++;
  53. }
  54. break;
  55. case 'u':
  56. all_users = 0;
  57. user_modes |= 1;
  58. c++;
  59. break;
  60. case 'g':
  61. all_users = 0;
  62. user_modes |= 2;
  63. c++;
  64. break;
  65. case 'o':
  66. all_users = 0;
  67. user_modes |= 4;
  68. c++;
  69. break;
  70. case 'a':
  71. all_users = 7;
  72. user_modes = 7;
  73. c++;
  74. break;
  75. case '-':
  76. mode_set = MODE_REMOVE;
  77. c++;
  78. break;
  79. case '+':
  80. mode_set = MODE_ADD;
  81. c++;
  82. break;
  83. case '=':
  84. mode_set = MODE_SET;
  85. c++;
  86. break;
  87. case 'r':
  88. mode |= calc(S_IROTH, user_modes | all_users);
  89. c++;
  90. break;
  91. case 'w':
  92. mode |= calc(S_IWOTH, user_modes | all_users);
  93. c++;
  94. break;
  95. case 'x':
  96. mode |= calc(S_IXOTH, user_modes | all_users);
  97. c++;
  98. break;
  99. }
  100. }
  101. int i = 2;
  102. while (i < argc) {
  103. int actual_mode = 0;
  104. struct stat _stat;
  105. if (stat(argv[i], &_stat) < 0) {
  106. fprintf(stderr, "%s: %s: error with stat\n", argv[0], argv[i]);
  107. }
  108. switch (mode_set) {
  109. case MODE_SET:
  110. actual_mode = mode;
  111. break;
  112. case MODE_ADD:
  113. actual_mode = _stat.st_mode | mode;
  114. break;
  115. case MODE_REMOVE:
  116. actual_mode = _stat.st_mode &= ~(mode);
  117. break;
  118. }
  119. if (chmod(argv[i], actual_mode) < 0) {
  120. fprintf(stderr, "%s: %s: error with chmod\n", argv[0], argv[i]);
  121. return 1;
  122. }
  123. i++;
  124. }
  125. return 0;
  126. }