~emersion/mrsh

41bcddb91a9ab4fa0c5ae2e53cdf9a3a8b4ef10c — Julian P Samaroo 1 year, 19 days 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