util.c revision a613819a96eeede9f9702d145e0575d459fdfd7a
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 <stdarg.h> 18#include <stdlib.h> 19#include <stdio.h> 20#include <string.h> 21#include <fcntl.h> 22#include <ctype.h> 23#include <errno.h> 24#include <time.h> 25#include <ftw.h> 26 27#include <selinux/label.h> 28 29#include <sys/stat.h> 30#include <sys/types.h> 31#include <sys/socket.h> 32#include <sys/un.h> 33 34/* for ANDROID_SOCKET_* */ 35#include <cutils/sockets.h> 36 37#include <private/android_filesystem_config.h> 38 39#include "init.h" 40#include "log.h" 41#include "util.h" 42 43/* 44 * android_name_to_id - returns the integer uid/gid associated with the given 45 * name, or -1U on error. 46 */ 47static unsigned int android_name_to_id(const char *name) 48{ 49 const struct android_id_info *info = android_ids; 50 unsigned int n; 51 52 for (n = 0; n < android_id_count; n++) { 53 if (!strcmp(info[n].name, name)) 54 return info[n].aid; 55 } 56 57 return -1U; 58} 59 60/* 61 * decode_uid - decodes and returns the given string, which can be either the 62 * numeric or name representation, into the integer uid or gid. Returns -1U on 63 * error. 64 */ 65unsigned int decode_uid(const char *s) 66{ 67 unsigned int v; 68 69 if (!s || *s == '\0') 70 return -1U; 71 if (isalpha(s[0])) 72 return android_name_to_id(s); 73 74 errno = 0; 75 v = (unsigned int) strtoul(s, 0, 0); 76 if (errno) 77 return -1U; 78 return v; 79} 80 81/* 82 * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR 83 * ("/dev/socket") as dictated in init.rc. This socket is inherited by the 84 * daemon. We communicate the file descriptor's value via the environment 85 * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo"). 86 */ 87int create_socket(const char *name, int type, mode_t perm, uid_t uid, 88 gid_t gid, const char *socketcon) 89{ 90 struct sockaddr_un addr; 91 int fd, ret; 92 char *filecon; 93 94 if (socketcon) 95 setsockcreatecon(socketcon); 96 97 fd = socket(PF_UNIX, type, 0); 98 if (fd < 0) { 99 ERROR("Failed to open socket '%s': %s\n", name, strerror(errno)); 100 return -1; 101 } 102 103 if (socketcon) 104 setsockcreatecon(NULL); 105 106 memset(&addr, 0 , sizeof(addr)); 107 addr.sun_family = AF_UNIX; 108 snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", 109 name); 110 111 ret = unlink(addr.sun_path); 112 if (ret != 0 && errno != ENOENT) { 113 ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno)); 114 goto out_close; 115 } 116 117 filecon = NULL; 118 if (sehandle) { 119 ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK); 120 if (ret == 0) 121 setfscreatecon(filecon); 122 } 123 124 ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr)); 125 if (ret) { 126 ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno)); 127 goto out_unlink; 128 } 129 130 setfscreatecon(NULL); 131 freecon(filecon); 132 133 chown(addr.sun_path, uid, gid); 134 chmod(addr.sun_path, perm); 135 136 INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n", 137 addr.sun_path, perm, uid, gid); 138 139 return fd; 140 141out_unlink: 142 unlink(addr.sun_path); 143out_close: 144 close(fd); 145 return -1; 146} 147 148/* reads a file, making sure it is terminated with \n \0 */ 149void *read_file(const char *fn, unsigned *_sz) 150{ 151 char *data; 152 int sz; 153 int fd; 154 struct stat sb; 155 156 data = 0; 157 fd = open(fn, O_RDONLY); 158 if(fd < 0) return 0; 159 160 // for security reasons, disallow world-writable 161 // or group-writable files 162 if (fstat(fd, &sb) < 0) { 163 ERROR("fstat failed for '%s'\n", fn); 164 goto oops; 165 } 166 if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) { 167 ERROR("skipping insecure file '%s'\n", fn); 168 goto oops; 169 } 170 171 sz = lseek(fd, 0, SEEK_END); 172 if(sz < 0) goto oops; 173 174 if(lseek(fd, 0, SEEK_SET) != 0) goto oops; 175 176 data = (char*) malloc(sz + 2); 177 if(data == 0) goto oops; 178 179 if(read(fd, data, sz) != sz) goto oops; 180 close(fd); 181 data[sz] = '\n'; 182 data[sz+1] = 0; 183 if(_sz) *_sz = sz; 184 return data; 185 186oops: 187 close(fd); 188 if(data != 0) free(data); 189 return 0; 190} 191 192#define MAX_MTD_PARTITIONS 16 193 194static struct { 195 char name[16]; 196 int number; 197} mtd_part_map[MAX_MTD_PARTITIONS]; 198 199static int mtd_part_count = -1; 200 201static void find_mtd_partitions(void) 202{ 203 int fd; 204 char buf[1024]; 205 char *pmtdbufp; 206 ssize_t pmtdsize; 207 int r; 208 209 fd = open("/proc/mtd", O_RDONLY); 210 if (fd < 0) 211 return; 212 213 buf[sizeof(buf) - 1] = '\0'; 214 pmtdsize = read(fd, buf, sizeof(buf) - 1); 215 pmtdbufp = buf; 216 while (pmtdsize > 0) { 217 int mtdnum, mtdsize, mtderasesize; 218 char mtdname[16]; 219 mtdname[0] = '\0'; 220 mtdnum = -1; 221 r = sscanf(pmtdbufp, "mtd%d: %x %x %15s", 222 &mtdnum, &mtdsize, &mtderasesize, mtdname); 223 if ((r == 4) && (mtdname[0] == '"')) { 224 char *x = strchr(mtdname + 1, '"'); 225 if (x) { 226 *x = 0; 227 } 228 INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1); 229 if (mtd_part_count < MAX_MTD_PARTITIONS) { 230 strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1); 231 mtd_part_map[mtd_part_count].number = mtdnum; 232 mtd_part_count++; 233 } else { 234 ERROR("too many mtd partitions\n"); 235 } 236 } 237 while (pmtdsize > 0 && *pmtdbufp != '\n') { 238 pmtdbufp++; 239 pmtdsize--; 240 } 241 if (pmtdsize > 0) { 242 pmtdbufp++; 243 pmtdsize--; 244 } 245 } 246 close(fd); 247} 248 249int mtd_name_to_number(const char *name) 250{ 251 int n; 252 if (mtd_part_count < 0) { 253 mtd_part_count = 0; 254 find_mtd_partitions(); 255 } 256 for (n = 0; n < mtd_part_count; n++) { 257 if (!strcmp(name, mtd_part_map[n].name)) { 258 return mtd_part_map[n].number; 259 } 260 } 261 return -1; 262} 263 264/* 265 * gettime() - returns the time in seconds of the system's monotonic clock or 266 * zero on error. 267 */ 268time_t gettime(void) 269{ 270 struct timespec ts; 271 int ret; 272 273 ret = clock_gettime(CLOCK_MONOTONIC, &ts); 274 if (ret < 0) { 275 ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno)); 276 return 0; 277 } 278 279 return ts.tv_sec; 280} 281 282int mkdir_recursive(const char *pathname, mode_t mode) 283{ 284 char buf[128]; 285 const char *slash; 286 const char *p = pathname; 287 int width; 288 int ret; 289 struct stat info; 290 291 while ((slash = strchr(p, '/')) != NULL) { 292 width = slash - pathname; 293 p = slash + 1; 294 if (width < 0) 295 break; 296 if (width == 0) 297 continue; 298 if ((unsigned int)width > sizeof(buf) - 1) { 299 ERROR("path too long for mkdir_recursive\n"); 300 return -1; 301 } 302 memcpy(buf, pathname, width); 303 buf[width] = 0; 304 if (stat(buf, &info) != 0) { 305 ret = make_dir(buf, mode); 306 if (ret && errno != EEXIST) 307 return ret; 308 } 309 } 310 ret = make_dir(pathname, mode); 311 if (ret && errno != EEXIST) 312 return ret; 313 return 0; 314} 315 316/* 317 * replaces any unacceptable characters with '_', the 318 * length of the resulting string is equal to the input string 319 */ 320void sanitize(char *s) 321{ 322 const char* accept = 323 "abcdefghijklmnopqrstuvwxyz" 324 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 325 "0123456789" 326 "_-."; 327 328 if (!s) 329 return; 330 331 for (; *s; s++) { 332 s += strspn(s, accept); 333 if (*s) *s = '_'; 334 } 335} 336 337void make_link(const char *oldpath, const char *newpath) 338{ 339 int ret; 340 char buf[256]; 341 char *slash; 342 int width; 343 344 slash = strrchr(newpath, '/'); 345 if (!slash) 346 return; 347 width = slash - newpath; 348 if (width <= 0 || width > (int)sizeof(buf) - 1) 349 return; 350 memcpy(buf, newpath, width); 351 buf[width] = 0; 352 ret = mkdir_recursive(buf, 0755); 353 if (ret) 354 ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno); 355 356 ret = symlink(oldpath, newpath); 357 if (ret && errno != EEXIST) 358 ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno); 359} 360 361void remove_link(const char *oldpath, const char *newpath) 362{ 363 char path[256]; 364 ssize_t ret; 365 ret = readlink(newpath, path, sizeof(path) - 1); 366 if (ret <= 0) 367 return; 368 path[ret] = 0; 369 if (!strcmp(path, oldpath)) 370 unlink(newpath); 371} 372 373int wait_for_file(const char *filename, int timeout) 374{ 375 struct stat info; 376 time_t timeout_time = gettime() + timeout; 377 int ret = -1; 378 379 while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0)) 380 usleep(10000); 381 382 return ret; 383} 384 385void open_devnull_stdio(void) 386{ 387 int fd; 388 static const char *name = "/dev/__null__"; 389 if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { 390 fd = open(name, O_RDWR); 391 unlink(name); 392 if (fd >= 0) { 393 dup2(fd, 0); 394 dup2(fd, 1); 395 dup2(fd, 2); 396 if (fd > 2) { 397 close(fd); 398 } 399 return; 400 } 401 } 402 403 exit(1); 404} 405 406void get_hardware_name(char *hardware, unsigned int *revision) 407{ 408 const char *cpuinfo = "/proc/cpuinfo"; 409 char *data = NULL; 410 size_t len = 0, limit = 1024; 411 int fd, n; 412 char *x, *hw, *rev; 413 414 /* Hardware string was provided on kernel command line */ 415 if (hardware[0]) 416 return; 417 418 fd = open(cpuinfo, O_RDONLY); 419 if (fd < 0) return; 420 421 for (;;) { 422 x = realloc(data, limit); 423 if (!x) { 424 ERROR("Failed to allocate memory to read %s\n", cpuinfo); 425 goto done; 426 } 427 data = x; 428 429 n = read(fd, data + len, limit - len); 430 if (n < 0) { 431 ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno); 432 goto done; 433 } 434 len += n; 435 436 if (len < limit) 437 break; 438 439 /* We filled the buffer, so increase size and loop to read more */ 440 limit *= 2; 441 } 442 443 data[len] = 0; 444 hw = strstr(data, "\nHardware"); 445 rev = strstr(data, "\nRevision"); 446 447 if (hw) { 448 x = strstr(hw, ": "); 449 if (x) { 450 x += 2; 451 n = 0; 452 while (*x && *x != '\n') { 453 if (!isspace(*x)) 454 hardware[n++] = tolower(*x); 455 x++; 456 if (n == 31) break; 457 } 458 hardware[n] = 0; 459 } 460 } 461 462 if (rev) { 463 x = strstr(rev, ": "); 464 if (x) { 465 *revision = strtoul(x + 2, 0, 16); 466 } 467 } 468 469done: 470 close(fd); 471 free(data); 472} 473 474void import_kernel_cmdline(int in_qemu, 475 void (*import_kernel_nv)(char *name, int in_qemu)) 476{ 477 char cmdline[2048]; 478 char *ptr; 479 int fd; 480 481 fd = open("/proc/cmdline", O_RDONLY); 482 if (fd >= 0) { 483 int n = read(fd, cmdline, sizeof(cmdline) - 1); 484 if (n < 0) n = 0; 485 486 /* get rid of trailing newline, it happens */ 487 if (n > 0 && cmdline[n-1] == '\n') n--; 488 489 cmdline[n] = 0; 490 close(fd); 491 } else { 492 cmdline[0] = 0; 493 } 494 495 ptr = cmdline; 496 while (ptr && *ptr) { 497 char *x = strchr(ptr, ' '); 498 if (x != 0) *x++ = 0; 499 import_kernel_nv(ptr, in_qemu); 500 ptr = x; 501 } 502} 503 504int make_dir(const char *path, mode_t mode) 505{ 506 int rc; 507 508 char *secontext = NULL; 509 510 if (sehandle) { 511 selabel_lookup(sehandle, &secontext, path, mode); 512 setfscreatecon(secontext); 513 } 514 515 rc = mkdir(path, mode); 516 517 if (secontext) { 518 int save_errno = errno; 519 freecon(secontext); 520 setfscreatecon(NULL); 521 errno = save_errno; 522 } 523 524 return rc; 525} 526 527static int restorecon_sb(const char *pathname, const struct stat *sb) 528{ 529 char *secontext = NULL; 530 char *oldsecontext = NULL; 531 int i; 532 533 if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0) 534 return -errno; 535 536 if (lgetfilecon(pathname, &oldsecontext) < 0) { 537 freecon(secontext); 538 return -errno; 539 } 540 541 if (strcmp(oldsecontext, secontext) != 0) { 542 if (lsetfilecon(pathname, secontext) < 0) { 543 freecon(oldsecontext); 544 freecon(secontext); 545 return -errno; 546 } 547 } 548 freecon(oldsecontext); 549 freecon(secontext); 550 return 0; 551} 552 553int restorecon(const char *pathname) 554{ 555 struct stat sb; 556 557 if (is_selinux_enabled() <= 0 || !sehandle) 558 return 0; 559 560 if (lstat(pathname, &sb) < 0) 561 return -errno; 562 563 return restorecon_sb(pathname, &sb); 564} 565 566static int nftw_restorecon(const char* filename, const struct stat* statptr, 567 int fileflags __attribute__((unused)), 568 struct FTW* pftw __attribute__((unused))) 569{ 570 restorecon_sb(filename, statptr); 571 return 0; 572} 573 574int restorecon_recursive(const char* pathname) 575{ 576 int fd_limit = 20; 577 int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS; 578 579 if (is_selinux_enabled() <= 0 || !sehandle) 580 return 0; 581 582 return nftw(pathname, nftw_restorecon, fd_limit, flags); 583} 584