builtins.c revision 6310a8261c922533a692fb3e74ece2da98d4bafa
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#include <linux/loop.h> 33 34#include "init.h" 35#include "keywords.h" 36#include "property_service.h" 37#include "devices.h" 38#include "init_parser.h" 39#include "util.h" 40#include "log.h" 41 42#include <private/android_filesystem_config.h> 43 44void add_environment(const char *name, const char *value); 45 46extern int init_module(void *, unsigned long, const char *); 47 48static int write_file(const char *path, const char *value) 49{ 50 int fd, ret, len; 51 52 fd = open(path, O_WRONLY|O_CREAT, 0622); 53 54 if (fd < 0) 55 return -errno; 56 57 len = strlen(value); 58 59 do { 60 ret = write(fd, value, len); 61 } while (ret < 0 && errno == EINTR); 62 63 close(fd); 64 if (ret < 0) { 65 return -errno; 66 } else { 67 return 0; 68 } 69} 70 71static int insmod(const char *filename, char *options) 72{ 73 void *module; 74 unsigned size; 75 int ret; 76 77 module = read_file(filename, &size); 78 if (!module) 79 return -1; 80 81 ret = init_module(module, size, options); 82 83 free(module); 84 85 return ret; 86} 87 88static int setkey(struct kbentry *kbe) 89{ 90 int fd, ret; 91 92 fd = open("/dev/tty0", O_RDWR | O_SYNC); 93 if (fd < 0) 94 return -1; 95 96 ret = ioctl(fd, KDSKBENT, kbe); 97 98 close(fd); 99 return ret; 100} 101 102static int __ifupdown(const char *interface, int up) 103{ 104 struct ifreq ifr; 105 int s, ret; 106 107 strlcpy(ifr.ifr_name, interface, IFNAMSIZ); 108 109 s = socket(AF_INET, SOCK_DGRAM, 0); 110 if (s < 0) 111 return -1; 112 113 ret = ioctl(s, SIOCGIFFLAGS, &ifr); 114 if (ret < 0) { 115 goto done; 116 } 117 118 if (up) 119 ifr.ifr_flags |= IFF_UP; 120 else 121 ifr.ifr_flags &= ~IFF_UP; 122 123 ret = ioctl(s, SIOCSIFFLAGS, &ifr); 124 125done: 126 close(s); 127 return ret; 128} 129 130static void service_start_if_not_disabled(struct service *svc) 131{ 132 if (!(svc->flags & SVC_DISABLED)) { 133 service_start(svc, NULL); 134 } 135} 136 137int do_chdir(int nargs, char **args) 138{ 139 chdir(args[1]); 140 return 0; 141} 142 143int do_chroot(int nargs, char **args) 144{ 145 chroot(args[1]); 146 return 0; 147} 148 149int do_class_start(int nargs, char **args) 150{ 151 /* Starting a class does not start services 152 * which are explicitly disabled. They must 153 * be started individually. 154 */ 155 service_for_each_class(args[1], service_start_if_not_disabled); 156 return 0; 157} 158 159int do_class_stop(int nargs, char **args) 160{ 161 service_for_each_class(args[1], service_stop); 162 return 0; 163} 164 165int do_domainname(int nargs, char **args) 166{ 167 return write_file("/proc/sys/kernel/domainname", args[1]); 168} 169 170int do_exec(int nargs, char **args) 171{ 172 return -1; 173} 174 175int do_export(int nargs, char **args) 176{ 177 add_environment(args[1], args[2]); 178 return 0; 179} 180 181int do_hostname(int nargs, char **args) 182{ 183 return write_file("/proc/sys/kernel/hostname", args[1]); 184} 185 186int do_ifup(int nargs, char **args) 187{ 188 return __ifupdown(args[1], 1); 189} 190 191 192static int do_insmod_inner(int nargs, char **args, int opt_len) 193{ 194 char options[opt_len + 1]; 195 int i; 196 197 options[0] = '\0'; 198 if (nargs > 2) { 199 strcpy(options, args[2]); 200 for (i = 3; i < nargs; ++i) { 201 strcat(options, " "); 202 strcat(options, args[i]); 203 } 204 } 205 206 return insmod(args[1], options); 207} 208 209int do_insmod(int nargs, char **args) 210{ 211 int i; 212 int size = 0; 213 214 if (nargs > 2) { 215 for (i = 2; i < nargs; ++i) 216 size += strlen(args[i]) + 1; 217 } 218 219 return do_insmod_inner(nargs, args, size); 220} 221 222int do_import(int nargs, char **args) 223{ 224 return init_parse_config_file(args[1]); 225} 226 227int do_mkdir(int nargs, char **args) 228{ 229 mode_t mode = 0755; 230 231 /* mkdir <path> [mode] [owner] [group] */ 232 233 if (nargs >= 3) { 234 mode = strtoul(args[2], 0, 8); 235 } 236 237 if (mkdir(args[1], mode)) { 238 return -errno; 239 } 240 241 if (nargs >= 4) { 242 uid_t uid = decode_uid(args[3]); 243 gid_t gid = -1; 244 245 if (nargs == 5) { 246 gid = decode_uid(args[4]); 247 } 248 249 if (chown(args[1], uid, gid)) { 250 return -errno; 251 } 252 } 253 254 return 0; 255} 256 257static struct { 258 const char *name; 259 unsigned flag; 260} mount_flags[] = { 261 { "noatime", MS_NOATIME }, 262 { "nosuid", MS_NOSUID }, 263 { "nodev", MS_NODEV }, 264 { "nodiratime", MS_NODIRATIME }, 265 { "ro", MS_RDONLY }, 266 { "rw", 0 }, 267 { "remount", MS_REMOUNT }, 268 { "defaults", 0 }, 269 { 0, 0 }, 270}; 271 272/* mount <type> <device> <path> <flags ...> <options> */ 273int do_mount(int nargs, char **args) 274{ 275 char tmp[64]; 276 char *source, *target, *system; 277 char *options = NULL; 278 unsigned flags = 0; 279 int n, i; 280 int wait = 0; 281 282 for (n = 4; n < nargs; n++) { 283 for (i = 0; mount_flags[i].name; i++) { 284 if (!strcmp(args[n], mount_flags[i].name)) { 285 flags |= mount_flags[i].flag; 286 break; 287 } 288 } 289 290 if (!mount_flags[i].name) { 291 if (!strcmp(args[n], "wait")) 292 wait = 1; 293 /* if our last argument isn't a flag, wolf it up as an option string */ 294 else if (n + 1 == nargs) 295 options = args[n]; 296 } 297 } 298 299 system = args[1]; 300 source = args[2]; 301 target = args[3]; 302 303 if (!strncmp(source, "mtd@", 4)) { 304 n = mtd_name_to_number(source + 4); 305 if (n < 0) { 306 return -1; 307 } 308 309 sprintf(tmp, "/dev/block/mtdblock%d", n); 310 311 if (wait) 312 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT); 313 if (mount(tmp, target, system, flags, options) < 0) { 314 return -1; 315 } 316 317 return 0; 318 } else if (!strncmp(source, "loop@", 5)) { 319 int mode, loop, fd; 320 struct loop_info info; 321 322 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; 323 fd = open(source + 5, mode); 324 if (fd < 0) { 325 return -1; 326 } 327 328 for (n = 0; ; n++) { 329 sprintf(tmp, "/dev/block/loop%d", n); 330 loop = open(tmp, mode); 331 if (loop < 0) { 332 return -1; 333 } 334 335 /* if it is a blank loop device */ 336 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { 337 /* if it becomes our loop device */ 338 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { 339 close(fd); 340 341 if (mount(tmp, target, system, flags, options) < 0) { 342 ioctl(loop, LOOP_CLR_FD, 0); 343 close(loop); 344 return -1; 345 } 346 347 close(loop); 348 return 0; 349 } 350 } 351 352 close(loop); 353 } 354 355 close(fd); 356 ERROR("out of loopback devices"); 357 return -1; 358 } else { 359 if (wait) 360 wait_for_file(source, COMMAND_RETRY_TIMEOUT); 361 if (mount(source, target, system, flags, options) < 0) { 362 return -1; 363 } 364 365 return 0; 366 } 367} 368 369int do_setkey(int nargs, char **args) 370{ 371 struct kbentry kbe; 372 kbe.kb_table = strtoul(args[1], 0, 0); 373 kbe.kb_index = strtoul(args[2], 0, 0); 374 kbe.kb_value = strtoul(args[3], 0, 0); 375 return setkey(&kbe); 376} 377 378int do_setprop(int nargs, char **args) 379{ 380 property_set(args[1], args[2]); 381 return 0; 382} 383 384int do_setrlimit(int nargs, char **args) 385{ 386 struct rlimit limit; 387 int resource; 388 resource = atoi(args[1]); 389 limit.rlim_cur = atoi(args[2]); 390 limit.rlim_max = atoi(args[3]); 391 return setrlimit(resource, &limit); 392} 393 394int do_start(int nargs, char **args) 395{ 396 struct service *svc; 397 svc = service_find_by_name(args[1]); 398 if (svc) { 399 service_start(svc, NULL); 400 } 401 return 0; 402} 403 404int do_stop(int nargs, char **args) 405{ 406 struct service *svc; 407 svc = service_find_by_name(args[1]); 408 if (svc) { 409 service_stop(svc); 410 } 411 return 0; 412} 413 414int do_restart(int nargs, char **args) 415{ 416 struct service *svc; 417 svc = service_find_by_name(args[1]); 418 if (svc) { 419 service_stop(svc); 420 service_start(svc, NULL); 421 } 422 return 0; 423} 424 425int do_trigger(int nargs, char **args) 426{ 427 action_for_each_trigger(args[1], action_add_queue_tail); 428 return 0; 429} 430 431int do_symlink(int nargs, char **args) 432{ 433 return symlink(args[1], args[2]); 434} 435 436int do_sysclktz(int nargs, char **args) 437{ 438 struct timezone tz; 439 440 if (nargs != 2) 441 return -1; 442 443 memset(&tz, 0, sizeof(tz)); 444 tz.tz_minuteswest = atoi(args[1]); 445 if (settimeofday(NULL, &tz)) 446 return -1; 447 return 0; 448} 449 450int do_write(int nargs, char **args) 451{ 452 return write_file(args[1], args[2]); 453} 454 455int do_copy(int nargs, char **args) 456{ 457 char *buffer = NULL; 458 int rc = 0; 459 int fd1 = -1, fd2 = -1; 460 struct stat info; 461 int brtw, brtr; 462 char *p; 463 464 if (nargs != 3) 465 return -1; 466 467 if (stat(args[1], &info) < 0) 468 return -1; 469 470 if ((fd1 = open(args[1], O_RDONLY)) < 0) 471 goto out_err; 472 473 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0) 474 goto out_err; 475 476 if (!(buffer = malloc(info.st_size))) 477 goto out_err; 478 479 p = buffer; 480 brtr = info.st_size; 481 while(brtr) { 482 rc = read(fd1, p, brtr); 483 if (rc < 0) 484 goto out_err; 485 if (rc == 0) 486 break; 487 p += rc; 488 brtr -= rc; 489 } 490 491 p = buffer; 492 brtw = info.st_size; 493 while(brtw) { 494 rc = write(fd2, p, brtw); 495 if (rc < 0) 496 goto out_err; 497 if (rc == 0) 498 break; 499 p += rc; 500 brtw -= rc; 501 } 502 503 rc = 0; 504 goto out; 505out_err: 506 rc = -1; 507out: 508 if (buffer) 509 free(buffer); 510 if (fd1 >= 0) 511 close(fd1); 512 if (fd2 >= 0) 513 close(fd2); 514 return rc; 515} 516 517int do_chown(int nargs, char **args) { 518 /* GID is optional. */ 519 if (nargs == 3) { 520 if (chown(args[2], decode_uid(args[1]), -1) < 0) 521 return -errno; 522 } else if (nargs == 4) { 523 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2]))) 524 return -errno; 525 } else { 526 return -1; 527 } 528 return 0; 529} 530 531static mode_t get_mode(const char *s) { 532 mode_t mode = 0; 533 while (*s) { 534 if (*s >= '0' && *s <= '7') { 535 mode = (mode<<3) | (*s-'0'); 536 } else { 537 return -1; 538 } 539 s++; 540 } 541 return mode; 542} 543 544int do_chmod(int nargs, char **args) { 545 mode_t mode = get_mode(args[1]); 546 if (chmod(args[2], mode) < 0) { 547 return -errno; 548 } 549 return 0; 550} 551 552int do_loglevel(int nargs, char **args) { 553 if (nargs == 2) { 554 log_set_level(atoi(args[1])); 555 return 0; 556 } 557 return -1; 558} 559 560int do_device(int nargs, char **args) { 561 int len; 562 char tmp[64]; 563 char *source = args[1]; 564 int prefix = 0; 565 566 if (nargs != 5) 567 return -1; 568 /* Check for wildcard '*' at the end which indicates a prefix. */ 569 len = strlen(args[1]) - 1; 570 if (args[1][len] == '*') { 571 args[1][len] = '\0'; 572 prefix = 1; 573 } 574 /* If path starts with mtd@ lookup the mount number. */ 575 if (!strncmp(source, "mtd@", 4)) { 576 int n = mtd_name_to_number(source + 4); 577 if (n >= 0) { 578 snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n); 579 source = tmp; 580 } 581 } 582 add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]), 583 decode_uid(args[4]), prefix); 584 return 0; 585} 586 587int do_wait(int nargs, char **args) 588{ 589 if (nargs == 2) { 590 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT); 591 } 592 return -1; 593} 594