exec-ulimit.c (5294B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; version 2 of the License. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 18 19 #ifdef HAVE_CONFIG_H 20 # include <config.h> 21 #endif 22 23 #include "util.h" 24 25 #include <sys/time.h> 26 #include <sys/resource.h> 27 #include <unistd.h> 28 #include <fcntl.h> 29 #include <errno.h> 30 31 #define ENSC_WRAPPERS_PREFIX "exec-ulimit: " 32 #define ENSC_WRAPPERS_UNISTD 1 33 #define ENSC_WRAPPERS_FCNTL 1 34 #define ENSC_WRAPPERS_RESOURCE 1 35 #include <wrappers.h> 36 37 /* dietlibc specifies this as (~0UL>>1), which is what's returned from 38 * sys_old_getrlimit, called on some arches for getrlimit. 39 * Reset it here so the kernel will have the correct values when we set it. */ 40 #undef RLIM_INFINITY 41 #define RLIM_INFINITY (~0UL) 42 #define OLD_RLIM_INFINITY (~0UL>>1) 43 44 #define DECLARE_LIMIT(RES,FNAME) { #FNAME, RLIMIT_##RES } 45 46 int wrapper_exit_code = 255; 47 48 static struct { 49 char const *fname; 50 int code; 51 } const LIMITS[] = { 52 DECLARE_LIMIT(CORE, core), 53 DECLARE_LIMIT(CPU, cpu), 54 DECLARE_LIMIT(DATA, data), 55 DECLARE_LIMIT(FSIZE, fsize), 56 DECLARE_LIMIT(LOCKS, locks), 57 DECLARE_LIMIT(MEMLOCK, memlock), 58 DECLARE_LIMIT(NOFILE, nofile), 59 DECLARE_LIMIT(NPROC, nproc), 60 DECLARE_LIMIT(RSS, rss), 61 DECLARE_LIMIT(STACK, stack), 62 }; 63 64 static rlim_t 65 readValue(int fd, char const *filename) 66 { 67 char buf[128]; 68 size_t len = Eread(fd, buf, sizeof(buf)-1); 69 long int res; 70 char * errptr; 71 72 buf[len] = '\0'; 73 if (strncmp(buf, "inf", 3)==0) return RLIM_INFINITY; 74 res = strtol(buf, &errptr, 0); 75 76 if (errptr!=buf) { 77 switch (*errptr) { 78 case 'M' : res *= 1024; /* fallthrough */ 79 case 'K' : res *= 1024; ++errptr; break; 80 case 'm' : res *= 1000; /* fallthrough */ 81 case 'k' : res *= 1000; ++errptr; break; 82 default : break; 83 } 84 } 85 86 if (errptr==buf || (*errptr!='\0' && *errptr!='\n')) { 87 WRITE_MSG(2, "Invalid limit in '"); 88 WRITE_STR(2, filename); 89 WRITE_STR(2, "'\n"); 90 exit(255); 91 } 92 93 return res; 94 } 95 96 static bool 97 readSingleLimit(struct rlimit *lim, char const *fname_base) 98 { 99 size_t fname_len = strlen(fname_base); 100 char fname[fname_len + sizeof(".hard")]; 101 int fd; 102 bool is_modified = false; 103 104 strcpy(fname, fname_base); 105 106 fd = open(fname, O_RDONLY); 107 if (fd!=-1) { 108 rlim_t tmp = readValue(fd, fname_base); 109 lim->rlim_cur = tmp; 110 lim->rlim_max = tmp; 111 Eclose(fd); 112 113 is_modified = true; 114 } 115 116 strcpy(fname+fname_len, ".hard"); 117 fd = open(fname, O_RDONLY); 118 if (fd!=-1) { 119 lim->rlim_max = readValue(fd, fname_base); 120 Eclose(fd); 121 122 is_modified = true; 123 } 124 125 strcpy(fname+fname_len, ".soft"); 126 fd = open(fname, O_RDONLY); 127 if (fd!=-1) { 128 lim->rlim_cur = readValue(fd, fname_base); 129 Eclose(fd); 130 131 is_modified = true; 132 } 133 134 if (is_modified && 135 lim->rlim_max!=RLIM_INFINITY && 136 (lim->rlim_cur==RLIM_INFINITY || 137 lim->rlim_cur>lim->rlim_max)) 138 lim->rlim_cur = lim->rlim_max; 139 140 return is_modified; 141 } 142 143 static void 144 showHelp(int fd, char const *cmd, int res) 145 { 146 WRITE_MSG(fd, "Usage: "); 147 WRITE_STR(fd, cmd); 148 WRITE_STR(fd, 149 "<ulimit-cfgdir> <cmd> <argv>*\n\n" 150 "Please report bugs to " PACKAGE_BUGREPORT "\n"); 151 exit(res); 152 } 153 154 static void 155 showVersion() 156 { 157 WRITE_MSG(1, 158 "exec-ulimit " VERSION " -- executes programs with resource limits\n" 159 "This program is part of " PACKAGE_STRING "\n\n" 160 "Copyright (C) 2003 Enrico Scholz\n" 161 VERSION_COPYRIGHT_DISCLAIMER); 162 exit(0); 163 } 164 165 int main(int argc, char *argv[]) 166 { 167 size_t i; 168 int cur_fd = Eopen(".", O_RDONLY, 0); 169 bool in_dir = false; 170 171 if (argc==2) { 172 if (strcmp(argv[1], "--help")==0) showHelp(1,argv[0],0); 173 if (strcmp(argv[1], "--version")==0) showVersion(); 174 } 175 176 if (argc<3) { 177 WRITE_MSG(2, "Bad parameter count; use '--help' for more information.\n"); 178 exit(255); 179 } 180 181 if (chdir(argv[1])!=-1) { 182 in_dir = true; 183 } 184 for (i=0; i<sizeof(LIMITS)/sizeof(LIMITS[0]); ++i) { 185 struct rlimit limit; 186 187 Egetrlimit(LIMITS[i].code, &limit); 188 /* if this arch uses sys_old_getrlimit... */ 189 if (limit.rlim_cur == OLD_RLIM_INFINITY) 190 limit.rlim_cur = RLIM_INFINITY; 191 if (in_dir && readSingleLimit(&limit, LIMITS[i].fname)) 192 Esetrlimit(LIMITS[i].code, &limit); 193 else if (LIMITS[i].code != RLIMIT_NOFILE) { 194 limit.rlim_max = RLIM_INFINITY; 195 Esetrlimit(LIMITS[i].code, &limit); 196 } 197 else { 198 /* RLIMIT_NOFILE can't be set to infinity, 1024*1024 seems to be the limit in most kernels */ 199 limit.rlim_max = 1024*1024; 200 setrlimit(LIMITS[i].code, &limit); 201 } 202 } 203 if (in_dir) 204 Efchdir(cur_fd); 205 Eclose(cur_fd); 206 207 Eexecv(argv[2], argv+2); 208 }