blob: 95fb22304150b01027ec22faa174e6f93d55a72b [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>
32
33#include "init.h"
34#include "keywords.h"
35#include "property_service.h"
36#include "devices.h"
37
38#include <private/android_filesystem_config.h>
39
40void add_environment(const char *name, const char *value);
41
42extern int init_module(void *, unsigned long, const char *);
43
44static int write_file(const char *path, const char *value)
45{
46 int fd, ret, len;
47
48 fd = open(path, O_WRONLY|O_CREAT, 0622);
49
50 if (fd < 0)
51 return -1;
52
53 len = strlen(value);
54
55 do {
56 ret = write(fd, value, len);
57 } while (ret < 0 && errno == EINTR);
58
59 close(fd);
60 if (ret < 0) {
61 return -1;
62 } else {
63 return 0;
64 }
65}
66
The Android Open Source Project35237d12008-12-17 18:08:08 -080067static int insmod(const char *filename, char *options)
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070068{
69 void *module;
70 unsigned size;
71 int ret;
72
73 module = read_file(filename, &size);
74 if (!module)
75 return -1;
76
The Android Open Source Project35237d12008-12-17 18:08:08 -080077 ret = init_module(module, size, options);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070078
79 free(module);
80
81 return ret;
82}
83
84static int setkey(struct kbentry *kbe)
85{
86 int fd, ret;
87
88 fd = open("/dev/tty0", O_RDWR | O_SYNC);
89 if (fd < 0)
90 return -1;
91
92 ret = ioctl(fd, KDSKBENT, kbe);
93
94 close(fd);
95 return ret;
96}
97
98static int __ifupdown(const char *interface, int up)
99{
100 struct ifreq ifr;
101 int s, ret;
102
103 strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
104
105 s = socket(AF_INET, SOCK_DGRAM, 0);
106 if (s < 0)
107 return -1;
108
109 ret = ioctl(s, SIOCGIFFLAGS, &ifr);
110 if (ret < 0) {
111 goto done;
112 }
113
114 if (up)
115 ifr.ifr_flags |= IFF_UP;
116 else
117 ifr.ifr_flags &= ~IFF_UP;
118
119 ret = ioctl(s, SIOCSIFFLAGS, &ifr);
120
121done:
122 close(s);
123 return ret;
124}
125
126static void service_start_if_not_disabled(struct service *svc)
127{
128 if (!(svc->flags & SVC_DISABLED)) {
129 service_start(svc);
130 }
131}
132
133int do_class_start(int nargs, char **args)
134{
135 /* Starting a class does not start services
136 * which are explicitly disabled. They must
137 * be started individually.
138 */
139 service_for_each_class(args[1], service_start_if_not_disabled);
140 return 0;
141}
142
143int do_class_stop(int nargs, char **args)
144{
145 service_for_each_class(args[1], service_stop);
146 return 0;
147}
148
149int do_domainname(int nargs, char **args)
150{
151 return write_file("/proc/sys/kernel/domainname", args[1]);
152}
153
154int do_exec(int nargs, char **args)
155{
156 return -1;
157}
158
159int do_export(int nargs, char **args)
160{
161 add_environment(args[1], args[2]);
162 return 0;
163}
164
165int do_hostname(int nargs, char **args)
166{
167 return write_file("/proc/sys/kernel/hostname", args[1]);
168}
169
170int do_ifup(int nargs, char **args)
171{
172 return __ifupdown(args[1], 1);
173}
174
The Android Open Source Project35237d12008-12-17 18:08:08 -0800175
176static int do_insmod_inner(int nargs, char **args, int opt_len)
177{
178 char options[opt_len + 1];
179 int i;
180
181 options[0] = '\0';
182 if (nargs > 2) {
183 strcpy(options, args[2]);
184 for (i = 3; i < nargs; ++i) {
185 strcat(options, " ");
186 strcat(options, args[i]);
187 }
188 }
189
190 return insmod(args[1], options);
191}
192
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700193int do_insmod(int nargs, char **args)
194{
The Android Open Source Project35237d12008-12-17 18:08:08 -0800195 int i;
196 int size = 0;
197
198 if (nargs > 2) {
199 for (i = 2; i < nargs; ++i)
200 size += strlen(args[i]) + 1;
201 }
202
203 return do_insmod_inner(nargs, args, size);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700204}
205
206int do_import(int nargs, char **args)
207{
208 return -1;
209}
210
211int do_mkdir(int nargs, char **args)
212{
213 mode_t mode = 0755;
214
215 /* mkdir <path> [mode] [owner] [group] */
216
217 if (nargs >= 3) {
218 mode = strtoul(args[2], 0, 8);
219 }
220
221 if (mkdir(args[1], mode)) {
222 return -errno;
223 }
224
225 if (nargs >= 4) {
226 uid_t uid = decode_uid(args[3]);
227 gid_t gid = -1;
228
229 if (nargs == 5) {
230 gid = decode_uid(args[4]);
231 }
232
233 if (chown(args[1], uid, gid)) {
234 return -errno;
235 }
236 }
237
238 return 0;
239}
240
241static struct {
242 const char *name;
243 unsigned flag;
244} mount_flags[] = {
245 { "noatime", MS_NOATIME },
246 { "nosuid", MS_NOSUID },
247 { "nodev", MS_NODEV },
248 { "nodiratime", MS_NODIRATIME },
249 { "ro", MS_RDONLY },
250 { "rw", 0 },
251 { "remount", MS_REMOUNT },
252 { "defaults", 0 },
253 { 0, 0 },
254};
255
256/* mount <type> <device> <path> <flags ...> <options> */
257int do_mount(int nargs, char **args)
258{
259 char tmp[64];
260 char *source;
261 char *options = NULL;
262 unsigned flags = 0;
263 int n, i;
264
265 for (n = 4; n < nargs; n++) {
266 for (i = 0; mount_flags[i].name; i++) {
267 if (!strcmp(args[n], mount_flags[i].name)) {
268 flags |= mount_flags[i].flag;
269 break;
270 }
271 }
272
273 /* if our last argument isn't a flag, wolf it up as an option string */
274 if (n + 1 == nargs && !mount_flags[i].name)
275 options = args[n];
276 }
277
278 source = args[2];
279 if (!strncmp(source, "mtd@", 4)) {
280 n = mtd_name_to_number(source + 4);
281 if (n >= 0) {
282 sprintf(tmp, "/dev/block/mtdblock%d", n);
283 source = tmp;
284 }
285 }
286 return mount(source, args[3], args[1], flags, options);
287}
288
289int do_setkey(int nargs, char **args)
290{
291 struct kbentry kbe;
292 kbe.kb_table = strtoul(args[1], 0, 0);
293 kbe.kb_index = strtoul(args[2], 0, 0);
294 kbe.kb_value = strtoul(args[3], 0, 0);
295 return setkey(&kbe);
296}
297
298int do_setprop(int nargs, char **args)
299{
300 property_set(args[1], args[2]);
301 return 0;
302}
303
304int do_setrlimit(int nargs, char **args)
305{
306 struct rlimit limit;
307 int resource;
308 resource = atoi(args[1]);
309 limit.rlim_cur = atoi(args[2]);
310 limit.rlim_max = atoi(args[3]);
311 return setrlimit(resource, &limit);
312}
313
314int do_start(int nargs, char **args)
315{
316 struct service *svc;
317 svc = service_find_by_name(args[1]);
318 if (svc) {
319 service_start(svc);
320 }
321 return 0;
322}
323
324int do_stop(int nargs, char **args)
325{
326 struct service *svc;
327 svc = service_find_by_name(args[1]);
328 if (svc) {
329 service_stop(svc);
330 }
331 return 0;
332}
333
334int do_restart(int nargs, char **args)
335{
336 struct service *svc;
337 svc = service_find_by_name(args[1]);
338 if (svc) {
339 service_stop(svc);
340 service_start(svc);
341 }
342 return 0;
343}
344
345int do_trigger(int nargs, char **args)
346{
347 return 0;
348}
349
350int do_symlink(int nargs, char **args)
351{
352 return symlink(args[1], args[2]);
353}
354
The Android Open Source Project35237d12008-12-17 18:08:08 -0800355int do_sysclktz(int nargs, char **args)
356{
357 struct timezone tz;
358
359 if (nargs != 2)
360 return -1;
361
362 memset(&tz, 0, sizeof(tz));
363 tz.tz_minuteswest = atoi(args[1]);
364 if (settimeofday(NULL, &tz))
365 return -1;
366 return 0;
367}
368
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700369int do_write(int nargs, char **args)
370{
371 return write_file(args[1], args[2]);
372}
373
374int do_chown(int nargs, char **args) {
375 /* GID is optional. */
376 if (nargs == 3) {
377 if (chown(args[2], decode_uid(args[1]), -1) < 0)
378 return -errno;
379 } else if (nargs == 4) {
380 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
381 return -errno;
382 } else {
383 return -1;
384 }
385 return 0;
386}
387
388static mode_t get_mode(const char *s) {
389 mode_t mode = 0;
390 while (*s) {
391 if (*s >= '0' && *s <= '7') {
392 mode = (mode<<3) | (*s-'0');
393 } else {
394 return -1;
395 }
396 s++;
397 }
398 return mode;
399}
400
401int do_chmod(int nargs, char **args) {
402 mode_t mode = get_mode(args[1]);
403 if (chmod(args[2], mode) < 0) {
404 return -errno;
405 }
406 return 0;
407}
408
409int do_loglevel(int nargs, char **args) {
410 if (nargs == 2) {
411 log_set_level(atoi(args[1]));
412 return 0;
413 }
414 return -1;
415}
416
417int do_device(int nargs, char **args) {
418 int len;
419 char tmp[64];
420 char *source = args[1];
421 int prefix = 0;
422
423 if (nargs != 5)
424 return -1;
425 /* Check for wildcard '*' at the end which indicates a prefix. */
426 len = strlen(args[1]) - 1;
427 if (args[1][len] == '*') {
428 args[1][len] = '\0';
429 prefix = 1;
430 }
431 /* If path starts with mtd@ lookup the mount number. */
432 if (!strncmp(source, "mtd@", 4)) {
433 int n = mtd_name_to_number(source + 4);
434 if (n >= 0) {
435 snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
436 source = tmp;
437 }
438 }
439 add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
440 decode_uid(args[4]), prefix);
441 return 0;
442}