builtins.c revision e520d036165b36cf5c4cb305f9cec7d183977b61
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 39#include <private/android_filesystem_config.h> 40 41void add_environment(const char *name, const char *value); 42 43extern int init_module(void *, unsigned long, const char *); 44 45static int write_file(const char *path, const char *value) 46{ 47 int fd, ret, len; 48 49 fd = open(path, O_WRONLY|O_CREAT, 0622); 50 51 if (fd < 0) 52 return -1; 53 54 len = strlen(value); 55 56 do { 57 ret = write(fd, value, len); 58 } while (ret < 0 && errno == EINTR); 59 60 close(fd); 61 if (ret < 0) { 62 return -1; 63 } else { 64 return 0; 65 } 66} 67 68static int insmod(const char *filename) 69{ 70 void *module; 71 unsigned size; 72 int ret; 73 74 module = read_file(filename, &size); 75 if (!module) 76 return -1; 77 78 ret = init_module(module, size, ""); 79 80 free(module); 81 82 return ret; 83} 84 85static int setkey(struct kbentry *kbe) 86{ 87 int fd, ret; 88 89 fd = open("/dev/tty0", O_RDWR | O_SYNC); 90 if (fd < 0) 91 return -1; 92 93 ret = ioctl(fd, KDSKBENT, kbe); 94 95 close(fd); 96 return ret; 97} 98 99static int __ifupdown(const char *interface, int up) 100{ 101 struct ifreq ifr; 102 int s, ret; 103 104 strlcpy(ifr.ifr_name, interface, IFNAMSIZ); 105 106 s = socket(AF_INET, SOCK_DGRAM, 0); 107 if (s < 0) 108 return -1; 109 110 ret = ioctl(s, SIOCGIFFLAGS, &ifr); 111 if (ret < 0) { 112 goto done; 113 } 114 115 if (up) 116 ifr.ifr_flags |= IFF_UP; 117 else 118 ifr.ifr_flags &= ~IFF_UP; 119 120 ret = ioctl(s, SIOCSIFFLAGS, &ifr); 121 122done: 123 close(s); 124 return ret; 125} 126 127static void service_start_if_not_disabled(struct service *svc) 128{ 129 if (!(svc->flags & SVC_DISABLED)) { 130 service_start(svc); 131 } 132} 133 134int do_class_start(int nargs, char **args) 135{ 136 /* Starting a class does not start services 137 * which are explicitly disabled. They must 138 * be started individually. 139 */ 140 service_for_each_class(args[1], service_start_if_not_disabled); 141 return 0; 142} 143 144int do_class_stop(int nargs, char **args) 145{ 146 service_for_each_class(args[1], service_stop); 147 return 0; 148} 149 150int do_domainname(int nargs, char **args) 151{ 152 return write_file("/proc/sys/kernel/domainname", args[1]); 153} 154 155int do_exec(int nargs, char **args) 156{ 157 return -1; 158} 159 160int do_export(int nargs, char **args) 161{ 162 add_environment(args[1], args[2]); 163 return 0; 164} 165 166int do_hostname(int nargs, char **args) 167{ 168 return write_file("/proc/sys/kernel/hostname", args[1]); 169} 170 171int do_ifup(int nargs, char **args) 172{ 173 return __ifupdown(args[1], 1); 174} 175 176int do_insmod(int nargs, char **args) 177{ 178 return insmod(args[1]); 179} 180 181int do_import(int nargs, char **args) 182{ 183 return -1; 184} 185 186int do_mkdir(int nargs, char **args) 187{ 188 mode_t mode = 0755; 189 190 /* mkdir <path> [mode] [owner] [group] */ 191 192 if (nargs >= 3) { 193 mode = strtoul(args[2], 0, 8); 194 } 195 196 if (mkdir(args[1], mode)) { 197 return -errno; 198 } 199 200 if (nargs >= 4) { 201 uid_t uid = decode_uid(args[3]); 202 gid_t gid = -1; 203 204 if (nargs == 5) { 205 gid = decode_uid(args[4]); 206 } 207 208 if (chown(args[1], uid, gid)) { 209 return -errno; 210 } 211 } 212 213 return 0; 214} 215 216static struct { 217 const char *name; 218 unsigned flag; 219} mount_flags[] = { 220 { "noatime", MS_NOATIME }, 221 { "nosuid", MS_NOSUID }, 222 { "nodev", MS_NODEV }, 223 { "nodiratime", MS_NODIRATIME }, 224 { "ro", MS_RDONLY }, 225 { "rw", 0 }, 226 { "remount", MS_REMOUNT }, 227 { "defaults", 0 }, 228 { 0, 0 }, 229}; 230 231/* mount <type> <device> <path> <flags ...> <options> */ 232int do_mount(int nargs, char **args) 233{ 234 char tmp[64]; 235 char *source, *target, *system; 236 char *options = NULL; 237 unsigned flags = 0; 238 int n, i; 239 240 for (n = 4; n < nargs; n++) { 241 for (i = 0; mount_flags[i].name; i++) { 242 if (!strcmp(args[n], mount_flags[i].name)) { 243 flags |= mount_flags[i].flag; 244 break; 245 } 246 } 247 248 /* if our last argument isn't a flag, wolf it up as an option string */ 249 if (n + 1 == nargs && !mount_flags[i].name) 250 options = args[n]; 251 } 252 253 system = args[1]; 254 source = args[2]; 255 target = args[3]; 256 257 if (!strncmp(source, "mtd@", 4)) { 258 n = mtd_name_to_number(source + 4); 259 if (n < 0) { 260 return -1; 261 } 262 263 sprintf(tmp, "/dev/block/mtdblock%d", n); 264 265 if (mount(tmp, target, system, flags, options) < 0) { 266 return -1; 267 } 268 269 return 0; 270 } else if (!strncmp(source, "loop@", 5)) { 271 int mode, loop, fd; 272 struct loop_info info; 273 274 mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; 275 fd = open(source + 5, mode); 276 if (fd < 0) { 277 return -1; 278 } 279 280 for (n = 0; ; n++) { 281 sprintf(tmp, "/dev/block/loop%d", n); 282 loop = open(tmp, mode); 283 if (loop < 0) { 284 return -1; 285 } 286 287 /* if it is a blank loop device */ 288 if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { 289 /* if it becomes our loop device */ 290 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { 291 close(fd); 292 293 if (mount(tmp, target, system, flags, options) < 0) { 294 ioctl(loop, LOOP_CLR_FD, 0); 295 close(loop); 296 return -1; 297 } 298 299 close(loop); 300 return 0; 301 } 302 } 303 304 close(loop); 305 } 306 307 close(fd); 308 ERROR("out of loopback devices"); 309 return -1; 310 } else { 311 if (mount(source, target, system, flags, options) < 0) { 312 return -1; 313 } 314 315 return 0; 316 } 317} 318 319int do_setkey(int nargs, char **args) 320{ 321 struct kbentry kbe; 322 kbe.kb_table = strtoul(args[1], 0, 0); 323 kbe.kb_index = strtoul(args[2], 0, 0); 324 kbe.kb_value = strtoul(args[3], 0, 0); 325 return setkey(&kbe); 326} 327 328int do_setprop(int nargs, char **args) 329{ 330 property_set(args[1], args[2]); 331 return 0; 332} 333 334int do_setrlimit(int nargs, char **args) 335{ 336 struct rlimit limit; 337 int resource; 338 resource = atoi(args[1]); 339 limit.rlim_cur = atoi(args[2]); 340 limit.rlim_max = atoi(args[3]); 341 return setrlimit(resource, &limit); 342} 343 344int do_start(int nargs, char **args) 345{ 346 struct service *svc; 347 svc = service_find_by_name(args[1]); 348 if (svc) { 349 service_start(svc); 350 } 351 return 0; 352} 353 354int do_stop(int nargs, char **args) 355{ 356 struct service *svc; 357 svc = service_find_by_name(args[1]); 358 if (svc) { 359 service_stop(svc); 360 } 361 return 0; 362} 363 364int do_restart(int nargs, char **args) 365{ 366 struct service *svc; 367 svc = service_find_by_name(args[1]); 368 if (svc) { 369 service_stop(svc); 370 service_start(svc); 371 } 372 return 0; 373} 374 375int do_trigger(int nargs, char **args) 376{ 377 return 0; 378} 379 380int do_symlink(int nargs, char **args) 381{ 382 return symlink(args[1], args[2]); 383} 384 385int do_write(int nargs, char **args) 386{ 387 return write_file(args[1], args[2]); 388} 389 390int do_chown(int nargs, char **args) { 391 /* GID is optional. */ 392 if (nargs == 3) { 393 if (chown(args[2], decode_uid(args[1]), -1) < 0) 394 return -errno; 395 } else if (nargs == 4) { 396 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2]))) 397 return -errno; 398 } else { 399 return -1; 400 } 401 return 0; 402} 403 404static mode_t get_mode(const char *s) { 405 mode_t mode = 0; 406 while (*s) { 407 if (*s >= '0' && *s <= '7') { 408 mode = (mode<<3) | (*s-'0'); 409 } else { 410 return -1; 411 } 412 s++; 413 } 414 return mode; 415} 416 417int do_chmod(int nargs, char **args) { 418 mode_t mode = get_mode(args[1]); 419 if (chmod(args[2], mode) < 0) { 420 return -errno; 421 } 422 return 0; 423} 424 425int do_loglevel(int nargs, char **args) { 426 if (nargs == 2) { 427 log_set_level(atoi(args[1])); 428 return 0; 429 } 430 return -1; 431} 432 433int do_device(int nargs, char **args) { 434 int len; 435 char tmp[64]; 436 char *source = args[1]; 437 int prefix = 0; 438 439 if (nargs != 5) 440 return -1; 441 /* Check for wildcard '*' at the end which indicates a prefix. */ 442 len = strlen(args[1]) - 1; 443 if (args[1][len] == '*') { 444 args[1][len] = '\0'; 445 prefix = 1; 446 } 447 /* If path starts with mtd@ lookup the mount number. */ 448 if (!strncmp(source, "mtd@", 4)) { 449 int n = mtd_name_to_number(source + 4); 450 if (n >= 0) { 451 snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n); 452 source = tmp; 453 } 454 } 455 add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]), 456 decode_uid(args[4]), prefix); 457 return 0; 458} 459