diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:29:04 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:29:04 -0800 |
commit | e54eebbf1a908d65ee8cf80bab62821c05666d70 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /init | |
parent | a1e1c1b106423de09bc918502e7a51d4ffe5a4ae (diff) | |
download | core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.gz core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.bz2 core-e54eebbf1a908d65ee8cf80bab62821c05666d70.zip |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'init')
-rw-r--r-- | init/Android.mk | 33 | ||||
-rw-r--r-- | init/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | init/NOTICE | 190 | ||||
-rw-r--r-- | init/README.BOOTCHART | 52 | ||||
-rw-r--r-- | init/bootchart.c | 378 | ||||
-rw-r--r-- | init/bootchart.h | 36 | ||||
-rw-r--r-- | init/builtins.c | 442 | ||||
-rw-r--r-- | init/devices.c | 626 | ||||
-rw-r--r-- | init/devices.h | 27 | ||||
-rwxr-xr-x | init/grab-bootchart.sh | 22 | ||||
-rw-r--r-- | init/init.c | 989 | ||||
-rw-r--r-- | init/init.h | 174 | ||||
-rw-r--r-- | init/keywords.h | 78 | ||||
-rw-r--r-- | init/logo.c | 163 | ||||
-rw-r--r-- | init/parser.c | 797 | ||||
-rw-r--r-- | init/property_service.c | 502 | ||||
-rw-r--r-- | init/property_service.h | 28 | ||||
-rw-r--r-- | init/readme.txt | 293 | ||||
-rw-r--r-- | init/util.c | 211 |
19 files changed, 0 insertions, 5041 deletions
diff --git a/init/Android.mk b/init/Android.mk deleted file mode 100644 index d3766d455..000000000 --- a/init/Android.mk +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2005 The Android Open Source Project - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - builtins.c \ - init.c \ - devices.c \ - property_service.c \ - util.c \ - parser.c \ - logo.c - -ifeq ($(strip $(INIT_BOOTCHART)),true) -LOCAL_SRC_FILES += bootchart.c -LOCAL_CFLAGS += -DBOOTCHART=1 -endif - -LOCAL_MODULE:= init - -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) -LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) - -LOCAL_STATIC_LIBRARIES := libcutils libc - -#LOCAL_STATIC_LIBRARIES := libcutils libc libminui libpixelflinger_static -#LOCAL_STATIC_LIBRARIES += libminzip libunz libamend libmtdutils libmincrypt -#LOCAL_STATIC_LIBRARIES += libstdc++_static - -include $(BUILD_EXECUTABLE) - diff --git a/init/MODULE_LICENSE_APACHE2 b/init/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29bb..000000000 --- a/init/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/init/NOTICE b/init/NOTICE deleted file mode 100644 index c5b1efa7a..000000000 --- a/init/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/init/README.BOOTCHART b/init/README.BOOTCHART deleted file mode 100644 index 70cf2c39b..000000000 --- a/init/README.BOOTCHART +++ /dev/null @@ -1,52 +0,0 @@ -This version of init contains code to perform "bootcharting", i.e. generating log -files that can be later processed by the tools provided by www.bootchart.org. - -To activate it, you need to define build 'init' with the INIT_BOOTCHART environment -variable defined to 'true', for example: - - touch system/init/init.c - m INIT_BOOTCHART=true - -On the emulator, use the new -bootchart <timeout> option to boot with bootcharting -activated for <timeout> seconds. - -Otherwise, flash your device, and start it. Then create a file on the /data partition -with a command like the following: - - adb shell 'echo $TIMEOUT > /data/bootchart-start' - -Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds; -for example, to bootchart for 2 minutes, do: - - adb shell 'echo 120 > /data/bootchart-start' - -Reboot your device, bootcharting will begin and stop after the period you gave. -You can also stop the bootcharting at any moment by doing the following: - - adb shell 'echo 1 > /data/bootchart-stop' - -Note that /data/bootchart-stop is deleted automatically by init at the end of the -bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it -when you're done collecting data: - - adb shell rm /data/bootchart-start - -The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh -which will use ADB to retrieve them and create a bootchart.tgz file that can be used with -the bootchart parser/renderer, or even uploaded directly to the form located at: - - http://www.bootchart.org/download.html - -NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an - image on your machine by doing the following: - - 1/ download the sources from www.bootchart.org - 2/ unpack them - 3/ in the source directory, type 'ant' to build the bootchart program - 4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz - -technical note: - -this implementation of bootcharting does use the 'bootchartd' script provided by -www.bootchart.org, but a C re-implementation that is directly compiled into our init -program. diff --git a/init/bootchart.c b/init/bootchart.c deleted file mode 100644 index f72fcaaca..000000000 --- a/init/bootchart.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* this code is used to generate a boot sequence profile that can be used - * with the 'bootchart' graphics generation tool. see www.bootchart.org - * note that unlike the original bootchartd, this is not a Bash script but - * some C code that is run right from the init script. - */ - -#include <stdio.h> -#include <time.h> -#include <dirent.h> -#include <unistd.h> -#include <fcntl.h> -#include <unistd.h> -#include <fcntl.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/stat.h> -#include "bootchart.h" - -#define VERSION "0.8" -#define SAMPLE_PERIOD 0.2 -#define LOG_ROOT "/data/bootchart" -#define LOG_STAT LOG_ROOT"/proc_stat.log" -#define LOG_PROCS LOG_ROOT"/proc_ps.log" -#define LOG_DISK LOG_ROOT"/proc_diskstats.log" -#define LOG_HEADER LOG_ROOT"/header" -#define LOG_ACCT LOG_ROOT"/kernel_pacct" - -#define LOG_STARTFILE "/data/bootchart-start" -#define LOG_STOPFILE "/data/bootchart-stop" - -static int -unix_read(int fd, void* buff, int len) -{ - int ret; - do { ret = read(fd, buff, len); } while (ret < 0 && errno == EINTR); - return ret; -} - -static int -unix_write(int fd, const void* buff, int len) -{ - int ret; - do { ret = write(fd, buff, len); } while (ret < 0 && errno == EINTR); - return ret; -} - -static int -proc_read(const char* filename, char* buff, size_t buffsize) -{ - int len = 0; - int fd = open(filename, O_RDONLY); - if (fd >= 0) { - len = unix_read(fd, buff, buffsize-1); - close(fd); - } - buff[len > 0 ? len : 0] = 0; - return len; -} - -#define FILE_BUFF_SIZE 65536 - -typedef struct { - int count; - int fd; - char data[FILE_BUFF_SIZE]; -} FileBuffRec, *FileBuff; - -static void -file_buff_open( FileBuff buff, const char* path ) -{ - buff->count = 0; - buff->fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0755); -} - -static void -file_buff_write( FileBuff buff, const void* src, int len ) -{ - while (len > 0) { - int avail = sizeof(buff->data) - buff->count; - if (avail > len) - avail = len; - - memcpy( buff->data + buff->count, src, avail ); - len -= avail; - src = (char*)src + avail; - - buff->count += avail; - if (buff->count == FILE_BUFF_SIZE) { - unix_write( buff->fd, buff->data, buff->count ); - buff->count = 0; - } - } -} - -static void -file_buff_done( FileBuff buff ) -{ - if (buff->count > 0) { - unix_write( buff->fd, buff->data, buff->count ); - buff->count = 0; - } -} - -static void -log_header(void) -{ - FILE* out; - char cmdline[1024]; - char uname[128]; - char cpuinfo[128]; - char* cpu; - char date[32]; - time_t now_t = time(NULL); - struct tm now = *localtime(&now_t); - strftime(date, sizeof(date), "%x %X", &now); - - out = fopen( LOG_HEADER, "w" ); - if (out == NULL) - return; - - proc_read("/proc/cmdline", cmdline, sizeof(cmdline)); - proc_read("/proc/version", uname, sizeof(uname)); - proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo)); - - cpu = strchr( cpuinfo, ':' ); - if (cpu) { - char* p = strchr(cpu, '\n'); - cpu += 2; - if (p) - *p = 0; - } - - fprintf(out, "version = %s\n", VERSION); - fprintf(out, "title = Boot chart for Android ( %s )\n", date); - fprintf(out, "system.uname = %s\n", uname); - fprintf(out, "system.release = 0.0\n"); - fprintf(out, "system.cpu = %s\n", cpu); - fprintf(out, "system.kernel.options = %s\n", cmdline); - fclose(out); -} - -static void -close_on_exec(int fd) -{ - fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -static void -open_log_file(int* plogfd, const char* logfile) -{ - int logfd = *plogfd; - - /* create log file if needed */ - if (logfd < 0) - { - logfd = open(logfile,O_WRONLY|O_CREAT|O_TRUNC,0755); - if (logfd < 0) { - *plogfd = -2; - return; - } - close_on_exec(logfd); - *plogfd = logfd; - } -} - -static void -do_log_uptime(FileBuff log) -{ - char buff[65]; - int fd, ret, len; - - fd = open("/proc/uptime",O_RDONLY); - if (fd >= 0) { - int ret; - ret = unix_read(fd, buff, 64); - close(fd); - buff[64] = 0; - if (ret >= 0) { - long long jiffies = 100LL*strtod(buff,NULL); - int len; - snprintf(buff,sizeof(buff),"%lld\n",jiffies); - len = strlen(buff); - file_buff_write(log, buff, len); - } - } -} - -static void -do_log_ln(FileBuff log) -{ - file_buff_write(log, "\n", 1); -} - - -static void -do_log_file(FileBuff log, const char* procfile) -{ - char buff[1024]; - int fd; - - do_log_uptime(log); - - /* append file content */ - fd = open(procfile,O_RDONLY); - if (fd >= 0) { - close_on_exec(fd); - for (;;) { - int ret; - ret = unix_read(fd, buff, sizeof(buff)); - if (ret <= 0) - break; - - file_buff_write(log, buff, ret); - if (ret < (int)sizeof(buff)) - break; - } - close(fd); - } - - do_log_ln(log); -} - -static void -do_log_procs(FileBuff log) -{ - DIR* dir = opendir("/proc"); - struct dirent* entry; - - do_log_uptime(log); - - while ((entry = readdir(dir)) != NULL) { - /* only match numeric values */ - char* end; - int pid = strtol( entry->d_name, &end, 10); - if (end != NULL && end > entry->d_name && *end == 0) { - char filename[32]; - char buff[1024]; - char cmdline[1024]; - int len; - int fd; - - /* read command line and extract program name */ - snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid); - proc_read(filename, cmdline, sizeof(cmdline)); - - /* read process stat line */ - snprintf(filename,sizeof(filename),"/proc/%d/stat",pid); - fd = open(filename,O_RDONLY); - if (fd >= 0) { - len = unix_read(fd, buff, sizeof(buff)-1); - close(fd); - if (len > 0) { - int len2 = strlen(cmdline); - if (len2 > 0) { - /* we want to substitute the process name with its real name */ - const char* p1; - const char* p2; - buff[len] = 0; - p1 = strchr(buff, '('); - p2 = strchr(p1, ')'); - file_buff_write(log, buff, p1+1-buff); - file_buff_write(log, cmdline, strlen(cmdline)); - file_buff_write(log, p2, strlen(p2)); - } else { - /* no substitution */ - file_buff_write(log,buff,len); - } - } - } - } - } - closedir(dir); - do_log_ln(log); -} - -static FileBuffRec log_stat[1]; -static FileBuffRec log_procs[1]; -static FileBuffRec log_disks[1]; - -/* called to setup bootcharting */ -int bootchart_init( void ) -{ - int ret; - char buff[4]; - int timeout = 0, count = 0; - - buff[0] = 0; - proc_read( LOG_STARTFILE, buff, sizeof(buff) ); - if (buff[0] != 0) { - timeout = atoi(buff); - } - else { - /* when running with emulator, androidboot.bootchart=<timeout> - * might be passed by as kernel parameters to specify the bootchart - * timeout. this is useful when using -wipe-data since the /data - * partition is fresh - */ - char cmdline[1024]; - char* s; -#define KERNEL_OPTION "androidboot.bootchart=" - proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) ); - s = strstr(cmdline, KERNEL_OPTION); - if (s) { - s += sizeof(KERNEL_OPTION)-1; - timeout = atoi(s); - } - } - if (timeout == 0) - return 0; - - if (timeout > BOOTCHART_MAX_TIME_SEC) - timeout = BOOTCHART_MAX_TIME_SEC; - - count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS; - - do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR); - - file_buff_open(log_stat, LOG_STAT); - file_buff_open(log_procs, LOG_PROCS); - file_buff_open(log_disks, LOG_DISK); - - /* create kernel process accounting file */ - { - int fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC,0644); - if (fd >= 0) { - close(fd); - acct( LOG_ACCT ); - } - } - - log_header(); - return count; -} - -/* called each time you want to perform a bootchart sampling op */ -int bootchart_step( void ) -{ - do_log_file(log_stat, "/proc/stat"); - do_log_file(log_disks, "/proc/diskstats"); - do_log_procs(log_procs); - - /* we stop when /data/bootchart-stop contains 1 */ - { - char buff[2]; - if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') { - return -1; - } - } - - return 0; -} - -void bootchart_finish( void ) -{ - unlink( LOG_STOPFILE ); - file_buff_done(log_stat); - file_buff_done(log_disks); - file_buff_done(log_procs); - acct(NULL); -} diff --git a/init/bootchart.h b/init/bootchart.h deleted file mode 100644 index 39d2d4f20..000000000 --- a/init/bootchart.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _BOOTCHART_H -#define _BOOTCHART_H - -#ifndef BOOTCHART -# define BOOTCHART 0 -#endif - -#if BOOTCHART - -extern int bootchart_init(void); -extern int bootchart_step(void); -extern void bootchart_finish(void); - -# define BOOTCHART_POLLING_MS 200 /* polling period in ms */ -# define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */ -# define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */ - -#endif /* BOOTCHART */ - -#endif /* _BOOTCHART_H */ diff --git a/init/builtins.c b/init/builtins.c deleted file mode 100644 index 95fb22304..000000000 --- a/init/builtins.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <linux/kd.h> -#include <errno.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <linux/if.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <sys/mount.h> -#include <sys/resource.h> - -#include "init.h" -#include "keywords.h" -#include "property_service.h" -#include "devices.h" - -#include <private/android_filesystem_config.h> - -void add_environment(const char *name, const char *value); - -extern int init_module(void *, unsigned long, const char *); - -static int write_file(const char *path, const char *value) -{ - int fd, ret, len; - - fd = open(path, O_WRONLY|O_CREAT, 0622); - - if (fd < 0) - return -1; - - len = strlen(value); - - do { - ret = write(fd, value, len); - } while (ret < 0 && errno == EINTR); - - close(fd); - if (ret < 0) { - return -1; - } else { - return 0; - } -} - -static int insmod(const char *filename, char *options) -{ - void *module; - unsigned size; - int ret; - - module = read_file(filename, &size); - if (!module) - return -1; - - ret = init_module(module, size, options); - - free(module); - - return ret; -} - -static int setkey(struct kbentry *kbe) -{ - int fd, ret; - - fd = open("/dev/tty0", O_RDWR | O_SYNC); - if (fd < 0) - return -1; - - ret = ioctl(fd, KDSKBENT, kbe); - - close(fd); - return ret; -} - -static int __ifupdown(const char *interface, int up) -{ - struct ifreq ifr; - int s, ret; - - strlcpy(ifr.ifr_name, interface, IFNAMSIZ); - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - return -1; - - ret = ioctl(s, SIOCGIFFLAGS, &ifr); - if (ret < 0) { - goto done; - } - - if (up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - ret = ioctl(s, SIOCSIFFLAGS, &ifr); - -done: - close(s); - return ret; -} - -static void service_start_if_not_disabled(struct service *svc) -{ - if (!(svc->flags & SVC_DISABLED)) { - service_start(svc); - } -} - -int do_class_start(int nargs, char **args) -{ - /* Starting a class does not start services - * which are explicitly disabled. They must - * be started individually. - */ - service_for_each_class(args[1], service_start_if_not_disabled); - return 0; -} - -int do_class_stop(int nargs, char **args) -{ - service_for_each_class(args[1], service_stop); - return 0; -} - -int do_domainname(int nargs, char **args) -{ - return write_file("/proc/sys/kernel/domainname", args[1]); -} - -int do_exec(int nargs, char **args) -{ - return -1; -} - -int do_export(int nargs, char **args) -{ - add_environment(args[1], args[2]); - return 0; -} - -int do_hostname(int nargs, char **args) -{ - return write_file("/proc/sys/kernel/hostname", args[1]); -} - -int do_ifup(int nargs, char **args) -{ - return __ifupdown(args[1], 1); -} - - -static int do_insmod_inner(int nargs, char **args, int opt_len) -{ - char options[opt_len + 1]; - int i; - - options[0] = '\0'; - if (nargs > 2) { - strcpy(options, args[2]); - for (i = 3; i < nargs; ++i) { - strcat(options, " "); - strcat(options, args[i]); - } - } - - return insmod(args[1], options); -} - -int do_insmod(int nargs, char **args) -{ - int i; - int size = 0; - - if (nargs > 2) { - for (i = 2; i < nargs; ++i) - size += strlen(args[i]) + 1; - } - - return do_insmod_inner(nargs, args, size); -} - -int do_import(int nargs, char **args) -{ - return -1; -} - -int do_mkdir(int nargs, char **args) -{ - mode_t mode = 0755; - - /* mkdir <path> [mode] [owner] [group] */ - - if (nargs >= 3) { - mode = strtoul(args[2], 0, 8); - } - - if (mkdir(args[1], mode)) { - return -errno; - } - - if (nargs >= 4) { - uid_t uid = decode_uid(args[3]); - gid_t gid = -1; - - if (nargs == 5) { - gid = decode_uid(args[4]); - } - - if (chown(args[1], uid, gid)) { - return -errno; - } - } - - return 0; -} - -static struct { - const char *name; - unsigned flag; -} mount_flags[] = { - { "noatime", MS_NOATIME }, - { "nosuid", MS_NOSUID }, - { "nodev", MS_NODEV }, - { "nodiratime", MS_NODIRATIME }, - { "ro", MS_RDONLY }, - { "rw", 0 }, - { "remount", MS_REMOUNT }, - { "defaults", 0 }, - { 0, 0 }, -}; - -/* mount <type> <device> <path> <flags ...> <options> */ -int do_mount(int nargs, char **args) -{ - char tmp[64]; - char *source; - char *options = NULL; - unsigned flags = 0; - int n, i; - - for (n = 4; n < nargs; n++) { - for (i = 0; mount_flags[i].name; i++) { - if (!strcmp(args[n], mount_flags[i].name)) { - flags |= mount_flags[i].flag; - break; - } - } - - /* if our last argument isn't a flag, wolf it up as an option string */ - if (n + 1 == nargs && !mount_flags[i].name) - options = args[n]; - } - - source = args[2]; - if (!strncmp(source, "mtd@", 4)) { - n = mtd_name_to_number(source + 4); - if (n >= 0) { - sprintf(tmp, "/dev/block/mtdblock%d", n); - source = tmp; - } - } - return mount(source, args[3], args[1], flags, options); -} - -int do_setkey(int nargs, char **args) -{ - struct kbentry kbe; - kbe.kb_table = strtoul(args[1], 0, 0); - kbe.kb_index = strtoul(args[2], 0, 0); - kbe.kb_value = strtoul(args[3], 0, 0); - return setkey(&kbe); -} - -int do_setprop(int nargs, char **args) -{ - property_set(args[1], args[2]); - return 0; -} - -int do_setrlimit(int nargs, char **args) -{ - struct rlimit limit; - int resource; - resource = atoi(args[1]); - limit.rlim_cur = atoi(args[2]); - limit.rlim_max = atoi(args[3]); - return setrlimit(resource, &limit); -} - -int do_start(int nargs, char **args) -{ - struct service *svc; - svc = service_find_by_name(args[1]); - if (svc) { - service_start(svc); - } - return 0; -} - -int do_stop(int nargs, char **args) -{ - struct service *svc; - svc = service_find_by_name(args[1]); - if (svc) { - service_stop(svc); - } - return 0; -} - -int do_restart(int nargs, char **args) -{ - struct service *svc; - svc = service_find_by_name(args[1]); - if (svc) { - service_stop(svc); - service_start(svc); - } - return 0; -} - -int do_trigger(int nargs, char **args) -{ - return 0; -} - -int do_symlink(int nargs, char **args) -{ - return symlink(args[1], args[2]); -} - -int do_sysclktz(int nargs, char **args) -{ - struct timezone tz; - - if (nargs != 2) - return -1; - - memset(&tz, 0, sizeof(tz)); - tz.tz_minuteswest = atoi(args[1]); - if (settimeofday(NULL, &tz)) - return -1; - return 0; -} - -int do_write(int nargs, char **args) -{ - return write_file(args[1], args[2]); -} - -int do_chown(int nargs, char **args) { - /* GID is optional. */ - if (nargs == 3) { - if (chown(args[2], decode_uid(args[1]), -1) < 0) - return -errno; - } else if (nargs == 4) { - if (chown(args[3], decode_uid(args[1]), decode_uid(args[2]))) - return -errno; - } else { - return -1; - } - return 0; -} - -static mode_t get_mode(const char *s) { - mode_t mode = 0; - while (*s) { - if (*s >= '0' && *s <= '7') { - mode = (mode<<3) | (*s-'0'); - } else { - return -1; - } - s++; - } - return mode; -} - -int do_chmod(int nargs, char **args) { - mode_t mode = get_mode(args[1]); - if (chmod(args[2], mode) < 0) { - return -errno; - } - return 0; -} - -int do_loglevel(int nargs, char **args) { - if (nargs == 2) { - log_set_level(atoi(args[1])); - return 0; - } - return -1; -} - -int do_device(int nargs, char **args) { - int len; - char tmp[64]; - char *source = args[1]; - int prefix = 0; - - if (nargs != 5) - return -1; - /* Check for wildcard '*' at the end which indicates a prefix. */ - len = strlen(args[1]) - 1; - if (args[1][len] == '*') { - args[1][len] = '\0'; - prefix = 1; - } - /* If path starts with mtd@ lookup the mount number. */ - if (!strncmp(source, "mtd@", 4)) { - int n = mtd_name_to_number(source + 4); - if (n >= 0) { - snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n); - source = tmp; - } - } - add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]), - decode_uid(args[4]), prefix); - return 0; -} diff --git a/init/devices.c b/init/devices.c deleted file mode 100644 index b1ef6ab2a..000000000 --- a/init/devices.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <fcntl.h> -#include <dirent.h> -#include <unistd.h> -#include <string.h> - -#include <sys/socket.h> -#include <sys/un.h> -#include <linux/netlink.h> -#include <private/android_filesystem_config.h> -#include <sys/time.h> -#include <asm/page.h> - -#include "init.h" -#include "devices.h" - -#define CMDLINE_PREFIX "/dev" -#define SYSFS_PREFIX "/sys" -#define FIRMWARE_DIR "/etc/firmware" -#define MAX_QEMU_PERM 6 - -struct uevent { - const char *action; - const char *path; - const char *subsystem; - const char *firmware; - int major; - int minor; -}; - -static int open_uevent_socket(void) -{ - struct sockaddr_nl addr; - int sz = 64*1024; // XXX larger? udev uses 16MB! - int s; - - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = getpid(); - addr.nl_groups = 0xffffffff; - - s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if(s < 0) - return -1; - - setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); - - if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(s); - return -1; - } - - return s; -} - -struct perms_ { - char *name; - mode_t perm; - unsigned int uid; - unsigned int gid; - unsigned short prefix; -}; -static struct perms_ devperms[] = { - { "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 }, - { "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 }, - - /* logger should be world writable (for logging) but not readable */ - { "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 }, - - /* these should not be world writable */ - { "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 }, - { "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 }, - { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, - { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, - { "/dev/uinput", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, - { "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 }, - { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 }, - { "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 }, - { "/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, - { "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 }, - { "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 }, - { "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 }, - { "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, - { "/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 }, - { "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 }, - { "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 }, - { "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 }, - { "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, - { "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, - { "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 }, - { "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 }, - { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 }, - { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 }, - { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 }, - { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 }, - { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, - { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, - { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, - { NULL, 0, 0, 0, 0 }, -}; - -/* devperms_partners list and perm_node are for hardware specific /dev entries */ -struct perm_node { - struct perms_ dp; - struct listnode plist; -}; -list_declare(devperms_partners); - -/* - * Permission override when in emulator mode, must be parsed before - * system properties is initalized. - */ -static int qemu_perm_count; -static struct perms_ qemu_perms[MAX_QEMU_PERM + 1]; - -int add_devperms_partners(const char *name, mode_t perm, unsigned int uid, - unsigned int gid, unsigned short prefix) { - int size; - struct perm_node *node = malloc(sizeof (struct perm_node)); - if (!node) - return -ENOMEM; - - size = strlen(name) + 1; - if ((node->dp.name = malloc(size)) == NULL) - return -ENOMEM; - - memcpy(node->dp.name, name, size); - node->dp.perm = perm; - node->dp.uid = uid; - node->dp.gid = gid; - node->dp.prefix = prefix; - - list_add_tail(&devperms_partners, &node->plist); - return 0; -} - -void qemu_init(void) { - qemu_perm_count = 0; - memset(&qemu_perms, 0, sizeof(qemu_perms)); -} - -static int qemu_perm(const char* name, mode_t perm, unsigned int uid, - unsigned int gid, unsigned short prefix) -{ - char *buf; - if (qemu_perm_count == MAX_QEMU_PERM) - return -ENOSPC; - - buf = malloc(strlen(name) + 1); - if (!buf) - return -errno; - - strlcpy(buf, name, strlen(name) + 1); - qemu_perms[qemu_perm_count].name = buf; - qemu_perms[qemu_perm_count].perm = perm; - qemu_perms[qemu_perm_count].uid = uid; - qemu_perms[qemu_perm_count].gid = gid; - qemu_perms[qemu_perm_count].prefix = prefix; - - qemu_perm_count++; - return 0; -} - -/* Permission overrides for emulator that are parsed from /proc/cmdline. */ -void qemu_cmdline(const char* name, const char *value) -{ - char *buf; - if (!strcmp(name, "android.ril")) { - /* cmd line params currently assume /dev/ prefix */ - if (asprintf(&buf, CMDLINE_PREFIX"/%s", value) == -1) { - return; - } - INFO("nani- buf:: %s\n", buf); - qemu_perm(buf, 0660, AID_RADIO, AID_ROOT, 0); - } -} - -static int get_device_perm_inner(struct perms_ *perms, const char *path, - unsigned *uid, unsigned *gid, mode_t *perm) -{ - int i; - for(i = 0; perms[i].name; i++) { - - if(perms[i].prefix) { - if(strncmp(path, perms[i].name, strlen(perms[i].name))) - continue; - } else { - if(strcmp(path, perms[i].name)) - continue; - } - *uid = perms[i].uid; - *gid = perms[i].gid; - *perm = perms[i].perm; - return 0; - } - return -1; -} - -/* First checks for emulator specific permissions specified in /proc/cmdline. */ -static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) -{ - mode_t perm; - - if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) { - return perm; - } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) { - return perm; - } else { - struct listnode *node; - struct perm_node *perm_node; - struct perms_ *dp; - - /* Check partners list. */ - list_for_each(node, &devperms_partners) { - perm_node = node_to_item(node, struct perm_node, plist); - dp = &perm_node->dp; - - if (dp->prefix) { - if (strncmp(path, dp->name, strlen(dp->name))) - continue; - } else { - if (strcmp(path, dp->name)) - continue; - } - /* Found perm in partner list. */ - *uid = dp->uid; - *gid = dp->gid; - return dp->perm; - } - /* Default if nothing found. */ - *uid = 0; - *gid = 0; - return 0600; - } -} - -static void make_device(const char *path, int block, int major, int minor) -{ - unsigned uid; - unsigned gid; - mode_t mode; - dev_t dev; - - if(major > 255 || minor > 255) - return; - - mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); - dev = (major << 8) | minor; - mknod(path, mode, dev); - chown(path, uid, gid); -} - -#ifdef LOG_UEVENTS - -static inline suseconds_t get_usecs(void) -{ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec; -} - -#define log_event_print(x...) INFO(x) - -#else - -#define log_event_print(fmt, args...) do { } while (0) -#define get_usecs() 0 - -#endif - -static void parse_event(const char *msg, struct uevent *uevent) -{ - uevent->action = ""; - uevent->path = ""; - uevent->subsystem = ""; - uevent->firmware = ""; - uevent->major = -1; - uevent->minor = -1; - - /* currently ignoring SEQNUM */ - while(*msg) { - if(!strncmp(msg, "ACTION=", 7)) { - msg += 7; - uevent->action = msg; - } else if(!strncmp(msg, "DEVPATH=", 8)) { - msg += 8; - uevent->path = msg; - } else if(!strncmp(msg, "SUBSYSTEM=", 10)) { - msg += 10; - uevent->subsystem = msg; - } else if(!strncmp(msg, "FIRMWARE=", 9)) { - msg += 9; - uevent->firmware = msg; - } else if(!strncmp(msg, "MAJOR=", 6)) { - msg += 6; - uevent->major = atoi(msg); - } else if(!strncmp(msg, "MINOR=", 6)) { - msg += 6; - uevent->minor = atoi(msg); - } - - /* advance to after the next \0 */ - while(*msg++) - ; - } - - log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n", - uevent->action, uevent->path, uevent->subsystem, - uevent->firmware, uevent->major, uevent->minor); -} - -static void handle_device_event(struct uevent *uevent) -{ - char devpath[96]; - char *base, *name; - int block; - - /* if it's not a /dev device, nothing to do */ - if((uevent->major < 0) || (uevent->minor < 0)) - return; - - /* do we have a name? */ - name = strrchr(uevent->path, '/'); - if(!name) - return; - name++; - - /* too-long names would overrun our buffer */ - if(strlen(name) > 64) - return; - - /* are we block or char? where should we live? */ - if(!strncmp(uevent->subsystem, "block", 5)) { - block = 1; - base = "/dev/block/"; - mkdir(base, 0755); - } else { - block = 0; - /* this should probably be configurable somehow */ - if(!strncmp(uevent->subsystem, "graphics", 8)) { - base = "/dev/graphics/"; - mkdir(base, 0755); - } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) { - base = "/dev/oncrpc/"; - mkdir(base, 0755); - } else if (!strncmp(uevent->subsystem, "adsp", 4)) { - base = "/dev/adsp/"; - mkdir(base, 0755); - } else if(!strncmp(uevent->subsystem, "input", 5)) { - base = "/dev/input/"; - mkdir(base, 0755); - } else if(!strncmp(uevent->subsystem, "mtd", 3)) { - base = "/dev/mtd/"; - mkdir(base, 0755); - } else if(!strncmp(uevent->subsystem, "misc", 4) && - !strncmp(name, "log_", 4)) { - base = "/dev/log/"; - mkdir(base, 0755); - name += 4; - } else - base = "/dev/"; - } - - snprintf(devpath, sizeof(devpath), "%s%s", base, name); - - if(!strcmp(uevent->action, "add")) { - make_device(devpath, block, uevent->major, uevent->minor); - return; - } - - if(!strcmp(uevent->action, "remove")) { - unlink(devpath); - return; - } -} - -static int load_firmware(int fw_fd, int loading_fd, int data_fd) -{ - struct stat st; - long len_to_copy; - int ret = 0; - - if(fstat(fw_fd, &st) < 0) - return -1; - len_to_copy = st.st_size; - - write(loading_fd, "1", 1); /* start transfer */ - - while (len_to_copy > 0) { - char buf[PAGE_SIZE]; - ssize_t nr; - - nr = read(fw_fd, buf, sizeof(buf)); - if(!nr) - break; - if(nr < 0) { - ret = -1; - break; - } - - len_to_copy -= nr; - while (nr > 0) { - ssize_t nw = 0; - - nw = write(data_fd, buf + nw, nr); - if(nw <= 0) { - ret = -1; - goto out; - } - nr -= nw; - } - } - -out: - if(!ret) - write(loading_fd, "0", 1); /* successful end of transfer */ - else - write(loading_fd, "-1", 2); /* abort transfer */ - - return ret; -} - -static void process_firmware_event(struct uevent *uevent) -{ - char *root, *loading, *data, *file; - int l, loading_fd, data_fd, fw_fd; - - log_event_print("firmware event { '%s', '%s' }\n", - uevent->path, uevent->firmware); - - l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path); - if (l == -1) - return; - - l = asprintf(&loading, "%sloading", root); - if (l == -1) - goto root_free_out; - - l = asprintf(&data, "%sdata", root); - if (l == -1) - goto loading_free_out; - - l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware); - if (l == -1) - goto data_free_out; - - loading_fd = open(loading, O_WRONLY); - if(loading_fd < 0) - goto file_free_out; - - data_fd = open(data, O_WRONLY); - if(data_fd < 0) - goto loading_close_out; - - fw_fd = open(file, O_RDONLY); - if(fw_fd < 0) - goto data_close_out; - - if(!load_firmware(fw_fd, loading_fd, data_fd)) - log_event_print("firmware copy success { '%s', '%s' }\n", root, file); - else - log_event_print("firmware copy failure { '%s', '%s' }\n", root, file); - - close(fw_fd); -data_close_out: - close(data_fd); -loading_close_out: - close(loading_fd); -file_free_out: - free(file); -data_free_out: - free(data); -loading_free_out: - free(loading); -root_free_out: - free(root); -} - -static void handle_firmware_event(struct uevent *uevent) -{ - pid_t pid; - - if(strcmp(uevent->subsystem, "firmware")) - return; - - if(strcmp(uevent->action, "add")) - return; - - /* we fork, to avoid making large memory allocations in init proper */ - pid = fork(); - if (!pid) { - process_firmware_event(uevent); - exit(EXIT_SUCCESS); - } -} - -#define UEVENT_MSG_LEN 1024 -void handle_device_fd(int fd) -{ - char msg[UEVENT_MSG_LEN+2]; - int n; - - while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) { - struct uevent uevent; - - if(n == UEVENT_MSG_LEN) /* overflow -- discard */ - continue; - - msg[n] = '\0'; - msg[n+1] = '\0'; - - parse_event(msg, &uevent); - - handle_device_event(&uevent); - handle_firmware_event(&uevent); - } -} - -/* Coldboot walks parts of the /sys tree and pokes the uevent files -** to cause the kernel to regenerate device add events that happened -** before init's device manager was started -** -** We drain any pending events from the netlink socket every time -** we poke another uevent file to make sure we don't overrun the -** socket's buffer. -*/ - -static void do_coldboot(int event_fd, DIR *d) -{ - struct dirent *de; - int dfd, fd; - - dfd = dirfd(d); - - fd = openat(dfd, "uevent", O_WRONLY); - if(fd >= 0) { - write(fd, "add\n", 4); - close(fd); - handle_device_fd(event_fd); - } - - while((de = readdir(d))) { - DIR *d2; - - if(de->d_type != DT_DIR || de->d_name[0] == '.') - continue; - - fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); - if(fd < 0) - continue; - - d2 = fdopendir(fd); - if(d2 == 0) - close(fd); - else { - do_coldboot(event_fd, d2); - closedir(d2); - } - } -} - -static void coldboot(int event_fd, const char *path) -{ - DIR *d = opendir(path); - if(d) { - do_coldboot(event_fd, d); - closedir(d); - } -} - -int device_init(void) -{ - suseconds_t t0, t1; - int fd; - - fd = open_uevent_socket(); - if(fd < 0) - return -1; - - fcntl(fd, F_SETFD, FD_CLOEXEC); - fcntl(fd, F_SETFL, O_NONBLOCK); - - t0 = get_usecs(); - coldboot(fd, "/sys/class"); - coldboot(fd, "/sys/block"); - coldboot(fd, "/sys/devices"); - t1 = get_usecs(); - - log_event_print("coldboot %ld uS\n", ((long) (t1 - t0))); - - return fd; -} diff --git a/init/devices.h b/init/devices.h deleted file mode 100644 index b484da45e..000000000 --- a/init/devices.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _INIT_DEVICES_H -#define _INIT_DEVICES_H - -extern void handle_device_fd(int fd); -extern int device_init(void); -extern void qemu_init(void); -extern void qemu_cmdline(const char* name, const char *value); -extern int add_devperms_partners(const char *name, mode_t perm, unsigned int uid, - unsigned int gid, unsigned short prefix); - -#endif /* _INIT_DEVICES_H */ diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh deleted file mode 100755 index 7fe890436..000000000 --- a/init/grab-bootchart.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# -# this script is used to retrieve the bootchart log generated -# by init when compiled with INIT_BOOTCHART=true. -# -# for all details, see //device/system/init/README.BOOTCHART -# -TMPDIR=/tmp/android-bootchart -rm -rf $TMPDIR -mkdir -p $TMPDIR - -LOGROOT=/data/bootchart -TARBALL=bootchart.tgz - -FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct" - -for f in $FILES; do - adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null -done -(cd $TMPDIR && tar -czf $TARBALL $FILES) -cp -f $TMPDIR/$TARBALL ./$TARBALL -echo "look at $TARBALL" diff --git a/init/init.c b/init/init.c deleted file mode 100644 index b8b4f4037..000000000 --- a/init/init.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <signal.h> -#include <sys/wait.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/poll.h> -#include <time.h> -#include <errno.h> -#include <stdarg.h> -#include <mtd/mtd-user.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/reboot.h> - -#include <cutils/sockets.h> -#include <termios.h> -#include <linux/kd.h> -#include <linux/keychord.h> - -#include <sys/system_properties.h> - -#include "devices.h" -#include "init.h" -#include "property_service.h" -#include "bootchart.h" - -static int property_triggers_enabled = 0; - -#if BOOTCHART -static int bootchart_count; -#endif - -static char console[32]; -static char serialno[32]; -static char bootmode[32]; -static char baseband[32]; -static char carrier[32]; -static char bootloader[32]; -static char hardware[32]; -static unsigned revision = 0; -static char qemu[32]; -static struct input_keychord *keychords = 0; -static int keychords_count = 0; -static int keychords_length = 0; - -static void drain_action_queue(void); - -static void notify_service_state(const char *name, const char *state) -{ - char pname[PROP_NAME_MAX]; - int len = strlen(name); - if ((len + 10) > PROP_NAME_MAX) - return; - snprintf(pname, sizeof(pname), "init.svc.%s", name); - property_set(pname, state); -} - -static int have_console; -static char *console_name = "/dev/console"; -static time_t process_needs_restart; - -static const char *ENV[32]; - -/* add_environment - add "key=value" to the current environment */ -int add_environment(const char *key, const char *val) -{ - int n; - - for (n = 0; n < 31; n++) { - if (!ENV[n]) { - size_t len = strlen(key) + strlen(val) + 2; - char *entry = malloc(len); - snprintf(entry, len, "%s=%s", key, val); - ENV[n] = entry; - return 0; - } - } - - return 1; -} - -static void zap_stdio(void) -{ - int fd; - fd = open("/dev/null", O_RDWR); - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - close(fd); -} - -static void open_console() -{ - int fd; - if ((fd = open(console_name, O_RDWR)) < 0) { - fd = open("/dev/null", O_RDWR); - } - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - close(fd); -} - -/* - * gettime() - returns the time in seconds of the system's monotonic clock or - * zero on error. - */ -static time_t gettime(void) -{ - struct timespec ts; - int ret; - - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (ret < 0) { - ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno)); - return 0; - } - - return ts.tv_sec; -} - -static void publish_socket(const char *name, int fd) -{ - char key[64] = ANDROID_SOCKET_ENV_PREFIX; - char val[64]; - - strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, - name, - sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); - snprintf(val, sizeof(val), "%d", fd); - add_environment(key, val); - - /* make sure we don't close-on-exec */ - fcntl(fd, F_SETFD, 0); -} - -void service_start(struct service *svc) -{ - struct stat s; - pid_t pid; - int needs_console; - int n; - - /* starting a service removes it from the disabled - * state and immediately takes it out of the restarting - * state if it was in there - */ - svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING)); - svc->time_started = 0; - - /* running processes require no additional work -- if - * they're in the process of exiting, we've ensured - * that they will immediately restart on exit, unless - * they are ONESHOT - */ - if (svc->flags & SVC_RUNNING) { - return; - } - - needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0; - if (needs_console && (!have_console)) { - ERROR("service '%s' requires console\n", svc->name); - svc->flags |= SVC_DISABLED; - return; - } - - if (stat(svc->args[0], &s) != 0) { - ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name); - svc->flags |= SVC_DISABLED; - return; - } - - NOTICE("starting '%s'\n", svc->name); - - pid = fork(); - - if (pid == 0) { - struct socketinfo *si; - struct svcenvinfo *ei; - char tmp[32]; - int fd, sz; - - get_property_workspace(&fd, &sz); - sprintf(tmp, "%d,%d", dup(fd), sz); - add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); - - for (ei = svc->envvars; ei; ei = ei->next) - add_environment(ei->name, ei->value); - - for (si = svc->sockets; si; si = si->next) { - int s = create_socket(si->name, - !strcmp(si->type, "dgram") ? - SOCK_DGRAM : SOCK_STREAM, - si->perm, si->uid, si->gid); - if (s >= 0) { - publish_socket(si->name, s); - } - } - - if (needs_console) { - setsid(); - open_console(); - } else { - zap_stdio(); - } - -#if 0 - for (n = 0; svc->args[n]; n++) { - INFO("args[%d] = '%s'\n", n, svc->args[n]); - } - for (n = 0; ENV[n]; n++) { - INFO("env[%d] = '%s'\n", n, ENV[n]); - } -#endif - - setpgid(0, getpid()); - - /* as requested, set our gid, supplemental gids, and uid */ - if (svc->gid) { - setgid(svc->gid); - } - if (svc->nr_supp_gids) { - setgroups(svc->nr_supp_gids, svc->supp_gids); - } - if (svc->uid) { - setuid(svc->uid); - } - - execve(svc->args[0], (char**) svc->args, (char**) ENV); - _exit(127); - } - - if (pid < 0) { - ERROR("failed to start '%s'\n", svc->name); - svc->pid = 0; - return; - } - - svc->time_started = gettime(); - svc->pid = pid; - svc->flags |= SVC_RUNNING; - - notify_service_state(svc->name, "running"); -} - -void service_stop(struct service *svc) -{ - /* we are no longer running, nor should we - * attempt to restart - */ - svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING)); - - /* if the service has not yet started, prevent - * it from auto-starting with its class - */ - svc->flags |= SVC_DISABLED; - - if (svc->pid) { - NOTICE("service '%s' is being killed\n", svc->name); - kill(-svc->pid, SIGTERM); - notify_service_state(svc->name, "stopping"); - } else { - notify_service_state(svc->name, "stopped"); - } -} - -void property_changed(const char *name, const char *value) -{ - if (property_triggers_enabled) { - queue_property_triggers(name, value); - drain_action_queue(); - } -} - -#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ -#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/ - -static int wait_for_one_process(int block) -{ - pid_t pid; - int status; - struct service *svc; - struct socketinfo *si; - time_t now; - struct listnode *node; - struct command *cmd; - - while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); - if (pid <= 0) return -1; - INFO("waitpid returned pid %d, status = %08x\n", pid, status); - - svc = service_find_by_pid(pid); - if (!svc) { - ERROR("untracked pid %d exited\n", pid); - return 0; - } - - NOTICE("process '%s', pid %d exited\n", svc->name, pid); - - if (!(svc->flags & SVC_ONESHOT)) { - kill(-pid, SIGKILL); - NOTICE("process '%s' killing any children in process group\n", svc->name); - } - - /* remove any sockets we may have created */ - for (si = svc->sockets; si; si = si->next) { - char tmp[128]; - snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name); - unlink(tmp); - } - - svc->pid = 0; - svc->flags &= (~SVC_RUNNING); - - /* oneshot processes go into the disabled state on exit */ - if (svc->flags & SVC_ONESHOT) { - svc->flags |= SVC_DISABLED; - } - - /* disabled processes do not get restarted automatically */ - if (svc->flags & SVC_DISABLED) { - notify_service_state(svc->name, "stopped"); - return 0; - } - - now = gettime(); - if (svc->flags & SVC_CRITICAL) { - if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { - if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { - ERROR("critical process '%s' exited %d times in %d minutes; " - "rebooting into recovery mode\n", svc->name, - CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); - sync(); - __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, "recovery"); - return 0; - } - } else { - svc->time_crashed = now; - svc->nr_crashed = 1; - } - } - - /* Execute all onrestart commands for this service. */ - list_for_each(node, &svc->onrestart.commands) { - cmd = node_to_item(node, struct command, clist); - cmd->func(cmd->nargs, cmd->args); - } - svc->flags |= SVC_RESTARTING; - notify_service_state(svc->name, "restarting"); - return 0; -} - -static void restart_service_if_needed(struct service *svc) -{ - time_t next_start_time = svc->time_started + 5; - - if (next_start_time <= gettime()) { - svc->flags &= (~SVC_RESTARTING); - service_start(svc); - return; - } - - if ((next_start_time < process_needs_restart) || - (process_needs_restart == 0)) { - process_needs_restart = next_start_time; - } -} - -static void restart_processes() -{ - process_needs_restart = 0; - service_for_each_flags(SVC_RESTARTING, - restart_service_if_needed); -} - -static int signal_fd = -1; - -static void sigchld_handler(int s) -{ - write(signal_fd, &s, 1); -} - -static void msg_start(const char *name) -{ - struct service *svc = service_find_by_name(name); - - if (svc) { - service_start(svc); - } else { - ERROR("no such service '%s'\n", name); - } -} - -static void msg_stop(const char *name) -{ - struct service *svc = service_find_by_name(name); - - if (svc) { - service_stop(svc); - } else { - ERROR("no such service '%s'\n"); - } -} - -void handle_control_message(const char *msg, const char *arg) -{ - if (!strcmp(msg,"start")) { - msg_start(arg); - } else if (!strcmp(msg,"stop")) { - msg_stop(arg); - } else { - ERROR("unknown control msg '%s'\n", msg); - } -} - -#define MAX_MTD_PARTITIONS 16 - -static struct { - char name[16]; - int number; -} mtd_part_map[MAX_MTD_PARTITIONS]; - -static int mtd_part_count = -1; - -static void find_mtd_partitions(void) -{ - int fd; - char buf[1024]; - char *pmtdbufp; - ssize_t pmtdsize; - int r; - - fd = open("/proc/mtd", O_RDONLY); - if (fd < 0) - return; - - buf[sizeof(buf) - 1] = '\0'; - pmtdsize = read(fd, buf, sizeof(buf) - 1); - pmtdbufp = buf; - while (pmtdsize > 0) { - int mtdnum, mtdsize, mtderasesize; - char mtdname[16]; - mtdname[0] = '\0'; - mtdnum = -1; - r = sscanf(pmtdbufp, "mtd%d: %x %x %15s", - &mtdnum, &mtdsize, &mtderasesize, mtdname); - if ((r == 4) && (mtdname[0] == '"')) { - char *x = strchr(mtdname + 1, '"'); - if (x) { - *x = 0; - } - INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1); - if (mtd_part_count < MAX_MTD_PARTITIONS) { - strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1); - mtd_part_map[mtd_part_count].number = mtdnum; - mtd_part_count++; - } else { - ERROR("too many mtd partitions\n"); - } - } - while (pmtdsize > 0 && *pmtdbufp != '\n') { - pmtdbufp++; - pmtdsize--; - } - if (pmtdsize > 0) { - pmtdbufp++; - pmtdsize--; - } - } - close(fd); -} - -int mtd_name_to_number(const char *name) -{ - int n; - if (mtd_part_count < 0) { - mtd_part_count = 0; - find_mtd_partitions(); - } - for (n = 0; n < mtd_part_count; n++) { - if (!strcmp(name, mtd_part_map[n].name)) { - return mtd_part_map[n].number; - } - } - return -1; -} - -static void import_kernel_nv(char *name, int in_qemu) -{ - char *value = strchr(name, '='); - - if (value == 0) return; - *value++ = 0; - if (*name == 0) return; - - if (!in_qemu) - { - /* on a real device, white-list the kernel options */ - if (!strcmp(name,"qemu")) { - strlcpy(qemu, value, sizeof(qemu)); - } else if (!strcmp(name,"androidboot.console")) { - strlcpy(console, value, sizeof(console)); - } else if (!strcmp(name,"androidboot.mode")) { - strlcpy(bootmode, value, sizeof(bootmode)); - } else if (!strcmp(name,"androidboot.serialno")) { - strlcpy(serialno, value, sizeof(serialno)); - } else if (!strcmp(name,"androidboot.baseband")) { - strlcpy(baseband, value, sizeof(baseband)); - } else if (!strcmp(name,"androidboot.carrier")) { - strlcpy(carrier, value, sizeof(carrier)); - } else if (!strcmp(name,"androidboot.bootloader")) { - strlcpy(bootloader, value, sizeof(bootloader)); - } else if (!strcmp(name,"androidboot.hardware")) { - strlcpy(hardware, value, sizeof(hardware)); - } else { - qemu_cmdline(name, value); - } - } else { - /* in the emulator, export any kernel option with the - * ro.kernel. prefix */ - char buff[32]; - int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name ); - if (len < (int)sizeof(buff)) { - property_set( buff, value ); - } - } -} - -static void import_kernel_cmdline(int in_qemu) -{ - char cmdline[1024]; - char *ptr; - int fd; - - fd = open("/proc/cmdline", O_RDONLY); - if (fd >= 0) { - int n = read(fd, cmdline, 1023); - if (n < 0) n = 0; - - /* get rid of trailing newline, it happens */ - if (n > 0 && cmdline[n-1] == '\n') n--; - - cmdline[n] = 0; - close(fd); - } else { - cmdline[0] = 0; - } - - ptr = cmdline; - while (ptr && *ptr) { - char *x = strchr(ptr, ' '); - if (x != 0) *x++ = 0; - import_kernel_nv(ptr, in_qemu); - ptr = x; - } - - /* don't expose the raw commandline to nonpriv processes */ - chmod("/proc/cmdline", 0440); -} - -static void get_hardware_name(void) -{ - char data[1024]; - int fd, n; - char *x, *hw, *rev; - - /* Hardware string was provided on kernel command line */ - if (hardware[0]) - return; - - fd = open("/proc/cpuinfo", O_RDONLY); - if (fd < 0) return; - - n = read(fd, data, 1023); - close(fd); - if (n < 0) return; - - data[n] = 0; - hw = strstr(data, "\nHardware"); - rev = strstr(data, "\nRevision"); - - if (hw) { - x = strstr(hw, ": "); - if (x) { - x += 2; - n = 0; - while (*x && !isspace(*x)) { - hardware[n++] = tolower(*x); - x++; - if (n == 31) break; - } - hardware[n] = 0; - } - } - - if (rev) { - x = strstr(rev, ": "); - if (x) { - revision = strtoul(x + 2, 0, 16); - } - } -} - -static void drain_action_queue(void) -{ - struct listnode *node; - struct command *cmd; - struct action *act; - int ret; - - while ((act = action_remove_queue_head())) { - INFO("processing action %p (%s)\n", act, act->name); - list_for_each(node, &act->commands) { - cmd = node_to_item(node, struct command, clist); - ret = cmd->func(cmd->nargs, cmd->args); - INFO("command '%s' r=%d\n", cmd->args[0], ret); - } - } -} - -void open_devnull_stdio(void) -{ - int fd; - static const char *name = "/dev/__null__"; - if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { - fd = open(name, O_RDWR); - unlink(name); - if (fd >= 0) { - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - if (fd > 2) { - close(fd); - } - return; - } - } - - exit(1); -} - -void add_service_keycodes(struct service *svc) -{ - struct input_keychord *keychord; - int i, size; - - if (svc->keycodes) { - /* add a new keychord to the list */ - size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]); - keychords = realloc(keychords, keychords_length + size); - if (!keychords) { - ERROR("could not allocate keychords\n"); - keychords_length = 0; - keychords_count = 0; - return; - } - - keychord = (struct input_keychord *)((char *)keychords + keychords_length); - keychord->version = KEYCHORD_VERSION; - keychord->id = keychords_count + 1; - keychord->count = svc->nkeycodes; - svc->keychord_id = keychord->id; - - for (i = 0; i < svc->nkeycodes; i++) { - keychord->keycodes[i] = svc->keycodes[i]; - } - keychords_count++; - keychords_length += size; - } -} - -int open_keychord() -{ - int fd, ret; - - service_for_each(add_service_keycodes); - - /* nothing to do if no services require keychords */ - if (!keychords) - return -1; - - fd = open("/dev/keychord", O_RDWR); - if (fd < 0) { - ERROR("could not open /dev/keychord\n"); - return fd; - } - fcntl(fd, F_SETFD, FD_CLOEXEC); - - ret = write(fd, keychords, keychords_length); - if (ret != keychords_length) { - ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno); - close(fd); - fd = -1; - } - - free(keychords); - keychords = 0; - - return fd; -} - -void handle_keychord(int fd) -{ - struct service *svc; - int ret; - __u16 id; - - ret = read(fd, &id, sizeof(id)); - if (ret != sizeof(id)) { - ERROR("could not read keychord id\n"); - return; - } - - svc = service_find_by_keychord(id); - if (svc) { - INFO("starting service %s from keychord\n", svc->name); - service_start(svc); - } else { - ERROR("service for keychord %d not found\n", id); - } -} - -int main(int argc, char **argv) -{ - int device_fd = -1; - int property_set_fd = -1; - int signal_recv_fd = -1; - int keychord_fd = -1; - int fd_count; - int s[2]; - int fd; - struct sigaction act; - char tmp[PROP_VALUE_MAX]; - struct pollfd ufds[4]; - char *tmpdev; - char* debuggable; - - act.sa_handler = sigchld_handler; - act.sa_flags = SA_NOCLDSTOP; - act.sa_mask = 0; - act.sa_restorer = NULL; - sigaction(SIGCHLD, &act, 0); - - /* clear the umask */ - umask(0); - - /* Get the basic filesystem setup we need put - * together in the initramdisk on / and then we'll - * let the rc file figure out the rest. - */ - mkdir("/dev", 0755); - mkdir("/proc", 0755); - mkdir("/sys", 0755); - - mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); - mkdir("/dev/pts", 0755); - mkdir("/dev/socket", 0755); - mount("devpts", "/dev/pts", "devpts", 0, NULL); - mount("proc", "/proc", "proc", 0, NULL); - mount("sysfs", "/sys", "sysfs", 0, NULL); - - /* We must have some place other than / to create the - * device nodes for kmsg and null, otherwise we won't - * be able to remount / read-only later on. - * Now that tmpfs is mounted on /dev, we can actually - * talk to the outside world. - */ - open_devnull_stdio(); - log_init(); - - INFO("reading config file\n"); - parse_config_file("/init.rc"); - - /* pull the kernel commandline and ramdisk properties file in */ - qemu_init(); - import_kernel_cmdline(0); - - get_hardware_name(); - snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); - parse_config_file(tmp); - - action_for_each_trigger("early-init", action_add_queue_tail); - drain_action_queue(); - - INFO("device init\n"); - device_fd = device_init(); - - property_init(); - - // only listen for keychords if ro.debuggable is true - debuggable = property_get("ro.debuggable"); - if (debuggable && !strcmp(debuggable, "1")) { - keychord_fd = open_keychord(); - } - - if (console[0]) { - snprintf(tmp, sizeof(tmp), "/dev/%s", console); - console_name = strdup(tmp); - } - - fd = open(console_name, O_RDWR); - if (fd >= 0) - have_console = 1; - close(fd); - - if( load_565rle_image(INIT_IMAGE_FILE) ) { - fd = open("/dev/tty0", O_WRONLY); - if (fd >= 0) { - const char *msg; - msg = "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" // console is 40 cols x 30 lines - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - " A N D R O I D "; - write(fd, msg, strlen(msg)); - close(fd); - } - } - - if (qemu[0]) - import_kernel_cmdline(1); - - if (!strcmp(bootmode,"factory")) - property_set("ro.factorytest", "1"); - else if (!strcmp(bootmode,"factory2")) - property_set("ro.factorytest", "2"); - else - property_set("ro.factorytest", "0"); - - property_set("ro.serialno", serialno[0] ? serialno : ""); - property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); - property_set("ro.baseband", baseband[0] ? baseband : "unknown"); - property_set("ro.carrier", carrier[0] ? carrier : "unknown"); - property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown"); - - property_set("ro.hardware", hardware); - snprintf(tmp, PROP_VALUE_MAX, "%d", revision); - property_set("ro.revision", tmp); - - /* execute all the boot actions to get us started */ - action_for_each_trigger("init", action_add_queue_tail); - drain_action_queue(); - - /* read any property files on system or data and - * fire up the property service. This must happen - * after the ro.foo properties are set above so - * that /data/local.prop cannot interfere with them. - */ - property_set_fd = start_property_service(); - - /* create a signalling mechanism for the sigchld handler */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { - signal_fd = s[0]; - signal_recv_fd = s[1]; - fcntl(s[0], F_SETFD, FD_CLOEXEC); - fcntl(s[0], F_SETFL, O_NONBLOCK); - fcntl(s[1], F_SETFD, FD_CLOEXEC); - fcntl(s[1], F_SETFL, O_NONBLOCK); - } - - /* make sure we actually have all the pieces we need */ - if ((device_fd < 0) || - (property_set_fd < 0) || - (signal_recv_fd < 0)) { - ERROR("init startup failure\n"); - return 1; - } - - /* execute all the boot actions to get us started */ - action_for_each_trigger("early-boot", action_add_queue_tail); - action_for_each_trigger("boot", action_add_queue_tail); - drain_action_queue(); - - /* run all property triggers based on current state of the properties */ - queue_all_property_triggers(); - drain_action_queue(); - - /* enable property triggers */ - property_triggers_enabled = 1; - - ufds[0].fd = device_fd; - ufds[0].events = POLLIN; - ufds[1].fd = property_set_fd; - ufds[1].events = POLLIN; - ufds[2].fd = signal_recv_fd; - ufds[2].events = POLLIN; - fd_count = 3; - - if (keychord_fd > 0) { - ufds[3].fd = keychord_fd; - ufds[3].events = POLLIN; - fd_count++; - } else { - ufds[3].events = 0; - ufds[3].revents = 0; - } - -#if BOOTCHART - bootchart_count = bootchart_init(); - if (bootchart_count < 0) { - ERROR("bootcharting init failure\n"); - } else if (bootchart_count > 0) { - NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS); - } else { - NOTICE("bootcharting ignored\n"); - } -#endif - - for(;;) { - int nr, i, timeout = -1; - - for (i = 0; i < fd_count; i++) - ufds[i].revents = 0; - - drain_action_queue(); - restart_processes(); - - if (process_needs_restart) { - timeout = (process_needs_restart - gettime()) * 1000; - if (timeout < 0) - timeout = 0; - } - -#if BOOTCHART - if (bootchart_count > 0) { - if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) - timeout = BOOTCHART_POLLING_MS; - if (bootchart_step() < 0 || --bootchart_count == 0) { - bootchart_finish(); - bootchart_count = 0; - } - } -#endif - nr = poll(ufds, fd_count, timeout); - if (nr <= 0) - continue; - - if (ufds[2].revents == POLLIN) { - /* we got a SIGCHLD - reap and restart as needed */ - read(signal_recv_fd, tmp, sizeof(tmp)); - while (!wait_for_one_process(0)) - ; - continue; - } - - if (ufds[0].revents == POLLIN) - handle_device_fd(device_fd); - - if (ufds[1].revents == POLLIN) - handle_property_set_fd(property_set_fd); - if (ufds[3].revents == POLLIN) - handle_keychord(keychord_fd); - } - - return 0; -} diff --git a/init/init.h b/init/init.h deleted file mode 100644 index b68686930..000000000 --- a/init/init.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _INIT_INIT_H -#define _INIT_INIT_H - -int mtd_name_to_number(const char *name); - -void handle_control_message(const char *msg, const char *arg); - -int create_socket(const char *name, int type, mode_t perm, - uid_t uid, gid_t gid); - -void *read_file(const char *fn, unsigned *_sz); - -void log_init(void); -void log_set_level(int level); -void log_close(void); -void log_write(int level, const char *fmt, ...); - -#define ERROR(x...) log_write(3, "<3>init: " x) -#define NOTICE(x...) log_write(5, "<5>init: " x) -#define INFO(x...) log_write(6, "<6>init: " x) - -#define LOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */ -#define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */ - -unsigned int decode_uid(const char *s); - -struct listnode -{ - struct listnode *next; - struct listnode *prev; -}; - -#define node_to_item(node, container, member) \ - (container *) (((char*) (node)) - offsetof(container, member)) - -#define list_declare(name) \ - struct listnode name = { \ - .next = &name, \ - .prev = &name, \ - } - -#define list_for_each(node, list) \ - for (node = (list)->next; node != (list); node = node->next) - -void list_init(struct listnode *list); -void list_add_tail(struct listnode *list, struct listnode *item); -void list_remove(struct listnode *item); - -#define list_empty(list) ((list) == (list)->next) -#define list_head(list) ((list)->next) -#define list_tail(list) ((list)->prev) - -struct command -{ - /* list of commands in an action */ - struct listnode clist; - - int (*func)(int nargs, char **args); - int nargs; - char *args[1]; -}; - -struct action { - /* node in list of all actions */ - struct listnode alist; - /* node in the queue of pending actions */ - struct listnode qlist; - /* node in list of actions for a trigger */ - struct listnode tlist; - - unsigned hash; - const char *name; - - struct listnode commands; - struct command *current; -}; - -struct socketinfo { - struct socketinfo *next; - const char *name; - const char *type; - uid_t uid; - gid_t gid; - int perm; -}; - -struct svcenvinfo { - struct svcenvinfo *next; - const char *name; - const char *value; -}; - -#define SVC_DISABLED 0x01 /* do not autostart with class */ -#define SVC_ONESHOT 0x02 /* do not restart on exit */ -#define SVC_RUNNING 0x04 /* currently active */ -#define SVC_RESTARTING 0x08 /* waiting to restart */ -#define SVC_CONSOLE 0x10 /* requires console */ -#define SVC_CRITICAL 0x20 /* will reboot into recovery if keeps crashing */ - -#define NR_SVC_SUPP_GIDS 6 /* six supplementary groups */ - -struct service { - /* list of all services */ - struct listnode slist; - - const char *name; - const char *classname; - - unsigned flags; - pid_t pid; - time_t time_started; /* time of last start */ - time_t time_crashed; /* first crash within inspection window */ - int nr_crashed; /* number of times crashed within window */ - - uid_t uid; - gid_t gid; - gid_t supp_gids[NR_SVC_SUPP_GIDS]; - size_t nr_supp_gids; - - struct socketinfo *sockets; - struct svcenvinfo *envvars; - - int nargs; - char *args[1]; - struct action onrestart; /* Actions to execute on restart. */ - - /* keycodes for triggering this service via /dev/keychord */ - int *keycodes; - int nkeycodes; - int keychord_id; -}; - -int parse_config_file(const char *fn); - -struct service *service_find_by_name(const char *name); -struct service *service_find_by_pid(pid_t pid); -struct service *service_find_by_keychord(int keychord_id); -void service_for_each(void (*func)(struct service *svc)); -void service_for_each_class(const char *classname, - void (*func)(struct service *svc)); -void service_for_each_flags(unsigned matchflags, - void (*func)(struct service *svc)); -void service_stop(struct service *svc); -void service_start(struct service *svc); -void property_changed(const char *name, const char *value); - -struct action *action_remove_queue_head(void); -void action_add_queue_tail(struct action *act); -void action_for_each_trigger(const char *trigger, - void (*func)(struct action *act)); -void queue_property_triggers(const char *name, const char *value); -void queue_all_property_triggers(); - -#define INIT_IMAGE_FILE "/initlogo.rle" - -int load_565rle_image( char *file_name ); - -#endif /* _INIT_INIT_H */ diff --git a/init/keywords.h b/init/keywords.h deleted file mode 100644 index 6f47379c6..000000000 --- a/init/keywords.h +++ /dev/null @@ -1,78 +0,0 @@ - -#ifndef KEYWORD -int do_class_start(int nargs, char **args); -int do_class_stop(int nargs, char **args); -int do_domainname(int nargs, char **args); -int do_exec(int nargs, char **args); -int do_export(int nargs, char **args); -int do_hostname(int nargs, char **args); -int do_ifup(int nargs, char **args); -int do_insmod(int nargs, char **args); -int do_import(int nargs, char **args); -int do_mkdir(int nargs, char **args); -int do_mount(int nargs, char **args); -int do_restart(int nargs, char **args); -int do_setkey(int nargs, char **args); -int do_setprop(int nargs, char **args); -int do_setrlimit(int nargs, char **args); -int do_start(int nargs, char **args); -int do_stop(int nargs, char **args); -int do_trigger(int nargs, char **args); -int do_symlink(int nargs, char **args); -int do_sysclktz(int nargs, char **args); -int do_write(int nargs, char **args); -int do_chown(int nargs, char **args); -int do_chmod(int nargs, char **args); -int do_loglevel(int nargs, char **args); -int do_device(int nargs, char **args); -#define __MAKE_KEYWORD_ENUM__ -#define KEYWORD(symbol, flags, nargs, func) K_##symbol, -enum { - K_UNKNOWN, -#endif - KEYWORD(capability, OPTION, 0, 0) - KEYWORD(class, OPTION, 0, 0) - KEYWORD(class_start, COMMAND, 1, do_class_start) - KEYWORD(class_stop, COMMAND, 1, do_class_stop) - KEYWORD(console, OPTION, 0, 0) - KEYWORD(critical, OPTION, 0, 0) - KEYWORD(disabled, OPTION, 0, 0) - KEYWORD(domainname, COMMAND, 1, do_domainname) - KEYWORD(exec, COMMAND, 1, do_exec) - KEYWORD(export, COMMAND, 2, do_export) - KEYWORD(group, OPTION, 0, 0) - KEYWORD(hostname, COMMAND, 1, do_hostname) - KEYWORD(ifup, COMMAND, 1, do_ifup) - KEYWORD(insmod, COMMAND, 1, do_insmod) - KEYWORD(import, COMMAND, 1, do_import) - KEYWORD(keycodes, OPTION, 0, 0) - KEYWORD(mkdir, COMMAND, 1, do_mkdir) - KEYWORD(mount, COMMAND, 3, do_mount) - KEYWORD(on, SECTION, 0, 0) - KEYWORD(oneshot, OPTION, 0, 0) - KEYWORD(onrestart, OPTION, 0, 0) - KEYWORD(restart, COMMAND, 1, do_restart) - KEYWORD(service, SECTION, 0, 0) - KEYWORD(setenv, OPTION, 2, 0) - KEYWORD(setkey, COMMAND, 0, do_setkey) - KEYWORD(setprop, COMMAND, 2, do_setprop) - KEYWORD(setrlimit, COMMAND, 3, do_setrlimit) - KEYWORD(socket, OPTION, 0, 0) - KEYWORD(start, COMMAND, 1, do_start) - KEYWORD(stop, COMMAND, 1, do_stop) - KEYWORD(trigger, COMMAND, 1, do_trigger) - KEYWORD(symlink, COMMAND, 1, do_symlink) - KEYWORD(sysclktz, COMMAND, 1, do_sysclktz) - KEYWORD(user, OPTION, 0, 0) - KEYWORD(write, COMMAND, 2, do_write) - KEYWORD(chown, COMMAND, 2, do_chown) - KEYWORD(chmod, COMMAND, 2, do_chmod) - KEYWORD(loglevel, COMMAND, 1, do_loglevel) - KEYWORD(device, COMMAND, 4, do_device) -#ifdef __MAKE_KEYWORD_ENUM__ - KEYWORD_COUNT, -}; -#undef __MAKE_KEYWORD_ENUM__ -#undef KEYWORD -#endif - diff --git a/init/logo.c b/init/logo.c deleted file mode 100644 index 6a740bfd6..000000000 --- a/init/logo.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <linux/fb.h> -#include <linux/kd.h> - -#include "init.h" - -#ifdef ANDROID -#include <cutils/memory.h> -#else -void android_memset16(void *_ptr, unsigned short val, unsigned count) -{ - unsigned short *ptr = _ptr; - count >>= 1; - while(count--) - *ptr++ = val; -} -#endif - -struct FB { - unsigned short *bits; - unsigned size; - int fd; - struct fb_fix_screeninfo fi; - struct fb_var_screeninfo vi; -}; - -#define fb_width(fb) ((fb)->vi.xres) -#define fb_height(fb) ((fb)->vi.yres) -#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2) - -static int fb_open(struct FB *fb) -{ - fb->fd = open("/dev/graphics/fb0", O_RDWR); - if (fb->fd < 0) - return -1; - - if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) - goto fail; - if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) - goto fail; - - fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, - MAP_SHARED, fb->fd, 0); - if (fb->bits == MAP_FAILED) - goto fail; - - return 0; - -fail: - close(fb->fd); - return -1; -} - -static void fb_close(struct FB *fb) -{ - munmap(fb->bits, fb_size(fb)); - close(fb->fd); -} - -/* there's got to be a more portable way to do this ... */ -static void fb_update(struct FB *fb) -{ - fb->vi.yoffset = 1; - ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); - fb->vi.yoffset = 0; - ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); -} - -static int vt_set_mode(int graphics) -{ - int fd, r; - fd = open("/dev/tty0", O_RDWR | O_SYNC); - if (fd < 0) - return -1; - r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT)); - close(fd); - return r; -} - -/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ - -int load_565rle_image(char *fn) -{ - struct FB fb; - struct stat s; - unsigned short *data, *bits, *ptr; - unsigned count, max; - int fd; - - if (vt_set_mode(1)) - return -1; - - fd = open(fn, O_RDONLY); - if (fd < 0) { - ERROR("cannot open '%s'\n", fn); - goto fail_restore_text; - } - - if (fstat(fd, &s) < 0) { - goto fail_close_file; - } - - data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) - goto fail_close_file; - - if (fb_open(&fb)) - goto fail_unmap_data; - - max = fb_width(&fb) * fb_height(&fb); - ptr = data; - count = s.st_size; - bits = fb.bits; - while (count > 3) { - unsigned n = ptr[0]; - if (n > max) - break; - android_memset16(bits, ptr[1], n << 1); - bits += n; - max -= n; - ptr += 2; - count -= 4; - } - - munmap(data, s.st_size); - fb_update(&fb); - fb_close(&fb); - close(fd); - unlink(fn); - return 0; - -fail_unmap_data: - munmap(data, s.st_size); -fail_close_file: - close(fd); -fail_restore_text: - vt_set_mode(0); - return -1; -} - diff --git a/init/parser.c b/init/parser.c deleted file mode 100644 index 6a22d242d..000000000 --- a/init/parser.c +++ /dev/null @@ -1,797 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdarg.h> -#include <string.h> -#include <stddef.h> -#include <ctype.h> - -#include "init.h" -#include "property_service.h" - -#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ -#include <sys/_system_properties.h> - -static list_declare(service_list); -static list_declare(action_list); -static list_declare(action_queue); - -#define RAW(x...) log_write(6, x) - -void DUMP(void) -{ -#if 0 - struct service *svc; - struct action *act; - struct command *cmd; - struct listnode *node; - struct listnode *node2; - struct socketinfo *si; - int n; - - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - RAW("service %s\n", svc->name); - RAW(" class '%s'\n", svc->classname); - RAW(" exec"); - for (n = 0; n < svc->nargs; n++) { - RAW(" '%s'", svc->args[n]); - } - RAW("\n"); - for (si = svc->sockets; si; si = si->next) { - RAW(" socket %s %s 0%o\n", si->name, si->type, si->perm); - } - } - - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - RAW("on %s\n", act->name); - list_for_each(node2, &act->commands) { - cmd = node_to_item(node2, struct command, clist); - RAW(" %p", cmd->func); - for (n = 0; n < cmd->nargs; n++) { - RAW(" %s", cmd->args[n]); - } - RAW("\n"); - } - RAW("\n"); - } -#endif -} - -#define MAXARGS 64 - -#define T_EOF 0 -#define T_TEXT 1 -#define T_NEWLINE 2 - -struct parse_state -{ - char *ptr; - char *text; - int line; - int nexttoken; - void *context; - void (*parse_line)(struct parse_state *state, int nargs, char **args); - const char *filename; -}; - -static void *parse_service(struct parse_state *state, int nargs, char **args); -static void parse_line_service(struct parse_state *state, int nargs, char **args); - -static void *parse_action(struct parse_state *state, int nargs, char **args); -static void parse_line_action(struct parse_state *state, int nargs, char **args); - -void parse_error(struct parse_state *state, const char *fmt, ...) -{ - va_list ap; - char buf[128]; - int off; - - snprintf(buf, 128, "%s: %d: ", state->filename, state->line); - buf[127] = 0; - off = strlen(buf); - - va_start(ap, fmt); - vsnprintf(buf + off, 128 - off, fmt, ap); - va_end(ap); - buf[127] = 0; - ERROR("%s", buf); -} - -#define SECTION 0x01 -#define COMMAND 0x02 -#define OPTION 0x04 - -#include "keywords.h" - -#define KEYWORD(symbol, flags, nargs, func) \ - [ K_##symbol ] = { #symbol, func, nargs + 1, flags, }, - -struct { - const char *name; - int (*func)(int nargs, char **args); - unsigned char nargs; - unsigned char flags; -} keyword_info[KEYWORD_COUNT] = { - [ K_UNKNOWN ] = { "unknown", 0, 0, 0 }, -#include "keywords.h" -}; -#undef KEYWORD - -#define kw_is(kw, type) (keyword_info[kw].flags & (type)) -#define kw_name(kw) (keyword_info[kw].name) -#define kw_func(kw) (keyword_info[kw].func) -#define kw_nargs(kw) (keyword_info[kw].nargs) - -int lookup_keyword(const char *s) -{ - switch (*s++) { - case 'c': - if (!strcmp(s, "apability")) return K_capability; - if (!strcmp(s, "lass")) return K_class; - if (!strcmp(s, "lass_start")) return K_class_start; - if (!strcmp(s, "lass_stop")) return K_class_stop; - if (!strcmp(s, "onsole")) return K_console; - if (!strcmp(s, "hown")) return K_chown; - if (!strcmp(s, "hmod")) return K_chmod; - if (!strcmp(s, "ritical")) return K_critical; - break; - case 'd': - if (!strcmp(s, "isabled")) return K_disabled; - if (!strcmp(s, "omainname")) return K_domainname; - if (!strcmp(s, "evice")) return K_device; - break; - case 'e': - if (!strcmp(s, "xec")) return K_exec; - if (!strcmp(s, "xport")) return K_export; - break; - case 'g': - if (!strcmp(s, "roup")) return K_group; - break; - case 'h': - if (!strcmp(s, "ostname")) return K_hostname; - break; - case 'i': - if (!strcmp(s, "fup")) return K_ifup; - if (!strcmp(s, "nsmod")) return K_insmod; - if (!strcmp(s, "mport")) return K_import; - break; - case 'k': - if (!strcmp(s, "eycodes")) return K_keycodes; - break; - case 'l': - if (!strcmp(s, "oglevel")) return K_loglevel; - break; - case 'm': - if (!strcmp(s, "kdir")) return K_mkdir; - if (!strcmp(s, "ount")) return K_mount; - break; - case 'o': - if (!strcmp(s, "n")) return K_on; - if (!strcmp(s, "neshot")) return K_oneshot; - if (!strcmp(s, "nrestart")) return K_onrestart; - break; - case 'r': - if (!strcmp(s, "estart")) return K_restart; - break; - case 's': - if (!strcmp(s, "ervice")) return K_service; - if (!strcmp(s, "etenv")) return K_setenv; - if (!strcmp(s, "etkey")) return K_setkey; - if (!strcmp(s, "etprop")) return K_setprop; - if (!strcmp(s, "etrlimit")) return K_setrlimit; - if (!strcmp(s, "ocket")) return K_socket; - if (!strcmp(s, "tart")) return K_start; - if (!strcmp(s, "top")) return K_stop; - if (!strcmp(s, "ymlink")) return K_symlink; - if (!strcmp(s, "ysclktz")) return K_sysclktz; - break; - case 't': - if (!strcmp(s, "rigger")) return K_trigger; - break; - case 'u': - if (!strcmp(s, "ser")) return K_user; - break; - case 'w': - if (!strcmp(s, "rite")) return K_write; - break; - } - return K_UNKNOWN; -} - -void parse_line_no_op(struct parse_state *state, int nargs, char **args) -{ -} - -int next_token(struct parse_state *state) -{ - char *x = state->ptr; - char *s; - - if (state->nexttoken) { - int t = state->nexttoken; - state->nexttoken = 0; - return t; - } - - for (;;) { - switch (*x) { - case 0: - state->ptr = x; - return T_EOF; - case '\n': - state->line++; - x++; - state->ptr = x; - return T_NEWLINE; - case ' ': - case '\t': - case '\r': - x++; - continue; - case '#': - while (*x && (*x != '\n')) x++; - state->line++; - state->ptr = x; - return T_NEWLINE; - default: - goto text; - } - } - -textdone: - state->ptr = x; - *s = 0; - return T_TEXT; -text: - state->text = s = x; -textresume: - for (;;) { - switch (*x) { - case 0: - goto textdone; - case ' ': - case '\t': - case '\r': - x++; - goto textdone; - case '\n': - state->nexttoken = T_NEWLINE; - x++; - goto textdone; - case '"': - x++; - for (;;) { - switch (*x) { - case 0: - /* unterminated quoted thing */ - state->ptr = x; - return T_EOF; - case '"': - x++; - goto textresume; - default: - *s++ = *x++; - } - } - break; - case '\\': - x++; - switch (*x) { - case 0: - goto textdone; - case 'n': - *s++ = '\n'; - break; - case 'r': - *s++ = '\r'; - break; - case 't': - *s++ = '\t'; - break; - case '\\': - *s++ = '\\'; - break; - case '\r': - /* \ <cr> <lf> -> line continuation */ - if (x[1] != '\n') { - x++; - continue; - } - case '\n': - /* \ <lf> -> line continuation */ - state->line++; - x++; - /* eat any extra whitespace */ - while((*x == ' ') || (*x == '\t')) x++; - continue; - default: - /* unknown escape -- just copy */ - *s++ = *x++; - } - continue; - default: - *s++ = *x++; - } - } - return T_EOF; -} - -void parse_line(int nargs, char **args) -{ - int n; - int id = lookup_keyword(args[0]); - printf("%s(%d)", args[0], id); - for (n = 1; n < nargs; n++) { - printf(" '%s'", args[n]); - } - printf("\n"); -} - -void parse_new_section(struct parse_state *state, int kw, - int nargs, char **args) -{ - printf("[ %s %s ]\n", args[0], - nargs > 1 ? args[1] : ""); - switch(kw) { - case K_service: - state->context = parse_service(state, nargs, args); - if (state->context) { - state->parse_line = parse_line_service; - return; - } - break; - case K_on: - state->context = parse_action(state, nargs, args); - if (state->context) { - state->parse_line = parse_line_action; - return; - } - break; - } - state->parse_line = parse_line_no_op; -} - -static void parse_config(const char *fn, char *s) -{ - struct parse_state state; - char *args[MAXARGS]; - int nargs; - - nargs = 0; - state.filename = fn; - state.line = 1; - state.ptr = s; - state.nexttoken = 0; - state.parse_line = parse_line_no_op; - for (;;) { - switch (next_token(&state)) { - case T_EOF: - state.parse_line(&state, 0, 0); - return; - case T_NEWLINE: - if (nargs) { - int kw = lookup_keyword(args[0]); - if (kw_is(kw, SECTION)) { - state.parse_line(&state, 0, 0); - parse_new_section(&state, kw, nargs, args); - } else { - state.parse_line(&state, nargs, args); - } - nargs = 0; - } - break; - case T_TEXT: - if (nargs < MAXARGS) { - args[nargs++] = state.text; - } - break; - } - } -} - -int parse_config_file(const char *fn) -{ - char *data; - data = read_file(fn, 0); - if (!data) return -1; - - parse_config(fn, data); - DUMP(); - return 0; -} - -static int valid_name(const char *name) -{ - if (strlen(name) > 16) { - return 0; - } - while (*name) { - if (!isalnum(*name) && (*name != '_') && (*name != '-')) { - return 0; - } - name++; - } - return 1; -} - -struct service *service_find_by_name(const char *name) -{ - struct listnode *node; - struct service *svc; - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - if (!strcmp(svc->name, name)) { - return svc; - } - } - return 0; -} - -struct service *service_find_by_pid(pid_t pid) -{ - struct listnode *node; - struct service *svc; - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - if (svc->pid == pid) { - return svc; - } - } - return 0; -} - -struct service *service_find_by_keychord(int keychord_id) -{ - struct listnode *node; - struct service *svc; - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - if (svc->keychord_id == keychord_id) { - return svc; - } - } - return 0; -} - -void service_for_each(void (*func)(struct service *svc)) -{ - struct listnode *node; - struct service *svc; - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - func(svc); - } -} - -void service_for_each_class(const char *classname, - void (*func)(struct service *svc)) -{ - struct listnode *node; - struct service *svc; - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - if (!strcmp(svc->classname, classname)) { - func(svc); - } - } -} - -void service_for_each_flags(unsigned matchflags, - void (*func)(struct service *svc)) -{ - struct listnode *node; - struct service *svc; - list_for_each(node, &service_list) { - svc = node_to_item(node, struct service, slist); - if (svc->flags & matchflags) { - func(svc); - } - } -} - -void action_for_each_trigger(const char *trigger, - void (*func)(struct action *act)) -{ - struct listnode *node; - struct action *act; - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - if (!strcmp(act->name, trigger)) { - func(act); - } - } -} - -void queue_property_triggers(const char *name, const char *value) -{ - struct listnode *node; - struct action *act; - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - if (!strncmp(act->name, "property:", strlen("property:"))) { - const char *test = act->name + strlen("property:"); - int name_length = strlen(name); - - if (!strncmp(name, test, name_length) && - test[name_length] == '=' && - !strcmp(test + name_length + 1, value)) { - action_add_queue_tail(act); - } - } - } -} - -void queue_all_property_triggers() -{ - struct listnode *node; - struct action *act; - list_for_each(node, &action_list) { - act = node_to_item(node, struct action, alist); - if (!strncmp(act->name, "property:", strlen("property:"))) { - /* parse property name and value - syntax is property:<name>=<value> */ - const char* name = act->name + strlen("property:"); - const char* equals = strchr(name, '='); - if (equals) { - char* prop_name[PROP_NAME_MAX + 1]; - const char* value; - int length = equals - name; - if (length > PROP_NAME_MAX) { - ERROR("property name too long in trigger %s", act->name); - } else { - memcpy(prop_name, name, length); - prop_name[length] = 0; - - /* does the property exist, and match the trigger value? */ - value = property_get((const char *)&prop_name[0]); - if (value && !strcmp(equals + 1, value)) { - action_add_queue_tail(act); - } - } - } - } - } -} - -void action_add_queue_tail(struct action *act) -{ - list_add_tail(&action_queue, &act->qlist); -} - -struct action *action_remove_queue_head(void) -{ - if (list_empty(&action_queue)) { - return 0; - } else { - struct listnode *node = list_head(&action_queue); - struct action *act = node_to_item(node, struct action, qlist); - list_remove(node); - return act; - } -} - -static void *parse_service(struct parse_state *state, int nargs, char **args) -{ - struct service *svc; - if (nargs < 3) { - parse_error(state, "services must have a name and a program\n"); - return 0; - } - if (!valid_name(args[1])) { - parse_error(state, "invalid service name '%s'\n", args[1]); - return 0; - } - - svc = service_find_by_name(args[1]); - if (svc) { - parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]); - return 0; - } - - nargs -= 2; - svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); - if (!svc) { - parse_error(state, "out of memory\n"); - return 0; - } - svc->name = args[1]; - svc->classname = "default"; - memcpy(svc->args, args + 2, sizeof(char*) * nargs); - svc->args[nargs] = 0; - svc->nargs = nargs; - svc->onrestart.name = "onrestart"; - list_init(&svc->onrestart.commands); - list_add_tail(&service_list, &svc->slist); - return svc; -} - -static void parse_line_service(struct parse_state *state, int nargs, char **args) -{ - struct service *svc = state->context; - struct command *cmd; - int i, kw, kw_nargs; - - if (nargs == 0) { - return; - } - - kw = lookup_keyword(args[0]); - switch (kw) { - case K_capability: - break; - case K_class: - if (nargs != 2) { - parse_error(state, "class option requires a classname\n"); - } else { - svc->classname = args[1]; - } - break; - case K_console: - svc->flags |= SVC_CONSOLE; - break; - case K_disabled: - svc->flags |= SVC_DISABLED; - break; - case K_group: - if (nargs < 2) { - parse_error(state, "group option requires a group id\n"); - } else if (nargs > NR_SVC_SUPP_GIDS + 2) { - parse_error(state, "group option accepts at most %d supp. groups\n", - NR_SVC_SUPP_GIDS); - } else { - int n; - svc->gid = decode_uid(args[1]); - for (n = 2; n < nargs; n++) { - svc->supp_gids[n-2] = decode_uid(args[n]); - } - svc->nr_supp_gids = n - 2; - } - break; - case K_keycodes: - if (nargs < 2) { - parse_error(state, "keycodes option requires atleast one keycode\n"); - } else { - svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0])); - if (!svc->keycodes) { - parse_error(state, "could not allocate keycodes\n"); - } else { - svc->nkeycodes = nargs - 1; - for (i = 1; i < nargs; i++) { - svc->keycodes[i - 1] = atoi(args[i]); - } - } - } - break; - case K_oneshot: - svc->flags |= SVC_ONESHOT; - break; - case K_onrestart: - nargs--; - args++; - kw = lookup_keyword(args[0]); - if (!kw_is(kw, COMMAND)) { - parse_error(state, "invalid command '%s'\n", args[0]); - break; - } - kw_nargs = kw_nargs(kw); - if (nargs < kw_nargs) { - parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1, - kw_nargs > 2 ? "arguments" : "argument"); - break; - } - - cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); - cmd->func = kw_func(kw); - cmd->nargs = nargs; - memcpy(cmd->args, args, sizeof(char*) * nargs); - list_add_tail(&svc->onrestart.commands, &cmd->clist); - break; - case K_critical: - svc->flags |= SVC_CRITICAL; - break; - case K_setenv: { /* name value */ - struct svcenvinfo *ei; - if (nargs < 2) { - parse_error(state, "setenv option requires name and value arguments\n"); - break; - } - ei = calloc(1, sizeof(*ei)); - if (!ei) { - parse_error(state, "out of memory\n"); - break; - } - ei->name = args[1]; - ei->value = args[2]; - ei->next = svc->envvars; - svc->envvars = ei; - break; - } - case K_socket: {/* name type perm [ uid gid ] */ - struct socketinfo *si; - if (nargs < 4) { - parse_error(state, "socket option requires name, type, perm arguments\n"); - break; - } - if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")) { - parse_error(state, "socket type must be 'dgram' or 'stream'\n"); - break; - } - si = calloc(1, sizeof(*si)); - if (!si) { - parse_error(state, "out of memory\n"); - break; - } - si->name = args[1]; - si->type = args[2]; - si->perm = strtoul(args[3], 0, 8); - if (nargs > 4) - si->uid = decode_uid(args[4]); - if (nargs > 5) - si->gid = decode_uid(args[5]); - si->next = svc->sockets; - svc->sockets = si; - break; - } - case K_user: - if (nargs != 2) { - parse_error(state, "user option requires a user id\n"); - } else { - svc->uid = decode_uid(args[1]); - } - break; - default: - parse_error(state, "invalid option '%s'\n", args[0]); - } -} - -static void *parse_action(struct parse_state *state, int nargs, char **args) -{ - struct action *act; - if (nargs < 2) { - parse_error(state, "actions must have a trigger\n"); - return 0; - } - if (nargs > 2) { - parse_error(state, "actions may not have extra parameters\n"); - return 0; - } - act = calloc(1, sizeof(*act)); - act->name = args[1]; - list_init(&act->commands); - list_add_tail(&action_list, &act->alist); - /* XXX add to hash */ - return act; -} - -static void parse_line_action(struct parse_state* state, int nargs, char **args) -{ - struct command *cmd; - struct action *act = state->context; - int (*func)(int nargs, char **args); - int kw, n; - - if (nargs == 0) { - return; - } - - kw = lookup_keyword(args[0]); - if (!kw_is(kw, COMMAND)) { - parse_error(state, "invalid command '%s'\n", args[0]); - return; - } - - n = kw_nargs(kw); - if (nargs < n) { - parse_error(state, "%s requires %d %s\n", args[0], n - 1, - n > 2 ? "arguments" : "argument"); - return; - } - cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); - cmd->func = kw_func(kw); - cmd->nargs = nargs; - memcpy(cmd->args, args, sizeof(char*) * nargs); - list_add_tail(&act->commands, &cmd->clist); -} diff --git a/init/property_service.c b/init/property_service.c deleted file mode 100644 index 7a6416b5e..000000000 --- a/init/property_service.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <fcntl.h> -#include <stdarg.h> -#include <dirent.h> -#include <limits.h> -#include <errno.h> - -#include <cutils/misc.h> -#include <cutils/sockets.h> -#include <cutils/ashmem.h> - -#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ -#include <sys/_system_properties.h> - -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/select.h> -#include <sys/types.h> -#include <netinet/in.h> -#include <sys/mman.h> -#include <sys/atomics.h> -#include <private/android_filesystem_config.h> - -#include "property_service.h" -#include "init.h" - -#define PERSISTENT_PROPERTY_DIR "/data/property" - -static int persistent_properties_loaded = 0; - -/* White list of permissions for setting property services. */ -struct { - const char *prefix; - unsigned int uid; -} property_perms[] = { - { "net.rmnet0.", AID_RADIO }, - { "net.gprs.", AID_RADIO }, - { "ril.", AID_RADIO }, - { "gsm.", AID_RADIO }, - { "net.dns", AID_RADIO }, - { "net.", AID_SYSTEM }, - { "dev.", AID_SYSTEM }, - { "runtime.", AID_SYSTEM }, - { "hw.", AID_SYSTEM }, - { "sys.", AID_SYSTEM }, - { "service.", AID_SYSTEM }, - { "wlan.", AID_SYSTEM }, - { "dhcp.", AID_SYSTEM }, - { "dhcp.", AID_DHCP }, - { "debug.", AID_SHELL }, - { "log.", AID_SHELL }, - { "persist.sys.", AID_SYSTEM }, - { "persist.service.", AID_SYSTEM }, - { NULL, 0 } -}; - -/* - * White list of UID that are allowed to start/stop services. - * Currently there are no user apps that require. - */ -struct { - const char *service; - unsigned int uid; -} control_perms[] = { - {NULL, 0 } -}; - -typedef struct { - void *data; - size_t size; - int fd; -} workspace; - -static int init_workspace(workspace *w, size_t size) -{ - void *data; - int fd; - - fd = ashmem_create_region("system_properties", size); - if(fd < 0) - return -1; - - data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if(data == MAP_FAILED) - goto out; - - /* allow the wolves we share with to do nothing but read */ - ashmem_set_prot_region(fd, PROT_READ); - - w->data = data; - w->size = size; - w->fd = fd; - - return 0; - -out: - close(fd); - return -1; -} - -/* (8 header words + 247 toc words) = 1020 bytes */ -/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */ - -#define PA_COUNT_MAX 247 -#define PA_INFO_START 1024 -#define PA_SIZE 32768 - -static workspace pa_workspace; -static prop_info *pa_info_array; - -extern prop_area *__system_property_area__; - -static int init_property_area(void) -{ - prop_area *pa; - - if(pa_info_array) - return -1; - - if(init_workspace(&pa_workspace, PA_SIZE)) - return -1; - - fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); - - pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START); - - pa = pa_workspace.data; - memset(pa, 0, PA_SIZE); - pa->magic = PROP_AREA_MAGIC; - pa->version = PROP_AREA_VERSION; - - /* plug into the lib property services */ - __system_property_area__ = pa; - - return 0; -} - -static void update_prop_info(prop_info *pi, const char *value, unsigned len) -{ - pi->serial = pi->serial | 1; - memcpy(pi->value, value, len + 1); - pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff); - __futex_wake(&pi->serial, INT32_MAX); -} - -static int property_write(prop_info *pi, const char *value) -{ - int valuelen = strlen(value); - if(valuelen >= PROP_VALUE_MAX) return -1; - update_prop_info(pi, value, valuelen); - return 0; -} - - -/* - * Checks permissions for starting/stoping system services. - * AID_SYSTEM and AID_ROOT are always allowed. - * - * Returns 1 if uid allowed, 0 otherwise. - */ -static int check_control_perms(const char *name, int uid) { - int i; - if (uid == AID_SYSTEM || uid == AID_ROOT) - return 1; - - /* Search the ACL */ - for (i = 0; control_perms[i].service; i++) { - if (strcmp(control_perms[i].service, name) == 0) { - if (control_perms[i].uid == uid) - return 1; - } - } - return 0; -} - -/* - * Checks permissions for setting system properties. - * Returns 1 if uid allowed, 0 otherwise. - */ -static int check_perms(const char *name, unsigned int uid) -{ - int i; - if (uid == 0) - return 1; - - if(!strncmp(name, "ro.", 3)) - name +=3; - - for (i = 0; property_perms[i].prefix; i++) { - int tmp; - if (strncmp(property_perms[i].prefix, name, - strlen(property_perms[i].prefix)) == 0) { - if (property_perms[i].uid == uid) { - return 1; - } - } - } - - return 0; -} - -const char* property_get(const char *name) -{ - prop_info *pi; - - if(strlen(name) >= PROP_NAME_MAX) return 0; - - pi = (prop_info*) __system_property_find(name); - - if(pi != 0) { - return pi->value; - } else { - return 0; - } -} - -static void write_peristent_property(const char *name, const char *value) -{ - const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp"; - char path[PATH_MAX]; - int fd, length; - - snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name); - - fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600); - if (fd < 0) { - ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno); - return; - } - write(fd, value, strlen(value)); - close(fd); - - if (rename(tempPath, path)) { - unlink(tempPath); - ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path); - } -} - -int property_set(const char *name, const char *value) -{ - prop_area *pa; - prop_info *pi; - - int namelen = strlen(name); - int valuelen = strlen(value); - - if(namelen >= PROP_NAME_MAX) return -1; - if(valuelen >= PROP_VALUE_MAX) return -1; - if(namelen < 1) return -1; - - pi = (prop_info*) __system_property_find(name); - - if(pi != 0) { - /* ro.* properties may NEVER be modified once set */ - if(!strncmp(name, "ro.", 3)) return -1; - - pa = __system_property_area__; - update_prop_info(pi, value, valuelen); - pa->serial++; - __futex_wake(&pa->serial, INT32_MAX); - } else { - pa = __system_property_area__; - if(pa->count == PA_COUNT_MAX) return -1; - - pi = pa_info_array + pa->count; - pi->serial = (valuelen << 24); - memcpy(pi->name, name, namelen + 1); - memcpy(pi->value, value, valuelen + 1); - - pa->toc[pa->count] = - (namelen << 24) | (((unsigned) pi) - ((unsigned) pa)); - - pa->count++; - pa->serial++; - __futex_wake(&pa->serial, INT32_MAX); - } - /* If name starts with "net." treat as a DNS property. */ - if (strncmp("net.", name, sizeof("net.") - 1) == 0) { - if (strcmp("net.change", name) == 0) { - return 0; - } - /* - * The 'net.change' property is a special property used track when any - * 'net.*' property name is updated. It is _ONLY_ updated here. Its value - * contains the last updated 'net.*' property. - */ - property_set("net.change", name); - } else if (persistent_properties_loaded && - strncmp("persist.", name, sizeof("persist.") - 1) == 0) { - /* - * Don't write properties to disk until after we have read all default properties - * to prevent them from being overwritten by default values. - */ - write_peristent_property(name, value); - } - property_changed(name, value); - return 0; -} - -static int property_list(void (*propfn)(const char *key, const char *value, void *cookie), - void *cookie) -{ - char name[PROP_NAME_MAX]; - char value[PROP_VALUE_MAX]; - const prop_info *pi; - unsigned n; - - for(n = 0; (pi = __system_property_find_nth(n)); n++) { - __system_property_read(pi, name, value); - propfn(name, value, cookie); - } - return 0; -} - -void handle_property_set_fd(int fd) -{ - prop_msg msg; - int s; - int r; - int res; - struct ucred cr; - struct sockaddr_un addr; - socklen_t addr_size = sizeof(addr); - socklen_t cr_size = sizeof(cr); - - if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) { - return; - } - - /* Check socket options here */ - if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { - close(s); - ERROR("Unable to recieve socket options\n"); - return; - } - - r = recv(s, &msg, sizeof(msg), 0); - close(s); - if(r != sizeof(prop_msg)) { - ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n", - r, sizeof(prop_msg)); - return; - } - - switch(msg.cmd) { - case PROP_MSG_SETPROP: - msg.name[PROP_NAME_MAX-1] = 0; - msg.value[PROP_VALUE_MAX-1] = 0; - - if(memcmp(msg.name,"ctl.",4) == 0) { - if (check_control_perms(msg.value, cr.uid)) { - handle_control_message((char*) msg.name + 4, (char*) msg.value); - } else { - ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n", - msg.name + 4, msg.value, cr.uid, cr.pid); - } - } else { - if (check_perms(msg.name, cr.uid)) { - property_set((char*) msg.name, (char*) msg.value); - } else { - ERROR("sys_prop: permission denied uid:%d name:%s\n", - cr.uid, msg.name); - } - } - break; - - default: - break; - } -} - -void get_property_workspace(int *fd, int *sz) -{ - *fd = pa_workspace.fd; - *sz = pa_workspace.size; -} - -static void load_properties(char *data) -{ - char *key, *value, *eol, *sol, *tmp; - - sol = data; - while((eol = strchr(sol, '\n'))) { - key = sol; - *eol++ = 0; - sol = eol; - - value = strchr(key, '='); - if(value == 0) continue; - *value++ = 0; - - while(isspace(*key)) key++; - if(*key == '#') continue; - tmp = value - 2; - while((tmp > key) && isspace(*tmp)) *tmp-- = 0; - - while(isspace(*value)) value++; - tmp = eol - 2; - while((tmp > value) && isspace(*tmp)) *tmp-- = 0; - - property_set(key, value); - } -} - -static void load_properties_from_file(const char *fn) -{ - char *data; - unsigned sz; - - data = read_file(fn, &sz); - - if(data != 0) { - load_properties(data); - free(data); - } -} - -static void load_persistent_properties() -{ - DIR* dir = opendir(PERSISTENT_PROPERTY_DIR); - struct dirent* entry; - char path[PATH_MAX]; - char value[PROP_VALUE_MAX]; - int fd, length; - - if (dir) { - while ((entry = readdir(dir)) != NULL) { - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") || - strncmp("persist.", entry->d_name, sizeof("persist.") - 1)) - continue; -#if HAVE_DIRENT_D_TYPE - if (entry->d_type != DT_REG) - continue; -#endif - /* open the file and read the property value */ - snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, entry->d_name); - fd = open(path, O_RDONLY); - if (fd >= 0) { - length = read(fd, value, sizeof(value) - 1); - if (length >= 0) { - value[length] = 0; - property_set(entry->d_name, value); - } else { - ERROR("Unable to read persistent property file %s errno: %d\n", path, errno); - } - close(fd); - } else { - ERROR("Unable to open persistent property file %s errno: %d\n", path, errno); - } - } - closedir(dir); - } else { - ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno); - } - - persistent_properties_loaded = 1; -} - -void property_init(void) -{ - init_property_area(); - load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT); -} - -int start_property_service(void) -{ - int fd; - - load_properties_from_file(PROP_PATH_SYSTEM_BUILD); - load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT); - load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE); - /* Read persistent properties after all default values have been loaded. */ - load_persistent_properties(); - - fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0); - if(fd < 0) return -1; - fcntl(fd, F_SETFD, FD_CLOEXEC); - fcntl(fd, F_SETFL, O_NONBLOCK); - - listen(fd, 8); - return fd; -} diff --git a/init/property_service.h b/init/property_service.h deleted file mode 100644 index d12f1f38b..000000000 --- a/init/property_service.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _INIT_PROPERTY_H -#define _INIT_PROPERTY_H - -extern void handle_property_fd(int fd); -extern void handle_property_set_fd(int fd); -extern void property_init(void); -extern int start_property_service(void); -void get_property_workspace(int *fd, int *sz); -extern const char* property_get(const char *name); -extern int property_set(const char *name, const char *value); - -#endif /* _INIT_PROPERTY_H */ diff --git a/init/readme.txt b/init/readme.txt deleted file mode 100644 index 665090bad..000000000 --- a/init/readme.txt +++ /dev/null @@ -1,293 +0,0 @@ - -Android Init Language ---------------------- - -The Android Init Language consists of four broad classes of statements, -which are Actions, Commands, Services, and Options. - -All of these are line-oriented, consisting of tokens separated by -whitespace. The c-style backslash escapes may be used to insert -whitespace into a token. Double quotes may also be used to prevent -whitespace from breaking text into multiple tokens. The backslash, -when it is the last character on a line, may be used for line-folding. - -Lines which start with a # (leading whitespace allowed) are comments. - -Actions and Services implicitly declare a new section. All commands -or options belong to the section most recently declared. Commands -or options before the first section are ignored. - -Actions and Services have unique names. If a second Action or Service -is declared with the same name as an existing one, it is ignored as -an error. (??? should we override instead) - - -Actions -------- -Actions are named sequences of commands. Actions have a trigger which -is used to determine when the action should occur. When an event -occurs which matches an action's trigger, that action is added to -the tail of a to-be-executed queue (unless it is already on the -queue). - -Each action in the queue is dequeued in sequence and each command in -that action is executed in sequence. Init handles other activities -(device creation/destruction, property setting, process restarting) -"between" the execution of the commands in activities. - -Actions take the form of: - -on <trigger> - <command> - <command> - <command> - - -Services --------- -Services are programs which init launches and (optionally) restarts -when they exit. Services take the form of: - -service <name> <pathname> [ <argument> ]* - <option> - <option> - ... - - -Options -------- -Options are modifiers to services. They affect how and when init -runs the service. - -critical - This is a device-critical service. If it exits more than four times in - four minutes, the device will reboot into recovery mode. - -disabled - This service will not automatically start with its class. - It must be explicitly started by name. - -setenv <name> <value> - Set the environment variable <name> to <value> in the launched process. - -socket <name> <type> <perm> [ <user> [ <group> ] ] - Create a unix domain socket named /dev/socket/<name> and pass - its fd to the launched process. <type> must be "dgram" or "stream". - User and group default to 0. - -user <username> - Change to username before exec'ing this service. - Currently defaults to root. (??? probably should default to nobody) - Currently, if your process requires linux capabilities then you cannot use - this command. You must instead request the capabilities in-process while - still root, and then drop to your desired uid. - -group <groupname> [ <groupname> ]* - Change to groupname before exec'ing this service. Additional - groupnames beyond the (required) first one are used to set the - supplemental groups of the process (via setgroups()). - Currently defaults to root. (??? probably should default to nobody) - -oneshot - Do not restart the service when it exits. - -class <name> - Specify a class name for the service. All services in a - named class may be started or stopped together. A service - is in the class "default" if one is not specified via the - class option. - -onrestart - Execute a Command (see below) when service restarts. - -Triggers --------- - Triggers are strings which can be used to match certain kinds - of events and used to cause an action to occur. - -boot - This is the first trigger that will occur when init starts - (after /init.conf is loaded) - -<name>=<value> - Triggers of this form occur when the property <name> is set - to the specific value <value>. - -device-added-<path> -device-removed-<path> - Triggers of these forms occur when a device node is added - or removed. - -service-exited-<name> - Triggers of this form occur when the specified service exits. - - -Commands --------- - -exec <path> [ <argument> ]* - Fork and execute a program (<path>). This will block until - the program completes execution. It is best to avoid exec - as unlike the builtin commands, it runs the risk of getting - init "stuck". (??? maybe there should be a timeout?) - -export <name> <value> - Set the environment variable <name> equal to <value> in the - global environment (which will be inherited by all processes - started after this command is executed) - -ifup <interface> - Bring the network interface <interface> online. - -import <filename> - Parse an init config file, extending the current configuration. - -hostname <name> - Set the host name. - -chmod <octal-mode> <path> - Change file access permissions. - -chown <owner> <group> <path> - Change file owner and group. - -class_start <serviceclass> - Start all services of the specified class if they are - not already running. - -class_stop <serviceclass> - Stop all services of the specified class if they are - currently running. - -domainname <name> - Set the domain name. - -insmod <path> - Install the module at <path> - -mkdir <path> [mode] [owner] [group] - Create a directory at <path>, optionally with the given mode, owner, and - group. If not provided, the directory is created with permissions 755 and - owned by the root user and root group. - -mount <type> <device> <dir> [ <mountoption> ]* - Attempt to mount the named device at the directory <dir> - <device> may be of the form mtd@name to specify a mtd block - device by name. - <mountoption>s include "ro", "rw", "remount", "noatime", ... - -setkey - TBD - -setprop <name> <value> - Set system property <name> to <value>. - -setrlimit <resource> <cur> <max> - Set the rlimit for a resource. - -start <service> - Start a service running if it is not already running. - -stop <service> - Stop a service from running if it is currently running. - -symlink <target> <path> - Create a symbolic link at <path> with the value <target> - -sysclktz <mins_west_of_gmt> - Set the system clock base (0 if system clock ticks in GMT) - -trigger <event> - Trigger an event. Used to queue an action from another - action. - -write <path> <string> [ <string> ]* - Open the file at <path> and write one or more strings - to it with write(2) - - -Properties ----------- -Init updates some system properties to provide some insight into -what it's doing: - -init.action - Equal to the name of the action currently being executed or "" if none - -init.command - Equal to the command being executed or "" if none. - -init.svc.<name> - State of a named service ("stopped", "running", "restarting") - - -Example init.conf ------------------ - -# not complete -- just providing some examples of usage -# -on boot - export PATH /sbin:/system/sbin:/system/bin - export LD_LIBRARY_PATH /system/lib - - mkdir /dev - mkdir /proc - mkdir /sys - - mount tmpfs tmpfs /dev - mkdir /dev/pts - mkdir /dev/socket - mount devpts devpts /dev/pts - mount proc proc /proc - mount sysfs sysfs /sys - - write /proc/cpu/alignment 4 - - ifup lo - - hostname localhost - domainname localhost - - mount yaffs2 mtd@system /system - mount yaffs2 mtd@userdata /data - - import /system/etc/init.conf - - class_start default - -service adbd /sbin/adbd - user adb - group adb - -service usbd /system/bin/usbd -r - user usbd - group usbd - socket usbd 666 - -service zygote /system/bin/app_process -Xzygote /system/bin --zygote - socket zygote 666 - -service runtime /system/bin/runtime - user system - group system - -on device-added-/dev/compass - start akmd - -on device-removed-/dev/compass - stop akmd - -service akmd /sbin/akmd - disabled - user akmd - group akmd - -Debugging notes ---------------- -By default, programs executed by init will drop stdout and stderr into -/dev/null. To help with debugging, you can execute your program via the -Andoird program logwrapper. This will redirect stdout/stderr into the -Android logging system (accessed via logcat). - -For example -service akmd /system/bin/logwrapper /sbin/akmd diff --git a/init/util.c b/init/util.c deleted file mode 100644 index 0b7667dae..000000000 --- a/init/util.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <ctype.h> -#include <errno.h> - -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> - -/* for ANDROID_SOCKET_* */ -#include <cutils/sockets.h> - -#include <private/android_filesystem_config.h> - -#include "init.h" - -static int log_fd = -1; -/* Inital log level before init.rc is parsed and this this is reset. */ -static int log_level = LOG_DEFAULT_LEVEL; - - -void log_set_level(int level) { - log_level = level; -} - -void log_init(void) -{ - static const char *name = "/dev/__kmsg__"; - if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) { - log_fd = open(name, O_WRONLY); - fcntl(log_fd, F_SETFD, FD_CLOEXEC); - unlink(name); - } -} - -#define LOG_BUF_MAX 512 - -void log_write(int level, const char *fmt, ...) -{ - char buf[LOG_BUF_MAX]; - va_list ap; - - if (level > log_level) return; - if (log_fd < 0) return; - - va_start(ap, fmt); - vsnprintf(buf, LOG_BUF_MAX, fmt, ap); - buf[LOG_BUF_MAX - 1] = 0; - va_end(ap); - write(log_fd, buf, strlen(buf)); -} - -/* - * android_name_to_id - returns the integer uid/gid associated with the given - * name, or -1U on error. - */ -static unsigned int android_name_to_id(const char *name) -{ - struct android_id_info *info = android_ids; - unsigned int n; - - for (n = 0; n < android_id_count; n++) { - if (!strcmp(info[n].name, name)) - return info[n].aid; - } - - return -1U; -} - -/* - * decode_uid - decodes and returns the given string, which can be either the - * numeric or name representation, into the integer uid or gid. Returns -1U on - * error. - */ -unsigned int decode_uid(const char *s) -{ - unsigned int v; - - if (!s || *s == '\0') - return -1U; - if (isalpha(s[0])) - return android_name_to_id(s); - - errno = 0; - v = (unsigned int) strtoul(s, 0, 0); - if (errno) - return -1U; - return v; -} - -/* - * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR - * ("/dev/socket") as dictated in init.rc. This socket is inherited by the - * daemon. We communicate the file descriptor's value via the environment - * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo"). - */ -int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) -{ - struct sockaddr_un addr; - int fd, ret; - - fd = socket(PF_UNIX, type, 0); - if (fd < 0) { - ERROR("Failed to open socket '%s': %s\n", name, strerror(errno)); - return -1; - } - - memset(&addr, 0 , sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", - name); - - ret = unlink(addr.sun_path); - if (ret != 0 && errno != ENOENT) { - ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno)); - goto out_close; - } - - ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr)); - if (ret) { - ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno)); - goto out_unlink; - } - - chown(addr.sun_path, uid, gid); - chmod(addr.sun_path, perm); - - INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n", - addr.sun_path, perm, uid, gid); - - return fd; - -out_unlink: - unlink(addr.sun_path); -out_close: - close(fd); - return -1; -} - -/* reads a file, making sure it is terminated with \n \0 */ -void *read_file(const char *fn, unsigned *_sz) -{ - char *data; - int sz; - int fd; - - data = 0; - fd = open(fn, O_RDONLY); - if(fd < 0) return 0; - - sz = lseek(fd, 0, SEEK_END); - if(sz < 0) goto oops; - - if(lseek(fd, 0, SEEK_SET) != 0) goto oops; - - data = (char*) malloc(sz + 2); - if(data == 0) goto oops; - - if(read(fd, data, sz) != sz) goto oops; - close(fd); - data[sz] = '\n'; - data[sz+1] = 0; - if(_sz) *_sz = sz; - return data; - -oops: - close(fd); - if(data != 0) free(data); - return 0; -} - -void list_init(struct listnode *node) -{ - node->next = node; - node->prev = node; -} - -void list_add_tail(struct listnode *head, struct listnode *item) -{ - item->next = head; - item->prev = head->prev; - head->prev->next = item; - head->prev = item; -} - -void list_remove(struct listnode *item) -{ - item->next->prev = item->prev; - item->prev->next = item->next; -} - |