blob: b955e7e72dd6442aa81b334e08595bcc4d74f08d [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
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>
Colin Cross504bc512010-04-13 19:35:09 -070024#include <time.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080025
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
Colin Crossed8a7d82010-04-19 17:05:34 -070036#include "log.h"
37#include "list.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080038
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
Colin Crossf24ed8c2010-04-12 18:51:06 -0700214#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}
Colin Cross504bc512010-04-13 19:35:09 -0700285
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}
Colin Crossb0ab94b2010-04-08 16:16:20 -0700303
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}