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