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