/* * libslack - https://libslack.org * * Copyright (C) 1999-2004, 2010, 2020-2023 raf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * 20230824 raf */ /* =head1 NAME I - I limits module =head1 SYNOPSIS #include #include long limit_arg(void); long limit_child(void); long limit_tick(void); long limit_group(void); long limit_open(void); long limit_stream(void); long limit_tzname(void); long limit_job(void); long limit_save_ids(void); long limit_version(void); long limit_pcanon(const char *path); long limit_fcanon(int fd); long limit_canon(void); long limit_pinput(const char *path); long limit_finput(int fd); long limit_input(void); long limit_pvdisable(const char *path); long limit_fvdisable(int fd); long limit_vdisable(void); long limit_plink(const char *path); long limit_flink(int fd); long limit_link(void); long limit_pname(const char *path); long limit_fname(int fd); long limit_name(void); long limit_ppath(const char *path); long limit_fpath(int fd); long limit_path(void); long limit_ppipe(const char *path); long limit_fpipe(int fd); long limit_pnotrunc(const char *path); long limit_fnotrunc(int fd); long limit_notrunc(void); long limit_pchown(const char *path); long limit_fchown(int fd); long limit_chown(void); =head1 DESCRIPTION This module provides functions for simply and reliably obtaining a I limit for the current system or a usable default when a particular facility is unlimited on the current system. These functions always return a usable value. =over 4 =cut */ #include "config.h" #include "std.h" #include #include #include "lim.h" #include "err.h" enum name_t { LIMIT_ARG, LIMIT_CHILD, LIMIT_TICK, LIMIT_GROUP, LIMIT_OPEN, LIMIT_STREAM, LIMIT_TZNAME, LIMIT_JOB, LIMIT_SAVE_IDS, LIMIT_VERSION, LIMIT_CANON, LIMIT_INPUT, LIMIT_VDISABLE, LIMIT_LINK, LIMIT_NAME, LIMIT_PATH, LIMIT_PIPE, LIMIT_NOTRUNC, LIMIT_CHOWN, LIMIT_COUNT }; typedef struct conf_t conf_t; struct conf_t { const int name; /* name argument for sysconf, [f]pathconf */ const long value; /* limit to use when indeterminate */ const off_t offset; /* offset to apply to value when not indeterminate */ }; #ifndef TEST static const struct { conf_t conf[LIMIT_COUNT]; } g = { { { _SC_ARG_MAX, 131072, 0 }, { _SC_CHILD_MAX, 1024, 0 }, { _SC_CLK_TCK, -1, 0 }, { _SC_NGROUPS_MAX, 32, 0 }, { _SC_OPEN_MAX, 1024, 0 }, { _SC_STREAM_MAX, 1024, 0 }, { _SC_TZNAME_MAX, 3, 0 }, { _SC_JOB_CONTROL, 0, 0 }, { _SC_SAVED_IDS, 0, 0 }, { _SC_VERSION, 0, 0 }, { _PC_MAX_CANON, 255, 0 }, { _PC_MAX_INPUT, 255, 0 }, { _PC_VDISABLE, 0, 0 }, { _PC_LINK_MAX, 32768, 0 }, { _PC_NAME_MAX, 1024, 0 }, { _PC_PATH_MAX, 4096, 2 }, { _PC_PIPE_BUF, 4096, 0 }, { _PC_NO_TRUNC, 0, 0 }, { _PC_CHOWN_RESTRICTED, 0, 0 } } }; /* C Returns system limits using I. If the limit is indeterminate, a predetermined default value is returned. Whatever happens, a usable value is returned. */ static long limit_sysconf(int limit) { long value; if ((value = sysconf(g.conf[limit].name)) == -1) return g.conf[limit].value; return value; } /* C Returns system limits using I. If the limit is indeterminate, a predetermined default value is returned. If the limit is determinate, a predetermined amount may be added to its value. This is only needed for C<_PC_PATH_MAX> which is the maximum length of a relative path. To be more useful, C<2> is added to this limit to account for the C<'/'> and C<'\0'> that will be needed to form an absolute path. Whatever happens, a usable value is returned. */ static long limit_pathconf(int limit, const char *path) { long value; if ((value = pathconf(path, g.conf[limit].name)) == -1) return g.conf[limit].value; return value + g.conf[limit].offset; } /* C Returns system limits using I. If the limit is indeterminate, a predetermined default value is returned. If the limit is determinate, a predetermined amount may be added to its value. This is only needed for C<_PC_PATH_MAX> which is the maximum length of a relative path. To be more useful, C<2> is added to this limit to account for the C<'/'> and C<'\0'> that will be needed to form an absolute path. Whatever happens, a usable value is returned. */ static long limit_fpathconf(int limit, int fd) { long value; if ((value = fpathconf(fd, g.conf[limit].name)) == -1) return g.conf[limit].value; return value + g.conf[limit].offset; } /* =item C Returns the maximum length of arguments to the I family of functions. If indeterminate, a usable value (131072) is returned. =cut */ long limit_arg(void) { return limit_sysconf(LIMIT_ARG); } /* =item C Returns the maximum number of simultaneous processes per user id. If indeterminate, a usable value (1024) is returned. =cut */ long limit_child(void) { return limit_sysconf(LIMIT_CHILD); } /* =item C Returns the number of clock ticks per second. If indeterminate (which makes no sense), -1 is returned. This should never happen. =cut */ long limit_tick(void) { return limit_sysconf(LIMIT_TICK); } /* =item C Returns the maximum number of groups that a user may belong to. If indeterminate, a usable value (32) is returned. =cut */ long limit_group(void) { return limit_sysconf(LIMIT_GROUP); } /* =item C Returns the maximum number of files that a process can have open at any time. If indeterminate, a usable value (1024) is returned. =cut */ long limit_open(void) { return limit_sysconf(LIMIT_OPEN); } /* =item C Returns the maximum number of streams that a process can have open at any time. If indeterminate, a usable value (1024) is returned. =cut */ long limit_stream(void) { return limit_sysconf(LIMIT_STREAM); } /* =item C Returns the maximum number of bytes in a time zone name. If indeterminate, a usable value (3) is returned. =cut */ long limit_tzname(void) { return limit_sysconf(LIMIT_TZNAME); } /* =item C Returns whether or not job control is supported. =cut */ long limit_job(void) { return limit_sysconf(LIMIT_JOB); } /* =item C Returns whether or not a process has a saved set-user-id and a saved set-group-id. =cut */ long limit_save_ids(void) { return limit_sysconf(LIMIT_SAVE_IDS); } /* =item C Returns the year and month the I standard was approved in the format I. =cut */ long limit_version(void) { return limit_sysconf(LIMIT_VERSION); } /* =item C Returns the maximum length of a formatted input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_pcanon(const char *path) { return limit_pathconf(LIMIT_CANON, path); } /* =item C Returns the maximum length of a formatted input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_fcanon(int fd) { return limit_fpathconf(LIMIT_CANON, fd); } /* =item C Returns the maximum length of a formatted input line for the controlling terminal (C). If indeterminate, a usable value (255) is returned. =cut */ long limit_canon(void) { return limit_pcanon("/dev/tty"); } /* =item C Returns the maximum length of an input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_pinput(const char *path) { return limit_pathconf(LIMIT_INPUT, path); } /* =item C Returns the maximum length of an input line for the terminal referred to by C. If indeterminate, a usable value (255) is returned. =cut */ long limit_finput(int fd) { return limit_fpathconf(LIMIT_INPUT, fd); } /* =item C Returns the maximum length of an input line for the controlling terminal (C). If indeterminate, a usable value (255) is returned. =cut */ long limit_input(void) { return limit_pinput("/dev/tty"); } /* =item C Returns whether or not special character processing can be disabled for the terminal referred to by C. =cut */ long limit_pvdisable(const char *path) { return limit_pathconf(LIMIT_VDISABLE, path); } /* =item C Returns whether or not special character processing can be disabled for the terminal referred to by C. =cut */ long limit_fvdisable(int fd) { return limit_fpathconf(LIMIT_VDISABLE, fd); } /* =item C Returns whether or not special character processing can be disabled for the controlling terminal (C). =cut */ long limit_vdisable(void) { return limit_pvdisable("/dev/tty"); } /* =item C Returns the maximum number of links to the file represented by C. If indeterminate, a usable value (32768) is returned. =cut */ long limit_plink(const char *path) { return limit_pathconf(LIMIT_LINK, path); } /* =item C Returns the maximum number of links to the file represented by C. If indeterminate, a usable value (32768) is returned. =cut */ long limit_flink(int fd) { return limit_fpathconf(LIMIT_LINK, fd); } /* =item C Returns the maximum number of links to the root directory (C). If indeterminate, a usable value (32768) is returned. =cut */ long limit_link(void) { return limit_plink("/"); } /* =item C Returns the maximum length of a filename in the directory referred to by C that the process can create. If indeterminate, a usable value (1024) is returned. =cut */ long limit_pname(const char *path) { return limit_pathconf(LIMIT_NAME, path); } /* =item C Returns the maximum length of a filename in the directory referred to by C that the process can create. If indeterminate, a usable value (1024) is returned. =cut */ long limit_fname(int fd) { return limit_fpathconf(LIMIT_NAME, fd); } /* =item C Returns the maximum length of a filename in the root directory (C) that the process can create. If indeterminate, a usable value (1024) is returned. =cut */ long limit_name(void) { return limit_pname("/"); } /* =item C Returns the maximum length of an absolute pathname (including the C character) when C is the current directory. If indeterminate, a usable value (4096) is returned. =cut */ long limit_ppath(const char *path) { return limit_pathconf(LIMIT_PATH, path); } /* =item C Returns the maximum length of an absolute pathname (including the C character) when C refers to the current directory. If indeterminate, a usable value (4096) is returned. =cut */ long limit_fpath(int fd) { return limit_fpathconf(LIMIT_PATH, fd); } /* =item C Returns the maximum length of an absolute pathname (including the C character). If indeterminate, a usable value (4096) is returned. =cut */ long limit_path(void) { return limit_ppath("/"); } /* =item C Returns the size of the pipe buffer for the fifo referred to by C. If indeterminate, a usable value (4096) is returned. =cut */ long limit_ppipe(const char *path) { return limit_pathconf(LIMIT_PIPE, path); } /* =item C Returns the size of the pipe buffer for the pipe or fifo referred to by C. If indeterminate, a usable value (4096) is returned. =cut */ long limit_fpipe(int fd) { return limit_fpathconf(LIMIT_PIPE, fd); } /* =item C Returns whether or not an error is generated when accessing filenames longer than the maximum filename length for the filesystem referred to by C. =cut */ long limit_pnotrunc(const char *path) { return limit_pathconf(LIMIT_NOTRUNC, path); } /* =item C Returns whether or not an error is generated when accessing filenames longer than the maximum filename length for the filesystem referred to by C. =cut */ long limit_fnotrunc(int fd) { return limit_fpathconf(LIMIT_NOTRUNC, fd); } /* =item C Returns whether or not an error is generated when accessing filenames longer than the maximum filename length for the root filesystem. =cut */ long limit_notrunc(void) { return limit_pnotrunc("/"); } /* =item C Returns whether or not I may be called on the file referred to by C or the files contained in the directory referred to by C. =cut */ long limit_pchown(const char *path) { return limit_pathconf(LIMIT_CHOWN, path); } /* =item C Returns whether or not I may be called on the file referred to by C or the files contained in the directory referred to by C. =cut */ long limit_fchown(int fd) { return limit_fpathconf(LIMIT_CHOWN, fd); } /* =item C Returns whether or not I may be called on the files contained in the root filesystem. =cut */ long limit_chown(void) { return limit_pchown("/"); } /* =back =head1 RETURNS The functions that return a condition return C<1> when the condition is true or C<0> when it is false. All of the others either return the system limit indicated, or a predetermined, usable value when the indicated limit is indeterminate. These functions never return C<-1>. =head1 MT-Level I =head1 EXAMPLES Store the current directory into allocated memory: #include #include int main() { long path_size = limit_path(); char *buf = malloc(path_size * sizeof(char)); if (!buf) return EXIT_FAILURE; printf("%s\n", getcwd(buf, path_size)); return EXIT_SUCCESS; } Close all file descriptors: #include #include int main() { int fd_limit = limit_open(); int fd; for (fd = 0; fd < fd_limit; ++fd) close(fd); return EXIT_SUCCESS; } =head1 SEE ALSO I, I, I, I, I =head1 AUTHOR 20230824 raf =cut */ #endif #ifdef TEST int main(int ac, char **av) { int fds[2]; long limit; int errors = 0; int verbose = (ac >= 2 && !strcmp(av[1], "-v")); if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [-v]\n", *av); return EXIT_SUCCESS; } printf("Testing: %s\n", "lim"); if ((limit = limit_arg()) == -1) ++errors, printf("Test1: limit_arg() failed\n"); else if (verbose) printf("arg = %ld\n", limit); if ((limit = limit_child()) == -1) ++errors, printf("Test2: limit_child() failed\n"); else if (verbose) printf("child = %ld\n", limit); if ((limit = limit_tick()) == -1) ++errors, printf("Test3: limit_tick() failed\n"); else if (verbose) printf("tick = %ld\n", limit); if ((limit = limit_group()) == -1) ++errors, printf("Test4: limit_group() failed\n"); else if (verbose) printf("group = %ld\n", limit); if ((limit = limit_open()) == -1) ++errors, printf("Test5: limit_open() failed\n"); else if (verbose) printf("open = %ld\n", limit); if ((limit = limit_stream()) == -1) ++errors, printf("Test6: limit_stream() failed\n"); else if (verbose) printf("stream = %ld\n", limit); if ((limit = limit_tzname()) == -1) ++errors, printf("Test7: limit_tzname() failed\n"); else if (verbose) printf("tzname = %ld\n", limit); if ((limit = limit_job()) == -1) ++errors, printf("Test8: limit_job() failed\n"); else if (verbose) printf("job = %ld\n", limit); if ((limit = limit_save_ids()) == -1) ++errors, printf("Test9: limit_save_ids() failed\n"); else if (verbose) printf("save_ids = %ld\n", limit); if ((limit = limit_version()) == -1) ++errors, printf("Test10: limit_version() failed\n"); else if (verbose) printf("version = %ld\n", limit); if ((limit = limit_canon()) == -1) ++errors, printf("Test11: limit_canon() failed\n"); else if (verbose) printf("canon = %ld\n", limit); if ((limit = limit_input()) == -1) ++errors, printf("Test12: limit_input() failed\n"); else if (verbose) printf("input = %ld\n", limit); if ((limit = limit_vdisable()) == -1) ++errors, printf("Test13: limit_vdisable() failed\n"); else if (verbose) printf("vdisable = %ld\n", limit); if ((limit = limit_link()) == -1) ++errors, printf("Test14: limit_link() failed\n"); else if (verbose) printf("link = %ld\n", limit); if ((limit = limit_name()) == -1) ++errors, printf("Test15: limit_name() failed\n"); else if (verbose) printf("name = %ld\n", limit); if ((limit = limit_path()) == -1) ++errors, printf("Test16: limit_path() failed\n"); else if (verbose) printf("path = %ld\n", limit); if (pipe(fds) == -1) { ++errors, printf("Test17: failed to test limit_fpipe() - pipe() failed (%s)\n", strerror(errno)); } else { if ((limit = limit_fpipe(fds[0])) == -1) ++errors, printf("Test17: limit_fpipe() failed\n"); else if (verbose) printf("pipe = %ld\n", limit); close(fds[0]); close(fds[1]); } if ((limit = limit_notrunc()) == -1) ++errors, printf("Test18: limit_notrunc() failed\n"); else if (verbose) printf("notrunc = %ld\n", limit); if ((limit = limit_chown()) == -1) ++errors, printf("Test19: limit_chown() failed\n"); else if (verbose) printf("chown = %ld\n", limit); if (errors) printf("%d/19 tests failed\n", errors); else printf("All tests passed\n"); return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif /* vi:set ts=4 sw=4: */