M builtin/builtin.c => builtin/builtin.c +1 -0
@@ 31,6 31,7 @@ static const struct builtin builtins[] = {
{ "times", builtin_times, true },
{ "true", builtin_true, false },
{ "type", builtin_type, false },
+ { "ulimit", builtin_ulimit, false },
{ "umask", builtin_umask, false },
{ "unalias", builtin_unalias, false },
{ "unset", builtin_unset, true },
A builtin/ulimit.c => builtin/ulimit.c +66 -0
@@ 0,0 1,66 @@
+#define _POSIX_C_SOURCE 200809L
+#include <mrsh/getopt.h>
+#include <mrsh/shell.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include "builtin.h"
+
+static const char ulimit_usage[] = "usage: ulimit [-f] [blocks]\n";
+
+int builtin_ulimit(struct mrsh_state *state, int argc, char *argv[]) {
+ mrsh_optind = 1;
+ int opt;
+ while ((opt = mrsh_getopt(argc, argv, ":f")) != -1) {
+ if (opt == 'f') {
+ // Nothing here
+ } else {
+ fprintf(stderr, "%s", ulimit_usage);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (mrsh_optind == argc - 1) {
+ errno = 0;
+ char *arg = argv[mrsh_optind];
+ char *endptr;
+ long int new_limit = strtol(arg, &endptr, 10);
+ if (errno != 0) {
+ fprintf(stderr, "strtol error: %s\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+ if ((endptr == arg) || (endptr[0] != '\0')) {
+ fprintf(stderr, "ulimit error: Invalid argument: %s\n",
+ arg);
+ return EXIT_FAILURE;
+ }
+ struct rlimit new = {
+ .rlim_cur = new_limit * 512,
+ .rlim_max = new_limit * 512
+ };
+ if (setrlimit(RLIMIT_FSIZE, &new) != 0) {
+ fprintf(stderr, "setrlimit error: %s\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+ } else if (mrsh_optind == argc) {
+ struct rlimit old = { 0 };
+ if (getrlimit(RLIMIT_FSIZE, &old) != 0) {
+ fprintf(stderr, "getrlimit error: %s\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+ if (old.rlim_max == RLIM_INFINITY) {
+ printf("unlimited\n");
+ } else {
+ printf("%lu\n", old.rlim_max / 512);
+ }
+ } else {
+ fprintf(stderr, "%s", ulimit_usage);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
M include/builtin.h => include/builtin.h +1 -0
@@ 24,6 24,7 @@ int builtin_shift(struct mrsh_state *state, int argc, char *argv[]);
int builtin_times(struct mrsh_state *state, int argc, char *argv[]);
int builtin_true(struct mrsh_state *state, int argc, char *argv[]);
int builtin_type(struct mrsh_state *state, int argc, char *argv[]);
+int builtin_ulimit(struct mrsh_state *state, int argc, char *argv[]);
int builtin_umask(struct mrsh_state *state, int argc, char *argv[]);
int builtin_unalias(struct mrsh_state *state, int argc, char *argv[]);
int builtin_unset(struct mrsh_state *state, int argc, char *argv[]);
M meson.build => meson.build +1 -0
@@ 64,6 64,7 @@ lib_mrsh = library(
'builtin/times.c',
'builtin/true.c',
'builtin/type.c',
+ 'builtin/ulimit.c',
'builtin/umask.c',
'builtin/unalias.c',
'builtin/unset.c',
M test/meson.build => test/meson.build +3 -2
@@ 5,11 5,12 @@ test_files = [
'conformance/if.sh',
'case.sh',
+ 'for.sh',
+ 'function.sh',
'loop.sh',
'subshell.sh',
+ 'ulimit.sh',
'word.sh',
- 'for.sh',
- 'function.sh',
]
foreach test_file : test_files
A test/ulimit.sh => test/ulimit.sh +19 -0
@@ 0,0 1,19 @@
+#!/bin/sh
+
+set -e
+
+mrsh_limits=`ulimit`
+[ $mrsh_limits == "unlimited" ]
+if [ -e /proc/self/limits ]
+then
+ grep "Max file size" /proc/self/limits | grep "unlimited"
+fi
+
+ulimit -f 100
+
+mrsh_limits=`ulimit`
+[ $mrsh_limits -eq 100 ]
+if [ -e /proc/self/limits ]
+then
+ grep "Max file size" /proc/self/limits | grep 51200
+fi