shell_common.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Adapted from ash applet code
  4. *
  5. * This code is derived from software contributed to Berkeley by
  6. * Kenneth Almquist.
  7. *
  8. * Copyright (c) 1989, 1991, 1993, 1994
  9. * The Regents of the University of California. All rights reserved.
  10. *
  11. * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
  12. * was re-ported from NetBSD and debianized.
  13. *
  14. * Copyright (c) 2010 Denys Vlasenko
  15. * Split from ash.c
  16. *
  17. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  18. */
  19. #include "libbb.h"
  20. #include "shell_common.h"
  21. #include <sys/resource.h> /* getrlimit */
  22. const char defifsvar[] ALIGN1 = "IFS= \t\n";
  23. const char defoptindvar[] ALIGN1 = "OPTIND=1";
  24. int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
  25. {
  26. if (!s || !(isalpha(*s) || *s == '_'))
  27. return 0;
  28. do
  29. s++;
  30. while (isalnum(*s) || *s == '_');
  31. return *s == terminator;
  32. }
  33. /* read builtin */
  34. /* Needs to be interruptible: shell must handle traps and shell-special signals
  35. * while inside read. To implement this, be sure to not loop on EINTR
  36. * and return errno == EINTR reliably.
  37. */
  38. //TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL"
  39. //string. hush naturally has it, and ash has setvareq().
  40. //Here we can simply store "VAR=" at buffer start and store read data directly
  41. //after "=", then pass buffer to setvar() to consume.
  42. const char* FAST_FUNC
  43. shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
  44. char **argv,
  45. const char *ifs,
  46. int read_flags,
  47. const char *opt_n,
  48. const char *opt_p,
  49. const char *opt_t,
  50. const char *opt_u
  51. )
  52. {
  53. unsigned err;
  54. unsigned end_ms; /* -t TIMEOUT */
  55. int fd; /* -u FD */
  56. int nchars; /* -n NUM */
  57. char **pp;
  58. char *buffer;
  59. struct termios tty, old_tty;
  60. const char *retval;
  61. int bufpos; /* need to be able to hold -1 */
  62. int startword;
  63. smallint backslash;
  64. errno = err = 0;
  65. pp = argv;
  66. while (*pp) {
  67. if (!is_well_formed_var_name(*pp, '\0')) {
  68. /* Mimic bash message */
  69. bb_error_msg("read: '%s': not a valid identifier", *pp);
  70. return (const char *)(uintptr_t)1;
  71. }
  72. pp++;
  73. }
  74. nchars = 0; /* if != 0, -n is in effect */
  75. if (opt_n) {
  76. nchars = bb_strtou(opt_n, NULL, 10);
  77. if (nchars < 0 || errno)
  78. return "invalid count";
  79. /* note: "-n 0": off (bash 3.2 does this too) */
  80. }
  81. end_ms = 0;
  82. if (opt_t) {
  83. end_ms = bb_strtou(opt_t, NULL, 10);
  84. if (errno || end_ms > UINT_MAX / 2048)
  85. return "invalid timeout";
  86. end_ms *= 1000;
  87. #if 0 /* even bash has no -t N.NNN support */
  88. ts.tv_sec = bb_strtou(opt_t, &p, 10);
  89. ts.tv_usec = 0;
  90. /* EINVAL means number is ok, but not terminated by NUL */
  91. if (*p == '.' && errno == EINVAL) {
  92. char *p2;
  93. if (*++p) {
  94. int scale;
  95. ts.tv_usec = bb_strtou(p, &p2, 10);
  96. if (errno)
  97. return "invalid timeout";
  98. scale = p2 - p;
  99. /* normalize to usec */
  100. if (scale > 6)
  101. return "invalid timeout";
  102. while (scale++ < 6)
  103. ts.tv_usec *= 10;
  104. }
  105. } else if (ts.tv_sec < 0 || errno) {
  106. return "invalid timeout";
  107. }
  108. if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
  109. return "invalid timeout";
  110. }
  111. #endif /* if 0 */
  112. }
  113. fd = STDIN_FILENO;
  114. if (opt_u) {
  115. fd = bb_strtou(opt_u, NULL, 10);
  116. if (fd < 0 || errno)
  117. return "invalid file descriptor";
  118. }
  119. if (opt_p && isatty(fd)) {
  120. fputs(opt_p, stderr);
  121. fflush_all();
  122. }
  123. if (ifs == NULL)
  124. ifs = defifs;
  125. if (nchars || (read_flags & BUILTIN_READ_SILENT)) {
  126. tcgetattr(fd, &tty);
  127. old_tty = tty;
  128. if (nchars) {
  129. tty.c_lflag &= ~ICANON;
  130. // Setting it to more than 1 breaks poll():
  131. // it blocks even if there's data. !??
  132. //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
  133. /* reads will block only if < 1 char is available */
  134. tty.c_cc[VMIN] = 1;
  135. /* no timeout (reads block forever) */
  136. tty.c_cc[VTIME] = 0;
  137. }
  138. if (read_flags & BUILTIN_READ_SILENT) {
  139. tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
  140. }
  141. /* This forces execution of "restoring" tcgetattr later */
  142. read_flags |= BUILTIN_READ_SILENT;
  143. /* if tcgetattr failed, tcsetattr will fail too.
  144. * Ignoring, it's harmless. */
  145. tcsetattr(fd, TCSANOW, &tty);
  146. }
  147. retval = (const char *)(uintptr_t)0;
  148. startword = 1;
  149. backslash = 0;
  150. if (end_ms) /* NB: end_ms stays nonzero: */
  151. end_ms = ((unsigned)monotonic_ms() + end_ms) | 1;
  152. buffer = NULL;
  153. bufpos = 0;
  154. do {
  155. char c;
  156. struct pollfd pfd[1];
  157. int timeout;
  158. if ((bufpos & 0xff) == 0)
  159. buffer = xrealloc(buffer, bufpos + 0x101);
  160. timeout = -1;
  161. if (end_ms) {
  162. timeout = end_ms - (unsigned)monotonic_ms();
  163. if (timeout <= 0) { /* already late? */
  164. retval = (const char *)(uintptr_t)1;
  165. goto ret;
  166. }
  167. }
  168. /* We must poll even if timeout is -1:
  169. * we want to be interrupted if signal arrives,
  170. * regardless of SA_RESTART-ness of that signal!
  171. */
  172. errno = 0;
  173. pfd[0].fd = fd;
  174. pfd[0].events = POLLIN;
  175. if (poll(pfd, 1, timeout) != 1) {
  176. /* timed out, or EINTR */
  177. err = errno;
  178. retval = (const char *)(uintptr_t)1;
  179. goto ret;
  180. }
  181. if (read(fd, &buffer[bufpos], 1) != 1) {
  182. err = errno;
  183. retval = (const char *)(uintptr_t)1;
  184. break;
  185. }
  186. c = buffer[bufpos];
  187. if (c == '\0')
  188. continue;
  189. if (!(read_flags & BUILTIN_READ_RAW)) {
  190. if (backslash) {
  191. backslash = 0;
  192. if (c != '\n')
  193. goto put;
  194. continue;
  195. }
  196. if (c == '\\') {
  197. backslash = 1;
  198. continue;
  199. }
  200. }
  201. if (c == '\n')
  202. break;
  203. /* $IFS splitting. NOT done if we run "read"
  204. * without variable names (bash compat).
  205. * Thus, "read" and "read REPLY" are not the same.
  206. */
  207. if (argv[0]) {
  208. /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
  209. const char *is_ifs = strchr(ifs, c);
  210. if (startword && is_ifs) {
  211. if (isspace(c))
  212. continue;
  213. /* it is a non-space ifs char */
  214. startword--;
  215. if (startword == 1) /* first one? */
  216. continue; /* yes, it is not next word yet */
  217. }
  218. startword = 0;
  219. if (argv[1] != NULL && is_ifs) {
  220. buffer[bufpos] = '\0';
  221. bufpos = 0;
  222. setvar(*argv, buffer);
  223. argv++;
  224. /* can we skip one non-space ifs char? (2: yes) */
  225. startword = isspace(c) ? 2 : 1;
  226. continue;
  227. }
  228. }
  229. put:
  230. bufpos++;
  231. } while (--nchars);
  232. if (argv[0]) {
  233. /* Remove trailing space $IFS chars */
  234. while (--bufpos >= 0 && isspace(buffer[bufpos]) && strchr(ifs, buffer[bufpos]) != NULL)
  235. continue;
  236. buffer[bufpos + 1] = '\0';
  237. /* Use the remainder as a value for the next variable */
  238. setvar(*argv, buffer);
  239. /* Set the rest to "" */
  240. while (*++argv)
  241. setvar(*argv, "");
  242. } else {
  243. /* Note: no $IFS removal */
  244. buffer[bufpos] = '\0';
  245. setvar("REPLY", buffer);
  246. }
  247. ret:
  248. free(buffer);
  249. if (read_flags & BUILTIN_READ_SILENT)
  250. tcsetattr(fd, TCSANOW, &old_tty);
  251. errno = err;
  252. return retval;
  253. }
  254. /* ulimit builtin */
  255. struct limits {
  256. uint8_t cmd; /* RLIMIT_xxx fit into it */
  257. uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
  258. char option;
  259. const char *name;
  260. };
  261. static const struct limits limits_tbl[] = {
  262. #ifdef RLIMIT_FSIZE
  263. { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" },
  264. #endif
  265. #ifdef RLIMIT_CPU
  266. { RLIMIT_CPU, 0, 't', "cpu time (seconds)" },
  267. #endif
  268. #ifdef RLIMIT_DATA
  269. { RLIMIT_DATA, 10, 'd', "data seg size (kb)" },
  270. #endif
  271. #ifdef RLIMIT_STACK
  272. { RLIMIT_STACK, 10, 's', "stack size (kb)" },
  273. #endif
  274. #ifdef RLIMIT_CORE
  275. { RLIMIT_CORE, 9, 'c', "core file size (blocks)" },
  276. #endif
  277. #ifdef RLIMIT_RSS
  278. { RLIMIT_RSS, 10, 'm', "resident set size (kb)" },
  279. #endif
  280. #ifdef RLIMIT_MEMLOCK
  281. { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" },
  282. #endif
  283. #ifdef RLIMIT_NPROC
  284. { RLIMIT_NPROC, 0, 'p', "processes" },
  285. #endif
  286. #ifdef RLIMIT_NOFILE
  287. { RLIMIT_NOFILE, 0, 'n', "file descriptors" },
  288. #endif
  289. #ifdef RLIMIT_AS
  290. { RLIMIT_AS, 10, 'v', "address space (kb)" },
  291. #endif
  292. #ifdef RLIMIT_LOCKS
  293. { RLIMIT_LOCKS, 0, 'w', "locks" },
  294. #endif
  295. #ifdef RLIMIT_NICE
  296. { RLIMIT_NICE, 0, 'e', "scheduling priority" },
  297. #endif
  298. #ifdef RLIMIT_RTPRIO
  299. { RLIMIT_RTPRIO, 0, 'r', "real-time priority" },
  300. #endif
  301. };
  302. enum {
  303. OPT_hard = (1 << 0),
  304. OPT_soft = (1 << 1),
  305. };
  306. /* "-": treat args as parameters of option with ASCII code 1 */
  307. static const char ulimit_opt_string[] ALIGN1 = "-HSa"
  308. #ifdef RLIMIT_FSIZE
  309. "f::"
  310. #endif
  311. #ifdef RLIMIT_CPU
  312. "t::"
  313. #endif
  314. #ifdef RLIMIT_DATA
  315. "d::"
  316. #endif
  317. #ifdef RLIMIT_STACK
  318. "s::"
  319. #endif
  320. #ifdef RLIMIT_CORE
  321. "c::"
  322. #endif
  323. #ifdef RLIMIT_RSS
  324. "m::"
  325. #endif
  326. #ifdef RLIMIT_MEMLOCK
  327. "l::"
  328. #endif
  329. #ifdef RLIMIT_NPROC
  330. "p::"
  331. #endif
  332. #ifdef RLIMIT_NOFILE
  333. "n::"
  334. #endif
  335. #ifdef RLIMIT_AS
  336. "v::"
  337. #endif
  338. #ifdef RLIMIT_LOCKS
  339. "w::"
  340. #endif
  341. #ifdef RLIMIT_NICE
  342. "e::"
  343. #endif
  344. #ifdef RLIMIT_RTPRIO
  345. "r::"
  346. #endif
  347. ;
  348. static void printlim(unsigned opts, const struct rlimit *limit,
  349. const struct limits *l)
  350. {
  351. rlim_t val;
  352. val = limit->rlim_max;
  353. if (!(opts & OPT_hard))
  354. val = limit->rlim_cur;
  355. if (val == RLIM_INFINITY)
  356. puts("unlimited");
  357. else {
  358. val >>= l->factor_shift;
  359. printf("%llu\n", (long long) val);
  360. }
  361. }
  362. int FAST_FUNC
  363. shell_builtin_ulimit(char **argv)
  364. {
  365. unsigned opts;
  366. unsigned argc;
  367. /* We can't use getopt32: need to handle commands like
  368. * ulimit 123 -c2 -l 456
  369. */
  370. /* In case getopt was already called:
  371. * reset the libc getopt() function, which keeps internal state.
  372. */
  373. GETOPT_RESET();
  374. argc = string_array_len(argv);
  375. opts = 0;
  376. while (1) {
  377. struct rlimit limit;
  378. const struct limits *l;
  379. int opt_char = getopt(argc, argv, ulimit_opt_string);
  380. if (opt_char == -1)
  381. break;
  382. if (opt_char == 'H') {
  383. opts |= OPT_hard;
  384. continue;
  385. }
  386. if (opt_char == 'S') {
  387. opts |= OPT_soft;
  388. continue;
  389. }
  390. if (opt_char == 'a') {
  391. for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
  392. getrlimit(l->cmd, &limit);
  393. printf("-%c: %-30s ", l->option, l->name);
  394. printlim(opts, &limit, l);
  395. }
  396. continue;
  397. }
  398. if (opt_char == 1)
  399. opt_char = 'f';
  400. for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
  401. if (opt_char == l->option) {
  402. char *val_str;
  403. getrlimit(l->cmd, &limit);
  404. val_str = optarg;
  405. if (!val_str && argv[optind] && argv[optind][0] != '-')
  406. val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */
  407. if (val_str) {
  408. rlim_t val;
  409. if (strcmp(val_str, "unlimited") == 0)
  410. val = RLIM_INFINITY;
  411. else {
  412. if (sizeof(val) == sizeof(int))
  413. val = bb_strtou(val_str, NULL, 10);
  414. else if (sizeof(val) == sizeof(long))
  415. val = bb_strtoul(val_str, NULL, 10);
  416. else
  417. val = bb_strtoull(val_str, NULL, 10);
  418. if (errno) {
  419. bb_error_msg("invalid number '%s'", val_str);
  420. return EXIT_FAILURE;
  421. }
  422. val <<= l->factor_shift;
  423. }
  424. //bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
  425. /* from man bash: "If neither -H nor -S
  426. * is specified, both the soft and hard
  427. * limits are set. */
  428. if (!opts)
  429. opts = OPT_hard + OPT_soft;
  430. if (opts & OPT_hard)
  431. limit.rlim_max = val;
  432. if (opts & OPT_soft)
  433. limit.rlim_cur = val;
  434. //bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
  435. if (setrlimit(l->cmd, &limit) < 0) {
  436. bb_perror_msg("error setting limit");
  437. return EXIT_FAILURE;
  438. }
  439. } else {
  440. printlim(opts, &limit, l);
  441. }
  442. break;
  443. }
  444. } /* for (every possible opt) */
  445. if (l == &limits_tbl[ARRAY_SIZE(limits_tbl)]) {
  446. /* bad option. getopt already complained. */
  447. break;
  448. }
  449. } /* while (there are options) */
  450. return 0;
  451. }