projtool.pl: do not attempt to check unset error codes
[girocco.git] / src / ulimit512.c
blob24a41db3b25d03285baad60a84217280deb134c9
1 /*
3 ulimit512.c - provide ulimit -f with 512-byte units on the command line
4 Copyright (C) 2018,2020 Kyle J. McKay. All rights reserved.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #define VERSION \
23 "ulimit512 version 1.0.0\n" \
24 "Copyright (C) 2018,2020,2021 Kyle J. McKay <mackyle at gmail dot com>\n" \
25 "License GPLv2+: GNU GPL version 2 or later.\n" \
26 "<http://gnu.org/licenses/gpl2.html>\n" \
27 "This is free software: you are free to change and redistribute it.\n" \
28 "There is NO WARRANTY, to the extent permitted by law.\n"
30 #define USAGE \
31 "Usage: ulimit512 [option...] [<command> [<arg>...]]\n" \
32 " --help/-h show this help\n" \
33 " --version/-V show version/license info\n" \
34 " -f <blks> set UL_SETFSIZE to <blks> (dec/oct/hex # of 512-byte units)\n" \
35 " -i ignore UL_SETFSIZE error if UL_GETFSIZE is <= <blks> value\n" \
36 " -- terminate options, next arg is command even if it starts with -\n" \
37 " <command> if omitted do nothing other than attempt to set ulimit fsize\n" \
38 " <arg>... zero or more optional args to pass to <command>\n" \
39 "First sets ulimit UL_SETFSIZE value if any -f option given then uses execvp to\n" \
40 "run the <command> with any given <arg> values. A failure of UL_SETFSIZE or\n" \
41 "execvp will always result in an error. Note that the value given for -f ALWAYS\n" \
42 "specifies the limit in number of 512-byte units as required by POSIX and that\n" \
43 "the maximum value is the largest positive value that fits in a `long` type.\n" \
44 "Any -f values starting with `0x` are taken to be hexadecimal, starting with `0`\n" \
45 "means octal otherwise the value is decimal. It may NOT be negative.\n" \
46 "Note that using a <blks> value of 0 means zero bytes and is in no way special.\n"
48 #define HAVE_RLIMIT 1
49 #ifdef CONFIG_H
50 #include CONFIG_H
51 #endif
52 #include <stddef.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <errno.h>
56 #include <string.h>
57 #include <unistd.h>
58 #ifdef HAVE_RLIMIT
59 #include <limits.h>
60 #include <sys/types.h>
61 #include <sys/time.h>
62 #include <sys/resource.h>
63 #else
64 #include <ulimit.h>
65 #endif
67 #ifdef HAVE_RLIMIT
68 static long ulimit_get(void)
70 struct rlimit rl;
71 int rc = getrlimit(RLIMIT_FSIZE, &rl);
72 rlim_t fs;
73 if (rc)
74 return -1;
75 fs = rl.rlim_max >> 9;
76 if (rl.rlim_max == RLIM_INFINITY || fs > LONG_MAX)
77 return LONG_MAX;
78 return (long)fs;
81 static long ulimit_set(long fs)
83 struct rlimit rl;
84 int rc;
85 rlim_t fsbytes;
86 if (fs < 0) {
87 errno = EINVAL;
88 return -1;
90 fsbytes = (rlim_t)fs << 9;
91 if ((fsbytes >> 9) != fs) {
92 errno = EINVAL;
93 return -1;
95 rl.rlim_max = fsbytes;
96 rl.rlim_cur = fsbytes;
97 rc = setrlimit(RLIMIT_FSIZE, &rl);
98 return rc ? -1 : 0;
100 #else
101 #define ulimit_get() ulimit(UL_GETFSIZE)
102 #define ulimit_set(fs) ulimit(UL_SETFSIZE, (fs))
103 #endif
105 int main(int argc, char *argv[])
108 int arg = 1;
109 long fsize = -1;
110 int ignore = 0;
112 while (arg < argc && *argv[arg] == '-') {
113 if (!strcmp(argv[arg], "--help") || !strcmp(argv[arg], "-h")) {
114 printf("%s", USAGE);
115 return 0;
117 if (!strcmp(argv[arg], "--version") || !strcmp(argv[arg], "-V")) {
118 printf("%s", VERSION);
119 return 0;
121 if (!strcmp(argv[arg], "-i")) {
122 ignore = 1;
123 ++arg;
124 continue;
126 if (!strcmp(argv[arg], "-f")) {
127 char *end;
129 if (++arg >= argc || !*argv[arg]) {
130 fprintf(stderr, "ulimit512: missing -f value\n");
131 return 1;
133 fsize = strtol(argv[arg], &end, 0);
134 if (*end) {
135 fprintf(stderr, "ulimit512: invalid number: %s\n",
136 argv[arg]);
137 return 2;
139 if (fsize < 0) {
140 fprintf(stderr, "ulimit512: invalid limit %ld "
141 "is < 0\n", fsize);
142 return 2;
144 ++arg;
145 continue;
147 if (!strcmp(argv[arg], "--")) {
148 ++arg;
149 break;
151 fprintf(stderr, "ulimit512: invalid option: %s (see ulimit512 -h)\n",
152 argv[arg]);
153 return 1;
155 if (fsize >= 0) {
156 long result;
158 errno = 0;
159 result = ulimit_set(fsize);
160 if (result == -1 && errno != 0) {
161 int olderr = errno;
162 if (ignore) {
163 result = 0;
164 result = ulimit_get();
165 if (result < 0 || result > fsize)
166 ignore = 0;
168 if (!ignore) {
169 fprintf(stderr, "ulimit512: error: "
170 "set FSIZE limit %ld 512-byte units "
171 "failed: %s\n", fsize,
172 strerror(olderr));
173 return 1;
178 if (arg < argc) {
179 int i, cnt = argc - arg;
180 char **cmd = (char **)malloc((cnt + 1) * sizeof(char *));
182 if (!cmd) {
183 fprintf(stderr, "ulimit512: out of memory\n");
184 return 1;
186 for (i = 0; i < cnt; ++i) {
187 cmd[i] = argv[arg + i];
189 cmd[i] = NULL;
190 if (execvp(cmd[0], cmd) == -1) {
191 fprintf(stderr, "ulimit512: error: execvp failed: %s\n",
192 strerror(errno));
193 return 1;
195 /* It's an error if execvp returns even if it's not -1 */
196 return 1;
199 /* No error if nothing to do or just UL_SETFSIZE and that succeeded */
200 return 0;