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