41bcddb91a9ab4fa0c5ae2e53cdf9a3a8b4ef10c — Julian P Samaroo 10 months ago aa7d536
Implemented ulimit builtin
6 files changed, 91 insertions(+), 2 deletions(-)

M builtin/builtin.c
A builtin/ulimit.c
M include/builtin.h
M meson.build
M test/meson.build
A test/ulimit.sh
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