builtins.c revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
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, char *options) 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, options); 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 175 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 193int do_insmod(int nargs, char **args) 194{ 195 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); 204} 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 355int 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 369int 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} 443