merge with 0.30.213
[util-vserver.git] / src / exec-ulimit.c
1 // $Id: exec-ulimit.c 2371 2006-11-05 17:46:33Z dhozac $    --*- 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 }