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