blob: bbee7b2d0486404043e3713eb862c0fa5e4fba1f [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <fcntl.h>
20#include <unistd.h>
21#include <string.h>
22#include <stdio.h>
23#include <linux/kd.h>
24#include <errno.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <linux/if.h>
28#include <arpa/inet.h>
29#include <stdlib.h>
30#include <sys/mount.h>
31#include <sys/resource.h>
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +000032#include <linux/loop.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070033
34#include "init.h"
35#include "keywords.h"
36#include "property_service.h"
37#include "devices.h"
38
39#include <private/android_filesystem_config.h>
40
41void add_environment(const char *name, const char *value);
42
43extern int init_module(void *, unsigned long, const char *);
44
45static int write_file(const char *path, const char *value)
46{
47 int fd, ret, len;
48
49 fd = open(path, O_WRONLY|O_CREAT, 0622);
50
51 if (fd < 0)
52 return -1;
53
54 len = strlen(value);
55
56 do {
57 ret = write(fd, value, len);
58 } while (ret < 0 && errno == EINTR);
59
60 close(fd);
61 if (ret < 0) {
62 return -1;
63 } else {
64 return 0;
65 }
66}
67
68static int insmod(const char *filename)
69{
70 void *module;
71 unsigned size;
72 int ret;
73
74 module = read_file(filename, &size);
75 if (!module)
76 return -1;
77
78 ret = init_module(module, size, "");
79
80 free(module);
81
82 return ret;
83}
84
85static int setkey(struct kbentry *kbe)
86{
87 int fd, ret;
88
89 fd = open("/dev/tty0", O_RDWR | O_SYNC);
90 if (fd < 0)
91 return -1;
92
93 ret = ioctl(fd, KDSKBENT, kbe);
94
95 close(fd);
96 return ret;
97}
98
99static int __ifupdown(const char *interface, int up)
100{
101 struct ifreq ifr;
102 int s, ret;
103
104 strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
105
106 s = socket(AF_INET, SOCK_DGRAM, 0);
107 if (s < 0)
108 return -1;
109
110 ret = ioctl(s, SIOCGIFFLAGS, &ifr);
111 if (ret < 0) {
112 goto done;
113 }
114
115 if (up)
116 ifr.ifr_flags |= IFF_UP;
117 else
118 ifr.ifr_flags &= ~IFF_UP;
119
120 ret = ioctl(s, SIOCSIFFLAGS, &ifr);
121
122done:
123 close(s);
124 return ret;
125}
126
127static void service_start_if_not_disabled(struct service *svc)
128{
129 if (!(svc->flags & SVC_DISABLED)) {
130 service_start(svc);
131 }
132}
133
134int do_class_start(int nargs, char **args)
135{
136 /* Starting a class does not start services
137 * which are explicitly disabled. They must
138 * be started individually.
139 */
140 service_for_each_class(args[1], service_start_if_not_disabled);
141 return 0;
142}
143
144int do_class_stop(int nargs, char **args)
145{
146 service_for_each_class(args[1], service_stop);
147 return 0;
148}
149
150int do_domainname(int nargs, char **args)
151{
152 return write_file("/proc/sys/kernel/domainname", args[1]);
153}
154
155int do_exec(int nargs, char **args)
156{
157 return -1;
158}
159
160int do_export(int nargs, char **args)
161{
162 add_environment(args[1], args[2]);
163 return 0;
164}
165
166int do_hostname(int nargs, char **args)
167{
168 return write_file("/proc/sys/kernel/hostname", args[1]);
169}
170
171int do_ifup(int nargs, char **args)
172{
173 return __ifupdown(args[1], 1);
174}
175
176int do_insmod(int nargs, char **args)
177{
178 return insmod(args[1]);
179}
180
181int do_import(int nargs, char **args)
182{
183 return -1;
184}
185
186int do_mkdir(int nargs, char **args)
187{
188 mode_t mode = 0755;
189
190 /* mkdir <path> [mode] [owner] [group] */
191
192 if (nargs >= 3) {
193 mode = strtoul(args[2], 0, 8);
194 }
195
196 if (mkdir(args[1], mode)) {
197 return -errno;
198 }
199
200 if (nargs >= 4) {
201 uid_t uid = decode_uid(args[3]);
202 gid_t gid = -1;
203
204 if (nargs == 5) {
205 gid = decode_uid(args[4]);
206 }
207
208 if (chown(args[1], uid, gid)) {
209 return -errno;
210 }
211 }
212
213 return 0;
214}
215
216static struct {
217 const char *name;
218 unsigned flag;
219} mount_flags[] = {
220 { "noatime", MS_NOATIME },
221 { "nosuid", MS_NOSUID },
222 { "nodev", MS_NODEV },
223 { "nodiratime", MS_NODIRATIME },
224 { "ro", MS_RDONLY },
225 { "rw", 0 },
226 { "remount", MS_REMOUNT },
227 { "defaults", 0 },
228 { 0, 0 },
229};
230
231/* mount <type> <device> <path> <flags ...> <options> */
232int do_mount(int nargs, char **args)
233{
234 char tmp[64];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000235 char *source, *target, *system;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700236 char *options = NULL;
237 unsigned flags = 0;
238 int n, i;
239
240 for (n = 4; n < nargs; n++) {
241 for (i = 0; mount_flags[i].name; i++) {
242 if (!strcmp(args[n], mount_flags[i].name)) {
243 flags |= mount_flags[i].flag;
244 break;
245 }
246 }
247
248 /* if our last argument isn't a flag, wolf it up as an option string */
249 if (n + 1 == nargs && !mount_flags[i].name)
250 options = args[n];
251 }
252
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000253 system = args[1];
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700254 source = args[2];
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000255 target = args[3];
256
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700257 if (!strncmp(source, "mtd@", 4)) {
258 n = mtd_name_to_number(source + 4);
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000259 if (n < 0) {
260 return -1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700261 }
Jay Freeman (saurik)e520d032008-11-20 03:37:30 +0000262
263 sprintf(tmp, "/dev/block/mtdblock%d", n);
264
265 if (mount(tmp, target, system, flags, options) < 0) {
266 return -1;
267 }
268
269 return 0;
270 } else if (!strncmp(source, "loop@", 5)) {
271 int mode, loop, fd;
272 struct loop_info info;
273
274 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
275 fd = open(source + 5, mode);
276 if (fd < 0) {
277 return -1;
278 }
279
280 for (n = 0; ; n++) {
281 sprintf(tmp, "/dev/block/loop%d", n);
282 loop = open(tmp, mode);
283 if (loop < 0) {
284 return -1;
285 }
286
287 /* if it is a blank loop device */
288 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
289 /* if it becomes our loop device */
290 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
291 close(fd);
292
293 if (mount(tmp, target, system, flags, options) < 0) {
294 ioctl(loop, LOOP_CLR_FD, 0);
295 close(loop);
296 return -1;
297 }
298
299 close(loop);
300 return 0;
301 }
302 }
303
304 close(loop);
305 }
306
307 close(fd);
308 ERROR("out of loopback devices");
309 return -1;
310 } else {
311 if (mount(source, target, system, flags, options) < 0) {
312 return -1;
313 }
314
315 return 0;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700316 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700317}
318
319int do_setkey(int nargs, char **args)
320{
321 struct kbentry kbe;
322 kbe.kb_table = strtoul(args[1], 0, 0);
323 kbe.kb_index = strtoul(args[2], 0, 0);
324 kbe.kb_value = strtoul(args[3], 0, 0);
325 return setkey(&kbe);
326}
327
328int do_setprop(int nargs, char **args)
329{
330 property_set(args[1], args[2]);
331 return 0;
332}
333
334int do_setrlimit(int nargs, char **args)
335{
336 struct rlimit limit;
337 int resource;
338 resource = atoi(args[1]);
339 limit.rlim_cur = atoi(args[2]);
340 limit.rlim_max = atoi(args[3]);
341 return setrlimit(resource, &limit);
342}
343
344int do_start(int nargs, char **args)
345{
346 struct service *svc;
347 svc = service_find_by_name(args[1]);
348 if (svc) {
349 service_start(svc);
350 }
351 return 0;
352}
353
354int do_stop(int nargs, char **args)
355{
356 struct service *svc;
357 svc = service_find_by_name(args[1]);
358 if (svc) {
359 service_stop(svc);
360 }
361 return 0;
362}
363
364int do_restart(int nargs, char **args)
365{
366 struct service *svc;
367 svc = service_find_by_name(args[1]);
368 if (svc) {
369 service_stop(svc);
370 service_start(svc);
371 }
372 return 0;
373}
374
375int do_trigger(int nargs, char **args)
376{
377 return 0;
378}
379
380int do_symlink(int nargs, char **args)
381{
382 return symlink(args[1], args[2]);
383}
384
385int do_write(int nargs, char **args)
386{
387 return write_file(args[1], args[2]);
388}
389
390int do_chown(int nargs, char **args) {
391 /* GID is optional. */
392 if (nargs == 3) {
393 if (chown(args[2], decode_uid(args[1]), -1) < 0)
394 return -errno;
395 } else if (nargs == 4) {
396 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
397 return -errno;
398 } else {
399 return -1;
400 }
401 return 0;
402}
403
404static mode_t get_mode(const char *s) {
405 mode_t mode = 0;
406 while (*s) {
407 if (*s >= '0' && *s <= '7') {
408 mode = (mode<<3) | (*s-'0');
409 } else {
410 return -1;
411 }
412 s++;
413 }
414 return mode;
415}
416
417int do_chmod(int nargs, char **args) {
418 mode_t mode = get_mode(args[1]);
419 if (chmod(args[2], mode) < 0) {
420 return -errno;
421 }
422 return 0;
423}
424
425int do_loglevel(int nargs, char **args) {
426 if (nargs == 2) {
427 log_set_level(atoi(args[1]));
428 return 0;
429 }
430 return -1;
431}
432
433int do_device(int nargs, char **args) {
434 int len;
435 char tmp[64];
436 char *source = args[1];
437 int prefix = 0;
438
439 if (nargs != 5)
440 return -1;
441 /* Check for wildcard '*' at the end which indicates a prefix. */
442 len = strlen(args[1]) - 1;
443 if (args[1][len] == '*') {
444 args[1][len] = '\0';
445 prefix = 1;
446 }
447 /* If path starts with mtd@ lookup the mount number. */
448 if (!strncmp(source, "mtd@", 4)) {
449 int n = mtd_name_to_number(source + 4);
450 if (n >= 0) {
451 snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
452 source = tmp;
453 }
454 }
455 add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
456 decode_uid(args[4]), prefix);
457 return 0;
458}