builtin_ulimit.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * ulimit builtin
  4. *
  5. * Adapted from ash applet code
  6. *
  7. * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
  8. * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
  9. * ash by J.T. Conklin.
  10. *
  11. * Public domain.
  12. *
  13. * Copyright (c) 2010 Tobias Klauser
  14. * Split from ash.c and slightly adapted.
  15. *
  16. * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  17. */
  18. #include "libbb.h"
  19. #include "builtin_ulimit.h"
  20. struct limits {
  21. uint8_t cmd; /* RLIMIT_xxx fit into it */
  22. uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
  23. char option;
  24. const char *name;
  25. };
  26. static const struct limits limits_tbl[] = {
  27. #ifdef RLIMIT_FSIZE
  28. { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" },
  29. #endif
  30. #ifdef RLIMIT_CPU
  31. { RLIMIT_CPU, 0, 't', "cpu time (seconds)" },
  32. #endif
  33. #ifdef RLIMIT_DATA
  34. { RLIMIT_DATA, 10, 'd', "data seg size (kb)" },
  35. #endif
  36. #ifdef RLIMIT_STACK
  37. { RLIMIT_STACK, 10, 's', "stack size (kb)" },
  38. #endif
  39. #ifdef RLIMIT_CORE
  40. { RLIMIT_CORE, 9, 'c', "core file size (blocks)" },
  41. #endif
  42. #ifdef RLIMIT_RSS
  43. { RLIMIT_RSS, 10, 'm', "resident set size (kb)" },
  44. #endif
  45. #ifdef RLIMIT_MEMLOCK
  46. { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" },
  47. #endif
  48. #ifdef RLIMIT_NPROC
  49. { RLIMIT_NPROC, 0, 'p', "processes" },
  50. #endif
  51. #ifdef RLIMIT_NOFILE
  52. { RLIMIT_NOFILE, 0, 'n', "file descriptors" },
  53. #endif
  54. #ifdef RLIMIT_AS
  55. { RLIMIT_AS, 10, 'v', "address space (kb)" },
  56. #endif
  57. #ifdef RLIMIT_LOCKS
  58. { RLIMIT_LOCKS, 0, 'w', "locks" },
  59. #endif
  60. };
  61. enum {
  62. OPT_hard = (1 << 0),
  63. OPT_soft = (1 << 1),
  64. };
  65. /* "-": treat args as parameters of option with ASCII code 1 */
  66. static const char ulimit_opt_string[] = "-HSa"
  67. #ifdef RLIMIT_FSIZE
  68. "f::"
  69. #endif
  70. #ifdef RLIMIT_CPU
  71. "t::"
  72. #endif
  73. #ifdef RLIMIT_DATA
  74. "d::"
  75. #endif
  76. #ifdef RLIMIT_STACK
  77. "s::"
  78. #endif
  79. #ifdef RLIMIT_CORE
  80. "c::"
  81. #endif
  82. #ifdef RLIMIT_RSS
  83. "m::"
  84. #endif
  85. #ifdef RLIMIT_MEMLOCK
  86. "l::"
  87. #endif
  88. #ifdef RLIMIT_NPROC
  89. "p::"
  90. #endif
  91. #ifdef RLIMIT_NOFILE
  92. "n::"
  93. #endif
  94. #ifdef RLIMIT_AS
  95. "v::"
  96. #endif
  97. #ifdef RLIMIT_LOCKS
  98. "w::"
  99. #endif
  100. ;
  101. static void printlim(unsigned opts, const struct rlimit *limit,
  102. const struct limits *l)
  103. {
  104. rlim_t val;
  105. val = limit->rlim_max;
  106. if (!(opts & OPT_hard))
  107. val = limit->rlim_cur;
  108. if (val == RLIM_INFINITY)
  109. printf("unlimited\n");
  110. else {
  111. val >>= l->factor_shift;
  112. printf("%llu\n", (long long) val);
  113. }
  114. }
  115. int FAST_FUNC shell_builtin_ulimit(char **argv)
  116. {
  117. unsigned opts;
  118. unsigned argc;
  119. /* We can't use getopt32: need to handle commands like
  120. * ulimit 123 -c2 -l 456
  121. */
  122. /* In case getopt was already called:
  123. * reset the libc getopt() function, which keeps internal state.
  124. */
  125. #ifdef __GLIBC__
  126. optind = 0;
  127. #else /* BSD style */
  128. optind = 1;
  129. /* optreset = 1; */
  130. #endif
  131. /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
  132. argc = 1;
  133. while (argv[argc])
  134. argc++;
  135. opts = 0;
  136. while (1) {
  137. struct rlimit limit;
  138. const struct limits *l;
  139. int opt_char = getopt(argc, argv, ulimit_opt_string);
  140. if (opt_char == -1)
  141. break;
  142. if (opt_char == 'H') {
  143. opts |= OPT_hard;
  144. continue;
  145. }
  146. if (opt_char == 'S') {
  147. opts |= OPT_soft;
  148. continue;
  149. }
  150. if (opt_char == 'a') {
  151. for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
  152. getrlimit(l->cmd, &limit);
  153. printf("-%c: %-30s ", l->option, l->name);
  154. printlim(opts, &limit, l);
  155. }
  156. continue;
  157. }
  158. if (opt_char == 1)
  159. opt_char = 'f';
  160. for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
  161. if (opt_char == l->option) {
  162. char *val_str;
  163. getrlimit(l->cmd, &limit);
  164. val_str = optarg;
  165. if (!val_str && argv[optind] && argv[optind][0] != '-')
  166. val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */
  167. if (val_str) {
  168. rlim_t val;
  169. if (strcmp(val_str, "unlimited") == 0)
  170. val = RLIM_INFINITY;
  171. else {
  172. if (sizeof(val) == sizeof(int))
  173. val = bb_strtou(val_str, NULL, 10);
  174. else if (sizeof(val) == sizeof(long))
  175. val = bb_strtoul(val_str, NULL, 10);
  176. else
  177. val = bb_strtoull(val_str, NULL, 10);
  178. if (errno) {
  179. bb_error_msg("bad number");
  180. return EXIT_FAILURE;
  181. }
  182. val <<= l->factor_shift;
  183. }
  184. //bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
  185. if (opts & OPT_hard)
  186. limit.rlim_max = val;
  187. if ((opts & OPT_soft) || opts == 0)
  188. limit.rlim_cur = val;
  189. //bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
  190. if (setrlimit(l->cmd, &limit) < 0) {
  191. bb_perror_msg("error setting limit");
  192. return EXIT_FAILURE;
  193. }
  194. } else {
  195. printlim(opts, &limit, l);
  196. }
  197. break;
  198. }
  199. } /* for (every possible opt) */
  200. if (l == &limits_tbl[ARRAY_SIZE(limits_tbl)]) {
  201. /* bad option. getopt already complained. */
  202. break;
  203. }
  204. } /* while (there are options) */
  205. return 0;
  206. }