Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 984 - (show annotations) (download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 9838 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 /*
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 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 /* Dependencies on runit_lib.c removed */
30
31 #include "libbb.h"
32 #include <dirent.h>
33
34 /*
35 Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
36
37 Only softlimit and chpst are taking options:
38
39 # 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
62 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
67 envdir, envuidgid, setuidgid take no options, but they reuse code which
68 handles -e, -U and -u.
69 */
70
71 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
95 /* TODO: use recursive_action? */
96 static NOINLINE void edir(const char *directory_name)
97 {
98 int wdir;
99 DIR *dir;
100 struct dirent *d;
101 int fd;
102
103 wdir = xopen(".", O_RDONLY | O_NDELAY);
104 xchdir(directory_name);
105 dir = xopendir(".");
106 for (;;) {
107 char buf[256];
108 char *tail;
109 int size;
110
111 errno = 0;
112 d = readdir(dir);
113 if (!d) {
114 if (errno)
115 bb_perror_msg_and_die("readdir %s",
116 directory_name);
117 break;
118 }
119 if (d->d_name[0] == '.')
120 continue;
121 fd = open(d->d_name, O_RDONLY | O_NDELAY);
122 if (fd < 0) {
123 if ((errno == EISDIR) && directory_name) {
124 if (option_mask32 & OPT_v)
125 bb_perror_msg("warning: %s/%s is a directory",
126 directory_name, d->d_name);
127 continue;
128 } else
129 bb_perror_msg_and_die("open %s/%s",
130 directory_name, d->d_name);
131 }
132 size = full_read(fd, buf, sizeof(buf)-1);
133 close(fd);
134 if (size < 0)
135 bb_perror_msg_and_die("read %s/%s",
136 directory_name, d->d_name);
137 if (size == 0) {
138 unsetenv(d->d_name);
139 continue;
140 }
141 buf[size] = '\n';
142 tail = strchr(buf, '\n');
143 /* skip trailing whitespace */
144 while (1) {
145 *tail = '\0';
146 tail--;
147 if (tail < buf || !isspace(*tail))
148 break;
149 }
150 xsetenv(d->d_name, buf);
151 }
152 closedir(dir);
153 if (fchdir(wdir) == -1)
154 bb_perror_msg_and_die("fchdir");
155 close(wdir);
156 }
157
158 static void limit(int what, long l)
159 {
160 struct rlimit r;
161
162 /* Never fails under Linux (except if you pass it bad arguments) */
163 getrlimit(what, &r);
164 if ((l < 0) || (l > r.rlim_max))
165 r.rlim_cur = r.rlim_max;
166 else
167 r.rlim_cur = l;
168 if (setrlimit(what, &r) == -1)
169 bb_perror_msg_and_die("setrlimit");
170 }
171
172 int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
173 int chpst_main(int argc UNUSED_PARAM, char **argv)
174 {
175 struct bb_uidgid_t ugid;
176 char *set_user = set_user; /* for compiler */
177 char *env_user = env_user;
178 char *env_dir = env_dir;
179 char *root;
180 char *nicestr;
181 unsigned limita;
182 unsigned limitc;
183 unsigned limitd;
184 unsigned limitf;
185 unsigned limitl;
186 unsigned limitm;
187 unsigned limito;
188 unsigned limitp;
189 unsigned limitr;
190 unsigned limits;
191 unsigned limitt;
192 unsigned opt;
193
194 if ((ENABLE_CHPST && applet_name[0] == 'c')
195 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
196 ) {
197 // FIXME: can we live with int-sized limits?
198 // can we live with 40000 days?
199 // if yes -> getopt converts strings to numbers for us
200 opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
201 opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
202 IF_CHPST("/:n:vP012"),
203 &limita, &limitc, &limitd, &limitf, &limitl,
204 &limitm, &limito, &limitp, &limitr, &limits, &limitt,
205 &set_user, &env_user, &env_dir
206 IF_CHPST(, &root, &nicestr));
207 argv += optind;
208 if (opt & OPT_m) { // -m means -asld
209 limita = limits = limitl = limitd = limitm;
210 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
211 }
212 } else {
213 option_mask32 = opt = 0;
214 argv++;
215 if (!*argv)
216 bb_show_usage();
217 }
218
219 // envdir?
220 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
221 env_dir = *argv++;
222 opt |= OPT_e;
223 }
224
225 // setuidgid?
226 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
227 set_user = *argv++;
228 opt |= OPT_u;
229 }
230
231 // envuidgid?
232 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
233 env_user = *argv++;
234 opt |= OPT_U;
235 }
236
237 // we must have PROG [ARGS]
238 if (!*argv)
239 bb_show_usage();
240
241 // set limits
242 if (opt & OPT_d) {
243 #ifdef RLIMIT_DATA
244 limit(RLIMIT_DATA, limitd);
245 #else
246 if (opt & OPT_v)
247 bb_error_msg("system does not support RLIMIT_%s",
248 "DATA");
249 #endif
250 }
251 if (opt & OPT_s) {
252 #ifdef RLIMIT_STACK
253 limit(RLIMIT_STACK, limits);
254 #else
255 if (opt & OPT_v)
256 bb_error_msg("system does not support RLIMIT_%s",
257 "STACK");
258 #endif
259 }
260 if (opt & OPT_l) {
261 #ifdef RLIMIT_MEMLOCK
262 limit(RLIMIT_MEMLOCK, limitl);
263 #else
264 if (opt & OPT_v)
265 bb_error_msg("system does not support RLIMIT_%s",
266 "MEMLOCK");
267 #endif
268 }
269 if (opt & OPT_a) {
270 #ifdef RLIMIT_VMEM
271 limit(RLIMIT_VMEM, limita);
272 #else
273 #ifdef RLIMIT_AS
274 limit(RLIMIT_AS, limita);
275 #else
276 if (opt & OPT_v)
277 bb_error_msg("system does not support RLIMIT_%s",
278 "VMEM");
279 #endif
280 #endif
281 }
282 if (opt & OPT_o) {
283 #ifdef RLIMIT_NOFILE
284 limit(RLIMIT_NOFILE, limito);
285 #else
286 #ifdef RLIMIT_OFILE
287 limit(RLIMIT_OFILE, limito);
288 #else
289 if (opt & OPT_v)
290 bb_error_msg("system does not support RLIMIT_%s",
291 "NOFILE");
292 #endif
293 #endif
294 }
295 if (opt & OPT_p) {
296 #ifdef RLIMIT_NPROC
297 limit(RLIMIT_NPROC, limitp);
298 #else
299 if (opt & OPT_v)
300 bb_error_msg("system does not support RLIMIT_%s",
301 "NPROC");
302 #endif
303 }
304 if (opt & OPT_f) {
305 #ifdef RLIMIT_FSIZE
306 limit(RLIMIT_FSIZE, limitf);
307 #else
308 if (opt & OPT_v)
309 bb_error_msg("system does not support RLIMIT_%s",
310 "FSIZE");
311 #endif
312 }
313 if (opt & OPT_c) {
314 #ifdef RLIMIT_CORE
315 limit(RLIMIT_CORE, limitc);
316 #else
317 if (opt & OPT_v)
318 bb_error_msg("system does not support RLIMIT_%s",
319 "CORE");
320 #endif
321 }
322 if (opt & OPT_r) {
323 #ifdef RLIMIT_RSS
324 limit(RLIMIT_RSS, limitr);
325 #else
326 if (opt & OPT_v)
327 bb_error_msg("system does not support RLIMIT_%s",
328 "RSS");
329 #endif
330 }
331 if (opt & OPT_t) {
332 #ifdef RLIMIT_CPU
333 limit(RLIMIT_CPU, limitt);
334 #else
335 if (opt & OPT_v)
336 bb_error_msg("system does not support RLIMIT_%s",
337 "CPU");
338 #endif
339 }
340
341 if (opt & OPT_P)
342 setsid();
343
344 if (opt & OPT_e)
345 edir(env_dir);
346
347 // FIXME: chrooted jail must have /etc/passwd if we move this after chroot!
348 // OTOH chroot fails for non-roots!
349 // SOLUTION: cache uid/gid before chroot, apply uid/gid after
350 if (opt & OPT_U) {
351 xget_uidgid(&ugid, env_user);
352 xsetenv("GID", utoa(ugid.gid));
353 xsetenv("UID", utoa(ugid.uid));
354 }
355
356 if (opt & OPT_u) {
357 xget_uidgid(&ugid, set_user);
358 }
359
360 if (opt & OPT_root) {
361 xchdir(root);
362 xchroot(".");
363 }
364
365 if (opt & OPT_u) {
366 if (setgroups(1, &ugid.gid) == -1)
367 bb_perror_msg_and_die("setgroups");
368 xsetgid(ugid.gid);
369 xsetuid(ugid.uid);
370 }
371
372 if (opt & OPT_n) {
373 errno = 0;
374 if (nice(xatoi(nicestr)) == -1)
375 bb_perror_msg_and_die("nice");
376 }
377
378 if (opt & OPT_0)
379 close(STDIN_FILENO);
380 if (opt & OPT_1)
381 close(STDOUT_FILENO);
382 if (opt & OPT_2)
383 close(STDERR_FILENO);
384
385 BB_EXECVP(argv[0], argv);
386 bb_perror_msg_and_die("exec %s", argv[0]);
387 }