work also, when ulimit-directory does not exist
[util-vserver.git] / util-vserver / src / exec-ulimit.c
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 "wrappers.h"
24 #include "util.h"
25
26 #include <sys/time.h>
27 #include <sys/resource.h>
28 #include <unistd.h>
29
30 #define DECLARE_LIMIT(RES,FNAME) { #FNAME, RLIMIT_##RES }
31
32 int     wrapper_exit_code = 255;
33
34 static struct {
35     char const  *fname;
36     int         code;
37 } const LIMITS[] = {
38   DECLARE_LIMIT(CPU,     cpu),
39   DECLARE_LIMIT(DATA,    data),
40   DECLARE_LIMIT(FSIZE,   fsize),
41   DECLARE_LIMIT(LOCKS,   locks),
42   DECLARE_LIMIT(MEMLOCK, memlock),
43   DECLARE_LIMIT(NOFILE,  nofile),
44   DECLARE_LIMIT(NPROC,   nproc),
45   DECLARE_LIMIT(RSS,     rss),
46   DECLARE_LIMIT(STACK,   stack),
47 };
48
49 static rlim_t
50 readValue(int fd, char const *filename)
51 {
52   char          buf[128];
53   size_t        len = Eread(fd, buf, sizeof(buf)-1);
54   long int      res;
55   char *        errptr;
56
57   buf[len] = '\0';
58   if (strncmp(buf, "inf", 3)==0) return RLIM_INFINITY;
59   res = strtol(buf, &errptr, 0);
60
61   if (errptr==buf || (*errptr!='\0' && *errptr!='\n')) {
62     WRITE_MSG(2, "Invalid limit in '");
63     WRITE_STR(2, filename);
64     WRITE_STR(2, "'\n");
65     exit(255);
66   }
67
68   return res;
69 }
70
71 static bool
72 readSingleLimit(struct rlimit *lim, char const *fname_base)
73 {
74   size_t        fname_len = strlen(fname_base);
75   char          fname[fname_len + sizeof(".hard")];
76   int           fd;
77   bool          is_modified = false;
78
79   strcpy(fname, fname_base);
80   
81   fd = open(fname, O_RDONLY);
82   if (fd!=-1) {
83     rlim_t      tmp = readValue(fd, fname_base);
84     lim->rlim_cur = tmp;
85     lim->rlim_max = tmp;
86     Eclose(fd);
87
88     is_modified = true;
89   }
90
91   strcpy(fname+fname_len, ".hard");
92   fd = open(fname, O_RDONLY);
93   if (fd!=-1) {
94     lim->rlim_max = readValue(fd, fname_base);
95     Eclose(fd);
96     
97     is_modified = true;
98   }
99
100   strcpy(fname+fname_len, ".soft");
101   fd = open(fname, O_RDONLY);
102   if (fd!=-1) {
103     lim->rlim_cur = readValue(fd, fname_base);
104     Eclose(fd);
105     
106     is_modified = true;
107   }
108
109   if (is_modified &&
110       lim->rlim_max!=RLIM_INFINITY &&
111       (lim->rlim_cur==RLIM_INFINITY ||
112        lim->rlim_cur>lim->rlim_max))
113     lim->rlim_cur = lim->rlim_max;
114
115   return is_modified;
116 }
117
118 int main(int argc, char *argv[])
119 {
120   size_t                i;
121   int                   cur_fd = Eopen(".", O_RDONLY, 0);
122   
123   if (argc<3) {
124     WRITE_MSG(2, "Usage: exec-ulimit <ulimit-cfgdir> <cmd> <argv>*\n");
125     exit(255);
126   }
127
128   if (chdir(argv[1])!=-1) {
129     for (i=0; i<sizeof(LIMITS)/sizeof(LIMITS[0]); ++i) {
130       struct rlimit     limit;
131
132       Egetrlimit(LIMITS[i].code, &limit);
133       if (readSingleLimit(&limit, LIMITS[i].fname))
134         Esetrlimit(LIMITS[i].code, &limit);
135     }
136     Efchdir(cur_fd);
137   }
138   Eclose(cur_fd);
139
140   Eexecv(argv[2], argv+2);
141 }