util.c revision e096e36e50b4b66638ebc4d3c09c2ee35f538dfa
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 26#ifdef HAVE_SELINUX 27#include <selinux/label.h> 28#endif 29 30#include <sys/stat.h> 31#include <sys/types.h> 32#include <sys/socket.h> 33#include <sys/un.h> 34 35/* for ANDROID_SOCKET_* */ 36#include <cutils/sockets.h> 37 38#include <private/android_filesystem_config.h> 39 40#include "init.h" 41#include "log.h" 42#include "util.h" 43 44/* 45 * android_name_to_id - returns the integer uid/gid associated with the given 46 * name, or -1U on error. 47 */ 48static unsigned int android_name_to_id(const char *name) 49{ 50 struct android_id_info *info = android_ids; 51 unsigned int n; 52 53 for (n = 0; n < android_id_count; n++) { 54 if (!strcmp(info[n].name, name)) 55 return info[n].aid; 56 } 57 58 return -1U; 59} 60 61/* 62 * decode_uid - decodes and returns the given string, which can be either the 63 * numeric or name representation, into the integer uid or gid. Returns -1U on 64 * error. 65 */ 66unsigned int decode_uid(const char *s) 67{ 68 unsigned int v; 69 70 if (!s || *s == '\0') 71 return -1U; 72 if (isalpha(s[0])) 73 return android_name_to_id(s); 74 75 errno = 0; 76 v = (unsigned int) strtoul(s, 0, 0); 77 if (errno) 78 return -1U; 79 return v; 80} 81 82/* 83 * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR 84 * ("/dev/socket") as dictated in init.rc. This socket is inherited by the 85 * daemon. We communicate the file descriptor's value via the environment 86 * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo"). 87 */ 88int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) 89{ 90 struct sockaddr_un addr; 91 int fd, ret; 92#ifdef HAVE_SELINUX 93 char *secon; 94#endif 95 96 fd = socket(PF_UNIX, type, 0); 97 if (fd < 0) { 98 ERROR("Failed to open socket '%s': %s\n", name, strerror(errno)); 99 return -1; 100 } 101 102 memset(&addr, 0 , sizeof(addr)); 103 addr.sun_family = AF_UNIX; 104 snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", 105 name); 106 107 ret = unlink(addr.sun_path); 108 if (ret != 0 && errno != ENOENT) { 109 ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno)); 110 goto out_close; 111 } 112 113#ifdef HAVE_SELINUX 114 secon = NULL; 115 if (sehandle) { 116 ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK); 117 if (ret == 0) 118 setfscreatecon(secon); 119 } 120#endif 121 122 ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr)); 123 if (ret) { 124 ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno)); 125 goto out_unlink; 126 } 127 128#ifdef HAVE_SELINUX 129 setfscreatecon(NULL); 130 freecon(secon); 131#endif 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 155 data = 0; 156 fd = open(fn, O_RDONLY); 157 if(fd < 0) return 0; 158 159 sz = lseek(fd, 0, SEEK_END); 160 if(sz < 0) goto oops; 161 162 if(lseek(fd, 0, SEEK_SET) != 0) goto oops; 163 164 data = (char*) malloc(sz + 2); 165 if(data == 0) goto oops; 166 167 if(read(fd, data, sz) != sz) goto oops; 168 close(fd); 169 data[sz] = '\n'; 170 data[sz+1] = 0; 171 if(_sz) *_sz = sz; 172 return data; 173 174oops: 175 close(fd); 176 if(data != 0) free(data); 177 return 0; 178} 179 180#define MAX_MTD_PARTITIONS 16 181 182static struct { 183 char name[16]; 184 int number; 185} mtd_part_map[MAX_MTD_PARTITIONS]; 186 187static int mtd_part_count = -1; 188 189static void find_mtd_partitions(void) 190{ 191 int fd; 192 char buf[1024]; 193 char *pmtdbufp; 194 ssize_t pmtdsize; 195 int r; 196 197 fd = open("/proc/mtd", O_RDONLY); 198 if (fd < 0) 199 return; 200 201 buf[sizeof(buf) - 1] = '\0'; 202 pmtdsize = read(fd, buf, sizeof(buf) - 1); 203 pmtdbufp = buf; 204 while (pmtdsize > 0) { 205 int mtdnum, mtdsize, mtderasesize; 206 char mtdname[16]; 207 mtdname[0] = '\0'; 208 mtdnum = -1; 209 r = sscanf(pmtdbufp, "mtd%d: %x %x %15s", 210 &mtdnum, &mtdsize, &mtderasesize, mtdname); 211 if ((r == 4) && (mtdname[0] == '"')) { 212 char *x = strchr(mtdname + 1, '"'); 213 if (x) { 214 *x = 0; 215 } 216 INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1); 217 if (mtd_part_count < MAX_MTD_PARTITIONS) { 218 strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1); 219 mtd_part_map[mtd_part_count].number = mtdnum; 220 mtd_part_count++; 221 } else { 222 ERROR("too many mtd partitions\n"); 223 } 224 } 225 while (pmtdsize > 0 && *pmtdbufp != '\n') { 226 pmtdbufp++; 227 pmtdsize--; 228 } 229 if (pmtdsize > 0) { 230 pmtdbufp++; 231 pmtdsize--; 232 } 233 } 234 close(fd); 235} 236 237int mtd_name_to_number(const char *name) 238{ 239 int n; 240 if (mtd_part_count < 0) { 241 mtd_part_count = 0; 242 find_mtd_partitions(); 243 } 244 for (n = 0; n < mtd_part_count; n++) { 245 if (!strcmp(name, mtd_part_map[n].name)) { 246 return mtd_part_map[n].number; 247 } 248 } 249 return -1; 250} 251 252/* 253 * gettime() - returns the time in seconds of the system's monotonic clock or 254 * zero on error. 255 */ 256time_t gettime(void) 257{ 258 struct timespec ts; 259 int ret; 260 261 ret = clock_gettime(CLOCK_MONOTONIC, &ts); 262 if (ret < 0) { 263 ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno)); 264 return 0; 265 } 266 267 return ts.tv_sec; 268} 269 270int mkdir_recursive(const char *pathname, mode_t mode) 271{ 272 char buf[128]; 273 const char *slash; 274 const char *p = pathname; 275 int width; 276 int ret; 277 struct stat info; 278 279 while ((slash = strchr(p, '/')) != NULL) { 280 width = slash - pathname; 281 p = slash + 1; 282 if (width < 0) 283 break; 284 if (width == 0) 285 continue; 286 if ((unsigned int)width > sizeof(buf) - 1) { 287 ERROR("path too long for mkdir_recursive\n"); 288 return -1; 289 } 290 memcpy(buf, pathname, width); 291 buf[width] = 0; 292 if (stat(buf, &info) != 0) { 293 ret = make_dir(buf, mode); 294 if (ret && errno != EEXIST) 295 return ret; 296 } 297 } 298 ret = make_dir(pathname, mode); 299 if (ret && errno != EEXIST) 300 return ret; 301 return 0; 302} 303 304void sanitize(char *s) 305{ 306 if (!s) 307 return; 308 while (isalnum(*s)) 309 s++; 310 *s = 0; 311} 312void make_link(const char *oldpath, const char *newpath) 313{ 314 int ret; 315 char buf[256]; 316 char *slash; 317 int width; 318 319 slash = strrchr(newpath, '/'); 320 if (!slash) 321 return; 322 width = slash - newpath; 323 if (width <= 0 || width > (int)sizeof(buf) - 1) 324 return; 325 memcpy(buf, newpath, width); 326 buf[width] = 0; 327 ret = mkdir_recursive(buf, 0755); 328 if (ret) 329 ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno); 330 331 ret = symlink(oldpath, newpath); 332 if (ret && errno != EEXIST) 333 ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno); 334} 335 336void remove_link(const char *oldpath, const char *newpath) 337{ 338 char path[256]; 339 ssize_t ret; 340 ret = readlink(newpath, path, sizeof(path) - 1); 341 if (ret <= 0) 342 return; 343 path[ret] = 0; 344 if (!strcmp(path, oldpath)) 345 unlink(newpath); 346} 347 348int wait_for_file(const char *filename, int timeout) 349{ 350 struct stat info; 351 time_t timeout_time = gettime() + timeout; 352 int ret = -1; 353 354 while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0)) 355 usleep(10000); 356 357 return ret; 358} 359 360void open_devnull_stdio(void) 361{ 362 int fd; 363 static const char *name = "/dev/__null__"; 364 if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { 365 fd = open(name, O_RDWR); 366 unlink(name); 367 if (fd >= 0) { 368 dup2(fd, 0); 369 dup2(fd, 1); 370 dup2(fd, 2); 371 if (fd > 2) { 372 close(fd); 373 } 374 return; 375 } 376 } 377 378 exit(1); 379} 380 381void get_hardware_name(char *hardware, unsigned int *revision) 382{ 383 char data[1024]; 384 int fd, n; 385 char *x, *hw, *rev; 386 387 /* Hardware string was provided on kernel command line */ 388 if (hardware[0]) 389 return; 390 391 fd = open("/proc/cpuinfo", O_RDONLY); 392 if (fd < 0) return; 393 394 n = read(fd, data, 1023); 395 close(fd); 396 if (n < 0) return; 397 398 data[n] = 0; 399 hw = strstr(data, "\nHardware"); 400 rev = strstr(data, "\nRevision"); 401 402 if (hw) { 403 x = strstr(hw, ": "); 404 if (x) { 405 x += 2; 406 n = 0; 407 while (*x && *x != '\n') { 408 if (!isspace(*x)) 409 hardware[n++] = tolower(*x); 410 x++; 411 if (n == 31) break; 412 } 413 hardware[n] = 0; 414 } 415 } 416 417 if (rev) { 418 x = strstr(rev, ": "); 419 if (x) { 420 *revision = strtoul(x + 2, 0, 16); 421 } 422 } 423} 424 425void import_kernel_cmdline(int in_qemu, 426 void (*import_kernel_nv)(char *name, int in_qemu)) 427{ 428 char cmdline[1024]; 429 char *ptr; 430 int fd; 431 432 fd = open("/proc/cmdline", O_RDONLY); 433 if (fd >= 0) { 434 int n = read(fd, cmdline, 1023); 435 if (n < 0) n = 0; 436 437 /* get rid of trailing newline, it happens */ 438 if (n > 0 && cmdline[n-1] == '\n') n--; 439 440 cmdline[n] = 0; 441 close(fd); 442 } else { 443 cmdline[0] = 0; 444 } 445 446 ptr = cmdline; 447 while (ptr && *ptr) { 448 char *x = strchr(ptr, ' '); 449 if (x != 0) *x++ = 0; 450 import_kernel_nv(ptr, in_qemu); 451 ptr = x; 452 } 453} 454 455int make_dir(const char *path, mode_t mode) 456{ 457 int rc; 458 459#ifdef HAVE_SELINUX 460 char *secontext = NULL; 461 462 if (sehandle) { 463 selabel_lookup(sehandle, &secontext, path, mode); 464 setfscreatecon(secontext); 465 } 466#endif 467 468 rc = mkdir(path, mode); 469 470#ifdef HAVE_SELINUX 471 if (secontext) { 472 int save_errno = errno; 473 freecon(secontext); 474 setfscreatecon(NULL); 475 errno = save_errno; 476 } 477#endif 478 return rc; 479} 480 481int restorecon(const char *pathname) 482{ 483#ifdef HAVE_SELINUX 484 char *secontext = NULL; 485 struct stat sb; 486 int i; 487 488 if (is_selinux_enabled() <= 0 || !sehandle) 489 return 0; 490 491 if (lstat(pathname, &sb) < 0) 492 return -errno; 493 if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0) 494 return -errno; 495 if (lsetfilecon(pathname, secontext) < 0) { 496 freecon(secontext); 497 return -errno; 498 } 499 freecon(secontext); 500#endif 501 return 0; 502} 503