builtins.c revision 4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53
1/* 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} 403