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