backing out to version 208 of util-vserver
[util-vserver.git] / src / exec-ulimit.c
1 // $Id: exec-ulimit.c,v 1.7 2004/05/08 01:40:25 ensc Exp $    --*- 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 #define DECLARE_LIMIT(RES,FNAME) { #FNAME, RLIMIT_##RES }
38
39 int     wrapper_exit_code = 255;
40
41 static struct {
42     char const  *fname;
43     int         code;
44 } const LIMITS[] = {
45   DECLARE_LIMIT(CORE,    core),
46   DECLARE_LIMIT(CPU,     cpu),
47   DECLARE_LIMIT(DATA,    data),
48   DECLARE_LIMIT(FSIZE,   fsize),
49   DECLARE_LIMIT(LOCKS,   locks),
50   DECLARE_LIMIT(MEMLOCK, memlock),
51   DECLARE_LIMIT(NOFILE,  nofile),
52   DECLARE_LIMIT(NPROC,   nproc),
53   DECLARE_LIMIT(RSS,     rss),
54   DECLARE_LIMIT(STACK,   stack),
55 };
56
57 static rlim_t
58 readValue(int fd, char const *filename)
59 {
60   char          buf[128];
61   size_t        len = Eread(fd, buf, sizeof(buf)-1);
62   long int      res;
63   char *        errptr;
64
65   buf[len] = '\0';
66   if (strncmp(buf, "inf", 3)==0) return RLIM_INFINITY;
67   res = strtol(buf, &errptr, 0);
68
69   if (errptr!=buf) {
70     switch (*errptr) {
71       case 'M'  :  res *= 1024; /* fallthrough */
72       case 'K'  :  res *= 1024; ++errptr; break;
73       case 'm'  :  res *= 1000; /* fallthrough */
74       case 'k'  :  res *= 1000; ++errptr; break;
75       default   :  break;
76     }
77   }
78
79   if (errptr==buf || (*errptr!='\0' && *errptr!='\n')) {
80     WRITE_MSG(2, "Invalid limit in '");
81     WRITE_STR(2, filename);
82     WRITE_STR(2, "'\n");
83     exit(255);
84   }
85
86   return res;
87 }
88
89 static bool
90 readSingleLimit(struct rlimit *lim, char const *fname_base)
91 {
92   size_t        fname_len = strlen(fname_base);
93   char          fname[fname_len + sizeof(".hard")];
94   int           fd;
95   bool          is_modified = false;
96
97   strcpy(fname, fname_base);
98   
99   fd = open(fname, O_RDONLY);
100   if (fd!=-1) {
101     rlim_t      tmp = readValue(fd, fname_base);
102     lim->rlim_cur = tmp;
103     lim->rlim_max = tmp;
104     Eclose(fd);
105
106     is_modified = true;
107   }
108
109   strcpy(fname+fname_len, ".hard");
110   fd = open(fname, O_RDONLY);
111   if (fd!=-1) {
112     lim->rlim_max = readValue(fd, fname_base);
113     Eclose(fd);
114     
115     is_modified = true;
116   }
117
118   strcpy(fname+fname_len, ".soft");
119   fd = open(fname, O_RDONLY);
120   if (fd!=-1) {
121     lim->rlim_cur = readValue(fd, fname_base);
122     Eclose(fd);
123     
124     is_modified = true;
125   }
126
127   if (is_modified &&
128       lim->rlim_max!=RLIM_INFINITY &&
129       (lim->rlim_cur==RLIM_INFINITY ||
130        lim->rlim_cur>lim->rlim_max))
131     lim->rlim_cur = lim->rlim_max;
132
133   return is_modified;
134 }
135
136 static void
137 showHelp(int fd, char const *cmd, int res)
138 {
139   WRITE_MSG(fd, "Usage:  ");
140   WRITE_STR(fd, cmd);
141   WRITE_STR(fd,
142             "<ulimit-cfgdir> <cmd> <argv>*\n\n"
143             "Please report bugs to " PACKAGE_BUGREPORT "\n");
144   exit(res);
145 }
146
147 static void
148 showVersion()
149 {
150   WRITE_MSG(1,
151             "exec-ulimit " VERSION " -- executes programs with resource limits\n"
152             "This program is part of " PACKAGE_STRING "\n\n"
153             "Copyright (C) 2003 Enrico Scholz\n"
154             VERSION_COPYRIGHT_DISCLAIMER);
155   exit(0);
156 }
157
158 int main(int argc, char *argv[])
159 {
160   size_t                i;
161   int                   cur_fd = Eopen(".", O_RDONLY, 0);
162
163   if (argc==2) {
164     if (strcmp(argv[1], "--help")==0)    showHelp(1,argv[0],0);
165     if (strcmp(argv[1], "--version")==0) showVersion();
166   }
167
168   if (argc<3) {
169     WRITE_MSG(2, "Bad parameter count; use '--help' for more information.\n");
170     exit(255);
171   }
172
173   if (chdir(argv[1])!=-1) {
174     for (i=0; i<sizeof(LIMITS)/sizeof(LIMITS[0]); ++i) {
175       struct rlimit     limit;
176
177       Egetrlimit(LIMITS[i].code, &limit);
178       if (readSingleLimit(&limit, LIMITS[i].fname))
179         Esetrlimit(LIMITS[i].code, &limit);
180     }
181     Efchdir(cur_fd);
182   }
183   Eclose(cur_fd);
184
185   Eexecv(argv[2], argv+2);
186 }