Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/runit/chpst.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 9862 byte(s)
-updated to busybox-1.13.4
1 niro 532 /*
2     Copyright (c) 2001-2006, Gerrit Pape
3     All rights reserved.
4    
5     Redistribution and use in source and binary forms, with or without
6     modification, are permitted provided that the following conditions are met:
7    
8     1. Redistributions of source code must retain the above copyright notice,
9     this list of conditions and the following disclaimer.
10     2. Redistributions in binary form must reproduce the above copyright
11     notice, this list of conditions and the following disclaimer in the
12     documentation and/or other materials provided with the distribution.
13     3. The name of the author may not be used to endorse or promote products
14     derived from this software without specific prior written permission.
15    
16     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17     WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19     EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26     */
27    
28 niro 816 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 niro 532 /* Dependencies on runit_lib.c removed */
30    
31 niro 816 #include "libbb.h"
32 niro 532 #include <dirent.h>
33    
34 niro 816 /*
35     Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
36 niro 532
37 niro 816 Only softlimit and chpst are taking options:
38 niro 532
39 niro 816 # common
40     -o N Limit number of open files per process
41     -p N Limit number of processes per uid
42     -m BYTES Same as -d BYTES -s BYTES -l BYTES [-a BYTES]
43     -d BYTES Limit data segment
44     -f BYTES Limit output file sizes
45     -c BYTES Limit core file size
46     # softlimit
47     -a BYTES Limit total size of all segments
48     -s BYTES Limit stack segment
49     -l BYTES Limit locked memory size
50     -r BYTES Limit resident set size
51     -t N Limit CPU time
52     # chpst
53     -u USER[:GRP] Set uid and gid
54     -U USER[:GRP] Set $UID and $GID in environment
55     -e DIR Set environment variables as specified by files in DIR
56     -/ DIR Chroot to DIR
57     -n NICE Add NICE to nice value
58     -v Verbose
59     -P Create new process group
60     -0 -1 -2 Close fd 0,1,2
61 niro 532
62 niro 816 Even though we accept all these options for both softlimit and chpst,
63     they are not to be advertised on their help texts.
64     We have enough problems with feature creep in other people's
65     software, don't want to add our own.
66 niro 532
67 niro 816 envdir, envuidgid, setuidgid take no options, but they reuse code which
68     handles -e, -U and -u.
69     */
70 niro 532
71 niro 816 enum {
72     OPT_a = (1 << 0) * ENABLE_SOFTLIMIT,
73     OPT_c = (1 << 1) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
74     OPT_d = (1 << 2) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
75     OPT_f = (1 << 3) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
76     OPT_l = (1 << 4) * ENABLE_SOFTLIMIT,
77     OPT_m = (1 << 5) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
78     OPT_o = (1 << 6) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
79     OPT_p = (1 << 7) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
80     OPT_r = (1 << 8) * ENABLE_SOFTLIMIT,
81     OPT_s = (1 << 9) * ENABLE_SOFTLIMIT,
82     OPT_t = (1 << 10) * ENABLE_SOFTLIMIT,
83     OPT_u = (1 << 11) * (ENABLE_CHPST || ENABLE_SETUIDGID),
84     OPT_U = (1 << 12) * (ENABLE_CHPST || ENABLE_ENVUIDGID),
85     OPT_e = (1 << 13) * (ENABLE_CHPST || ENABLE_ENVDIR),
86     OPT_root = (1 << 14) * ENABLE_CHPST,
87     OPT_n = (1 << 15) * ENABLE_CHPST,
88     OPT_v = (1 << 16) * ENABLE_CHPST,
89     OPT_P = (1 << 17) * ENABLE_CHPST,
90     OPT_0 = (1 << 18) * ENABLE_CHPST,
91     OPT_1 = (1 << 19) * ENABLE_CHPST,
92     OPT_2 = (1 << 20) * ENABLE_CHPST,
93     };
94 niro 532
95     static void edir(const char *directory_name)
96     {
97     int wdir;
98     DIR *dir;
99     struct dirent *d;
100     int fd;
101    
102     wdir = xopen(".", O_RDONLY | O_NDELAY);
103     xchdir(directory_name);
104     dir = opendir(".");
105     if (!dir)
106     bb_perror_msg_and_die("opendir %s", directory_name);
107     for (;;) {
108 niro 816 char buf[256];
109     char *tail;
110     int size;
111    
112 niro 532 errno = 0;
113     d = readdir(dir);
114     if (!d) {
115     if (errno)
116     bb_perror_msg_and_die("readdir %s",
117     directory_name);
118     break;
119     }
120 niro 816 if (d->d_name[0] == '.')
121     continue;
122 niro 532 fd = open(d->d_name, O_RDONLY | O_NDELAY);
123     if (fd < 0) {
124 niro 816 if ((errno == EISDIR) && directory_name) {
125     if (option_mask32 & OPT_v)
126 niro 532 bb_perror_msg("warning: %s/%s is a directory",
127     directory_name, d->d_name);
128     continue;
129     } else
130     bb_perror_msg_and_die("open %s/%s",
131     directory_name, d->d_name);
132     }
133 niro 816 size = full_read(fd, buf, sizeof(buf)-1);
134     close(fd);
135     if (size < 0)
136     bb_perror_msg_and_die("read %s/%s",
137     directory_name, d->d_name);
138     if (size == 0) {
139     unsetenv(d->d_name);
140     continue;
141 niro 532 }
142 niro 816 buf[size] = '\n';
143     tail = strchr(buf, '\n');
144     /* skip trailing whitespace */
145     while (1) {
146     *tail = '\0';
147     tail--;
148     if (tail < buf || !isspace(*tail))
149     break;
150     }
151     xsetenv(d->d_name, buf);
152 niro 532 }
153     closedir(dir);
154 niro 816 if (fchdir(wdir) == -1)
155     bb_perror_msg_and_die("fchdir");
156 niro 532 close(wdir);
157     }
158    
159     static void limit(int what, long l)
160     {
161     struct rlimit r;
162    
163 niro 816 /* Never fails under Linux (except if you pass it bad arguments) */
164     getrlimit(what, &r);
165 niro 532 if ((l < 0) || (l > r.rlim_max))
166     r.rlim_cur = r.rlim_max;
167     else
168     r.rlim_cur = l;
169 niro 816 if (setrlimit(what, &r) == -1)
170     bb_perror_msg_and_die("setrlimit");
171 niro 532 }
172    
173 niro 816 int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
174     int chpst_main(int argc UNUSED_PARAM, char **argv)
175 niro 532 {
176 niro 816 struct bb_uidgid_t ugid;
177     char *set_user = set_user; /* for compiler */
178     char *env_user = env_user;
179     char *env_dir = env_dir;
180     char *root;
181     char *nicestr;
182     unsigned limita;
183     unsigned limitc;
184     unsigned limitd;
185     unsigned limitf;
186     unsigned limitl;
187     unsigned limitm;
188     unsigned limito;
189     unsigned limitp;
190     unsigned limitr;
191     unsigned limits;
192     unsigned limitt;
193     unsigned opt;
194    
195     if ((ENABLE_CHPST && applet_name[0] == 'c')
196     || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
197     ) {
198     // FIXME: can we live with int-sized limits?
199     // can we live with 40000 days?
200     // if yes -> getopt converts strings to numbers for us
201     opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
202     opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
203     USE_CHPST("/:n:vP012"),
204     &limita, &limitc, &limitd, &limitf, &limitl,
205     &limitm, &limito, &limitp, &limitr, &limits, &limitt,
206     &set_user, &env_user, &env_dir
207     USE_CHPST(, &root, &nicestr));
208     argv += optind;
209     if (opt & OPT_m) { // -m means -asld
210     limita = limits = limitl = limitd = limitm;
211     opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
212     }
213     } else {
214     option_mask32 = opt = 0;
215     argv++;
216     if (!*argv)
217     bb_show_usage();
218     }
219    
220     // envdir?
221     if (ENABLE_ENVDIR && applet_name[3] == 'd') {
222     env_dir = *argv++;
223     opt |= OPT_e;
224     }
225    
226     // setuidgid?
227     if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
228     set_user = *argv++;
229     opt |= OPT_u;
230     }
231    
232     // envuidgid?
233     if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
234     env_user = *argv++;
235     opt |= OPT_U;
236     }
237    
238     // we must have PROG [ARGS]
239     if (!*argv)
240     bb_show_usage();
241    
242     // set limits
243     if (opt & OPT_d) {
244 niro 532 #ifdef RLIMIT_DATA
245     limit(RLIMIT_DATA, limitd);
246     #else
247 niro 816 if (opt & OPT_v)
248     bb_error_msg("system does not support RLIMIT_%s",
249     "DATA");
250 niro 532 #endif
251     }
252 niro 816 if (opt & OPT_s) {
253 niro 532 #ifdef RLIMIT_STACK
254     limit(RLIMIT_STACK, limits);
255     #else
256 niro 816 if (opt & OPT_v)
257     bb_error_msg("system does not support RLIMIT_%s",
258     "STACK");
259 niro 532 #endif
260     }
261 niro 816 if (opt & OPT_l) {
262 niro 532 #ifdef RLIMIT_MEMLOCK
263     limit(RLIMIT_MEMLOCK, limitl);
264     #else
265 niro 816 if (opt & OPT_v)
266     bb_error_msg("system does not support RLIMIT_%s",
267     "MEMLOCK");
268 niro 532 #endif
269     }
270 niro 816 if (opt & OPT_a) {
271 niro 532 #ifdef RLIMIT_VMEM
272     limit(RLIMIT_VMEM, limita);
273     #else
274     #ifdef RLIMIT_AS
275     limit(RLIMIT_AS, limita);
276     #else
277 niro 816 if (opt & OPT_v)
278     bb_error_msg("system does not support RLIMIT_%s",
279     "VMEM");
280 niro 532 #endif
281     #endif
282     }
283 niro 816 if (opt & OPT_o) {
284 niro 532 #ifdef RLIMIT_NOFILE
285     limit(RLIMIT_NOFILE, limito);
286     #else
287     #ifdef RLIMIT_OFILE
288     limit(RLIMIT_OFILE, limito);
289     #else
290 niro 816 if (opt & OPT_v)
291     bb_error_msg("system does not support RLIMIT_%s",
292     "NOFILE");
293 niro 532 #endif
294     #endif
295     }
296 niro 816 if (opt & OPT_p) {
297 niro 532 #ifdef RLIMIT_NPROC
298     limit(RLIMIT_NPROC, limitp);
299     #else
300 niro 816 if (opt & OPT_v)
301     bb_error_msg("system does not support RLIMIT_%s",
302     "NPROC");
303 niro 532 #endif
304     }
305 niro 816 if (opt & OPT_f) {
306 niro 532 #ifdef RLIMIT_FSIZE
307     limit(RLIMIT_FSIZE, limitf);
308     #else
309 niro 816 if (opt & OPT_v)
310     bb_error_msg("system does not support RLIMIT_%s",
311     "FSIZE");
312 niro 532 #endif
313     }
314 niro 816 if (opt & OPT_c) {
315 niro 532 #ifdef RLIMIT_CORE
316     limit(RLIMIT_CORE, limitc);
317     #else
318 niro 816 if (opt & OPT_v)
319     bb_error_msg("system does not support RLIMIT_%s",
320     "CORE");
321 niro 532 #endif
322     }
323 niro 816 if (opt & OPT_r) {
324 niro 532 #ifdef RLIMIT_RSS
325     limit(RLIMIT_RSS, limitr);
326     #else
327 niro 816 if (opt & OPT_v)
328     bb_error_msg("system does not support RLIMIT_%s",
329     "RSS");
330 niro 532 #endif
331     }
332 niro 816 if (opt & OPT_t) {
333 niro 532 #ifdef RLIMIT_CPU
334     limit(RLIMIT_CPU, limitt);
335     #else
336 niro 816 if (opt & OPT_v)
337     bb_error_msg("system does not support RLIMIT_%s",
338     "CPU");
339 niro 532 #endif
340     }
341    
342 niro 816 if (opt & OPT_P)
343     setsid();
344 niro 532
345 niro 816 if (opt & OPT_e)
346     edir(env_dir);
347 niro 532
348 niro 816 // FIXME: chrooted jail must have /etc/passwd if we move this after chroot!
349     // OTOH chroot fails for non-roots!
350     // SOLUTION: cache uid/gid before chroot, apply uid/gid after
351     if (opt & OPT_U) {
352     xget_uidgid(&ugid, env_user);
353     xsetenv("GID", utoa(ugid.gid));
354     xsetenv("UID", utoa(ugid.uid));
355 niro 532 }
356    
357 niro 816 if (opt & OPT_u) {
358     xget_uidgid(&ugid, set_user);
359     }
360    
361     if (opt & OPT_root) {
362 niro 532 xchdir(root);
363 niro 816 xchroot(".");
364 niro 532 }
365 niro 816
366     if (opt & OPT_u) {
367     if (setgroups(1, &ugid.gid) == -1)
368     bb_perror_msg_and_die("setgroups");
369     xsetgid(ugid.gid);
370     xsetuid(ugid.uid);
371     }
372    
373     if (opt & OPT_n) {
374 niro 532 errno = 0;
375 niro 816 if (nice(xatoi(nicestr)) == -1)
376 niro 532 bb_perror_msg_and_die("nice");
377     }
378    
379 niro 816 if (opt & OPT_0)
380     close(STDIN_FILENO);
381     if (opt & OPT_1)
382     close(STDOUT_FILENO);
383     if (opt & OPT_2)
384     close(STDERR_FILENO);
385 niro 532
386 niro 816 BB_EXECVP(argv[0], argv);
387 niro 532 bb_perror_msg_and_die("exec %s", argv[0]);
388     }