builtins.c revision e46f9d510db9351682cf17c49115110870147335
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#include <cutils/partition_utils.h> 34#include <sys/system_properties.h> 35 36#ifdef HAVE_SELINUX 37#include <selinux/selinux.h> 38#include <selinux/label.h> 39#endif 40 41#include "init.h" 42#include "keywords.h" 43#include "property_service.h" 44#include "devices.h" 45#include "init_parser.h" 46#include "util.h" 47#include "log.h" 48 49#include <private/android_filesystem_config.h> 50 51void add_environment(const char *name, const char *value); 52 53extern int init_module(void *, unsigned long, const char *); 54 55static int write_file(const char *path, const char *value) 56{ 57 int fd, ret, len; 58 59 fd = open(path, O_WRONLY|O_CREAT, 0622); 60 61 if (fd < 0) 62 return -errno; 63 64 len = strlen(value); 65 66 do { 67 ret = write(fd, value, len); 68 } while (ret < 0 && errno == EINTR); 69 70 close(fd); 71 if (ret < 0) { 72 return -errno; 73 } else { 74 return 0; 75 } 76} 77 78static int insmod(const char *filename, char *options) 79{ 80 void *module; 81 unsigned size; 82 int ret; 83 84 module = read_file(filename, &size); 85 if (!module) 86 return -1; 87 88 ret = init_module(module, size, options); 89 90 free(module); 91 92 return ret; 93} 94 95static int setkey(struct kbentry *kbe) 96{ 97 int fd, ret; 98 99 fd = open("/dev/tty0", O_RDWR | O_SYNC); 100 if (fd < 0) 101 return -1; 102 103 ret = ioctl(fd, KDSKBENT, kbe); 104 105 close(fd); 106 return ret; 107} 108 109static int __ifupdown(const char *interface, int up) 110{ 111 struct ifreq ifr; 112 int s, ret; 113 114 strlcpy(ifr.ifr_name, interface, IFNAMSIZ); 115 116 s = socket(AF_INET, SOCK_DGRAM, 0); 117 if (s < 0) 118 return -1; 119 120 ret = ioctl(s, SIOCGIFFLAGS, &ifr); 121 if (ret < 0) { 122 goto done; 123 } 124 125 if (up) 126 ifr.ifr_flags |= IFF_UP; 127 else 128 ifr.ifr_flags &= ~IFF_UP; 129 130 ret = ioctl(s, SIOCSIFFLAGS, &ifr); 131 132done: 133 close(s); 134 return ret; 135} 136 137static void service_start_if_not_disabled(struct service *svc) 138{ 139 if (!(svc->flags & SVC_DISABLED)) { 140 service_start(svc, NULL); 141 } 142} 143 144int do_chdir(int nargs, char **args) 145{ 146 chdir(args[1]); 147 return 0; 148} 149 150int do_chroot(int nargs, char **args) 151{ 152 chroot(args[1]); 153 return 0; 154} 155 156int do_class_start(int nargs, char **args) 157{ 158 /* Starting a class does not start services 159 * which are explicitly disabled. They must 160 * be started individually. 161 */ 162 service_for_each_class(args[1], service_start_if_not_disabled); 163 return 0; 164} 165 166int do_class_stop(int nargs, char **args) 167{ 168 service_for_each_class(args[1], service_stop); 169 return 0; 170} 171 172int do_class_reset(int nargs, char **args) 173{ 174 service_for_each_class(args[1], service_reset); 175 return 0; 176} 177 178int do_domainname(int nargs, char **args) 179{ 180 return write_file("/proc/sys/kernel/domainname", args[1]); 181} 182 183int do_exec(int nargs, char **args) 184{ 185 return -1; 186} 187 188int do_export(int nargs, char **args) 189{ 190 add_environment(args[1], args[2]); 191 return 0; 192} 193 194int do_hostname(int nargs, char **args) 195{ 196 return write_file("/proc/sys/kernel/hostname", args[1]); 197} 198 199int do_ifup(int nargs, char **args) 200{ 201 return __ifupdown(args[1], 1); 202} 203 204 205static int do_insmod_inner(int nargs, char **args, int opt_len) 206{ 207 char options[opt_len + 1]; 208 int i; 209 210 options[0] = '\0'; 211 if (nargs > 2) { 212 strcpy(options, args[2]); 213 for (i = 3; i < nargs; ++i) { 214 strcat(options, " "); 215 strcat(options, args[i]); 216 } 217 } 218 219 return insmod(args[1], options); 220} 221 222int do_insmod(int nargs, char **args) 223{ 224 int i; 225 int size = 0; 226 227 if (nargs > 2) { 228 for (i = 2; i < nargs; ++i) 229 size += strlen(args[i]) + 1; 230 } 231 232 return do_insmod_inner(nargs, args, size); 233} 234 235int do_mkdir(int nargs, char **args) 236{ 237 mode_t mode = 0755; 238 int ret; 239 240 /* mkdir <path> [mode] [owner] [group] */ 241 242 if (nargs >= 3) { 243 mode = strtoul(args[2], 0, 8); 244 } 245 246 ret = mkdir(args[1], mode); 247 /* chmod in case the directory already exists */ 248 if (ret == -1 && errno == EEXIST) { 249 ret = chmod(args[1], mode); 250 } 251 if (ret == -1) { 252 return -errno; 253 } 254 255 if (nargs >= 4) { 256 uid_t uid = decode_uid(args[3]); 257 gid_t gid = -1; 258 259 if (nargs == 5) { 260 gid = decode_uid(args[4]); 261 } 262 263 if (chown(args[1], uid, gid)) { 264 return -errno; 265 } 266 } 267 268 return 0; 269} 270 271static struct { 272 const char *name; 273 unsigned flag; 274} mount_flags[] = { 275 { "noatime", MS_NOATIME }, 276 { "nosuid", MS_NOSUID }, 277 { "nodev", MS_NODEV }, 278 { "nodiratime", MS_NODIRATIME }, 279 { "ro", MS_RDONLY }, 280 { "rw", 0 }, 281 { "remount", MS_REMOUNT }, 282 { "defaults", 0 }, 283 { 0, 0 }, 284}; 285 286#define DATA_MNT_POINT "/data" 287 288/* mount <type> <device> <path> <flags ...> <options> */ 289int do_mount(int nargs, char **args) 290{ 291 char tmp[64]; 292 char *source, *target, *system; 293 char *options = NULL; 294 unsigned flags = 0; 295 int n, i; 296 int wait = 0; 297 298 for (n = 4; n < nargs; n++) { 299 for (i = 0; mount_flags[i].name; i++) { 300 if (!strcmp(args[n], mount_flags[i].name)) { 301 flags |= mount_flags[i].flag; 302 break; 303 } 304 } 305 306 if (!mount_flags[i].name) { 307 if (!strcmp(args[n], "wait")) 308 wait = 1; 309 /* if our last argument isn't a flag, wolf it up as an option string */ 310 else if (n + 1 == nargs) 311 options = args[n]; 312 } 313 } 314 315 system = args[1]; 316 source = args[2]; 317 target = args[3]; 318 319 if (!strncmp(source, "mtd@", 4)) { 320 n = mtd_name_to_number(source + 4); 321 if (n < 0) { 322 return -1; 323 } 324 325 sprintf(tmp, "/dev/block/mtdblock%d", n); 326 327 if (wait) 328 wait_for_file(tmp, COMMAND_RETRY_TIMEOUT); 329 if (mount(tmp, target, system, flags, options) < 0) { 330 return -1; 331 } 332 333 goto exit_success; 334 } else if (!strncmp(source, "loop@", 5)) { 335 int mode, loop, fd; 336 struct loop_info info; 337 338 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; 339 fd = open(source + 5, mode); 340 if (fd < 0) { 341 return -1; 342 } 343 344 for (n = 0; ; n++) { 345 sprintf(tmp, "/dev/block/loop%d", n); 346 loop = open(tmp, mode); 347 if (loop < 0) { 348 return -1; 349 } 350 351 /* if it is a blank loop device */ 352 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { 353 /* if it becomes our loop device */ 354 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { 355 close(fd); 356 357 if (mount(tmp, target, system, flags, options) < 0) { 358 ioctl(loop, LOOP_CLR_FD, 0); 359 close(loop); 360 return -1; 361 } 362 363 close(loop); 364 goto exit_success; 365 } 366 } 367 368 close(loop); 369 } 370 371 close(fd); 372 ERROR("out of loopback devices"); 373 return -1; 374 } else { 375 if (wait) 376 wait_for_file(source, COMMAND_RETRY_TIMEOUT); 377 if (mount(source, target, system, flags, options) < 0) { 378 /* If this fails, it may be an encrypted filesystem 379 * or it could just be wiped. If wiped, that will be 380 * handled later in the boot process. 381 * We only support encrypting /data. Check 382 * if we're trying to mount it, and if so, 383 * assume it's encrypted, mount a tmpfs instead. 384 * Then save the orig mount parms in properties 385 * for vold to query when it mounts the real 386 * encrypted /data. 387 */ 388 if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) { 389 const char *tmpfs_options; 390 391 tmpfs_options = property_get("ro.crypto.tmpfs_options"); 392 393 if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV, 394 tmpfs_options) < 0) { 395 return -1; 396 } 397 398 /* Set the property that triggers the framework to do a minimal 399 * startup and ask the user for a password 400 */ 401 property_set("ro.crypto.state", "encrypted"); 402 property_set("vold.decrypt", "1"); 403 } else { 404 return -1; 405 } 406 } 407 408 if (!strcmp(target, DATA_MNT_POINT)) { 409 char fs_flags[32]; 410 411 /* Save the original mount options */ 412 property_set("ro.crypto.fs_type", system); 413 property_set("ro.crypto.fs_real_blkdev", source); 414 property_set("ro.crypto.fs_mnt_point", target); 415 if (options) { 416 property_set("ro.crypto.fs_options", options); 417 } 418 snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags); 419 property_set("ro.crypto.fs_flags", fs_flags); 420 } 421 } 422 423exit_success: 424 /* If not running encrypted, then set the property saying we are 425 * unencrypted, and also trigger the action for a nonencrypted system. 426 */ 427 if (!strcmp(target, DATA_MNT_POINT)) { 428 const char *prop; 429 430 prop = property_get("ro.crypto.state"); 431 if (! prop) { 432 prop = "notset"; 433 } 434 if (strcmp(prop, "encrypted")) { 435 property_set("ro.crypto.state", "unencrypted"); 436 action_for_each_trigger("nonencrypted", action_add_queue_tail); 437 } 438 } 439 440 return 0; 441 442} 443 444int do_setcon(int nargs, char **args) { 445#ifdef HAVE_SELINUX 446 if (is_selinux_enabled() <= 0) 447 return 0; 448 if (setcon(args[1]) < 0) { 449 return -errno; 450 } 451#endif 452 return 0; 453} 454 455int do_setenforce(int nargs, char **args) { 456#ifdef HAVE_SELINUX 457 if (is_selinux_enabled() <= 0) 458 return 0; 459 if (security_setenforce(atoi(args[1])) < 0) { 460 return -errno; 461 } 462#endif 463 return 0; 464} 465 466int do_setkey(int nargs, char **args) 467{ 468 struct kbentry kbe; 469 kbe.kb_table = strtoul(args[1], 0, 0); 470 kbe.kb_index = strtoul(args[2], 0, 0); 471 kbe.kb_value = strtoul(args[3], 0, 0); 472 return setkey(&kbe); 473} 474 475int do_setprop(int nargs, char **args) 476{ 477 const char *name = args[1]; 478 const char *value = args[2]; 479 char prop_val[PROP_VALUE_MAX]; 480 int ret; 481 482 ret = expand_props(prop_val, value, sizeof(prop_val)); 483 if (ret) { 484 ERROR("cannot expand '%s' while assigning to '%s'\n", value, name); 485 return -EINVAL; 486 } 487 property_set(name, prop_val); 488 return 0; 489} 490 491int do_setrlimit(int nargs, char **args) 492{ 493 struct rlimit limit; 494 int resource; 495 resource = atoi(args[1]); 496 limit.rlim_cur = atoi(args[2]); 497 limit.rlim_max = atoi(args[3]); 498 return setrlimit(resource, &limit); 499} 500 501int do_start(int nargs, char **args) 502{ 503 struct service *svc; 504 svc = service_find_by_name(args[1]); 505 if (svc) { 506 service_start(svc, NULL); 507 } 508 return 0; 509} 510 511int do_stop(int nargs, char **args) 512{ 513 struct service *svc; 514 svc = service_find_by_name(args[1]); 515 if (svc) { 516 service_stop(svc); 517 } 518 return 0; 519} 520 521int do_restart(int nargs, char **args) 522{ 523 struct service *svc; 524 svc = service_find_by_name(args[1]); 525 if (svc) { 526 service_stop(svc); 527 service_start(svc, NULL); 528 } 529 return 0; 530} 531 532int do_trigger(int nargs, char **args) 533{ 534 action_for_each_trigger(args[1], action_add_queue_tail); 535 return 0; 536} 537 538int do_symlink(int nargs, char **args) 539{ 540 return symlink(args[1], args[2]); 541} 542 543int do_rm(int nargs, char **args) 544{ 545 return unlink(args[1]); 546} 547 548int do_rmdir(int nargs, char **args) 549{ 550 return rmdir(args[1]); 551} 552 553int do_sysclktz(int nargs, char **args) 554{ 555 struct timezone tz; 556 557 if (nargs != 2) 558 return -1; 559 560 memset(&tz, 0, sizeof(tz)); 561 tz.tz_minuteswest = atoi(args[1]); 562 if (settimeofday(NULL, &tz)) 563 return -1; 564 return 0; 565} 566 567int do_write(int nargs, char **args) 568{ 569 const char *path = args[1]; 570 const char *value = args[2]; 571 char prop_val[PROP_VALUE_MAX]; 572 int ret; 573 574 ret = expand_props(prop_val, value, sizeof(prop_val)); 575 if (ret) { 576 ERROR("cannot expand '%s' while writing to '%s'\n", value, path); 577 return -EINVAL; 578 } 579 return write_file(path, prop_val); 580} 581 582int do_copy(int nargs, char **args) 583{ 584 char *buffer = NULL; 585 int rc = 0; 586 int fd1 = -1, fd2 = -1; 587 struct stat info; 588 int brtw, brtr; 589 char *p; 590 591 if (nargs != 3) 592 return -1; 593 594 if (stat(args[1], &info) < 0) 595 return -1; 596 597 if ((fd1 = open(args[1], O_RDONLY)) < 0) 598 goto out_err; 599 600 if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0) 601 goto out_err; 602 603 if (!(buffer = malloc(info.st_size))) 604 goto out_err; 605 606 p = buffer; 607 brtr = info.st_size; 608 while(brtr) { 609 rc = read(fd1, p, brtr); 610 if (rc < 0) 611 goto out_err; 612 if (rc == 0) 613 break; 614 p += rc; 615 brtr -= rc; 616 } 617 618 p = buffer; 619 brtw = info.st_size; 620 while(brtw) { 621 rc = write(fd2, p, brtw); 622 if (rc < 0) 623 goto out_err; 624 if (rc == 0) 625 break; 626 p += rc; 627 brtw -= rc; 628 } 629 630 rc = 0; 631 goto out; 632out_err: 633 rc = -1; 634out: 635 if (buffer) 636 free(buffer); 637 if (fd1 >= 0) 638 close(fd1); 639 if (fd2 >= 0) 640 close(fd2); 641 return rc; 642} 643 644int do_chown(int nargs, char **args) { 645 /* GID is optional. */ 646 if (nargs == 3) { 647 if (chown(args[2], decode_uid(args[1]), -1) < 0) 648 return -errno; 649 } else if (nargs == 4) { 650 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2]))) 651 return -errno; 652 } else { 653 return -1; 654 } 655 return 0; 656} 657 658static mode_t get_mode(const char *s) { 659 mode_t mode = 0; 660 while (*s) { 661 if (*s >= '0' && *s <= '7') { 662 mode = (mode<<3) | (*s-'0'); 663 } else { 664 return -1; 665 } 666 s++; 667 } 668 return mode; 669} 670 671int do_chmod(int nargs, char **args) { 672 mode_t mode = get_mode(args[1]); 673 if (chmod(args[2], mode) < 0) { 674 return -errno; 675 } 676 return 0; 677} 678 679int do_restorecon(int nargs, char **args) { 680#ifdef HAVE_SELINUX 681 char *secontext = NULL; 682 struct stat sb; 683 int i; 684 685 if (is_selinux_enabled() <= 0 || !sehandle) 686 return 0; 687 688 for (i = 1; i < nargs; i++) { 689 if (lstat(args[i], &sb) < 0) 690 return -errno; 691 if (selabel_lookup(sehandle, &secontext, args[i], sb.st_mode) < 0) 692 return -errno; 693 if (lsetfilecon(args[i], secontext) < 0) { 694 freecon(secontext); 695 return -errno; 696 } 697 freecon(secontext); 698 } 699#endif 700 return 0; 701} 702 703int do_setsebool(int nargs, char **args) { 704#ifdef HAVE_SELINUX 705 SELboolean *b = alloca(nargs * sizeof(SELboolean)); 706 char *v; 707 int i; 708 709 if (is_selinux_enabled() <= 0) 710 return 0; 711 712 for (i = 1; i < nargs; i++) { 713 char *name = args[i]; 714 v = strchr(name, '='); 715 if (!v) { 716 ERROR("setsebool: argument %s had no =\n", name); 717 return -EINVAL; 718 } 719 *v++ = 0; 720 b[i-1].name = name; 721 if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on")) 722 b[i-1].value = 1; 723 else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off")) 724 b[i-1].value = 0; 725 else { 726 ERROR("setsebool: invalid value %s\n", v); 727 return -EINVAL; 728 } 729 } 730 731 if (security_set_boolean_list(nargs - 1, b, 0) < 0) 732 return -errno; 733#endif 734 return 0; 735} 736 737int do_loglevel(int nargs, char **args) { 738 if (nargs == 2) { 739 klog_set_level(atoi(args[1])); 740 return 0; 741 } 742 return -1; 743} 744 745int do_load_persist_props(int nargs, char **args) { 746 if (nargs == 1) { 747 load_persist_props(); 748 return 0; 749 } 750 return -1; 751} 752 753int do_wait(int nargs, char **args) 754{ 755 if (nargs == 2) { 756 return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT); 757 } 758 return -1; 759} 760