blob: ba344100c55a970ff8ecfe167e5086e971a3c453 [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
67static int insmod(const char *filename)
68{
69 void *module;
70 unsigned size;
71 int ret;
72
73 module = read_file(filename, &size);
74 if (!module)
75 return -1;
76
77 ret = init_module(module, size, "");
78
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
175int do_insmod(int nargs, char **args)
176{
177 return insmod(args[1]);
178}
179
180int do_import(int nargs, char **args)
181{
182 return -1;
183}
184
185int do_mkdir(int nargs, char **args)
186{
187 mode_t mode = 0755;
188
189 /* mkdir <path> [mode] [owner] [group] */
190
191 if (nargs >= 3) {
192 mode = strtoul(args[2], 0, 8);
193 }
194
195 if (mkdir(args[1], mode)) {
196 return -errno;
197 }
198
199 if (nargs >= 4) {
200 uid_t uid = decode_uid(args[3]);
201 gid_t gid = -1;
202
203 if (nargs == 5) {
204 gid = decode_uid(args[4]);
205 }
206
207 if (chown(args[1], uid, gid)) {
208 return -errno;
209 }
210 }
211
212 return 0;
213}
214
215static struct {
216 const char *name;
217 unsigned flag;
218} mount_flags[] = {
219 { "noatime", MS_NOATIME },
220 { "nosuid", MS_NOSUID },
221 { "nodev", MS_NODEV },
222 { "nodiratime", MS_NODIRATIME },
223 { "ro", MS_RDONLY },
224 { "rw", 0 },
225 { "remount", MS_REMOUNT },
226 { "defaults", 0 },
227 { 0, 0 },
228};
229
230/* mount <type> <device> <path> <flags ...> <options> */
231int do_mount(int nargs, char **args)
232{
233 char tmp[64];
234 char *source;
235 char *options = NULL;
236 unsigned flags = 0;
237 int n, i;
238
239 for (n = 4; n < nargs; n++) {
240 for (i = 0; mount_flags[i].name; i++) {
241 if (!strcmp(args[n], mount_flags[i].name)) {
242 flags |= mount_flags[i].flag;
243 break;
244 }
245 }
246
247 /* if our last argument isn't a flag, wolf it up as an option string */
248 if (n + 1 == nargs && !mount_flags[i].name)
249 options = args[n];
250 }
251
252 source = args[2];
253 if (!strncmp(source, "mtd@", 4)) {
254 n = mtd_name_to_number(source + 4);
255 if (n >= 0) {
256 sprintf(tmp, "/dev/block/mtdblock%d", n);
257 source = tmp;
258 }
259 }
260 return mount(source, args[3], args[1], flags, options);
261}
262
263int do_setkey(int nargs, char **args)
264{
265 struct kbentry kbe;
266 kbe.kb_table = strtoul(args[1], 0, 0);
267 kbe.kb_index = strtoul(args[2], 0, 0);
268 kbe.kb_value = strtoul(args[3], 0, 0);
269 return setkey(&kbe);
270}
271
272int do_setprop(int nargs, char **args)
273{
274 property_set(args[1], args[2]);
275 return 0;
276}
277
278int do_setrlimit(int nargs, char **args)
279{
280 struct rlimit limit;
281 int resource;
282 resource = atoi(args[1]);
283 limit.rlim_cur = atoi(args[2]);
284 limit.rlim_max = atoi(args[3]);
285 return setrlimit(resource, &limit);
286}
287
288int do_start(int nargs, char **args)
289{
290 struct service *svc;
291 svc = service_find_by_name(args[1]);
292 if (svc) {
293 service_start(svc);
294 }
295 return 0;
296}
297
298int do_stop(int nargs, char **args)
299{
300 struct service *svc;
301 svc = service_find_by_name(args[1]);
302 if (svc) {
303 service_stop(svc);
304 }
305 return 0;
306}
307
308int do_restart(int nargs, char **args)
309{
310 struct service *svc;
311 svc = service_find_by_name(args[1]);
312 if (svc) {
313 service_stop(svc);
314 service_start(svc);
315 }
316 return 0;
317}
318
319int do_trigger(int nargs, char **args)
320{
321 return 0;
322}
323
324int do_symlink(int nargs, char **args)
325{
326 return symlink(args[1], args[2]);
327}
328
329int do_write(int nargs, char **args)
330{
331 return write_file(args[1], args[2]);
332}
333
334int do_chown(int nargs, char **args) {
335 /* GID is optional. */
336 if (nargs == 3) {
337 if (chown(args[2], decode_uid(args[1]), -1) < 0)
338 return -errno;
339 } else if (nargs == 4) {
340 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
341 return -errno;
342 } else {
343 return -1;
344 }
345 return 0;
346}
347
348static mode_t get_mode(const char *s) {
349 mode_t mode = 0;
350 while (*s) {
351 if (*s >= '0' && *s <= '7') {
352 mode = (mode<<3) | (*s-'0');
353 } else {
354 return -1;
355 }
356 s++;
357 }
358 return mode;
359}
360
361int do_chmod(int nargs, char **args) {
362 mode_t mode = get_mode(args[1]);
363 if (chmod(args[2], mode) < 0) {
364 return -errno;
365 }
366 return 0;
367}
368
369int do_loglevel(int nargs, char **args) {
370 if (nargs == 2) {
371 log_set_level(atoi(args[1]));
372 return 0;
373 }
374 return -1;
375}
376
377int do_device(int nargs, char **args) {
378 int len;
379 char tmp[64];
380 char *source = args[1];
381 int prefix = 0;
382
383 if (nargs != 5)
384 return -1;
385 /* Check for wildcard '*' at the end which indicates a prefix. */
386 len = strlen(args[1]) - 1;
387 if (args[1][len] == '*') {
388 args[1][len] = '\0';
389 prefix = 1;
390 }
391 /* If path starts with mtd@ lookup the mount number. */
392 if (!strncmp(source, "mtd@", 4)) {
393 int n = mtd_name_to_number(source + 4);
394 if (n >= 0) {
395 snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
396 source = tmp;
397 }
398 }
399 add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
400 decode_uid(args[4]), prefix);
401 return 0;
402}