Codebase list android-platform-system-core / e54eebb
auto import from //depot/cupcake/@135843 The Android Open Source Project 15 years ago
466 changed file(s) with 0 addition(s) and 107166 deletion(s). Raw diff Collapse all Expand all
+0
-29
Android.mk less more
0 #
1 # Copyright (C) 2008 The Android Open Source Project
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 LOCAL_PATH := $(my-dir)
16
17 ifneq ($(TARGET_SIMULATOR),true)
18 include $(call first-makefiles-under,$(LOCAL_PATH))
19 else
20 include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
21 adb \
22 libcutils \
23 liblog \
24 libnetutils \
25 libpixelflinger \
26 libzipfile \
27 ))
28 endif
+0
-20
README less more
0
1 The system/ directory is intended for pieces of the world that are the
2 core of the embedded linux platform at the heart of Android. These
3 essential bits are required for basic booting, operation, and debugging.
4
5 They should not depend on libraries outside of system/... (some of them
6 do currently -- they need to be updated or changed) and they should not
7 be required for the simulator build.
8
9 The license for all these pieces should be clean (Apache2, BSD, or MIT).
10
11 Currently system/bluetooth/... and system/extra/... have some pieces
12 with GPL/LGPL licensed code.
13
14 Assorted Issues:
15
16 - pppd depends on libutils for logging
17 - pppd depends on libcrypt/libcrypto
18 - init, linker, debuggerd, toolbox, usbd depend on libcutils
19 - should probably rename bionic to libc
+0
-140
adb/Android.mk less more
0 # Copyright 2005 The Android Open Source Project
1 #
2 # Android.mk for adb
3 #
4
5 LOCAL_PATH:= $(call my-dir)
6
7 # adb host tool
8 # =========================================================
9 ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean (also unused with the sim)
10 include $(CLEAR_VARS)
11
12 # Default to a virtual (sockets) usb interface
13 USB_SRCS :=
14 EXTRA_SRCS :=
15
16 ifeq ($(HOST_OS),linux)
17 USB_SRCS := usb_linux.c
18 EXTRA_SRCS := get_my_path_linux.c
19 LOCAL_LDLIBS += -lrt -lncurses -lpthread
20 endif
21
22 ifeq ($(HOST_OS),darwin)
23 USB_SRCS := usb_osx.c
24 EXTRA_SRCS := get_my_path_darwin.c
25 LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
26 endif
27
28 ifeq ($(HOST_OS),windows)
29 USB_SRCS := usb_windows.c
30 EXTRA_SRCS := get_my_path_windows.c
31 EXTRA_STATIC_LIBS := AdbWinApi
32 LOCAL_C_INCLUDES += /usr/include/w32api/ddk development/host/windows/usb/api/
33 ifneq ($(strip $(USE_CYGWIN)),)
34 LOCAL_LDLIBS += -lpthread
35 else
36 LOCAL_LDLIBS += -lws2_32
37 USE_SYSDEPS_WIN32 := 1
38 endif
39 endif
40
41 LOCAL_SRC_FILES := \
42 adb.c \
43 console.c \
44 transport.c \
45 transport_local.c \
46 transport_usb.c \
47 commandline.c \
48 adb_client.c \
49 sockets.c \
50 services.c \
51 file_sync_client.c \
52 $(EXTRA_SRCS) \
53 $(USB_SRCS) \
54 shlist.c \
55 utils.c \
56
57
58 ifneq ($(USE_SYSDEPS_WIN32),)
59 LOCAL_SRC_FILES += sysdeps_win32.c
60 endif
61
62 LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter
63 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY
64 LOCAL_MODULE := adb
65
66 LOCAL_STATIC_LIBRARIES := libzipfile libunz $(EXTRA_STATIC_LIBS)
67 ifeq ($(USE_SYSDEPS_WIN32),)
68 LOCAL_STATIC_LIBRARIES += libcutils
69 endif
70
71 include $(BUILD_HOST_EXECUTABLE)
72
73 $(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
74
75 ifeq ($(HOST_OS),windows)
76 $(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
77 endif
78
79 endif
80
81 # adbd device daemon
82 # =========================================================
83
84 # build adbd in all non-simulator builds
85 BUILD_ADBD := false
86 ifneq ($(TARGET_SIMULATOR),true)
87 BUILD_ADBD := true
88 endif
89
90 # build adbd for the Linux simulator build
91 # so we can use it to test the adb USB gadget driver on x86
92 ifeq ($(HOST_OS),linux)
93 BUILD_ADBD := true
94 endif
95
96
97 ifeq ($(BUILD_ADBD),true)
98 include $(CLEAR_VARS)
99
100 LOCAL_SRC_FILES := \
101 adb.c \
102 transport.c \
103 transport_local.c \
104 transport_usb.c \
105 sockets.c \
106 services.c \
107 file_sync_service.c \
108 jdwp_service.c \
109 framebuffer_service.c \
110 remount_service.c \
111 usb_linux_client.c \
112 log_service.c \
113 utils.c \
114
115 LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
116 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
117
118 # TODO: This should probably be board specific, whether or not the kernel has
119 # the gadget driver; rather than relying on the architecture type.
120 ifeq ($(TARGET_ARCH),arm)
121 LOCAL_CFLAGS += -DANDROID_GADGET=1
122 endif
123
124 LOCAL_MODULE := adbd
125
126 LOCAL_FORCE_STATIC_EXECUTABLE := true
127 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
128 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
129
130 ifeq ($(TARGET_SIMULATOR),true)
131 LOCAL_STATIC_LIBRARIES := libcutils
132 LOCAL_LDLIBS += -lpthread
133 include $(BUILD_HOST_EXECUTABLE)
134 else
135 LOCAL_STATIC_LIBRARIES := libcutils libc
136 include $(BUILD_EXECUTABLE)
137 endif
138
139 endif
+0
-139
adb/OVERVIEW.TXT less more
0 Implementation notes regarding ADB.
1
2 I. General Overview:
3
4 The Android Debug Bridge (ADB) is used to:
5
6 - keep track of all Android devices and emulators instances
7 connected to or running on a given host developer machine
8
9 - implement various control commands (e.g. "adb shell", "adb pull", etc..)
10 for the benefit of clients (command-line users, or helper programs like
11 DDMS). These commands are what is called a 'service' in ADB.
12
13 As a whole, everything works through the following components:
14
15 1. The ADB server
16
17 This is a background process that runs on the host machine. Its purpose
18 if to sense the USB ports to know when devices are attached/removed,
19 as well as when emulator instances start/stop.
20
21 It thus maintains a list of "connected devices" and assigns a 'state'
22 to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on
23 this below).
24
25 The ADB server is really one giant multiplexing loop whose purpose is
26 to orchestrate the exchange of data (packets, really) between clients,
27 services and devices.
28
29
30 2. The ADB daemon (adbd)
31
32 The 'adbd' program runs as a background process within an Android device
33 or emulated system. Its purpose is to connect to the ADB server
34 (through USB for devices, through TCP for emulators) and provide a
35 few services for clients that run on the host.
36
37 The ADB server considers that a device is ONLINE when it has succesfully
38 connected to the adbd program within it. Otherwise, the device is OFFLINE,
39 meaning that the ADB server detected a new device/emulator, but could not
40 connect to the adbd daemon.
41
42 the BOOTLOADER and RECOVERY states correspond to alternate states of
43 devices when they are in the bootloader or recovery mode.
44
45 3. The ADB command-line client
46
47 The 'adb' command-line program is used to run adb commands from a shell
48 or a script. It first tries to locate the ADB server on the host machine,
49 and will start one automatically if none is found.
50
51 then, the client sends its service requests to the ADB server. It doesn't
52 need to know.
53
54 Currently, a single 'adb' binary is used for both the server and client.
55 this makes distribution and starting the server easier.
56
57
58 4. Services
59
60 There are essentially two kinds of services that a client can talk to.
61
62 Host Services:
63 these services run within the ADB Server and thus do not need to
64 communicate with a device at all. A typical example is "adb devices"
65 which is used to return the list of currently known devices and their
66 state. They are a few couple other services though.
67
68 Local Services:
69 these services either run within the adbd daemon, or are started by
70 it on the device. The ADB server is used to multiplex streams
71 between the client and the service running in adbd. In this case
72 its role is to initiate the connection, then of being a pass-through
73 for the data.
74
75
76 II. Protocol details:
77
78 1. Client <-> Server protocol:
79
80 This details the protocol used between ADB clients and the ADB
81 server itself. The ADB server listens on TCP:localhost:5037.
82
83 A client sends a request using the following format:
84
85 1. A 4-byte hexadecimal string giving the length of the payload
86 2. Followed by the payload itself.
87
88 For example, to query the ADB server for its internal version number,
89 the client will do the following:
90
91 1. Connect to tcp:localhost:5037
92 2. Send the string "000Chost:version" to the corresponding socket
93
94 The 'host:' prefix is used to indicate that the request is addressed
95 to the server itself (we will talk about other kinds of requests later).
96 The content length is encoded in ASCII for easier debugging.
97
98 The server should answer a request with one of the following:
99
100 1. For success, the 4-byte "OKAY" string
101
102 2. For failure, the 4-byte "FAIL" string, followed by a
103 4-byte hex length, followed by a string giving the reason
104 for failure.
105
106 3. As a special exception, for 'host:version', a 4-byte
107 hex string corresponding to the server's internal version number
108
109 Note that the connection is still alive after an OKAY, which allows the
110 client to make other requests. But in certain cases, an OKAY will even
111 change the state of the connection.
112
113 For example, the case of the 'host:transport:<serialnumber>' request,
114 where '<serialnumber>' is used to identify a given device/emulator; after
115 the "OKAY" answer, all further requests made by the client will go
116 directly to the corresponding adbd daemon.
117
118 The file SERVICES.TXT lists all services currently implemented by ADB.
119
120
121 2. Transports:
122
123 An ADB transport models a connection between the ADB server and one device
124 or emulator. There are currently two kinds of transports:
125
126 - USB transports, for physical devices through USB
127
128 - Local transports, for emulators running on the host, connected to
129 the server through TCP
130
131 In theory, it should be possible to write a local transport that proxies
132 a connection between an ADB server and a device/emulator connected to/
133 running on another machine. This hasn't been done yet though.
134
135 Each transport can carry one or more multiplexed streams between clients
136 and the device/emulator they point to. The ADB server must handle
137 unexpected transport disconnections (e.g. when a device is physically
138 unplugged) properly.
+0
-236
adb/SERVICES.TXT less more
0 This file tries to document all requests a client can make
1 to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
2 to understand what's going on here.
3
4 HOST SERVICES:
5
6 host:version
7 Ask the ADB server for its internal version number.
8
9 As a special exception, the server will respond with a 4-byte
10 hex string corresponding to its internal version number, without
11 any OKAY or FAIL.
12
13 host:kill
14 Ask the ADB server to quit immediately. This is used when the
15 ADB client detects that an obsolete server is running after an
16 upgrade.
17
18 host:devices
19 Ask to return the list of available Android devices and their
20 state. After the OKAY, this is followed by a 4-byte hex len,
21 and a string that will be dumped as-is by the client, then
22 the connection is closed
23
24 host:track-devices
25 This is a variant of host:devices which doesn't close the
26 connection. Instead, a new device list description is sent
27 each time a device is added/removed or the state of a given
28 device changes (hex4 + content). This allows tools like DDMS
29 to track the state of connected devices in real-time without
30 polling the server repeatedly.
31
32 host:emulator:<port>
33 This is a special query that is sent to the ADB server when a
34 new emulator starts up. <port> is a decimal number corresponding
35 to the emulator's ADB control port, i.e. the TCP port that the
36 emulator will forward automatically to the adbd daemon running
37 in the emulator system.
38
39 This mechanism allows the ADB server to know when new emulator
40 instances start.
41
42 host:transport:<serial-number>
43 Ask to switch the connection to the device/emulator identified by
44 <serial-number>. After the OKAY response, every client request will
45 be sent directly to the adbd daemon running on the device.
46 (Used to implement the -s option)
47
48 host:transport-usb
49 Ask to switch the connection to one device connected through USB
50 to the host machine. This will fail if there are more than one such
51 devices. (Used to implement the -d convenience option)
52
53 host:transport-local
54 Ask to switch the connection to one emulator connected through TCP.
55 This will fail if there is more than one such emulator instance
56 running. (Used to implement the -e convenience option)
57
58 host:transport-any
59 Another host:transport variant. Ask to switch the connection to
60 either the device or emulator connect to/running on the host.
61 Will fail if there is more than one such device/emulator available.
62 (Used when neither -s, -d or -e are provided)
63
64 host-serial:<serial-number>:<request>
65 This is a special form of query, where the 'host-serial:<serial-number>:'
66 prefix can be used to indicate that the client is asking the ADB server
67 for information related to a specific device. <request> can be in one
68 of the format described below.
69
70 host-usb:<request>
71 A variant of host-serial used to target the single USB device connected
72 to the host. This will fail if there is none or more than one.
73
74 host-local:<request>
75 A variant of host-serial used to target the single emulator instance
76 running on the host. This will fail if therre is none or more than one.
77
78 host:<request>
79 When asking for information related to a device, 'host:' can also be
80 interpreted as 'any single device or emulator connected to/running on
81 the host'.
82
83 <host-prefix>:get-product
84 XXX
85
86 <host-prefix>:get-serialno
87 Returns the serial number of the corresponding device/emulator.
88 Note that emulator serial numbers are of the form "emulator-5554"
89
90 <host-prefix>:get-state
91 Returns the state of a given device as a string.
92
93 <host-prefix>:forward:<local>;<remote>
94 Asks the ADB server to forward local connections from <local>
95 to the <remote> address on a given device.
96
97 There, <host-prefix> can be one of the
98 host-serial/host-usb/host-local/host prefixes as described previously
99 and indicates which device/emulator to target.
100
101 the format of <local> is one of:
102
103 tcp:<port> -> TCP connection on localhost:<port>
104 local:<path> -> Unix local domain socket on <path>
105
106 the format of <remote> is one of:
107
108 tcp:<port> -> TCP localhost:<port> on device
109 local:<path> -> Unix local domain socket on device
110 jdwp:<pid> -> JDWP thread on VM process <pid>
111
112 or even any one of the local services described below.
113
114
115
116 LOCAL SERVICES:
117
118 All the queries below assumed that you already switched the transport
119 to a real device, or that you have used a query prefix as described
120 above.
121
122 shell:command arg1 arg2 ...
123 Run 'command arg1 arg2 ...' in a shell on the device, and return
124 its output and error streams. Note that arguments must be separated
125 by spaces. If an argument contains a space, it must be quoted with
126 double-quotes. Arguments cannot contain double quotes or things
127 will go very wrong.
128
129 Note that this is the non-interactive version of "adb shell"
130
131 shell:
132 Start an interactive shell session on the device. Redirect
133 stdin/stdout/stderr as appropriate. Note that the ADB server uses
134 this to implement "adb shell", but will also cook the input before
135 sending it to the device (see interactive_shell() in commandline.c)
136
137 remount:
138 Ask adbd to remount the device's filesystem in read-write mode,
139 instead of read-only. This is usually necessary before performing
140 an "adb sync" or "adb push" request.
141
142 This request may not succeed on certain builds which do not allow
143 that.
144
145 dev:<path>
146 Opens a device file and connects the client directly to it for
147 read/write purposes. Useful for debugging, but may require special
148 priviledges and thus may not run on all devices. <path> is a full
149 path from the root of the filesystem.
150
151 tcp:<port>
152 Tries to connect to tcp port <port> on localhost.
153
154 tcp:<port>:<server-name>
155 Tries to connect to tcp port <port> on machine <server-name> from
156 the device. This can be useful to debug some networking/proxy
157 issues that can only be revealed on the device itself.
158
159 local:<path>
160 Tries to connect to a Unix domain socket <path> on the device
161
162 localreserved:<path>
163 localabstract:<path>
164 localfilesystem:<path>
165 Variants of local:<path> that are used to access other Android
166 socket namespaces.
167
168 log:<name>
169 Opens one of the system logs (/dev/log/<name>) and allows the client
170 to read them directly. Used to implement 'adb logcat'. The stream
171 will be read-only for the client.
172
173 framebuffer:
174 This service is used to send snapshots of the framebuffer to a client.
175 It requires sufficient priviledges but works as follow:
176
177 After the OKAY, the service sends 16-byte binary structure
178 containing the following fields (little-endian format):
179
180 depth: uint32_t: framebuffer depth
181 size: uint32_t: framebuffer size in bytes
182 width: uint32_t: framebuffer width in pixels
183 height: uint32_t: framebuffer height in pixels
184
185 With the current implementation, depth is always 16, and
186 size is always width*height*2
187
188 Then, each time the client wants a snapshot, it should send
189 one byte through the channel, which will trigger the service
190 to send it 'size' bytes of framebuffer data.
191
192 If the adbd daemon doesn't have sufficient priviledges to open
193 the framebuffer device, the connection is simply closed immediately.
194
195 dns:<server-name>
196 This service is an exception because it only runs within the ADB server.
197 It is used to implement USB networking, i.e. to provide a network connection
198 to the device through the host machine (note: this is the exact opposite of
199 network thetering).
200
201 It is used to perform a gethostbyname(<address>) on the host and return
202 the corresponding IP address as a 4-byte string.
203
204 recover:<size>
205 This service is used to upload a recovery image to the device. <size>
206 must be a number corresponding to the size of the file. The service works
207 by:
208
209 - creating a file named /tmp/update
210 - reading 'size' bytes from the client and writing them to /tmp/update
211 - when everything is read succesfully, create a file named /tmp/update.start
212
213 This service can only work when the device is in recovery mode. Otherwise,
214 the /tmp directory doesn't exist and the connection will be closed immediately.
215
216 jdwp:<pid>
217 Connects to the JDWP thread running in the VM of process <pid>.
218
219 track-jdwp
220 This is used to send the list of JDWP pids periodically to the client.
221 The format of the returned data is the following:
222
223 <hex4>: the length of all content as a 4-char hexadecimal string
224 <content>: a series of ASCII lines of the following format:
225 <pid> "\n"
226
227 This service is used by DDMS to know which debuggable processes are running
228 on the device/emulator.
229
230 Note that there is no single-shot service to retrieve the list only once.
231
232 sync:
233 This starts the file synchronisation service, used to implement "adb push"
234 and "adb pull". Since this service is pretty complex, it will be detailed
235 in a companion document named SYNC.TXT
+0
-1083
adb/adb.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define TRACE_TAG TRACE_ADB
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <stdarg.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <time.h>
25
26 #include "sysdeps.h"
27 #include "adb.h"
28
29 #if !ADB_HOST
30 #include <private/android_filesystem_config.h>
31 #endif
32
33
34 int HOST = 0;
35
36 static const char *adb_device_banner = "device";
37
38 void fatal(const char *fmt, ...)
39 {
40 va_list ap;
41 va_start(ap, fmt);
42 fprintf(stderr, "error: ");
43 vfprintf(stderr, fmt, ap);
44 fprintf(stderr, "\n");
45 va_end(ap);
46 exit(-1);
47 }
48
49 void fatal_errno(const char *fmt, ...)
50 {
51 va_list ap;
52 va_start(ap, fmt);
53 fprintf(stderr, "error: %s: ", strerror(errno));
54 vfprintf(stderr, fmt, ap);
55 fprintf(stderr, "\n");
56 va_end(ap);
57 exit(-1);
58 }
59
60 int adb_trace_mask;
61
62 /* read a comma/space/colum/semi-column separated list of tags
63 * from the ADB_TRACE environment variable and build the trace
64 * mask from it. note that '1' and 'all' are special cases to
65 * enable all tracing
66 */
67 void adb_trace_init(void)
68 {
69 const char* p = getenv("ADB_TRACE");
70 const char* q;
71
72 static const struct {
73 const char* tag;
74 int flag;
75 } tags[] = {
76 { "1", 0 },
77 { "all", 0 },
78 { "adb", TRACE_ADB },
79 { "sockets", TRACE_SOCKETS },
80 { "packets", TRACE_PACKETS },
81 { "rwx", TRACE_RWX },
82 { "usb", TRACE_USB },
83 { "sync", TRACE_SYNC },
84 { "sysdeps", TRACE_SYSDEPS },
85 { "transport", TRACE_TRANSPORT },
86 { "jdwp", TRACE_JDWP },
87 { NULL, 0 }
88 };
89
90 if (p == NULL)
91 return;
92
93 /* use a comma/column/semi-colum/space separated list */
94 while (*p) {
95 int len, tagn;
96
97 q = strpbrk(p, " ,:;");
98 if (q == NULL) {
99 q = p + strlen(p);
100 }
101 len = q - p;
102
103 for (tagn = 0; tags[tagn].tag != NULL; tagn++)
104 {
105 int taglen = strlen(tags[tagn].tag);
106
107 if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
108 {
109 int flag = tags[tagn].flag;
110 if (flag == 0) {
111 adb_trace_mask = ~0;
112 return;
113 }
114 adb_trace_mask |= (1 << flag);
115 break;
116 }
117 }
118 p = q;
119 if (*p)
120 p++;
121 }
122 }
123
124
125 apacket *get_apacket(void)
126 {
127 apacket *p = malloc(sizeof(apacket));
128 if(p == 0) fatal("failed to allocate an apacket");
129 memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
130 return p;
131 }
132
133 void put_apacket(apacket *p)
134 {
135 free(p);
136 }
137
138 void handle_online(void)
139 {
140 D("adb: online\n");
141 #if !ADB_HOST
142 property_set("adb.connected","1");
143 #endif
144 }
145
146 void handle_offline(atransport *t)
147 {
148 D("adb: offline\n");
149 //Close the associated usb
150 run_transport_disconnects(t);
151 #if !ADB_HOST
152 property_set("adb.connected","");
153 #endif
154 }
155
156 #if TRACE_PACKETS
157 #define DUMPMAX 32
158 void print_packet(const char *label, apacket *p)
159 {
160 char *tag;
161 char *x;
162 unsigned count;
163
164 switch(p->msg.command){
165 case A_SYNC: tag = "SYNC"; break;
166 case A_CNXN: tag = "CNXN" ; break;
167 case A_OPEN: tag = "OPEN"; break;
168 case A_OKAY: tag = "OKAY"; break;
169 case A_CLSE: tag = "CLSE"; break;
170 case A_WRTE: tag = "WRTE"; break;
171 default: tag = "????"; break;
172 }
173
174 fprintf(stderr, "%s: %s %08x %08x %04x \"",
175 label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
176 count = p->msg.data_length;
177 x = (char*) p->data;
178 if(count > DUMPMAX) {
179 count = DUMPMAX;
180 tag = "\n";
181 } else {
182 tag = "\"\n";
183 }
184 while(count-- > 0){
185 if((*x >= ' ') && (*x < 127)) {
186 fputc(*x, stderr);
187 } else {
188 fputc('.', stderr);
189 }
190 x++;
191 }
192 fprintf(stderr, tag);
193 }
194 #endif
195
196 static void send_ready(unsigned local, unsigned remote, atransport *t)
197 {
198 D("Calling send_ready \n");
199 apacket *p = get_apacket();
200 p->msg.command = A_OKAY;
201 p->msg.arg0 = local;
202 p->msg.arg1 = remote;
203 send_packet(p, t);
204 }
205
206 static void send_close(unsigned local, unsigned remote, atransport *t)
207 {
208 D("Calling send_close \n");
209 apacket *p = get_apacket();
210 p->msg.command = A_CLSE;
211 p->msg.arg0 = local;
212 p->msg.arg1 = remote;
213 send_packet(p, t);
214 }
215
216 static void send_connect(atransport *t)
217 {
218 D("Calling send_connect \n");
219 apacket *cp = get_apacket();
220 cp->msg.command = A_CNXN;
221 cp->msg.arg0 = A_VERSION;
222 cp->msg.arg1 = MAX_PAYLOAD;
223 snprintf((char*) cp->data, sizeof cp->data, "%s::",
224 HOST ? "host" : adb_device_banner);
225 cp->msg.data_length = strlen((char*) cp->data) + 1;
226 send_packet(cp, t);
227 #if ADB_HOST
228 /* XXX why sleep here? */
229 // allow the device some time to respond to the connect message
230 adb_sleep_ms(1000);
231 #endif
232 }
233
234 static char *connection_state_name(atransport *t)
235 {
236 if (t == NULL) {
237 return "unknown";
238 }
239
240 switch(t->connection_state) {
241 case CS_BOOTLOADER:
242 return "bootloader";
243 case CS_DEVICE:
244 return "device";
245 case CS_OFFLINE:
246 return "offline";
247 default:
248 return "unknown";
249 }
250 }
251
252 void parse_banner(char *banner, atransport *t)
253 {
254 char *type, *product, *end;
255
256 D("parse_banner: %s\n", banner);
257 type = banner;
258 product = strchr(type, ':');
259 if(product) {
260 *product++ = 0;
261 } else {
262 product = "";
263 }
264
265 /* remove trailing ':' */
266 end = strchr(product, ':');
267 if(end) *end = 0;
268
269 /* save product name in device structure */
270 if (t->product == NULL) {
271 t->product = strdup(product);
272 } else if (strcmp(product, t->product) != 0) {
273 free(t->product);
274 t->product = strdup(product);
275 }
276
277 if(!strcmp(type, "bootloader")){
278 D("setting connection_state to CS_BOOTLOADER\n");
279 t->connection_state = CS_BOOTLOADER;
280 update_transports();
281 return;
282 }
283
284 if(!strcmp(type, "device")) {
285 D("setting connection_state to CS_DEVICE\n");
286 t->connection_state = CS_DEVICE;
287 update_transports();
288 return;
289 }
290
291 if(!strcmp(type, "recovery")) {
292 D("setting connection_state to CS_RECOVERY\n");
293 t->connection_state = CS_RECOVERY;
294 update_transports();
295 return;
296 }
297
298 t->connection_state = CS_HOST;
299 }
300
301 void handle_packet(apacket *p, atransport *t)
302 {
303 asocket *s;
304
305 D("handle_packet() %d\n", p->msg.command);
306
307 print_packet("recv", p);
308
309 switch(p->msg.command){
310 case A_SYNC:
311 if(p->msg.arg0){
312 send_packet(p, t);
313 if(HOST) send_connect(t);
314 } else {
315 t->connection_state = CS_OFFLINE;
316 handle_offline(t);
317 send_packet(p, t);
318 }
319 return;
320
321 case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
322 /* XXX verify version, etc */
323 if(t->connection_state != CS_OFFLINE) {
324 t->connection_state = CS_OFFLINE;
325 handle_offline(t);
326 }
327 parse_banner((char*) p->data, t);
328 handle_online();
329 if(!HOST) send_connect(t);
330 break;
331
332 case A_OPEN: /* OPEN(local-id, 0, "destination") */
333 if(t->connection_state != CS_OFFLINE) {
334 char *name = (char*) p->data;
335 name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
336 s = create_local_service_socket(name);
337 if(s == 0) {
338 send_close(0, p->msg.arg0, t);
339 } else {
340 s->peer = create_remote_socket(p->msg.arg0, t);
341 s->peer->peer = s;
342 send_ready(s->id, s->peer->id, t);
343 s->ready(s);
344 }
345 }
346 break;
347
348 case A_OKAY: /* READY(local-id, remote-id, "") */
349 if(t->connection_state != CS_OFFLINE) {
350 if((s = find_local_socket(p->msg.arg1))) {
351 if(s->peer == 0) {
352 s->peer = create_remote_socket(p->msg.arg0, t);
353 s->peer->peer = s;
354 }
355 s->ready(s);
356 }
357 }
358 break;
359
360 case A_CLSE: /* CLOSE(local-id, remote-id, "") */
361 if(t->connection_state != CS_OFFLINE) {
362 if((s = find_local_socket(p->msg.arg1))) {
363 s->close(s);
364 }
365 }
366 break;
367
368 case A_WRTE:
369 if(t->connection_state != CS_OFFLINE) {
370 if((s = find_local_socket(p->msg.arg1))) {
371 unsigned rid = p->msg.arg0;
372 p->len = p->msg.data_length;
373
374 if(s->enqueue(s, p) == 0) {
375 D("Enqueue the socket\n");
376 send_ready(s->id, rid, t);
377 }
378 return;
379 }
380 }
381 break;
382
383 default:
384 printf("handle_packet: what is %08x?!\n", p->msg.command);
385 }
386
387 put_apacket(p);
388 }
389
390 alistener listener_list = {
391 .next = &listener_list,
392 .prev = &listener_list,
393 };
394
395 static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
396 {
397 asocket *s;
398
399 if(ev & FDE_READ) {
400 struct sockaddr addr;
401 socklen_t alen;
402 int fd;
403
404 alen = sizeof(addr);
405 fd = adb_socket_accept(_fd, &addr, &alen);
406 if(fd < 0) return;
407
408 adb_socket_setbufsize(fd, CHUNK_SIZE);
409
410 s = create_local_socket(fd);
411 if(s) {
412 connect_to_smartsocket(s);
413 return;
414 }
415
416 adb_close(fd);
417 }
418 }
419
420 static void listener_event_func(int _fd, unsigned ev, void *_l)
421 {
422 alistener *l = _l;
423 asocket *s;
424
425 if(ev & FDE_READ) {
426 struct sockaddr addr;
427 socklen_t alen;
428 int fd;
429
430 alen = sizeof(addr);
431 fd = adb_socket_accept(_fd, &addr, &alen);
432 if(fd < 0) return;
433
434 s = create_local_socket(fd);
435 if(s) {
436 s->transport = l->transport;
437 connect_to_remote(s, l->connect_to);
438 return;
439 }
440
441 adb_close(fd);
442 }
443 }
444
445 static void free_listener(alistener* l)
446 {
447 if (l->next) {
448 l->next->prev = l->prev;
449 l->prev->next = l->next;
450 l->next = l->prev = l;
451 }
452
453 // closes the corresponding fd
454 fdevent_remove(&l->fde);
455
456 if (l->local_name)
457 free((char*)l->local_name);
458
459 if (l->connect_to)
460 free((char*)l->connect_to);
461
462 if (l->transport) {
463 remove_transport_disconnect(l->transport, &l->disconnect);
464 }
465 free(l);
466 }
467
468 static void listener_disconnect(void* _l, atransport* t)
469 {
470 alistener* l = _l;
471
472 free_listener(l);
473 }
474
475 int local_name_to_fd(const char *name)
476 {
477 int port;
478
479 if(!strncmp("tcp:", name, 4)){
480 int ret;
481 port = atoi(name + 4);
482 ret = socket_loopback_server(port, SOCK_STREAM);
483 return ret;
484 }
485 #ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
486 // It's non-sensical to support the "reserved" space on the adb host side
487 if(!strncmp(name, "local:", 6)) {
488 return socket_local_server(name + 6,
489 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
490 } else if(!strncmp(name, "localabstract:", 14)) {
491 return socket_local_server(name + 14,
492 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
493 } else if(!strncmp(name, "localfilesystem:", 16)) {
494 return socket_local_server(name + 16,
495 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
496 }
497
498 #endif
499 printf("unknown local portname '%s'\n", name);
500 return -1;
501 }
502
503 static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
504 {
505 alistener *l;
506
507 for (l = listener_list.next; l != &listener_list; l = l->next) {
508 if (!strcmp(local_name, l->local_name) &&
509 !strcmp(connect_to, l->connect_to) &&
510 l->transport && l->transport == transport) {
511
512 listener_disconnect(l, transport);
513 return 0;
514 }
515 }
516
517 return -1;
518 }
519
520 static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
521 {
522 alistener *l;
523
524 //printf("install_listener('%s','%s')\n", local_name, connect_to);
525
526 for(l = listener_list.next; l != &listener_list; l = l->next){
527 if(strcmp(local_name, l->local_name) == 0) {
528 char *cto;
529
530 /* can't repurpose a smartsocket */
531 if(l->connect_to[0] == '*') {
532 return -1;
533 }
534
535 cto = strdup(connect_to);
536 if(cto == 0) {
537 return -1;
538 }
539
540 //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
541 free((void*) l->connect_to);
542 l->connect_to = cto;
543 if (l->transport != transport) {
544 remove_transport_disconnect(l->transport, &l->disconnect);
545 l->transport = transport;
546 add_transport_disconnect(l->transport, &l->disconnect);
547 }
548 return 0;
549 }
550 }
551
552 if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
553 if((l->local_name = strdup(local_name)) == 0) goto nomem;
554 if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
555
556
557 l->fd = local_name_to_fd(local_name);
558 if(l->fd < 0) {
559 free((void*) l->local_name);
560 free((void*) l->connect_to);
561 free(l);
562 printf("cannot bind '%s'\n", local_name);
563 return -2;
564 }
565
566 close_on_exec(l->fd);
567 if(!strcmp(l->connect_to, "*smartsocket*")) {
568 fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
569 } else {
570 fdevent_install(&l->fde, l->fd, listener_event_func, l);
571 }
572 fdevent_set(&l->fde, FDE_READ);
573
574 l->next = &listener_list;
575 l->prev = listener_list.prev;
576 l->next->prev = l;
577 l->prev->next = l;
578 l->transport = transport;
579
580 if (transport) {
581 l->disconnect.opaque = l;
582 l->disconnect.func = listener_disconnect;
583 add_transport_disconnect(transport, &l->disconnect);
584 }
585 return 0;
586
587 nomem:
588 fatal("cannot allocate listener");
589 return 0;
590 }
591
592 #ifdef HAVE_FORKEXEC
593 static void sigchld_handler(int n)
594 {
595 int status;
596 while(waitpid(-1, &status, WNOHANG) > 0) ;
597 }
598 #endif
599
600 #ifdef HAVE_WIN32_PROC
601 static BOOL WINAPI ctrlc_handler(DWORD type)
602 {
603 exit(STATUS_CONTROL_C_EXIT);
604 return TRUE;
605 }
606 #endif
607
608 static void adb_cleanup(void)
609 {
610 usb_cleanup();
611 }
612
613 void start_logging(void)
614 {
615 #ifdef HAVE_WIN32_PROC
616 char temp[ MAX_PATH ];
617 FILE* fnul;
618 FILE* flog;
619
620 GetTempPath( sizeof(temp) - 8, temp );
621 strcat( temp, "adb.log" );
622
623 /* Win32 specific redirections */
624 fnul = fopen( "NUL", "rt" );
625 if (fnul != NULL)
626 stdin[0] = fnul[0];
627
628 flog = fopen( temp, "at" );
629 if (flog == NULL)
630 flog = fnul;
631
632 setvbuf( flog, NULL, _IONBF, 0 );
633
634 stdout[0] = flog[0];
635 stderr[0] = flog[0];
636 fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
637 #else
638 int fd;
639
640 fd = unix_open("/dev/null", O_RDONLY);
641 dup2(fd, 0);
642
643 fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
644 if(fd < 0) {
645 fd = unix_open("/dev/null", O_WRONLY);
646 }
647 dup2(fd, 1);
648 dup2(fd, 2);
649 fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
650 #endif
651 }
652
653 #if !ADB_HOST
654 void start_device_log(void)
655 {
656 int fd;
657 char path[100];
658
659 snprintf(path, sizeof path, "/data/adb_%ld.txt", (long)time(NULL));
660 fd = unix_open(path, O_WRONLY | O_CREAT | O_APPEND, 0640);
661 if (fd < 0)
662 return;
663
664 // redirect stdout and stderr to the log file
665 dup2(fd, 1);
666 dup2(fd, 2);
667 fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
668
669 fd = unix_open("/dev/null", O_RDONLY);
670 dup2(fd, 0);
671
672 // log everything
673 adb_trace_mask = ~0;
674 // except TRACE_RWX is a bit too verbose
675 adb_trace_mask &= ~TRACE_RWX;
676 }
677 #endif
678
679 #if ADB_HOST
680 int launch_server()
681 {
682 #ifdef HAVE_WIN32_PROC
683 /* we need to start the server in the background */
684 /* we create a PIPE that will be used to wait for the server's "OK" */
685 /* message since the pipe handles must be inheritable, we use a */
686 /* security attribute */
687 HANDLE pipe_read, pipe_write;
688 SECURITY_ATTRIBUTES sa;
689 STARTUPINFO startup;
690 PROCESS_INFORMATION pinfo;
691 char program_path[ MAX_PATH ];
692 int ret;
693
694 sa.nLength = sizeof(sa);
695 sa.lpSecurityDescriptor = NULL;
696 sa.bInheritHandle = TRUE;
697
698 /* create pipe, and ensure its read handle isn't inheritable */
699 ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
700 if (!ret) {
701 fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
702 return -1;
703 }
704
705 SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
706
707 ZeroMemory( &startup, sizeof(startup) );
708 startup.cb = sizeof(startup);
709 startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
710 startup.hStdOutput = pipe_write;
711 startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
712 startup.dwFlags = STARTF_USESTDHANDLES;
713
714 ZeroMemory( &pinfo, sizeof(pinfo) );
715
716 /* get path of current program */
717 GetModuleFileName( NULL, program_path, sizeof(program_path) );
718
719 ret = CreateProcess(
720 program_path, /* program path */
721 "adb fork-server server",
722 /* the fork-server argument will set the
723 debug = 2 in the child */
724 NULL, /* process handle is not inheritable */
725 NULL, /* thread handle is not inheritable */
726 TRUE, /* yes, inherit some handles */
727 DETACHED_PROCESS, /* the new process doesn't have a console */
728 NULL, /* use parent's environment block */
729 NULL, /* use parent's starting directory */
730 &startup, /* startup info, i.e. std handles */
731 &pinfo );
732
733 CloseHandle( pipe_write );
734
735 if (!ret) {
736 fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
737 CloseHandle( pipe_read );
738 return -1;
739 }
740
741 CloseHandle( pinfo.hProcess );
742 CloseHandle( pinfo.hThread );
743
744 /* wait for the "OK\n" message */
745 {
746 char temp[3];
747 DWORD count;
748
749 ret = ReadFile( pipe_read, temp, 3, &count, NULL );
750 CloseHandle( pipe_read );
751 if ( !ret ) {
752 fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
753 return -1;
754 }
755 if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
756 fprintf(stderr, "ADB server didn't ACK\n" );
757 return -1;
758 }
759 }
760 #elif defined(HAVE_FORKEXEC)
761 char path[PATH_MAX];
762 int fd[2];
763
764 // set up a pipe so the child can tell us when it is ready.
765 // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
766 if (pipe(fd)) {
767 fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
768 return -1;
769 }
770 get_my_path(path);
771 pid_t pid = fork();
772 if(pid < 0) return -1;
773
774 if (pid == 0) {
775 // child side of the fork
776
777 // redirect stderr to the pipe
778 // we use stderr instead of stdout due to stdout's buffering behavior.
779 adb_close(fd[0]);
780 dup2(fd[1], STDERR_FILENO);
781 adb_close(fd[1]);
782
783 // child process
784 int result = execl(path, "adb", "fork-server", "server", NULL);
785 // this should not return
786 fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
787 } else {
788 // parent side of the fork
789
790 char temp[3];
791
792 temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
793 // wait for the "OK\n" message
794 adb_close(fd[1]);
795 int ret = adb_read(fd[0], temp, 3);
796 adb_close(fd[0]);
797 if (ret < 0) {
798 fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno);
799 return -1;
800 }
801 if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
802 fprintf(stderr, "ADB server didn't ACK\n" );
803 return -1;
804 }
805
806 setsid();
807 }
808 #else
809 #error "cannot implement background server start on this platform"
810 #endif
811 return 0;
812 }
813 #endif
814
815 int adb_main(int is_daemon)
816 {
817 #if !ADB_HOST
818 int secure = 0;
819 char value[PROPERTY_VALUE_MAX];
820
821 // prevent the OOM killer from killing us
822 char text[64];
823 snprintf(text, sizeof text, "/proc/%d/oom_adj", (int)getpid());
824 int fd = adb_open(text, O_WRONLY);
825 if (fd >= 0) {
826 // -17 should make us immune to OOM
827 snprintf(text, sizeof text, "%d", -17);
828 adb_write(fd, text, strlen(text));
829 adb_close(fd);
830 } else {
831 D("adb: unable to open %s\n", text);
832 }
833 #endif
834
835 atexit(adb_cleanup);
836 #ifdef HAVE_WIN32_PROC
837 SetConsoleCtrlHandler( ctrlc_handler, TRUE );
838 #elif defined(HAVE_FORKEXEC)
839 signal(SIGCHLD, sigchld_handler);
840 signal(SIGPIPE, SIG_IGN);
841 #endif
842
843 init_transport_registration();
844
845
846 #if ADB_HOST
847 HOST = 1;
848 usb_init();
849 local_init();
850
851 if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
852 exit(1);
853 }
854 #else
855 /* run adbd in secure mode if ro.secure is set and
856 ** we are not in the emulator
857 */
858 property_get("ro.kernel.qemu", value, "");
859 if (strcmp(value, "1") != 0) {
860 property_get("ro.secure", value, "");
861 if (strcmp(value, "1") == 0)
862 secure = 1;
863 }
864
865 /* don't listen on port 5037 if we are running in secure mode */
866 /* don't run as root if we are running in secure mode */
867 if (secure) {
868 /* add extra groups:
869 ** AID_ADB to access the USB driver
870 ** AID_LOG to read system logs (adb logcat)
871 ** AID_INPUT to diagnose input issues (getevent)
872 ** AID_INET to diagnose network issues (netcfg, ping)
873 ** AID_GRAPHICS to access the frame buffer
874 */
875 gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS };
876 setgroups(sizeof(groups)/sizeof(groups[0]), groups);
877
878 /* then switch user and group to "shell" */
879 setgid(AID_SHELL);
880 setuid(AID_SHELL);
881
882 D("Local port 5037 disabled\n");
883 } else {
884 if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
885 exit(1);
886 }
887 }
888
889 /* for the device, start the usb transport if the
890 ** android usb device exists, otherwise start the
891 ** network transport.
892 */
893 if(access("/dev/android_adb", F_OK) == 0 ||
894 access("/dev/android", F_OK) == 0) {
895 usb_init();
896 } else {
897 local_init();
898 }
899 init_jdwp();
900 #endif
901
902 if (is_daemon)
903 {
904 // inform our parent that we are up and running.
905 #ifdef HAVE_WIN32_PROC
906 DWORD count;
907 WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
908 #elif defined(HAVE_FORKEXEC)
909 fprintf(stderr, "OK\n");
910 #endif
911 start_logging();
912 }
913
914 fdevent_loop();
915
916 usb_cleanup();
917
918 return 0;
919 }
920
921 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
922 {
923 atransport *transport = NULL;
924 char buf[4096];
925
926 if(!strcmp(service, "kill")) {
927 fprintf(stderr,"adb server killed by remote request\n");
928 fflush(stdout);
929 adb_write(reply_fd, "OKAY", 4);
930 usb_cleanup();
931 exit(0);
932 }
933
934 #if ADB_HOST
935 // "transport:" is used for switching transport with a specified serial number
936 // "transport-usb:" is used for switching transport to the only USB transport
937 // "transport-local:" is used for switching transport to the only local transport
938 // "transport-any:" is used for switching transport to the only transport
939 if (!strncmp(service, "transport", strlen("transport"))) {
940 char* error_string = "unknown failure";
941 transport_type type = kTransportAny;
942
943 if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
944 type = kTransportUsb;
945 } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
946 type = kTransportLocal;
947 } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
948 type = kTransportAny;
949 } else if (!strncmp(service, "transport:", strlen("transport:"))) {
950 service += strlen("transport:");
951 serial = strdup(service);
952 }
953
954 transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
955
956 if (transport) {
957 s->transport = transport;
958 adb_write(reply_fd, "OKAY", 4);
959 } else {
960 sendfailmsg(reply_fd, error_string);
961 }
962 return 1;
963 }
964
965 // return a list of all connected devices
966 if (!strcmp(service, "devices")) {
967 char buffer[4096];
968 memset(buf, 0, sizeof(buf));
969 memset(buffer, 0, sizeof(buffer));
970 D("Getting device list \n");
971 list_transports(buffer, sizeof(buffer));
972 snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
973 D("Wrote device list \n");
974 writex(reply_fd, buf, strlen(buf));
975 return 0;
976 }
977
978 // returns our value for ADB_SERVER_VERSION
979 if (!strcmp(service, "version")) {
980 char version[12];
981 snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
982 snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
983 writex(reply_fd, buf, strlen(buf));
984 return 0;
985 }
986
987 if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
988 char *out = "unknown";
989 transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
990 if (transport && transport->serial) {
991 out = transport->serial;
992 }
993 snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
994 writex(reply_fd, buf, strlen(buf));
995 return 0;
996 }
997 // indicates a new emulator instance has started
998 if (!strncmp(service,"emulator:",9)) {
999 int port = atoi(service+9);
1000 local_connect(port);
1001 /* we don't even need to send a reply */
1002 return 0;
1003 }
1004 #endif // ADB_HOST
1005
1006 if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
1007 char *local, *remote, *err;
1008 int r;
1009 atransport *transport;
1010
1011 int createForward = strncmp(service,"kill",4);
1012
1013 local = service + (createForward ? 8 : 12);
1014 remote = strchr(local,';');
1015 if(remote == 0) {
1016 sendfailmsg(reply_fd, "malformed forward spec");
1017 return 0;
1018 }
1019
1020 *remote++ = 0;
1021 if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
1022 sendfailmsg(reply_fd, "malformed forward spec");
1023 return 0;
1024 }
1025
1026 transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
1027 if (!transport) {
1028 sendfailmsg(reply_fd, err);
1029 return 0;
1030 }
1031
1032 if (createForward) {
1033 r = install_listener(local, remote, transport);
1034 } else {
1035 r = remove_listener(local, remote, transport);
1036 }
1037 if(r == 0) {
1038 /* 1st OKAY is connect, 2nd OKAY is status */
1039 writex(reply_fd, "OKAYOKAY", 8);
1040 return 0;
1041 }
1042
1043 if (createForward) {
1044 sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
1045 } else {
1046 sendfailmsg(reply_fd, "cannot remove listener");
1047 }
1048 return 0;
1049 }
1050
1051 if(!strncmp(service,"get-state",strlen("get-state"))) {
1052 transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
1053 char *state = connection_state_name(transport);
1054 snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
1055 writex(reply_fd, buf, strlen(buf));
1056 return 0;
1057 }
1058 return -1;
1059 }
1060
1061 #if !ADB_HOST
1062 int recovery_mode = 0;
1063 #endif
1064
1065 int main(int argc, char **argv)
1066 {
1067 adb_trace_init();
1068 #if ADB_HOST
1069 adb_sysdeps_init();
1070 return adb_commandline(argc - 1, argv + 1);
1071 #else
1072 if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
1073 adb_device_banner = "recovery";
1074 recovery_mode = 1;
1075 }
1076 #if ADB_DEVICE_LOG
1077 start_device_log();
1078 #endif
1079 return adb_main(0);
1080 #endif
1081 }
1082
+0
-407
adb/adb.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __ADB_H
17 #define __ADB_H
18
19 #include <limits.h>
20
21 #define MAX_PAYLOAD 4096
22
23 #define A_SYNC 0x434e5953
24 #define A_CNXN 0x4e584e43
25 #define A_OPEN 0x4e45504f
26 #define A_OKAY 0x59414b4f
27 #define A_CLSE 0x45534c43
28 #define A_WRTE 0x45545257
29
30 #define A_VERSION 0x01000000 // ADB protocol version
31
32 #define ADB_VERSION_MAJOR 1 // Used for help/version information
33 #define ADB_VERSION_MINOR 0 // Used for help/version information
34
35 #define ADB_SERVER_VERSION 20 // Increment this when we want to force users to start a new adb server
36
37 typedef struct amessage amessage;
38 typedef struct apacket apacket;
39 typedef struct asocket asocket;
40 typedef struct alistener alistener;
41 typedef struct aservice aservice;
42 typedef struct atransport atransport;
43 typedef struct adisconnect adisconnect;
44 typedef struct usb_handle usb_handle;
45
46 struct amessage {
47 unsigned command; /* command identifier constant */
48 unsigned arg0; /* first argument */
49 unsigned arg1; /* second argument */
50 unsigned data_length; /* length of payload (0 is allowed) */
51 unsigned data_check; /* checksum of data payload */
52 unsigned magic; /* command ^ 0xffffffff */
53 };
54
55 struct apacket
56 {
57 apacket *next;
58
59 unsigned len;
60 unsigned char *ptr;
61
62 amessage msg;
63 unsigned char data[MAX_PAYLOAD];
64 };
65
66 /* An asocket represents one half of a connection between a local and
67 ** remote entity. A local asocket is bound to a file descriptor. A
68 ** remote asocket is bound to the protocol engine.
69 */
70 struct asocket {
71 /* chain pointers for the local/remote list of
72 ** asockets that this asocket lives in
73 */
74 asocket *next;
75 asocket *prev;
76
77 /* the unique identifier for this asocket
78 */
79 unsigned id;
80
81 /* flag: set when the socket's peer has closed
82 ** but packets are still queued for delivery
83 */
84 int closing;
85
86 /* the asocket we are connected to
87 */
88
89 asocket *peer;
90
91 /* For local asockets, the fde is used to bind
92 ** us to our fd event system. For remote asockets
93 ** these fields are not used.
94 */
95 fdevent fde;
96 int fd;
97
98 /* queue of apackets waiting to be written
99 */
100 apacket *pkt_first;
101 apacket *pkt_last;
102
103 /* enqueue is called by our peer when it has data
104 ** for us. It should return 0 if we can accept more
105 ** data or 1 if not. If we return 1, we must call
106 ** peer->ready() when we once again are ready to
107 ** receive data.
108 */
109 int (*enqueue)(asocket *s, apacket *pkt);
110
111 /* ready is called by the peer when it is ready for
112 ** us to send data via enqueue again
113 */
114 void (*ready)(asocket *s);
115
116 /* close is called by the peer when it has gone away.
117 ** we are not allowed to make any further calls on the
118 ** peer once our close method is called.
119 */
120 void (*close)(asocket *s);
121
122 /* socket-type-specific extradata */
123 void *extra;
124
125 /* A socket is bound to atransport */
126 atransport *transport;
127 };
128
129
130 /* the adisconnect structure is used to record a callback that
131 ** will be called whenever a transport is disconnected (e.g. by the user)
132 ** this should be used to cleanup objects that depend on the
133 ** transport (e.g. remote sockets, listeners, etc...)
134 */
135 struct adisconnect
136 {
137 void (*func)(void* opaque, atransport* t);
138 void* opaque;
139 adisconnect* next;
140 adisconnect* prev;
141 };
142
143
144 /* a transport object models the connection to a remote device or emulator
145 ** there is one transport per connected device/emulator. a "local transport"
146 ** connects through TCP (for the emulator), while a "usb transport" through
147 ** USB (for real devices)
148 **
149 ** note that kTransportHost doesn't really correspond to a real transport
150 ** object, it's a special value used to indicate that a client wants to
151 ** connect to a service implemented within the ADB server itself.
152 */
153 typedef enum transport_type {
154 kTransportUsb,
155 kTransportLocal,
156 kTransportAny,
157 kTransportHost,
158 } transport_type;
159
160 struct atransport
161 {
162 atransport *next;
163 atransport *prev;
164
165 int (*read_from_remote)(apacket *p, atransport *t);
166 int (*write_to_remote)(apacket *p, atransport *t);
167 void (*close)(atransport *t);
168 void (*kick)(atransport *t);
169
170 int fd;
171 int transport_socket;
172 fdevent transport_fde;
173 int ref_count;
174 unsigned sync_token;
175 int connection_state;
176 transport_type type;
177
178 /* usb handle or socket fd as needed */
179 usb_handle *usb;
180 int sfd;
181
182 /* used to identify transports for clients */
183 char *serial;
184 char *product;
185
186 /* a list of adisconnect callbacks called when the transport is kicked */
187 int kicked;
188 adisconnect disconnects;
189 };
190
191
192 /* A listener is an entity which binds to a local port
193 ** and, upon receiving a connection on that port, creates
194 ** an asocket to connect the new local connection to a
195 ** specific remote service.
196 **
197 ** TODO: some listeners read from the new connection to
198 ** determine what exact service to connect to on the far
199 ** side.
200 */
201 struct alistener
202 {
203 alistener *next;
204 alistener *prev;
205
206 fdevent fde;
207 int fd;
208
209 const char *local_name;
210 const char *connect_to;
211 atransport *transport;
212 adisconnect disconnect;
213 };
214
215
216 void print_packet(const char *label, apacket *p);
217
218 asocket *find_local_socket(unsigned id);
219 void install_local_socket(asocket *s);
220 void remove_socket(asocket *s);
221 void close_all_sockets(atransport *t);
222
223 #define LOCAL_CLIENT_PREFIX "emulator-"
224
225 asocket *create_local_socket(int fd);
226 asocket *create_local_service_socket(const char *destination);
227
228 asocket *create_remote_socket(unsigned id, atransport *t);
229 void connect_to_remote(asocket *s, const char *destination);
230 void connect_to_smartsocket(asocket *s);
231
232 void fatal(const char *fmt, ...);
233 void fatal_errno(const char *fmt, ...);
234
235 void handle_packet(apacket *p, atransport *t);
236 void send_packet(apacket *p, atransport *t);
237
238 void get_my_path(char s[PATH_MAX]);
239 int launch_server();
240 int adb_main(int is_daemon);
241
242
243 /* transports are ref-counted
244 ** get_device_transport does an acquire on your behalf before returning
245 */
246 void init_transport_registration(void);
247 int list_transports(char *buf, size_t bufsize);
248 void update_transports(void);
249
250 asocket* create_device_tracker(void);
251
252 /* Obtain a transport from the available transports.
253 ** If state is != CS_ANY, only transports in that state are considered.
254 ** If serial is non-NULL then only the device with that serial will be chosen.
255 ** If no suitable transport is found, error is set.
256 */
257 atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
258 void add_transport_disconnect( atransport* t, adisconnect* dis );
259 void remove_transport_disconnect( atransport* t, adisconnect* dis );
260 void run_transport_disconnects( atransport* t );
261 void kick_transport( atransport* t );
262
263 /* initialize a transport object's func pointers and state */
264 int init_socket_transport(atransport *t, int s, int port);
265 void init_usb_transport(atransport *t, usb_handle *usb);
266
267 /* for MacOS X cleanup */
268 void close_usb_devices();
269
270 /* cause new transports to be init'd and added to the list */
271 void register_socket_transport(int s, const char *serial, int port);
272 void register_usb_transport(usb_handle *h, const char *serial);
273
274 int service_to_fd(const char *name);
275 #if ADB_HOST
276 asocket *host_service_to_socket(const char* name, const char *serial);
277 #endif
278
279 #if !ADB_HOST
280 int init_jdwp(void);
281 asocket* create_jdwp_service_socket();
282 asocket* create_jdwp_tracker_service_socket();
283 int create_jdwp_connection_fd(int jdwp_pid);
284 #endif
285
286 #if !ADB_HOST
287 void framebuffer_service(int fd, void *cookie);
288 void log_service(int fd, void *cookie);
289 void remount_service(int fd, void *cookie);
290 char * get_log_file_path(const char * log_name);
291 #endif
292
293 /* packet allocator */
294 apacket *get_apacket(void);
295 void put_apacket(apacket *p);
296
297 int check_header(apacket *p);
298 int check_data(apacket *p);
299
300 /* convenience wrappers around read/write that will retry on
301 ** EINTR and/or short read/write. Returns 0 on success, -1
302 ** on error or EOF.
303 */
304 int readx(int fd, void *ptr, size_t len);
305 int writex(int fd, const void *ptr, size_t len);
306
307 /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
308
309 #define ADB_TRACE 1
310
311 /* IMPORTANT: if you change the following list, don't
312 * forget to update the corresponding 'tags' table in
313 * the adb_trace_init() function implemented in adb.c
314 */
315 typedef enum {
316 TRACE_ADB = 0,
317 TRACE_SOCKETS,
318 TRACE_PACKETS,
319 TRACE_TRANSPORT,
320 TRACE_RWX,
321 TRACE_USB,
322 TRACE_SYNC,
323 TRACE_SYSDEPS,
324 TRACE_JDWP,
325 } AdbTrace;
326
327 #if ADB_TRACE
328
329 int adb_trace_mask;
330
331 void adb_trace_init(void);
332
333 # define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
334
335 /* you must define TRACE_TAG before using this macro */
336 #define D(...) \
337 do { \
338 if (ADB_TRACING) \
339 fprintf(stderr, __VA_ARGS__ ); \
340 } while (0)
341 #else
342 # define D(...) ((void)0)
343 # define ADB_TRACING 0
344 #endif
345
346
347 /* set this to log to /data/adb/adb_<time>.txt on the device.
348 * has no effect if the /data/adb/ directory does not exist.
349 */
350 #define ADB_DEVICE_LOG 0
351
352 #if !TRACE_PACKETS
353 #define print_packet(tag,p) do {} while (0)
354 #endif
355
356 #define ADB_PORT 5037
357 #define ADB_LOCAL_TRANSPORT_PORT 5555
358
359 // Google's USB Vendor ID
360 #define VENDOR_ID_GOOGLE 0x18d1
361 // HTC's USB Vendor ID
362 #define VENDOR_ID_HTC 0x0bb4
363
364 // products for VENDOR_ID_GOOGLE
365 #define PRODUCT_ID_SOONER 0xd00d // Sooner bootloader
366 #define PRODUCT_ID_SOONER_COMP 0xdeed // Sooner composite device
367
368 // products for VENDOR_ID_HTC
369 #define PRODUCT_ID_DREAM 0x0c01 // Dream bootloader
370 #define PRODUCT_ID_DREAM_COMP 0x0c02 // Dream composite device
371
372 void local_init();
373 int local_connect(int port);
374
375 /* usb host/client interface */
376 void usb_init();
377 void usb_cleanup();
378 int usb_write(usb_handle *h, const void *data, int len);
379 int usb_read(usb_handle *h, void *data, int len);
380 int usb_close(usb_handle *h);
381 void usb_kick(usb_handle *h);
382
383 /* used for USB device detection */
384 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
385
386 unsigned host_to_le32(unsigned n);
387 int adb_commandline(int argc, char **argv);
388
389 int connection_state(atransport *t);
390
391 #define CS_ANY -1
392 #define CS_OFFLINE 0
393 #define CS_BOOTLOADER 1
394 #define CS_DEVICE 2
395 #define CS_HOST 3
396 #define CS_RECOVERY 4
397 #define CS_ERROR 5
398
399 extern int HOST;
400
401 #define CHUNK_SIZE (64*1024)
402
403 int sendfailmsg(int fd, const char *reason);
404 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
405
406 #endif
+0
-318
adb/adb_client.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdarg.h>
6 #include <zipfile/zipfile.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9
10 #include "sysdeps.h"
11
12 #define TRACE_TAG TRACE_ADB
13 #include "adb_client.h"
14
15 static transport_type __adb_transport = kTransportAny;
16 static const char* __adb_serial = NULL;
17
18 void adb_set_transport(transport_type type, const char* serial)
19 {
20 __adb_transport = type;
21 __adb_serial = serial;
22 }
23
24 int adb_get_emulator_console_port(void)
25 {
26 const char* serial = __adb_serial;
27 int port;
28
29 if (serial == NULL) {
30 /* if no specific device was specified, we need to look at */
31 /* the list of connected devices, and extract an emulator */
32 /* name from it. two emulators is an error */
33 char* tmp = adb_query("host:devices");
34 char* p = tmp;
35 if(!tmp) {
36 printf("no emulator connected\n");
37 return -1;
38 }
39 while (*p) {
40 char* q = strchr(p, '\n');
41 if (q != NULL)
42 *q++ = 0;
43 else
44 q = p + strlen(p);
45
46 if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
47 if (serial != NULL) { /* more than one emulator listed */
48 free(tmp);
49 return -2;
50 }
51 serial = p;
52 }
53
54 p = q;
55 }
56 free(tmp);
57
58 if (serial == NULL)
59 return -1; /* no emulator found */
60 }
61 else {
62 if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
63 return -1; /* not an emulator */
64 }
65
66 serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
67 port = strtol(serial, NULL, 10);
68 return port;
69 }
70
71 static char __adb_error[256] = { 0 };
72
73 const char *adb_error(void)
74 {
75 return __adb_error;
76 }
77
78 static int switch_socket_transport(int fd)
79 {
80 char service[64];
81 char tmp[5];
82 int len;
83
84 if (__adb_serial)
85 snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
86 else {
87 char* transport_type = "???";
88
89 switch (__adb_transport) {
90 case kTransportUsb:
91 transport_type = "transport-usb";
92 break;
93 case kTransportLocal:
94 transport_type = "transport-local";
95 break;
96 case kTransportAny:
97 transport_type = "transport-any";
98 break;
99 case kTransportHost:
100 // no switch necessary
101 return 0;
102 break;
103 }
104
105 snprintf(service, sizeof service, "host:%s", transport_type);
106 }
107 len = strlen(service);
108 snprintf(tmp, sizeof tmp, "%04x", len);
109
110 if(writex(fd, tmp, 4) || writex(fd, service, len)) {
111 strcpy(__adb_error, "write failure during connection");
112 adb_close(fd);
113 return -1;
114 }
115 D("Switch transport in progress\n");
116
117 if(adb_status(fd)) {
118 adb_close(fd);
119 D("Switch transport failed\n");
120 return -1;
121 }
122 D("Switch transport success\n");
123 return 0;
124 }
125
126 int adb_status(int fd)
127 {
128 unsigned char buf[5];
129 unsigned len;
130
131 if(readx(fd, buf, 4)) {
132 strcpy(__adb_error, "protocol fault (no status)");
133 return -1;
134 }
135
136 if(!memcmp(buf, "OKAY", 4)) {
137 return 0;
138 }
139
140 if(memcmp(buf, "FAIL", 4)) {
141 sprintf(__adb_error,
142 "protocol fault (status %02x %02x %02x %02x?!)",
143 buf[0], buf[1], buf[2], buf[3]);
144 return -1;
145 }
146
147 if(readx(fd, buf, 4)) {
148 strcpy(__adb_error, "protocol fault (status len)");
149 return -1;
150 }
151 buf[4] = 0;
152 len = strtoul((char*)buf, 0, 16);
153 if(len > 255) len = 255;
154 if(readx(fd, __adb_error, len)) {
155 strcpy(__adb_error, "protocol fault (status read)");
156 return -1;
157 }
158 __adb_error[len] = 0;
159 return -1;
160 }
161
162 int _adb_connect(const char *service)
163 {
164 char tmp[5];
165 int len;
166 int fd;
167
168 D("_adb_connect: %s\n", service);
169 len = strlen(service);
170 if((len < 1) || (len > 1024)) {
171 strcpy(__adb_error, "service name too long");
172 return -1;
173 }
174 snprintf(tmp, sizeof tmp, "%04x", len);
175
176 fd = socket_loopback_client(ADB_PORT, SOCK_STREAM);
177 if(fd < 0) {
178 strcpy(__adb_error, "cannot connect to daemon");
179 return -2;
180 }
181
182 if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
183 return -1;
184 }
185
186 if(writex(fd, tmp, 4) || writex(fd, service, len)) {
187 strcpy(__adb_error, "write failure during connection");
188 adb_close(fd);
189 return -1;
190 }
191
192 if(adb_status(fd)) {
193 adb_close(fd);
194 return -1;
195 }
196
197 return fd;
198 }
199
200 int adb_connect(const char *service)
201 {
202 // first query the adb server's version
203 int fd = _adb_connect("host:version");
204
205 if(fd == -2) {
206 fprintf(stdout,"* daemon not running. starting it now *\n");
207 start_server:
208 if(launch_server(0)) {
209 fprintf(stderr,"* failed to start daemon *\n");
210 return -1;
211 } else {
212 fprintf(stdout,"* daemon started successfully *\n");
213 }
214 /* give the server some time to start properly and detect devices */
215 adb_sleep_ms(2000);
216 // fall through to _adb_connect
217 } else {
218 // if server was running, check its version to make sure it is not out of date
219 char buf[100];
220 int n;
221 int version = ADB_SERVER_VERSION - 1;
222
223 // if we have a file descriptor, then parse version result
224 if(fd >= 0) {
225 if(readx(fd, buf, 4)) goto error;
226
227 buf[4] = 0;
228 n = strtoul(buf, 0, 16);
229 if(n > (int)sizeof(buf)) goto error;
230 if(readx(fd, buf, n)) goto error;
231 adb_close(fd);
232
233 if (sscanf(buf, "%04x", &version) != 1) goto error;
234 } else {
235 // if fd is -1, then check for "unknown host service",
236 // which would indicate a version of adb that does not support the version command
237 if (strcmp(__adb_error, "unknown host service") != 0)
238 return fd;
239 }
240
241 if(version != ADB_SERVER_VERSION) {
242 printf("adb server is out of date. killing...\n");
243 fd = _adb_connect("host:kill");
244 adb_close(fd);
245
246 /* XXX can we better detect its death? */
247 adb_sleep_ms(2000);
248 goto start_server;
249 }
250 }
251
252 // if the command is start-server, we are done.
253 if (!strcmp(service, "host:start-server"))
254 return 0;
255
256 fd = _adb_connect(service);
257 if(fd == -2) {
258 fprintf(stderr,"** daemon still not running");
259 }
260
261 return fd;
262 error:
263 adb_close(fd);
264 return -1;
265 }
266
267
268 int adb_command(const char *service)
269 {
270 int fd = adb_connect(service);
271 if(fd < 0) {
272 return -1;
273 }
274
275 if(adb_status(fd)) {
276 adb_close(fd);
277 return -1;
278 }
279
280 return 0;
281 }
282
283 char *adb_query(const char *service)
284 {
285 char buf[5];
286 unsigned n;
287 char *tmp;
288
289 D("adb_query: %s\n", service);
290 int fd = adb_connect(service);
291 if(fd < 0) {
292 fprintf(stderr,"error: %s\n", __adb_error);
293 return 0;
294 }
295
296 if(readx(fd, buf, 4)) goto oops;
297
298 buf[4] = 0;
299 n = strtoul(buf, 0, 16);
300 if(n > 1024) goto oops;
301
302 tmp = malloc(n + 1);
303 if(tmp == 0) goto oops;
304
305 if(readx(fd, tmp, n) == 0) {
306 tmp[n] = 0;
307 adb_close(fd);
308 return tmp;
309 }
310 free(tmp);
311
312 oops:
313 adb_close(fd);
314 return 0;
315 }
316
317
+0
-49
adb/adb_client.h less more
0 #ifndef _ADB_CLIENT_H_
1 #define _ADB_CLIENT_H_
2
3 #include "adb.h"
4
5 /* connect to adb, connect to the named service, and return
6 ** a valid fd for interacting with that service upon success
7 ** or a negative number on failure
8 */
9 int adb_connect(const char *service);
10 int _adb_connect(const char *service);
11
12 /* connect to adb, connect to the named service, return 0 if
13 ** the connection succeeded AND the service returned OKAY
14 */
15 int adb_command(const char *service);
16
17 /* connect to adb, connect to the named service, return
18 ** a malloc'd string of its response upon success or NULL
19 ** on failure.
20 */
21 char *adb_query(const char *service);
22
23 /* Set the preferred transport to connect to.
24 */
25 void adb_set_transport(transport_type type, const char* serial);
26
27 /* Return the console port of the currently connected emulator (if any)
28 * of -1 if there is no emulator, and -2 if there is more than one.
29 * assumes adb_set_transport() was alled previously...
30 */
31 int adb_get_emulator_console_port(void);
32
33 /* send commands to the current emulator instance. will fail if there
34 * is zero, or more than one emulator connected (or if you use -s <serial>
35 * with a <serial> that does not designate an emulator)
36 */
37 int adb_send_emulator_command(int argc, char** argv);
38
39 /* return verbose error string from last operation */
40 const char *adb_error(void);
41
42 /* read a standard adb status response (OKAY|FAIL) and
43 ** return 0 in the event of OKAY, -1 in the event of FAIL
44 ** or protocol error
45 */
46 int adb_status(int fd);
47
48 #endif
+0
-1249
adb/commandline.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <limits.h>
22 #include <stdarg.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <ctype.h>
26 #include <assert.h>
27
28 #include "sysdeps.h"
29
30 #ifdef HAVE_TERMIO_H
31 #include <termios.h>
32 #endif
33
34 #define TRACE_TAG TRACE_ADB
35 #include "adb.h"
36 #include "adb_client.h"
37 #include "file_sync_service.h"
38
39 #ifdef SH_HISTORY
40 #include "shlist.h"
41 #include "history.h"
42 #endif
43
44 enum {
45 IGNORE_DATA,
46 WIPE_DATA,
47 FLASH_DATA
48 };
49
50 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
51
52 void get_my_path(char s[PATH_MAX]);
53 int find_sync_dirs(const char *srcarg,
54 char **android_srcdir_out, char **data_srcdir_out);
55 int install_app(transport_type transport, char* serial, int argc, char** argv);
56 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
57
58 static const char *gProductOutPath = NULL;
59
60 static char *product_file(const char *extra)
61 {
62 int n;
63 char *x;
64
65 if (gProductOutPath == NULL) {
66 fprintf(stderr, "adb: Product directory not specified; "
67 "use -p or define ANDROID_PRODUCT_OUT\n");
68 exit(1);
69 }
70
71 n = strlen(gProductOutPath) + strlen(extra) + 2;
72 x = malloc(n);
73 if (x == 0) {
74 fprintf(stderr, "adb: Out of memory (product_file())\n");
75 exit(1);
76 }
77
78 snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
79 return x;
80 }
81
82 void version(FILE * out) {
83 fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
84 ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
85 }
86
87 void help()
88 {
89 version(stderr);
90
91 fprintf(stderr,
92 "\n"
93 " -d - directs command to the only connected USB device\n"
94 " returns an error if more than one USB device is present.\n"
95 " -e - directs command to the only running emulator.\n"
96 " returns an error if more than one emulator is running.\n"
97 " -s <serial number> - directs command to the USB device or emulator with\n"
98 " the given serial number\n"
99 " -p <product name or path> - simple product name like 'sooner', or\n"
100 " a relative/absolute path to a product\n"
101 " out directory like 'out/target/product/sooner'.\n"
102 " If -p is not specified, the ANDROID_PRODUCT_OUT\n"
103 " environment variable is used, which must\n"
104 " be an absolute path.\n"
105 " devices - list all connected devices\n"
106 "\n"
107 "device commands:\n"
108 " adb push <local> <remote> - copy file/dir to device\n"
109 " adb pull <remote> <local> - copy file/dir from device\n"
110 " adb sync [ <directory> ] - copy host->device only if changed\n"
111 " (see 'adb help all')\n"
112 " adb shell - run remote shell interactively\n"
113 " adb shell <command> - run remote shell command\n"
114 " adb emu <command> - run emulator console command\n"
115 " adb logcat [ <filter-spec> ] - View device log\n"
116 " adb forward <local> <remote> - forward socket connections\n"
117 " forward specs are one of: \n"
118 " tcp:<port>\n"
119 " localabstract:<unix domain socket name>\n"
120 " localreserved:<unix domain socket name>\n"
121 " localfilesystem:<unix domain socket name>\n"
122 " dev:<character device name>\n"
123 " jdwp:<process pid> (remote only)\n"
124 " adb jdwp - list PIDs of processes hosting a JDWP transport\n"
125 " adb install [-l] [-r] <file> - push this package file to the device and install it\n"
126 " ('-l' means forward-lock the app)\n"
127 " ('-r' means reinstall the app, keeping its data)\n"
128 " adb uninstall [-k] <package> - remove this app package from the device\n"
129 " ('-k' means keep the data and cache directories)\n"
130 " adb bugreport - return all information from the device\n"
131 " that should be included in a bug report.\n"
132 "\n"
133 " adb help - show this help message\n"
134 " adb version - show version num\n"
135 "\n"
136 "DATAOPTS:\n"
137 " (no option) - don't touch the data partition\n"
138 " -w - wipe the data partition\n"
139 " -d - flash the data partition\n"
140 "\n"
141 "scripting:\n"
142 " adb wait-for-device - block until device is online\n"
143 " adb start-server - ensure that there is a server running\n"
144 " adb kill-server - kill the server if it is running\n"
145 " adb get-state - prints: offline | bootloader | device\n"
146 " adb get-serialno - prints: <serial-number>\n"
147 " adb status-window - continuously print device status for a specified device\n"
148 " adb remount - remounts the /system partition on the device read-write\n"
149 "\n"
150 "networking:\n"
151 " adb ppp <tty> [parameters] - Run PPP over USB.\n"
152 " Note: you should not automatically start a PDP connection.\n"
153 " <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1\n"
154 " [parameters] - Eg. defaultroute debug dump local notty usepeerdns\n"
155 "\n"
156 "adb sync notes: adb sync [ <directory> ]\n"
157 " <localdir> can be interpreted in several ways:\n"
158 "\n"
159 " - If <directory> is not specified, both /system and /data partitions will be updated.\n"
160 "\n"
161 " - If it is \"system\" or \"data\", only the corresponding partition\n"
162 " is updated.\n"
163 );
164 }
165
166 int usage()
167 {
168 help();
169 return 1;
170 }
171
172 #ifdef HAVE_TERMIO_H
173 static struct termios tio_save;
174
175 static void stdin_raw_init(int fd)
176 {
177 struct termios tio;
178
179 if(tcgetattr(fd, &tio)) return;
180 if(tcgetattr(fd, &tio_save)) return;
181
182 tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
183
184 /* no timeout but request at least one character per read */
185 tio.c_cc[VTIME] = 0;
186 tio.c_cc[VMIN] = 1;
187
188 tcsetattr(fd, TCSANOW, &tio);
189 tcflush(fd, TCIFLUSH);
190 }
191
192 static void stdin_raw_restore(int fd)
193 {
194 tcsetattr(fd, TCSANOW, &tio_save);
195 tcflush(fd, TCIFLUSH);
196 }
197 #endif
198
199 static void read_and_dump(int fd)
200 {
201 char buf[4096];
202 int len;
203
204 while(fd >= 0) {
205 len = adb_read(fd, buf, 4096);
206 if(len == 0) {
207 break;
208 }
209
210 if(len < 0) {
211 if(errno == EINTR) continue;
212 break;
213 }
214 /* we want to output to stdout, so no adb_write here !! */
215 unix_write(1, buf, len);
216 }
217 }
218
219 #ifdef SH_HISTORY
220 int shItemCmp( void *val, void *idata )
221 {
222 return( (strcmp( val, idata ) == 0) );
223 }
224 #endif
225
226 static void *stdin_read_thread(void *x)
227 {
228 int fd, fdi;
229 unsigned char buf[1024];
230 #ifdef SH_HISTORY
231 unsigned char realbuf[1024], *buf_ptr;
232 SHLIST history;
233 SHLIST *item = &history;
234 int cmdlen = 0, ins_flag = 0;
235 #endif
236 int r, n;
237 int state = 0;
238
239 int *fds = (int*) x;
240 fd = fds[0];
241 fdi = fds[1];
242 free(fds);
243
244 #ifdef SH_HISTORY
245 shListInitList( &history );
246 #endif
247 for(;;) {
248 /* fdi is really the client's stdin, so use read, not adb_read here */
249 r = unix_read(fdi, buf, 1024);
250 if(r == 0) break;
251 if(r < 0) {
252 if(errno == EINTR) continue;
253 break;
254 }
255 #ifdef SH_HISTORY
256 if( (r == 3) && /* Arrow processing */
257 (memcmp( (void *)buf, SH_ARROW_ANY, 2 ) == 0) ) {
258 switch( buf[2] ) {
259 case SH_ARROW_UP:
260 item = shListGetNextItem( &history, item );
261 break;
262 case SH_ARROW_DOWN:
263 item = shListGetPrevItem( &history, item );
264 break;
265 default:
266 item = NULL;
267 break;
268 }
269 memset( buf, SH_DEL_CHAR, cmdlen );
270 if( item != NULL ) {
271 n = snprintf( (char *)(&buf[cmdlen]), sizeof buf - cmdlen, "%s", (char *)(item->data) );
272 memcpy( realbuf, item->data, n );
273 }
274 else { /* Clean buffer */
275 item = &history;
276 n = 0;
277 }
278 r = n + cmdlen;
279 cmdlen = n;
280 ins_flag = 0;
281 if( r == 0 )
282 continue;
283 }
284 else {
285 #endif
286 for(n = 0; n < r; n++){
287 switch(buf[n]) {
288 case '\n':
289 #ifdef SH_HISTORY
290 if( ins_flag && (SH_BLANK_CHAR <= realbuf[0]) ) {
291 buf_ptr = malloc(cmdlen + 1);
292 if( buf_ptr != NULL ) {
293 memcpy( buf_ptr, realbuf, cmdlen );
294 buf_ptr[cmdlen] = '\0';
295 if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
296 shListInsFirstItem( &history, (void *)buf_ptr );
297 item = &history;
298 }
299 }
300 }
301 cmdlen = 0;
302 ins_flag = 0;
303 #endif
304 state = 1;
305 break;
306 case '\r':
307 state = 1;
308 break;
309 case '~':
310 if(state == 1) state++;
311 break;
312 case '.':
313 if(state == 2) {
314 fprintf(stderr,"\n* disconnect *\n");
315 #ifdef HAVE_TERMIO_H
316 stdin_raw_restore(fdi);
317 #endif
318 exit(0);
319 }
320 default:
321 #ifdef SH_HISTORY
322 if( buf[n] == SH_DEL_CHAR ) {
323 if( cmdlen > 0 )
324 cmdlen--;
325 }
326 else {
327 realbuf[cmdlen] = buf[n];
328 cmdlen++;
329 }
330 ins_flag = 1;
331 #endif
332 state = 0;
333 }
334 }
335 #ifdef SH_HISTORY
336 }
337 #endif
338 r = adb_write(fd, buf, r);
339 if(r <= 0) {
340 break;
341 }
342 }
343 #ifdef SH_HISTORY
344 shListDelAllItems( &history, (shListFree)free );
345 #endif
346 return 0;
347 }
348
349 int interactive_shell(void)
350 {
351 adb_thread_t thr;
352 int fdi, fd;
353 int *fds;
354
355 fd = adb_connect("shell:");
356 if(fd < 0) {
357 fprintf(stderr,"error: %s\n", adb_error());
358 return 1;
359 }
360 fdi = 0; //dup(0);
361
362 fds = malloc(sizeof(int) * 2);
363 fds[0] = fd;
364 fds[1] = fdi;
365
366 #ifdef HAVE_TERMIO_H
367 stdin_raw_init(fdi);
368 #endif
369 adb_thread_create(&thr, stdin_read_thread, fds);
370 read_and_dump(fd);
371 #ifdef HAVE_TERMIO_H
372 stdin_raw_restore(fdi);
373 #endif
374 return 0;
375 }
376
377
378 static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
379 {
380 if (serial) {
381 snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
382 } else {
383 const char* prefix = "host";
384 if (ttype == kTransportUsb)
385 prefix = "host-usb";
386 else if (ttype == kTransportLocal)
387 prefix = "host-local";
388
389 snprintf(buffer, buflen, "%s:%s", prefix, command);
390 }
391 }
392
393 static void status_window(transport_type ttype, const char* serial)
394 {
395 char command[4096];
396 char *state = 0;
397 char *laststate = 0;
398
399 /* silence stderr */
400 #ifdef _WIN32
401 /* XXX: TODO */
402 #else
403 int fd;
404 fd = unix_open("/dev/null", O_WRONLY);
405 dup2(fd, 2);
406 adb_close(fd);
407 #endif
408
409 format_host_command(command, sizeof command, "get-state", ttype, serial);
410
411 for(;;) {
412 adb_sleep_ms(250);
413
414 if(state) {
415 free(state);
416 state = 0;
417 }
418
419 state = adb_query(command);
420
421 if(state) {
422 if(laststate && !strcmp(state,laststate)){
423 continue;
424 } else {
425 if(laststate) free(laststate);
426 laststate = strdup(state);
427 }
428 }
429
430 printf("%c[2J%c[2H", 27, 27);
431 printf("Android Debug Bridge\n");
432 printf("State: %s\n", state ? state : "offline");
433 fflush(stdout);
434 }
435 }
436
437 /** duplicate string and quote all \ " ( ) chars + space character. */
438 static char *
439 dupAndQuote(const char *s)
440 {
441 const char *ts;
442 size_t alloc_len;
443 char *ret;
444 char *dest;
445
446 ts = s;
447
448 alloc_len = 0;
449
450 for( ;*ts != '\0'; ts++) {
451 alloc_len++;
452 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
453 alloc_len++;
454 }
455 }
456
457 ret = (char *)malloc(alloc_len + 1);
458
459 ts = s;
460 dest = ret;
461
462 for ( ;*ts != '\0'; ts++) {
463 if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
464 *dest++ = '\\';
465 }
466
467 *dest++ = *ts;
468 }
469
470 *dest++ = '\0';
471
472 return ret;
473 }
474
475 /**
476 * Run ppp in "notty" mode against a resource listed as the first parameter
477 * eg:
478 *
479 * ppp dev:/dev/omap_csmi_tty0 <ppp options>
480 *
481 */
482 int ppp(int argc, char **argv)
483 {
484 #ifdef HAVE_WIN32_PROC
485 fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
486 return -1;
487 #else
488 char *adb_service_name;
489 pid_t pid;
490 int fd;
491
492 if (argc < 2) {
493 fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
494 argv[0]);
495
496 return 1;
497 }
498
499 adb_service_name = argv[1];
500
501 fd = adb_connect(adb_service_name);
502
503 if(fd < 0) {
504 fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
505 adb_service_name, adb_error());
506 return 1;
507 }
508
509 pid = fork();
510
511 if (pid < 0) {
512 perror("from fork()");
513 return 1;
514 } else if (pid == 0) {
515 int err;
516 int i;
517 const char **ppp_args;
518
519 // copy args
520 ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
521 ppp_args[0] = "pppd";
522 for (i = 2 ; i < argc ; i++) {
523 //argv[2] and beyond become ppp_args[1] and beyond
524 ppp_args[i - 1] = argv[i];
525 }
526 ppp_args[i-1] = NULL;
527
528 // child side
529
530 dup2(fd, STDIN_FILENO);
531 dup2(fd, STDOUT_FILENO);
532 adb_close(STDERR_FILENO);
533 adb_close(fd);
534
535 err = execvp("pppd", (char * const *)ppp_args);
536
537 if (err < 0) {
538 perror("execing pppd");
539 }
540 exit(-1);
541 } else {
542 // parent side
543
544 adb_close(fd);
545 return 0;
546 }
547 #endif /* !HAVE_WIN32_PROC */
548 }
549
550 static int send_shellcommand(transport_type transport, char* serial, char* buf)
551 {
552 int fd, ret;
553
554 for(;;) {
555 fd = adb_connect(buf);
556 if(fd >= 0)
557 break;
558 fprintf(stderr,"- waiting for device -\n");
559 adb_sleep_ms(1000);
560 do_cmd(transport, serial, "wait-for-device", 0);
561 }
562
563 read_and_dump(fd);
564 ret = adb_close(fd);
565 if (ret)
566 perror("close");
567
568 return ret;
569 }
570
571 static int logcat(transport_type transport, char* serial, int argc, char **argv)
572 {
573 char buf[4096];
574
575 char *log_tags;
576 char *quoted_log_tags;
577
578 log_tags = getenv("ANDROID_LOG_TAGS");
579 quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
580
581 snprintf(buf, sizeof(buf),
582 "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
583 quoted_log_tags);
584
585 free(quoted_log_tags);
586
587 argc -= 1;
588 argv += 1;
589 while(argc-- > 0) {
590 char *quoted;
591
592 quoted = dupAndQuote (*argv++);
593
594 strncat(buf, " ", sizeof(buf)-1);
595 strncat(buf, quoted, sizeof(buf)-1);
596 free(quoted);
597 }
598
599 send_shellcommand(transport, serial, buf);
600 return 0;
601 }
602
603 #define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
604 static int top_works(const char *top)
605 {
606 if (top != NULL && adb_is_absolute_host_path(top)) {
607 char path_buf[PATH_MAX];
608 snprintf(path_buf, sizeof(path_buf),
609 "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
610 return access(path_buf, F_OK) == 0;
611 }
612 return 0;
613 }
614
615 static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
616 {
617 strcpy(path_buf, indir);
618 while (1) {
619 if (top_works(path_buf)) {
620 return path_buf;
621 }
622 char *s = adb_dirstop(path_buf);
623 if (s != NULL) {
624 *s = '\0';
625 } else {
626 path_buf[0] = '\0';
627 return NULL;
628 }
629 }
630 }
631
632 static char *find_top(char path_buf[PATH_MAX])
633 {
634 char *top = getenv("ANDROID_BUILD_TOP");
635 if (top != NULL && top[0] != '\0') {
636 if (!top_works(top)) {
637 fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
638 return NULL;
639 }
640 } else {
641 top = getenv("TOP");
642 if (top != NULL && top[0] != '\0') {
643 if (!top_works(top)) {
644 fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
645 return NULL;
646 }
647 } else {
648 top = NULL;
649 }
650 }
651
652 if (top != NULL) {
653 /* The environment pointed to a top directory that works.
654 */
655 strcpy(path_buf, top);
656 return path_buf;
657 }
658
659 /* The environment didn't help. Walk up the tree from the CWD
660 * to see if we can find the top.
661 */
662 char dir[PATH_MAX];
663 top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
664 if (top == NULL) {
665 /* If the CWD isn't under a good-looking top, see if the
666 * executable is.
667 */
668 get_my_path(dir);
669 top = find_top_from(dir, path_buf);
670 }
671 return top;
672 }
673
674 /* <hint> may be:
675 * - A simple product name
676 * e.g., "sooner"
677 TODO: debug? sooner-debug, sooner:debug?
678 * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
679 * e.g., "out/target/product/sooner"
680 * - An absolute path to the PRODUCT_OUT dir
681 * e.g., "/src/device/out/target/product/sooner"
682 *
683 * Given <hint>, try to construct an absolute path to the
684 * ANDROID_PRODUCT_OUT dir.
685 */
686 static const char *find_product_out_path(const char *hint)
687 {
688 static char path_buf[PATH_MAX];
689
690 if (hint == NULL || hint[0] == '\0') {
691 return NULL;
692 }
693
694 /* If it's already absolute, don't bother doing any work.
695 */
696 if (adb_is_absolute_host_path(hint)) {
697 strcpy(path_buf, hint);
698 return path_buf;
699 }
700
701 /* If there are any slashes in it, assume it's a relative path;
702 * make it absolute.
703 */
704 if (adb_dirstart(hint) != NULL) {
705 if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
706 fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
707 return NULL;
708 }
709 if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
710 fprintf(stderr, "adb: Couldn't assemble path\n");
711 return NULL;
712 }
713 strcat(path_buf, OS_PATH_SEPARATOR_STR);
714 strcat(path_buf, hint);
715 return path_buf;
716 }
717
718 /* It's a string without any slashes. Try to do something with it.
719 *
720 * Try to find the root of the build tree, and build a PRODUCT_OUT
721 * path from there.
722 */
723 char top_buf[PATH_MAX];
724 const char *top = find_top(top_buf);
725 if (top == NULL) {
726 fprintf(stderr, "adb: Couldn't find top of build tree\n");
727 return NULL;
728 }
729 //TODO: if we have a way to indicate debug, look in out/debug/target/...
730 snprintf(path_buf, sizeof(path_buf),
731 "%s" OS_PATH_SEPARATOR_STR
732 "out" OS_PATH_SEPARATOR_STR
733 "target" OS_PATH_SEPARATOR_STR
734 "product" OS_PATH_SEPARATOR_STR
735 "%s", top_buf, hint);
736 if (access(path_buf, F_OK) < 0) {
737 fprintf(stderr, "adb: Couldn't find a product dir "
738 "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
739 return NULL;
740 }
741 return path_buf;
742 }
743
744 int adb_commandline(int argc, char **argv)
745 {
746 char buf[4096];
747 int no_daemon = 0;
748 int is_daemon = 0;
749 int persist = 0;
750 int r;
751 int quote;
752 transport_type ttype = kTransportAny;
753 char* serial = NULL;
754
755 /* If defined, this should be an absolute path to
756 * the directory containing all of the various system images
757 * for a particular product. If not defined, and the adb
758 * command requires this information, then the user must
759 * specify the path using "-p".
760 */
761 gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
762 if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
763 gProductOutPath = NULL;
764 }
765 // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
766
767 /* modifiers and flags */
768 while(argc > 0) {
769 if(!strcmp(argv[0],"nodaemon")) {
770 no_daemon = 1;
771 } else if (!strcmp(argv[0], "fork-server")) {
772 /* this is a special flag used only when the ADB client launches the ADB Server */
773 is_daemon = 1;
774 } else if(!strcmp(argv[0],"persist")) {
775 persist = 1;
776 } else if(!strncmp(argv[0], "-p", 2)) {
777 const char *product = NULL;
778 if (argv[0][2] == '\0') {
779 if (argc < 2) return usage();
780 product = argv[1];
781 argc--;
782 argv++;
783 } else {
784 product = argv[1] + 2;
785 }
786 gProductOutPath = find_product_out_path(product);
787 if (gProductOutPath == NULL) {
788 fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
789 product);
790 return usage();
791 }
792 } else if (argv[0][0]=='-' && argv[0][1]=='s') {
793 if (isdigit(argv[0][2])) {
794 serial = argv[0] + 2;
795 } else {
796 if(argc < 2) return usage();
797 serial = argv[1];
798 argc--;
799 argv++;
800 }
801 } else if (!strcmp(argv[0],"-d")) {
802 ttype = kTransportUsb;
803 } else if (!strcmp(argv[0],"-e")) {
804 ttype = kTransportLocal;
805 } else {
806 /* out of recognized modifiers and flags */
807 break;
808 }
809 argc--;
810 argv++;
811 }
812
813 adb_set_transport(ttype, serial);
814
815 if ((argc > 0) && (!strcmp(argv[0],"server"))) {
816 if (no_daemon || is_daemon) {
817 r = adb_main(is_daemon);
818 } else {
819 r = launch_server();
820 }
821 if(r) {
822 fprintf(stderr,"* could not start server *\n");
823 }
824 return r;
825 }
826
827 top:
828 if(argc == 0) {
829 return usage();
830 }
831
832 /* adb_connect() commands */
833
834 if(!strcmp(argv[0], "devices")) {
835 char *tmp;
836 snprintf(buf, sizeof buf, "host:%s", argv[0]);
837 tmp = adb_query(buf);
838 if(tmp) {
839 printf("List of devices attached \n");
840 printf("%s\n", tmp);
841 return 0;
842 } else {
843 return 1;
844 }
845 }
846
847 if (!strcmp(argv[0], "emu")) {
848 return adb_send_emulator_command(argc, argv);
849 }
850
851 if(!strcmp(argv[0], "shell")) {
852 int r;
853 int fd;
854
855 if(argc < 2) {
856 return interactive_shell();
857 }
858
859 snprintf(buf, sizeof buf, "shell:%s", argv[1]);
860 argc -= 2;
861 argv += 2;
862 while(argc-- > 0) {
863 strcat(buf, " ");
864
865 /* quote empty strings and strings with spaces */
866 quote = (**argv == 0 || strchr(*argv, ' '));
867 if (quote)
868 strcat(buf, "\"");
869 strcat(buf, *argv++);
870 if (quote)
871 strcat(buf, "\"");
872 }
873
874 for(;;) {
875 fd = adb_connect(buf);
876 if(fd >= 0) {
877 read_and_dump(fd);
878 adb_close(fd);
879 r = 0;
880 } else {
881 fprintf(stderr,"error: %s\n", adb_error());
882 r = -1;
883 }
884
885 if(persist) {
886 fprintf(stderr,"\n- waiting for device -\n");
887 adb_sleep_ms(1000);
888 do_cmd(ttype, serial, "wait-for-device", 0);
889 } else {
890 return r;
891 }
892 }
893 }
894
895 if(!strcmp(argv[0], "kill-server")) {
896 int fd;
897 fd = _adb_connect("host:kill");
898 if(fd == -1) {
899 fprintf(stderr,"* server not running *\n");
900 return 1;
901 }
902 return 0;
903 }
904
905 if(!strcmp(argv[0], "remount")) {
906 int fd = adb_connect("remount:");
907 if(fd >= 0) {
908 read_and_dump(fd);
909 adb_close(fd);
910 return 0;
911 }
912 fprintf(stderr,"error: %s\n", adb_error());
913 return 1;
914 }
915
916 if(!strcmp(argv[0], "bugreport")) {
917 if (argc != 1) {
918 return 1;
919 }
920 do_cmd(ttype, serial, "shell", "dumpstate", "-", 0);
921 return 0;
922 }
923
924 /* adb_command() wrapper commands */
925
926 if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
927 char* service = argv[0];
928 if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
929 if (ttype == kTransportUsb) {
930 service = "wait-for-usb";
931 } else if (ttype == kTransportLocal) {
932 service = "wait-for-local";
933 } else {
934 service = "wait-for-any";
935 }
936 }
937
938 format_host_command(buf, sizeof buf, service, ttype, serial);
939
940 if (adb_command(buf)) {
941 D("failure: %s *\n",adb_error());
942 fprintf(stderr,"error: %s\n", adb_error());
943 return 1;
944 }
945
946 /* Allow a command to be run after wait-for-device,
947 * e.g. 'adb wait-for-device shell'.
948 */
949 if(argc > 1) {
950 argc--;
951 argv++;
952 goto top;
953 }
954 return 0;
955 }
956
957 if(!strcmp(argv[0], "forward")) {
958 if(argc != 3) return usage();
959 if (serial) {
960 snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial,argv[1],argv[2]);
961 } else {
962 snprintf(buf, sizeof buf, "host:forward:%s;%s",argv[1],argv[2]);
963 }
964 if(adb_command(buf)) {
965 fprintf(stderr,"error: %s\n", adb_error());
966 return 1;
967 }
968 return 0;
969 }
970
971 /* do_sync_*() commands */
972
973 if(!strcmp(argv[0], "ls")) {
974 if(argc != 2) return usage();
975 return do_sync_ls(argv[1]);
976 }
977
978 if(!strcmp(argv[0], "push")) {
979 if(argc != 3) return usage();
980 return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
981 }
982
983 if(!strcmp(argv[0], "pull")) {
984 if(argc != 3) return usage();
985 return do_sync_pull(argv[1], argv[2]);
986 }
987
988 if(!strcmp(argv[0], "install")) {
989 if (argc < 2) return usage();
990 return install_app(ttype, serial, argc, argv);
991 }
992
993 if(!strcmp(argv[0], "uninstall")) {
994 if (argc < 2) return usage();
995 return uninstall_app(ttype, serial, argc, argv);
996 }
997
998 if(!strcmp(argv[0], "sync")) {
999 char *srcarg, *android_srcpath, *data_srcpath;
1000 int ret;
1001 if(argc < 2) {
1002 /* No local path was specified. */
1003 srcarg = NULL;
1004 } else if(argc == 2) {
1005 /* A local path or "android"/"data" arg was specified. */
1006 srcarg = argv[1];
1007 } else {
1008 return usage();
1009 }
1010 ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
1011 if(ret != 0) return usage();
1012
1013 if(android_srcpath != NULL)
1014 ret = do_sync_sync(android_srcpath, "/system");
1015 if(ret == 0 && data_srcpath != NULL)
1016 ret = do_sync_sync(data_srcpath, "/data");
1017
1018 free(android_srcpath);
1019 free(data_srcpath);
1020 return ret;
1021 }
1022
1023 /* passthrough commands */
1024
1025 if(!strcmp(argv[0],"get-state") ||
1026 !strcmp(argv[0],"get-serialno"))
1027 {
1028 char *tmp;
1029
1030 format_host_command(buf, sizeof buf, argv[0], ttype, serial);
1031 tmp = adb_query(buf);
1032 if(tmp) {
1033 printf("%s\n", tmp);
1034 return 0;
1035 } else {
1036 return 1;
1037 }
1038 }
1039
1040 /* other commands */
1041
1042 if(!strcmp(argv[0],"status-window")) {
1043 status_window(ttype, serial);
1044 return 0;
1045 }
1046
1047 if(!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat")) {
1048 return logcat(ttype, serial, argc, argv);
1049 }
1050
1051 if(!strcmp(argv[0],"ppp")) {
1052 return ppp(argc, argv);
1053 }
1054
1055 if (!strcmp(argv[0], "start-server")) {
1056 return adb_connect("host:start-server");
1057 }
1058
1059 if (!strcmp(argv[0], "jdwp")) {
1060 int fd = adb_connect("jdwp");
1061 if (fd >= 0) {
1062 read_and_dump(fd);
1063 adb_close(fd);
1064 return 0;
1065 } else {
1066 fprintf(stderr, "error: %s\n", adb_error());
1067 return -1;
1068 }
1069 }
1070
1071 /* "adb /?" is a common idiom under Windows */
1072 if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
1073 help();
1074 return 0;
1075 }
1076
1077 if(!strcmp(argv[0], "version")) {
1078 version(stdout);
1079 return 0;
1080 }
1081
1082 usage();
1083 return 1;
1084 }
1085
1086 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
1087 {
1088 char *argv[16];
1089 int argc;
1090 va_list ap;
1091
1092 va_start(ap, cmd);
1093 argc = 0;
1094
1095 if (serial) {
1096 argv[argc++] = "-s";
1097 argv[argc++] = serial;
1098 } else if (ttype == kTransportUsb) {
1099 argv[argc++] = "-d";
1100 } else if (ttype == kTransportLocal) {
1101 argv[argc++] = "-e";
1102 }
1103
1104 argv[argc++] = cmd;
1105 while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
1106 va_end(ap);
1107
1108 #if 0
1109 int n;
1110 fprintf(stderr,"argc = %d\n",argc);
1111 for(n = 0; n < argc; n++) {
1112 fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
1113 }
1114 #endif
1115
1116 return adb_commandline(argc, argv);
1117 }
1118
1119 int find_sync_dirs(const char *srcarg,
1120 char **android_srcdir_out, char **data_srcdir_out)
1121 {
1122 char *android_srcdir, *data_srcdir;
1123
1124 if(srcarg == NULL) {
1125 android_srcdir = product_file("system");
1126 data_srcdir = product_file("data");
1127 } else {
1128 /* srcarg may be "data", "system" or NULL.
1129 * if srcarg is NULL, then both data and system are synced
1130 */
1131 if(strcmp(srcarg, "system") == 0) {
1132 android_srcdir = product_file("system");
1133 data_srcdir = NULL;
1134 } else if(strcmp(srcarg, "data") == 0) {
1135 android_srcdir = NULL;
1136 data_srcdir = product_file("data");
1137 } else {
1138 /* It's not "system" or "data".
1139 */
1140 return 1;
1141 }
1142 }
1143
1144 if(android_srcdir_out != NULL)
1145 *android_srcdir_out = android_srcdir;
1146 else
1147 free(android_srcdir);
1148
1149 if(data_srcdir_out != NULL)
1150 *data_srcdir_out = data_srcdir;
1151 else
1152 free(data_srcdir);
1153
1154 return 0;
1155 }
1156
1157 static int pm_command(transport_type transport, char* serial,
1158 int argc, char** argv)
1159 {
1160 char buf[4096];
1161
1162 snprintf(buf, sizeof(buf), "shell:pm");
1163
1164 while(argc-- > 0) {
1165 char *quoted;
1166
1167 quoted = dupAndQuote(*argv++);
1168
1169 strncat(buf, " ", sizeof(buf)-1);
1170 strncat(buf, quoted, sizeof(buf)-1);
1171 free(quoted);
1172 }
1173
1174 send_shellcommand(transport, serial, buf);
1175 return 0;
1176 }
1177
1178 int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
1179 {
1180 /* if the user choose the -k option, we refuse to do it until devices are
1181 out with the option to uninstall the remaining data somehow (adb/ui) */
1182 if (argc == 3 && strcmp(argv[1], "-k") == 0)
1183 {
1184 printf(
1185 "The -k option uninstalls the application while retaining the data/cache.\n"
1186 "At the moment, there is no way to remove the remaining data.\n"
1187 "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
1188 "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
1189 return -1;
1190 }
1191
1192 /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
1193 return pm_command(transport, serial, argc, argv);
1194 }
1195
1196 static int delete_file(transport_type transport, char* serial, char* filename)
1197 {
1198 char buf[4096];
1199 char* quoted;
1200
1201 snprintf(buf, sizeof(buf), "shell:rm ");
1202 quoted = dupAndQuote(filename);
1203 strncat(buf, quoted, sizeof(buf)-1);
1204 free(quoted);
1205
1206 send_shellcommand(transport, serial, buf);
1207 return 0;
1208 }
1209
1210 int install_app(transport_type transport, char* serial, int argc, char** argv)
1211 {
1212 struct stat st;
1213 int err;
1214 const char *const WHERE = "/data/local/tmp/%s";
1215 char to[PATH_MAX];
1216 char* filename = argv[argc - 1];
1217 const char* p;
1218
1219 p = adb_dirstop(filename);
1220 if (p) {
1221 p++;
1222 snprintf(to, sizeof to, WHERE, p);
1223 } else {
1224 snprintf(to, sizeof to, WHERE, filename);
1225 }
1226 if (p[0] == '\0') {
1227 }
1228
1229 err = stat(filename, &st);
1230 if (err != 0) {
1231 fprintf(stderr, "can't find '%s' to install\n", filename);
1232 return 1;
1233 }
1234 if (!S_ISREG(st.st_mode)) {
1235 fprintf(stderr, "can't install '%s' because it's not a file\n",
1236 filename);
1237 return 1;
1238 }
1239
1240 if (!(err = do_sync_push(filename, to, 1 /* verify APK */))) {
1241 /* file in place; tell the Package Manager to install it */
1242 argv[argc - 1] = to; /* destination name, not source location */
1243 pm_command(transport, serial, argc, argv);
1244 delete_file(transport, serial, to);
1245 }
1246
1247 return err;
1248 }
+0
-45
adb/console.c less more
0 #include "sysdeps.h"
1 #include "adb.h"
2 #include "adb_client.h"
3 #include <stdio.h>
4
5 static int connect_to_console(void)
6 {
7 int fd, port;
8
9 port = adb_get_emulator_console_port();
10 if (port < 0) {
11 if (port == -2)
12 fprintf(stderr, "error: more than one emulator detected. use -s option\n");
13 else
14 fprintf(stderr, "error: no emulator detected\n");
15 return -1;
16 }
17 fd = socket_loopback_client( port, SOCK_STREAM );
18 if (fd < 0) {
19 fprintf(stderr, "error: could not connect to TCP port %d\n", port);
20 return -1;
21 }
22 return fd;
23 }
24
25
26 int adb_send_emulator_command(int argc, char** argv)
27 {
28 int fd, nn;
29
30 fd = connect_to_console();
31 if (fd < 0)
32 return 1;
33
34 #define QUIT "quit\n"
35
36 for (nn = 1; nn < argc; nn++) {
37 adb_write( fd, argv[nn], strlen(argv[nn]) );
38 adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
39 }
40 adb_write( fd, QUIT, sizeof(QUIT)-1 );
41 adb_close(fd);
42
43 return 0;
44 }
+0
-1022
adb/file_sync_client.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <time.h>
23 #include <dirent.h>
24 #include <limits.h>
25 #include <sys/types.h>
26 #include <zipfile/zipfile.h>
27
28 #include "sysdeps.h"
29 #include "adb.h"
30 #include "adb_client.h"
31 #include "file_sync_service.h"
32
33
34 static unsigned total_bytes;
35 static long long start_time;
36
37 static long long NOW()
38 {
39 struct timeval tv;
40 gettimeofday(&tv, 0);
41 return ((long long) tv.tv_usec) +
42 1000000LL * ((long long) tv.tv_sec);
43 }
44
45 static void BEGIN()
46 {
47 total_bytes = 0;
48 start_time = NOW();
49 }
50
51 static void END()
52 {
53 long long t = NOW() - start_time;
54 if(total_bytes == 0) return;
55
56 if (t == 0) /* prevent division by 0 :-) */
57 t = 1000000;
58
59 fprintf(stderr,"%lld KB/s (%d bytes in %lld.%03llds)\n",
60 ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
61 total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
62 }
63
64 void sync_quit(int fd)
65 {
66 syncmsg msg;
67
68 msg.req.id = ID_QUIT;
69 msg.req.namelen = 0;
70
71 writex(fd, &msg.req, sizeof(msg.req));
72 }
73
74 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
75
76 int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
77 {
78 syncmsg msg;
79 char buf[257];
80 int len;
81
82 len = strlen(path);
83 if(len > 1024) goto fail;
84
85 msg.req.id = ID_LIST;
86 msg.req.namelen = htoll(len);
87
88 if(writex(fd, &msg.req, sizeof(msg.req)) ||
89 writex(fd, path, len)) {
90 goto fail;
91 }
92
93 for(;;) {
94 if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
95 if(msg.dent.id == ID_DONE) return 0;
96 if(msg.dent.id != ID_DENT) break;
97
98 len = ltohl(msg.dent.namelen);
99 if(len > 256) break;
100
101 if(readx(fd, buf, len)) break;
102 buf[len] = 0;
103
104 func(ltohl(msg.dent.mode),
105 ltohl(msg.dent.size),
106 ltohl(msg.dent.time),
107 buf, cookie);
108 }
109
110 fail:
111 adb_close(fd);
112 return -1;
113 }
114
115 typedef struct syncsendbuf syncsendbuf;
116
117 struct syncsendbuf {
118 unsigned id;
119 unsigned size;
120 char data[SYNC_DATA_MAX];
121 };
122
123 static syncsendbuf send_buffer;
124
125 int sync_readtime(int fd, const char *path, unsigned *timestamp)
126 {
127 syncmsg msg;
128 int len = strlen(path);
129
130 msg.req.id = ID_STAT;
131 msg.req.namelen = htoll(len);
132
133 if(writex(fd, &msg.req, sizeof(msg.req)) ||
134 writex(fd, path, len)) {
135 return -1;
136 }
137
138 if(readx(fd, &msg.stat, sizeof(msg.stat))) {
139 return -1;
140 }
141
142 if(msg.stat.id != ID_STAT) {
143 return -1;
144 }
145
146 *timestamp = ltohl(msg.stat.time);
147 return 0;
148 }
149
150 static int sync_start_readtime(int fd, const char *path)
151 {
152 syncmsg msg;
153 int len = strlen(path);
154
155 msg.req.id = ID_STAT;
156 msg.req.namelen = htoll(len);
157
158 if(writex(fd, &msg.req, sizeof(msg.req)) ||
159 writex(fd, path, len)) {
160 return -1;
161 }
162
163 return 0;
164 }
165
166 static int sync_finish_readtime(int fd, unsigned int *timestamp,
167 unsigned int *mode, unsigned int *size)
168 {
169 syncmsg msg;
170
171 if(readx(fd, &msg.stat, sizeof(msg.stat)))
172 return -1;
173
174 if(msg.stat.id != ID_STAT)
175 return -1;
176
177 *timestamp = ltohl(msg.stat.time);
178 *mode = ltohl(msg.stat.mode);
179 *size = ltohl(msg.stat.size);
180
181 return 0;
182 }
183
184 int sync_readmode(int fd, const char *path, unsigned *mode)
185 {
186 syncmsg msg;
187 int len = strlen(path);
188
189 msg.req.id = ID_STAT;
190 msg.req.namelen = htoll(len);
191
192 if(writex(fd, &msg.req, sizeof(msg.req)) ||
193 writex(fd, path, len)) {
194 return -1;
195 }
196
197 if(readx(fd, &msg.stat, sizeof(msg.stat))) {
198 return -1;
199 }
200
201 if(msg.stat.id != ID_STAT) {
202 return -1;
203 }
204
205 *mode = ltohl(msg.stat.mode);
206 return 0;
207 }
208
209 static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
210 {
211 int lfd, err = 0;
212
213 lfd = adb_open(path, O_RDONLY);
214 if(lfd < 0) {
215 fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
216 return -1;
217 }
218
219 sbuf->id = ID_DATA;
220 for(;;) {
221 int ret;
222
223 ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
224 if(!ret)
225 break;
226
227 if(ret < 0) {
228 if(errno == EINTR)
229 continue;
230 fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
231 break;
232 }
233
234 sbuf->size = htoll(ret);
235 if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
236 err = -1;
237 break;
238 }
239 total_bytes += ret;
240 }
241
242 adb_close(lfd);
243 return err;
244 }
245
246 static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
247 {
248 int err = 0;
249 int total = 0;
250
251 sbuf->id = ID_DATA;
252 while (total < size) {
253 int count = size - total;
254 if (count > SYNC_DATA_MAX) {
255 count = SYNC_DATA_MAX;
256 }
257
258 memcpy(sbuf->data, &file_buffer[total], count);
259 sbuf->size = htoll(count);
260 if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
261 err = -1;
262 break;
263 }
264 total += count;
265 total_bytes += count;
266 }
267
268 return err;
269 }
270
271 #ifdef HAVE_SYMLINKS
272 static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
273 {
274 int len, ret;
275
276 len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
277 if(len < 0) {
278 fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
279 return -1;
280 }
281 sbuf->data[len] = '\0';
282
283 sbuf->size = htoll(len + 1);
284 sbuf->id = ID_DATA;
285
286 ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
287 if(ret)
288 return -1;
289
290 total_bytes += len + 1;
291
292 return 0;
293 }
294 #endif
295
296 static int sync_send(int fd, const char *lpath, const char *rpath,
297 unsigned mtime, mode_t mode, int verifyApk)
298 {
299 syncmsg msg;
300 int len, r;
301 syncsendbuf *sbuf = &send_buffer;
302 char* file_buffer = NULL;
303 int size = 0;
304 char tmp[64];
305
306 len = strlen(rpath);
307 if(len > 1024) goto fail;
308
309 snprintf(tmp, sizeof(tmp), ",%d", mode);
310 r = strlen(tmp);
311
312 if (verifyApk) {
313 int lfd;
314 zipfile_t zip;
315 zipentry_t entry;
316 int amt;
317
318 // if we are transferring an APK file, then sanity check to make sure
319 // we have a real zip file that contains an AndroidManifest.xml
320 // this requires that we read the entire file into memory.
321 lfd = adb_open(lpath, O_RDONLY);
322 if(lfd < 0) {
323 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
324 return -1;
325 }
326
327 size = adb_lseek(lfd, 0, SEEK_END);
328 if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
329 fprintf(stderr, "error seeking in file '%s'\n", lpath);
330 adb_close(lfd);
331 return 1;
332 }
333
334 file_buffer = (char *)malloc(size);
335 if (file_buffer == NULL) {
336 fprintf(stderr, "could not allocate buffer for '%s'\n",
337 lpath);
338 adb_close(lfd);
339 return 1;
340 }
341 amt = adb_read(lfd, file_buffer, size);
342 if (amt != size) {
343 fprintf(stderr, "error reading from file: '%s'\n", lpath);
344 adb_close(lfd);
345 free(file_buffer);
346 return 1;
347 }
348
349 adb_close(lfd);
350
351 zip = init_zipfile(file_buffer, size);
352 if (zip == NULL) {
353 fprintf(stderr, "file '%s' is not a valid zip file\n",
354 lpath);
355 free(file_buffer);
356 return 1;
357 }
358
359 entry = lookup_zipentry(zip, "AndroidManifest.xml");
360 release_zipfile(zip);
361 if (entry == NULL) {
362 fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
363 lpath);
364 free(file_buffer);
365 return 1;
366 }
367 }
368
369 msg.req.id = ID_SEND;
370 msg.req.namelen = htoll(len + r);
371
372 if(writex(fd, &msg.req, sizeof(msg.req)) ||
373 writex(fd, rpath, len) || writex(fd, tmp, r)) {
374 free(file_buffer);
375 goto fail;
376 }
377
378 if (file_buffer) {
379 write_data_buffer(fd, file_buffer, size, sbuf);
380 free(file_buffer);
381 } else if (S_ISREG(mode))
382 write_data_file(fd, lpath, sbuf);
383 #ifdef HAVE_SYMLINKS
384 else if (S_ISLNK(mode))
385 write_data_link(fd, lpath, sbuf);
386 #endif
387 else
388 goto fail;
389
390 msg.data.id = ID_DONE;
391 msg.data.size = htoll(mtime);
392 if(writex(fd, &msg.data, sizeof(msg.data)))
393 goto fail;
394
395 if(readx(fd, &msg.status, sizeof(msg.status)))
396 return -1;
397
398 if(msg.status.id != ID_OKAY) {
399 if(msg.status.id == ID_FAIL) {
400 len = ltohl(msg.status.msglen);
401 if(len > 256) len = 256;
402 if(readx(fd, sbuf->data, len)) {
403 return -1;
404 }
405 sbuf->data[len] = 0;
406 } else
407 strcpy(sbuf->data, "unknown reason");
408
409 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
410 return -1;
411 }
412
413 return 0;
414
415 fail:
416 fprintf(stderr,"protocol failure\n");
417 adb_close(fd);
418 return -1;
419 }
420
421 static int mkdirs(char *name)
422 {
423 int ret;
424 char *x = name + 1;
425
426 for(;;) {
427 x = adb_dirstart(x);
428 if(x == 0) return 0;
429 *x = 0;
430 ret = adb_mkdir(name, 0775);
431 *x = OS_PATH_SEPARATOR;
432 if((ret < 0) && (errno != EEXIST)) {
433 return ret;
434 }
435 x++;
436 }
437 return 0;
438 }
439
440 int sync_recv(int fd, const char *rpath, const char *lpath)
441 {
442 syncmsg msg;
443 int len;
444 int lfd = -1;
445 char *buffer = send_buffer.data;
446 unsigned id;
447
448 len = strlen(rpath);
449 if(len > 1024) return -1;
450
451 msg.req.id = ID_RECV;
452 msg.req.namelen = htoll(len);
453 if(writex(fd, &msg.req, sizeof(msg.req)) ||
454 writex(fd, rpath, len)) {
455 return -1;
456 }
457
458 if(readx(fd, &msg.data, sizeof(msg.data))) {
459 return -1;
460 }
461 id = msg.data.id;
462
463 if((id == ID_DATA) || (id == ID_DONE)) {
464 adb_unlink(lpath);
465 mkdirs((char *)lpath);
466 lfd = adb_creat(lpath, 0644);
467 if(lfd < 0) {
468 fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
469 return -1;
470 }
471 goto handle_data;
472 } else {
473 goto remote_error;
474 }
475
476 for(;;) {
477 if(readx(fd, &msg.data, sizeof(msg.data))) {
478 return -1;
479 }
480 id = msg.data.id;
481
482 handle_data:
483 len = ltohl(msg.data.size);
484 if(id == ID_DONE) break;
485 if(id != ID_DATA) goto remote_error;
486 if(len > SYNC_DATA_MAX) {
487 fprintf(stderr,"data overrun\n");
488 adb_close(lfd);
489 return -1;
490 }
491
492 if(readx(fd, buffer, len)) {
493 adb_close(lfd);
494 return -1;
495 }
496
497 if(writex(lfd, buffer, len)) {
498 fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
499 adb_close(lfd);
500 return -1;
501 }
502
503 total_bytes += len;
504 }
505
506 adb_close(lfd);
507 return 0;
508
509 remote_error:
510 adb_close(lfd);
511 adb_unlink(lpath);
512
513 if(id == ID_FAIL) {
514 len = ltohl(msg.data.size);
515 if(len > 256) len = 256;
516 if(readx(fd, buffer, len)) {
517 return -1;
518 }
519 buffer[len] = 0;
520 } else {
521 memcpy(buffer, &id, 4);
522 buffer[4] = 0;
523 // strcpy(buffer,"unknown reason");
524 }
525 fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
526 return 0;
527 }
528
529
530
531 /* --- */
532
533
534 static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
535 const char *name, void *cookie)
536 {
537 printf("%08x %08x %08x %s\n", mode, size, time, name);
538 }
539
540 int do_sync_ls(const char *path)
541 {
542 int fd = adb_connect("sync:");
543 if(fd < 0) {
544 fprintf(stderr,"error: %s\n", adb_error());
545 return 1;
546 }
547
548 if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
549 return 1;
550 } else {
551 sync_quit(fd);
552 return 0;
553 }
554 }
555
556 typedef struct copyinfo copyinfo;
557
558 struct copyinfo
559 {
560 copyinfo *next;
561 const char *src;
562 const char *dst;
563 unsigned int time;
564 unsigned int mode;
565 unsigned int size;
566 int flag;
567 //char data[0];
568 };
569
570 copyinfo *mkcopyinfo(const char *spath, const char *dpath,
571 const char *name, int isdir)
572 {
573 int slen = strlen(spath);
574 int dlen = strlen(dpath);
575 int nlen = strlen(name);
576 int ssize = slen + nlen + 2;
577 int dsize = dlen + nlen + 2;
578
579 copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
580 if(ci == 0) {
581 fprintf(stderr,"out of memory\n");
582 abort();
583 }
584
585 ci->next = 0;
586 ci->time = 0;
587 ci->mode = 0;
588 ci->size = 0;
589 ci->flag = 0;
590 ci->src = (const char*)(ci + 1);
591 ci->dst = ci->src + ssize;
592 snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
593 snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
594
595 // fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
596 return ci;
597 }
598
599
600 static int local_build_list(copyinfo **filelist,
601 const char *lpath, const char *rpath)
602 {
603 DIR *d;
604 struct dirent *de;
605 struct stat st;
606 copyinfo *dirlist = 0;
607 copyinfo *ci, *next;
608
609 // fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
610
611 d = opendir(lpath);
612 if(d == 0) {
613 fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
614 return -1;
615 }
616
617 while((de = readdir(d))) {
618 char stat_path[PATH_MAX];
619 char *name = de->d_name;
620
621 if(name[0] == '.') {
622 if(name[1] == 0) continue;
623 if((name[1] == '.') && (name[2] == 0)) continue;
624 }
625
626 /*
627 * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
628 * always returns DT_UNKNOWN, so we just use stat() for all cases.
629 */
630 if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
631 continue;
632 strcpy(stat_path, lpath);
633 strcat(stat_path, de->d_name);
634 stat(stat_path, &st);
635
636 if (S_ISDIR(st.st_mode)) {
637 ci = mkcopyinfo(lpath, rpath, name, 1);
638 ci->next = dirlist;
639 dirlist = ci;
640 } else {
641 ci = mkcopyinfo(lpath, rpath, name, 0);
642 if(lstat(ci->src, &st)) {
643 closedir(d);
644 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
645 return -1;
646 }
647 if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
648 fprintf(stderr, "skipping special file '%s'\n", ci->src);
649 free(ci);
650 } else {
651 ci->time = st.st_mtime;
652 ci->mode = st.st_mode;
653 ci->size = st.st_size;
654 ci->next = *filelist;
655 *filelist = ci;
656 }
657 }
658 }
659
660 closedir(d);
661
662 for(ci = dirlist; ci != 0; ci = next) {
663 next = ci->next;
664 local_build_list(filelist, ci->src, ci->dst);
665 free(ci);
666 }
667
668 return 0;
669 }
670
671
672 static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps)
673 {
674 copyinfo *filelist = 0;
675 copyinfo *ci, *next;
676 int pushed = 0;
677 int skipped = 0;
678
679 if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
680 if(lpath[strlen(lpath) - 1] != '/') {
681 int tmplen = strlen(lpath)+2;
682 char *tmp = malloc(tmplen);
683 if(tmp == 0) return -1;
684 snprintf(tmp, tmplen, "%s/",lpath);
685 lpath = tmp;
686 }
687 if(rpath[strlen(rpath) - 1] != '/') {
688 int tmplen = strlen(rpath)+2;
689 char *tmp = malloc(tmplen);
690 if(tmp == 0) return -1;
691 snprintf(tmp, tmplen, "%s/",rpath);
692 rpath = tmp;
693 }
694
695 if(local_build_list(&filelist, lpath, rpath)) {
696 return -1;
697 }
698
699 if(checktimestamps){
700 for(ci = filelist; ci != 0; ci = ci->next) {
701 if(sync_start_readtime(fd, ci->dst)) {
702 return 1;
703 }
704 }
705 for(ci = filelist; ci != 0; ci = ci->next) {
706 unsigned int timestamp, mode, size;
707 if(sync_finish_readtime(fd, &timestamp, &mode, &size))
708 return 1;
709 if(size == ci->size) {
710 /* for links, we cannot update the atime/mtime */
711 if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
712 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
713 ci->flag = 1;
714 }
715 }
716 }
717 for(ci = filelist; ci != 0; ci = next) {
718 next = ci->next;
719 if(ci->flag == 0) {
720 fprintf(stderr,"push: %s -> %s\n", ci->src, ci->dst);
721 if(sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
722 return 1;
723 }
724 pushed++;
725 } else {
726 skipped++;
727 }
728 free(ci);
729 }
730
731 fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
732 pushed, (pushed == 1) ? "" : "s",
733 skipped, (skipped == 1) ? "" : "s");
734
735 return 0;
736 }
737
738
739 int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
740 {
741 struct stat st;
742 unsigned mode;
743 int fd;
744
745 fd = adb_connect("sync:");
746 if(fd < 0) {
747 fprintf(stderr,"error: %s\n", adb_error());
748 return 1;
749 }
750
751 if(stat(lpath, &st)) {
752 fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
753 sync_quit(fd);
754 return 1;
755 }
756
757 if(S_ISDIR(st.st_mode)) {
758 BEGIN();
759 if(copy_local_dir_remote(fd, lpath, rpath, 0)) {
760 return 1;
761 } else {
762 END();
763 sync_quit(fd);
764 }
765 } else {
766 if(sync_readmode(fd, rpath, &mode)) {
767 return 1;
768 }
769 if((mode != 0) && S_ISDIR(mode)) {
770 /* if we're copying a local file to a remote directory,
771 ** we *really* want to copy to remotedir + "/" + localfilename
772 */
773 const char *name = adb_dirstop(lpath);
774 if(name == 0) {
775 name = lpath;
776 } else {
777 name++;
778 }
779 int tmplen = strlen(name) + strlen(rpath) + 2;
780 char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
781 if(tmp == 0) return 1;
782 snprintf(tmp, tmplen, "%s/%s", rpath, name);
783 rpath = tmp;
784 }
785 BEGIN();
786 if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
787 return 1;
788 } else {
789 END();
790 sync_quit(fd);
791 return 0;
792 }
793 }
794
795 return 0;
796 }
797
798
799 typedef struct {
800 copyinfo **filelist;
801 copyinfo **dirlist;
802 const char *rpath;
803 const char *lpath;
804 } sync_ls_build_list_cb_args;
805
806 void
807 sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
808 const char *name, void *cookie)
809 {
810 sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
811 copyinfo *ci;
812
813 if (S_ISDIR(mode)) {
814 copyinfo **dirlist = args->dirlist;
815
816 /* Don't try recursing down "." or ".." */
817 if (name[0] == '.') {
818 if (name[1] == '\0') return;
819 if ((name[1] == '.') && (name[2] == '\0')) return;
820 }
821
822 ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
823 ci->next = *dirlist;
824 *dirlist = ci;
825 } else if (S_ISREG(mode) || S_ISLNK(mode)) {
826 copyinfo **filelist = args->filelist;
827
828 ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
829 ci->time = time;
830 ci->mode = mode;
831 ci->size = size;
832 ci->next = *filelist;
833 *filelist = ci;
834 } else {
835 fprintf(stderr, "skipping special file '%s'\n", name);
836 }
837 }
838
839 static int remote_build_list(int syncfd, copyinfo **filelist,
840 const char *rpath, const char *lpath)
841 {
842 copyinfo *dirlist = NULL;
843 sync_ls_build_list_cb_args args;
844
845 args.filelist = filelist;
846 args.dirlist = &dirlist;
847 args.rpath = rpath;
848 args.lpath = lpath;
849
850 /* Put the files/dirs in rpath on the lists. */
851 if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
852 return 1;
853 }
854
855 /* Recurse into each directory we found. */
856 while (dirlist != NULL) {
857 copyinfo *next = dirlist->next;
858 if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
859 return 1;
860 }
861 free(dirlist);
862 dirlist = next;
863 }
864
865 return 0;
866 }
867
868 static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
869 int checktimestamps)
870 {
871 copyinfo *filelist = 0;
872 copyinfo *ci, *next;
873 int pulled = 0;
874 int skipped = 0;
875
876 /* Make sure that both directory paths end in a slash. */
877 if (rpath[0] == 0 || lpath[0] == 0) return -1;
878 if (rpath[strlen(rpath) - 1] != '/') {
879 int tmplen = strlen(rpath) + 2;
880 char *tmp = malloc(tmplen);
881 if (tmp == 0) return -1;
882 snprintf(tmp, tmplen, "%s/", rpath);
883 rpath = tmp;
884 }
885 if (lpath[strlen(lpath) - 1] != '/') {
886 int tmplen = strlen(lpath) + 2;
887 char *tmp = malloc(tmplen);
888 if (tmp == 0) return -1;
889 snprintf(tmp, tmplen, "%s/", lpath);
890 lpath = tmp;
891 }
892
893 fprintf(stderr, "pull: building file list...\n");
894 /* Recursively build the list of files to copy. */
895 if (remote_build_list(fd, &filelist, rpath, lpath)) {
896 return -1;
897 }
898
899 #if 0
900 if (checktimestamps) {
901 for (ci = filelist; ci != 0; ci = ci->next) {
902 if (sync_start_readtime(fd, ci->dst)) {
903 return 1;
904 }
905 }
906 for (ci = filelist; ci != 0; ci = ci->next) {
907 unsigned int timestamp, mode, size;
908 if (sync_finish_readtime(fd, &timestamp, &mode, &size))
909 return 1;
910 if (size == ci->size) {
911 /* for links, we cannot update the atime/mtime */
912 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
913 (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
914 ci->flag = 1;
915 }
916 }
917 }
918 #endif
919 for (ci = filelist; ci != 0; ci = next) {
920 next = ci->next;
921 if (ci->flag == 0) {
922 fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
923 if (sync_recv(fd, ci->src, ci->dst)) {
924 return 1;
925 }
926 pulled++;
927 } else {
928 skipped++;
929 }
930 free(ci);
931 }
932
933 fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
934 pulled, (pulled == 1) ? "" : "s",
935 skipped, (skipped == 1) ? "" : "s");
936
937 return 0;
938 }
939
940 int do_sync_pull(const char *rpath, const char *lpath)
941 {
942 unsigned mode;
943 struct stat st;
944
945 int fd;
946
947 fd = adb_connect("sync:");
948 if(fd < 0) {
949 fprintf(stderr,"error: %s\n", adb_error());
950 return 1;
951 }
952
953 if(sync_readmode(fd, rpath, &mode)) {
954 return 1;
955 }
956 if(mode == 0) {
957 fprintf(stderr,"remote object '%s' does not exist\n", rpath);
958 return 1;
959 }
960
961 if(S_ISREG(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
962 if(stat(lpath, &st) == 0) {
963 if(S_ISDIR(st.st_mode)) {
964 /* if we're copying a remote file to a local directory,
965 ** we *really* want to copy to localdir + "/" + remotefilename
966 */
967 const char *name = adb_dirstop(rpath);
968 if(name == 0) {
969 name = rpath;
970 } else {
971 name++;
972 }
973 int tmplen = strlen(name) + strlen(lpath) + 2;
974 char *tmp = malloc(tmplen);
975 if(tmp == 0) return 1;
976 snprintf(tmp, tmplen, "%s/%s", lpath, name);
977 lpath = tmp;
978 }
979 }
980 BEGIN();
981 if(sync_recv(fd, rpath, lpath)) {
982 return 1;
983 } else {
984 END();
985 sync_quit(fd);
986 return 0;
987 }
988 } else if(S_ISDIR(mode)) {
989 BEGIN();
990 if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
991 return 1;
992 } else {
993 END();
994 sync_quit(fd);
995 return 0;
996 }
997 } else {
998 fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
999 return 1;
1000 }
1001 }
1002
1003 int do_sync_sync(const char *lpath, const char *rpath)
1004 {
1005 fprintf(stderr,"syncing %s...\n",rpath);
1006
1007 int fd = adb_connect("sync:");
1008 if(fd < 0) {
1009 fprintf(stderr,"error: %s\n", adb_error());
1010 return 1;
1011 }
1012
1013 BEGIN();
1014 if(copy_local_dir_remote(fd, lpath, rpath, 1)){
1015 return 1;
1016 } else {
1017 END();
1018 sync_quit(fd);
1019 return 0;
1020 }
1021 }
+0
-412
adb/file_sync_service.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <dirent.h>
23 #include <utime.h>
24
25 #include <errno.h>
26
27 #include "sysdeps.h"
28
29 #define TRACE_TAG TRACE_SYNC
30 #include "adb.h"
31 #include "file_sync_service.h"
32
33 static int mkdirs(char *name)
34 {
35 int ret;
36 char *x = name + 1;
37
38 if(name[0] != '/') return -1;
39
40 for(;;) {
41 x = adb_dirstart(x);
42 if(x == 0) return 0;
43 *x = 0;
44 ret = adb_mkdir(name, 0775);
45 if((ret < 0) && (errno != EEXIST)) {
46 D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
47 *x = '/';
48 return ret;
49 }
50 *x++ = '/';
51 }
52 return 0;
53 }
54
55 static int do_stat(int s, const char *path)
56 {
57 syncmsg msg;
58 struct stat st;
59
60 msg.stat.id = ID_STAT;
61
62 if(lstat(path, &st)) {
63 msg.stat.mode = 0;
64 msg.stat.size = 0;
65 msg.stat.time = 0;
66 } else {
67 msg.stat.mode = htoll(st.st_mode);
68 msg.stat.size = htoll(st.st_size);
69 msg.stat.time = htoll(st.st_mtime);
70 }
71
72 return writex(s, &msg.stat, sizeof(msg.stat));
73 }
74
75 static int do_list(int s, const char *path)
76 {
77 DIR *d;
78 struct dirent *de;
79 struct stat st;
80 syncmsg msg;
81 int len;
82
83 char tmp[1024 + 256 + 1];
84 char *fname;
85
86 len = strlen(path);
87 memcpy(tmp, path, len);
88 tmp[len] = '/';
89 fname = tmp + len + 1;
90
91 msg.dent.id = ID_DENT;
92
93 d = opendir(path);
94 if(d == 0) goto done;
95
96 while((de = readdir(d))) {
97 int len = strlen(de->d_name);
98
99 /* not supposed to be possible, but
100 if it does happen, let's not buffer overrun */
101 if(len > 256) continue;
102
103 strcpy(fname, de->d_name);
104 if(lstat(tmp, &st) == 0) {
105 msg.dent.mode = htoll(st.st_mode);
106 msg.dent.size = htoll(st.st_size);
107 msg.dent.time = htoll(st.st_mtime);
108 msg.dent.namelen = htoll(len);
109
110 if(writex(s, &msg.dent, sizeof(msg.dent)) ||
111 writex(s, de->d_name, len)) {
112 return -1;
113 }
114 }
115 }
116
117 closedir(d);
118
119 done:
120 msg.dent.id = ID_DONE;
121 msg.dent.mode = 0;
122 msg.dent.size = 0;
123 msg.dent.time = 0;
124 msg.dent.namelen = 0;
125 return writex(s, &msg.dent, sizeof(msg.dent));
126 }
127
128 static int fail_message(int s, const char *reason)
129 {
130 syncmsg msg;
131 int len = strlen(reason);
132
133 D("sync: failure: %s\n", reason);
134
135 msg.data.id = ID_FAIL;
136 msg.data.size = htoll(len);
137 if(writex(s, &msg.data, sizeof(msg.data)) ||
138 writex(s, reason, len)) {
139 return -1;
140 } else {
141 return 0;
142 }
143 }
144
145 static int fail_errno(int s)
146 {
147 return fail_message(s, strerror(errno));
148 }
149
150 static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
151 {
152 syncmsg msg;
153 unsigned int timestamp = 0;
154 int fd;
155
156 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
157 if(fd < 0 && errno == ENOENT) {
158 mkdirs(path);
159 fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
160 }
161 if(fd < 0 && errno == EEXIST) {
162 fd = adb_open_mode(path, O_WRONLY, mode);
163 }
164 if(fd < 0) {
165 if(fail_errno(s))
166 return -1;
167 fd = -1;
168 }
169
170 for(;;) {
171 unsigned int len;
172
173 if(readx(s, &msg.data, sizeof(msg.data)))
174 goto fail;
175
176 if(msg.data.id != ID_DATA) {
177 if(msg.data.id == ID_DONE) {
178 timestamp = ltohl(msg.data.size);
179 break;
180 }
181 fail_message(s, "invalid data message");
182 goto fail;
183 }
184 len = ltohl(msg.data.size);
185 if(len > SYNC_DATA_MAX) {
186 fail_message(s, "oversize data message");
187 goto fail;
188 }
189 if(readx(s, buffer, len))
190 goto fail;
191
192 if(fd < 0)
193 continue;
194 if(writex(fd, buffer, len)) {
195 adb_close(fd);
196 adb_unlink(path);
197 fd = -1;
198 if(fail_errno(s)) return -1;
199 }
200 }
201
202 if(fd >= 0) {
203 struct utimbuf u;
204 adb_close(fd);
205 u.actime = timestamp;
206 u.modtime = timestamp;
207 utime(path, &u);
208
209 msg.status.id = ID_OKAY;
210 msg.status.msglen = 0;
211 if(writex(s, &msg.status, sizeof(msg.status)))
212 return -1;
213 }
214 return 0;
215
216 fail:
217 if(fd >= 0)
218 adb_close(fd);
219 adb_unlink(path);
220 return -1;
221 }
222
223 #ifdef HAVE_SYMLINKS
224 static int handle_send_link(int s, char *path, char *buffer)
225 {
226 syncmsg msg;
227 unsigned int len;
228 int ret;
229
230 if(readx(s, &msg.data, sizeof(msg.data)))
231 return -1;
232
233 if(msg.data.id != ID_DATA) {
234 fail_message(s, "invalid data message: expected ID_DATA");
235 return -1;
236 }
237
238 len = ltohl(msg.data.size);
239 if(len > SYNC_DATA_MAX) {
240 fail_message(s, "oversize data message");
241 return -1;
242 }
243 if(readx(s, buffer, len))
244 return -1;
245
246 ret = symlink(buffer, path);
247 if(ret && errno == ENOENT) {
248 mkdirs(path);
249 ret = symlink(buffer, path);
250 }
251 if(ret) {
252 fail_errno(s);
253 return -1;
254 }
255
256 if(readx(s, &msg.data, sizeof(msg.data)))
257 return -1;
258
259 if(msg.data.id == ID_DONE) {
260 msg.status.id = ID_OKAY;
261 msg.status.msglen = 0;
262 if(writex(s, &msg.status, sizeof(msg.status)))
263 return -1;
264 } else {
265 fail_message(s, "invalid data message: expected ID_DONE");
266 return -1;
267 }
268
269 return 0;
270 }
271 #endif /* HAVE_SYMLINKS */
272
273 static int do_send(int s, char *path, char *buffer)
274 {
275 char *tmp;
276 mode_t mode;
277 int is_link, ret;
278
279 tmp = strrchr(path,',');
280 if(tmp) {
281 *tmp = 0;
282 errno = 0;
283 mode = strtoul(tmp + 1, NULL, 0);
284 #ifndef HAVE_SYMLINKS
285 is_link = 0;
286 #else
287 is_link = S_ISLNK(mode);
288 #endif
289 mode &= 0777;
290 }
291 if(!tmp || errno) {
292 mode = 0644;
293 is_link = 0;
294 }
295
296 adb_unlink(path);
297
298
299 #ifdef HAVE_SYMLINKS
300 if(is_link)
301 ret = handle_send_link(s, path, buffer);
302 else {
303 #else
304 {
305 #endif
306 /* copy user permission bits to "group" and "other" permissions */
307 mode |= ((mode >> 3) & 0070);
308 mode |= ((mode >> 3) & 0007);
309
310 ret = handle_send_file(s, path, mode, buffer);
311 }
312
313 return ret;
314 }
315
316 static int do_recv(int s, const char *path, char *buffer)
317 {
318 syncmsg msg;
319 int fd, r;
320
321 fd = adb_open(path, O_RDONLY);
322 if(fd < 0) {
323 if(fail_errno(s)) return -1;
324 return 0;
325 }
326
327 msg.data.id = ID_DATA;
328 for(;;) {
329 r = adb_read(fd, buffer, SYNC_DATA_MAX);
330 if(r <= 0) {
331 if(r == 0) break;
332 if(errno == EINTR) continue;
333 r = fail_errno(s);
334 adb_close(fd);
335 return r;
336 }
337 msg.data.size = htoll(r);
338 if(writex(s, &msg.data, sizeof(msg.data)) ||
339 writex(s, buffer, r)) {
340 adb_close(fd);
341 return -1;
342 }
343 }
344
345 adb_close(fd);
346
347 msg.data.id = ID_DONE;
348 msg.data.size = 0;
349 if(writex(s, &msg.data, sizeof(msg.data))) {
350 return -1;
351 }
352
353 return 0;
354 }
355
356 void file_sync_service(int fd, void *cookie)
357 {
358 syncmsg msg;
359 char name[1025];
360 unsigned namelen;
361
362 char *buffer = malloc(SYNC_DATA_MAX);
363 if(buffer == 0) goto fail;
364
365 for(;;) {
366 D("sync: waiting for command\n");
367
368 if(readx(fd, &msg.req, sizeof(msg.req))) {
369 fail_message(fd, "command read failure");
370 break;
371 }
372 namelen = ltohl(msg.req.namelen);
373 if(namelen > 1024) {
374 fail_message(fd, "invalid namelen");
375 break;
376 }
377 if(readx(fd, name, namelen)) {
378 fail_message(fd, "filename read failure");
379 break;
380 }
381 name[namelen] = 0;
382
383 msg.req.namelen = 0;
384 D("sync: '%s' '%s'\n", (char*) &msg.req, name);
385
386 switch(msg.req.id) {
387 case ID_STAT:
388 if(do_stat(fd, name)) goto fail;
389 break;
390 case ID_LIST:
391 if(do_list(fd, name)) goto fail;
392 break;
393 case ID_SEND:
394 if(do_send(fd, name, buffer)) goto fail;
395 break;
396 case ID_RECV:
397 if(do_recv(fd, name, buffer)) goto fail;
398 break;
399 case ID_QUIT:
400 goto fail;
401 default:
402 fail_message(fd, "unknown command");
403 goto fail;
404 }
405 }
406
407 fail:
408 if(buffer != 0) free(buffer);
409 D("sync: done\n");
410 adb_close(fd);
411 }
+0
-87
adb/file_sync_service.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _FILE_SYNC_SERVICE_H_
17 #define _FILE_SYNC_SERVICE_H_
18
19 #ifdef __ppc__
20 static inline unsigned __swap_uint32(unsigned x)
21 {
22 return (((x) & 0xFF000000) >> 24)
23 | (((x) & 0x00FF0000) >> 8)
24 | (((x) & 0x0000FF00) << 8)
25 | (((x) & 0x000000FF) << 24);
26 }
27 #define htoll(x) __swap_uint32(x)
28 #define ltohl(x) __swap_uint32(x)
29 #define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
30 #else
31 #define htoll(x) (x)
32 #define ltohl(x) (x)
33 #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
34 #endif
35
36 #define ID_STAT MKID('S','T','A','T')
37 #define ID_LIST MKID('L','I','S','T')
38 #define ID_ULNK MKID('U','L','N','K')
39 #define ID_SEND MKID('S','E','N','D')
40 #define ID_RECV MKID('R','E','C','V')
41 #define ID_DENT MKID('D','E','N','T')
42 #define ID_DONE MKID('D','O','N','E')
43 #define ID_DATA MKID('D','A','T','A')
44 #define ID_OKAY MKID('O','K','A','Y')
45 #define ID_FAIL MKID('F','A','I','L')
46 #define ID_QUIT MKID('Q','U','I','T')
47
48 typedef union {
49 unsigned id;
50 struct {
51 unsigned id;
52 unsigned namelen;
53 } req;
54 struct {
55 unsigned id;
56 unsigned mode;
57 unsigned size;
58 unsigned time;
59 } stat;
60 struct {
61 unsigned id;
62 unsigned mode;
63 unsigned size;
64 unsigned time;
65 unsigned namelen;
66 } dent;
67 struct {
68 unsigned id;
69 unsigned size;
70 } data;
71 struct {
72 unsigned id;
73 unsigned msglen;
74 } status;
75 } syncmsg;
76
77
78 void file_sync_service(int fd, void *cookie);
79 int do_sync_ls(const char *path);
80 int do_sync_push(const char *lpath, const char *rpath, int verifyApk);
81 int do_sync_sync(const char *lpath, const char *rpath);
82 int do_sync_pull(const char *rpath, const char *lpath);
83
84 #define SYNC_DATA_MAX (64*1024)
85
86 #endif
+0
-70
adb/framebuffer_service.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <fcntl.h>
21
22 #include <cutils/fdevent.h>
23 #include "adb.h"
24
25 #include <linux/fb.h>
26 #include <sys/ioctl.h>
27 #include <sys/mman.h>
28
29 /* TODO:
30 ** - grab the current buffer, not the first buffer
31 ** - sync with vsync to avoid tearing
32 */
33
34 void framebuffer_service(int fd, void *cookie)
35 {
36 struct fb_var_screeninfo vinfo;
37 int fb;
38 void *ptr = MAP_FAILED;
39 char x;
40
41 unsigned fbinfo[4];
42
43 fb = open("/dev/graphics/fb0", O_RDONLY);
44 if(fb < 0) goto done;
45
46 if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) goto done;
47 fcntl(fb, F_SETFD, FD_CLOEXEC);
48
49 fbinfo[0] = 16;
50 fbinfo[1] = vinfo.xres * vinfo.yres * 2;
51 fbinfo[2] = vinfo.xres;
52 fbinfo[3] = vinfo.yres;
53
54 ptr = mmap(0, fbinfo[1], PROT_READ, MAP_SHARED, fb, 0);
55 if(ptr == MAP_FAILED) goto done;
56
57 if(writex(fd, fbinfo, sizeof(unsigned) * 4)) goto done;
58
59 for(;;) {
60 if(readx(fd, &x, 1)) goto done;
61 if(writex(fd, ptr, fbinfo[1])) goto done;
62 }
63
64 done:
65 if(ptr != MAP_FAILED) munmap(ptr, fbinfo[1]);
66 if(fb >= 0) close(fb);
67 close(fd);
68 }
69
+0
-31
adb/get_my_path_darwin.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <utils/executablepath.h>
17 #import <Carbon/Carbon.h>
18 #include <unistd.h>
19
20 void get_my_path(char s[PATH_MAX])
21 {
22 ProcessSerialNumber psn;
23 GetCurrentProcess(&psn);
24 CFDictionaryRef dict;
25 dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
26 CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
27 CFSTR("CFBundleExecutable"));
28 CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
29 }
30
+0
-33
adb/get_my_path_linux.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <limits.h>
19 #include <stdio.h>
20
21 void get_my_path(char exe[PATH_MAX])
22 {
23 char proc[64];
24 snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
25 int err = readlink(proc, exe, PATH_MAX - 1);
26 if(err > 0) {
27 exe[err] = 0;
28 } else {
29 exe[0] = 0;
30 }
31 }
32
+0
-31
adb/get_my_path_windows.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <limits.h>
17 #include <assert.h>
18 #include <windows.h>
19
20 void get_my_path(char exe[PATH_MAX])
21 {
22 char* r;
23
24 GetModuleFileName( NULL, exe, PATH_MAX-1 );
25 exe[PATH_MAX-1] = 0;
26 r = strrchr( exe, '\\' );
27 if (r)
28 *r = 0;
29 }
30
+0
-13
adb/history.h less more
0 #ifndef _HISTORY_H_
1 #define _HISTORY_H_
2
3 #define SH_ARROW_ANY "\x1b\x5b"
4 #define SH_ARROW_UP '\x41'
5 #define SH_ARROW_DOWN '\x42'
6 #define SH_ARROW_RIGHT '\x43'
7 #define SH_ARROW_LEFT '\x44'
8 #define SH_DEL_CHAR '\x7F'
9 #define SH_BLANK_CHAR '\x20'
10
11 #endif
12
+0
-709
adb/jdwp_service.c less more
0 /* implement the "debug-ports" and "track-debug-ports" device services */
1 #include "sysdeps.h"
2 #define TRACE_TAG TRACE_JDWP
3 #include "adb.h"
4 #include <errno.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 /* here's how these things work.
9
10 when adbd starts, it creates a unix server socket
11 named @vm-debug-control (@ is a shortcut for "first byte is zero"
12 to use the private namespace instead of the file system)
13
14 when a new JDWP daemon thread starts in a new VM process, it creates
15 a connection to @vm-debug-control to announce its availability.
16
17
18 JDWP thread @vm-debug-control
19 | |
20 |-------------------------------> |
21 | hello I'm in process <pid> |
22 | |
23 | |
24
25 the connection is kept alive. it will be closed automatically if
26 the JDWP process terminates (this allows adbd to detect dead
27 processes).
28
29 adbd thus maintains a list of "active" JDWP processes. it can send
30 its content to clients through the "device:debug-ports" service,
31 or even updates through the "device:track-debug-ports" service.
32
33 when a debugger wants to connect, it simply runs the command
34 equivalent to "adb forward tcp:<hostport> jdwp:<pid>"
35
36 "jdwp:<pid>" is a new forward destination format used to target
37 a given JDWP process on the device. when sutch a request arrives,
38 adbd does the following:
39
40 - first, it calls socketpair() to create a pair of equivalent
41 sockets.
42
43 - it attaches the first socket in the pair to a local socket
44 which is itself attached to the transport's remote socket:
45
46
47 - it sends the file descriptor of the second socket directly
48 to the JDWP process with the help of sendmsg()
49
50
51 JDWP thread @vm-debug-control
52 | |
53 | <----------------------|
54 | OK, try this file descriptor |
55 | |
56 | |
57
58 then, the JDWP thread uses this new socket descriptor as its
59 pass-through connection to the debugger (and receives the
60 JDWP-Handshake message, answers to it, etc...)
61
62 this gives the following graphics:
63 ____________________________________
64 | |
65 | ADB Server (host) |
66 | |
67 Debugger <---> LocalSocket <----> RemoteSocket |
68 | ^^ |
69 |___________________________||_______|
70 ||
71 Transport ||
72 (TCP for emulator - USB for device) ||
73 ||
74 ___________________________||_______
75 | || |
76 | ADBD (device) || |
77 | VV |
78 JDWP <======> LocalSocket <----> RemoteSocket |
79 | |
80 |____________________________________|
81
82 due to the way adb works, this doesn't need a special socket
83 type or fancy handling of socket termination if either the debugger
84 or the JDWP process closes the connection.
85
86 THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
87 TO HAVE A BETTER IDEA, LET ME KNOW - Digit
88
89 **********************************************************************/
90
91 /** JDWP PID List Support Code
92 ** for each JDWP process, we record its pid and its connected socket
93 **/
94
95 #define MAX_OUT_FDS 4
96
97 #if !ADB_HOST
98
99 #include <sys/socket.h>
100 #include <sys/un.h>
101
102 typedef struct JdwpProcess JdwpProcess;
103 struct JdwpProcess {
104 JdwpProcess* next;
105 JdwpProcess* prev;
106 int pid;
107 int socket;
108 fdevent* fde;
109
110 char in_buff[4]; /* input character to read PID */
111 int in_len; /* number from JDWP process */
112
113 int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
114 int out_count; /* to send to the JDWP process */
115 };
116
117 static JdwpProcess _jdwp_list;
118
119 static int
120 jdwp_process_list( char* buffer, int bufferlen )
121 {
122 char* end = buffer + bufferlen;
123 char* p = buffer;
124 JdwpProcess* proc = _jdwp_list.next;
125
126 for ( ; proc != &_jdwp_list; proc = proc->next ) {
127 int len;
128
129 /* skip transient connections */
130 if (proc->pid < 0)
131 continue;
132
133 len = snprintf(p, end-p, "%d\n", proc->pid);
134 if (p + len >= end)
135 break;
136 p += len;
137 }
138 p[0] = 0;
139 return (p - buffer);
140 }
141
142
143 static int
144 jdwp_process_list_msg( char* buffer, int bufferlen )
145 {
146 char head[5];
147 int len = jdwp_process_list( buffer+4, bufferlen-4 );
148 snprintf(head, sizeof head, "%04x", len);
149 memcpy(buffer, head, 4);
150 return len + 4;
151 }
152
153
154 static void jdwp_process_list_updated(void);
155
156 static void
157 jdwp_process_free( JdwpProcess* proc )
158 {
159 if (proc) {
160 int n;
161
162 proc->prev->next = proc->next;
163 proc->next->prev = proc->prev;
164
165 if (proc->socket >= 0) {
166 shutdown(proc->socket, SHUT_RDWR);
167 adb_close(proc->socket);
168 proc->socket = -1;
169 }
170
171 if (proc->fde != NULL) {
172 fdevent_destroy(proc->fde);
173 proc->fde = NULL;
174 }
175 proc->pid = -1;
176
177 for (n = 0; n < proc->out_count; n++) {
178 adb_close(proc->out_fds[n]);
179 }
180 proc->out_count = 0;
181
182 free(proc);
183
184 jdwp_process_list_updated();
185 }
186 }
187
188
189 static void jdwp_process_event(int, unsigned, void*); /* forward */
190
191
192 static JdwpProcess*
193 jdwp_process_alloc( int socket )
194 {
195 JdwpProcess* proc = calloc(1,sizeof(*proc));
196
197 if (proc == NULL) {
198 D("not enough memory to create new JDWP process\n");
199 return NULL;
200 }
201
202 proc->socket = socket;
203 proc->pid = -1;
204 proc->next = proc;
205 proc->prev = proc;
206
207 proc->fde = fdevent_create( socket, jdwp_process_event, proc );
208 if (proc->fde == NULL) {
209 D("could not create fdevent for new JDWP process\n" );
210 free(proc);
211 return NULL;
212 }
213
214 proc->fde->state |= FDE_DONT_CLOSE;
215 proc->in_len = 0;
216 proc->out_count = 0;
217
218 /* append to list */
219 proc->next = &_jdwp_list;
220 proc->prev = proc->next->prev;
221
222 proc->prev->next = proc;
223 proc->next->prev = proc;
224
225 /* start by waiting for the PID */
226 fdevent_add(proc->fde, FDE_READ);
227
228 return proc;
229 }
230
231
232 static void
233 jdwp_process_event( int socket, unsigned events, void* _proc )
234 {
235 JdwpProcess* proc = _proc;
236
237 if (events & FDE_READ) {
238 if (proc->pid < 0) {
239 /* read the PID as a 4-hexchar string */
240 char* p = proc->in_buff + proc->in_len;
241 int size = 4 - proc->in_len;
242 char temp[5];
243 while (size > 0) {
244 int len = recv( socket, p, size, 0 );
245 if (len < 0) {
246 if (errno == EINTR)
247 continue;
248 if (errno == EAGAIN)
249 return;
250 /* this can fail here if the JDWP process crashes very fast */
251 D("weird unknown JDWP process failure: %s\n",
252 strerror(errno));
253
254 goto CloseProcess;
255 }
256 if (len == 0) { /* end of stream ? */
257 D("weird end-of-stream from unknown JDWP process\n");
258 goto CloseProcess;
259 }
260 p += len;
261 proc->in_len += len;
262 size -= len;
263 }
264 /* we have read 4 characters, now decode the pid */
265 memcpy(temp, proc->in_buff, 4);
266 temp[4] = 0;
267
268 if (sscanf( temp, "%04x", &proc->pid ) != 1) {
269 D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
270 goto CloseProcess;
271 }
272
273 /* all is well, keep reading to detect connection closure */
274 D("Adding pid %d to jdwp process list\n", proc->pid);
275 jdwp_process_list_updated();
276 }
277 else
278 {
279 /* the pid was read, if we get there it's probably because the connection
280 * was closed (e.g. the JDWP process exited or crashed) */
281 char buf[32];
282
283 for (;;) {
284 int len = recv(socket, buf, sizeof(buf), 0);
285
286 if (len <= 0) {
287 if (len < 0 && errno == EINTR)
288 continue;
289 if (len < 0 && errno == EAGAIN)
290 return;
291 else {
292 D("terminating JDWP %d connection: %s\n", proc->pid,
293 strerror(errno));
294 break;
295 }
296 }
297 else {
298 D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
299 proc->pid, len );
300 }
301 }
302
303 CloseProcess:
304 if (proc->pid >= 0)
305 D( "remove pid %d to jdwp process list\n", proc->pid );
306 jdwp_process_free(proc);
307 return;
308 }
309 }
310
311 if (events & FDE_WRITE) {
312 D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
313 proc->pid, proc->out_count, proc->out_fds[0]);
314 if (proc->out_count > 0) {
315 int fd = proc->out_fds[0];
316 int n, ret;
317 struct cmsghdr* cmsg;
318 struct msghdr msg;
319 struct iovec iov;
320 char dummy = '!';
321 char buffer[sizeof(struct cmsghdr) + sizeof(int)];
322
323 iov.iov_base = &dummy;
324 iov.iov_len = 1;
325 msg.msg_name = NULL;
326 msg.msg_namelen = 0;
327 msg.msg_iov = &iov;
328 msg.msg_iovlen = 1;
329 msg.msg_flags = 0;
330 msg.msg_control = buffer;
331 msg.msg_controllen = sizeof(buffer);
332
333 cmsg = CMSG_FIRSTHDR(&msg);
334 cmsg->cmsg_len = msg.msg_controllen;
335 cmsg->cmsg_level = SOL_SOCKET;
336 cmsg->cmsg_type = SCM_RIGHTS;
337 ((int*)CMSG_DATA(cmsg))[0] = fd;
338
339 for (;;) {
340 ret = sendmsg(proc->socket, &msg, 0);
341 if (ret >= 0)
342 break;
343 if (errno == EINTR)
344 continue;
345 D("sending new file descriptor to JDWP %d failed: %s\n",
346 proc->pid, strerror(errno));
347 goto CloseProcess;
348 }
349
350 D("sent file descriptor %d to JDWP process %d\n",
351 fd, proc->pid);
352
353 for (n = 1; n < proc->out_count; n++)
354 proc->out_fds[n-1] = proc->out_fds[n];
355
356 if (--proc->out_count == 0)
357 fdevent_del( proc->fde, FDE_WRITE );
358 }
359 }
360 }
361
362
363 int
364 create_jdwp_connection_fd(int pid)
365 {
366 JdwpProcess* proc = _jdwp_list.next;
367
368 D("looking for pid %d in JDWP process list\n", pid);
369 for ( ; proc != &_jdwp_list; proc = proc->next ) {
370 if (proc->pid == pid) {
371 goto FoundIt;
372 }
373 }
374 D("search failed !!\n");
375 return -1;
376
377 FoundIt:
378 {
379 int fds[2];
380
381 if (proc->out_count >= MAX_OUT_FDS) {
382 D("%s: too many pending JDWP connection for pid %d\n",
383 __FUNCTION__, pid);
384 return -1;
385 }
386
387 if (adb_socketpair(fds) < 0) {
388 D("%s: socket pair creation failed: %s\n",
389 __FUNCTION__, strerror(errno));
390 return -1;
391 }
392
393 proc->out_fds[ proc->out_count ] = fds[1];
394 if (++proc->out_count == 1)
395 fdevent_add( proc->fde, FDE_WRITE );
396
397 return fds[0];
398 }
399 }
400
401 /** VM DEBUG CONTROL SOCKET
402 **
403 ** we do implement a custom asocket to receive the data
404 **/
405
406 /* name of the debug control Unix socket */
407 #define JDWP_CONTROL_NAME "\0jdwp-control"
408 #define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1)
409
410 typedef struct {
411 int listen_socket;
412 fdevent* fde;
413
414 } JdwpControl;
415
416
417 static void
418 jdwp_control_event(int s, unsigned events, void* user);
419
420
421 static int
422 jdwp_control_init( JdwpControl* control,
423 const char* sockname,
424 int socknamelen )
425 {
426 struct sockaddr_un addr;
427 socklen_t addrlen;
428 int s;
429 int maxpath = sizeof(addr.sun_path);
430 int pathlen = socknamelen;
431
432 if (pathlen >= maxpath) {
433 D( "vm debug control socket name too long (%d extra chars)\n",
434 pathlen+1-maxpath );
435 return -1;
436 }
437
438 memset(&addr, 0, sizeof(addr));
439 addr.sun_family = AF_UNIX;
440 memcpy(addr.sun_path, sockname, socknamelen);
441
442 s = socket( AF_UNIX, SOCK_STREAM, 0 );
443 if (s < 0) {
444 D( "could not create vm debug control socket. %d: %s\n",
445 errno, strerror(errno));
446 return -1;
447 }
448
449 addrlen = (pathlen + sizeof(addr.sun_family));
450
451 if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
452 D( "could not bind vm debug control socket: %d: %s\n",
453 errno, strerror(errno) );
454 adb_close(s);
455 return -1;
456 }
457
458 if ( listen(s, 4) < 0 ) {
459 D("listen failed in jdwp control socket: %d: %s\n",
460 errno, strerror(errno));
461 adb_close(s);
462 return -1;
463 }
464
465 control->listen_socket = s;
466
467 control->fde = fdevent_create(s, jdwp_control_event, control);
468 if (control->fde == NULL) {
469 D( "could not create fdevent for jdwp control socket\n" );
470 adb_close(s);
471 return -1;
472 }
473
474 /* only wait for incoming connections */
475 fdevent_add(control->fde, FDE_READ);
476
477 D("jdwp control socket started (%d)\n", control->listen_socket);
478 return 0;
479 }
480
481
482 static void
483 jdwp_control_event( int s, unsigned events, void* _control )
484 {
485 JdwpControl* control = (JdwpControl*) _control;
486
487 if (events & FDE_READ) {
488 struct sockaddr addr;
489 socklen_t addrlen = sizeof(addr);
490 int s = -1;
491 JdwpProcess* proc;
492
493 do {
494 s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
495 if (s < 0) {
496 if (errno == EINTR)
497 continue;
498 if (errno == ECONNABORTED) {
499 /* oops, the JDWP process died really quick */
500 D("oops, the JDWP process died really quick\n");
501 return;
502 }
503 /* the socket is probably closed ? */
504 D( "weird accept() failed on jdwp control socket: %s\n",
505 strerror(errno) );
506 return;
507 }
508 }
509 while (s < 0);
510
511 proc = jdwp_process_alloc( s );
512 if (proc == NULL)
513 return;
514 }
515 }
516
517
518 static JdwpControl _jdwp_control;
519
520 /** "jdwp" local service implementation
521 ** this simply returns the list of known JDWP process pids
522 **/
523
524 typedef struct {
525 asocket socket;
526 int pass;
527 } JdwpSocket;
528
529 static void
530 jdwp_socket_close( asocket* s )
531 {
532 asocket* peer = s->peer;
533
534 remove_socket(s);
535
536 if (peer) {
537 peer->peer = NULL;
538 peer->close(peer);
539 }
540 free(s);
541 }
542
543 static int
544 jdwp_socket_enqueue( asocket* s, apacket* p )
545 {
546 /* you can't write to this asocket */
547 put_apacket(p);
548 s->peer->close(s->peer);
549 return -1;
550 }
551
552
553 static void
554 jdwp_socket_ready( asocket* s )
555 {
556 JdwpSocket* jdwp = (JdwpSocket*)s;
557 asocket* peer = jdwp->socket.peer;
558
559 /* on the first call, send the list of pids,
560 * on the second one, close the connection
561 */
562 if (jdwp->pass == 0) {
563 apacket* p = get_apacket();
564 p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
565 peer->enqueue(peer, p);
566 jdwp->pass = 1;
567 }
568 else {
569 peer->close(peer);
570 }
571 }
572
573 asocket*
574 create_jdwp_service_socket( void )
575 {
576 JdwpSocket* s = calloc(sizeof(*s),1);
577
578 if (s == NULL)
579 return NULL;
580
581 install_local_socket(&s->socket);
582
583 s->socket.ready = jdwp_socket_ready;
584 s->socket.enqueue = jdwp_socket_enqueue;
585 s->socket.close = jdwp_socket_close;
586 s->pass = 0;
587
588 return &s->socket;
589 }
590
591 /** "track-jdwp" local service implementation
592 ** this periodically sends the list of known JDWP process pids
593 ** to the client...
594 **/
595
596 typedef struct JdwpTracker JdwpTracker;
597
598 struct JdwpTracker {
599 asocket socket;
600 JdwpTracker* next;
601 JdwpTracker* prev;
602 int need_update;
603 };
604
605 static JdwpTracker _jdwp_trackers_list;
606
607
608 static void
609 jdwp_process_list_updated(void)
610 {
611 char buffer[1024];
612 int len;
613 JdwpTracker* t = _jdwp_trackers_list.next;
614
615 len = jdwp_process_list_msg(buffer, sizeof(buffer));
616
617 for ( ; t != &_jdwp_trackers_list; t = t->next ) {
618 apacket* p = get_apacket();
619 asocket* peer = t->socket.peer;
620 memcpy(p->data, buffer, len);
621 p->len = len;
622 peer->enqueue( peer, p );
623 }
624 }
625
626 static void
627 jdwp_tracker_close( asocket* s )
628 {
629 JdwpTracker* tracker = (JdwpTracker*) s;
630 asocket* peer = s->peer;
631
632 if (peer) {
633 peer->peer = NULL;
634 peer->close(peer);
635 }
636
637 remove_socket(s);
638
639 tracker->prev->next = tracker->next;
640 tracker->next->prev = tracker->prev;
641
642 free(s);
643 }
644
645 static void
646 jdwp_tracker_ready( asocket* s )
647 {
648 JdwpTracker* t = (JdwpTracker*) s;
649
650 if (t->need_update) {
651 apacket* p = get_apacket();
652 t->need_update = 0;
653 p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data));
654 s->peer->enqueue(s->peer, p);
655 }
656 }
657
658 static int
659 jdwp_tracker_enqueue( asocket* s, apacket* p )
660 {
661 /* you can't write to this socket */
662 put_apacket(p);
663 s->peer->close(s->peer);
664 return -1;
665 }
666
667
668 asocket*
669 create_jdwp_tracker_service_socket( void )
670 {
671 JdwpTracker* t = calloc(sizeof(*t),1);
672
673 if (t == NULL)
674 return NULL;
675
676 t->next = &_jdwp_trackers_list;
677 t->prev = t->next->prev;
678
679 t->next->prev = t;
680 t->prev->next = t;
681
682 install_local_socket(&t->socket);
683
684 t->socket.ready = jdwp_tracker_ready;
685 t->socket.enqueue = jdwp_tracker_enqueue;
686 t->socket.close = jdwp_tracker_close;
687 t->need_update = 1;
688
689 return &t->socket;
690 }
691
692
693 int
694 init_jdwp(void)
695 {
696 _jdwp_list.next = &_jdwp_list;
697 _jdwp_list.prev = &_jdwp_list;
698
699 _jdwp_trackers_list.next = &_jdwp_trackers_list;
700 _jdwp_trackers_list.prev = &_jdwp_trackers_list;
701
702 return jdwp_control_init( &_jdwp_control,
703 JDWP_CONTROL_NAME,
704 JDWP_CONTROL_NAME_LEN );
705 }
706
707 #endif /* !ADB_HOST */
708
+0
-92
adb/log_service.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <sys/socket.h>
24 #include <cutils/logger.h>
25 #include "sysdeps.h"
26 #include "adb.h"
27
28 #define LOG_FILE_DIR "/dev/log/"
29
30 void write_log_entry(int fd, struct logger_entry *buf);
31
32 void log_service(int fd, void *cookie)
33 {
34 /* get the name of the log filepath to read */
35 char * log_filepath = cookie;
36
37 /* open the log file. */
38 int logfd = unix_open(log_filepath, O_RDONLY);
39 if (logfd < 0) {
40 goto done;
41 }
42
43 // temp buffer to read the entries
44 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
45 struct logger_entry *entry = (struct logger_entry *) buf;
46
47 while (1) {
48 int ret;
49
50 ret = unix_read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
51 if (ret < 0) {
52 if (errno == EINTR || errno == EAGAIN)
53 continue;
54 // perror("logcat read");
55 goto done;
56 }
57 else if (!ret) {
58 // fprintf(stderr, "read: Unexpected EOF!\n");
59 goto done;
60 }
61
62 /* NOTE: driver guarantees we read exactly one full entry */
63
64 entry->msg[entry->len] = '\0';
65
66 write_log_entry(fd, entry);
67 }
68
69 done:
70 unix_close(fd);
71 free(log_filepath);
72 }
73
74 /* returns the full path to the log file in a newly allocated string */
75 char * get_log_file_path(const char * log_name) {
76 char *log_device = malloc(strlen(LOG_FILE_DIR) + strlen(log_name) + 1);
77
78 strcpy(log_device, LOG_FILE_DIR);
79 strcat(log_device, log_name);
80
81 return log_device;
82 }
83
84
85 /* prints one log entry into the file descriptor fd */
86 void write_log_entry(int fd, struct logger_entry *buf)
87 {
88 size_t size = sizeof(struct logger_entry) + buf->len;
89
90 writex(fd, buf, size);
91 }
+0
-14
adb/mutex_list.h less more
0 /* the list of mutexes used by addb */
1 #ifndef ADB_MUTEX
2 #error ADB_MUTEX not defined when including this file
3 #endif
4
5 ADB_MUTEX(dns_lock)
6 ADB_MUTEX(socket_list_lock)
7 ADB_MUTEX(transport_lock)
8 #if ADB_HOST
9 ADB_MUTEX(local_transports_lock)
10 #endif
11 ADB_MUTEX(usb_lock)
12
13 #undef ADB_MUTEX
+0
-252
adb/protocol.txt less more
0
1 --- a replacement for aproto -------------------------------------------
2
3 When it comes down to it, aproto's primary purpose is to forward
4 various streams between the host computer and client device (in either
5 direction).
6
7 This replacement further simplifies the concept, reducing the protocol
8 to an extremely straightforward model optimized to accomplish the
9 forwarding of these streams and removing additional state or
10 complexity.
11
12 The host side becomes a simple comms bridge with no "UI", which will
13 be used by either commandline or interactive tools to communicate with
14 a device or emulator that is connected to the bridge.
15
16 The protocol is designed to be straightforward and well-defined enough
17 that if it needs to be reimplemented in another environment (Java
18 perhaps), there should not problems ensuring perfect interoperability.
19
20 The protocol discards the layering aproto has and should allow the
21 implementation to be much more robust.
22
23
24 --- protocol overview and basics ---------------------------------------
25
26 The transport layer deals in "messages", which consist of a 24 byte
27 header followed (optionally) by a payload. The header consists of 6
28 32 bit words which are sent across the wire in little endian format.
29
30 struct message {
31 unsigned command; /* command identifier constant */
32 unsigned arg0; /* first argument */
33 unsigned arg1; /* second argument */
34 unsigned data_length; /* length of payload (0 is allowed) */
35 unsigned data_crc32; /* crc32 of data payload */
36 unsigned magic; /* command ^ 0xffffffff */
37 };
38
39 Receipt of an invalid message header, corrupt message payload, or an
40 unrecognized command MUST result in the closing of the remote
41 connection. The protocol depends on shared state and any break in the
42 message stream will result in state getting out of sync.
43
44 The following sections describe the six defined message types in
45 detail. Their format is COMMAND(arg0, arg1, payload) where the payload
46 is represented by a quoted string or an empty string if none should be
47 sent.
48
49 The identifiers "local-id" and "remote-id" are always relative to the
50 *sender* of the message, so for a receiver, the meanings are effectively
51 reversed.
52
53
54
55 --- CONNECT(version, maxdata, "system-identity-string") ----------------
56
57 The CONNECT message establishes the presence of a remote system.
58 The version is used to ensure protocol compatibility and maxdata
59 declares the maximum message body size that the remote system
60 is willing to accept.
61
62 Currently, version=0x01000000 and maxdata=4096
63
64 Both sides send a CONNECT message when the connection between them is
65 established. Until a CONNECT message is received no other messages may
66 be sent. Any messages received before a CONNECT message MUST be ignored.
67
68 If a CONNECT message is received with an unknown version or insufficiently
69 large maxdata value, the connection with the other side must be closed.
70
71 The system identity string should be "<systemtype>:<serialno>:<banner>"
72 where systemtype is "bootloader", "device", or "host", serialno is some
73 kind of unique ID (or empty), and banner is a human-readable version
74 or identifier string (informational only).
75
76
77 --- OPEN(local-id, 0, "destination") -----------------------------------
78
79 The OPEN message informs the recipient that the sender has a stream
80 identified by local-id that it wishes to connect to the named
81 destination in the message payload. The local-id may not be zero.
82
83 The OPEN message MUST result in either a READY message indicating that
84 the connection has been established (and identifying the other end) or
85 a CLOSE message, indicating failure. An OPEN message also implies
86 a READY message sent at the same time.
87
88 Common destination naming conventions include:
89
90 * "tcp:<host>:<port>" - host may be omitted to indicate localhost
91 * "udp:<host>:<port>" - host may be omitted to indicate localhost
92 * "local-dgram:<identifier>"
93 * "local-stream:<identifier>"
94 * "shell" - local shell service
95 * "upload" - service for pushing files across (like aproto's /sync)
96 * "fs-bridge" - FUSE protocol filesystem bridge
97
98
99 --- READY(local-id, remote-id, "") -------------------------------------
100
101 The READY message informs the recipient that the sender's stream
102 identified by local-id is ready for write messages and that it is
103 connected to the recipient's stream identified by remote-id.
104
105 Neither the local-id nor the remote-id may be zero.
106
107 A READY message containing a remote-id which does not map to an open
108 stream on the recipient's side is ignored. The stream may have been
109 closed while this message was in-flight.
110
111 The local-id is ignored on all but the first READY message (where it
112 is used to establish the connection). Nonetheless, the local-id MUST
113 not change on later READY messages sent to the same stream.
114
115
116
117 --- WRITE(0, remote-id, "data") ----------------------------------------
118
119 The WRITE message sends data to the recipient's stream identified by
120 remote-id. The payload MUST be <= maxdata in length.
121
122 A WRITE message containing a remote-id which does not map to an open
123 stream on the recipient's side is ignored. The stream may have been
124 closed while this message was in-flight.
125
126 A WRITE message may not be sent until a READY message is received.
127 Once a WRITE message is sent, an additional WRITE message may not be
128 sent until another READY message has been received. Recipients of
129 a WRITE message that is in violation of this requirement will CLOSE
130 the connection.
131
132
133 --- CLOSE(local-id, remote-id, "") -------------------------------------
134
135 The CLOSE message informs recipient that the connection between the
136 sender's stream (local-id) and the recipient's stream (remote-id) is
137 broken. The remote-id MUST not be zero, but the local-id MAY be zero
138 if this CLOSE indicates a failed OPEN.
139
140 A CLOSE message containing a remote-id which does not map to an open
141 stream on the recipient's side is ignored. The stream may have
142 already been closed by the recipient while this message was in-flight.
143
144 The recipient should not respond to a CLOSE message in any way. The
145 recipient should cancel pending WRITEs or CLOSEs, but this is not a
146 requirement, since they will be ignored.
147
148
149 --- SYNC(online, sequence, "") -----------------------------------------
150
151 The SYNC message is used by the io pump to make sure that stale
152 outbound messages are discarded when the connection to the remote side
153 is broken. It is only used internally to the bridge and never valid
154 to send across the wire.
155
156 * when the connection to the remote side goes offline, the io pump
157 sends a SYNC(0, 0) and starts discarding all messages
158 * when the connection to the remote side is established, the io pump
159 sends a SYNC(1, token) and continues to discard messages
160 * when the io pump receives a matching SYNC(1, token), it once again
161 starts accepting messages to forward to the remote side
162
163
164 --- message command constants ------------------------------------------
165
166 #define A_SYNC 0x434e5953
167 #define A_CNXN 0x4e584e43
168 #define A_OPEN 0x4e45504f
169 #define A_OKAY 0x59414b4f
170 #define A_CLSE 0x45534c43
171 #define A_WRTE 0x45545257
172
173
174
175 --- implementation details ---------------------------------------------
176
177 The core of the bridge program will use three threads. One thread
178 will be a select/epoll loop to handle io between various inbound and
179 outbound connections and the connection to the remote side.
180
181 The remote side connection will be implemented as two threads (one for
182 reading, one for writing) and a datagram socketpair to provide the
183 channel between the main select/epoll thread and the remote connection
184 threadpair. The reason for this is that for usb connections, the
185 kernel interface on linux and osx does not allow you to do meaningful
186 nonblocking IO.
187
188 The endian swapping for the message headers will happen (as needed) in
189 the remote connection threadpair and that the rest of the program will
190 always treat message header values as native-endian.
191
192 The bridge program will be able to have a number of mini-servers
193 compiled in. They will be published under known names (examples
194 "shell", "fs-bridge", etc) and upon receiving an OPEN() to such a
195 service, the bridge program will create a stream socketpair and spawn
196 a thread or subprocess to handle the io.
197
198
199 --- simplified / embedded implementation -------------------------------
200
201 For limited environments, like the bootloader, it is allowable to
202 support a smaller, fixed number of channels using pre-assigned channel
203 ID numbers such that only one stream may be connected to a bootloader
204 endpoint at any given time. The protocol remains unchanged, but the
205 "embedded" version of it is less dynamic.
206
207 The bootloader will support two streams. A "bootloader:debug" stream,
208 which may be opened to get debug messages from the bootloader and a
209 "bootloader:control", stream which will support the set of basic
210 bootloader commands.
211
212 Example command stream dialogues:
213 "flash_kernel,2515049,........\n" "okay\n"
214 "flash_ramdisk,5038,........\n" "fail,flash write error\n"
215 "bogus_command......" <CLOSE>
216
217
218 --- future expansion ---------------------------------------------------
219
220 I plan on providing either a message or a special control stream so that
221 the client device could ask the host computer to setup inbound socket
222 translations on the fly on behalf of the client device.
223
224
225 The initial design does handshaking to provide flow control, with a
226 message flow that looks like:
227
228 >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE
229
230 The far side may choose to issue the READY message as soon as it receives
231 a WRITE or it may defer the READY until the write to the local stream
232 succeeds. A future version may want to do some level of windowing where
233 multiple WRITEs may be sent without requiring individual READY acks.
234
235 ------------------------------------------------------------------------
236
237 --- smartsockets -------------------------------------------------------
238
239 Port 5037 is used for smart sockets which allow a client on the host
240 side to request access to a service in the host adb daemon or in the
241 remote (device) daemon. The service is requested by ascii name,
242 preceeded by a 4 digit hex length. Upon successful connection an
243 "OKAY" response is sent, otherwise a "FAIL" message is returned. Once
244 connected the client is talking to that (remote or local) service.
245
246 client: <hex4> <service-name>
247 server: "OKAY"
248
249 client: <hex4> <service-name>
250 server: "FAIL" <hex4> <reason>
251
+0
-103
adb/remount_service.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <sys/mount.h>
22 #include <errno.h>
23
24 #include "sysdeps.h"
25
26 #define TRACE_TAG TRACE_ADB
27 #include "adb.h"
28
29
30 static int system_ro = 1;
31
32 /* Returns the mount number of the requested partition from /proc/mtd */
33 static int find_mount(const char *findme)
34 {
35 int fd;
36 int res;
37 int size;
38 char *token = NULL;
39 const char delims[] = "\n";
40 char buf[1024];
41
42 fd = unix_open("/proc/mtd", O_RDONLY);
43 if (fd < 0)
44 return -errno;
45
46 buf[sizeof(buf) - 1] = '\0';
47 size = adb_read(fd, buf, sizeof(buf) - 1);
48 adb_close(fd);
49
50 token = strtok(buf, delims);
51
52 while (token) {
53 char mtdname[16];
54 int mtdnum, mtdsize, mtderasesize;
55
56 res = sscanf(token, "mtd%d: %x %x %15s",
57 &mtdnum, &mtdsize, &mtderasesize, mtdname);
58
59 if (res == 4 && !strcmp(mtdname, findme))
60 return mtdnum;
61
62 token = strtok(NULL, delims);
63 }
64 return -1;
65 }
66
67 /* Init mounts /system as read only, remount to enable writes. */
68 static int remount_system()
69 {
70 int num;
71 char source[64];
72 if (system_ro == 0) {
73 return 0;
74 }
75 if ((num = find_mount("\"system\"")) < 0)
76 return -1;
77
78 snprintf(source, sizeof source, "/dev/block/mtdblock%d", num);
79 system_ro = mount(source, "/system", "yaffs2", MS_REMOUNT, NULL);
80 return system_ro;
81 }
82
83 static void write_string(int fd, const char* str)
84 {
85 writex(fd, str, strlen(str));
86 }
87
88 void remount_service(int fd, void *cookie)
89 {
90 int ret = remount_system();
91
92 if (!ret)
93 write_string(fd, "remount succeeded\n");
94 else {
95 char buffer[200];
96 snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
97 write_string(fd, buffer);
98 }
99
100 adb_close(fd);
101 }
102
+0
-367
adb/services.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "sysdeps.h"
23
24 #define TRACE_TAG TRACE_ADB
25 #include "adb.h"
26 #include "file_sync_service.h"
27
28 #if ADB_HOST
29 # ifndef HAVE_WINSOCK
30 # include <netinet/in.h>
31 # include <netdb.h>
32 # endif
33 #endif
34
35 typedef struct stinfo stinfo;
36
37 struct stinfo {
38 void (*func)(int fd, void *cookie);
39 int fd;
40 void *cookie;
41 };
42
43
44 void *service_bootstrap_func(void *x)
45 {
46 stinfo *sti = x;
47 sti->func(sti->fd, sti->cookie);
48 free(sti);
49 return 0;
50 }
51
52 #if ADB_HOST
53 ADB_MUTEX_DEFINE( dns_lock );
54
55 static void dns_service(int fd, void *cookie)
56 {
57 char *hostname = cookie;
58 struct hostent *hp;
59 unsigned zero = 0;
60
61 adb_mutex_lock(&dns_lock);
62 hp = gethostbyname(hostname);
63 if(hp == 0) {
64 writex(fd, &zero, 4);
65 } else {
66 writex(fd, hp->h_addr, 4);
67 }
68 adb_mutex_unlock(&dns_lock);
69 adb_close(fd);
70 }
71 #else
72 extern int recovery_mode;
73
74 static void recover_service(int s, void *cookie)
75 {
76 unsigned char buf[4096];
77 unsigned count = (unsigned) cookie;
78 int fd;
79
80 fd = adb_creat("/tmp/update", 0644);
81 if(fd < 0) {
82 adb_close(s);
83 return;
84 }
85
86 while(count > 0) {
87 unsigned xfer = (count > 4096) ? 4096 : count;
88 if(readx(s, buf, xfer)) break;
89 if(writex(fd, buf, xfer)) break;
90 count -= xfer;
91 }
92
93 if(count == 0) {
94 writex(s, "OKAY", 4);
95 } else {
96 writex(s, "FAIL", 4);
97 }
98 adb_close(fd);
99 adb_close(s);
100
101 fd = adb_creat("/tmp/update.begin", 0644);
102 adb_close(fd);
103 }
104
105 #endif
106
107 #if 0
108 static void echo_service(int fd, void *cookie)
109 {
110 char buf[4096];
111 int r;
112 char *p;
113 int c;
114
115 for(;;) {
116 r = read(fd, buf, 4096);
117 if(r == 0) goto done;
118 if(r < 0) {
119 if(errno == EINTR) continue;
120 else goto done;
121 }
122
123 c = r;
124 p = buf;
125 while(c > 0) {
126 r = write(fd, p, c);
127 if(r > 0) {
128 c -= r;
129 p += r;
130 continue;
131 }
132 if((r < 0) && (errno == EINTR)) continue;
133 goto done;
134 }
135 }
136 done:
137 close(fd);
138 }
139 #endif
140
141 static int create_service_thread(void (*func)(int, void *), void *cookie)
142 {
143 stinfo *sti;
144 adb_thread_t t;
145 int s[2];
146
147 if(adb_socketpair(s)) {
148 printf("cannot create service socket pair\n");
149 return -1;
150 }
151
152 sti = malloc(sizeof(stinfo));
153 if(sti == 0) fatal("cannot allocate stinfo");
154 sti->func = func;
155 sti->cookie = cookie;
156 sti->fd = s[1];
157
158 if(adb_thread_create( &t, service_bootstrap_func, sti)){
159 free(sti);
160 adb_close(s[0]);
161 adb_close(s[1]);
162 printf("cannot create service thread\n");
163 return -1;
164 }
165
166 D("service thread started, %d:%d\n",s[0], s[1]);
167 return s[0];
168 }
169
170 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
171 {
172 #ifdef HAVE_WIN32_PROC
173 fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
174 return -1;
175 #else /* !HAVE_WIN32_PROC */
176 char *devname;
177 int ptm;
178 pid_t pid;
179
180 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
181 if(ptm < 0){
182 printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
183 return -1;
184 }
185 fcntl(ptm, F_SETFD, FD_CLOEXEC);
186
187 if(grantpt(ptm) || unlockpt(ptm) ||
188 ((devname = (char*) ptsname(ptm)) == 0)){
189 printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
190 return -1;
191 }
192
193 pid = fork();
194 if(pid < 0) {
195 printf("- fork failed: %s -\n", strerror(errno));
196 return -1;
197 }
198
199 if(pid == 0){
200 int pts;
201
202 setsid();
203
204 pts = unix_open(devname, O_RDWR);
205 if(pts < 0) exit(-1);
206
207 dup2(pts, 0);
208 dup2(pts, 1);
209 dup2(pts, 2);
210
211 adb_close(ptm);
212
213 execl(cmd, cmd, arg0, arg1, NULL);
214 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
215 cmd, strerror(errno), errno);
216 exit(-1);
217 } else {
218 return ptm;
219 }
220 #endif /* !HAVE_WIN32_PROC */
221 }
222
223 #if ADB_HOST
224 #define SHELL_COMMAND "/bin/sh"
225 #else
226 #define SHELL_COMMAND "/system/bin/sh"
227 #endif
228
229 int service_to_fd(const char *name)
230 {
231 int ret = -1;
232
233 if(!strncmp(name, "tcp:", 4)) {
234 int port = atoi(name + 4);
235 name = strchr(name + 4, ':');
236 if(name == 0) {
237 ret = socket_loopback_client(port, SOCK_STREAM);
238 if (ret >= 0)
239 disable_tcp_nagle(ret);
240 } else {
241 #if ADB_HOST
242 adb_mutex_lock(&dns_lock);
243 ret = socket_network_client(name + 1, port, SOCK_STREAM);
244 adb_mutex_unlock(&dns_lock);
245 #else
246 return -1;
247 #endif
248 }
249 #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
250 } else if(!strncmp(name, "local:", 6)) {
251 ret = socket_local_client(name + 6,
252 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
253 } else if(!strncmp(name, "localreserved:", 14)) {
254 ret = socket_local_client(name + 14,
255 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
256 } else if(!strncmp(name, "localabstract:", 14)) {
257 ret = socket_local_client(name + 14,
258 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
259 } else if(!strncmp(name, "localfilesystem:", 16)) {
260 ret = socket_local_client(name + 16,
261 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
262 #endif
263 #if ADB_HOST
264 } else if(!strncmp("dns:", name, 4)){
265 char *n = strdup(name + 4);
266 if(n == 0) return -1;
267 ret = create_service_thread(dns_service, n);
268 #else /* !ADB_HOST */
269 } else if(!strncmp("dev:", name, 4)) {
270 ret = unix_open(name + 4, O_RDWR);
271 } else if(!strncmp(name, "framebuffer:", 12)) {
272 ret = create_service_thread(framebuffer_service, 0);
273 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
274 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
275 } else if (!strncmp(name, "jdwp:", 5)) {
276 ret = create_jdwp_connection_fd(atoi(name+5));
277 } else if (!strncmp(name, "log:", 4)) {
278 ret = create_service_thread(log_service, get_log_file_path(name + 4));
279 #endif
280 } else if(!HOST && !strncmp(name, "shell:", 6)) {
281 if(name[6]) {
282 ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
283 } else {
284 ret = create_subprocess(SHELL_COMMAND, "-", 0);
285 }
286 #if !ADB_HOST
287 } else if(!strncmp(name, "sync:", 5)) {
288 ret = create_service_thread(file_sync_service, NULL);
289 } else if(!strncmp(name, "remount:", 8)) {
290 ret = create_service_thread(remount_service, NULL);
291 #endif
292 #if 0
293 } else if(!strncmp(name, "echo:", 5)){
294 ret = create_service_thread(echo_service, 0);
295 #endif
296 }
297 if (ret >= 0) {
298 close_on_exec(ret);
299 }
300 return ret;
301 }
302
303 #if ADB_HOST
304 struct state_info {
305 transport_type transport;
306 char* serial;
307 int state;
308 };
309
310 static void wait_for_state(int fd, void* cookie)
311 {
312 struct state_info* sinfo = cookie;
313 char* err = "unknown error";
314
315 D("wait_for_state %d\n", sinfo->state);
316
317 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
318 if(t != 0) {
319 writex(fd, "OKAY", 4);
320 } else {
321 sendfailmsg(fd, err);
322 }
323
324 if (sinfo->serial)
325 free(sinfo->serial);
326 free(sinfo);
327 adb_close(fd);
328 D("wait_for_state is done\n");
329 }
330 #endif
331
332 #if ADB_HOST
333 asocket* host_service_to_socket(const char* name, const char *serial)
334 {
335 if (!strcmp(name,"track-devices")) {
336 return create_device_tracker();
337 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
338 struct state_info* sinfo = malloc(sizeof(struct state_info));
339
340 if (serial)
341 sinfo->serial = strdup(serial);
342 else
343 sinfo->serial = NULL;
344
345 name += strlen("wait-for-");
346
347 if (!strncmp(name, "local", strlen("local"))) {
348 sinfo->transport = kTransportLocal;
349 sinfo->state = CS_DEVICE;
350 } else if (!strncmp(name, "usb", strlen("usb"))) {
351 sinfo->transport = kTransportUsb;
352 sinfo->state = CS_DEVICE;
353 } else if (!strncmp(name, "any", strlen("any"))) {
354 sinfo->transport = kTransportAny;
355 sinfo->state = CS_DEVICE;
356 } else {
357 free(sinfo);
358 return NULL;
359 }
360
361 int fd = create_service_thread(wait_for_state, sinfo);
362 return create_local_socket(fd);
363 }
364 return NULL;
365 }
366 #endif /* ADB_HOST */
+0
-185
adb/shlist.c less more
0 /*-------------------------------------------------------------------*/
1 /* List Functionality */
2 /*-------------------------------------------------------------------*/
3 /* #define SH_LIST_DEBUG */
4 /*-------------------------------------------------------------------*/
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "shlist.h"
8 /*-------------------------------------------------------------------*/
9 void shListInitList( SHLIST *listPtr )
10 {
11 listPtr->data = (void *)0L;
12 listPtr->next = listPtr;
13 listPtr->prev = listPtr;
14 }
15
16 SHLIST *shListFindItem( SHLIST *head, void *val, shListEqual func )
17 {
18 SHLIST *item;
19
20 for(item=head->next;( item != head );item=item->next)
21 if( func ) {
22 if( func( val, item->data ) ) {
23 return( item );
24 }
25 }
26 else {
27 if( item->data == val ) {
28 return( item );
29 }
30 }
31 return( NULL );
32 }
33
34 SHLIST *shListGetLastItem( SHLIST *head )
35 {
36 if( head->prev != head )
37 return( head->prev );
38 return( NULL );
39 }
40
41 SHLIST *shListGetFirstItem( SHLIST *head )
42 {
43 if( head->next != head )
44 return( head->next );
45 return( NULL );
46 }
47
48 SHLIST *shListGetNItem( SHLIST *head, unsigned long num )
49 {
50 SHLIST *item;
51 unsigned long i;
52
53 for(i=0,item=head->next;( (i < num) && (item != head) );i++,item=item->next);
54 if( item != head )
55 return( item );
56 return( NULL );
57 }
58
59 SHLIST *shListGetNextItem( SHLIST *head, SHLIST *item )
60 {
61 if( item == NULL )
62 return( NULL );
63 if( item->next != head )
64 return( item->next );
65 return( NULL );
66 }
67
68 SHLIST *shListGetPrevItem( SHLIST *head, SHLIST *item )
69 {
70 if( item == NULL )
71 return( NULL );
72 if( item->prev != head )
73 return( item->prev );
74 return( NULL );
75 }
76
77 void shListDelItem( SHLIST *head, SHLIST *item, shListFree func )
78 {
79 if( item == NULL )
80 return;
81 #ifdef SH_LIST_DEBUG
82 fprintf(stderr, "Del %lx\n", (unsigned long)(item->data));
83 #endif
84 (item->prev)->next = item->next;
85 (item->next)->prev = item->prev;
86 if( func && item->data ) {
87 func( (void *)(item->data) );
88 }
89 free( item );
90 head->data = (void *)((unsigned long)(head->data) - 1);
91 }
92
93 void shListInsFirstItem( SHLIST *head, void *val )
94 { /* Insert to the beginning of the list */
95 SHLIST *item;
96
97 item = (SHLIST *)malloc( sizeof(SHLIST) );
98 if( item == NULL )
99 return;
100 item->data = val;
101 item->next = head->next;
102 item->prev = head;
103 (head->next)->prev = item;
104 head->next = item;
105 #ifdef SH_LIST_DEBUG
106 fprintf(stderr, "Ins First %lx\n", (unsigned long)(item->data));
107 #endif
108 head->data = (void *)((unsigned long)(head->data) + 1);
109 }
110
111 void shListInsLastItem( SHLIST *head, void *val )
112 { /* Insert to the end of the list */
113 SHLIST *item;
114
115 item = (SHLIST *)malloc( sizeof(SHLIST) );
116 if( item == NULL )
117 return;
118 item->data = val;
119 item->next = head;
120 item->prev = head->prev;
121 (head->prev)->next = item;
122 head->prev = item;
123 #ifdef SH_LIST_DEBUG
124 fprintf(stderr, "Ins Last %lx\n", (unsigned long)(item->data));
125 #endif
126 head->data = (void *)((unsigned long)(head->data) + 1);
127 }
128
129 void shListInsBeforeItem( SHLIST *head, void *val, void *etal,
130 shListCmp func )
131 {
132 SHLIST *item, *iptr;
133
134 if( func == NULL )
135 shListInsFirstItem( head, val );
136 else {
137 item = (SHLIST *)malloc( sizeof(SHLIST) );
138 if( item == NULL )
139 return;
140 item->data = val;
141 for(iptr=head->next;( iptr != head );iptr=iptr->next)
142 if( func( val, iptr->data, etal ) )
143 break;
144 item->next = iptr;
145 item->prev = iptr->prev;
146 (iptr->prev)->next = item;
147 iptr->prev = item;
148 #ifdef SH_LIST_DEBUG
149 fprintf(stderr, "Ins Before %lx\n", (unsigned long)(item->data));
150 #endif
151 head->data = (void *)((unsigned long)(head->data) + 1);
152 }
153 }
154
155 void shListDelAllItems( SHLIST *head, shListFree func )
156 {
157 SHLIST *item;
158
159 for(item=head->next;( item != head );) {
160 shListDelItem( head, item, func );
161 item = head->next;
162 }
163 head->data = (void *)0L;
164 }
165
166 void shListPrintAllItems( SHLIST *head, shListPrint func )
167 {
168 #ifdef SH_LIST_DEBUG
169 SHLIST *item;
170
171 for(item=head->next;( item != head );item=item->next)
172 if( func ) {
173 func(item->data);
174 }
175 else {
176 fprintf(stderr, "Item: %lx\n",(unsigned long)(item->data));
177 }
178 #endif
179 }
180
181 unsigned long shListGetCount( SHLIST *head )
182 {
183 return( (unsigned long)(head->data) );
184 }
+0
-34
adb/shlist.h less more
0 /*-------------------------------------------------------------------*/
1 /* List Functionality */
2 /*-------------------------------------------------------------------*/
3 #ifndef _SHLIST_H_
4 #define _SHLIST_H_
5
6 typedef struct SHLIST_STRUC {
7 void *data;
8 struct SHLIST_STRUC *next;
9 struct SHLIST_STRUC *prev;
10 } SHLIST;
11
12 typedef int (*shListCmp)( void *valo, void *valn, void *etalon );
13 typedef int (*shListPrint)( void *val );
14 typedef void (*shListFree)( void *val );
15 typedef int (*shListEqual)( void *val, void *idata );
16
17 void shListInitList( SHLIST *listPtr );
18 SHLIST *shListFindItem( SHLIST *head, void *val, shListEqual func );
19 SHLIST *shListGetFirstItem( SHLIST *head );
20 SHLIST *shListGetNItem( SHLIST *head, unsigned long num );
21 SHLIST *shListGetLastItem( SHLIST *head );
22 SHLIST *shListGetNextItem( SHLIST *head, SHLIST *item );
23 SHLIST *shListGetPrevItem( SHLIST *head, SHLIST *item );
24 void shListDelItem( SHLIST *head, SHLIST *item, shListFree func );
25 void shListInsFirstItem( SHLIST *head, void *val );
26 void shListInsBeforeItem( SHLIST *head, void *val, void *etalon,
27 shListCmp func );
28 void shListInsLastItem( SHLIST *head, void *val );
29 void shListDelAllItems( SHLIST *head, shListFree func );
30 void shListPrintAllItems( SHLIST *head, shListPrint func );
31 unsigned long shListGetCount( SHLIST *head );
32
33 #endif
+0
-787
adb/sockets.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <ctype.h>
22
23 #include "sysdeps.h"
24
25 #define TRACE_TAG TRACE_SOCKETS
26 #include "adb.h"
27
28 ADB_MUTEX_DEFINE( socket_list_lock );
29
30 static void local_socket_close_locked(asocket *s);
31
32 int sendfailmsg(int fd, const char *reason)
33 {
34 char buf[9];
35 int len;
36 len = strlen(reason);
37 if(len > 0xffff) len = 0xffff;
38 snprintf(buf, sizeof buf, "FAIL%04x", len);
39 if(writex(fd, buf, 8)) return -1;
40 return writex(fd, reason, len);
41 }
42
43 //extern int online;
44
45 static unsigned local_socket_next_id = 1;
46
47 static asocket local_socket_list = {
48 .next = &local_socket_list,
49 .prev = &local_socket_list,
50 };
51
52 /* the the list of currently closing local sockets.
53 ** these have no peer anymore, but still packets to
54 ** write to their fd.
55 */
56 static asocket local_socket_closing_list = {
57 .next = &local_socket_closing_list,
58 .prev = &local_socket_closing_list,
59 };
60
61 asocket *find_local_socket(unsigned id)
62 {
63 asocket *s;
64 asocket *result = NULL;
65
66 adb_mutex_lock(&socket_list_lock);
67 for(s = local_socket_list.next; s != &local_socket_list && !result; s = s->next) {
68 if(s->id == id) result = s;
69 }
70 adb_mutex_unlock(&socket_list_lock);
71
72 return result;
73 }
74
75 static void
76 insert_local_socket(asocket* s, asocket* list)
77 {
78 s->next = list;
79 s->prev = s->next->prev;
80 s->prev->next = s;
81 s->next->prev = s;
82 }
83
84
85 void install_local_socket(asocket *s)
86 {
87 adb_mutex_lock(&socket_list_lock);
88
89 s->id = local_socket_next_id++;
90 insert_local_socket(s, &local_socket_list);
91
92 adb_mutex_unlock(&socket_list_lock);
93 }
94
95 void remove_socket(asocket *s)
96 {
97 // socket_list_lock should already be held
98 if (s->prev && s->next)
99 {
100 s->prev->next = s->next;
101 s->next->prev = s->prev;
102 s->next = 0;
103 s->prev = 0;
104 s->id = 0;
105 }
106 }
107
108 void close_all_sockets(atransport *t)
109 {
110 asocket *s;
111
112 /* this is a little gross, but since s->close() *will* modify
113 ** the list out from under you, your options are limited.
114 */
115 adb_mutex_lock(&socket_list_lock);
116 restart:
117 for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
118 if(s->transport == t || (s->peer && s->peer->transport == t)) {
119 local_socket_close_locked(s);
120 goto restart;
121 }
122 }
123 adb_mutex_unlock(&socket_list_lock);
124 }
125
126 static int local_socket_enqueue(asocket *s, apacket *p)
127 {
128 D("LS(%d): enqueue %d\n", s->id, p->len);
129
130 p->ptr = p->data;
131
132 /* if there is already data queue'd, we will receive
133 ** events when it's time to write. just add this to
134 ** the tail
135 */
136 if(s->pkt_first) {
137 goto enqueue;
138 }
139
140 /* write as much as we can, until we
141 ** would block or there is an error/eof
142 */
143 while(p->len > 0) {
144 int r = adb_write(s->fd, p->ptr, p->len);
145 if(r > 0) {
146 p->len -= r;
147 p->ptr += r;
148 continue;
149 }
150 if((r == 0) || (errno != EAGAIN)) {
151 D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
152 s->close(s);
153 return 1; /* not ready (error) */
154 } else {
155 break;
156 }
157 }
158
159 if(p->len == 0) {
160 put_apacket(p);
161 return 0; /* ready for more data */
162 }
163
164 enqueue:
165 p->next = 0;
166 if(s->pkt_first) {
167 s->pkt_last->next = p;
168 } else {
169 s->pkt_first = p;
170 }
171 s->pkt_last = p;
172
173 /* make sure we are notified when we can drain the queue */
174 fdevent_add(&s->fde, FDE_WRITE);
175
176 return 1; /* not ready (backlog) */
177 }
178
179 static void local_socket_ready(asocket *s)
180 {
181 /* far side is ready for data, pay attention to
182 readable events */
183 fdevent_add(&s->fde, FDE_READ);
184 // D("LS(%d): ready()\n", s->id);
185 }
186
187 static void local_socket_close(asocket *s)
188 {
189 adb_mutex_lock(&socket_list_lock);
190 local_socket_close_locked(s);
191 adb_mutex_unlock(&socket_list_lock);
192 }
193
194 // be sure to hold the socket list lock when calling this
195 static void local_socket_destroy(asocket *s)
196 {
197 apacket *p, *n;
198
199 /* IMPORTANT: the remove closes the fd
200 ** that belongs to this socket
201 */
202 fdevent_remove(&s->fde);
203
204 /* dispose of any unwritten data */
205 for(p = s->pkt_first; p; p = n) {
206 D("LS(%d): discarding %d bytes\n", s->id, p->len);
207 n = p->next;
208 put_apacket(p);
209 }
210 remove_socket(s);
211 free(s);
212 }
213
214
215 static void local_socket_close_locked(asocket *s)
216 {
217 if(s->peer) {
218 s->peer->peer = 0;
219 // tweak to avoid deadlock
220 if (s->peer->close == local_socket_close)
221 local_socket_close_locked(s->peer);
222 else
223 s->peer->close(s->peer);
224 }
225
226 /* If we are already closing, or if there are no
227 ** pending packets, destroy immediately
228 */
229 if (s->closing || s->pkt_first == NULL) {
230 int id = s->id;
231 local_socket_destroy(s);
232 D("LS(%d): closed\n", id);
233 return;
234 }
235
236 /* otherwise, put on the closing list
237 */
238 D("LS(%d): closing\n", s->id);
239 s->closing = 1;
240 fdevent_del(&s->fde, FDE_READ);
241 remove_socket(s);
242 insert_local_socket(s, &local_socket_closing_list);
243 }
244
245 static void local_socket_event_func(int fd, unsigned ev, void *_s)
246 {
247 asocket *s = _s;
248
249 /* put the FDE_WRITE processing before the FDE_READ
250 ** in order to simplify the code.
251 */
252 if(ev & FDE_WRITE){
253 apacket *p;
254
255 while((p = s->pkt_first) != 0) {
256 while(p->len > 0) {
257 int r = adb_write(fd, p->ptr, p->len);
258 if(r > 0) {
259 p->ptr += r;
260 p->len -= r;
261 continue;
262 }
263 if(r < 0) {
264 /* returning here is ok because FDE_READ will
265 ** be processed in the next iteration loop
266 */
267 if(errno == EAGAIN) return;
268 if(errno == EINTR) continue;
269 }
270 s->close(s);
271 return;
272 }
273
274 if(p->len == 0) {
275 s->pkt_first = p->next;
276 if(s->pkt_first == 0) s->pkt_last = 0;
277 put_apacket(p);
278 }
279 }
280
281 /* if we sent the last packet of a closing socket,
282 ** we can now destroy it.
283 */
284 if (s->closing) {
285 s->close(s);
286 return;
287 }
288
289 /* no more packets queued, so we can ignore
290 ** writable events again and tell our peer
291 ** to resume writing
292 */
293 fdevent_del(&s->fde, FDE_WRITE);
294 s->peer->ready(s->peer);
295 }
296
297
298 if(ev & FDE_READ){
299 apacket *p = get_apacket();
300 unsigned char *x = p->data;
301 size_t avail = MAX_PAYLOAD;
302 int r;
303 int is_eof = 0;
304
305 while(avail > 0) {
306 r = adb_read(fd, x, avail);
307 if(r > 0) {
308 avail -= r;
309 x += r;
310 continue;
311 }
312 if(r < 0) {
313 if(errno == EAGAIN) break;
314 if(errno == EINTR) continue;
315 }
316
317 /* r = 0 or unhandled error */
318 is_eof = 1;
319 break;
320 }
321
322 if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
323 put_apacket(p);
324 } else {
325 p->len = MAX_PAYLOAD - avail;
326
327 r = s->peer->enqueue(s->peer, p);
328
329 if(r < 0) {
330 /* error return means they closed us as a side-effect
331 ** and we must return immediately.
332 **
333 ** note that if we still have buffered packets, the
334 ** socket will be placed on the closing socket list.
335 ** this handler function will be called again
336 ** to process FDE_WRITE events.
337 */
338 return;
339 }
340
341 if(r > 0) {
342 /* if the remote cannot accept further events,
343 ** we disable notification of READs. They'll
344 ** be enabled again when we get a call to ready()
345 */
346 fdevent_del(&s->fde, FDE_READ);
347 }
348 }
349
350 if(is_eof) {
351 s->close(s);
352 }
353 }
354
355 if(ev & FDE_ERROR){
356 /* this should be caught be the next read or write
357 ** catching it here means we may skip the last few
358 ** bytes of readable data.
359 */
360 // s->close(s);
361 return;
362 }
363 }
364
365 asocket *create_local_socket(int fd)
366 {
367 asocket *s = calloc(1, sizeof(asocket));
368 if(s == 0) fatal("cannot allocate socket");
369 install_local_socket(s);
370 s->fd = fd;
371 s->enqueue = local_socket_enqueue;
372 s->ready = local_socket_ready;
373 s->close = local_socket_close;
374
375 fdevent_install(&s->fde, fd, local_socket_event_func, s);
376 /* fdevent_add(&s->fde, FDE_ERROR); */
377 //fprintf(stderr, "Created local socket in create_local_socket \n");
378 D("LS(%d): created (fd=%d)\n", s->id, s->fd);
379 return s;
380 }
381
382 asocket *create_local_service_socket(const char *name)
383 {
384 asocket *s;
385 int fd;
386
387 #if !ADB_HOST
388 if (!strcmp(name,"jdwp")) {
389 return create_jdwp_service_socket();
390 }
391 if (!strcmp(name,"track-jdwp")) {
392 return create_jdwp_tracker_service_socket();
393 }
394 #endif
395 fd = service_to_fd(name);
396 if(fd < 0) return 0;
397
398 s = create_local_socket(fd);
399 D("LS(%d): bound to '%s'\n", s->id, name);
400 return s;
401 }
402
403 #if ADB_HOST
404 static asocket *create_host_service_socket(const char *name, const char* serial)
405 {
406 asocket *s;
407
408 s = host_service_to_socket(name, serial);
409
410 if (s != NULL) {
411 D("LS(%d) bound to '%s'\n", s->id, name);
412 return s;
413 }
414
415 return s;
416 }
417 #endif /* ADB_HOST */
418
419 /* a Remote socket is used to send/receive data to/from a given transport object
420 ** it needs to be closed when the transport is forcibly destroyed by the user
421 */
422 typedef struct aremotesocket {
423 asocket socket;
424 adisconnect disconnect;
425 } aremotesocket;
426
427 static int remote_socket_enqueue(asocket *s, apacket *p)
428 {
429 D("Calling remote_socket_enqueue\n");
430 p->msg.command = A_WRTE;
431 p->msg.arg0 = s->peer->id;
432 p->msg.arg1 = s->id;
433 p->msg.data_length = p->len;
434 send_packet(p, s->transport);
435 return 1;
436 }
437
438 static void remote_socket_ready(asocket *s)
439 {
440 D("Calling remote_socket_ready\n");
441 apacket *p = get_apacket();
442 p->msg.command = A_OKAY;
443 p->msg.arg0 = s->peer->id;
444 p->msg.arg1 = s->id;
445 send_packet(p, s->transport);
446 }
447
448 static void remote_socket_close(asocket *s)
449 {
450 D("Calling remote_socket_close\n");
451 apacket *p = get_apacket();
452 p->msg.command = A_CLSE;
453 if(s->peer) {
454 p->msg.arg0 = s->peer->id;
455 s->peer->peer = 0;
456 s->peer->close(s->peer);
457 }
458 p->msg.arg1 = s->id;
459 send_packet(p, s->transport);
460 D("RS(%d): closed\n", s->id);
461 remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
462 free(s);
463 }
464
465 static void remote_socket_disconnect(void* _s, atransport* t)
466 {
467 asocket* s = _s;
468 asocket* peer = s->peer;
469
470 D("remote_socket_disconnect RS(%d)\n", s->id);
471 if (peer) {
472 peer->peer = NULL;
473 peer->close(peer);
474 }
475 remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
476 free(s);
477 }
478
479 asocket *create_remote_socket(unsigned id, atransport *t)
480 {
481 asocket *s = calloc(1, sizeof(aremotesocket));
482 adisconnect* dis = &((aremotesocket*)s)->disconnect;
483
484 if(s == 0) fatal("cannot allocate socket");
485 s->id = id;
486 s->enqueue = remote_socket_enqueue;
487 s->ready = remote_socket_ready;
488 s->close = remote_socket_close;
489 s->transport = t;
490
491 dis->func = remote_socket_disconnect;
492 dis->opaque = s;
493 add_transport_disconnect( t, dis );
494 D("RS(%d): created\n", s->id);
495 return s;
496 }
497
498 void connect_to_remote(asocket *s, const char *destination)
499 {
500 D("Connect_to_remote call \n");
501 apacket *p = get_apacket();
502 int len = strlen(destination) + 1;
503
504 if(len > (MAX_PAYLOAD-1)) {
505 fatal("destination oversized");
506 }
507
508 D("LS(%d): connect('%s')\n", s->id, destination);
509 p->msg.command = A_OPEN;
510 p->msg.arg0 = s->id;
511 p->msg.data_length = len;
512 strcpy((char*) p->data, destination);
513 send_packet(p, s->transport);
514 }
515
516
517 /* this is used by magic sockets to rig local sockets to
518 send the go-ahead message when they connect */
519 static void local_socket_ready_notify(asocket *s)
520 {
521 s->ready = local_socket_ready;
522 s->close = local_socket_close;
523 adb_write(s->fd, "OKAY", 4);
524 s->ready(s);
525 }
526
527 /* this is used by magic sockets to rig local sockets to
528 send the failure message if they are closed before
529 connected (to avoid closing them without a status message) */
530 static void local_socket_close_notify(asocket *s)
531 {
532 s->ready = local_socket_ready;
533 s->close = local_socket_close;
534 sendfailmsg(s->fd, "closed");
535 s->close(s);
536 }
537
538 unsigned unhex(unsigned char *s, int len)
539 {
540 unsigned n = 0, c;
541
542 while(len-- > 0) {
543 switch((c = *s++)) {
544 case '0': case '1': case '2':
545 case '3': case '4': case '5':
546 case '6': case '7': case '8':
547 case '9':
548 c -= '0';
549 break;
550 case 'a': case 'b': case 'c':
551 case 'd': case 'e': case 'f':
552 c = c - 'a' + 10;
553 break;
554 case 'A': case 'B': case 'C':
555 case 'D': case 'E': case 'F':
556 c = c - 'A' + 10;
557 break;
558 default:
559 return 0xffffffff;
560 }
561
562 n = (n << 4) | c;
563 }
564
565 return n;
566 }
567
568 static int smart_socket_enqueue(asocket *s, apacket *p)
569 {
570 unsigned len;
571 #if ADB_HOST
572 char *service = NULL;
573 char* serial = NULL;
574 transport_type ttype = kTransportAny;
575 #endif
576
577 D("SS(%d): enqueue %d\n", s->id, p->len);
578
579 if(s->pkt_first == 0) {
580 s->pkt_first = p;
581 s->pkt_last = p;
582 } else {
583 if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
584 D("SS(%d): overflow\n", s->id);
585 put_apacket(p);
586 goto fail;
587 }
588
589 memcpy(s->pkt_first->data + s->pkt_first->len,
590 p->data, p->len);
591 s->pkt_first->len += p->len;
592 put_apacket(p);
593
594 p = s->pkt_first;
595 }
596
597 /* don't bother if we can't decode the length */
598 if(p->len < 4) return 0;
599
600 len = unhex(p->data, 4);
601 if((len < 1) || (len > 1024)) {
602 D("SS(%d): bad size (%d)\n", s->id, len);
603 goto fail;
604 }
605
606 D("SS(%d): len is %d\n", s->id, len );
607 /* can't do anything until we have the full header */
608 if((len + 4) > p->len) {
609 D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
610 return 0;
611 }
612
613 p->data[len + 4] = 0;
614
615 D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
616
617 #if ADB_HOST
618 service = (char *)p->data + 4;
619 if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
620 char* serial_end;
621 service += strlen("host-serial:");
622
623 // serial number should follow "host:"
624 serial_end = strchr(service, ':');
625 if (serial_end) {
626 *serial_end = 0; // terminate string
627 serial = service;
628 service = serial_end + 1;
629 }
630 } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
631 ttype = kTransportUsb;
632 service += strlen("host-usb:");
633 } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
634 ttype = kTransportLocal;
635 service += strlen("host-local:");
636 } else if (!strncmp(service, "host:", strlen("host:"))) {
637 ttype = kTransportAny;
638 service += strlen("host:");
639 } else {
640 service = NULL;
641 }
642
643 if (service) {
644 asocket *s2;
645
646 /* some requests are handled immediately -- in that
647 ** case the handle_host_request() routine has sent
648 ** the OKAY or FAIL message and all we have to do
649 ** is clean up.
650 */
651 if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
652 /* XXX fail message? */
653 D( "SS(%d): handled host service '%s'\n", s->id, service );
654 goto fail;
655 }
656 if (!strncmp(service, "transport", strlen("transport"))) {
657 D( "SS(%d): okay transport\n", s->id );
658 p->len = 0;
659 return 0;
660 }
661
662 /* try to find a local service with this name.
663 ** if no such service exists, we'll fail out
664 ** and tear down here.
665 */
666 s2 = create_host_service_socket(service, serial);
667 if(s2 == 0) {
668 D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
669 sendfailmsg(s->peer->fd, "unknown host service");
670 goto fail;
671 }
672
673 /* we've connected to a local host service,
674 ** so we make our peer back into a regular
675 ** local socket and bind it to the new local
676 ** service socket, acknowledge the successful
677 ** connection, and close this smart socket now
678 ** that its work is done.
679 */
680 adb_write(s->peer->fd, "OKAY", 4);
681
682 s->peer->ready = local_socket_ready;
683 s->peer->close = local_socket_close;
684 s->peer->peer = s2;
685 s2->peer = s->peer;
686 s->peer = 0;
687 D( "SS(%d): okay\n", s->id );
688 s->close(s);
689
690 /* initial state is "ready" */
691 s2->ready(s2);
692 return 0;
693 }
694 #else /* !ADB_HOST */
695 if (s->transport == NULL) {
696 char* error_string = "unknown failure";
697 s->transport = acquire_one_transport (CS_ANY,
698 kTransportAny, NULL, &error_string);
699
700 if (s->transport == NULL) {
701 sendfailmsg(s->peer->fd, error_string);
702 goto fail;
703 }
704 }
705 #endif
706
707 if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
708 /* if there's no remote we fail the connection
709 ** right here and terminate it
710 */
711 sendfailmsg(s->peer->fd, "device offline (x)");
712 goto fail;
713 }
714
715
716 /* instrument our peer to pass the success or fail
717 ** message back once it connects or closes, then
718 ** detach from it, request the connection, and
719 ** tear down
720 */
721 s->peer->ready = local_socket_ready_notify;
722 s->peer->close = local_socket_close_notify;
723 s->peer->peer = 0;
724 /* give him our transport and upref it */
725 s->peer->transport = s->transport;
726
727 connect_to_remote(s->peer, (char*) (p->data + 4));
728 s->peer = 0;
729 s->close(s);
730 return 1;
731
732 fail:
733 /* we're going to close our peer as a side-effect, so
734 ** return -1 to signal that state to the local socket
735 ** who is enqueueing against us
736 */
737 s->close(s);
738 return -1;
739 }
740
741 static void smart_socket_ready(asocket *s)
742 {
743 D("SS(%d): ready\n", s->id);
744 }
745
746 static void smart_socket_close(asocket *s)
747 {
748 D("SS(%d): closed\n", s->id);
749 if(s->pkt_first){
750 put_apacket(s->pkt_first);
751 }
752 if(s->peer) {
753 s->peer->peer = 0;
754 s->peer->close(s->peer);
755 }
756 free(s);
757 }
758
759 asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
760 {
761 D("Creating smart socket \n");
762 asocket *s = calloc(1, sizeof(asocket));
763 if(s == 0) fatal("cannot allocate socket");
764 s->id = 0;
765 s->enqueue = smart_socket_enqueue;
766 s->ready = smart_socket_ready;
767 s->close = smart_socket_close;
768 s->extra = action_cb;
769
770 D("SS(%d): created %p\n", s->id, action_cb);
771 return s;
772 }
773
774 void smart_socket_action(asocket *s, const char *act)
775 {
776
777 }
778
779 void connect_to_smartsocket(asocket *s)
780 {
781 D("Connecting to smart socket \n");
782 asocket *ss = create_smart_socket(smart_socket_action);
783 s->peer = ss;
784 ss->peer = s;
785 s->ready(s);
786 }
adb/sockets.dia less more
Binary diff not shown
+0
-473
adb/sysdeps.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* this file contains system-dependent definitions used by ADB
17 * they're related to threads, sockets and file descriptors
18 */
19 #ifndef _ADB_SYSDEPS_H
20 #define _ADB_SYSDEPS_H
21
22 #ifdef __CYGWIN__
23 # undef _WIN32
24 #endif
25
26 #ifdef _WIN32
27
28 #include <windows.h>
29 #include <winsock2.h>
30 #include <ws2tcpip.h>
31 #include <process.h>
32 #include <fcntl.h>
33 #include <io.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 #include <ctype.h>
37
38 #define OS_PATH_SEPARATOR '\\'
39 #define OS_PATH_SEPARATOR_STR "\\"
40
41 typedef CRITICAL_SECTION adb_mutex_t;
42
43 #define ADB_MUTEX_DEFINE(x) adb_mutex_t x
44
45 /* declare all mutexes */
46 #define ADB_MUTEX(x) extern adb_mutex_t x;
47 #include "mutex_list.h"
48
49 extern void adb_sysdeps_init(void);
50
51 static __inline__ void adb_mutex_lock( adb_mutex_t* lock )
52 {
53 EnterCriticalSection( lock );
54 }
55
56 static __inline__ void adb_mutex_unlock( adb_mutex_t* lock )
57 {
58 LeaveCriticalSection( lock );
59 }
60
61 typedef struct { unsigned tid; } adb_thread_t;
62
63 typedef void* (*adb_thread_func_t)(void* arg);
64
65 typedef void (*win_thread_func_t)(void* arg);
66
67 static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg)
68 {
69 thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
70 if (thread->tid == (unsigned)-1L) {
71 return -1;
72 }
73 return 0;
74 }
75
76 static __inline__ void close_on_exec(int fd)
77 {
78 /* nothing really */
79 }
80
81 extern void disable_tcp_nagle(int fd);
82
83 #define lstat stat /* no symlinks on Win32 */
84
85 #define S_ISLNK(m) 0 /* no symlinks on Win32 */
86
87 static __inline__ int adb_unlink(const char* path)
88 {
89 int rc = unlink(path);
90
91 if (rc == -1 && errno == EACCES) {
92 /* unlink returns EACCES when the file is read-only, so we first */
93 /* try to make it writable, then unlink again... */
94 rc = chmod(path, _S_IREAD|_S_IWRITE );
95 if (rc == 0)
96 rc = unlink(path);
97 }
98 return rc;
99 }
100 #undef unlink
101 #define unlink ___xxx_unlink
102
103 static __inline__ int adb_mkdir(const char* path, int mode)
104 {
105 return _mkdir(path);
106 }
107 #undef mkdir
108 #define mkdir ___xxx_mkdir
109
110 extern int adb_open(const char* path, int options);
111 extern int adb_creat(const char* path, int mode);
112 extern int adb_read(int fd, void* buf, int len);
113 extern int adb_write(int fd, const void* buf, int len);
114 extern int adb_lseek(int fd, int pos, int where);
115 extern int adb_close(int fd);
116
117 static __inline__ int unix_close(int fd)
118 {
119 return close(fd);
120 }
121 #undef close
122 #define close ____xxx_close
123
124 static __inline__ int unix_read(int fd, void* buf, size_t len)
125 {
126 return read(fd, buf, len);
127 }
128 #undef read
129 #define read ___xxx_read
130
131 static __inline__ int unix_write(int fd, const void* buf, size_t len)
132 {
133 return write(fd, buf, len);
134 }
135 #undef write
136 #define write ___xxx_write
137
138 static __inline__ int adb_open_mode(const char* path, int options, int mode)
139 {
140 return adb_open(path, options);
141 }
142
143 static __inline__ int unix_open(const char* path, int options,...)
144 {
145 if ((options & O_CREAT) == 0)
146 {
147 return open(path, options);
148 }
149 else
150 {
151 int mode;
152 va_list args;
153 va_start( args, options );
154 mode = va_arg( args, int );
155 va_end( args );
156 return open(path, options, mode);
157 }
158 }
159 #define open ___xxx_unix_open
160
161
162 /* normally provided by <cutils/misc.h> */
163 extern void* load_file(const char* pathname, unsigned* psize);
164
165 /* normally provided by <cutils/sockets.h> */
166 extern int socket_loopback_client(int port, int type);
167 extern int socket_network_client(const char *host, int port, int type);
168 extern int socket_loopback_server(int port, int type);
169 extern int socket_inaddr_any_server(int port, int type);
170
171 /* normally provided by <cutils/fdevent.h> */
172
173 #define FDE_READ 0x0001
174 #define FDE_WRITE 0x0002
175 #define FDE_ERROR 0x0004
176 #define FDE_DONT_CLOSE 0x0080
177
178 typedef struct fdevent fdevent;
179
180 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
181
182 fdevent *fdevent_create(int fd, fd_func func, void *arg);
183 void fdevent_destroy(fdevent *fde);
184 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
185 void fdevent_remove(fdevent *item);
186 void fdevent_set(fdevent *fde, unsigned events);
187 void fdevent_add(fdevent *fde, unsigned events);
188 void fdevent_del(fdevent *fde, unsigned events);
189 void fdevent_loop();
190
191 struct fdevent {
192 fdevent *next;
193 fdevent *prev;
194
195 int fd;
196 unsigned short state;
197 unsigned short events;
198
199 fd_func func;
200 void *arg;
201 };
202
203 static __inline__ void adb_sleep_ms( int mseconds )
204 {
205 Sleep( mseconds );
206 }
207
208 extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
209
210 #undef accept
211 #define accept ___xxx_accept
212
213 static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
214 {
215 int opt = bufsize;
216 return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
217 }
218
219 extern int adb_socketpair( int sv[2] );
220
221 static __inline__ char* adb_dirstart( const char* path )
222 {
223 char* p = strchr(path, '/');
224 char* p2 = strchr(path, '\\');
225
226 if ( !p )
227 p = p2;
228 else if ( p2 && p2 > p )
229 p = p2;
230
231 return p;
232 }
233
234 static __inline__ char* adb_dirstop( const char* path )
235 {
236 char* p = strrchr(path, '/');
237 char* p2 = strrchr(path, '\\');
238
239 if ( !p )
240 p = p2;
241 else if ( p2 && p2 > p )
242 p = p2;
243
244 return p;
245 }
246
247 static __inline__ int adb_is_absolute_host_path( const char* path )
248 {
249 return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
250 }
251
252 #else /* !_WIN32 a.k.a. Unix */
253
254 #include <cutils/fdevent.h>
255 #include <cutils/sockets.h>
256 #include <cutils/properties.h>
257 #include <cutils/misc.h>
258 #include <signal.h>
259 #include <sys/wait.h>
260 #include <sys/stat.h>
261 #include <fcntl.h>
262
263 #include <pthread.h>
264 #include <unistd.h>
265 #include <fcntl.h>
266 #include <stdarg.h>
267 #include <netinet/in.h>
268 #include <netinet/tcp.h>
269 #include <string.h>
270
271 #define OS_PATH_SEPARATOR '/'
272 #define OS_PATH_SEPARATOR_STR "/"
273
274 typedef pthread_mutex_t adb_mutex_t;
275 #define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
276 #define adb_mutex_init pthread_mutex_init
277 #define adb_mutex_lock pthread_mutex_lock
278 #define adb_mutex_unlock pthread_mutex_unlock
279 #define adb_mutex_destroy pthread_mutex_destroy
280
281 #define ADB_MUTEX_DEFINE(m) static adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER
282
283 #define adb_cond_t pthread_cond_t
284 #define adb_cond_init pthread_cond_init
285 #define adb_cond_wait pthread_cond_wait
286 #define adb_cond_broadcast pthread_cond_broadcast
287 #define adb_cond_signal pthread_cond_signal
288 #define adb_cond_destroy pthread_cond_destroy
289
290 static __inline__ void close_on_exec(int fd)
291 {
292 fcntl( fd, F_SETFD, FD_CLOEXEC );
293 }
294
295 static __inline__ int unix_open(const char* path, int options,...)
296 {
297 if ((options & O_CREAT) == 0)
298 {
299 return open(path, options);
300 }
301 else
302 {
303 int mode;
304 va_list args;
305 va_start( args, options );
306 mode = va_arg( args, int );
307 va_end( args );
308 return open(path, options, mode);
309 }
310 }
311
312 static __inline__ int adb_open_mode( const char* pathname, int options, int mode )
313 {
314 return open( pathname, options, mode );
315 }
316
317
318 static __inline__ int adb_open( const char* pathname, int options )
319 {
320 int fd = open( pathname, options );
321 if (fd < 0)
322 return -1;
323 close_on_exec( fd );
324 return fd;
325 }
326 #undef open
327 #define open ___xxx_open
328
329 static __inline__ int adb_close(int fd)
330 {
331 return close(fd);
332 }
333 #undef close
334 #define close ____xxx_close
335
336
337 static __inline__ int adb_read(int fd, void* buf, size_t len)
338 {
339 return read(fd, buf, len);
340 }
341
342 #undef read
343 #define read ___xxx_read
344
345 static __inline__ int adb_write(int fd, const void* buf, size_t len)
346 {
347 return write(fd, buf, len);
348 }
349 #undef write
350 #define write ___xxx_write
351
352 static __inline__ int adb_lseek(int fd, int pos, int where)
353 {
354 return lseek(fd, pos, where);
355 }
356 #undef lseek
357 #define lseek ___xxx_lseek
358
359 static __inline__ int adb_unlink(const char* path)
360 {
361 return unlink(path);
362 }
363 #undef unlink
364 #define unlink ___xxx_unlink
365
366 static __inline__ int adb_creat(const char* path, int mode)
367 {
368 int fd = creat(path, mode);
369
370 if ( fd < 0 )
371 return -1;
372
373 close_on_exec(fd);
374 return fd;
375 }
376 #undef creat
377 #define creat ___xxx_creat
378
379 static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
380 {
381 return accept( serverfd, addr, addrlen );
382 }
383
384 #undef accept
385 #define accept ___xxx_accept
386
387 #define unix_read adb_read
388 #define unix_write adb_write
389 #define unix_close adb_close
390
391 typedef pthread_t adb_thread_t;
392
393 typedef void* (*adb_thread_func_t)( void* arg );
394
395 static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg )
396 {
397 pthread_attr_t attr;
398
399 pthread_attr_init (&attr);
400 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
401
402 return pthread_create( pthread, &attr, start, arg );
403 }
404
405 static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
406 {
407 int opt = bufsize;
408 return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
409 }
410
411 static __inline__ void disable_tcp_nagle(int fd)
412 {
413 int on = 1;
414 setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
415 }
416
417
418 static __inline__ int unix_socketpair( int d, int type, int protocol, int sv[2] )
419 {
420 return socketpair( d, type, protocol, sv );
421 }
422
423 static __inline__ int adb_socketpair( int sv[2] )
424 {
425 int rc;
426
427 rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
428 if (rc < 0)
429 return -1;
430
431 close_on_exec( sv[0] );
432 close_on_exec( sv[1] );
433 return 0;
434 }
435
436 #undef socketpair
437 #define socketpair ___xxx_socketpair
438
439 static __inline__ void adb_sleep_ms( int mseconds )
440 {
441 usleep( mseconds*1000 );
442 }
443
444 static __inline__ int adb_mkdir(const char* path, int mode)
445 {
446 return mkdir(path, mode);
447 }
448 #undef mkdir
449 #define mkdir ___xxx_mkdir
450
451 static __inline__ void adb_sysdeps_init(void)
452 {
453 }
454
455 static __inline__ char* adb_dirstart(const char* path)
456 {
457 return strchr(path, '/');
458 }
459
460 static __inline__ char* adb_dirstop(const char* path)
461 {
462 return strrchr(path, '/');
463 }
464
465 static __inline__ int adb_is_absolute_host_path( const char* path )
466 {
467 return path[0] == '/';
468 }
469
470 #endif /* !_WIN32 */
471
472 #endif /* _ADB_SYSDEPS_H */
+0
-1953
adb/sysdeps_win32.c less more
0 #include "sysdeps.h"
1 #include <windows.h>
2 #include <winsock2.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #define TRACE_TAG TRACE_SYSDEPS
6 #include "adb.h"
7
8 extern void fatal(const char *fmt, ...);
9
10 #define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /***** *****/
15 /***** replaces libs/cutils/load_file.c *****/
16 /***** *****/
17 /**************************************************************************/
18 /**************************************************************************/
19
20 void *load_file(const char *fn, unsigned *_sz)
21 {
22 HANDLE file;
23 char *data;
24 DWORD file_size;
25
26 file = CreateFile( fn,
27 GENERIC_READ,
28 FILE_SHARE_READ,
29 NULL,
30 OPEN_EXISTING,
31 0,
32 NULL );
33
34 if (file == INVALID_HANDLE_VALUE)
35 return NULL;
36
37 file_size = GetFileSize( file, NULL );
38 data = NULL;
39
40 if (file_size > 0) {
41 data = (char*) malloc( file_size + 1 );
42 if (data == NULL) {
43 D("load_file: could not allocate %ld bytes\n", file_size );
44 file_size = 0;
45 } else {
46 DWORD out_bytes;
47
48 if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
49 out_bytes != file_size )
50 {
51 D("load_file: could not read %ld bytes from '%s'\n", file_size, fn);
52 free(data);
53 data = NULL;
54 file_size = 0;
55 }
56 }
57 }
58 CloseHandle( file );
59
60 *_sz = (unsigned) file_size;
61 return data;
62 }
63
64 /**************************************************************************/
65 /**************************************************************************/
66 /***** *****/
67 /***** common file descriptor handling *****/
68 /***** *****/
69 /**************************************************************************/
70 /**************************************************************************/
71
72 typedef const struct FHClassRec_* FHClass;
73
74 typedef struct FHRec_* FH;
75
76 typedef struct EventHookRec_* EventHook;
77
78 typedef struct FHClassRec_
79 {
80 void (*_fh_init) ( FH f );
81 int (*_fh_close)( FH f );
82 int (*_fh_lseek)( FH f, int pos, int origin );
83 int (*_fh_read) ( FH f, void* buf, int len );
84 int (*_fh_write)( FH f, const void* buf, int len );
85 void (*_fh_hook) ( FH f, int events, EventHook hook );
86
87 } FHClassRec;
88
89 /* used to emulate unix-domain socket pairs */
90 typedef struct SocketPairRec_* SocketPair;
91
92 typedef struct FHRec_
93 {
94 FHClass clazz;
95 int used;
96 int eof;
97 union {
98 HANDLE handle;
99 SOCKET socket;
100 SocketPair pair;
101 } u;
102
103 HANDLE event;
104 int mask;
105
106 char name[32];
107
108 } FHRec;
109
110 #define fh_handle u.handle
111 #define fh_socket u.socket
112 #define fh_pair u.pair
113
114 #define WIN32_FH_BASE 100
115
116 #define WIN32_MAX_FHS 128
117
118 static adb_mutex_t _win32_lock;
119 static FHRec _win32_fhs[ WIN32_MAX_FHS ];
120 static int _win32_fh_count;
121
122 static FH
123 _fh_from_int( int fd )
124 {
125 FH f;
126
127 fd -= WIN32_FH_BASE;
128
129 if (fd < 0 || fd >= _win32_fh_count) {
130 D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
131 errno = EBADF;
132 return NULL;
133 }
134
135 f = &_win32_fhs[fd];
136
137 if (f->used == 0) {
138 D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
139 errno = EBADF;
140 return NULL;
141 }
142
143 return f;
144 }
145
146
147 static int
148 _fh_to_int( FH f )
149 {
150 if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
151 return (int)(f - _win32_fhs) + WIN32_FH_BASE;
152
153 return -1;
154 }
155
156 static FH
157 _fh_alloc( FHClass clazz )
158 {
159 int nn;
160 FH f = NULL;
161
162 adb_mutex_lock( &_win32_lock );
163
164 if (_win32_fh_count < WIN32_MAX_FHS) {
165 f = &_win32_fhs[ _win32_fh_count++ ];
166 goto Exit;
167 }
168
169 for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
170 if ( _win32_fhs[nn].clazz == NULL) {
171 f = &_win32_fhs[nn];
172 goto Exit;
173 }
174 }
175 D( "_fh_alloc: no more free file descriptors\n" );
176 Exit:
177 if (f) {
178 f->clazz = clazz;
179 f->used = 1;
180 f->eof = 0;
181 clazz->_fh_init(f);
182 }
183 adb_mutex_unlock( &_win32_lock );
184 return f;
185 }
186
187
188 static int
189 _fh_close( FH f )
190 {
191 if ( f->used ) {
192 f->clazz->_fh_close( f );
193 f->used = 0;
194 f->eof = 0;
195 f->clazz = NULL;
196 }
197 return 0;
198 }
199
200 /* forward definitions */
201 static const FHClassRec _fh_file_class;
202 static const FHClassRec _fh_socket_class;
203
204 /**************************************************************************/
205 /**************************************************************************/
206 /***** *****/
207 /***** file-based descriptor handling *****/
208 /***** *****/
209 /**************************************************************************/
210 /**************************************************************************/
211
212 static void
213 _fh_file_init( FH f )
214 {
215 f->fh_handle = INVALID_HANDLE_VALUE;
216 }
217
218 static int
219 _fh_file_close( FH f )
220 {
221 CloseHandle( f->fh_handle );
222 f->fh_handle = INVALID_HANDLE_VALUE;
223 return 0;
224 }
225
226 static int
227 _fh_file_read( FH f, void* buf, int len )
228 {
229 DWORD read_bytes;
230
231 if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
232 D( "adb_read: could not read %d bytes from %s\n", len, f->name );
233 errno = EIO;
234 return -1;
235 } else if (read_bytes < (DWORD)len) {
236 f->eof = 1;
237 }
238 return (int)read_bytes;
239 }
240
241 static int
242 _fh_file_write( FH f, const void* buf, int len )
243 {
244 DWORD wrote_bytes;
245
246 if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
247 D( "adb_file_write: could not write %d bytes from %s\n", len, f->name );
248 errno = EIO;
249 return -1;
250 } else if (wrote_bytes < (DWORD)len) {
251 f->eof = 1;
252 }
253 return (int)wrote_bytes;
254 }
255
256 static int
257 _fh_file_lseek( FH f, int pos, int origin )
258 {
259 DWORD method;
260 DWORD result;
261
262 switch (origin)
263 {
264 case SEEK_SET: method = FILE_BEGIN; break;
265 case SEEK_CUR: method = FILE_CURRENT; break;
266 case SEEK_END: method = FILE_END; break;
267 default:
268 errno = EINVAL;
269 return -1;
270 }
271
272 result = SetFilePointer( f->fh_handle, pos, NULL, method );
273 if (result == INVALID_SET_FILE_POINTER) {
274 errno = EIO;
275 return -1;
276 } else {
277 f->eof = 0;
278 }
279 return (int)result;
280 }
281
282 static void _fh_file_hook( FH f, int event, EventHook eventhook ); /* forward */
283
284 static const FHClassRec _fh_file_class =
285 {
286 _fh_file_init,
287 _fh_file_close,
288 _fh_file_lseek,
289 _fh_file_read,
290 _fh_file_write,
291 _fh_file_hook
292 };
293
294 /**************************************************************************/
295 /**************************************************************************/
296 /***** *****/
297 /***** file-based descriptor handling *****/
298 /***** *****/
299 /**************************************************************************/
300 /**************************************************************************/
301
302 int adb_open(const char* path, int options)
303 {
304 FH f;
305
306 DWORD desiredAccess = 0;
307 DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
308
309 switch (options) {
310 case O_RDONLY:
311 desiredAccess = GENERIC_READ;
312 break;
313 case O_WRONLY:
314 desiredAccess = GENERIC_WRITE;
315 break;
316 case O_RDWR:
317 desiredAccess = GENERIC_READ | GENERIC_WRITE;
318 break;
319 default:
320 D("adb_open: invalid options (0x%0x)\n", options);
321 errno = EINVAL;
322 return -1;
323 }
324
325 f = _fh_alloc( &_fh_file_class );
326 if ( !f ) {
327 errno = ENOMEM;
328 return -1;
329 }
330
331 f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
332 0, NULL );
333
334 if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
335 _fh_close(f);
336 D( "adb_open: could not open '%s':", path );
337 switch (GetLastError()) {
338 case ERROR_FILE_NOT_FOUND:
339 D( "file not found\n" );
340 errno = ENOENT;
341 return -1;
342
343 case ERROR_PATH_NOT_FOUND:
344 D( "path not found\n" );
345 errno = ENOTDIR;
346 return -1;
347
348 default:
349 D( "unknown error\n" );
350 errno = ENOENT;
351 return -1;
352 }
353 }
354
355 snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
356 D( "adb_open: '%s' => fd %d\n", path, _fh_to_int(f) );
357 return _fh_to_int(f);
358 }
359
360 /* ignore mode on Win32 */
361 int adb_creat(const char* path, int mode)
362 {
363 FH f;
364
365 f = _fh_alloc( &_fh_file_class );
366 if ( !f ) {
367 errno = ENOMEM;
368 return -1;
369 }
370
371 f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
372 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
373 NULL );
374
375 if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
376 _fh_close(f);
377 D( "adb_creat: could not open '%s':", path );
378 switch (GetLastError()) {
379 case ERROR_FILE_NOT_FOUND:
380 D( "file not found\n" );
381 errno = ENOENT;
382 return -1;
383
384 case ERROR_PATH_NOT_FOUND:
385 D( "path not found\n" );
386 errno = ENOTDIR;
387 return -1;
388
389 default:
390 D( "unknown error\n" );
391 errno = ENOENT;
392 return -1;
393 }
394 }
395 snprintf( f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path );
396 D( "adb_creat: '%s' => fd %d\n", path, _fh_to_int(f) );
397 return _fh_to_int(f);
398 }
399
400
401 int adb_read(int fd, void* buf, int len)
402 {
403 FH f = _fh_from_int(fd);
404
405 if (f == NULL) {
406 return -1;
407 }
408
409 return f->clazz->_fh_read( f, buf, len );
410 }
411
412
413 int adb_write(int fd, const void* buf, int len)
414 {
415 FH f = _fh_from_int(fd);
416
417 if (f == NULL) {
418 return -1;
419 }
420
421 return f->clazz->_fh_write(f, buf, len);
422 }
423
424
425 int adb_lseek(int fd, int pos, int where)
426 {
427 FH f = _fh_from_int(fd);
428
429 if (!f) {
430 return -1;
431 }
432
433 return f->clazz->_fh_lseek(f, pos, where);
434 }
435
436
437 int adb_close(int fd)
438 {
439 FH f = _fh_from_int(fd);
440
441 if (!f) {
442 return -1;
443 }
444
445 D( "adb_close: %s\n", f->name);
446 _fh_close(f);
447 return 0;
448 }
449
450 /**************************************************************************/
451 /**************************************************************************/
452 /***** *****/
453 /***** socket-based file descriptors *****/
454 /***** *****/
455 /**************************************************************************/
456 /**************************************************************************/
457
458 static void
459 _socket_set_errno( void )
460 {
461 switch (WSAGetLastError()) {
462 case 0: errno = 0; break;
463 case WSAEWOULDBLOCK: errno = EAGAIN; break;
464 case WSAEINTR: errno = EINTR; break;
465 default:
466 D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
467 errno = EINVAL;
468 }
469 }
470
471 static void
472 _fh_socket_init( FH f )
473 {
474 f->fh_socket = INVALID_SOCKET;
475 f->event = WSACreateEvent();
476 f->mask = 0;
477 }
478
479 static int
480 _fh_socket_close( FH f )
481 {
482 /* gently tell any peer that we're closing the socket */
483 shutdown( f->fh_socket, SD_BOTH );
484 closesocket( f->fh_socket );
485 f->fh_socket = INVALID_SOCKET;
486 CloseHandle( f->event );
487 f->mask = 0;
488 return 0;
489 }
490
491 static int
492 _fh_socket_lseek( FH f, int pos, int origin )
493 {
494 errno = EPIPE;
495 return -1;
496 }
497
498 static int
499 _fh_socket_read( FH f, void* buf, int len )
500 {
501 int result = recv( f->fh_socket, buf, len, 0 );
502 if (result == SOCKET_ERROR) {
503 _socket_set_errno();
504 result = -1;
505 }
506 return result;
507 }
508
509 static int
510 _fh_socket_write( FH f, const void* buf, int len )
511 {
512 int result = send( f->fh_socket, buf, len, 0 );
513 if (result == SOCKET_ERROR) {
514 _socket_set_errno();
515 result = -1;
516 }
517 return result;
518 }
519
520 static void _fh_socket_hook( FH f, int event, EventHook hook ); /* forward */
521
522 static const FHClassRec _fh_socket_class =
523 {
524 _fh_socket_init,
525 _fh_socket_close,
526 _fh_socket_lseek,
527 _fh_socket_read,
528 _fh_socket_write,
529 _fh_socket_hook
530 };
531
532 /**************************************************************************/
533 /**************************************************************************/
534 /***** *****/
535 /***** replacement for libs/cutils/socket_xxxx.c *****/
536 /***** *****/
537 /**************************************************************************/
538 /**************************************************************************/
539
540 #include <winsock2.h>
541
542 static int _winsock_init;
543
544 static void
545 _cleanup_winsock( void )
546 {
547 WSACleanup();
548 }
549
550 static void
551 _init_winsock( void )
552 {
553 if (!_winsock_init) {
554 WSADATA wsaData;
555 int rc = WSAStartup( MAKEWORD(2,2), &wsaData);
556 if (rc != 0) {
557 fatal( "adb: could not initialize Winsock\n" );
558 }
559 atexit( _cleanup_winsock );
560 _winsock_init = 1;
561 }
562 }
563
564 int socket_loopback_client(int port, int type)
565 {
566 FH f = _fh_alloc( &_fh_socket_class );
567 struct sockaddr_in addr;
568 SOCKET s;
569
570 if (!f)
571 return -1;
572
573 if (!_winsock_init)
574 _init_winsock();
575
576 memset(&addr, 0, sizeof(addr));
577 addr.sin_family = AF_INET;
578 addr.sin_port = htons(port);
579 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
580
581 s = socket(AF_INET, type, 0);
582 if(s == INVALID_SOCKET) {
583 D("socket_loopback_client: could not create socket\n" );
584 _fh_close(f);
585 return -1;
586 }
587
588 f->fh_socket = s;
589 if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
590 D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
591 _fh_close(f);
592 return -1;
593 }
594 snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
595 D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
596 return _fh_to_int(f);
597 }
598
599 #define LISTEN_BACKLOG 4
600
601 int socket_loopback_server(int port, int type)
602 {
603 FH f = _fh_alloc( &_fh_socket_class );
604 struct sockaddr_in addr;
605 SOCKET s;
606 int n;
607
608 if (!f) {
609 return -1;
610 }
611
612 if (!_winsock_init)
613 _init_winsock();
614
615 memset(&addr, 0, sizeof(addr));
616 addr.sin_family = AF_INET;
617 addr.sin_port = htons(port);
618 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
619
620 s = socket(AF_INET, type, 0);
621 if(s == INVALID_SOCKET) return -1;
622
623 f->fh_socket = s;
624
625 n = 1;
626 setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
627
628 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
629 _fh_close(f);
630 return -1;
631 }
632 if (type == SOCK_STREAM) {
633 int ret;
634
635 ret = listen(s, LISTEN_BACKLOG);
636 if (ret < 0) {
637 _fh_close(f);
638 return -1;
639 }
640 }
641 snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
642 D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
643 return _fh_to_int(f);
644 }
645
646
647 int socket_network_client(const char *host, int port, int type)
648 {
649 FH f = _fh_alloc( &_fh_socket_class );
650 struct hostent *hp;
651 struct sockaddr_in addr;
652 SOCKET s;
653
654 if (!f)
655 return -1;
656
657 if (!_winsock_init)
658 _init_winsock();
659
660 hp = gethostbyname(host);
661 if(hp == 0) {
662 _fh_close(f);
663 return -1;
664 }
665
666 memset(&addr, 0, sizeof(addr));
667 addr.sin_family = hp->h_addrtype;
668 addr.sin_port = htons(port);
669 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
670
671 s = socket(hp->h_addrtype, type, 0);
672 if(s == INVALID_SOCKET) {
673 _fh_close(f);
674 return -1;
675 }
676 f->fh_socket = s;
677
678 if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
679 _fh_close(f);
680 return -1;
681 }
682
683 snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
684 D( "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
685 return _fh_to_int(f);
686 }
687
688
689 int socket_inaddr_any_server(int port, int type)
690 {
691 FH f = _fh_alloc( &_fh_socket_class );
692 struct sockaddr_in addr;
693 SOCKET s;
694 int n;
695
696 if (!f)
697 return -1;
698
699 if (!_winsock_init)
700 _init_winsock();
701
702 memset(&addr, 0, sizeof(addr));
703 addr.sin_family = AF_INET;
704 addr.sin_port = htons(port);
705 addr.sin_addr.s_addr = htonl(INADDR_ANY);
706
707 s = socket(AF_INET, type, 0);
708 if(s == INVALID_SOCKET) {
709 _fh_close(f);
710 return -1;
711 }
712
713 f->fh_socket = s;
714 n = 1;
715 setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
716
717 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
718 _fh_close(f);
719 return -1;
720 }
721
722 if (type == SOCK_STREAM) {
723 int ret;
724
725 ret = listen(s, LISTEN_BACKLOG);
726 if (ret < 0) {
727 _fh_close(f);
728 return -1;
729 }
730 }
731 snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
732 D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
733 return _fh_to_int(f);
734 }
735
736 #undef accept
737 int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
738 {
739 FH serverfh = _fh_from_int(serverfd);
740 FH fh;
741
742 if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
743 D( "adb_socket_accept: invalid fd %d\n", serverfd );
744 return -1;
745 }
746
747 fh = _fh_alloc( &_fh_socket_class );
748 if (!fh) {
749 D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
750 return -1;
751 }
752
753 fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
754 if (fh->fh_socket == INVALID_SOCKET) {
755 _fh_close( fh );
756 D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
757 return -1;
758 }
759
760 snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
761 D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
762 return _fh_to_int(fh);
763 }
764
765
766 void disable_tcp_nagle(int fd)
767 {
768 FH fh = _fh_from_int(fd);
769 int on;
770
771 if ( !fh || fh->clazz != &_fh_socket_class )
772 return;
773
774 setsockopt( fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on) );
775 }
776
777 /**************************************************************************/
778 /**************************************************************************/
779 /***** *****/
780 /***** emulated socketpairs *****/
781 /***** *****/
782 /**************************************************************************/
783 /**************************************************************************/
784
785 /* we implement socketpairs directly in use space for the following reasons:
786 * - it avoids copying data from/to the Nt kernel
787 * - it allows us to implement fdevent hooks easily and cheaply, something
788 * that is not possible with standard Win32 pipes !!
789 *
790 * basically, we use two circular buffers, each one corresponding to a given
791 * direction.
792 *
793 * each buffer is implemented as two regions:
794 *
795 * region A which is (a_start,a_end)
796 * region B which is (0, b_end) with b_end <= a_start
797 *
798 * an empty buffer has: a_start = a_end = b_end = 0
799 *
800 * a_start is the pointer where we start reading data
801 * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
802 * then you start writing at b_end
803 *
804 * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE
805 *
806 * there is room when b_end < a_start || a_end < BUFER_SIZE
807 *
808 * when reading, a_start is incremented, it a_start meets a_end, then
809 * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on..
810 */
811
812 #define BIP_BUFFER_SIZE 4096
813
814 #if 0
815 #include <stdio.h>
816 # define BIPD(x) D x
817 # define BIPDUMP bip_dump_hex
818
819 static void bip_dump_hex( const unsigned char* ptr, size_t len )
820 {
821 int nn, len2 = len;
822
823 if (len2 > 8) len2 = 8;
824
825 for (nn = 0; nn < len2; nn++)
826 printf("%02x", ptr[nn]);
827 printf(" ");
828
829 for (nn = 0; nn < len2; nn++) {
830 int c = ptr[nn];
831 if (c < 32 || c > 127)
832 c = '.';
833 printf("%c", c);
834 }
835 printf("\n");
836 fflush(stdout);
837 }
838
839 #else
840 # define BIPD(x) do {} while (0)
841 # define BIPDUMP(p,l) BIPD(p)
842 #endif
843
844 typedef struct BipBufferRec_
845 {
846 int a_start;
847 int a_end;
848 int b_end;
849 int fdin;
850 int fdout;
851 int closed;
852 int can_write; /* boolean */
853 HANDLE evt_write; /* event signaled when one can write to a buffer */
854 int can_read; /* boolean */
855 HANDLE evt_read; /* event signaled when one can read from a buffer */
856 CRITICAL_SECTION lock;
857 unsigned char buff[ BIP_BUFFER_SIZE ];
858
859 } BipBufferRec, *BipBuffer;
860
861 static void
862 bip_buffer_init( BipBuffer buffer )
863 {
864 D( "bit_buffer_init %p\n", buffer );
865 buffer->a_start = 0;
866 buffer->a_end = 0;
867 buffer->b_end = 0;
868 buffer->can_write = 1;
869 buffer->can_read = 0;
870 buffer->fdin = 0;
871 buffer->fdout = 0;
872 buffer->closed = 0;
873 buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
874 buffer->evt_read = CreateEvent( NULL, TRUE, FALSE, NULL );
875 InitializeCriticalSection( &buffer->lock );
876 }
877
878 static void
879 bip_buffer_close( BipBuffer bip )
880 {
881 bip->closed = 1;
882
883 if (!bip->can_read) {
884 SetEvent( bip->evt_read );
885 }
886 if (!bip->can_write) {
887 SetEvent( bip->evt_write );
888 }
889 }
890
891 static void
892 bip_buffer_done( BipBuffer bip )
893 {
894 BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
895 CloseHandle( bip->evt_read );
896 CloseHandle( bip->evt_write );
897 DeleteCriticalSection( &bip->lock );
898 }
899
900 static int
901 bip_buffer_write( BipBuffer bip, const void* src, int len )
902 {
903 int avail, count = 0;
904
905 if (len <= 0)
906 return 0;
907
908 BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
909 BIPDUMP( src, len );
910
911 EnterCriticalSection( &bip->lock );
912
913 while (!bip->can_write) {
914 int ret;
915 LeaveCriticalSection( &bip->lock );
916
917 if (bip->closed) {
918 errno = EPIPE;
919 return -1;
920 }
921 /* spinlocking here is probably unfair, but let's live with it */
922 ret = WaitForSingleObject( bip->evt_write, INFINITE );
923 if (ret != WAIT_OBJECT_0) { /* buffer probably closed */
924 D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError() );
925 return 0;
926 }
927 if (bip->closed) {
928 errno = EPIPE;
929 return -1;
930 }
931 EnterCriticalSection( &bip->lock );
932 }
933
934 BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
935
936 avail = BIP_BUFFER_SIZE - bip->a_end;
937 if (avail > 0)
938 {
939 /* we can append to region A */
940 if (avail > len)
941 avail = len;
942
943 memcpy( bip->buff + bip->a_end, src, avail );
944 src += avail;
945 count += avail;
946 len -= avail;
947
948 bip->a_end += avail;
949 if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
950 bip->can_write = 0;
951 ResetEvent( bip->evt_write );
952 goto Exit;
953 }
954 }
955
956 if (len == 0)
957 goto Exit;
958
959 avail = bip->a_start - bip->b_end;
960 assert( avail > 0 ); /* since can_write is TRUE */
961
962 if (avail > len)
963 avail = len;
964
965 memcpy( bip->buff + bip->b_end, src, avail );
966 count += avail;
967 bip->b_end += avail;
968
969 if (bip->b_end == bip->a_start) {
970 bip->can_write = 0;
971 ResetEvent( bip->evt_write );
972 }
973
974 Exit:
975 assert( count > 0 );
976
977 if ( !bip->can_read ) {
978 bip->can_read = 1;
979 SetEvent( bip->evt_read );
980 }
981
982 BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
983 bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
984 LeaveCriticalSection( &bip->lock );
985
986 return count;
987 }
988
989 static int
990 bip_buffer_read( BipBuffer bip, void* dst, int len )
991 {
992 int avail, count = 0;
993
994 if (len <= 0)
995 return 0;
996
997 BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
998
999 EnterCriticalSection( &bip->lock );
1000 while ( !bip->can_read )
1001 {
1002 #if 0
1003 LeaveCriticalSection( &bip->lock );
1004 errno = EAGAIN;
1005 return -1;
1006 #else
1007 int ret;
1008 LeaveCriticalSection( &bip->lock );
1009
1010 if (bip->closed) {
1011 errno = EPIPE;
1012 return -1;
1013 }
1014
1015 ret = WaitForSingleObject( bip->evt_read, INFINITE );
1016 if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
1017 D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
1018 return 0;
1019 }
1020 if (bip->closed) {
1021 errno = EPIPE;
1022 return -1;
1023 }
1024 EnterCriticalSection( &bip->lock );
1025 #endif
1026 }
1027
1028 BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
1029
1030 avail = bip->a_end - bip->a_start;
1031 assert( avail > 0 ); /* since can_read is TRUE */
1032
1033 if (avail > len)
1034 avail = len;
1035
1036 memcpy( dst, bip->buff + bip->a_start, avail );
1037 dst += avail;
1038 count += avail;
1039 len -= avail;
1040
1041 bip->a_start += avail;
1042 if (bip->a_start < bip->a_end)
1043 goto Exit;
1044
1045 bip->a_start = 0;
1046 bip->a_end = bip->b_end;
1047 bip->b_end = 0;
1048
1049 avail = bip->a_end;
1050 if (avail > 0) {
1051 if (avail > len)
1052 avail = len;
1053 memcpy( dst, bip->buff, avail );
1054 count += avail;
1055 bip->a_start += avail;
1056
1057 if ( bip->a_start < bip->a_end )
1058 goto Exit;
1059
1060 bip->a_start = bip->a_end = 0;
1061 }
1062
1063 bip->can_read = 0;
1064 ResetEvent( bip->evt_read );
1065
1066 Exit:
1067 assert( count > 0 );
1068
1069 if (!bip->can_write ) {
1070 bip->can_write = 1;
1071 SetEvent( bip->evt_write );
1072 }
1073
1074 BIPDUMP( (const unsigned char*)dst - count, count );
1075 BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
1076 bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
1077 LeaveCriticalSection( &bip->lock );
1078
1079 return count;
1080 }
1081
1082 typedef struct SocketPairRec_
1083 {
1084 BipBufferRec a2b_bip;
1085 BipBufferRec b2a_bip;
1086 FH a_fd;
1087 int used;
1088
1089 } SocketPairRec;
1090
1091 void _fh_socketpair_init( FH f )
1092 {
1093 f->fh_pair = NULL;
1094 }
1095
1096 static int
1097 _fh_socketpair_close( FH f )
1098 {
1099 if ( f->fh_pair ) {
1100 SocketPair pair = f->fh_pair;
1101
1102 if ( f == pair->a_fd ) {
1103 pair->a_fd = NULL;
1104 }
1105
1106 bip_buffer_close( &pair->b2a_bip );
1107 bip_buffer_close( &pair->a2b_bip );
1108
1109 if ( --pair->used == 0 ) {
1110 bip_buffer_done( &pair->b2a_bip );
1111 bip_buffer_done( &pair->a2b_bip );
1112 free( pair );
1113 }
1114 f->fh_pair = NULL;
1115 }
1116 return 0;
1117 }
1118
1119 static int
1120 _fh_socketpair_lseek( FH f, int pos, int origin )
1121 {
1122 errno = ESPIPE;
1123 return -1;
1124 }
1125
1126 static int
1127 _fh_socketpair_read( FH f, void* buf, int len )
1128 {
1129 SocketPair pair = f->fh_pair;
1130 BipBuffer bip;
1131
1132 if (!pair)
1133 return -1;
1134
1135 if ( f == pair->a_fd )
1136 bip = &pair->b2a_bip;
1137 else
1138 bip = &pair->a2b_bip;
1139
1140 return bip_buffer_read( bip, buf, len );
1141 }
1142
1143 static int
1144 _fh_socketpair_write( FH f, const void* buf, int len )
1145 {
1146 SocketPair pair = f->fh_pair;
1147 BipBuffer bip;
1148
1149 if (!pair)
1150 return -1;
1151
1152 if ( f == pair->a_fd )
1153 bip = &pair->a2b_bip;
1154 else
1155 bip = &pair->b2a_bip;
1156
1157 return bip_buffer_write( bip, buf, len );
1158 }
1159
1160
1161 static void _fh_socketpair_hook( FH f, int event, EventHook hook ); /* forward */
1162
1163 static const FHClassRec _fh_socketpair_class =
1164 {
1165 _fh_socketpair_init,
1166 _fh_socketpair_close,
1167 _fh_socketpair_lseek,
1168 _fh_socketpair_read,
1169 _fh_socketpair_write,
1170 _fh_socketpair_hook
1171 };
1172
1173
1174 int adb_socketpair( int sv[2] )
1175 {
1176 FH fa, fb;
1177 SocketPair pair;
1178
1179 fa = _fh_alloc( &_fh_socketpair_class );
1180 fb = _fh_alloc( &_fh_socketpair_class );
1181
1182 if (!fa || !fb)
1183 goto Fail;
1184
1185 pair = malloc( sizeof(*pair) );
1186 if (pair == NULL) {
1187 D("adb_socketpair: not enough memory to allocate pipes\n" );
1188 goto Fail;
1189 }
1190
1191 bip_buffer_init( &pair->a2b_bip );
1192 bip_buffer_init( &pair->b2a_bip );
1193
1194 fa->fh_pair = pair;
1195 fb->fh_pair = pair;
1196 pair->used = 2;
1197 pair->a_fd = fa;
1198
1199 sv[0] = _fh_to_int(fa);
1200 sv[1] = _fh_to_int(fb);
1201
1202 pair->a2b_bip.fdin = sv[0];
1203 pair->a2b_bip.fdout = sv[1];
1204 pair->b2a_bip.fdin = sv[1];
1205 pair->b2a_bip.fdout = sv[0];
1206
1207 snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
1208 snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
1209 D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
1210 return 0;
1211
1212 Fail:
1213 _fh_close(fb);
1214 _fh_close(fa);
1215 return -1;
1216 }
1217
1218 /**************************************************************************/
1219 /**************************************************************************/
1220 /***** *****/
1221 /***** fdevents emulation *****/
1222 /***** *****/
1223 /***** this is a very simple implementation, we rely on the fact *****/
1224 /***** that ADB doesn't use FDE_ERROR. *****/
1225 /***** *****/
1226 /**************************************************************************/
1227 /**************************************************************************/
1228
1229 #define FATAL(x...) fatal(__FUNCTION__, x)
1230
1231 #if DEBUG
1232 static void dump_fde(fdevent *fde, const char *info)
1233 {
1234 fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
1235 fde->state & FDE_READ ? 'R' : ' ',
1236 fde->state & FDE_WRITE ? 'W' : ' ',
1237 fde->state & FDE_ERROR ? 'E' : ' ',
1238 info);
1239 }
1240 #else
1241 #define dump_fde(fde, info) do { } while(0)
1242 #endif
1243
1244 #define FDE_EVENTMASK 0x00ff
1245 #define FDE_STATEMASK 0xff00
1246
1247 #define FDE_ACTIVE 0x0100
1248 #define FDE_PENDING 0x0200
1249 #define FDE_CREATED 0x0400
1250
1251 static void fdevent_plist_enqueue(fdevent *node);
1252 static void fdevent_plist_remove(fdevent *node);
1253 static fdevent *fdevent_plist_dequeue(void);
1254
1255 static fdevent list_pending = {
1256 .next = &list_pending,
1257 .prev = &list_pending,
1258 };
1259
1260 static fdevent **fd_table = 0;
1261 static int fd_table_max = 0;
1262
1263 typedef struct EventLooperRec_* EventLooper;
1264
1265 typedef struct EventHookRec_
1266 {
1267 EventHook next;
1268 FH fh;
1269 HANDLE h;
1270 int wanted; /* wanted event flags */
1271 int ready; /* ready event flags */
1272 void* aux;
1273 void (*prepare)( EventHook hook );
1274 int (*start) ( EventHook hook );
1275 void (*stop) ( EventHook hook );
1276 int (*check) ( EventHook hook );
1277 int (*peek) ( EventHook hook );
1278 } EventHookRec;
1279
1280 static EventHook _free_hooks;
1281
1282 static EventHook
1283 event_hook_alloc( FH fh )
1284 {
1285 EventHook hook = _free_hooks;
1286 if (hook != NULL)
1287 _free_hooks = hook->next;
1288 else {
1289 hook = malloc( sizeof(*hook) );
1290 if (hook == NULL)
1291 fatal( "could not allocate event hook\n" );
1292 }
1293 hook->next = NULL;
1294 hook->fh = fh;
1295 hook->wanted = 0;
1296 hook->ready = 0;
1297 hook->h = INVALID_HANDLE_VALUE;
1298 hook->aux = NULL;
1299
1300 hook->prepare = NULL;
1301 hook->start = NULL;
1302 hook->stop = NULL;
1303 hook->check = NULL;
1304 hook->peek = NULL;
1305
1306 return hook;
1307 }
1308
1309 static void
1310 event_hook_free( EventHook hook )
1311 {
1312 hook->fh = NULL;
1313 hook->wanted = 0;
1314 hook->ready = 0;
1315 hook->next = _free_hooks;
1316 _free_hooks = hook;
1317 }
1318
1319
1320 static void
1321 event_hook_signal( EventHook hook )
1322 {
1323 FH f = hook->fh;
1324 int fd = _fh_to_int(f);
1325 fdevent* fde = fd_table[ fd - WIN32_FH_BASE ];
1326
1327 if (fde != NULL && fde->fd == fd) {
1328 if ((fde->state & FDE_PENDING) == 0) {
1329 fde->state |= FDE_PENDING;
1330 fdevent_plist_enqueue( fde );
1331 }
1332 fde->events |= hook->wanted;
1333 }
1334 }
1335
1336
1337 #define MAX_LOOPER_HANDLES WIN32_MAX_FHS
1338
1339 typedef struct EventLooperRec_
1340 {
1341 EventHook hooks;
1342 HANDLE htab[ MAX_LOOPER_HANDLES ];
1343 int htab_count;
1344
1345 } EventLooperRec;
1346
1347 static EventHook*
1348 event_looper_find_p( EventLooper looper, FH fh )
1349 {
1350 EventHook *pnode = &looper->hooks;
1351 EventHook node = *pnode;
1352 for (;;) {
1353 if ( node == NULL || node->fh == fh )
1354 break;
1355 pnode = &node->next;
1356 node = *pnode;
1357 }
1358 return pnode;
1359 }
1360
1361 static void
1362 event_looper_hook( EventLooper looper, int fd, int events )
1363 {
1364 FH f = _fh_from_int(fd);
1365 EventHook *pnode;
1366 EventHook node;
1367
1368 if (f == NULL) /* invalid arg */ {
1369 D("event_looper_hook: invalid fd=%d\n", fd);
1370 return;
1371 }
1372
1373 pnode = event_looper_find_p( looper, f );
1374 node = *pnode;
1375 if ( node == NULL ) {
1376 node = event_hook_alloc( f );
1377 node->next = *pnode;
1378 *pnode = node;
1379 }
1380
1381 if ( (node->wanted & events) != events ) {
1382 /* this should update start/stop/check/peek */
1383 D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
1384 fd, node->wanted, events);
1385 f->clazz->_fh_hook( f, events & ~node->wanted, node );
1386 node->wanted |= events;
1387 } else {
1388 D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
1389 events, fd, node->wanted);
1390 }
1391 }
1392
1393 static void
1394 event_looper_unhook( EventLooper looper, int fd, int events )
1395 {
1396 FH fh = _fh_from_int(fd);
1397 EventHook *pnode = event_looper_find_p( looper, fh );
1398 EventHook node = *pnode;
1399
1400 if (node != NULL) {
1401 int events2 = events & node->wanted;
1402 if ( events2 == 0 ) {
1403 D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
1404 return;
1405 }
1406 node->wanted &= ~events2;
1407 if (!node->wanted) {
1408 *pnode = node->next;
1409 event_hook_free( node );
1410 }
1411 }
1412 }
1413
1414 static EventLooperRec win32_looper;
1415
1416 static void fdevent_init(void)
1417 {
1418 win32_looper.htab_count = 0;
1419 win32_looper.hooks = NULL;
1420 }
1421
1422 static void fdevent_connect(fdevent *fde)
1423 {
1424 EventLooper looper = &win32_looper;
1425 int events = fde->state & FDE_EVENTMASK;
1426
1427 if (events != 0)
1428 event_looper_hook( looper, fde->fd, events );
1429 }
1430
1431 static void fdevent_disconnect(fdevent *fde)
1432 {
1433 EventLooper looper = &win32_looper;
1434 int events = fde->state & FDE_EVENTMASK;
1435
1436 if (events != 0)
1437 event_looper_unhook( looper, fde->fd, events );
1438 }
1439
1440 static void fdevent_update(fdevent *fde, unsigned events)
1441 {
1442 EventLooper looper = &win32_looper;
1443 unsigned events0 = fde->state & FDE_EVENTMASK;
1444
1445 if (events != events0) {
1446 int removes = events0 & ~events;
1447 int adds = events & ~events0;
1448 if (removes) {
1449 D("fdevent_update: remove %x from %d\n", removes, fde->fd);
1450 event_looper_unhook( looper, fde->fd, removes );
1451 }
1452 if (adds) {
1453 D("fdevent_update: add %x to %d\n", adds, fde->fd);
1454 event_looper_hook ( looper, fde->fd, adds );
1455 }
1456 }
1457 }
1458
1459 static void fdevent_process()
1460 {
1461 EventLooper looper = &win32_looper;
1462 EventHook hook;
1463 int gotone = 0;
1464
1465 /* if we have at least one ready hook, execute it/them */
1466 for (hook = looper->hooks; hook; hook = hook->next) {
1467 hook->ready = 0;
1468 if (hook->prepare) {
1469 hook->prepare(hook);
1470 if (hook->ready != 0) {
1471 event_hook_signal( hook );
1472 gotone = 1;
1473 }
1474 }
1475 }
1476
1477 /* nothing's ready yet, so wait for something to happen */
1478 if (!gotone)
1479 {
1480 looper->htab_count = 0;
1481
1482 for (hook = looper->hooks; hook; hook = hook->next)
1483 {
1484 if (hook->start && !hook->start(hook)) {
1485 D( "fdevent_process: error when starting a hook\n" );
1486 return;
1487 }
1488 if (hook->h != INVALID_HANDLE_VALUE) {
1489 int nn;
1490
1491 for (nn = 0; nn < looper->htab_count; nn++)
1492 {
1493 if ( looper->htab[nn] == hook->h )
1494 goto DontAdd;
1495 }
1496 looper->htab[ looper->htab_count++ ] = hook->h;
1497 DontAdd:
1498 ;
1499 }
1500 }
1501
1502 if (looper->htab_count == 0) {
1503 D( "fdevent_process: nothing to wait for !!\n" );
1504 return;
1505 }
1506
1507 do
1508 {
1509 int wait_ret;
1510
1511 D( "adb_win32: waiting for %d events\n", looper->htab_count );
1512 if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
1513 D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", looper->htab_count);
1514 abort();
1515 }
1516 wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
1517 if (wait_ret == (int)WAIT_FAILED) {
1518 D( "adb_win32: wait failed, error %ld\n", GetLastError() );
1519 } else {
1520 D( "adb_win32: got one (index %d)\n", wait_ret );
1521
1522 /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
1523 * like mouse movements. we need to filter these with the "check" function
1524 */
1525 if ((unsigned)wait_ret < (unsigned)looper->htab_count)
1526 {
1527 for (hook = looper->hooks; hook; hook = hook->next)
1528 {
1529 if ( looper->htab[wait_ret] == hook->h &&
1530 (!hook->check || hook->check(hook)) )
1531 {
1532 D( "adb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
1533 event_hook_signal( hook );
1534 gotone = 1;
1535 break;
1536 }
1537 }
1538 }
1539 }
1540 }
1541 while (!gotone);
1542
1543 for (hook = looper->hooks; hook; hook = hook->next) {
1544 if (hook->stop)
1545 hook->stop( hook );
1546 }
1547 }
1548
1549 for (hook = looper->hooks; hook; hook = hook->next) {
1550 if (hook->peek && hook->peek(hook))
1551 event_hook_signal( hook );
1552 }
1553 }
1554
1555
1556 static void fdevent_register(fdevent *fde)
1557 {
1558 int fd = fde->fd - WIN32_FH_BASE;
1559
1560 if(fd < 0) {
1561 FATAL("bogus negative fd (%d)\n", fde->fd);
1562 }
1563
1564 if(fd >= fd_table_max) {
1565 int oldmax = fd_table_max;
1566 if(fde->fd > 32000) {
1567 FATAL("bogus huuuuge fd (%d)\n", fde->fd);
1568 }
1569 if(fd_table_max == 0) {
1570 fdevent_init();
1571 fd_table_max = 256;
1572 }
1573 while(fd_table_max <= fd) {
1574 fd_table_max *= 2;
1575 }
1576 fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
1577 if(fd_table == 0) {
1578 FATAL("could not expand fd_table to %d entries\n", fd_table_max);
1579 }
1580 memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
1581 }
1582
1583 fd_table[fd] = fde;
1584 }
1585
1586 static void fdevent_unregister(fdevent *fde)
1587 {
1588 int fd = fde->fd - WIN32_FH_BASE;
1589
1590 if((fd < 0) || (fd >= fd_table_max)) {
1591 FATAL("fd out of range (%d)\n", fde->fd);
1592 }
1593
1594 if(fd_table[fd] != fde) {
1595 FATAL("fd_table out of sync");
1596 }
1597
1598 fd_table[fd] = 0;
1599
1600 if(!(fde->state & FDE_DONT_CLOSE)) {
1601 dump_fde(fde, "close");
1602 adb_close(fde->fd);
1603 }
1604 }
1605
1606 static void fdevent_plist_enqueue(fdevent *node)
1607 {
1608 fdevent *list = &list_pending;
1609
1610 node->next = list;
1611 node->prev = list->prev;
1612 node->prev->next = node;
1613 list->prev = node;
1614 }
1615
1616 static void fdevent_plist_remove(fdevent *node)
1617 {
1618 node->prev->next = node->next;
1619 node->next->prev = node->prev;
1620 node->next = 0;
1621 node->prev = 0;
1622 }
1623
1624 static fdevent *fdevent_plist_dequeue(void)
1625 {
1626 fdevent *list = &list_pending;
1627 fdevent *node = list->next;
1628
1629 if(node == list) return 0;
1630
1631 list->next = node->next;
1632 list->next->prev = list;
1633 node->next = 0;
1634 node->prev = 0;
1635
1636 return node;
1637 }
1638
1639 fdevent *fdevent_create(int fd, fd_func func, void *arg)
1640 {
1641 fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
1642 if(fde == 0) return 0;
1643 fdevent_install(fde, fd, func, arg);
1644 fde->state |= FDE_CREATED;
1645 return fde;
1646 }
1647
1648 void fdevent_destroy(fdevent *fde)
1649 {
1650 if(fde == 0) return;
1651 if(!(fde->state & FDE_CREATED)) {
1652 FATAL("fde %p not created by fdevent_create()\n", fde);
1653 }
1654 fdevent_remove(fde);
1655 }
1656
1657 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
1658 {
1659 memset(fde, 0, sizeof(fdevent));
1660 fde->state = FDE_ACTIVE;
1661 fde->fd = fd;
1662 fde->func = func;
1663 fde->arg = arg;
1664
1665 fdevent_register(fde);
1666 dump_fde(fde, "connect");
1667 fdevent_connect(fde);
1668 fde->state |= FDE_ACTIVE;
1669 }
1670
1671 void fdevent_remove(fdevent *fde)
1672 {
1673 if(fde->state & FDE_PENDING) {
1674 fdevent_plist_remove(fde);
1675 }
1676
1677 if(fde->state & FDE_ACTIVE) {
1678 fdevent_disconnect(fde);
1679 dump_fde(fde, "disconnect");
1680 fdevent_unregister(fde);
1681 }
1682
1683 fde->state = 0;
1684 fde->events = 0;
1685 }
1686
1687
1688 void fdevent_set(fdevent *fde, unsigned events)
1689 {
1690 events &= FDE_EVENTMASK;
1691
1692 if((fde->state & FDE_EVENTMASK) == (int)events) return;
1693
1694 if(fde->state & FDE_ACTIVE) {
1695 fdevent_update(fde, events);
1696 dump_fde(fde, "update");
1697 }
1698
1699 fde->state = (fde->state & FDE_STATEMASK) | events;
1700
1701 if(fde->state & FDE_PENDING) {
1702 /* if we're pending, make sure
1703 ** we don't signal an event that
1704 ** is no longer wanted.
1705 */
1706 fde->events &= (~events);
1707 if(fde->events == 0) {
1708 fdevent_plist_remove(fde);
1709 fde->state &= (~FDE_PENDING);
1710 }
1711 }
1712 }
1713
1714 void fdevent_add(fdevent *fde, unsigned events)
1715 {
1716 fdevent_set(
1717 fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
1718 }
1719
1720 void fdevent_del(fdevent *fde, unsigned events)
1721 {
1722 fdevent_set(
1723 fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
1724 }
1725
1726 void fdevent_loop()
1727 {
1728 fdevent *fde;
1729
1730 for(;;) {
1731 #if DEBUG
1732 fprintf(stderr,"--- ---- waiting for events\n");
1733 #endif
1734 fdevent_process();
1735
1736 while((fde = fdevent_plist_dequeue())) {
1737 unsigned events = fde->events;
1738 fde->events = 0;
1739 fde->state &= (~FDE_PENDING);
1740 dump_fde(fde, "callback");
1741 fde->func(fde->fd, events, fde->arg);
1742 }
1743 }
1744 }
1745
1746 /** FILE EVENT HOOKS
1747 **/
1748
1749 static void _event_file_prepare( EventHook hook )
1750 {
1751 if (hook->wanted & (FDE_READ|FDE_WRITE)) {
1752 /* we can always read/write */
1753 hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
1754 }
1755 }
1756
1757 static int _event_file_peek( EventHook hook )
1758 {
1759 return (hook->wanted & (FDE_READ|FDE_WRITE));
1760 }
1761
1762 static void _fh_file_hook( FH f, int events, EventHook hook )
1763 {
1764 hook->h = f->fh_handle;
1765 hook->prepare = _event_file_prepare;
1766 hook->peek = _event_file_peek;
1767 }
1768
1769 /** SOCKET EVENT HOOKS
1770 **/
1771
1772 static void _event_socket_verify( EventHook hook, WSANETWORKEVENTS* evts )
1773 {
1774 if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
1775 if (hook->wanted & FDE_READ)
1776 hook->ready |= FDE_READ;
1777 if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
1778 hook->ready |= FDE_ERROR;
1779 }
1780 if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
1781 if (hook->wanted & FDE_WRITE)
1782 hook->ready |= FDE_WRITE;
1783 if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
1784 hook->ready |= FDE_ERROR;
1785 }
1786 if ( evts->lNetworkEvents & FD_OOB ) {
1787 if (hook->wanted & FDE_ERROR)
1788 hook->ready |= FDE_ERROR;
1789 }
1790 }
1791
1792 static void _event_socket_prepare( EventHook hook )
1793 {
1794 WSANETWORKEVENTS evts;
1795
1796 /* look if some of the events we want already happened ? */
1797 if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
1798 _event_socket_verify( hook, &evts );
1799 }
1800
1801 static int _socket_wanted_to_flags( int wanted )
1802 {
1803 int flags = 0;
1804 if (wanted & FDE_READ)
1805 flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
1806
1807 if (wanted & FDE_WRITE)
1808 flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
1809
1810 if (wanted & FDE_ERROR)
1811 flags |= FD_OOB;
1812
1813 return flags;
1814 }
1815
1816 static int _event_socket_start( EventHook hook )
1817 {
1818 /* create an event which we're going to wait for */
1819 FH fh = hook->fh;
1820 long flags = _socket_wanted_to_flags( hook->wanted );
1821
1822 hook->h = fh->event;
1823 if (hook->h == INVALID_HANDLE_VALUE) {
1824 D( "_event_socket_start: no event for %s\n", fh->name );
1825 return 0;
1826 }
1827
1828 if ( flags != fh->mask ) {
1829 D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
1830 if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
1831 D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError() );
1832 CloseHandle( hook->h );
1833 hook->h = INVALID_HANDLE_VALUE;
1834 exit(1);
1835 return 0;
1836 }
1837 fh->mask = flags;
1838 }
1839 return 1;
1840 }
1841
1842 static void _event_socket_stop( EventHook hook )
1843 {
1844 hook->h = INVALID_HANDLE_VALUE;
1845 }
1846
1847 static int _event_socket_check( EventHook hook )
1848 {
1849 int result = 0;
1850 FH fh = hook->fh;
1851 WSANETWORKEVENTS evts;
1852
1853 if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
1854 _event_socket_verify( hook, &evts );
1855 result = (hook->ready != 0);
1856 if (result) {
1857 ResetEvent( hook->h );
1858 }
1859 }
1860 D( "_event_socket_check %s returns %d\n", fh->name, result );
1861 return result;
1862 }
1863
1864 static int _event_socket_peek( EventHook hook )
1865 {
1866 WSANETWORKEVENTS evts;
1867 FH fh = hook->fh;
1868
1869 /* look if some of the events we want already happened ? */
1870 if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
1871 _event_socket_verify( hook, &evts );
1872 if (hook->ready)
1873 ResetEvent( hook->h );
1874 }
1875
1876 return hook->ready != 0;
1877 }
1878
1879
1880
1881 static void _fh_socket_hook( FH f, int events, EventHook hook )
1882 {
1883 hook->prepare = _event_socket_prepare;
1884 hook->start = _event_socket_start;
1885 hook->stop = _event_socket_stop;
1886 hook->check = _event_socket_check;
1887 hook->peek = _event_socket_peek;
1888
1889 _event_socket_start( hook );
1890 }
1891
1892 /** SOCKETPAIR EVENT HOOKS
1893 **/
1894
1895 static void _event_socketpair_prepare( EventHook hook )
1896 {
1897 FH fh = hook->fh;
1898 SocketPair pair = fh->fh_pair;
1899 BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
1900 BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
1901
1902 if (hook->wanted & FDE_READ && rbip->can_read)
1903 hook->ready |= FDE_READ;
1904
1905 if (hook->wanted & FDE_WRITE && wbip->can_write)
1906 hook->ready |= FDE_WRITE;
1907 }
1908
1909 static int _event_socketpair_start( EventHook hook )
1910 {
1911 FH fh = hook->fh;
1912 SocketPair pair = fh->fh_pair;
1913 BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
1914 BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
1915
1916 if (hook->wanted == FDE_READ)
1917 hook->h = rbip->evt_read;
1918
1919 else if (hook->wanted == FDE_WRITE)
1920 hook->h = wbip->evt_write;
1921
1922 else {
1923 D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
1924 return 0;
1925 }
1926 D( "_event_socketpair_start: hook %s for %x wanted=%x\n",
1927 hook->fh->name, _fh_to_int(fh), hook->wanted);
1928 return 1;
1929 }
1930
1931 static int _event_socketpair_peek( EventHook hook )
1932 {
1933 _event_socketpair_prepare( hook );
1934 return hook->ready != 0;
1935 }
1936
1937 static void _fh_socketpair_hook( FH fh, int events, EventHook hook )
1938 {
1939 hook->prepare = _event_socketpair_prepare;
1940 hook->start = _event_socketpair_start;
1941 hook->peek = _event_socketpair_peek;
1942 }
1943
1944
1945 void
1946 adb_sysdeps_init( void )
1947 {
1948 #define ADB_MUTEX(x) InitializeCriticalSection( & x );
1949 #include "mutex_list.h"
1950 InitializeCriticalSection( &_win32_lock );
1951 }
1952
+0
-97
adb/test_track_devices.c less more
0 /* a simple test program, connects to ADB server, and opens a track-devices session */
1 #include <netdb.h>
2 #include <sys/socket.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <memory.h>
7
8 static void
9 panic( const char* msg )
10 {
11 fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
12 exit(1);
13 }
14
15 static int
16 unix_write( int fd, const char* buf, int len )
17 {
18 int result = 0;
19 while (len > 0) {
20 int len2 = write(fd, buf, len);
21 if (len2 < 0) {
22 if (errno == EINTR || errno == EAGAIN)
23 continue;
24 return -1;
25 }
26 result += len2;
27 len -= len2;
28 buf += len2;
29 }
30 return result;
31 }
32
33 static int
34 unix_read( int fd, char* buf, int len )
35 {
36 int result = 0;
37 while (len > 0) {
38 int len2 = read(fd, buf, len);
39 if (len2 < 0) {
40 if (errno == EINTR || errno == EAGAIN)
41 continue;
42 return -1;
43 }
44 result += len2;
45 len -= len2;
46 buf += len2;
47 }
48 return result;
49 }
50
51
52 int main( void )
53 {
54 int ret, s;
55 struct sockaddr_in server;
56 char buffer[1024];
57 const char* request = "host:track-devices";
58 int len;
59
60 memset( &server, 0, sizeof(server) );
61 server.sin_family = AF_INET;
62 server.sin_port = htons(5037);
63 server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
64
65 s = socket( PF_INET, SOCK_STREAM, 0 );
66 ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
67 if (ret < 0) panic( "could not connect to server" );
68
69 /* send the request */
70 len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
71 if (unix_write(s, buffer, len) < 0)
72 panic( "could not send request" );
73
74 /* read the OKAY answer */
75 if (unix_read(s, buffer, 4) != 4)
76 panic( "could not read request" );
77
78 printf( "server answer: %.*s\n", 4, buffer );
79
80 /* now loop */
81 for (;;) {
82 char head[5] = "0000";
83
84 if (unix_read(s, head, 4) < 0)
85 panic("could not read length");
86
87 if ( sscanf( head, "%04x", &len ) != 1 )
88 panic("could not decode length");
89
90 if (unix_read(s, buffer, len) != len)
91 panic("could not read data");
92
93 printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
94 }
95 close(s);
96 }
+0
-97
adb/test_track_jdwp.c less more
0 /* a simple test program, connects to ADB server, and opens a track-devices session */
1 #include <netdb.h>
2 #include <sys/socket.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <memory.h>
7
8 static void
9 panic( const char* msg )
10 {
11 fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
12 exit(1);
13 }
14
15 static int
16 unix_write( int fd, const char* buf, int len )
17 {
18 int result = 0;
19 while (len > 0) {
20 int len2 = write(fd, buf, len);
21 if (len2 < 0) {
22 if (errno == EINTR || errno == EAGAIN)
23 continue;
24 return -1;
25 }
26 result += len2;
27 len -= len2;
28 buf += len2;
29 }
30 return result;
31 }
32
33 static int
34 unix_read( int fd, char* buf, int len )
35 {
36 int result = 0;
37 while (len > 0) {
38 int len2 = read(fd, buf, len);
39 if (len2 < 0) {
40 if (errno == EINTR || errno == EAGAIN)
41 continue;
42 return -1;
43 }
44 result += len2;
45 len -= len2;
46 buf += len2;
47 }
48 return result;
49 }
50
51
52 int main( void )
53 {
54 int ret, s;
55 struct sockaddr_in server;
56 char buffer[1024];
57 const char* request = "track-jdwp";
58 int len;
59
60 memset( &server, 0, sizeof(server) );
61 server.sin_family = AF_INET;
62 server.sin_port = htons(5037);
63 server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
64
65 s = socket( PF_INET, SOCK_STREAM, 0 );
66 ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
67 if (ret < 0) panic( "could not connect to server" );
68
69 /* send the request */
70 len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
71 if (unix_write(s, buffer, len) < 0)
72 panic( "could not send request" );
73
74 /* read the OKAY answer */
75 if (unix_read(s, buffer, 4) != 4)
76 panic( "could not read request" );
77
78 printf( "server answer: %.*s\n", 4, buffer );
79
80 /* now loop */
81 for (;;) {
82 char head[5] = "0000";
83
84 if (unix_read(s, head, 4) < 0)
85 panic("could not read length");
86
87 if ( sscanf( head, "%04x", &len ) != 1 )
88 panic("could not decode length");
89
90 if (unix_read(s, buffer, len) != len)
91 panic("could not read data");
92
93 printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
94 }
95 close(s);
96 }
+0
-958
adb/transport.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "sysdeps.h"
23
24 #define TRACE_TAG TRACE_TRANSPORT
25 #include "adb.h"
26
27 static void transport_unref(atransport *t);
28
29 static atransport transport_list = {
30 .next = &transport_list,
31 .prev = &transport_list,
32 };
33
34 ADB_MUTEX_DEFINE( transport_lock );
35
36 #if ADB_TRACE
37 static void dump_hex( const unsigned char* ptr, size_t len )
38 {
39 int nn, len2 = len;
40
41 if (len2 > 16) len2 = 16;
42
43 for (nn = 0; nn < len2; nn++)
44 D("%02x", ptr[nn]);
45 D(" ");
46
47 for (nn = 0; nn < len2; nn++) {
48 int c = ptr[nn];
49 if (c < 32 || c > 127)
50 c = '.';
51 D("%c", c);
52 }
53 D("\n");
54 fflush(stdout);
55 }
56 #endif
57
58 void
59 kick_transport(atransport* t)
60 {
61 if (t && !t->kicked)
62 {
63 int kicked;
64
65 adb_mutex_lock(&transport_lock);
66 kicked = t->kicked;
67 if (!kicked)
68 t->kicked = 1;
69 adb_mutex_unlock(&transport_lock);
70
71 if (!kicked)
72 t->kick(t);
73 }
74 }
75
76 void
77 run_transport_disconnects(atransport* t)
78 {
79 adisconnect* dis = t->disconnects.next;
80
81 D("run_transport_disconnects: %p (%s)\n", t, t->serial ? t->serial : "unknown" );
82 while (dis != &t->disconnects) {
83 adisconnect* next = dis->next;
84 dis->func( dis->opaque, t );
85 dis = next;
86 }
87 }
88
89 static int
90 read_packet(int fd, apacket** ppacket)
91 {
92 char *p = (char*)ppacket; /* really read a packet address */
93 int r;
94 int len = sizeof(*ppacket);
95 while(len > 0) {
96 r = adb_read(fd, p, len);
97 if(r > 0) {
98 len -= r;
99 p += r;
100 } else {
101 D("read_packet: %d error %d %d\n", fd, r, errno);
102 if((r < 0) && (errno == EINTR)) continue;
103 return -1;
104 }
105 }
106
107 #if ADB_TRACE
108 if (ADB_TRACING)
109 {
110 unsigned command = (*ppacket)->msg.command;
111 int len = (*ppacket)->msg.data_length;
112 char cmd[5];
113 int n;
114
115 for (n = 0; n < 4; n++) {
116 int b = (command >> (n*8)) & 255;
117 if (b >= 32 && b < 127)
118 cmd[n] = (char)b;
119 else
120 cmd[n] = '.';
121 }
122 cmd[4] = 0;
123
124 D("read_packet: %d ok: [%08x %s] %08x %08x (%d) ",
125 fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len);
126 dump_hex((*ppacket)->data, len);
127 }
128 #endif
129 return 0;
130 }
131
132 static int
133 write_packet(int fd, apacket** ppacket)
134 {
135 char *p = (char*) ppacket; /* we really write the packet address */
136 int r, len = sizeof(ppacket);
137
138 #if ADB_TRACE
139 if (ADB_TRACING)
140 {
141 unsigned command = (*ppacket)->msg.command;
142 int len = (*ppacket)->msg.data_length;
143 char cmd[5];
144 int n;
145
146 for (n = 0; n < 4; n++) {
147 int b = (command >> (n*8)) & 255;
148 if (b >= 32 && b < 127)
149 cmd[n] = (char)b;
150 else
151 cmd[n] = '.';
152 }
153 cmd[4] = 0;
154
155 D("write_packet: %d [%08x %s] %08x %08x (%d) ",
156 fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len);
157 dump_hex((*ppacket)->data, len);
158 }
159 #endif
160 len = sizeof(ppacket);
161 while(len > 0) {
162 r = adb_write(fd, p, len);
163 if(r > 0) {
164 len -= r;
165 p += r;
166 } else {
167 D("write_packet: %d error %d %d\n", fd, r, errno);
168 if((r < 0) && (errno == EINTR)) continue;
169 return -1;
170 }
171 }
172 return 0;
173 }
174
175 static void transport_socket_events(int fd, unsigned events, void *_t)
176 {
177 if(events & FDE_READ){
178 apacket *p = 0;
179 if(read_packet(fd, &p)){
180 D("failed to read packet from transport socket on fd %d\n", fd);
181 } else {
182 handle_packet(p, (atransport *) _t);
183 }
184 }
185 }
186
187 void send_packet(apacket *p, atransport *t)
188 {
189 unsigned char *x;
190 unsigned sum;
191 unsigned count;
192
193 p->msg.magic = p->msg.command ^ 0xffffffff;
194
195 count = p->msg.data_length;
196 x = (unsigned char *) p->data;
197 sum = 0;
198 while(count-- > 0){
199 sum += *x++;
200 }
201 p->msg.data_check = sum;
202
203 print_packet("send", p);
204
205 if (t == NULL) {
206 fatal_errno("Transport is null");
207 D("Transport is null \n");
208 }
209
210 if(write_packet(t->transport_socket, &p)){
211 fatal_errno("cannot enqueue packet on transport socket");
212 }
213 }
214
215 /* The transport is opened by transport_register_func before
216 ** the input and output threads are started.
217 **
218 ** The output thread issues a SYNC(1, token) message to let
219 ** the input thread know to start things up. In the event
220 ** of transport IO failure, the output thread will post a
221 ** SYNC(0,0) message to ensure shutdown.
222 **
223 ** The transport will not actually be closed until both
224 ** threads exit, but the input thread will kick the transport
225 ** on its way out to disconnect the underlying device.
226 */
227
228 static void *output_thread(void *_t)
229 {
230 atransport *t = _t;
231 apacket *p;
232
233 D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd );
234
235 D("from_remote: transport %p SYNC online (%d)\n", t, t->sync_token + 1);
236 p = get_apacket();
237 p->msg.command = A_SYNC;
238 p->msg.arg0 = 1;
239 p->msg.arg1 = ++(t->sync_token);
240 p->msg.magic = A_SYNC ^ 0xffffffff;
241 if(write_packet(t->fd, &p)) {
242 put_apacket(p);
243 D("from_remote: failed to write SYNC apacket to transport %p", t);
244 goto oops;
245 }
246
247 D("from_remote: data pump for transport %p\n", t);
248 for(;;) {
249 p = get_apacket();
250
251 if(t->read_from_remote(p, t) == 0){
252 D("from_remote: received remote packet, sending to transport %p\n",
253 t);
254 if(write_packet(t->fd, &p)){
255 put_apacket(p);
256 D("from_remote: failed to write apacket to transport %p", t);
257 goto oops;
258 }
259 } else {
260 D("from_remote: remote read failed for transport %p\n", p);
261 put_apacket(p);
262 break;
263 }
264 }
265
266 D("from_remote: SYNC offline for transport %p\n", t);
267 p = get_apacket();
268 p->msg.command = A_SYNC;
269 p->msg.arg0 = 0;
270 p->msg.arg1 = 0;
271 p->msg.magic = A_SYNC ^ 0xffffffff;
272 if(write_packet(t->fd, &p)) {
273 put_apacket(p);
274 D("from_remote: failed to write SYNC apacket to transport %p", t);
275 }
276
277 oops:
278 D("from_remote: thread is exiting for transport %p\n", t);
279 kick_transport(t);
280 transport_unref(t);
281 return 0;
282 }
283
284 static void *input_thread(void *_t)
285 {
286 atransport *t = _t;
287 apacket *p;
288 int active = 0;
289
290 D("to_remote: starting input_thread for %p, reading from fd %d\n",
291 t, t->fd);
292
293 for(;;){
294 if(read_packet(t->fd, &p)) {
295 D("to_remote: failed to read apacket from transport %p on fd %d\n",
296 t, t->fd );
297 break;
298 }
299 if(p->msg.command == A_SYNC){
300 if(p->msg.arg0 == 0) {
301 D("to_remote: transport %p SYNC offline\n", t);
302 put_apacket(p);
303 break;
304 } else {
305 if(p->msg.arg1 == t->sync_token) {
306 D("to_remote: transport %p SYNC online\n", t);
307 active = 1;
308 } else {
309 D("to_remote: trandport %p ignoring SYNC %d != %d\n",
310 t, p->msg.arg1, t->sync_token);
311 }
312 }
313 } else {
314 if(active) {
315 D("to_remote: transport %p got packet, sending to remote\n", t);
316 t->write_to_remote(p, t);
317 } else {
318 D("to_remote: transport %p ignoring packet while offline\n", t);
319 }
320 }
321
322 put_apacket(p);
323 }
324
325 // this is necessary to avoid a race condition that occured when a transport closes
326 // while a client socket is still active.
327 close_all_sockets(t);
328
329 D("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd);
330 kick_transport(t);
331 transport_unref(t);
332 return 0;
333 }
334
335
336 static int transport_registration_send = -1;
337 static int transport_registration_recv = -1;
338 static fdevent transport_registration_fde;
339
340
341 #if ADB_HOST
342 static int list_transports_msg(char* buffer, size_t bufferlen)
343 {
344 char head[5];
345 int len;
346
347 len = list_transports(buffer+4, bufferlen-4);
348 snprintf(head, sizeof(head), "%04x", len);
349 memcpy(buffer, head, 4);
350 len += 4;
351 return len;
352 }
353
354 /* this adds support required by the 'track-devices' service.
355 * this is used to send the content of "list_transport" to any
356 * number of client connections that want it through a single
357 * live TCP connection
358 */
359 typedef struct device_tracker device_tracker;
360 struct device_tracker {
361 asocket socket;
362 int update_needed;
363 device_tracker* next;
364 };
365
366 /* linked list of all device trackers */
367 static device_tracker* device_tracker_list;
368
369 static void
370 device_tracker_remove( device_tracker* tracker )
371 {
372 device_tracker** pnode = &device_tracker_list;
373 device_tracker* node = *pnode;
374
375 adb_mutex_lock( &transport_lock );
376 while (node) {
377 if (node == tracker) {
378 *pnode = node->next;
379 break;
380 }
381 pnode = &node->next;
382 node = *pnode;
383 }
384 adb_mutex_unlock( &transport_lock );
385 }
386
387 static void
388 device_tracker_close( asocket* socket )
389 {
390 device_tracker* tracker = (device_tracker*) socket;
391 asocket* peer = socket->peer;
392
393 D( "device tracker %p removed\n", tracker);
394 if (peer) {
395 peer->peer = NULL;
396 peer->close(peer);
397 }
398 device_tracker_remove(tracker);
399 free(tracker);
400 }
401
402 static int
403 device_tracker_enqueue( asocket* socket, apacket* p )
404 {
405 /* you can't read from a device tracker, close immediately */
406 put_apacket(p);
407 device_tracker_close(socket);
408 return -1;
409 }
410
411 static int
412 device_tracker_send( device_tracker* tracker,
413 const char* buffer,
414 int len )
415 {
416 apacket* p = get_apacket();
417 asocket* peer = tracker->socket.peer;
418
419 memcpy(p->data, buffer, len);
420 p->len = len;
421 return peer->enqueue( peer, p );
422 }
423
424
425 static void
426 device_tracker_ready( asocket* socket )
427 {
428 device_tracker* tracker = (device_tracker*) socket;
429
430 /* we want to send the device list when the tracker connects
431 * for the first time, even if no update occured */
432 if (tracker->update_needed > 0) {
433 char buffer[1024];
434 int len;
435
436 tracker->update_needed = 0;
437
438 len = list_transports_msg(buffer, sizeof(buffer));
439 device_tracker_send(tracker, buffer, len);
440 }
441 }
442
443
444 asocket*
445 create_device_tracker(void)
446 {
447 device_tracker* tracker = calloc(1,sizeof(*tracker));
448
449 if(tracker == 0) fatal("cannot allocate device tracker");
450
451 D( "device tracker %p created\n", tracker);
452
453 tracker->socket.enqueue = device_tracker_enqueue;
454 tracker->socket.ready = device_tracker_ready;
455 tracker->socket.close = device_tracker_close;
456 tracker->update_needed = 1;
457
458 tracker->next = device_tracker_list;
459 device_tracker_list = tracker;
460
461 return &tracker->socket;
462 }
463
464
465 /* call this function each time the transport list has changed */
466 void update_transports(void)
467 {
468 char buffer[1024];
469 int len;
470 device_tracker* tracker;
471
472 len = list_transports_msg(buffer, sizeof(buffer));
473
474 tracker = device_tracker_list;
475 while (tracker != NULL) {
476 device_tracker* next = tracker->next;
477 /* note: this may destroy the tracker if the connection is closed */
478 device_tracker_send(tracker, buffer, len);
479 tracker = next;
480 }
481 }
482 #else
483 void update_transports(void)
484 {
485 // nothing to do on the device side
486 }
487 #endif // ADB_HOST
488
489 typedef struct tmsg tmsg;
490 struct tmsg
491 {
492 atransport *transport;
493 int action;
494 };
495
496 static int
497 transport_read_action(int fd, struct tmsg* m)
498 {
499 char *p = (char*)m;
500 int len = sizeof(*m);
501 int r;
502
503 while(len > 0) {
504 r = adb_read(fd, p, len);
505 if(r > 0) {
506 len -= r;
507 p += r;
508 } else {
509 if((r < 0) && (errno == EINTR)) continue;
510 D("transport_read_action: on fd %d, error %d: %s\n",
511 fd, errno, strerror(errno));
512 return -1;
513 }
514 }
515 return 0;
516 }
517
518 static int
519 transport_write_action(int fd, struct tmsg* m)
520 {
521 char *p = (char*)m;
522 int len = sizeof(*m);
523 int r;
524
525 while(len > 0) {
526 r = adb_write(fd, p, len);
527 if(r > 0) {
528 len -= r;
529 p += r;
530 } else {
531 if((r < 0) && (errno == EINTR)) continue;
532 D("transport_write_action: on fd %d, error %d: %s\n",
533 fd, errno, strerror(errno));
534 return -1;
535 }
536 }
537 return 0;
538 }
539
540 static void transport_registration_func(int _fd, unsigned ev, void *data)
541 {
542 tmsg m;
543 adb_thread_t output_thread_ptr;
544 adb_thread_t input_thread_ptr;
545 int s[2];
546 atransport *t;
547
548 if(!(ev & FDE_READ)) {
549 return;
550 }
551
552 if(transport_read_action(_fd, &m)) {
553 fatal_errno("cannot read transport registration socket");
554 }
555
556 t = m.transport;
557
558 if(m.action == 0){
559 D("transport: %p removing and free'ing %d\n", t, t->transport_socket);
560
561 /* IMPORTANT: the remove closes one half of the
562 ** socket pair. The close closes the other half.
563 */
564 fdevent_remove(&(t->transport_fde));
565 adb_close(t->fd);
566
567 adb_mutex_lock(&transport_lock);
568 t->next->prev = t->prev;
569 t->prev->next = t->next;
570 adb_mutex_unlock(&transport_lock);
571
572 run_transport_disconnects(t);
573
574 if (t->product)
575 free(t->product);
576 if (t->serial)
577 free(t->serial);
578
579 memset(t,0xee,sizeof(atransport));
580 free(t);
581
582 update_transports();
583 return;
584 }
585
586 /* initial references are the two threads */
587 t->ref_count = 2;
588
589 if(adb_socketpair(s)) {
590 fatal_errno("cannot open transport socketpair");
591 }
592
593 D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
594
595 t->transport_socket = s[0];
596 t->fd = s[1];
597
598 /* put us on the master device list */
599 adb_mutex_lock(&transport_lock);
600 t->next = &transport_list;
601 t->prev = transport_list.prev;
602 t->next->prev = t;
603 t->prev->next = t;
604 adb_mutex_unlock(&transport_lock);
605
606 D("transport: %p install %d\n", t, t->transport_socket );
607 fdevent_install(&(t->transport_fde),
608 t->transport_socket,
609 transport_socket_events,
610 t);
611
612 fdevent_set(&(t->transport_fde), FDE_READ);
613
614 if(adb_thread_create(&input_thread_ptr, input_thread, t)){
615 fatal_errno("cannot create input thread");
616 }
617
618 if(adb_thread_create(&output_thread_ptr, output_thread, t)){
619 fatal_errno("cannot create output thread");
620 }
621
622 t->disconnects.next = t->disconnects.prev = &t->disconnects;
623
624 update_transports();
625 }
626
627 void init_transport_registration(void)
628 {
629 int s[2];
630
631 if(adb_socketpair(s)){
632 fatal_errno("cannot open transport registration socketpair");
633 }
634
635 transport_registration_send = s[0];
636 transport_registration_recv = s[1];
637
638 fdevent_install(&transport_registration_fde,
639 transport_registration_recv,
640 transport_registration_func,
641 0);
642
643 fdevent_set(&transport_registration_fde, FDE_READ);
644 }
645
646 /* the fdevent select pump is single threaded */
647 static void register_transport(atransport *transport)
648 {
649 tmsg m;
650 m.transport = transport;
651 m.action = 1;
652 D("transport: %p registered\n", transport);
653 if(transport_write_action(transport_registration_send, &m)) {
654 fatal_errno("cannot write transport registration socket\n");
655 }
656 }
657
658 static void remove_transport(atransport *transport)
659 {
660 tmsg m;
661 m.transport = transport;
662 m.action = 0;
663 D("transport: %p removed\n", transport);
664 if(transport_write_action(transport_registration_send, &m)) {
665 fatal_errno("cannot write transport registration socket\n");
666 }
667 }
668
669
670 static void transport_unref(atransport *t)
671 {
672 if (t) {
673 adb_mutex_lock(&transport_lock);
674 t->ref_count--;
675 D("transport: %p R- (ref=%d)\n", t, t->ref_count);
676 if (t->ref_count == 0) {
677 D("transport: %p kicking and closing\n", t);
678 if (!t->kicked) {
679 t->kicked = 1;
680 t->kick(t);
681 }
682 t->close(t);
683 remove_transport(t);
684 }
685 adb_mutex_unlock(&transport_lock);
686 }
687 }
688
689 void add_transport_disconnect(atransport* t, adisconnect* dis)
690 {
691 adb_mutex_lock(&transport_lock);
692 dis->next = &t->disconnects;
693 dis->prev = dis->next->prev;
694 dis->prev->next = dis;
695 dis->next->prev = dis;
696 adb_mutex_unlock(&transport_lock);
697 }
698
699 void remove_transport_disconnect(atransport* t, adisconnect* dis)
700 {
701 dis->prev->next = dis->next;
702 dis->next->prev = dis->prev;
703 dis->next = dis->prev = dis;
704 }
705
706
707 atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
708 {
709 atransport *t;
710 atransport *result = NULL;
711 int ambiguous = 0;
712
713 retry:
714 if (error_out)
715 *error_out = "device not found";
716
717 adb_mutex_lock(&transport_lock);
718 for (t = transport_list.next; t != &transport_list; t = t->next) {
719 /* check for matching serial number */
720 if (serial) {
721 if (t->serial && !strcmp(serial, t->serial)) {
722 result = t;
723 break;
724 }
725 } else {
726 if (ttype == kTransportUsb && t->type == kTransportUsb) {
727 if (result) {
728 if (error_out)
729 *error_out = "more than one device";
730 ambiguous = 1;
731 result = NULL;
732 break;
733 }
734 result = t;
735 } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
736 if (result) {
737 if (error_out)
738 *error_out = "more than one emulator";
739 ambiguous = 1;
740 result = NULL;
741 break;
742 }
743 result = t;
744 } else if (ttype == kTransportAny) {
745 if (result) {
746 if (error_out)
747 *error_out = "more than one device and emulator";
748 ambiguous = 1;
749 result = NULL;
750 break;
751 }
752 result = t;
753 }
754 }
755 }
756 adb_mutex_unlock(&transport_lock);
757
758 if (result) {
759 /* offline devices are ignored -- they are either being born or dying */
760 if (result && result->connection_state == CS_OFFLINE) {
761 if (error_out)
762 *error_out = "device offline";
763 result = NULL;
764 }
765
766 /* check for required connection state */
767 if (result && state != CS_ANY && result->connection_state != state) {
768 if (error_out)
769 *error_out = "invalid device state";
770 result = NULL;
771 }
772 }
773
774 if (result) {
775 /* found one that we can take */
776 if (error_out)
777 *error_out = NULL;
778 } else if (state != CS_ANY && (serial || !ambiguous)) {
779 adb_sleep_ms(1000);
780 goto retry;
781 }
782
783 return result;
784 }
785
786 #if ADB_HOST
787 static const char *statename(atransport *t)
788 {
789 switch(t->connection_state){
790 case CS_OFFLINE: return "offline";
791 case CS_BOOTLOADER: return "bootloader";
792 case CS_DEVICE: return "device";
793 case CS_HOST: return "host";
794 case CS_RECOVERY: return "recovery";
795 default: return "unknown";
796 }
797 }
798
799 int list_transports(char *buf, size_t bufsize)
800 {
801 char* p = buf;
802 char* end = buf + bufsize;
803 int len;
804 atransport *t;
805
806 /* XXX OVERRUN PROBLEMS XXX */
807 adb_mutex_lock(&transport_lock);
808 for(t = transport_list.next; t != &transport_list; t = t->next) {
809 len = snprintf(p, end - p, "%s\t%s\n",
810 t->serial ? t->serial : "",
811 statename(t));
812
813 if (p + len >= end) {
814 /* discard last line if buffer is too short */
815 break;
816 }
817 p += len;
818 }
819 p[0] = 0;
820 adb_mutex_unlock(&transport_lock);
821 return p - buf;
822 }
823
824
825 /* hack for osx */
826 void close_usb_devices()
827 {
828 atransport *t;
829
830 adb_mutex_lock(&transport_lock);
831 for(t = transport_list.next; t != &transport_list; t = t->next) {
832 if ( !t->kicked ) {
833 t->kicked = 1;
834 t->kick(t);
835 }
836 }
837 adb_mutex_unlock(&transport_lock);
838 }
839 #endif // ADB_HOST
840
841 void register_socket_transport(int s, const char *serial, int port)
842 {
843 atransport *t = calloc(1, sizeof(atransport));
844 D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
845 if ( init_socket_transport(t, s, port) < 0 ) {
846 adb_close(s);
847 free(t);
848 return;
849 }
850 if(serial) {
851 t->serial = strdup(serial);
852 }
853 register_transport(t);
854 }
855
856 void register_usb_transport(usb_handle *usb, const char *serial)
857 {
858 atransport *t = calloc(1, sizeof(atransport));
859 D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
860 serial ? serial : "");
861 init_usb_transport(t, usb);
862 if(serial) {
863 t->serial = strdup(serial);
864 }
865 register_transport(t);
866 }
867
868
869 #undef TRACE_TAG
870 #define TRACE_TAG TRACE_RWX
871
872 int readx(int fd, void *ptr, size_t len)
873 {
874 char *p = ptr;
875 int r;
876 #if ADB_TRACE
877 int len0 = len;
878 #endif
879 D("readx: %d %p %d\n", fd, ptr, (int)len);
880 while(len > 0) {
881 r = adb_read(fd, p, len);
882 if(r > 0) {
883 len -= r;
884 p += r;
885 } else {
886 D("readx: %d %d %s\n", fd, r, strerror(errno));
887 if((r < 0) && (errno == EINTR)) continue;
888 return -1;
889 }
890 }
891
892 #if ADB_TRACE
893 D("readx: %d ok: ", fd);
894 dump_hex( ptr, len0 );
895 #endif
896 return 0;
897 }
898
899 int writex(int fd, const void *ptr, size_t len)
900 {
901 char *p = (char*) ptr;
902 int r;
903
904 #if ADB_TRACE
905 D("writex: %d %p %d: ", fd, ptr, (int)len);
906 dump_hex( ptr, len );
907 #endif
908 while(len > 0) {
909 r = adb_write(fd, p, len);
910 if(r > 0) {
911 len -= r;
912 p += r;
913 } else {
914 D("writex: %d %d %s\n", fd, r, strerror(errno));
915 if((r < 0) && (errno == EINTR)) continue;
916 return -1;
917 }
918 }
919
920 D("writex: %d ok\n", fd);
921 return 0;
922 }
923
924 int check_header(apacket *p)
925 {
926 if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
927 D("check_header(): invalid magic\n");
928 return -1;
929 }
930
931 if(p->msg.data_length > MAX_PAYLOAD) {
932 D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
933 return -1;
934 }
935
936 return 0;
937 }
938
939 int check_data(apacket *p)
940 {
941 unsigned count, sum;
942 unsigned char *x;
943
944 count = p->msg.data_length;
945 x = p->data;
946 sum = 0;
947 while(count-- > 0) {
948 sum += *x++;
949 }
950
951 if(sum != p->msg.data_check) {
952 return -1;
953 } else {
954 return 0;
955 }
956 }
957
+0
-263
adb/transport_local.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #include "sysdeps.h"
22 #include <sys/types.h>
23
24 #define TRACE_TAG TRACE_TRANSPORT
25 #include "adb.h"
26
27 #ifdef __ppc__
28 #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
29 static inline void fix_endians(apacket *p)
30 {
31 p->msg.command = H4(p->msg.command);
32 p->msg.arg0 = H4(p->msg.arg0);
33 p->msg.arg1 = H4(p->msg.arg1);
34 p->msg.data_length = H4(p->msg.data_length);
35 p->msg.data_check = H4(p->msg.data_check);
36 p->msg.magic = H4(p->msg.magic);
37 }
38 #else
39 #define fix_endians(p) do {} while (0)
40 #endif
41
42 #if ADB_HOST
43 /* we keep a list of opened transports, transport 0 is bound to 5555,
44 * transport 1 to 5557, .. transport n to 5555 + n*2. the list is used
45 * to detect when we're trying to connect twice to a given local transport
46 */
47 #define ADB_LOCAL_TRANSPORT_MAX 16
48
49 ADB_MUTEX_DEFINE( local_transports_lock );
50
51 static atransport* local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
52 #endif /* ADB_HOST */
53
54 static int remote_read(apacket *p, atransport *t)
55 {
56 if(readx(t->sfd, &p->msg, sizeof(amessage))){
57 D("remote local: read terminated (message)\n");
58 return -1;
59 }
60
61 fix_endians(p);
62
63 #if 0 && defined __ppc__
64 D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
65 p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
66 #endif
67 if(check_header(p)) {
68 D("bad header: terminated (data)\n");
69 return -1;
70 }
71
72 if(readx(t->sfd, p->data, p->msg.data_length)){
73 D("remote local: terminated (data)\n");
74 return -1;
75 }
76
77 if(check_data(p)) {
78 D("bad data: terminated (data)\n");
79 return -1;
80 }
81
82 return 0;
83 }
84
85 static int remote_write(apacket *p, atransport *t)
86 {
87 int length = p->msg.data_length;
88
89 fix_endians(p);
90
91 #if 0 && defined __ppc__
92 D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
93 p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
94 #endif
95 if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
96 D("remote local: write terminated\n");
97 return -1;
98 }
99
100 return 0;
101 }
102
103
104 int local_connect(int port)
105 {
106 char buf[64];
107 int fd = -1;
108
109 #if ADB_HOST
110 const char *host = getenv("ADBHOST");
111 if (host) {
112 fd = socket_network_client(host, port, SOCK_STREAM);
113 }
114 #endif
115 if (fd < 0) {
116 fd = socket_loopback_client(port, SOCK_STREAM);
117 }
118
119 if (fd >= 0) {
120 D("client: connected on remote on fd %d\n", fd);
121 close_on_exec(fd);
122 disable_tcp_nagle(fd);
123 snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, port - 1);
124 register_socket_transport(fd, buf, port);
125 return 0;
126 }
127 return -1;
128 }
129
130
131 static void *client_socket_thread(void *x)
132 {
133 #if ADB_HOST
134 int port = ADB_LOCAL_TRANSPORT_PORT;
135 int count = ADB_LOCAL_TRANSPORT_MAX;
136
137 D("transport: client_socket_thread() starting\n");
138
139 /* try to connect to any number of running emulator instances */
140 /* this is only done when ADB starts up. later, each new emulator */
141 /* will send a message to ADB to indicate that is is starting up */
142 for ( ; count > 0; count--, port += 2 ) {
143 (void) local_connect(port);
144 }
145 #endif
146 return 0;
147 }
148
149 static void *server_socket_thread(void *x)
150 {
151 int serverfd, fd;
152 struct sockaddr addr;
153 socklen_t alen;
154
155 D("transport: server_socket_thread() starting\n");
156 serverfd = -1;
157 for(;;) {
158 if(serverfd == -1) {
159 serverfd = socket_inaddr_any_server(ADB_LOCAL_TRANSPORT_PORT, SOCK_STREAM);
160 if(serverfd < 0) {
161 D("server: cannot bind socket yet\n");
162 adb_sleep_ms(1000);
163 continue;
164 }
165 close_on_exec(serverfd);
166 }
167
168 alen = sizeof(addr);
169 D("server: trying to get new connection from %d\n", ADB_LOCAL_TRANSPORT_PORT);
170 fd = adb_socket_accept(serverfd, &addr, &alen);
171 if(fd >= 0) {
172 D("server: new connection on fd %d\n", fd);
173 close_on_exec(fd);
174 disable_tcp_nagle(fd);
175 register_socket_transport(fd,"host",ADB_LOCAL_TRANSPORT_PORT);
176 }
177 }
178 D("transport: server_socket_thread() exiting\n");
179 return 0;
180 }
181
182 void local_init(void)
183 {
184 adb_thread_t thr;
185 void* (*func)(void *);
186
187 if(HOST) {
188 func = client_socket_thread;
189 } else {
190 func = server_socket_thread;
191 }
192
193 D("transport: local %s init\n", HOST ? "client" : "server");
194
195 if(adb_thread_create(&thr, func, 0)) {
196 fatal_errno("cannot create local socket %s thread",
197 HOST ? "client" : "server");
198 }
199 }
200
201 static void remote_kick(atransport *t)
202 {
203 int fd = t->sfd;
204 t->sfd = -1;
205 adb_close(fd);
206
207 #if ADB_HOST
208 if(HOST) {
209 int nn;
210 adb_mutex_lock( &local_transports_lock );
211 for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
212 if (local_transports[nn] == t) {
213 local_transports[nn] = NULL;
214 break;
215 }
216 }
217 adb_mutex_unlock( &local_transports_lock );
218 }
219 #endif
220 }
221
222 static void remote_close(atransport *t)
223 {
224 adb_close(t->fd);
225 }
226
227 int init_socket_transport(atransport *t, int s, int port)
228 {
229 int fail = 0;
230
231 t->kick = remote_kick;
232 t->close = remote_close;
233 t->read_from_remote = remote_read;
234 t->write_to_remote = remote_write;
235 t->sfd = s;
236 t->sync_token = 1;
237 t->connection_state = CS_OFFLINE;
238 t->type = kTransportLocal;
239
240 #if ADB_HOST
241 if (HOST) {
242 adb_mutex_lock( &local_transports_lock );
243 {
244 int index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;
245
246 if (!(port & 1) || index < 0 || index >= ADB_LOCAL_TRANSPORT_MAX) {
247 D("bad local transport port number: %d\n", port);
248 fail = -1;
249 }
250 else if (local_transports[index] != NULL) {
251 D("local transport for port %d already registered (%p)?\n",
252 port, local_transports[index]);
253 fail = -1;
254 }
255 else
256 local_transports[index] = t;
257 }
258 adb_mutex_unlock( &local_transports_lock );
259 }
260 #endif
261 return fail;
262 }
+0
-147
adb/transport_usb.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <sysdeps.h>
21
22 #define TRACE_TAG TRACE_TRANSPORT
23 #include "adb.h"
24
25 /* XXX better define? */
26 #ifdef __ppc__
27 #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
28 static inline void fix_endians(apacket *p)
29 {
30 p->msg.command = H4(p->msg.command);
31 p->msg.arg0 = H4(p->msg.arg0);
32 p->msg.arg1 = H4(p->msg.arg1);
33 p->msg.data_length = H4(p->msg.data_length);
34 p->msg.data_check = H4(p->msg.data_check);
35 p->msg.magic = H4(p->msg.magic);
36 }
37 unsigned host_to_le32(unsigned n)
38 {
39 return H4(n);
40 }
41 #else
42 #define fix_endians(p) do {} while (0)
43 unsigned host_to_le32(unsigned n)
44 {
45 return n;
46 }
47 #endif
48
49 static int remote_read(apacket *p, atransport *t)
50 {
51 if(usb_read(t->usb, &p->msg, sizeof(amessage))){
52 D("remote usb: read terminated (message)\n");
53 return -1;
54 }
55
56 fix_endians(p);
57
58 if(check_header(p)) {
59 D("remote usb: check_header failed\n");
60 return -1;
61 }
62
63 if(p->msg.data_length) {
64 if(usb_read(t->usb, p->data, p->msg.data_length)){
65 D("remote usb: terminated (data)\n");
66 return -1;
67 }
68 }
69
70 if(check_data(p)) {
71 D("remote usb: check_data failed\n");
72 return -1;
73 }
74
75 return 0;
76 }
77
78 static int remote_write(apacket *p, atransport *t)
79 {
80 unsigned size = p->msg.data_length;
81
82 fix_endians(p);
83
84 if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
85 D("remote usb: 1 - write terminated\n");
86 return -1;
87 }
88 if(p->msg.data_length == 0) return 0;
89 if(usb_write(t->usb, &p->data, size)) {
90 D("remote usb: 2 - write terminated\n");
91 return -1;
92 }
93
94 return 0;
95 }
96
97 static void remote_close(atransport *t)
98 {
99 usb_close(t->usb);
100 t->usb = 0;
101 }
102
103 static void remote_kick(atransport *t)
104 {
105 usb_kick(t->usb);
106 }
107
108 void init_usb_transport(atransport *t, usb_handle *h)
109 {
110 D("transport: usb\n");
111 t->close = remote_close;
112 t->kick = remote_kick;
113 t->read_from_remote = remote_read;
114 t->write_to_remote = remote_write;
115 t->sync_token = 1;
116 t->connection_state = CS_OFFLINE;
117 t->type = kTransportUsb;
118 t->usb = h;
119
120 #if ADB_HOST
121 HOST = 1;
122 #else
123 HOST = 0;
124 #endif
125 }
126
127 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
128 {
129 if (vid == VENDOR_ID_GOOGLE) {
130 /* might support adb */
131 } else if (vid == VENDOR_ID_HTC) {
132 /* might support adb */
133 } else {
134 /* not supported */
135 return 0;
136 }
137
138 /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
139 if(usb_class == 0xff) {
140 if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
141 return 1;
142 }
143 }
144
145 return 0;
146 }
+0
-654
adb/usb_linux.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <ctype.h>
27
28 #include <linux/usbdevice_fs.h>
29 #include <linux/version.h>
30 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
31 #include <linux/usb/ch9.h>
32 #else
33 #include <linux/usb_ch9.h>
34 #endif
35 #include <asm/byteorder.h>
36
37 #include "sysdeps.h"
38
39 #define TRACE_TAG TRACE_USB
40 #include "adb.h"
41
42
43 /* usb scan debugging is waaaay too verbose */
44 #define DBGX(x...)
45
46 static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
47
48 struct usb_handle
49 {
50 usb_handle *prev;
51 usb_handle *next;
52
53 char fname[64];
54 int desc;
55 unsigned char ep_in;
56 unsigned char ep_out;
57
58 unsigned zero_mask;
59
60 struct usbdevfs_urb urb_in;
61 struct usbdevfs_urb urb_out;
62
63 int urb_in_busy;
64 int urb_out_busy;
65 int dead;
66
67 adb_cond_t notify;
68 adb_mutex_t lock;
69
70 // for garbage collecting disconnected devices
71 int mark;
72
73 // ID of thread currently in REAPURB
74 pthread_t reaper_thread;
75 };
76
77 static usb_handle handle_list = {
78 .prev = &handle_list,
79 .next = &handle_list,
80 };
81
82 static int known_device(const char *dev_name)
83 {
84 usb_handle *usb;
85
86 adb_mutex_lock(&usb_lock);
87 for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
88 if(!strcmp(usb->fname, dev_name)) {
89 // set mark flag to indicate this device is still alive
90 usb->mark = 1;
91 adb_mutex_unlock(&usb_lock);
92 return 1;
93 }
94 }
95 adb_mutex_unlock(&usb_lock);
96 return 0;
97 }
98
99 static void kick_disconnected_devices()
100 {
101 usb_handle *usb;
102
103 adb_mutex_lock(&usb_lock);
104 // kick any devices in the device list that were not found in the device scan
105 for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
106 if (usb->mark == 0) {
107 usb_kick(usb);
108 } else {
109 usb->mark = 0;
110 }
111 }
112 adb_mutex_unlock(&usb_lock);
113
114 }
115
116 static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
117 int ifc, const char *serial, unsigned zero_mask);
118
119 static inline int badname(const char *name)
120 {
121 while(*name) {
122 if(!isdigit(*name++)) return 1;
123 }
124 return 0;
125 }
126
127 static int find_usb_device(const char *base,
128 void (*register_device_callback) (const char *, unsigned char, unsigned char, int, const char *, unsigned))
129 {
130 char busname[32], devname[32];
131 unsigned char local_ep_in, local_ep_out;
132 DIR *busdir , *devdir ;
133 struct dirent *de;
134 int fd ;
135 int found_device = 0;
136 char serial[256];
137
138 busdir = opendir(base);
139 if(busdir == 0) return 0;
140
141 while((de = readdir(busdir)) != 0) {
142 if(badname(de->d_name)) continue;
143
144 snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
145 devdir = opendir(busname);
146 if(devdir == 0) continue;
147
148 // DBGX("[ scanning %s ]\n", busname);
149 while((de = readdir(devdir))) {
150 unsigned char devdesc[256];
151 unsigned char* bufptr = devdesc;
152 struct usb_device_descriptor* device;
153 struct usb_config_descriptor* config;
154 struct usb_interface_descriptor* interface;
155 struct usb_endpoint_descriptor *ep1, *ep2;
156 unsigned zero_mask = 0;
157 unsigned vid, pid;
158 int i, interfaces;
159 size_t desclength;
160
161 if(badname(de->d_name)) continue;
162 snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
163
164 if(known_device(devname)) {
165 DBGX("skipping %s\n", devname);
166 continue;
167 }
168
169 // DBGX("[ scanning %s ]\n", devname);
170 if((fd = unix_open(devname, O_RDWR)) < 0) {
171 continue;
172 }
173
174 desclength = adb_read(fd, devdesc, sizeof(devdesc));
175
176 // should have device and configuration descriptors, and atleast two endpoints
177 if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
178 D("desclength %d is too small\n", desclength);
179 adb_close(fd);
180 continue;
181 }
182
183 device = (struct usb_device_descriptor*)bufptr;
184 bufptr += USB_DT_DEVICE_SIZE;
185
186 if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
187 adb_close(fd);
188 continue;
189 }
190
191 vid = __le16_to_cpu(device->idVendor);
192 pid = __le16_to_cpu(device->idProduct);
193 pid = devdesc[10] | (devdesc[11] << 8);
194 DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
195
196 // should have config descriptor next
197 config = (struct usb_config_descriptor *)bufptr;
198 bufptr += USB_DT_CONFIG_SIZE;
199 if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
200 D("usb_config_descriptor not found\n");
201 adb_close(fd);
202 continue;
203 }
204
205 // loop through all the interfaces and look for the ADB interface
206 interfaces = config->bNumInterfaces;
207 for (i = 0; i < interfaces; i++) {
208 if (bufptr + USB_DT_ENDPOINT_SIZE > devdesc + desclength)
209 break;
210
211 interface = (struct usb_interface_descriptor *)bufptr;
212 bufptr += USB_DT_INTERFACE_SIZE;
213 if (interface->bLength != USB_DT_INTERFACE_SIZE ||
214 interface->bDescriptorType != USB_DT_INTERFACE) {
215 D("usb_interface_descriptor not found\n");
216 break;
217 }
218
219 DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d,"
220 "bInterfaceProtocol: %d, bNumEndpoints: %d\n",
221 interface->bInterfaceClass, interface->bInterfaceSubClass,
222 interface->bInterfaceProtocol, interface->bNumEndpoints);
223
224 if (interface->bNumEndpoints == 2 &&
225 is_adb_interface(vid, pid, interface->bInterfaceClass,
226 interface->bInterfaceSubClass, interface->bInterfaceProtocol)) {
227
228 DBGX("looking for bulk endpoints\n");
229 // looks like ADB...
230 ep1 = (struct usb_endpoint_descriptor *)bufptr;
231 bufptr += USB_DT_ENDPOINT_SIZE;
232 ep2 = (struct usb_endpoint_descriptor *)bufptr;
233 bufptr += USB_DT_ENDPOINT_SIZE;
234
235 if (bufptr > devdesc + desclength ||
236 ep1->bLength != USB_DT_ENDPOINT_SIZE ||
237 ep1->bDescriptorType != USB_DT_ENDPOINT ||
238 ep2->bLength != USB_DT_ENDPOINT_SIZE ||
239 ep2->bDescriptorType != USB_DT_ENDPOINT) {
240 D("endpoints not found\n");
241 break;
242 }
243
244 // both endpoints should be bulk
245 if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
246 ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
247 D("bulk endpoints not found\n");
248 continue;
249 }
250
251 /* aproto 01 needs 0 termination */
252 if(interface->bInterfaceProtocol == 0x01) {
253 zero_mask = ep1->wMaxPacketSize - 1;
254 }
255
256 // we have a match. now we just need to figure out which is in and which is out.
257 if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
258 local_ep_in = ep1->bEndpointAddress;
259 local_ep_out = ep2->bEndpointAddress;
260 } else {
261 local_ep_in = ep2->bEndpointAddress;
262 local_ep_out = ep1->bEndpointAddress;
263 }
264
265 // read the device's serial number
266 serial[0] = 0;
267 memset(serial, 0, sizeof(serial));
268 if (device->iSerialNumber) {
269 struct usbdevfs_ctrltransfer ctrl;
270 __u16 buffer[128];
271 int result;
272
273 memset(buffer, 0, sizeof(buffer));
274 memset(&ctrl, 0, sizeof(ctrl));
275
276 ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
277 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
278 ctrl.wValue = (USB_DT_STRING << 8) | device->iSerialNumber;
279 ctrl.wIndex = 0;
280 ctrl.wLength = sizeof(buffer);
281 ctrl.data = buffer;
282
283 result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
284 if (result > 0) {
285 int i;
286 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
287 result /= 2;
288 for (i = 1; i < result; i++)
289 serial[i - 1] = buffer[i];
290 serial[i - 1] = 0;
291 }
292 }
293
294 register_device_callback(devname, local_ep_in, local_ep_out,
295 interface->bInterfaceNumber, serial, zero_mask);
296
297 found_device = 1;
298 break;
299 } else {
300 // skip to next interface
301 bufptr += (interface->bNumEndpoints * USB_DT_ENDPOINT_SIZE);
302 }
303 } // end of for
304
305 adb_close(fd);
306 } // end of devdir while
307 closedir(devdir);
308 } //end of busdir while
309 closedir(busdir);
310
311 return found_device;
312 }
313
314 void usb_cleanup()
315 {
316 }
317
318 static int usb_bulk_write(usb_handle *h, const void *data, int len)
319 {
320 struct usbdevfs_urb *urb = &h->urb_out;
321 int res;
322
323 memset(urb, 0, sizeof(*urb));
324 urb->type = USBDEVFS_URB_TYPE_BULK;
325 urb->endpoint = h->ep_out;
326 urb->status = -1;
327 urb->buffer = (void*) data;
328 urb->buffer_length = len;
329
330 D("++ write ++\n");
331
332 adb_mutex_lock(&h->lock);
333 if(h->dead) {
334 res = -1;
335 goto fail;
336 }
337 do {
338 res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
339 } while((res < 0) && (errno == EINTR));
340
341 if(res < 0) {
342 goto fail;
343 }
344
345 res = -1;
346 h->urb_out_busy = 1;
347 for(;;) {
348 adb_cond_wait(&h->notify, &h->lock);
349 if(h->dead) {
350 break;
351 }
352 if(h->urb_out_busy == 0) {
353 if(urb->status == 0) {
354 res = urb->actual_length;
355 }
356 break;
357 }
358 }
359 fail:
360 adb_mutex_unlock(&h->lock);
361 D("-- write --\n");
362 return res;
363 }
364
365 static int usb_bulk_read(usb_handle *h, void *data, int len)
366 {
367 struct usbdevfs_urb *urb = &h->urb_in;
368 struct usbdevfs_urb *out = NULL;
369 int res;
370
371 memset(urb, 0, sizeof(*urb));
372 urb->type = USBDEVFS_URB_TYPE_BULK;
373 urb->endpoint = h->ep_in;
374 urb->status = -1;
375 urb->buffer = data;
376 urb->buffer_length = len;
377
378
379 adb_mutex_lock(&h->lock);
380 if(h->dead) {
381 res = -1;
382 goto fail;
383 }
384 do {
385 res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
386 } while((res < 0) && (errno == EINTR));
387
388 if(res < 0) {
389 goto fail;
390 }
391
392 h->urb_in_busy = 1;
393 for(;;) {
394 D("[ reap urb - wait ]\n");
395 h->reaper_thread = pthread_self();
396 adb_mutex_unlock(&h->lock);
397 res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
398 adb_mutex_lock(&h->lock);
399 h->reaper_thread = 0;
400 if(h->dead) {
401 res = -1;
402 break;
403 }
404 if(res < 0) {
405 if(errno == EINTR) {
406 continue;
407 }
408 D("[ reap urb - error ]\n");
409 break;
410 }
411 D("[ urb @%p status = %d, actual = %d ]\n",
412 out, out->status, out->actual_length);
413
414 if(out == &h->urb_in) {
415 D("[ reap urb - IN complete ]\n");
416 h->urb_in_busy = 0;
417 if(urb->status == 0) {
418 res = urb->actual_length;
419 } else {
420 res = -1;
421 }
422 break;
423 }
424 if(out == &h->urb_out) {
425 D("[ reap urb - OUT compelete ]\n");
426 h->urb_out_busy = 0;
427 adb_cond_broadcast(&h->notify);
428 }
429 }
430 fail:
431 adb_mutex_unlock(&h->lock);
432 return res;
433 }
434
435
436 int usb_write(usb_handle *h, const void *_data, int len)
437 {
438 unsigned char *data = (unsigned char*) _data;
439 int n;
440 int need_zero = 0;
441
442 if(h->zero_mask) {
443 /* if we need 0-markers and our transfer
444 ** is an even multiple of the packet size,
445 ** we make note of it
446 */
447 if(!(len & h->zero_mask)) {
448 need_zero = 1;
449 }
450 }
451
452 while(len > 0) {
453 int xfer = (len > 4096) ? 4096 : len;
454
455 n = usb_bulk_write(h, data, xfer);
456 if(n != xfer) {
457 D("ERROR: n = %d, errno = %d (%s)\n",
458 n, errno, strerror(errno));
459 return -1;
460 }
461
462 len -= xfer;
463 data += xfer;
464 }
465
466 if(need_zero){
467 n = usb_bulk_write(h, _data, 0);
468 return n;
469 }
470
471 return 0;
472 }
473
474 int usb_read(usb_handle *h, void *_data, int len)
475 {
476 unsigned char *data = (unsigned char*) _data;
477 int n;
478
479 D("++ usb_read ++\n");
480 while(len > 0) {
481 int xfer = (len > 4096) ? 4096 : len;
482
483 D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
484 n = usb_bulk_read(h, data, xfer);
485 D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
486 if(n != xfer) {
487 if((errno == ETIMEDOUT) && (h->desc != -1)) {
488 D("[ timeout ]\n");
489 if(n > 0){
490 data += n;
491 len -= n;
492 }
493 continue;
494 }
495 D("ERROR: n = %d, errno = %d (%s)\n",
496 n, errno, strerror(errno));
497 return -1;
498 }
499
500 len -= xfer;
501 data += xfer;
502 }
503
504 D("-- usb_read --\n");
505 return 0;
506 }
507
508 void usb_kick(usb_handle *h)
509 {
510 D("[ kicking %p (fd = %d) ]\n", h, h->desc);
511 adb_mutex_lock(&h->lock);
512 if(h->dead == 0) {
513 h->dead = 1;
514
515 /* HACK ALERT!
516 ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
517 ** This is a workaround for that problem.
518 */
519 if (h->reaper_thread) {
520 pthread_kill(h->reaper_thread, SIGALRM);
521 }
522
523 /* cancel any pending transactions
524 ** these will quietly fail if the txns are not active,
525 ** but this ensures that a reader blocked on REAPURB
526 ** will get unblocked
527 */
528 ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
529 ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
530 h->urb_in.status = -ENODEV;
531 h->urb_out.status = -ENODEV;
532 h->urb_in_busy = 0;
533 h->urb_out_busy = 0;
534 adb_cond_broadcast(&h->notify);
535 }
536 adb_mutex_unlock(&h->lock);
537 }
538
539 int usb_close(usb_handle *h)
540 {
541 D("[ usb close ... ]\n");
542 adb_mutex_lock(&usb_lock);
543 h->next->prev = h->prev;
544 h->prev->next = h->next;
545 h->prev = 0;
546 h->next = 0;
547
548 adb_close(h->desc);
549 D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
550 adb_mutex_unlock(&usb_lock);
551
552 free(h);
553 return 0;
554 }
555
556 static void register_device(const char *dev_name,
557 unsigned char ep_in, unsigned char ep_out,
558 int interface,
559 const char *serial, unsigned zero_mask)
560 {
561 usb_handle* usb = 0;
562 int n = 0;
563
564 /* Since Linux will not reassign the device ID (and dev_name)
565 ** as long as the device is open, we can add to the list here
566 ** once we open it and remove from the list when we're finally
567 ** closed and everything will work out fine.
568 **
569 ** If we have a usb_handle on the list 'o handles with a matching
570 ** name, we have no further work to do.
571 */
572 adb_mutex_lock(&usb_lock);
573 for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
574 if(!strcmp(usb->fname, dev_name)) {
575 adb_mutex_unlock(&usb_lock);
576 return;
577 }
578 }
579 adb_mutex_unlock(&usb_lock);
580
581 D("[ usb located new device %s (%d/%d/%d) ]\n",
582 dev_name, ep_in, ep_out, interface);
583 usb = calloc(1, sizeof(usb_handle));
584 strcpy(usb->fname, dev_name);
585 usb->ep_in = ep_in;
586 usb->ep_out = ep_out;
587 usb->zero_mask = zero_mask;
588
589 adb_cond_init(&usb->notify, 0);
590 adb_mutex_init(&usb->lock, 0);
591 /* initialize mark to 1 so we don't get garbage collected after the device scan */
592 usb->mark = 1;
593 usb->reaper_thread = 0;
594
595 usb->desc = unix_open(usb->fname, O_RDWR);
596 if(usb->desc < 0) goto fail;
597 D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
598 n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
599 if(n != 0) goto fail;
600
601 /* add to the end of the active handles */
602 adb_mutex_lock(&usb_lock);
603 usb->next = &handle_list;
604 usb->prev = handle_list.prev;
605 usb->prev->next = usb;
606 usb->next->prev = usb;
607 adb_mutex_unlock(&usb_lock);
608
609 register_usb_transport(usb, serial);
610 return;
611
612 fail:
613 D("[ usb open %s error=%d, err_str = %s]\n",
614 usb->fname, errno, strerror(errno));
615 if(usb->desc >= 0) {
616 adb_close(usb->desc);
617 }
618 free(usb);
619 }
620
621 void* device_poll_thread(void* unused)
622 {
623 D("Created device thread\n");
624 for(;;) {
625 /* XXX use inotify */
626 find_usb_device("/dev/bus/usb", register_device);
627 kick_disconnected_devices();
628 sleep(1);
629 }
630 return NULL;
631 }
632
633 static void sigalrm_handler(int signo)
634 {
635 // don't need to do anything here
636 }
637
638 void usb_init()
639 {
640 adb_thread_t tid;
641 struct sigaction actions;
642
643 memset(&actions, 0, sizeof(actions));
644 sigemptyset(&actions.sa_mask);
645 actions.sa_flags = 0;
646 actions.sa_handler = sigalrm_handler;
647 sigaction(SIGALRM,& actions, NULL);
648
649 if(adb_thread_create(&tid, device_poll_thread, NULL)){
650 fatal_errno("cannot create input thread");
651 }
652 }
653
+0
-156
adb/usb_linux_client.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <errno.h>
25
26 #include "sysdeps.h"
27
28 #define TRACE_TAG TRACE_USB
29 #include "adb.h"
30
31
32 struct usb_handle
33 {
34 int fd;
35 adb_cond_t notify;
36 adb_mutex_t lock;
37 };
38
39 void usb_cleanup()
40 {
41 // nothing to do here
42 }
43
44 static void *usb_open_thread(void *x)
45 {
46 struct usb_handle *usb = (struct usb_handle *)x;
47 int fd;
48
49 while (1) {
50 // wait until the USB device needs opening
51 adb_mutex_lock(&usb->lock);
52 while (usb->fd != -1)
53 adb_cond_wait(&usb->notify, &usb->lock);
54 adb_mutex_unlock(&usb->lock);
55
56 D("[ usb_thread - opening device ]\n");
57 do {
58 /* XXX use inotify? */
59 fd = unix_open("/dev/android_adb", O_RDWR);
60 if (fd < 0) {
61 // to support older kernels
62 fd = unix_open("/dev/android", O_RDWR);
63 }
64 if (fd < 0) {
65 adb_sleep_ms(1000);
66 }
67 } while (fd < 0);
68 D("[ opening device succeeded ]\n");
69
70 close_on_exec(fd);
71 usb->fd = fd;
72
73 D("[ usb_thread - registering device ]\n");
74 register_usb_transport(usb, 0);
75 }
76
77 // never gets here
78 return 0;
79 }
80
81 int usb_write(usb_handle *h, const void *data, int len)
82 {
83 int n;
84
85 D("[ write %d ]\n", len);
86 n = adb_write(h->fd, data, len);
87 if(n != len) {
88 D("ERROR: n = %d, errno = %d (%s)\n",
89 n, errno, strerror(errno));
90 return -1;
91 }
92 D("[ done ]\n");
93 return 0;
94 }
95
96 int usb_read(usb_handle *h, void *data, int len)
97 {
98 int n;
99
100 D("[ read %d ]\n", len);
101 n = adb_read(h->fd, data, len);
102 if(n != len) {
103 D("ERROR: n = %d, errno = %d (%s)\n",
104 n, errno, strerror(errno));
105 return -1;
106 }
107 return 0;
108 }
109
110 void usb_init()
111 {
112 usb_handle *h;
113 adb_thread_t tid;
114 int fd;
115
116 h = calloc(1, sizeof(usb_handle));
117 h->fd = -1;
118 adb_cond_init(&h->notify, 0);
119 adb_mutex_init(&h->lock, 0);
120
121 // Open the file /dev/android_adb_enable to trigger
122 // the enabling of the adb USB function in the kernel.
123 // We never touch this file again - just leave it open
124 // indefinitely so the kernel will know when we are running
125 // and when we are not.
126 fd = unix_open("/dev/android_adb_enable", O_RDWR);
127 if (fd < 0) {
128 D("failed to open /dev/android_adb_enable\n");
129 } else {
130 close_on_exec(fd);
131 }
132
133 D("[ usb_init - starting thread ]\n");
134 if(adb_thread_create(&tid, usb_open_thread, h)){
135 fatal_errno("cannot create usb thread");
136 }
137 }
138
139 void usb_kick(usb_handle *h)
140 {
141 D("usb_kick\n");
142 adb_mutex_lock(&h->lock);
143 adb_close(h->fd);
144 h->fd = -1;
145
146 // notify usb_open_thread that we are disconnected
147 adb_cond_signal(&h->notify);
148 adb_mutex_unlock(&h->lock);
149 }
150
151 int usb_close(usb_handle *h)
152 {
153 // nothing to do here
154 return 0;
155 }
+0
-536
adb/usb_osx.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <CoreFoundation/CoreFoundation.h>
17
18 #include <IOKit/IOKitLib.h>
19 #include <IOKit/IOCFPlugIn.h>
20 #include <IOKit/usb/IOUSBLib.h>
21 #include <IOKit/IOMessage.h>
22 #include <mach/mach_port.h>
23
24 #include "sysdeps.h"
25
26 #include <stdio.h>
27
28 #define TRACE_TAG TRACE_USB
29 #include "adb.h"
30
31 #define DBG D
32
33 typedef struct {
34 int vid;
35 int pid;
36 } VendorProduct;
37
38 #define kSupportedDeviceCount 4
39 VendorProduct kSupportedDevices[kSupportedDeviceCount] = {
40 { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER },
41 { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER_COMP },
42 { VENDOR_ID_HTC, PRODUCT_ID_DREAM },
43 { VENDOR_ID_HTC, PRODUCT_ID_DREAM_COMP },
44 };
45
46 static IONotificationPortRef notificationPort = 0;
47 static io_iterator_t notificationIterators[kSupportedDeviceCount];
48
49 struct usb_handle
50 {
51 UInt8 bulkIn;
52 UInt8 bulkOut;
53 IOUSBInterfaceInterface **interface;
54 io_object_t usbNotification;
55 unsigned int zero_mask;
56 };
57
58 static CFRunLoopRef currentRunLoop = 0;
59 static pthread_mutex_t start_lock;
60 static pthread_cond_t start_cond;
61
62
63 static void AndroidDeviceAdded(void *refCon, io_iterator_t iterator);
64 static void AndroidDeviceNotify(void *refCon, io_iterator_t iterator, natural_t messageType, void *messageArgument);
65 static usb_handle* FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product);
66
67 static int
68 InitUSB()
69 {
70 CFMutableDictionaryRef matchingDict;
71 CFRunLoopSourceRef runLoopSource;
72 SInt32 vendor, product;
73 int i;
74
75 //* To set up asynchronous notifications, create a notification port and
76 //* add its run loop event source to the program's run loop
77 notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
78 runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
79 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
80
81 memset(notificationIterators, 0, sizeof(notificationIterators));
82
83 //* loop through all supported vendor/product pairs
84 for (i = 0; i < kSupportedDeviceCount; i++) {
85 //* Create our matching dictionary to find the Android device
86 //* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
87 matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
88
89 if (!matchingDict) {
90 DBG("ERR: Couldn't create USB matching dictionary.\n");
91 return -1;
92 }
93
94 //* Set up two matching dictionaries, one for each product ID we support.
95 //* This will cause the kernel to notify us only if the vendor and product IDs match.
96 vendor = kSupportedDevices[i].vid;
97 product = kSupportedDevices[i].pid;
98 CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
99 CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
100
101 //* Now set up two notifications: one to be called when a raw device
102 //* is first matched by the I/O Kit and another to be called when the
103 //* device is terminated.
104 //* we need to do this with each matching dictionary.
105 IOServiceAddMatchingNotification(
106 notificationPort,
107 kIOFirstMatchNotification,
108 matchingDict,
109 AndroidDeviceAdded,
110 NULL,
111 &notificationIterators[i]);
112
113 //* Iterate over set of matching devices to access already-present devices
114 //* and to arm the notification
115 AndroidDeviceAdded(NULL, notificationIterators[i]);
116 }
117
118 return 0;
119 }
120
121 static void
122 AndroidDeviceAdded(void *refCon, io_iterator_t iterator)
123 {
124 kern_return_t kr;
125 io_service_t usbDevice;
126 IOCFPlugInInterface **plugInInterface = NULL;
127 IOUSBDeviceInterface182 **dev = NULL;
128 HRESULT result;
129 SInt32 score;
130 UInt16 vendor;
131 UInt16 product;
132 UInt8 serialIndex;
133 char serial[256];
134
135 while ((usbDevice = IOIteratorNext(iterator))) {
136 //* Create an intermediate plugin
137 kr = IOCreatePlugInInterfaceForService(usbDevice,
138 kIOUSBDeviceUserClientTypeID,
139 kIOCFPlugInInterfaceID,
140 &plugInInterface, &score);
141
142 if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
143 DBG("ERR: Unable to create a plug-in (%08x)\n", kr);
144 goto continue1;
145 }
146
147 //* Now create the device interface
148 result = (*plugInInterface)->QueryInterface(plugInInterface,
149 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
150
151 if (result || !dev) {
152 DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result);
153 goto continue2;
154 }
155
156 //* Check the device to see if it's ours
157 kr = (*dev)->GetDeviceVendor(dev, &vendor);
158 kr = (*dev)->GetDeviceProduct(dev, &product);
159 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
160
161 if (serialIndex > 0) {
162 IOUSBDevRequest req;
163 UInt16 buffer[256];
164
165 req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
166 req.bRequest = kUSBRqGetDescriptor;
167 req.wValue = (kUSBStringDesc << 8) | serialIndex;
168 req.wIndex = 0;
169 req.pData = buffer;
170 req.wLength = sizeof(buffer);
171 kr = (*dev)->DeviceRequest(dev, &req);
172
173 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
174 int i, count;
175
176 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
177 count = (req.wLenDone - 1) / 2;
178 for (i = 0; i < count; i++)
179 serial[i] = buffer[i + 1];
180 serial[i] = 0;
181 }
182 }
183
184 usb_handle* handle = NULL;
185
186 //* Open the device
187 kr = (*dev)->USBDeviceOpen(dev);
188
189 if (kr != kIOReturnSuccess) {
190 DBG("ERR: Could not open device: %08x\n", kr);
191 goto continue3;
192 } else {
193 //* Find an interface for the device
194 handle = FindDeviceInterface((IOUSBDeviceInterface**)dev, vendor, product);
195 }
196
197 if (handle == NULL) {
198 DBG("ERR: Could not find device interface: %08x\n", kr);
199 (*dev)->USBDeviceClose(dev);
200 goto continue3;
201 }
202
203 DBG("AndroidDeviceAdded calling register_usb_transport\n");
204 register_usb_transport(handle, (serial[0] ? serial : NULL));
205
206 // Register for an interest notification of this device being removed. Pass the reference to our
207 // private data as the refCon for the notification.
208 kr = IOServiceAddInterestNotification(notificationPort,
209 usbDevice,
210 kIOGeneralInterest,
211 AndroidDeviceNotify,
212 handle,
213 &handle->usbNotification);
214 if (kIOReturnSuccess != kr) {
215 DBG("ERR: Unable to create interest notification (%08x)\n", kr);
216 }
217
218 continue3:
219 (void)(*dev)->Release(dev);
220 continue2:
221 IODestroyPlugInInterface(plugInInterface);
222 continue1:
223 IOObjectRelease(usbDevice);
224 }
225 }
226
227 static void
228 AndroidDeviceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
229 {
230 usb_handle *handle = (usb_handle *)refCon;
231
232 if (messageType == kIOMessageServiceIsTerminated) {
233 DBG("AndroidDeviceNotify\n");
234 IOObjectRelease(handle->usbNotification);
235 usb_kick(handle);
236 }
237 }
238
239 static usb_handle*
240 FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product)
241 {
242 usb_handle* handle = NULL;
243 IOReturn kr;
244 IOUSBFindInterfaceRequest request;
245 io_iterator_t iterator;
246 io_service_t usbInterface;
247 IOCFPlugInInterface **plugInInterface;
248 IOUSBInterfaceInterface **interface = NULL;
249 HRESULT result;
250 SInt32 score;
251 UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
252 UInt8 endpoint, configuration;
253
254 //* Placing the constant KIOUSBFindInterfaceDontCare into the following
255 //* fields of the IOUSBFindInterfaceRequest structure will allow us to
256 //* find all of the interfaces
257 request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
258 request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
259 request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
260 request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
261
262 //* SetConfiguration will kill an existing UMS connection, so let's not do this if not necessary.
263 configuration = 0;
264 (*dev)->GetConfiguration(dev, &configuration);
265 if (configuration != 1)
266 (*dev)->SetConfiguration(dev, 1);
267
268 //* Get an iterator for the interfaces on the device
269 kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
270
271 if (kr != kIOReturnSuccess) {
272 DBG("ERR: Couldn't create a device interface iterator: (%08x)\n", kr);
273 return NULL;
274 }
275
276 while ((usbInterface = IOIteratorNext(iterator))) {
277 //* Create an intermediate plugin
278 kr = IOCreatePlugInInterfaceForService(
279 usbInterface,
280 kIOUSBInterfaceUserClientTypeID,
281 kIOCFPlugInInterfaceID,
282 &plugInInterface,
283 &score);
284
285 //* No longer need the usbInterface object now that we have the plugin
286 (void) IOObjectRelease(usbInterface);
287
288 if ((kr != kIOReturnSuccess) || (!plugInInterface)) {
289 DBG("ERR: Unable to create plugin (%08x)\n", kr);
290 break;
291 }
292
293 //* Now create the interface interface for the interface
294 result = (*plugInInterface)->QueryInterface(
295 plugInInterface,
296 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
297 (LPVOID) &interface);
298
299 //* No longer need the intermediate plugin
300 (*plugInInterface)->Release(plugInInterface);
301
302 if (result || !interface) {
303 DBG("ERR: Couldn't create interface interface: (%08x)\n",
304 (unsigned int) result);
305 break;
306 }
307
308 //* Now open the interface. This will cause the pipes associated with
309 //* the endpoints in the interface descriptor to be instantiated
310 kr = (*interface)->USBInterfaceOpen(interface);
311
312 if (kr != kIOReturnSuccess)
313 {
314 DBG("ERR: Could not open interface: (%08x)\n", kr);
315 (void) (*interface)->Release(interface);
316 //* continue so we can try the next interface
317 continue;
318 }
319
320 //* Get the number of endpoints associated with this interface
321 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
322
323 if (kr != kIOReturnSuccess) {
324 DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
325 goto next_interface;
326 }
327
328 //* Get interface class, subclass and protocol
329 if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
330 (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
331 (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess)
332 {
333 DBG("ERR: Unable to get interface class, subclass and protocol\n");
334 goto next_interface;
335 }
336
337 //* check to make sure interface class, subclass and protocol match ADB
338 //* avoid opening mass storage endpoints
339 if (is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) {
340 handle = calloc(1, sizeof(usb_handle));
341
342 //* Iterate over the endpoints for this interface and find the first
343 //* bulk in/out pipes available. These will be our read/write pipes.
344 for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
345 UInt8 transferType;
346 UInt16 maxPacketSize;
347 UInt8 interval;
348 UInt8 number;
349 UInt8 direction;
350
351 kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
352 &number, &transferType, &maxPacketSize, &interval);
353
354 if (kIOReturnSuccess == kr) {
355 if (kUSBBulk != transferType)
356 continue;
357
358 if (kUSBIn == direction)
359 handle->bulkIn = endpoint;
360
361 if (kUSBOut == direction)
362 handle->bulkOut = endpoint;
363
364 if (interfaceProtocol == 0x01) {
365 handle->zero_mask = maxPacketSize - 1;
366 }
367
368 } else {
369 DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
370 }
371 }
372
373 handle->interface = interface;
374 break;
375 }
376
377 next_interface:
378 (*interface)->USBInterfaceClose(interface);
379 (*interface)->Release(interface);
380 }
381
382 return handle;
383 }
384
385
386 void* RunLoopThread(void* unused)
387 {
388 int i;
389
390 InitUSB();
391
392 currentRunLoop = CFRunLoopGetCurrent();
393
394 // Signal the parent that we are running
395 adb_mutex_lock(&start_lock);
396 adb_cond_signal(&start_cond);
397 adb_mutex_unlock(&start_lock);
398
399 CFRunLoopRun();
400 currentRunLoop = 0;
401
402 for (i = 0; i < kSupportedDeviceCount; i++) {
403 IOObjectRelease(notificationIterators[i]);
404 }
405 IONotificationPortDestroy(notificationPort);
406
407 DBG("RunLoopThread done\n");
408 return NULL;
409 }
410
411
412 static int initialized = 0;
413 void usb_init()
414 {
415 if (!initialized)
416 {
417 adb_thread_t tid;
418
419 adb_mutex_init(&start_lock, NULL);
420 adb_cond_init(&start_cond, NULL);
421
422 if(adb_thread_create(&tid, RunLoopThread, NULL))
423 fatal_errno("cannot create input thread");
424
425 // Wait for initialization to finish
426 adb_mutex_lock(&start_lock);
427 adb_cond_wait(&start_cond, &start_lock);
428 adb_mutex_unlock(&start_lock);
429
430 adb_mutex_destroy(&start_lock);
431 adb_cond_destroy(&start_cond);
432
433 initialized = 1;
434 }
435 }
436
437 void usb_cleanup()
438 {
439 DBG("usb_cleanup\n");
440 close_usb_devices();
441 if (currentRunLoop)
442 CFRunLoopStop(currentRunLoop);
443 }
444
445 int usb_write(usb_handle *handle, const void *buf, int len)
446 {
447 IOReturn result;
448
449 if (!len)
450 return 0;
451
452 if (!handle)
453 return -1;
454
455 if (NULL == handle->interface) {
456 DBG("ERR: usb_write interface was null\n");
457 return -1;
458 }
459
460 if (0 == handle->bulkOut) {
461 DBG("ERR: bulkOut endpoint not assigned\n");
462 return -1;
463 }
464
465 result =
466 (*handle->interface)->WritePipe(
467 handle->interface, handle->bulkOut, (void *)buf, len);
468
469 if ((result == 0) && (handle->zero_mask)) {
470 /* we need 0-markers and our transfer */
471 if(!(len & handle->zero_mask)) {
472 result =
473 (*handle->interface)->WritePipe(
474 handle->interface, handle->bulkOut, (void *)buf, 0);
475 }
476 }
477
478 if (0 == result)
479 return 0;
480
481 DBG("ERR: usb_write failed with status %d\n", result);
482 return -1;
483 }
484
485 int usb_read(usb_handle *handle, void *buf, int len)
486 {
487 IOReturn result;
488 UInt32 numBytes = len;
489
490 if (!len) {
491 return 0;
492 }
493
494 if (!handle) {
495 return -1;
496 }
497
498 if (NULL == handle->interface) {
499 DBG("ERR: usb_read interface was null\n");
500 return -1;
501 }
502
503 if (0 == handle->bulkIn) {
504 DBG("ERR: bulkIn endpoint not assigned\n");
505 return -1;
506 }
507
508 result =
509 (*handle->interface)->ReadPipe(handle->interface,
510 handle->bulkIn, buf, &numBytes);
511
512 if (0 == result)
513 return 0;
514 else {
515 DBG("ERR: usb_read failed with status %d\n", result);
516 }
517
518 return -1;
519 }
520
521 int usb_close(usb_handle *handle)
522 {
523 return 0;
524 }
525
526 void usb_kick(usb_handle *handle)
527 {
528 /* release the interface */
529 if (handle->interface)
530 {
531 (*handle->interface)->USBInterfaceClose(handle->interface);
532 (*handle->interface)->Release(handle->interface);
533 handle->interface = 0;
534 }
535 }
+0
-513
adb/usb_windows.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <windows.h>
17 #include <winerror.h>
18 #include <errno.h>
19 #include <usb100.h>
20 #include <adb_api.h>
21 #include <stdio.h>
22
23 #include "sysdeps.h"
24
25 #define TRACE_TAG TRACE_USB
26 #include "adb.h"
27
28 /** Structure usb_handle describes our connection to the usb device via
29 AdbWinApi.dll. This structure is returned from usb_open() routine and
30 is expected in each subsequent call that is accessing the device.
31 */
32 struct usb_handle {
33 /// Previous entry in the list of opened usb handles
34 usb_handle *prev;
35
36 /// Next entry in the list of opened usb handles
37 usb_handle *next;
38
39 /// Handle to USB interface
40 ADBAPIHANDLE adb_interface;
41
42 /// Handle to USB read pipe (endpoint)
43 ADBAPIHANDLE adb_read_pipe;
44
45 /// Handle to USB write pipe (endpoint)
46 ADBAPIHANDLE adb_write_pipe;
47
48 /// Interface name
49 char* interface_name;
50
51 /// Mask for determining when to use zero length packets
52 unsigned zero_mask;
53 };
54
55 /// Class ID assigned to the device by androidusb.sys
56 static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
57
58 /// List of opened usb handles
59 static usb_handle handle_list = {
60 .prev = &handle_list,
61 .next = &handle_list,
62 };
63
64 /// Locker for the list of opened usb handles
65 ADB_MUTEX_DEFINE( usb_lock );
66
67 /// Checks if there is opened usb handle in handle_list for this device.
68 int known_device(const char* dev_name);
69
70 /// Checks if there is opened usb handle in handle_list for this device.
71 /// usb_lock mutex must be held before calling this routine.
72 int known_device_locked(const char* dev_name);
73
74 /// Registers opened usb handle (adds it to handle_list).
75 int register_new_device(usb_handle* handle);
76
77 /// Checks if interface (device) matches certain criteria
78 int recognized_device(usb_handle* handle);
79
80 /// Enumerates present and available interfaces (devices), opens new ones and
81 /// registers usb transport for them.
82 void find_devices();
83
84 /// Entry point for thread that polls (every second) for new usb interfaces.
85 /// This routine calls find_devices in infinite loop.
86 void* device_poll_thread(void* unused);
87
88 /// Initializes this module
89 void usb_init();
90
91 /// Cleans up this module
92 void usb_cleanup();
93
94 /// Opens usb interface (device) by interface (device) name.
95 usb_handle* do_usb_open(const wchar_t* interface_name);
96
97 /// Writes data to the opened usb handle
98 int usb_write(usb_handle* handle, const void* data, int len);
99
100 /// Reads data using the opened usb handle
101 int usb_read(usb_handle *handle, void* data, int len);
102
103 /// Cleans up opened usb handle
104 void usb_cleanup_handle(usb_handle* handle);
105
106 /// Cleans up (but don't close) opened usb handle
107 void usb_kick(usb_handle* handle);
108
109 /// Closes opened usb handle
110 int usb_close(usb_handle* handle);
111
112 /// Gets interface (device) name for an opened usb handle
113 const char *usb_name(usb_handle* handle);
114
115 int known_device_locked(const char* dev_name) {
116 usb_handle* usb;
117
118 if (NULL != dev_name) {
119 // Iterate through the list looking for the name match.
120 for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
121 // In Windows names are not case sensetive!
122 if((NULL != usb->interface_name) &&
123 (0 == stricmp(usb->interface_name, dev_name))) {
124 return 1;
125 }
126 }
127 }
128
129 return 0;
130 }
131
132 int known_device(const char* dev_name) {
133 int ret = 0;
134
135 if (NULL != dev_name) {
136 adb_mutex_lock(&usb_lock);
137 ret = known_device_locked(dev_name);
138 adb_mutex_unlock(&usb_lock);
139 }
140
141 return ret;
142 }
143
144 int register_new_device(usb_handle* handle) {
145 if (NULL == handle)
146 return 0;
147
148 adb_mutex_lock(&usb_lock);
149
150 // Check if device is already in the list
151 if (known_device_locked(handle->interface_name)) {
152 adb_mutex_unlock(&usb_lock);
153 return 0;
154 }
155
156 // Not in the list. Add this handle to the list.
157 handle->next = &handle_list;
158 handle->prev = handle_list.prev;
159 handle->prev->next = handle;
160 handle->next->prev = handle;
161
162 adb_mutex_unlock(&usb_lock);
163
164 return 1;
165 }
166
167 void* device_poll_thread(void* unused) {
168 D("Created device thread\n");
169
170 while(1) {
171 find_devices();
172 adb_sleep_ms(1000);
173 }
174
175 return NULL;
176 }
177
178 void usb_init() {
179 adb_thread_t tid;
180
181 if(adb_thread_create(&tid, device_poll_thread, NULL)) {
182 fatal_errno("cannot create input thread");
183 }
184 }
185
186 void usb_cleanup() {
187 }
188
189 usb_handle* do_usb_open(const wchar_t* interface_name) {
190 // Allocate our handle
191 usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
192 if (NULL == ret)
193 return NULL;
194
195 // Set linkers back to the handle
196 ret->next = ret;
197 ret->prev = ret;
198
199 // Create interface.
200 ret->adb_interface = AdbCreateInterfaceByName(interface_name);
201
202 if (NULL == ret->adb_interface) {
203 free(ret);
204 errno = GetLastError();
205 return NULL;
206 }
207
208 // Open read pipe (endpoint)
209 ret->adb_read_pipe =
210 AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
211 AdbOpenAccessTypeReadWrite,
212 AdbOpenSharingModeReadWrite);
213 if (NULL != ret->adb_read_pipe) {
214 // Open write pipe (endpoint)
215 ret->adb_write_pipe =
216 AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
217 AdbOpenAccessTypeReadWrite,
218 AdbOpenSharingModeReadWrite);
219 if (NULL != ret->adb_write_pipe) {
220 // Save interface name
221 unsigned long name_len = 0;
222
223 // First get expected name length
224 AdbGetInterfaceName(ret->adb_interface,
225 NULL,
226 &name_len,
227 true);
228 if (0 != name_len) {
229 ret->interface_name = (char*)malloc(name_len);
230
231 if (NULL != ret->interface_name) {
232 // Now save the name
233 if (AdbGetInterfaceName(ret->adb_interface,
234 ret->interface_name,
235 &name_len,
236 true)) {
237 // We're done at this point
238 return ret;
239 }
240 } else {
241 SetLastError(ERROR_OUTOFMEMORY);
242 }
243 }
244 }
245 }
246
247 // Something went wrong.
248 errno = GetLastError();
249 usb_cleanup_handle(ret);
250 free(ret);
251 SetLastError(errno);
252
253 return NULL;
254 }
255
256 int usb_write(usb_handle* handle, const void* data, int len) {
257 unsigned long time_out = 500 + len * 8;
258 unsigned long written = 0;
259 int ret;
260
261 D("usb_write %d\n", len);
262 if (NULL != handle) {
263 // Perform write
264 ret = AdbWriteEndpointSync(handle->adb_write_pipe,
265 (void*)data,
266 (unsigned long)len,
267 &written,
268 time_out);
269 errno = GetLastError();
270
271 if (ret) {
272 // Make sure that we've written what we were asked to write
273 D("usb_write got: %ld, expected: %d\n", written, len);
274 if (written == (unsigned long)len) {
275 if(handle->zero_mask && (len & handle->zero_mask) == 0) {
276 // Send a zero length packet
277 AdbWriteEndpointSync(handle->adb_write_pipe,
278 (void*)data,
279 0,
280 &written,
281 time_out);
282 }
283 return 0;
284 }
285 } else {
286 // assume ERROR_INVALID_HANDLE indicates we are disconnected
287 if (errno == ERROR_INVALID_HANDLE)
288 usb_kick(handle);
289 }
290 } else {
291 D("usb_write NULL handle\n");
292 SetLastError(ERROR_INVALID_HANDLE);
293 }
294
295 D("usb_write failed: %d\n", errno);
296
297 return -1;
298 }
299
300 int usb_read(usb_handle *handle, void* data, int len) {
301 unsigned long time_out = 500 + len * 8;
302 unsigned long read = 0;
303 int ret;
304
305 D("usb_read %d\n", len);
306 if (NULL != handle) {
307 while (len > 0) {
308 int xfer = (len > 4096) ? 4096 : len;
309
310 ret = AdbReadEndpointSync(handle->adb_read_pipe,
311 (void*)data,
312 (unsigned long)xfer,
313 &read,
314 time_out);
315 errno = GetLastError();
316 D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
317 if (ret) {
318 data += read;
319 len -= read;
320
321 if (len == 0)
322 return 0;
323 } else if (errno != ERROR_SEM_TIMEOUT) {
324 // assume ERROR_INVALID_HANDLE indicates we are disconnected
325 if (errno == ERROR_INVALID_HANDLE)
326 usb_kick(handle);
327 break;
328 }
329 }
330 } else {
331 D("usb_read NULL handle\n");
332 SetLastError(ERROR_INVALID_HANDLE);
333 }
334
335 D("usb_read failed: %d\n", errno);
336
337 return -1;
338 }
339
340 void usb_cleanup_handle(usb_handle* handle) {
341 if (NULL != handle) {
342 if (NULL != handle->interface_name)
343 free(handle->interface_name);
344 if (NULL != handle->adb_write_pipe)
345 AdbCloseHandle(handle->adb_write_pipe);
346 if (NULL != handle->adb_read_pipe)
347 AdbCloseHandle(handle->adb_read_pipe);
348 if (NULL != handle->adb_interface)
349 AdbCloseHandle(handle->adb_interface);
350
351 handle->interface_name = NULL;
352 handle->adb_write_pipe = NULL;
353 handle->adb_read_pipe = NULL;
354 handle->adb_interface = NULL;
355 }
356 }
357
358 void usb_kick(usb_handle* handle) {
359 if (NULL != handle) {
360 adb_mutex_lock(&usb_lock);
361
362 usb_cleanup_handle(handle);
363
364 adb_mutex_unlock(&usb_lock);
365 } else {
366 SetLastError(ERROR_INVALID_HANDLE);
367 errno = ERROR_INVALID_HANDLE;
368 }
369 }
370
371 int usb_close(usb_handle* handle) {
372 D("usb_close\n");
373
374 if (NULL != handle) {
375 // Remove handle from the list
376 adb_mutex_lock(&usb_lock);
377
378 if ((handle->next != handle) && (handle->prev != handle)) {
379 handle->next->prev = handle->prev;
380 handle->prev->next = handle->next;
381 handle->prev = handle;
382 handle->next = handle;
383 }
384
385 adb_mutex_unlock(&usb_lock);
386
387 // Cleanup handle
388 usb_cleanup_handle(handle);
389 free(handle);
390 }
391
392 return 0;
393 }
394
395 const char *usb_name(usb_handle* handle) {
396 if (NULL == handle) {
397 SetLastError(ERROR_INVALID_HANDLE);
398 errno = ERROR_INVALID_HANDLE;
399 return NULL;
400 }
401
402 return (const char*)handle->interface_name;
403 }
404
405 int recognized_device(usb_handle* handle) {
406 if (NULL == handle)
407 return 0;
408
409 // Check vendor and product id first
410 USB_DEVICE_DESCRIPTOR device_desc;
411
412 if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
413 &device_desc)) {
414 return 0;
415 }
416
417 // Then check interface properties
418 USB_INTERFACE_DESCRIPTOR interf_desc;
419
420 if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
421 &interf_desc)) {
422 return 0;
423 }
424
425 // Must have two endpoints
426 if (2 != interf_desc.bNumEndpoints) {
427 return 0;
428 }
429
430 if (is_adb_interface(device_desc.idVendor, device_desc.idProduct,
431 interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
432
433 if(interf_desc.bInterfaceProtocol == 0x01) {
434 AdbEndpointInformation endpoint_info;
435 // assuming zero is a valid bulk endpoint ID
436 if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
437 handle->zero_mask = endpoint_info.max_packet_size - 1;
438 }
439 }
440
441 return 1;
442 }
443
444 return 0;
445 }
446
447 void find_devices() {
448 usb_handle* handle = NULL;
449 char entry_buffer[2048];
450 char interf_name[2048];
451 AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
452 unsigned long entry_buffer_size = sizeof(entry_buffer);
453 char* copy_name;
454
455 // Enumerate all present and active interfaces.
456 ADBAPIHANDLE enum_handle =
457 AdbEnumInterfaces(usb_class_id, true, true, true);
458
459 if (NULL == enum_handle)
460 return;
461
462 while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
463 // TODO: FIXME - temp hack converting wchar_t into char.
464 // It would be better to change AdbNextInterface so it will return
465 // interface name as single char string.
466 const wchar_t* wchar_name = next_interface->device_name;
467 for(copy_name = interf_name;
468 L'\0' != *wchar_name;
469 wchar_name++, copy_name++) {
470 *copy_name = (char)(*wchar_name);
471 }
472 *copy_name = '\0';
473
474 // Lets see if we already have this device in the list
475 if (!known_device(interf_name)) {
476 // This seems to be a new device. Open it!
477 handle = do_usb_open(next_interface->device_name);
478 if (NULL != handle) {
479 // Lets see if this interface (device) belongs to us
480 if (recognized_device(handle)) {
481 D("adding a new device %s\n", interf_name);
482 char serial_number[512];
483 unsigned long serial_number_len = sizeof(serial_number);
484 if (AdbGetSerialNumber(handle->adb_interface,
485 serial_number,
486 &serial_number_len,
487 true)) {
488 // Lets make sure that we don't duplicate this device
489 if (register_new_device(handle)) {
490 register_usb_transport(handle, serial_number);
491 } else {
492 D("register_new_device failed for %s\n", interf_name);
493 usb_cleanup_handle(handle);
494 free(handle);
495 }
496 } else {
497 D("cannot get serial number\n");
498 usb_cleanup_handle(handle);
499 free(handle);
500 }
501 } else {
502 usb_cleanup_handle(handle);
503 free(handle);
504 }
505 }
506 }
507
508 entry_buffer_size = sizeof(entry_buffer);
509 }
510
511 AdbCloseHandle(enum_handle);
512 }
+0
-106
adb/utils.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "utils.h"
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 char*
21 buff_addc (char* buff, char* buffEnd, int c)
22 {
23 int avail = buffEnd - buff;
24
25 if (avail <= 0) /* already in overflow mode */
26 return buff;
27
28 if (avail == 1) { /* overflowing, the last byte is reserved for zero */
29 buff[0] = 0;
30 return buff + 1;
31 }
32
33 buff[0] = (char) c; /* add char and terminating zero */
34 buff[1] = 0;
35 return buff + 1;
36 }
37
38 char*
39 buff_adds (char* buff, char* buffEnd, const char* s)
40 {
41 int slen = strlen(s);
42
43 return buff_addb(buff, buffEnd, s, slen);
44 }
45
46 char*
47 buff_addb (char* buff, char* buffEnd, const void* data, int len)
48 {
49 int avail = (buffEnd - buff);
50
51 if (avail <= 0 || len <= 0) /* already overflowing */
52 return buff;
53
54 if (len > avail)
55 len = avail;
56
57 memcpy(buff, data, len);
58
59 buff += len;
60
61 /* ensure there is a terminating zero */
62 if (buff >= buffEnd) { /* overflow */
63 buff[-1] = 0;
64 } else
65 buff[0] = 0;
66
67 return buff;
68 }
69
70 char*
71 buff_add (char* buff, char* buffEnd, const char* format, ... )
72 {
73 int avail;
74
75 avail = (buffEnd - buff);
76
77 if (avail > 0) {
78 va_list args;
79 int nn;
80
81 va_start(args, format);
82 nn = vsnprintf( buff, avail, format, args);
83 va_end(args);
84
85 if (nn < 0) {
86 /* some C libraries return -1 in case of overflow,
87 * but they will also do that if the format spec is
88 * invalid. We assume ADB is not buggy enough to
89 * trigger that last case. */
90 nn = avail;
91 }
92 else if (nn > avail) {
93 nn = avail;
94 }
95
96 buff += nn;
97
98 /* ensure that there is a terminating zero */
99 if (buff >= buffEnd)
100 buff[-1] = 0;
101 else
102 buff[0] = 0;
103 }
104 return buff;
105 }
+0
-68
adb/utils.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef _ADB_UTILS_H
16 #define _ADB_UTILS_H
17
18 /* bounded buffer functions */
19
20 /* all these functions are used to append data to a bounded buffer.
21 *
22 * after each operation, the buffer is guaranteed to be zero-terminated,
23 * even in the case of an overflow. they all return the new buffer position
24 * which allows one to use them in succession, only checking for overflows
25 * at the end. For example:
26 *
27 * BUFF_DECL(temp,p,end,1024);
28 * char* p;
29 *
30 * p = buff_addc(temp, end, '"');
31 * p = buff_adds(temp, end, string);
32 * p = buff_addc(temp, end, '"');
33 *
34 * if (p >= end) {
35 * overflow detected. note that 'temp' is
36 * zero-terminated for safety.
37 * }
38 * return strdup(temp);
39 */
40
41 /* tries to add a character to the buffer, in case of overflow
42 * this will only write a terminating zero and return buffEnd.
43 */
44 char* buff_addc (char* buff, char* buffEnd, int c);
45
46 /* tries to add a string to the buffer */
47 char* buff_adds (char* buff, char* buffEnd, const char* s);
48
49 /* tries to add a bytes to the buffer. the input can contain zero bytes,
50 * but a terminating zero will always be appended at the end anyway
51 */
52 char* buff_addb (char* buff, char* buffEnd, const void* data, int len);
53
54 /* tries to add a formatted string to a bounded buffer */
55 char* buff_add (char* buff, char* buffEnd, const char* format, ... );
56
57 /* convenience macro used to define a bounded buffer, as well as
58 * a 'cursor' and 'end' variables all in one go.
59 *
60 * note: this doesn't place an initial terminating zero in the buffer,
61 * you need to use one of the buff_ functions for this. or simply
62 * do _cursor[0] = 0 manually.
63 */
64 #define BUFF_DECL(_buff,_cursor,_end,_size) \
65 char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
66
67 #endif /* _ADB_UTILS_H */
+0
-13
cpio/Android.mk less more
0 # Copyright 2005 The Android Open Source Project
1
2 LOCAL_PATH:= $(call my-dir)
3 include $(CLEAR_VARS)
4
5 LOCAL_SRC_FILES := \
6 mkbootfs.c
7
8 LOCAL_MODULE := mkbootfs
9
10 include $(BUILD_HOST_EXECUTABLE)
11
12 $(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+0
-261
cpio/mkbootfs.c less more
0
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <dirent.h>
9
10 #include <stdarg.h>
11 #include <fcntl.h>
12
13 #include <private/android_filesystem_config.h>
14
15 /* NOTES
16 **
17 ** - see buffer-format.txt from the linux kernel docs for
18 ** an explanation of this file format
19 ** - dotfiles are ignored
20 ** - directories named 'root' are ignored
21 ** - device notes, pipes, etc are not supported (error)
22 */
23
24 void die(const char *why, ...)
25 {
26 va_list ap;
27
28 va_start(ap, why);
29 fprintf(stderr,"error: ");
30 vfprintf(stderr, why, ap);
31 fprintf(stderr,"\n");
32 va_end(ap);
33 exit(1);
34 }
35
36 static int verbose = 0;
37 static int total_size = 0;
38
39 static void fix_stat(const char *path, struct stat *s)
40 {
41 fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
42 }
43
44 static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
45 {
46 // Nothing is special about this value, just picked something in the
47 // approximate range that was being used already, and avoiding small
48 // values which may be special.
49 static unsigned next_inode = 300000;
50
51 while(total_size & 3) {
52 total_size++;
53 putchar(0);
54 }
55
56 fix_stat(out, s);
57 // fprintf(stderr, "_eject %s: mode=0%o\n", out, s->st_mode);
58
59 printf("%06x%08x%08x%08x%08x%08x%08x"
60 "%08x%08x%08x%08x%08x%08x%08x%s%c",
61 0x070701,
62 next_inode++, // s.st_ino,
63 s->st_mode,
64 0, // s.st_uid,
65 0, // s.st_gid,
66 1, // s.st_nlink,
67 0, // s.st_mtime,
68 datasize,
69 0, // volmajor
70 0, // volminor
71 0, // devmajor
72 0, // devminor,
73 olen + 1,
74 0,
75 out,
76 0
77 );
78
79 total_size += 6 + 8*13 + olen + 1;
80
81 if(strlen(out) != olen) die("ACK!");
82
83 while(total_size & 3) {
84 total_size++;
85 putchar(0);
86 }
87
88 if(datasize) {
89 fwrite(data, datasize, 1, stdout);
90 total_size += datasize;
91 }
92 }
93
94 static void _eject_trailer()
95 {
96 struct stat s;
97 memset(&s, 0, sizeof(s));
98 _eject(&s, "TRAILER!!!", 10, 0, 0);
99
100 while(total_size & 0xff) {
101 total_size++;
102 putchar(0);
103 }
104 }
105
106 static void _archive(char *in, char *out, int ilen, int olen);
107
108 static int compare(const void* a, const void* b) {
109 return strcmp(*(const char**)a, *(const char**)b);
110 }
111
112 static void _archive_dir(char *in, char *out, int ilen, int olen)
113 {
114 int i, t;
115 DIR *d;
116 struct dirent *de;
117
118 if(verbose) {
119 fprintf(stderr,"_archive_dir('%s','%s',%d,%d)\n",
120 in, out, ilen, olen);
121 }
122
123 d = opendir(in);
124 if(d == 0) die("cannot open directory '%s'", in);
125
126 int size = 32;
127 int entries = 0;
128 char** names = malloc(size * sizeof(char*));
129 if (names == NULL) {
130 fprintf(stderr, "failed to allocate dir names array (size %d)\n", size);
131 exit(1);
132 }
133
134 while((de = readdir(d)) != 0){
135 /* xxx: feature? maybe some dotfiles are okay */
136 if(de->d_name[0] == '.') continue;
137
138 /* xxx: hack. use a real exclude list */
139 if(!strcmp(de->d_name, "root")) continue;
140
141 if (entries >= size) {
142 size *= 2;
143 names = realloc(names, size * sizeof(char*));
144 if (names == NULL) {
145 fprintf(stderr, "failed to reallocate dir names array (size %d)\n",
146 size);
147 exit(1);
148 }
149 }
150 names[entries] = strdup(de->d_name);
151 if (names[entries] == NULL) {
152 fprintf(stderr, "failed to strdup name \"%s\"\n",
153 de->d_name);
154 exit(1);
155 }
156 ++entries;
157 }
158
159 qsort(names, entries, sizeof(char*), compare);
160
161 for (i = 0; i < entries; ++i) {
162 t = strlen(names[i]);
163 in[ilen] = '/';
164 memcpy(in + ilen + 1, names[i], t + 1);
165
166 if(olen > 0) {
167 out[olen] = '/';
168 memcpy(out + olen + 1, names[i], t + 1);
169 _archive(in, out, ilen + t + 1, olen + t + 1);
170 } else {
171 memcpy(out, names[i], t + 1);
172 _archive(in, out, ilen + t + 1, t);
173 }
174
175 in[ilen] = 0;
176 out[olen] = 0;
177
178 free(names[i]);
179 }
180 free(names);
181 }
182
183 static void _archive(char *in, char *out, int ilen, int olen)
184 {
185 struct stat s;
186
187 if(verbose) {
188 fprintf(stderr,"_archive('%s','%s',%d,%d)\n",
189 in, out, ilen, olen);
190 }
191
192 if(lstat(in, &s)) die("could not stat '%s'\n", in);
193
194 if(S_ISREG(s.st_mode)){
195 char *tmp;
196 int fd;
197
198 fd = open(in, O_RDONLY);
199 if(fd < 0) die("cannot open '%s' for read", in);
200
201 tmp = (char*) malloc(s.st_size);
202 if(tmp == 0) die("cannot allocate %d bytes", s.st_size);
203
204 if(read(fd, tmp, s.st_size) != s.st_size) {
205 die("cannot read %d bytes", s.st_size);
206 }
207
208 _eject(&s, out, olen, tmp, s.st_size);
209
210 free(tmp);
211 close(fd);
212 } else if(S_ISDIR(s.st_mode)) {
213 _eject(&s, out, olen, 0, 0);
214 _archive_dir(in, out, ilen, olen);
215 } else if(S_ISLNK(s.st_mode)) {
216 char buf[1024];
217 int size;
218 size = readlink(in, buf, 1024);
219 if(size < 0) die("cannot read symlink '%s'", in);
220 _eject(&s, out, olen, buf, size);
221 } else {
222 die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
223 }
224 }
225
226 void archive(const char *start, const char *prefix)
227 {
228 char in[8192];
229 char out[8192];
230
231 strcpy(in, start);
232 strcpy(out, prefix);
233
234 _archive_dir(in, out, strlen(in), strlen(out));
235 }
236
237 int main(int argc, char *argv[])
238 {
239 argc--;
240 argv++;
241
242 if(argc == 0) die("no directories to process?!");
243
244 while(argc-- > 0){
245 char *x = strchr(*argv, '=');
246 if(x != 0) {
247 *x++ = 0;
248 } else {
249 x = "";
250 }
251
252 archive(*argv, x);
253
254 argv++;
255 }
256
257 _eject_trailer();
258
259 return 0;
260 }
+0
-26
debuggerd/Android.mk less more
0 # Copyright 2005 The Android Open Source Project
1
2 ifeq ($(TARGET_ARCH),arm)
3
4 LOCAL_PATH:= $(call my-dir)
5 include $(CLEAR_VARS)
6
7 LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c
8 LOCAL_CFLAGS := -Wall
9 LOCAL_MODULE := debuggerd
10
11 LOCAL_STATIC_LIBRARIES := libcutils libc
12
13 include $(BUILD_EXECUTABLE)
14
15 include $(CLEAR_VARS)
16 LOCAL_SRC_FILES := crasher.c
17 LOCAL_SRC_FILES += crashglue.S
18 LOCAL_MODULE := crasher
19 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
20 LOCAL_MODULE_TAGS := eng
21 #LOCAL_FORCE_STATIC_EXECUTABLE := true
22 LOCAL_SHARED_LIBRARIES := libcutils libc
23 include $(BUILD_EXECUTABLE)
24
25 endif # TARGET_ARCH == arm
+0
-0
debuggerd/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
debuggerd/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-105
debuggerd/crasher.c less more
0
1 //#include <cutils/misc.h>
2
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sched.h>
8 #include <errno.h>
9
10 #include <signal.h>
11 #include <sys/ptrace.h>
12 #include <sys/wait.h>
13 #include <sys/socket.h>
14
15 #include <pthread.h>
16
17 #include <cutils/sockets.h>
18
19 void crash1(void);
20 void crashnostack(void);
21
22 static void debuggerd_connect()
23 {
24 char tmp[1];
25 int s;
26 sprintf(tmp, "%d", gettid());
27 s = socket_local_client("android:debuggerd",
28 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
29 if(s >= 0) {
30 read(s, tmp, 1);
31 close(s);
32 }
33 }
34
35 void test_call1()
36 {
37 *((int*) 32) = 1;
38 }
39
40 void *test_thread(void *x)
41 {
42 printf("crasher: thread pid=%d tid=%d\n", getpid(), gettid());
43
44 sleep(1);
45 test_call1();
46 printf("goodbye\n");
47
48 return 0;
49 }
50
51 void *noisy(void *x)
52 {
53 char c = (unsigned) x;
54 for(;;) {
55 usleep(250*1000);
56 write(2, &c, 1);
57 if(c == 'C') *((unsigned*) 0) = 42;
58 }
59 return 0;
60 }
61
62 int ctest()
63 {
64 pthread_t thr;
65 pthread_attr_t attr;
66 pthread_attr_init(&attr);
67 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
68 pthread_create(&thr, &attr, noisy, (void*) 'A');
69 pthread_create(&thr, &attr, noisy, (void*) 'B');
70 pthread_create(&thr, &attr, noisy, (void*) 'C');
71 for(;;) ;
72 return 0;
73 }
74
75 int main(int argc, char **argv)
76 {
77 pthread_t thr;
78 pthread_attr_t attr;
79
80 fprintf(stderr,"crasher: " __TIME__ "!@\n");
81 fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
82
83 if(argc > 1) {
84 if(!strcmp(argv[1],"nostack")) crashnostack();
85 if(!strcmp(argv[1],"ctest")) return ctest();
86 if(!strcmp(argv[1],"exit")) exit(1);
87 if(!strcmp(argv[1],"abort")) maybeabort();
88
89 pthread_attr_init(&attr);
90 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
91 pthread_create(&thr, &attr, test_thread, 0);
92 while(1) sleep(1);
93 } else {
94 crash1();
95 // *((int*) 0) = 42;
96 }
97
98 return 0;
99 }
100
101 void maybeabort()
102 {
103 if(time(0) != 42) abort();
104 }
+0
-28
debuggerd/crashglue.S less more
0 .globl crash1
1 .globl crashnostack
2
3 crash1:
4 ldr r0, =0xa5a50000
5 ldr r1, =0xa5a50001
6 ldr r2, =0xa5a50002
7 ldr r3, =0xa5a50003
8 ldr r4, =0xa5a50004
9 ldr r5, =0xa5a50005
10 ldr r6, =0xa5a50006
11 ldr r7, =0xa5a50007
12 ldr r8, =0xa5a50008
13 ldr r9, =0xa5a50009
14 ldr r10, =0xa5a50010
15 ldr r11, =0xa5a50011
16 ldr r12, =0xa5a50012
17
18 mov lr, #0
19 ldr lr, [lr]
20 b .
21
22
23 crashnostack:
24 mov sp, #0
25 mov r0, #0
26 ldr r0, [r0]
27 b .
+0
-852
debuggerd/debuggerd.c less more
0 /* system/debuggerd/debuggerd.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <signal.h>
22 #include <pthread.h>
23 #include <stdarg.h>
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <dirent.h>
27
28 #include <sys/ptrace.h>
29 #include <sys/wait.h>
30 #include <sys/exec_elf.h>
31 #include <sys/stat.h>
32
33 #include <cutils/sockets.h>
34 #include <cutils/logd.h>
35 #include <cutils/sockets.h>
36 #include <cutils/properties.h>
37
38 #include <linux/input.h>
39
40 #include <private/android_filesystem_config.h>
41
42 #include "utility.h"
43
44 /* Main entry point to get the backtrace from the crashing process */
45 extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
46 unsigned int sp_list[],
47 int *frame0_pc_sane,
48 bool at_fault);
49
50 static char **process_name_ptr;
51
52 static int logsocket = -1;
53
54 #define ANDROID_LOG_INFO 4
55
56 /* Log information onto the tombstone */
57 void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
58 {
59 char buf[128];
60
61 va_list ap;
62 va_start(ap, fmt);
63
64 if (tfd >= 0) {
65 int len;
66 vsnprintf(buf, sizeof(buf), fmt, ap);
67 len = strlen(buf);
68 if(tfd >= 0) write(tfd, buf, len);
69 }
70
71 if (!in_tombstone_only)
72 __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
73 }
74
75 #define LOG(fmt...) _LOG(-1, 0, fmt)
76 #if 0
77 #define XLOG(fmt...) _LOG(-1, 0, fmt)
78 #else
79 #define XLOG(fmt...) do {} while(0)
80 #endif
81
82 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
83 // 012345678901234567890123456789012345678901234567890123456789
84 // 0 1 2 3 4 5
85
86 mapinfo *parse_maps_line(char *line)
87 {
88 mapinfo *mi;
89 int len = strlen(line);
90
91 if(len < 1) return 0;
92 line[--len] = 0;
93
94 if(len < 50) return 0;
95 if(line[20] != 'x') return 0;
96
97 mi = malloc(sizeof(mapinfo) + (len - 47));
98 if(mi == 0) return 0;
99
100 mi->start = strtoul(line, 0, 16);
101 mi->end = strtoul(line + 9, 0, 16);
102 /* To be filled in parse_exidx_info if the mapped section starts with
103 * elf_header
104 */
105 mi->exidx_start = mi->exidx_end = 0;
106 mi->next = 0;
107 strcpy(mi->name, line + 49);
108
109 return mi;
110 }
111
112 void dump_build_info(int tfd)
113 {
114 char fingerprint[PROPERTY_VALUE_MAX];
115
116 property_get("ro.build.fingerprint", fingerprint, "unknown");
117
118 _LOG(tfd, false, "Build fingerprint: '%s'\n", fingerprint);
119 }
120
121
122 void dump_stack_and_code(int tfd, int pid, mapinfo *map,
123 int unwind_depth, unsigned int sp_list[],
124 int frame0_pc_sane, bool at_fault)
125 {
126 unsigned int sp, pc, p, end, data;
127 struct pt_regs r;
128 int sp_depth;
129 bool only_in_tombstone = !at_fault;
130
131 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
132 sp = r.ARM_sp;
133 pc = r.ARM_pc;
134
135 /* Died because calling the weeds - dump
136 * the code around the PC in the next frame instead.
137 */
138 if (frame0_pc_sane == 0) {
139 pc = r.ARM_lr;
140 }
141
142 _LOG(tfd, true, "code%s:\n", frame0_pc_sane ? "" : " (around frame #01)");
143
144 end = p = pc & ~3;
145 p -= 16;
146
147 /* Dump the code as:
148 * PC contents
149 * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c
150 * 00008d44 f7ff18a0 490ced94 68035860 d0012b00
151 */
152 while (p <= end) {
153 int i;
154
155 _LOG(tfd, true, " %08x ", p);
156 for (i = 0; i < 4; i++) {
157 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
158 _LOG(tfd, true, " %08x", data);
159 p += 4;
160 }
161 _LOG(tfd, true, "\n", p);
162 }
163
164 p = sp - 64;
165 p &= ~3;
166 if (unwind_depth != 0) {
167 if (unwind_depth < STACK_CONTENT_DEPTH) {
168 end = sp_list[unwind_depth-1];
169 }
170 else {
171 end = sp_list[STACK_CONTENT_DEPTH-1];
172 }
173 }
174 else {
175 end = sp | 0x000000ff;
176 end += 0xff;
177 }
178
179 _LOG(tfd, only_in_tombstone, "stack:\n");
180
181 /* If the crash is due to PC == 0, there will be two frames that
182 * have identical SP value.
183 */
184 if (sp_list[0] == sp_list[1]) {
185 sp_depth = 1;
186 }
187 else {
188 sp_depth = 0;
189 }
190
191 while (p <= end) {
192 char *prompt;
193 char level[16];
194 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
195 if (p == sp_list[sp_depth]) {
196 sprintf(level, "#%02d", sp_depth++);
197 prompt = level;
198 }
199 else {
200 prompt = " ";
201 }
202
203 /* Print the stack content in the log for the first 3 frames. For the
204 * rest only print them in the tombstone file.
205 */
206 _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
207 "%s %08x %08x %s\n", prompt, p, data,
208 map_to_name(map, data, ""));
209 p += 4;
210 }
211 /* print another 64-byte of stack data after the last frame */
212
213 end = p+64;
214 while (p <= end) {
215 data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
216 _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
217 " %08x %08x %s\n", p, data,
218 map_to_name(map, data, ""));
219 p += 4;
220 }
221 }
222
223 void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level,
224 bool at_fault)
225 {
226 struct pt_regs r;
227
228 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
229 _LOG(tfd, !at_fault, "tid %d not responding!\n", pid);
230 return;
231 }
232
233 if (unwound_level == 0) {
234 _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 0, r.ARM_pc,
235 map_to_name(map, r.ARM_pc, "<unknown>"));
236 }
237 _LOG(tfd, !at_fault, " #%02d lr %08x %s\n", 1, r.ARM_lr,
238 map_to_name(map, r.ARM_lr, "<unknown>"));
239 }
240
241 void dump_registers(int tfd, int pid, bool at_fault)
242 {
243 struct pt_regs r;
244 bool only_in_tombstone = !at_fault;
245
246 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
247 _LOG(tfd, only_in_tombstone,
248 "cannot get registers: %s\n", strerror(errno));
249 return;
250 }
251
252 _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
253 r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3);
254 _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
255 r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7);
256 _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n",
257 r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp);
258 _LOG(tfd, only_in_tombstone,
259 " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
260 r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr);
261 }
262
263 const char *get_signame(int sig)
264 {
265 switch(sig) {
266 case SIGILL: return "SIGILL";
267 case SIGABRT: return "SIGABRT";
268 case SIGBUS: return "SIGBUS";
269 case SIGFPE: return "SIGFPE";
270 case SIGSEGV: return "SIGSEGV";
271 case SIGSTKFLT: return "SIGSTKFLT";
272 default: return "?";
273 }
274 }
275
276 void dump_fault_addr(int tfd, int pid, int sig)
277 {
278 siginfo_t si;
279
280 memset(&si, 0, sizeof(si));
281 if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){
282 _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno));
283 } else {
284 _LOG(tfd, false, "signal %d (%s), fault addr %08x\n",
285 sig, get_signame(sig), si.si_addr);
286 }
287 }
288
289 void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig)
290 {
291 char data[1024];
292 char *x = 0;
293 FILE *fp;
294
295 sprintf(data, "/proc/%d/cmdline", pid);
296 fp = fopen(data, "r");
297 if(fp) {
298 x = fgets(data, 1024, fp);
299 fclose(fp);
300 }
301
302 _LOG(tfd, false,
303 "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
304 dump_build_info(tfd);
305 _LOG(tfd, false, "pid: %d, tid: %d >>> %s <<<\n",
306 pid, tid, x ? x : "UNKNOWN");
307
308 if(sig) dump_fault_addr(tfd, tid, sig);
309 }
310
311 static void parse_exidx_info(mapinfo *milist, pid_t pid)
312 {
313 mapinfo *mi;
314 for (mi = milist; mi != NULL; mi = mi->next) {
315 Elf32_Ehdr ehdr;
316
317 memset(&ehdr, 0, sizeof(Elf32_Ehdr));
318 /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of
319 * mapped section.
320 */
321 get_remote_struct(pid, (void *) (mi->start), &ehdr,
322 sizeof(Elf32_Ehdr));
323 /* Check if it has the matching magic words */
324 if (IS_ELF(ehdr)) {
325 Elf32_Phdr phdr;
326 Elf32_Phdr *ptr;
327 int i;
328
329 ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff);
330 for (i = 0; i < ehdr.e_phnum; i++) {
331 /* Parse the program header */
332 get_remote_struct(pid, (void *) ptr+i, &phdr,
333 sizeof(Elf32_Phdr));
334 /* Found a EXIDX segment? */
335 if (phdr.p_type == PT_ARM_EXIDX) {
336 mi->exidx_start = mi->start + phdr.p_offset;
337 mi->exidx_end = mi->exidx_start + phdr.p_filesz;
338 break;
339 }
340 }
341 }
342 }
343 }
344
345 void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault)
346 {
347 char data[1024];
348 FILE *fp;
349 mapinfo *milist = 0;
350 unsigned int sp_list[STACK_CONTENT_DEPTH];
351 int stack_depth;
352 int frame0_pc_sane = 1;
353
354 if (!at_fault) {
355 _LOG(tfd, true,
356 "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
357 _LOG(tfd, true, "pid: %d, tid: %d\n", pid, tid);
358 }
359
360 dump_registers(tfd, tid, at_fault);
361
362 /* Clear stack pointer records */
363 memset(sp_list, 0, sizeof(sp_list));
364
365 sprintf(data, "/proc/%d/maps", pid);
366 fp = fopen(data, "r");
367 if(fp) {
368 while(fgets(data, 1024, fp)) {
369 mapinfo *mi = parse_maps_line(data);
370 if(mi) {
371 mi->next = milist;
372 milist = mi;
373 }
374 }
375 fclose(fp);
376 }
377
378 parse_exidx_info(milist, tid);
379
380 /* If stack unwinder fails, use the default solution to dump the stack
381 * content.
382 */
383 stack_depth = unwind_backtrace_with_ptrace(tfd, tid, milist, sp_list,
384 &frame0_pc_sane, at_fault);
385
386 /* The stack unwinder should at least unwind two levels of stack. If less
387 * level is seen we make sure at lease pc and lr are dumped.
388 */
389 if (stack_depth < 2) {
390 dump_pc_and_lr(tfd, tid, milist, stack_depth, at_fault);
391 }
392
393 dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, frame0_pc_sane,
394 at_fault);
395
396 while(milist) {
397 mapinfo *next = milist->next;
398 free(milist);
399 milist = next;
400 }
401 }
402
403 /* FIXME: unused: use it or lose it*/
404 #if 0
405 static
406 void start_gdbserver_vs(int pid, int port)
407 {
408 pid_t p;
409 char *args[5];
410 char commspec[16];
411 char pidspec[16];
412
413 p = fork();
414 if(p < 0) {
415 LOG("could not fork()\n");
416 return;
417 }
418
419 if(p == 0) {
420 sprintf(commspec, ":%d", port);
421 sprintf(pidspec, "%d", pid);
422 args[0] = "/system/bin/gdbserver";
423 args[1] = commspec;
424 args[2] = "--attach";
425 args[3] = pidspec;
426 args[4] = 0;
427 exit(execv(args[0], args));
428 } else {
429 LOG("gdbserver pid=%d port=%d targetpid=%d\n",
430 p, port, pid);
431
432 sleep(5);
433 }
434 }
435 #endif
436
437 #define MAX_TOMBSTONES 10
438
439 #define typecheck(x,y) { \
440 typeof(x) __dummy1; \
441 typeof(y) __dummy2; \
442 (void)(&__dummy1 == &__dummy2); }
443
444 #define TOMBSTONE_DIR "/data/tombstones"
445
446 /*
447 * find_and_open_tombstone - find an available tombstone slot, if any, of the
448 * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
449 * file is available, we reuse the least-recently-modified file.
450 */
451 static int find_and_open_tombstone(void)
452 {
453 unsigned long mtime = ULONG_MAX;
454 struct stat sb;
455 char path[128];
456 int fd, i, oldest = 0;
457
458 /*
459 * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
460 * to, our logic breaks. This check will generate a warning if that happens.
461 */
462 typecheck(mtime, sb.st_mtime);
463
464 /*
465 * In a single wolf-like pass, find an available slot and, in case none
466 * exist, find and record the least-recently-modified file.
467 */
468 for (i = 0; i < MAX_TOMBSTONES; i++) {
469 snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
470
471 if (!stat(path, &sb)) {
472 if (sb.st_mtime < mtime) {
473 oldest = i;
474 mtime = sb.st_mtime;
475 }
476 continue;
477 }
478 if (errno != ENOENT)
479 continue;
480
481 fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
482 if (fd < 0)
483 continue; /* raced ? */
484
485 fchown(fd, AID_SYSTEM, AID_SYSTEM);
486 return fd;
487 }
488
489 /* we didn't find an available file, so we clobber the oldest one */
490 snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
491 fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
492 fchown(fd, AID_SYSTEM, AID_SYSTEM);
493
494 return fd;
495 }
496
497 /* Return true if some thread is not detached cleanly */
498 static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid)
499 {
500 char task_path[1024];
501
502 sprintf(task_path, "/proc/%d/task", pid);
503 DIR *d;
504 struct dirent *de;
505 int need_cleanup = 0;
506
507 d = opendir(task_path);
508 /* Bail early if cannot open the task directory */
509 if (d == NULL) {
510 XLOG("Cannot open /proc/%d/task\n", pid);
511 return false;
512 }
513 while ((de = readdir(d)) != NULL) {
514 unsigned new_tid;
515 /* Ignore "." and ".." */
516 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
517 continue;
518 new_tid = atoi(de->d_name);
519 /* The main thread at fault has been handled individually */
520 if (new_tid == tid)
521 continue;
522
523 /* Skip this thread if cannot ptrace it */
524 if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0)
525 continue;
526
527 dump_crash_report(tfd, pid, new_tid, false);
528 need_cleanup |= ptrace(PTRACE_DETACH, new_tid, 0, 0);
529 }
530 closedir(d);
531 return need_cleanup != 0;
532 }
533
534 /* Return true if some thread is not detached cleanly */
535 static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid,
536 int signal)
537 {
538 int fd;
539 bool need_cleanup = false;
540
541 mkdir(TOMBSTONE_DIR, 0755);
542 chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
543
544 fd = find_and_open_tombstone();
545 if (fd < 0)
546 return need_cleanup;
547
548 dump_crash_banner(fd, pid, tid, signal);
549 dump_crash_report(fd, pid, tid, true);
550 /*
551 * If the user has requested to attach gdb, don't collect the per-thread
552 * information as it increases the chance to lose track of the process.
553 */
554 if ((signed)pid > debug_uid) {
555 need_cleanup = dump_sibling_thread_report(fd, pid, tid);
556 }
557
558 close(fd);
559 return need_cleanup;
560 }
561
562 static int
563 write_string(const char* file, const char* string)
564 {
565 int len;
566 int fd;
567 ssize_t amt;
568 fd = open(file, O_RDWR);
569 len = strlen(string);
570 if (fd < 0)
571 return -errno;
572 amt = write(fd, string, len);
573 close(fd);
574 return amt >= 0 ? 0 : -errno;
575 }
576
577 static
578 void init_debug_led(void)
579 {
580 // trout leds
581 write_string("/sys/class/leds/red/brightness", "0");
582 write_string("/sys/class/leds/green/brightness", "0");
583 write_string("/sys/class/leds/blue/brightness", "0");
584 write_string("/sys/class/leds/red/device/blink", "0");
585 // sardine leds
586 write_string("/sys/class/leds/left/cadence", "0,0");
587 }
588
589 static
590 void enable_debug_led(void)
591 {
592 // trout leds
593 write_string("/sys/class/leds/red/brightness", "255");
594 // sardine leds
595 write_string("/sys/class/leds/left/cadence", "1,0");
596 }
597
598 static
599 void disable_debug_led(void)
600 {
601 // trout leds
602 write_string("/sys/class/leds/red/brightness", "0");
603 // sardine leds
604 write_string("/sys/class/leds/left/cadence", "0,0");
605 }
606
607 extern int init_getevent();
608 extern void uninit_getevent();
609 extern int get_event(struct input_event* event, int timeout);
610
611 static void wait_for_user_action(unsigned tid, struct ucred* cr)
612 {
613 (void)tid;
614 /* First log a helpful message */
615 LOG( "********************************************************\n"
616 "* process %d crashed. debuggerd waiting for gdbserver \n"
617 "* \n"
618 "* adb shell gdbserver :port --attach %d & \n"
619 "* \n"
620 "* and press the HOME key. \n"
621 "********************************************************\n",
622 cr->pid, cr->pid);
623
624 /* wait for HOME key */
625 if (init_getevent() == 0) {
626 int ms = 1200 / 10;
627 int dit = 1;
628 int dah = 3*dit;
629 int _ = -dit;
630 int ___ = 3*_;
631 int _______ = 7*_;
632 const signed char codes[] = {
633 dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
634 };
635 size_t s = 0;
636 struct input_event e;
637 int home = 0;
638 init_debug_led();
639 enable_debug_led();
640 do {
641 int timeout = abs((int)(codes[s])) * ms;
642 int res = get_event(&e, timeout);
643 if (res == 0) {
644 if (e.type==EV_KEY && e.code==KEY_HOME && e.value==0)
645 home = 1;
646 } else if (res == 1) {
647 if (++s >= sizeof(codes)/sizeof(*codes))
648 s = 0;
649 if (codes[s] > 0) {
650 enable_debug_led();
651 } else {
652 disable_debug_led();
653 }
654 }
655 } while (!home);
656 uninit_getevent();
657 }
658
659 /* don't forget to turn debug led off */
660 disable_debug_led();
661
662 /* close filedescriptor */
663 LOG("debuggerd resuming process %d", cr->pid);
664 }
665
666 static void handle_crashing_process(int fd)
667 {
668 char buf[64];
669 struct stat s;
670 unsigned tid;
671 struct ucred cr;
672 int n, len, status;
673 int tid_attach_status = -1;
674 unsigned retry = 30;
675 bool need_cleanup = false;
676
677 char value[PROPERTY_VALUE_MAX];
678 property_get("debug.db.uid", value, "-1");
679 int debug_uid = atoi(value);
680
681 XLOG("handle_crashing_process(%d)\n", fd);
682
683 len = sizeof(cr);
684 n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
685 if(n != 0) {
686 LOG("cannot get credentials\n");
687 goto done;
688 }
689
690 XLOG("reading tid\n");
691 fcntl(fd, F_SETFL, O_NONBLOCK);
692 while((n = read(fd, &tid, sizeof(unsigned))) != sizeof(unsigned)) {
693 if(errno == EINTR) continue;
694 if(errno == EWOULDBLOCK) {
695 if(retry-- > 0) {
696 usleep(100 * 1000);
697 continue;
698 }
699 LOG("timed out reading tid\n");
700 goto done;
701 }
702 LOG("read failure? %s\n", strerror(errno));
703 goto done;
704 }
705
706 sprintf(buf,"/proc/%d/task/%d", cr.pid, tid);
707 if(stat(buf, &s)) {
708 LOG("tid %d does not exist in pid %d. ignorning debug request\n",
709 tid, cr.pid);
710 close(fd);
711 return;
712 }
713
714 XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid);
715
716 tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0);
717 if(tid_attach_status < 0) {
718 LOG("ptrace attach failed: %s\n", strerror(errno));
719 goto done;
720 }
721
722 close(fd);
723 fd = -1;
724
725 for(;;) {
726 n = waitpid(tid, &status, __WALL);
727
728 if(n < 0) {
729 if(errno == EAGAIN) continue;
730 LOG("waitpid failed: %s\n", strerror(errno));
731 goto done;
732 }
733
734 XLOG("waitpid: n=%d status=%08x\n", n, status);
735
736 if(WIFSTOPPED(status)){
737 n = WSTOPSIG(status);
738 switch(n) {
739 case SIGSTOP:
740 XLOG("stopped -- continuing\n");
741 n = ptrace(PTRACE_CONT, tid, 0, 0);
742 if(n) {
743 LOG("ptrace failed: %s\n", strerror(errno));
744 goto done;
745 }
746 continue;
747
748 case SIGILL:
749 case SIGABRT:
750 case SIGBUS:
751 case SIGFPE:
752 case SIGSEGV:
753 case SIGSTKFLT: {
754 XLOG("stopped -- fatal signal\n");
755 need_cleanup = engrave_tombstone(cr.pid, tid, debug_uid, n);
756 kill(tid, SIGSTOP);
757 goto done;
758 }
759
760 default:
761 XLOG("stopped -- unexpected signal\n");
762 goto done;
763 }
764 } else {
765 XLOG("unexpected waitpid response\n");
766 goto done;
767 }
768 }
769
770 done:
771 XLOG("detaching\n");
772
773 /* stop the process so we can debug */
774 kill(cr.pid, SIGSTOP);
775
776 /*
777 * If a thread has been attached by ptrace, make sure it is detached
778 * successfully otherwise we will get a zombie.
779 */
780 if (tid_attach_status == 0) {
781 int detach_status;
782 /* detach so we can attach gdbserver */
783 detach_status = ptrace(PTRACE_DETACH, tid, 0, 0);
784 need_cleanup |= (detach_status != 0);
785 }
786
787 /*
788 * if debug.db.uid is set, its value indicates if we should wait
789 * for user action for the crashing process.
790 * in this case, we log a message and turn the debug LED on
791 * waiting for a gdb connection (for instance)
792 */
793
794 if ((signed)cr.uid <= debug_uid) {
795 wait_for_user_action(tid, &cr);
796 }
797
798 /* resume stopped process (so it can crash in peace) */
799 kill(cr.pid, SIGCONT);
800
801 if (need_cleanup) {
802 LOG("debuggerd committing suicide to free the zombie!\n");
803 kill(getpid(), SIGKILL);
804 }
805
806 if(fd != -1) close(fd);
807 }
808
809 int main(int argc, char **argv)
810 {
811 int s;
812 struct sigaction act;
813
814 process_name_ptr = argv;
815
816 logsocket = socket_local_client("logd",
817 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
818 if(logsocket < 0) {
819 logsocket = -1;
820 } else {
821 fcntl(logsocket, F_SETFD, FD_CLOEXEC);
822 }
823
824 act.sa_handler = SIG_DFL;
825 sigemptyset(&act.sa_mask);
826 sigaddset(&act.sa_mask,SIGCHLD);
827 act.sa_flags = SA_NOCLDWAIT;
828 sigaction(SIGCHLD, &act, 0);
829
830 s = socket_local_server("android:debuggerd",
831 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
832 if(s < 0) return -1;
833 fcntl(s, F_SETFD, FD_CLOEXEC);
834
835 LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
836
837 for(;;) {
838 struct sockaddr addr;
839 socklen_t alen;
840 int fd;
841
842 alen = sizeof(addr);
843 fd = accept(s, &addr, &alen);
844 if(fd < 0) continue;
845
846 fcntl(fd, F_SETFD, FD_CLOEXEC);
847
848 handle_crashing_process(fd);
849 }
850 return 0;
851 }
+0
-219
debuggerd/getevent.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <dirent.h>
5 #include <fcntl.h>
6 #include <sys/ioctl.h>
7 #include <sys/inotify.h>
8 #include <sys/limits.h>
9 #include <sys/poll.h>
10 #include <linux/input.h>
11 #include <errno.h>
12 #include <cutils/log.h>
13
14 static struct pollfd *ufds;
15 static char **device_names;
16 static int nfds;
17
18 static int open_device(const char *device)
19 {
20 int version;
21 int fd;
22 struct pollfd *new_ufds;
23 char **new_device_names;
24 char name[80];
25 char location[80];
26 char idstr[80];
27 struct input_id id;
28
29 fd = open(device, O_RDWR);
30 if(fd < 0) {
31 return -1;
32 }
33
34 if(ioctl(fd, EVIOCGVERSION, &version)) {
35 return -1;
36 }
37 if(ioctl(fd, EVIOCGID, &id)) {
38 return -1;
39 }
40 name[sizeof(name) - 1] = '\0';
41 location[sizeof(location) - 1] = '\0';
42 idstr[sizeof(idstr) - 1] = '\0';
43 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
44 //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
45 name[0] = '\0';
46 }
47 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
48 //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
49 location[0] = '\0';
50 }
51 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
52 //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
53 idstr[0] = '\0';
54 }
55
56 new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
57 if(new_ufds == NULL) {
58 fprintf(stderr, "out of memory\n");
59 return -1;
60 }
61 ufds = new_ufds;
62 new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
63 if(new_device_names == NULL) {
64 fprintf(stderr, "out of memory\n");
65 return -1;
66 }
67 device_names = new_device_names;
68 ufds[nfds].fd = fd;
69 ufds[nfds].events = POLLIN;
70 device_names[nfds] = strdup(device);
71 nfds++;
72
73 return 0;
74 }
75
76 int close_device(const char *device)
77 {
78 int i;
79 for(i = 1; i < nfds; i++) {
80 if(strcmp(device_names[i], device) == 0) {
81 int count = nfds - i - 1;
82 free(device_names[i]);
83 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
84 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
85 nfds--;
86 return 0;
87 }
88 }
89 return -1;
90 }
91
92 static int read_notify(const char *dirname, int nfd)
93 {
94 int res;
95 char devname[PATH_MAX];
96 char *filename;
97 char event_buf[512];
98 int event_size;
99 int event_pos = 0;
100 struct inotify_event *event;
101
102 res = read(nfd, event_buf, sizeof(event_buf));
103 if(res < (int)sizeof(*event)) {
104 if(errno == EINTR)
105 return 0;
106 fprintf(stderr, "could not get event, %s\n", strerror(errno));
107 return 1;
108 }
109 //printf("got %d bytes of event information\n", res);
110
111 strcpy(devname, dirname);
112 filename = devname + strlen(devname);
113 *filename++ = '/';
114
115 while(res >= (int)sizeof(*event)) {
116 event = (struct inotify_event *)(event_buf + event_pos);
117 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
118 if(event->len) {
119 strcpy(filename, event->name);
120 if(event->mask & IN_CREATE) {
121 open_device(devname);
122 }
123 else {
124 close_device(devname);
125 }
126 }
127 event_size = sizeof(*event) + event->len;
128 res -= event_size;
129 event_pos += event_size;
130 }
131 return 0;
132 }
133
134 static int scan_dir(const char *dirname)
135 {
136 char devname[PATH_MAX];
137 char *filename;
138 DIR *dir;
139 struct dirent *de;
140 dir = opendir(dirname);
141 if(dir == NULL)
142 return -1;
143 strcpy(devname, dirname);
144 filename = devname + strlen(devname);
145 *filename++ = '/';
146 while((de = readdir(dir))) {
147 if(de->d_name[0] == '.' &&
148 (de->d_name[1] == '\0' ||
149 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
150 continue;
151 strcpy(filename, de->d_name);
152 open_device(devname);
153 }
154 closedir(dir);
155 return 0;
156 }
157
158 int init_getevent()
159 {
160 int res;
161 const char *device_path = "/dev/input";
162
163 nfds = 1;
164 ufds = calloc(1, sizeof(ufds[0]));
165 ufds[0].fd = inotify_init();
166 ufds[0].events = POLLIN;
167
168 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
169 if(res < 0) {
170 return 1;
171 }
172 res = scan_dir(device_path);
173 if(res < 0) {
174 return 1;
175 }
176 return 0;
177 }
178
179 void uninit_getevent()
180 {
181 int i;
182 for(i = 0; i < nfds; i++) {
183 close(ufds[i].fd);
184 }
185 free(ufds);
186 ufds = 0;
187 nfds = 0;
188 }
189
190 int get_event(struct input_event* event, int timeout)
191 {
192 int res;
193 int i;
194 int pollres;
195 const char *device_path = "/dev/input";
196 while(1) {
197 pollres = poll(ufds, nfds, timeout);
198 if (pollres == 0) {
199 return 1;
200 }
201 if(ufds[0].revents & POLLIN) {
202 read_notify(device_path, ufds[0].fd);
203 }
204 for(i = 1; i < nfds; i++) {
205 if(ufds[i].revents) {
206 if(ufds[i].revents & POLLIN) {
207 res = read(ufds[i].fd, event, sizeof(*event));
208 if(res < (int)sizeof(event)) {
209 fprintf(stderr, "could not get event\n");
210 return -1;
211 }
212 return 0;
213 }
214 }
215 }
216 }
217 return 0;
218 }
+0
-345
debuggerd/pr-support.c less more
0 /* ARM EABI compliant unwinding routines
1 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
2 Contributed by Paul Brook
3
4 This file is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any
7 later version.
8
9 In addition to the permissions in the GNU General Public License, the
10 Free Software Foundation gives you unlimited permission to link the
11 compiled version of this file into combinations with other programs,
12 and to distribute those combinations without any restriction coming
13 from the use of this file. (The General Public License restrictions
14 do apply in other respects; for example, they cover modification of
15 the file, and distribution when not linked into a combine
16 executable.)
17
18 This file is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; see the file COPYING. If not, write to
25 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26 Boston, MA 02110-1301, USA. */
27
28 /****************************************************************************
29 * The functions here are derived from gcc/config/arm/pr-support.c from the
30 * 4.3.x release. The main changes here involve the use of ptrace to retrieve
31 * memory/processor states from a remote process.
32 ****************************************************************************/
33
34 #include <sys/types.h>
35 #include <unwind.h>
36
37 #include "utility.h"
38
39 /* We add a prototype for abort here to avoid creating a dependency on
40 target headers. */
41 extern void abort (void);
42
43 /* Derived from _Unwind_VRS_Pop to use ptrace */
44 extern _Unwind_VRS_Result
45 unwind_VRS_Pop_with_ptrace (_Unwind_Context *context,
46 _Unwind_VRS_RegClass regclass,
47 _uw discriminator,
48 _Unwind_VRS_DataRepresentation representation,
49 pid_t pid);
50
51 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
52
53 /* Misc constants. */
54 #define R_IP 12
55 #define R_SP 13
56 #define R_LR 14
57 #define R_PC 15
58
59 #define uint32_highbit (((_uw) 1) << 31)
60
61 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
62
63 /* Unwind descriptors. */
64
65 typedef struct
66 {
67 _uw16 length;
68 _uw16 offset;
69 } EHT16;
70
71 typedef struct
72 {
73 _uw length;
74 _uw offset;
75 } EHT32;
76
77 /* Personality routine helper functions. */
78
79 #define CODE_FINISH (0xb0)
80
81 /* Derived from next_unwind_byte to use ptrace */
82 /* Return the next byte of unwinding information, or CODE_FINISH if there is
83 no data remaining. */
84 static inline _uw8
85 next_unwind_byte_with_ptrace (__gnu_unwind_state * uws, pid_t pid)
86 {
87 _uw8 b;
88
89 if (uws->bytes_left == 0)
90 {
91 /* Load another word */
92 if (uws->words_left == 0)
93 return CODE_FINISH; /* Nothing left. */
94 uws->words_left--;
95 uws->data = get_remote_word(pid, uws->next);
96 uws->next++;
97 uws->bytes_left = 3;
98 }
99 else
100 uws->bytes_left--;
101
102 /* Extract the most significant byte. */
103 b = (uws->data >> 24) & 0xff;
104 uws->data <<= 8;
105 return b;
106 }
107
108 /* Execute the unwinding instructions described by UWS. */
109 _Unwind_Reason_Code
110 unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws,
111 pid_t pid)
112 {
113 _uw op;
114 int set_pc;
115 _uw reg;
116
117 set_pc = 0;
118 for (;;)
119 {
120 op = next_unwind_byte_with_ptrace (uws, pid);
121 if (op == CODE_FINISH)
122 {
123 /* If we haven't already set pc then copy it from lr. */
124 if (!set_pc)
125 {
126 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
127 &reg);
128 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
129 &reg);
130 set_pc = 1;
131 }
132 /* Drop out of the loop. */
133 break;
134 }
135 if ((op & 0x80) == 0)
136 {
137 /* vsp = vsp +- (imm6 << 2 + 4). */
138 _uw offset;
139
140 offset = ((op & 0x3f) << 2) + 4;
141 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
142 if (op & 0x40)
143 reg -= offset;
144 else
145 reg += offset;
146 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
147 continue;
148 }
149
150 if ((op & 0xf0) == 0x80)
151 {
152 op = (op << 8) | next_unwind_byte_with_ptrace (uws, pid);
153 if (op == 0x8000)
154 {
155 /* Refuse to unwind. */
156 return _URC_FAILURE;
157 }
158 /* Pop r4-r15 under mask. */
159 op = (op << 4) & 0xfff0;
160 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, _UVRSD_UINT32,
161 pid)
162 != _UVRSR_OK)
163 return _URC_FAILURE;
164 if (op & (1 << R_PC))
165 set_pc = 1;
166 continue;
167 }
168 if ((op & 0xf0) == 0x90)
169 {
170 op &= 0xf;
171 if (op == 13 || op == 15)
172 /* Reserved. */
173 return _URC_FAILURE;
174 /* vsp = r[nnnn]. */
175 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
176 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
177 continue;
178 }
179 if ((op & 0xf0) == 0xa0)
180 {
181 /* Pop r4-r[4+nnn], [lr]. */
182 _uw mask;
183
184 mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
185 if (op & 8)
186 mask |= (1 << R_LR);
187 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, mask, _UVRSD_UINT32,
188 pid)
189 != _UVRSR_OK)
190 return _URC_FAILURE;
191 continue;
192 }
193 if ((op & 0xf0) == 0xb0)
194 {
195 /* op == 0xb0 already handled. */
196 if (op == 0xb1)
197 {
198 op = next_unwind_byte_with_ptrace (uws, pid);
199 if (op == 0 || ((op & 0xf0) != 0))
200 /* Spare. */
201 return _URC_FAILURE;
202 /* Pop r0-r4 under mask. */
203 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op,
204 _UVRSD_UINT32, pid)
205 != _UVRSR_OK)
206 return _URC_FAILURE;
207 continue;
208 }
209 if (op == 0xb2)
210 {
211 /* vsp = vsp + 0x204 + (uleb128 << 2). */
212 int shift;
213
214 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
215 &reg);
216 op = next_unwind_byte_with_ptrace (uws, pid);
217 shift = 2;
218 while (op & 0x80)
219 {
220 reg += ((op & 0x7f) << shift);
221 shift += 7;
222 op = next_unwind_byte_with_ptrace (uws, pid);
223 }
224 reg += ((op & 0x7f) << shift) + 0x204;
225 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
226 &reg);
227 continue;
228 }
229 if (op == 0xb3)
230 {
231 /* Pop VFP registers with fldmx. */
232 op = next_unwind_byte_with_ptrace (uws, pid);
233 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
234 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX,
235 pid)
236 != _UVRSR_OK)
237 return _URC_FAILURE;
238 continue;
239 }
240 if ((op & 0xfc) == 0xb4)
241 {
242 /* Pop FPA E[4]-E[4+nn]. */
243 op = 0x40000 | ((op & 3) + 1);
244 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
245 pid)
246 != _UVRSR_OK)
247 return _URC_FAILURE;
248 continue;
249 }
250 /* op & 0xf8 == 0xb8. */
251 /* Pop VFP D[8]-D[8+nnn] with fldmx. */
252 op = 0x80000 | ((op & 7) + 1);
253 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, pid)
254 != _UVRSR_OK)
255 return _URC_FAILURE;
256 continue;
257 }
258 if ((op & 0xf0) == 0xc0)
259 {
260 if (op == 0xc6)
261 {
262 /* Pop iWMMXt D registers. */
263 op = next_unwind_byte_with_ptrace (uws, pid);
264 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
265 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op,
266 _UVRSD_UINT64, pid)
267 != _UVRSR_OK)
268 return _URC_FAILURE;
269 continue;
270 }
271 if (op == 0xc7)
272 {
273 op = next_unwind_byte_with_ptrace (uws, pid);
274 if (op == 0 || (op & 0xf0) != 0)
275 /* Spare. */
276 return _URC_FAILURE;
277 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */
278 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXC, op,
279 _UVRSD_UINT32, pid)
280 != _UVRSR_OK)
281 return _URC_FAILURE;
282 continue;
283 }
284 if ((op & 0xf8) == 0xc0)
285 {
286 /* Pop iWMMXt wR[10]-wR[10+nnn]. */
287 op = 0xa0000 | ((op & 0xf) + 1);
288 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op,
289 _UVRSD_UINT64, pid)
290 != _UVRSR_OK)
291 return _URC_FAILURE;
292 continue;
293 }
294 if (op == 0xc8)
295 {
296 #ifndef __VFP_FP__
297 /* Pop FPA registers. */
298 op = next_unwind_byte_with_ptrace (uws, pid);
299 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
300 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
301 pid)
302 != _UVRSR_OK)
303 return _URC_FAILURE;
304 continue;
305 #else
306 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
307 op = next_unwind_byte_with_ptrace (uws, pid);
308 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
309 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op,
310 _UVRSD_DOUBLE, pid)
311 != _UVRSR_OK)
312 return _URC_FAILURE;
313 continue;
314 #endif
315 }
316 if (op == 0xc9)
317 {
318 /* Pop VFP registers with fldmd. */
319 op = next_unwind_byte_with_ptrace (uws, pid);
320 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
321 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op,
322 _UVRSD_DOUBLE, pid)
323 != _UVRSR_OK)
324 return _URC_FAILURE;
325 continue;
326 }
327 /* Spare. */
328 return _URC_FAILURE;
329 }
330 if ((op & 0xf8) == 0xd0)
331 {
332 /* Pop VFP D[8]-D[8+nnn] with fldmd. */
333 op = 0x80000 | ((op & 7) + 1);
334 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_DOUBLE,
335 pid)
336 != _UVRSR_OK)
337 return _URC_FAILURE;
338 continue;
339 }
340 /* Spare. */
341 return _URC_FAILURE;
342 }
343 return _URC_OK;
344 }
+0
-654
debuggerd/unwind-arm.c less more
0 /* ARM EABI compliant unwinding routines.
1 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
2 Contributed by Paul Brook
3
4 This file is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any
7 later version.
8
9 In addition to the permissions in the GNU General Public License, the
10 Free Software Foundation gives you unlimited permission to link the
11 compiled version of this file into combinations with other programs,
12 and to distribute those combinations without any restriction coming
13 from the use of this file. (The General Public License restrictions
14 do apply in other respects; for example, they cover modification of
15 the file, and distribution when not linked into a combine
16 executable.)
17
18 This file is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; see the file COPYING. If not, write to
25 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26 Boston, MA 02110-1301, USA. */
27
28 /****************************************************************************
29 * The functions here are derived from gcc/config/arm/unwind-arm.c from the
30 * 4.3.x release. The main changes here involve the use of ptrace to retrieve
31 * memory/processor states from a remote process.
32 ****************************************************************************/
33
34 #include <cutils/logd.h>
35 #include <sys/ptrace.h>
36 #include <unwind.h>
37 #include "utility.h"
38
39 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
40
41 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
42 bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
43 bool __attribute__((weak)) __cxa_type_match(_Unwind_Control_Block *ucbp,
44 const type_info *rttip,
45 bool is_reference,
46 void **matched_object);
47
48 /* Misc constants. */
49 #define R_IP 12
50 #define R_SP 13
51 #define R_LR 14
52 #define R_PC 15
53
54 #define EXIDX_CANTUNWIND 1
55 #define uint32_highbit (((_uw) 1) << 31)
56
57 #define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1)
58 #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2)
59 #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3)
60 #define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4)
61
62 struct core_regs
63 {
64 _uw r[16];
65 };
66
67 /* We use normal integer types here to avoid the compiler generating
68 coprocessor instructions. */
69 struct vfp_regs
70 {
71 _uw64 d[16];
72 _uw pad;
73 };
74
75 struct vfpv3_regs
76 {
77 /* Always populated via VSTM, so no need for the "pad" field from
78 vfp_regs (which is used to store the format word for FSTMX). */
79 _uw64 d[16];
80 };
81
82 struct fpa_reg
83 {
84 _uw w[3];
85 };
86
87 struct fpa_regs
88 {
89 struct fpa_reg f[8];
90 };
91
92 struct wmmxd_regs
93 {
94 _uw64 wd[16];
95 };
96
97 struct wmmxc_regs
98 {
99 _uw wc[4];
100 };
101
102 /* Unwind descriptors. */
103
104 typedef struct
105 {
106 _uw16 length;
107 _uw16 offset;
108 } EHT16;
109
110 typedef struct
111 {
112 _uw length;
113 _uw offset;
114 } EHT32;
115
116 /* The ABI specifies that the unwind routines may only use core registers,
117 except when actually manipulating coprocessor state. This allows
118 us to write one implementation that works on all platforms by
119 demand-saving coprocessor registers.
120
121 During unwinding we hold the coprocessor state in the actual hardware
122 registers and allocate demand-save areas for use during phase1
123 unwinding. */
124
125 typedef struct
126 {
127 /* The first fields must be the same as a phase2_vrs. */
128 _uw demand_save_flags;
129 struct core_regs core;
130 _uw prev_sp; /* Only valid during forced unwinding. */
131 struct vfp_regs vfp;
132 struct vfpv3_regs vfp_regs_16_to_31;
133 struct fpa_regs fpa;
134 struct wmmxd_regs wmmxd;
135 struct wmmxc_regs wmmxc;
136 } phase1_vrs;
137
138 /* This must match the structure created by the assembly wrappers. */
139 typedef struct
140 {
141 _uw demand_save_flags;
142 struct core_regs core;
143 } phase2_vrs;
144
145
146 /* An exception index table entry. */
147
148 typedef struct __EIT_entry
149 {
150 _uw fnoffset;
151 _uw content;
152 } __EIT_entry;
153
154 /* Derived version to use ptrace */
155 typedef _Unwind_Reason_Code (*personality_routine_with_ptrace)
156 (_Unwind_State,
157 _Unwind_Control_Block *,
158 _Unwind_Context *,
159 pid_t);
160
161 /* Derived version to use ptrace */
162 /* ABI defined personality routines. */
163 static _Unwind_Reason_Code unwind_cpp_pr0_with_ptrace (_Unwind_State,
164 _Unwind_Control_Block *, _Unwind_Context *, pid_t);
165 static _Unwind_Reason_Code unwind_cpp_pr1_with_ptrace (_Unwind_State,
166 _Unwind_Control_Block *, _Unwind_Context *, pid_t);
167 static _Unwind_Reason_Code unwind_cpp_pr2_with_ptrace (_Unwind_State,
168 _Unwind_Control_Block *, _Unwind_Context *, pid_t);
169
170 /* Execute the unwinding instructions described by UWS. */
171 extern _Unwind_Reason_Code
172 unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws,
173 pid_t pid);
174
175 /* Derived version to use ptrace. Only handles core registers. Disregards
176 * FP and others.
177 */
178 /* ABI defined function to pop registers off the stack. */
179
180 _Unwind_VRS_Result unwind_VRS_Pop_with_ptrace (_Unwind_Context *context,
181 _Unwind_VRS_RegClass regclass,
182 _uw discriminator,
183 _Unwind_VRS_DataRepresentation representation,
184 pid_t pid)
185 {
186 phase1_vrs *vrs = (phase1_vrs *) context;
187
188 switch (regclass)
189 {
190 case _UVRSC_CORE:
191 {
192 _uw *ptr;
193 _uw mask;
194 int i;
195
196 if (representation != _UVRSD_UINT32)
197 return _UVRSR_FAILED;
198
199 mask = discriminator & 0xffff;
200 ptr = (_uw *) vrs->core.r[R_SP];
201 /* Pop the requested registers. */
202 for (i = 0; i < 16; i++)
203 {
204 if (mask & (1 << i)) {
205 vrs->core.r[i] = get_remote_word(pid, ptr);
206 ptr++;
207 }
208 }
209 /* Writeback the stack pointer value if it wasn't restored. */
210 if ((mask & (1 << R_SP)) == 0)
211 vrs->core.r[R_SP] = (_uw) ptr;
212 }
213 return _UVRSR_OK;
214
215 default:
216 return _UVRSR_FAILED;
217 }
218 }
219
220 /* Core unwinding functions. */
221
222 /* Calculate the address encoded by a 31-bit self-relative offset at address
223 P. */
224 static inline _uw
225 selfrel_offset31 (const _uw *p, pid_t pid)
226 {
227 _uw offset = get_remote_word(pid, (void*)p);
228
229 //offset = *p;
230 /* Sign extend to 32 bits. */
231 if (offset & (1 << 30))
232 offset |= 1u << 31;
233 else
234 offset &= ~(1u << 31);
235
236 return offset + (_uw) p;
237 }
238
239
240 /* Perform a binary search for RETURN_ADDRESS in TABLE. The table contains
241 NREC entries. */
242
243 static const __EIT_entry *
244 search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address,
245 pid_t pid)
246 {
247 _uw next_fn;
248 _uw this_fn;
249 int n, left, right;
250
251 if (nrec == 0)
252 return (__EIT_entry *) 0;
253
254 left = 0;
255 right = nrec - 1;
256
257 while (1)
258 {
259 n = (left + right) / 2;
260 this_fn = selfrel_offset31 (&table[n].fnoffset, pid);
261 if (n != nrec - 1)
262 next_fn = selfrel_offset31 (&table[n + 1].fnoffset, pid) - 1;
263 else
264 next_fn = (_uw)0 - 1;
265
266 if (return_address < this_fn)
267 {
268 if (n == left)
269 return (__EIT_entry *) 0;
270 right = n - 1;
271 }
272 else if (return_address <= next_fn)
273 return &table[n];
274 else
275 left = n + 1;
276 }
277 }
278
279 /* Find the exception index table eintry for the given address. */
280 static const __EIT_entry*
281 get_eitp(_uw return_address, pid_t pid, mapinfo *map, mapinfo **containing_map)
282 {
283 const __EIT_entry *eitp = NULL;
284 int nrec;
285 mapinfo *mi;
286
287 /* The return address is the address of the instruction following the
288 call instruction (plus one in thumb mode). If this was the last
289 instruction in the function the address will lie in the following
290 function. Subtract 2 from the address so that it points within the call
291 instruction itself. */
292 if (return_address >= 2)
293 return_address -= 2;
294
295 for (mi = map; mi != NULL; mi = mi->next) {
296 if (return_address >= mi->start && return_address <= mi->end) break;
297 }
298
299 if (mi) {
300 if (containing_map) *containing_map = mi;
301 eitp = (__EIT_entry *) mi->exidx_start;
302 nrec = (mi->exidx_end - mi->exidx_start)/sizeof(__EIT_entry);
303 eitp = search_EIT_table (eitp, nrec, return_address, pid);
304 }
305 return eitp;
306 }
307
308 /* Find the exception index table eintry for the given address.
309 Fill in the relevant fields of the UCB.
310 Returns _URC_FAILURE if an error occurred, _URC_OK on success. */
311
312 static _Unwind_Reason_Code
313 get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address, pid_t pid,
314 mapinfo *map, mapinfo **containing_map)
315 {
316 const __EIT_entry *eitp;
317
318 eitp = get_eitp(return_address, pid, map, containing_map);
319
320 if (!eitp)
321 {
322 UCB_PR_ADDR (ucbp) = 0;
323 return _URC_FAILURE;
324 }
325 ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset, pid);
326
327 _uw eitp_content = get_remote_word(pid, (void *)&eitp->content);
328
329 /* Can this frame be unwound at all? */
330 if (eitp_content == EXIDX_CANTUNWIND)
331 {
332 UCB_PR_ADDR (ucbp) = 0;
333 return _URC_END_OF_STACK;
334 }
335
336 /* Obtain the address of the "real" __EHT_Header word. */
337
338 if (eitp_content & uint32_highbit)
339 {
340 /* It is immediate data. */
341 ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content;
342 ucbp->pr_cache.additional = 1;
343 }
344 else
345 {
346 /* The low 31 bits of the content field are a self-relative
347 offset to an _Unwind_EHT_Entry structure. */
348 ucbp->pr_cache.ehtp =
349 (_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content, pid);
350 ucbp->pr_cache.additional = 0;
351 }
352
353 /* Discover the personality routine address. */
354 if (get_remote_word(pid, ucbp->pr_cache.ehtp) & (1u << 31))
355 {
356 /* One of the predefined standard routines. */
357 _uw idx = (get_remote_word(pid, ucbp->pr_cache.ehtp) >> 24) & 0xf;
358 if (idx == 0)
359 UCB_PR_ADDR (ucbp) = (_uw) &unwind_cpp_pr0_with_ptrace;
360 else if (idx == 1)
361 UCB_PR_ADDR (ucbp) = (_uw) &unwind_cpp_pr1_with_ptrace;
362 else if (idx == 2)
363 UCB_PR_ADDR (ucbp) = (_uw) &unwind_cpp_pr2_with_ptrace;
364 else
365 { /* Failed */
366 UCB_PR_ADDR (ucbp) = 0;
367 return _URC_FAILURE;
368 }
369 }
370 else
371 {
372 /* Execute region offset to PR */
373 UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp, pid);
374 /* Since we are unwinding the stack from a different process, it is
375 * impossible to execute the personality routine in debuggerd. Punt here.
376 */
377 return _URC_FAILURE;
378 }
379 return _URC_OK;
380 }
381
382 /* Print out the current call level, pc, and module name in the crash log */
383 static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid,
384 int tfd,
385 int stack_level,
386 mapinfo *map,
387 unsigned int sp_list[],
388 bool at_fault)
389 {
390 _uw pc;
391 _uw rel_pc;
392 phase2_vrs *vrs = (phase2_vrs*) context;
393 const mapinfo *mi;
394 bool only_in_tombstone = !at_fault;
395
396 if (stack_level < STACK_CONTENT_DEPTH) {
397 sp_list[stack_level] = vrs->core.r[R_SP];
398 }
399 pc = vrs->core.r[R_PC];
400
401 // Top level frame
402 if (stack_level == 0) {
403 pc &= ~1;
404 }
405 // For deeper framers, rollback pc by one instruction
406 else {
407 pc = vrs->core.r[R_PC];
408 /* Thumb mode - need to check whether the bl(x) has long offset or not.
409 * Examples:
410 *
411 * arm blx in the middle of thumb:
412 * 187ae: 2300 movs r3, #0
413 * 187b0: f7fe ee1c blx 173ec
414 * 187b4: 2c00 cmp r4, #0
415 *
416 * arm bl in the middle of thumb:
417 * 187d8: 1c20 adds r0, r4, #0
418 * 187da: f136 fd15 bl 14f208
419 * 187de: 2800 cmp r0, #0
420 *
421 * pure thumb:
422 * 18894: 189b adds r3, r3, r2
423 * 18896: 4798 blx r3
424 * 18898: b001 add sp, #4
425 */
426 if (pc & 1) {
427 _uw prev_word;
428 pc = (pc & ~1);
429 prev_word = get_remote_word(pid, (void *) pc-4);
430 // Long offset
431 if ((prev_word & 0xf0000000) == 0xf0000000 &&
432 (prev_word & 0x0000e000) == 0x0000e000) {
433 pc -= 4;
434 }
435 else {
436 pc -= 2;
437 }
438 }
439 else {
440 pc -= 4;
441 }
442 }
443
444 /* We used to print the absolute PC in the back trace, and mask out the top
445 * 3 bits to guesstimate the offset in the .so file. This is not working for
446 * non-prelinked libraries since the starting offset may not be aligned on
447 * 1MB boundaries, and the library may be larger than 1MB. So for .so
448 * addresses we print the relative offset in back trace.
449 */
450 rel_pc = pc;
451 mi = pc_to_mapinfo(map, pc, &rel_pc);
452
453 _LOG(tfd, only_in_tombstone,
454 " #%02d pc %08x %s\n", stack_level, rel_pc,
455 mi ? mi->name : "");
456
457 return _URC_NO_REASON;
458 }
459
460 /* Derived from __gnu_Unwind_Backtrace to use ptrace */
461 /* Perform stack backtrace through unwind data. Return the level of stack it
462 * unwinds.
463 */
464 int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
465 unsigned int sp_list[], int *frame0_pc_sane,
466 bool at_fault)
467 {
468 phase1_vrs saved_vrs;
469 _Unwind_Reason_Code code = _URC_OK;
470 struct pt_regs r;
471 int i;
472 int stack_level = 0;
473
474 _Unwind_Control_Block ucb;
475 _Unwind_Control_Block *ucbp = &ucb;
476
477 if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return 0;
478
479 for (i = 0; i < 16; i++) {
480 saved_vrs.core.r[i] = r.uregs[i];
481 /*
482 _LOG(tfd, "r[%d] = 0x%x\n", i, saved_vrs.core.r[i]);
483 */
484 }
485
486 /* Set demand-save flags. */
487 saved_vrs.demand_save_flags = ~(_uw) 0;
488
489 /*
490 * If the app crashes because of calling the weeds, we cannot pass the PC
491 * to the usual unwinding code as the EXIDX mapping will fail.
492 * Instead, we simply print out the 0 as the top frame, and resume the
493 * unwinding process with the value stored in LR.
494 */
495 if (get_eitp(saved_vrs.core.r[R_PC], pid, map, NULL) == NULL) {
496 *frame0_pc_sane = 0;
497 log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level,
498 map, sp_list, at_fault);
499 saved_vrs.core.r[R_PC] = saved_vrs.core.r[R_LR];
500 stack_level++;
501 }
502
503 do {
504 mapinfo *this_map = NULL;
505 /* Find the entry for this routine. */
506 if (get_eit_entry(ucbp, saved_vrs.core.r[R_PC], pid, map, &this_map)
507 != _URC_OK) {
508 /* Uncomment the code below to study why the unwinder failed */
509 #if 0
510 /* Shed more debugging info for stack unwinder improvement */
511 if (this_map) {
512 _LOG(tfd, 1,
513 "Relative PC=%#x from %s not contained in EXIDX\n",
514 saved_vrs.core.r[R_PC] - this_map->start, this_map->name);
515 }
516 _LOG(tfd, 1, "PC=%#x SP=%#x\n",
517 saved_vrs.core.r[R_PC], saved_vrs.core.r[R_SP]);
518 #endif
519 code = _URC_FAILURE;
520 break;
521 }
522
523 /* The dwarf unwinder assumes the context structure holds things
524 like the function and LSDA pointers. The ARM implementation
525 caches these in the exception header (UCB). To avoid
526 rewriting everything we make the virtual IP register point at
527 the UCB. */
528 _Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp);
529
530 /* Call log function. */
531 if (log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level,
532 map, sp_list, at_fault) != _URC_NO_REASON) {
533 code = _URC_FAILURE;
534 break;
535 }
536 stack_level++;
537
538 /* Call the pr to decide what to do. */
539 code = ((personality_routine_with_ptrace) UCB_PR_ADDR (ucbp))(
540 _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, ucbp,
541 (void *) &saved_vrs, pid);
542 /*
543 * In theory the unwinding process will stop when the end of stack is
544 * reached or there is no unwinding information for the code address.
545 * To add another level of guarantee that the unwinding process
546 * will terminate we will stop it when the STACK_CONTENT_DEPTH is reached.
547 */
548 } while (code != _URC_END_OF_STACK && code != _URC_FAILURE &&
549 stack_level < STACK_CONTENT_DEPTH);
550 return stack_level;
551 }
552
553
554 /* Derived version to use ptrace */
555 /* Common implementation for ARM ABI defined personality routines.
556 ID is the index of the personality routine, other arguments are as defined
557 by __aeabi_unwind_cpp_pr{0,1,2}. */
558
559 static _Unwind_Reason_Code
560 unwind_pr_common_with_ptrace (_Unwind_State state,
561 _Unwind_Control_Block *ucbp,
562 _Unwind_Context *context,
563 int id,
564 pid_t pid)
565 {
566 __gnu_unwind_state uws;
567 _uw *data;
568 int phase2_call_unexpected_after_unwind = 0;
569
570 state &= _US_ACTION_MASK;
571
572 data = (_uw *) ucbp->pr_cache.ehtp;
573 uws.data = get_remote_word(pid, data);
574 data++;
575 uws.next = data;
576 if (id == 0)
577 {
578 uws.data <<= 8;
579 uws.words_left = 0;
580 uws.bytes_left = 3;
581 }
582 else
583 {
584 uws.words_left = (uws.data >> 16) & 0xff;
585 uws.data <<= 16;
586 uws.bytes_left = 2;
587 data += uws.words_left;
588 }
589
590 /* Restore the saved pointer. */
591 if (state == _US_UNWIND_FRAME_RESUME)
592 data = (_uw *) ucbp->cleanup_cache.bitpattern[0];
593
594 if ((ucbp->pr_cache.additional & 1) == 0)
595 {
596 /* Process descriptors. */
597 while (get_remote_word(pid, data)) {
598 /**********************************************************************
599 * The original code here seems to deal with exceptions that are not
600 * applicable in our toolchain, thus there is no way to test it for now.
601 * Instead of leaving it here and causing potential instability in
602 * debuggerd, we'd better punt here and leave the stack unwound.
603 * In the future when we discover cases where the stack should be unwound
604 * further but is not, we can revisit the code here.
605 **********************************************************************/
606 return _URC_FAILURE;
607 }
608 /* Finished processing this descriptor. */
609 }
610
611 if (unwind_execute_with_ptrace (context, &uws, pid) != _URC_OK)
612 return _URC_FAILURE;
613
614 if (phase2_call_unexpected_after_unwind)
615 {
616 /* Enter __cxa_unexpected as if called from the call site. */
617 _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC));
618 _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected);
619 return _URC_INSTALL_CONTEXT;
620 }
621
622 return _URC_CONTINUE_UNWIND;
623 }
624
625
626 /* ABI defined personality routine entry points. */
627
628 static _Unwind_Reason_Code
629 unwind_cpp_pr0_with_ptrace (_Unwind_State state,
630 _Unwind_Control_Block *ucbp,
631 _Unwind_Context *context,
632 pid_t pid)
633 {
634 return unwind_pr_common_with_ptrace (state, ucbp, context, 0, pid);
635 }
636
637 static _Unwind_Reason_Code
638 unwind_cpp_pr1_with_ptrace (_Unwind_State state,
639 _Unwind_Control_Block *ucbp,
640 _Unwind_Context *context,
641 pid_t pid)
642 {
643 return unwind_pr_common_with_ptrace (state, ucbp, context, 1, pid);
644 }
645
646 static _Unwind_Reason_Code
647 unwind_cpp_pr2_with_ptrace (_Unwind_State state,
648 _Unwind_Control_Block *ucbp,
649 _Unwind_Context *context,
650 pid_t pid)
651 {
652 return unwind_pr_common_with_ptrace (state, ucbp, context, 2, pid);
653 }
+0
-83
debuggerd/utility.c less more
0 /* system/debuggerd/utility.c
1 **
2 ** Copyright 2008, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <sys/ptrace.h>
18 #include <sys/exec_elf.h>
19 #include <assert.h>
20 #include <string.h>
21 #include <errno.h>
22
23 #include "utility.h"
24
25 /* Get a word from pid using ptrace. The result is the return value. */
26 int get_remote_word(int pid, void *src)
27 {
28 return ptrace(PTRACE_PEEKTEXT, pid, src, NULL);
29 }
30
31
32 /* Handy routine to read aggregated data from pid using ptrace. The read
33 * values are written to the dest locations directly.
34 */
35 void get_remote_struct(int pid, void *src, void *dst, size_t size)
36 {
37 unsigned int i;
38
39 for (i = 0; i+4 <= size; i+=4) {
40 *(int *)(dst+i) = ptrace(PTRACE_PEEKTEXT, pid, src+i, NULL);
41 }
42
43 if (i < size) {
44 int val;
45
46 assert((size - i) < 4);
47 val = ptrace(PTRACE_PEEKTEXT, pid, src+i, NULL);
48 while (i < size) {
49 ((unsigned char *)dst)[i] = val & 0xff;
50 i++;
51 val >>= 8;
52 }
53 }
54 }
55
56 /* Map a pc address to the name of the containing ELF file */
57 const char *map_to_name(mapinfo *mi, unsigned pc, const char* def)
58 {
59 while(mi) {
60 if((pc >= mi->start) && (pc < mi->end)){
61 return mi->name;
62 }
63 mi = mi->next;
64 }
65 return def;
66 }
67
68 /* Find the containing map info for the pc */
69 const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
70 {
71 while(mi) {
72 if((pc >= mi->start) && (pc < mi->end)){
73 // Only calculate the relative offset for shared libraries
74 if (strstr(mi->name, ".so")) {
75 *rel_pc = pc - mi->start;
76 }
77 return mi;
78 }
79 mi = mi->next;
80 }
81 return NULL;
82 }
+0
-56
debuggerd/utility.h less more
0 /* system/debuggerd/utility.h
1 **
2 ** Copyright 2008, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #ifndef __utility_h
18 #define __utility_h
19
20 #include <stddef.h>
21 #include <stdbool.h>
22
23 #ifndef PT_ARM_EXIDX
24 #define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
25 #endif
26
27 #define STACK_CONTENT_DEPTH 32
28
29 typedef struct mapinfo {
30 struct mapinfo *next;
31 unsigned start;
32 unsigned end;
33 unsigned exidx_start;
34 unsigned exidx_end;
35 char name[];
36 } mapinfo;
37
38 /* Get a word from pid using ptrace. The result is the return value. */
39 extern int get_remote_word(int pid, void *src);
40
41 /* Handy routine to read aggregated data from pid using ptrace. The read
42 * values are written to the dest locations directly.
43 */
44 extern void get_remote_struct(int pid, void *src, void *dst, size_t size);
45
46 /* Find the containing map for the pc */
47 const mapinfo *pc_to_mapinfo (mapinfo *mi, unsigned pc, unsigned *rel_pc);
48
49 /* Map a pc address to the name of the containing ELF file */
50 const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
51
52 /* Log information onto the tombstone */
53 extern void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...);
54
55 #endif
+0
-57
fastboot/Android.mk less more
0 # Copyright (C) 2007 Google Inc.
1 #
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #
6 # http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 LOCAL_PATH:= $(call my-dir)
15
16 include $(CLEAR_VARS)
17
18 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg
19 LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
20 LOCAL_MODULE := fastboot
21
22 ifeq ($(HOST_OS),linux)
23 LOCAL_SRC_FILES += usb_linux.c util_linux.c
24 endif
25
26 ifeq ($(HOST_OS),darwin)
27 LOCAL_SRC_FILES += usb_osx.c util_osx.c
28 LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit \
29 -framework Carbon
30 endif
31
32 ifeq ($(HOST_OS),windows)
33 LOCAL_SRC_FILES += usb_windows.c util_windows.c
34 EXTRA_STATIC_LIBS := AdbWinApi
35 LOCAL_C_INCLUDES += /usr/include/w32api/ddk development/host/windows/usb/api
36 ifeq ($(strip $(USE_CYGWIN)),)
37 LOCAL_LDLIBS += -lws2_32
38 USE_SYSDEPS_WIN32 := 1
39 endif
40 endif
41
42 LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz
43
44 include $(BUILD_HOST_EXECUTABLE)
45 $(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
46
47 ifeq ($(HOST_OS),linux)
48 include $(CLEAR_VARS)
49 LOCAL_SRC_FILES := usbtest.c usb_linux.c
50 LOCAL_MODULE := usbtest
51 include $(BUILD_HOST_EXECUTABLE)
52 endif
53
54 ifeq ($(HOST_OS),windows)
55 $(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
56 endif
+0
-85
fastboot/bootimg.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <bootimg.h>
33
34 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline)
35 {
36 strcpy((char*) h->cmdline, cmdline);
37 }
38
39 boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
40 void *ramdisk, unsigned ramdisk_size,
41 void *second, unsigned second_size,
42 unsigned page_size,
43 unsigned *bootimg_size)
44 {
45 unsigned kernel_actual;
46 unsigned ramdisk_actual;
47 unsigned second_actual;
48 unsigned page_mask;
49 boot_img_hdr *hdr;
50
51 page_mask = page_size - 1;
52
53 kernel_actual = (kernel_size + page_mask) & (~page_mask);
54 ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
55 second_actual = (second_size + page_mask) & (~page_mask);
56
57 *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
58
59 hdr = calloc(*bootimg_size, 1);
60
61 if(hdr == 0) {
62 return hdr;
63 }
64
65 memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
66
67 hdr->kernel_size = kernel_size;
68 hdr->kernel_addr = 0x10008000;
69 hdr->ramdisk_size = ramdisk_size;
70 hdr->ramdisk_addr = 0x11000000;
71 hdr->second_size = second_size;
72 hdr->second_addr = 0x10F00000;
73
74 hdr->tags_addr = 0x10000100;
75 hdr->page_size = page_size;
76
77 memcpy(hdr->magic + page_size,
78 kernel, kernel_size);
79 memcpy(hdr->magic + page_size + kernel_actual,
80 ramdisk, ramdisk_size);
81 memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual,
82 second, second_size);
83 return hdr;
84 }
+0
-289
fastboot/engine.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <string.h>
32
33 #include "fastboot.h"
34
35 char *mkmsg(const char *fmt, ...)
36 {
37 char buf[256];
38 char *s;
39 va_list ap;
40
41 va_start(ap, fmt);
42 vsprintf(buf, fmt, ap);
43 va_end(ap);
44
45 s = strdup(buf);
46 if (s == 0) die("out of memory");
47 return s;
48 }
49
50 #define OP_DOWNLOAD 1
51 #define OP_COMMAND 2
52 #define OP_QUERY 3
53 #define OP_NOTICE 4
54
55 typedef struct Action Action;
56
57 struct Action
58 {
59 unsigned op;
60 Action *next;
61
62 char cmd[64];
63 void *data;
64 unsigned size;
65
66 const char *msg;
67 int (*func)(Action *a, int status, char *resp);
68 };
69
70 static Action *action_list = 0;
71 static Action *action_last = 0;
72
73 static int cb_default(Action *a, int status, char *resp)
74 {
75 if (status) {
76 fprintf(stderr,"FAILED (%s)\n", resp);
77 } else {
78 fprintf(stderr,"OKAY\n");
79 }
80 return status;
81 }
82
83 static Action *queue_action(unsigned op, const char *fmt, ...)
84 {
85 Action *a;
86 va_list ap;
87
88 a = calloc(1, sizeof(Action));
89 if (a == 0) die("out of memory");
90
91 va_start(ap, fmt);
92 vsprintf(a->cmd, fmt, ap);
93 va_end(ap);
94
95 if (action_last) {
96 action_last->next = a;
97 } else {
98 action_list = a;
99 }
100 action_last = a;
101 a->op = op;
102 a->func = cb_default;
103 return a;
104 }
105
106 void fb_queue_erase(const char *ptn)
107 {
108 Action *a;
109 a = queue_action(OP_COMMAND, "erase:%s", ptn);
110 a->msg = mkmsg("erasing '%s'", ptn);
111 }
112
113 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
114 {
115 Action *a;
116
117 a = queue_action(OP_DOWNLOAD, "");
118 a->data = data;
119 a->size = sz;
120 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
121
122 a = queue_action(OP_COMMAND, "flash:%s", ptn);
123 a->msg = mkmsg("writing '%s'", ptn);
124 }
125
126 static int match(char *str, const char **value, unsigned count)
127 {
128 const char *val;
129 unsigned n;
130 int len;
131
132 for (n = 0; n < count; n++) {
133 const char *val = value[n];
134 int len = strlen(val);
135 int match;
136
137 if ((len > 1) && (val[len-1] == '*')) {
138 len--;
139 match = !strncmp(val, str, len);
140 } else {
141 match = !strcmp(val, str);
142 }
143
144 if (match) return 1;
145 }
146
147 return 0;
148 }
149
150
151
152 static int cb_check(Action *a, int status, char *resp, int invert)
153 {
154 const char **value = a->data;
155 unsigned count = a->size;
156 unsigned n;
157 int yes;
158
159 if (status) {
160 fprintf(stderr,"FAILED (%s)\n", resp);
161 return status;
162 }
163
164 yes = match(resp, value, count);
165 if (invert) yes = !yes;
166
167 if (yes) {
168 fprintf(stderr,"OKAY\n");
169 return 0;
170 }
171
172 fprintf(stderr,"FAILED\n\n");
173 fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
174 fprintf(stderr,"Update %s '%s'",
175 invert ? "rejects" : "requires", value[0]);
176 for (n = 1; n < count; n++) {
177 fprintf(stderr," or '%s'", value[n]);
178 }
179 fprintf(stderr,".\n\n");
180 return -1;
181 }
182
183 static int cb_require(Action *a, int status, char *resp)
184 {
185 return cb_check(a, status, resp, 0);
186 }
187
188 static int cb_reject(Action *a, int status, char *resp)
189 {
190 return cb_check(a, status, resp, 1);
191 }
192
193 void fb_queue_require(const char *var, int invert, unsigned nvalues, const char **value)
194 {
195 Action *a;
196 a = queue_action(OP_QUERY, "getvar:%s", var);
197 a->data = value;
198 a->size = nvalues;
199 a->msg = mkmsg("checking %s", var);
200 a->func = invert ? cb_reject : cb_require;
201 if (a->data == 0) die("out of memory");
202 }
203
204 static int cb_display(Action *a, int status, char *resp)
205 {
206 if (status) {
207 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
208 return status;
209 }
210 fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
211 return 0;
212 }
213
214 void fb_queue_display(const char *var, const char *prettyname)
215 {
216 Action *a;
217 a = queue_action(OP_QUERY, "getvar:%s", var);
218 a->data = strdup(prettyname);
219 if (a->data == 0) die("out of memory");
220 a->func = cb_display;
221 }
222
223 static int cb_do_nothing(Action *a, int status, char *resp)
224 {
225 fprintf(stderr,"\n");
226 return 0;
227 }
228
229 void fb_queue_reboot(void)
230 {
231 Action *a = queue_action(OP_COMMAND, "reboot");
232 a->func = cb_do_nothing;
233 a->msg = "rebooting";
234 }
235
236 void fb_queue_command(const char *cmd, const char *msg)
237 {
238 Action *a = queue_action(OP_COMMAND, cmd);
239 a->msg = msg;
240 }
241
242 void fb_queue_download(const char *name, void *data, unsigned size)
243 {
244 Action *a = queue_action(OP_DOWNLOAD, "");
245 a->data = data;
246 a->size = size;
247 a->msg = mkmsg("downloading '%s'", name);
248 }
249
250 void fb_queue_notice(const char *notice)
251 {
252 Action *a = queue_action(OP_NOTICE, "");
253 a->data = (void*) notice;
254 }
255
256 void fb_execute_queue(usb_handle *usb)
257 {
258 Action *a;
259 char resp[FB_RESPONSE_SZ+1];
260 int status;
261
262 a = action_list;
263 resp[FB_RESPONSE_SZ] = 0;
264
265 for (a = action_list; a; a = a->next) {
266 if (a->msg) {
267 fprintf(stderr,"%s... ",a->msg);
268 }
269 if (a->op == OP_DOWNLOAD) {
270 status = fb_download_data(usb, a->data, a->size);
271 status = a->func(a, status, status ? fb_get_error() : "");
272 if (status) break;
273 } else if (a->op == OP_COMMAND) {
274 status = fb_command(usb, a->cmd);
275 status = a->func(a, status, status ? fb_get_error() : "");
276 if (status) break;
277 } else if (a->op == OP_QUERY) {
278 status = fb_command_response(usb, a->cmd, resp);
279 status = a->func(a, status, status ? fb_get_error() : resp);
280 if (status) break;
281 } else if (a->op == OP_NOTICE) {
282 fprintf(stderr,"%s\n",(char*)a->data);
283 } else {
284 die("bogus action");
285 }
286 }
287 }
288
fastboot/engineering_key.p12 less more
Binary diff not shown
+0
-673
fastboot/fastboot.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include <ctype.h>
37
38 #include <sys/time.h>
39 #include <bootimg.h>
40 #include <zipfile/zipfile.h>
41
42 #include "fastboot.h"
43
44 static usb_handle *usb = 0;
45 static const char *serial = 0;
46 static const char *product = 0;
47 static const char *cmdline = 0;
48 static int wipe_data = 0;
49 static unsigned short vendor_id = 0;
50
51 void die(const char *fmt, ...)
52 {
53 va_list ap;
54 va_start(ap, fmt);
55 fprintf(stderr,"error: ");
56 vfprintf(stderr, fmt, ap);
57 fprintf(stderr,"\n");
58 va_end(ap);
59 exit(1);
60 }
61
62 void get_my_path(char *path);
63
64 char *find_item(const char *item, const char *product)
65 {
66 char *dir;
67 char *fn;
68 char path[PATH_MAX + 128];
69
70 if(!strcmp(item,"boot")) {
71 fn = "boot.img";
72 } else if(!strcmp(item,"recovery")) {
73 fn = "recovery.img";
74 } else if(!strcmp(item,"system")) {
75 fn = "system.img";
76 } else if(!strcmp(item,"userdata")) {
77 fn = "userdata.img";
78 } else if(!strcmp(item,"info")) {
79 fn = "android-info.txt";
80 } else {
81 fprintf(stderr,"unknown partition '%s'\n", item);
82 return 0;
83 }
84
85 if(product) {
86 get_my_path(path);
87 sprintf(path + strlen(path),
88 "../../../target/product/%s/%s", product, fn);
89 return strdup(path);
90 }
91
92 dir = getenv("ANDROID_PRODUCT_OUT");
93 if((dir == 0) || (dir[0] == 0)) {
94 die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
95 return 0;
96 }
97
98 sprintf(path, "%s/%s", dir, fn);
99 return strdup(path);
100 }
101
102 #ifdef _WIN32
103 void *load_file(const char *fn, unsigned *_sz);
104 #else
105 void *load_file(const char *fn, unsigned *_sz)
106 {
107 char *data;
108 int sz;
109 int fd;
110
111 data = 0;
112 fd = open(fn, O_RDONLY);
113 if(fd < 0) return 0;
114
115 sz = lseek(fd, 0, SEEK_END);
116 if(sz < 0) goto oops;
117
118 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
119
120 data = (char*) malloc(sz);
121 if(data == 0) goto oops;
122
123 if(read(fd, data, sz) != sz) goto oops;
124 close(fd);
125
126 if(_sz) *_sz = sz;
127 return data;
128
129 oops:
130 close(fd);
131 if(data != 0) free(data);
132 return 0;
133 }
134 #endif
135
136 int match_fastboot(usb_ifc_info *info)
137 {
138 if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
139 (info->dev_vendor != 0x18d1) &&
140 (info->dev_vendor != 0x0bb4)) return -1;
141 if(info->ifc_class != 0xff) return -1;
142 if(info->ifc_subclass != 0x42) return -1;
143 if(info->ifc_protocol != 0x03) return -1;
144 // require matching serial number if a serial number is specified
145 // at the command line with the -s option.
146 if (serial && strcmp(serial, info->serial_number) != 0) return -1;
147 return 0;
148 }
149
150 int list_devices_callback(usb_ifc_info *info)
151 {
152 if (match_fastboot(info) == 0) {
153 char* serial = info->serial_number;
154 if (!serial[0]) {
155 serial = "????????????";
156 }
157 // output compatible with "adb devices"
158 printf("%s\tfastboot\n", serial);
159 }
160
161 return -1;
162 }
163
164 usb_handle *open_device(void)
165 {
166 static usb_handle *usb = 0;
167 int announce = 1;
168
169 if(usb) return usb;
170
171 for(;;) {
172 usb = usb_open(match_fastboot);
173 if(usb) return usb;
174 if(announce) {
175 announce = 0;
176 fprintf(stderr,"< waiting for device >\n");
177 }
178 sleep(1);
179 }
180 }
181
182 void list_devices(void) {
183 // We don't actually open a USB device here,
184 // just getting our callback called so we can
185 // list all the connected devices.
186 usb_open(list_devices_callback);
187 }
188
189 void usage(void)
190 {
191 fprintf(stderr,
192 /* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
193 "usage: fastboot [ <option> ] <command>\n"
194 "\n"
195 "commands:\n"
196 " update <filename> reflash device from update.zip\n"
197 " flashall flash boot + recovery + system\n"
198 " flash <partition> [ <filename> ] write a file to a flash partition\n"
199 " erase <partition> erase a flash partition\n"
200 " getvar <variable> display a bootloader variable\n"
201 " boot <kernel> [ <ramdisk> ] download and boot kernel\n"
202 " flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n"
203 " devices list all connected devices\n"
204 " reboot reboot device normally\n"
205 " reboot-bootloader reboot device into bootloader\n"
206 "\n"
207 "options:\n"
208 " -w erase userdata and cache\n"
209 " -s <serial number> specify device serial number\n"
210 " -p <product> specify product name\n"
211 " -c <cmdline> override kernel commandline\n"
212 " -i <vendor id> specify a custom USB vendor id\n"
213 );
214 exit(1);
215 }
216
217 void *load_bootable_image(const char *kernel, const char *ramdisk,
218 unsigned *sz, const char *cmdline)
219 {
220 void *kdata = 0, *rdata = 0;
221 unsigned ksize = 0, rsize = 0;
222 void *bdata;
223 unsigned bsize;
224
225 if(kernel == 0) {
226 fprintf(stderr, "no image specified\n");
227 return 0;
228 }
229
230 kdata = load_file(kernel, &ksize);
231 if(kdata == 0) {
232 fprintf(stderr, "cannot load '%s'\n", kernel);
233 return 0;
234 }
235
236 /* is this actually a boot image? */
237 if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
238 if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
239
240 if(ramdisk) {
241 fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
242 return 0;
243 }
244
245 *sz = ksize;
246 return kdata;
247 }
248
249 if(ramdisk) {
250 rdata = load_file(ramdisk, &rsize);
251 if(rdata == 0) {
252 fprintf(stderr,"cannot load '%s'\n", ramdisk);
253 return 0;
254 }
255 }
256
257 fprintf(stderr,"creating boot image...\n");
258 bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, 2048, &bsize);
259 if(bdata == 0) {
260 fprintf(stderr,"failed to create boot.img\n");
261 return 0;
262 }
263 if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
264 fprintf(stderr,"creating boot image - %d bytes\n", bsize);
265 *sz = bsize;
266
267 return bdata;
268 }
269
270 void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
271 {
272 void *data;
273 zipentry_t entry;
274 unsigned datasz;
275
276 entry = lookup_zipentry(zip, name);
277 if (entry == NULL) {
278 fprintf(stderr, "archive does not contain '%s'\n", name);
279 return 0;
280 }
281
282 *sz = get_zipentry_size(entry);
283
284 datasz = *sz * 1.001;
285 data = malloc(datasz);
286
287 if(data == 0) {
288 fprintf(stderr, "failed to allocate %d bytes\n", *sz);
289 return 0;
290 }
291
292 if (decompress_zipentry(entry, data, datasz)) {
293 fprintf(stderr, "failed to unzip '%s' from archive\n", name);
294 free(data);
295 return 0;
296 }
297
298 return data;
299 }
300
301 static char *strip(char *s)
302 {
303 int n;
304 while(*s && isspace(*s)) s++;
305 n = strlen(s);
306 while(n-- > 0) {
307 if(!isspace(s[n])) break;
308 s[n] = 0;
309 }
310 return s;
311 }
312
313 #define MAX_OPTIONS 32
314 static int setup_requirement_line(char *name)
315 {
316 char *val[MAX_OPTIONS];
317 const char **out;
318 unsigned n, count;
319 char *x;
320 int invert = 0;
321
322 if (!strncmp(name, "reject ", 7)) {
323 name += 7;
324 invert = 1;
325 } else if (!strncmp(name, "require ", 8)) {
326 name += 8;
327 invert = 0;
328 }
329
330 x = strchr(name, '=');
331 if (x == 0) return 0;
332 *x = 0;
333 val[0] = x + 1;
334
335 for(count = 1; count < MAX_OPTIONS; count++) {
336 x = strchr(val[count - 1],'|');
337 if (x == 0) break;
338 *x = 0;
339 val[count] = x + 1;
340 }
341
342 name = strip(name);
343 for(n = 0; n < count; n++) val[n] = strip(val[n]);
344
345 name = strip(name);
346 if (name == 0) return -1;
347
348 /* work around an unfortunate name mismatch */
349 if (!strcmp(name,"board")) name = "product";
350
351 out = malloc(sizeof(char*) * count);
352 if (out == 0) return -1;
353
354 for(n = 0; n < count; n++) {
355 out[n] = strdup(strip(val[n]));
356 if (out[n] == 0) return -1;
357 }
358
359 fb_queue_require(name, invert, n, out);
360 return 0;
361 }
362
363 static void setup_requirements(char *data, unsigned sz)
364 {
365 char *s;
366
367 s = data;
368 while (sz-- > 0) {
369 if(*s == '\n') {
370 *s++ = 0;
371 if (setup_requirement_line(data)) {
372 die("out of memory");
373 }
374 data = s;
375 } else {
376 s++;
377 }
378 }
379 }
380
381 void queue_info_dump(void)
382 {
383 fb_queue_notice("--------------------------------------------");
384 fb_queue_display("version-bootloader", "Bootloader Version...");
385 fb_queue_display("version-baseband", "Baseband Version.....");
386 fb_queue_display("serialno", "Serial Number........");
387 fb_queue_notice("--------------------------------------------");
388 }
389
390 void do_update_signature(zipfile_t zip, char *fn)
391 {
392 void *data;
393 unsigned sz;
394 data = unzip_file(zip, fn, &sz);
395 if (data == 0) return;
396 fb_queue_download("signature", data, sz);
397 fb_queue_command("signature", "installing signature");
398 }
399
400 void do_update(char *fn)
401 {
402 void *zdata;
403 unsigned zsize;
404 void *data;
405 unsigned sz;
406 zipfile_t zip;
407
408 queue_info_dump();
409
410 zdata = load_file(fn, &zsize);
411 if (zdata == 0) die("failed to load '%s'", fn);
412
413 zip = init_zipfile(zdata, zsize);
414 if(zip == 0) die("failed to access zipdata in '%s'");
415
416 data = unzip_file(zip, "android-info.txt", &sz);
417 if (data == 0) {
418 char *tmp;
419 /* fallback for older zipfiles */
420 data = unzip_file(zip, "android-product.txt", &sz);
421 if ((data == 0) || (sz < 1)) {
422 die("update package has no android-info.txt or android-product.txt");
423 }
424 tmp = malloc(sz + 128);
425 if (tmp == 0) die("out of memory");
426 sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
427 data = tmp;
428 sz = strlen(tmp);
429 }
430
431 setup_requirements(data, sz);
432
433 data = unzip_file(zip, "boot.img", &sz);
434 if (data == 0) die("update package missing boot.img");
435 do_update_signature(zip, "boot.sig");
436 fb_queue_flash("boot", data, sz);
437
438 data = unzip_file(zip, "recovery.img", &sz);
439 if (data != 0) {
440 do_update_signature(zip, "recovery.sig");
441 fb_queue_flash("recovery", data, sz);
442 }
443
444 data = unzip_file(zip, "system.img", &sz);
445 if (data == 0) die("update package missing system.img");
446 do_update_signature(zip, "system.sig");
447 fb_queue_flash("system", data, sz);
448 }
449
450 void do_send_signature(char *fn)
451 {
452 void *data;
453 unsigned sz;
454 char *xtn;
455
456 xtn = strrchr(fn, '.');
457 if (!xtn) return;
458 if (strcmp(xtn, ".img")) return;
459
460 strcpy(xtn,".sig");
461 data = load_file(fn, &sz);
462 strcpy(xtn,".img");
463 if (data == 0) return;
464 fb_queue_download("signature", data, sz);
465 fb_queue_command("signature", "installing signature");
466 }
467
468 void do_flashall(void)
469 {
470 char *fname;
471 void *data;
472 unsigned sz;
473
474 queue_info_dump();
475
476 fname = find_item("info", product);
477 if (fname == 0) die("cannot find android-info.txt");
478 data = load_file(fname, &sz);
479 if (data == 0) die("could not load android-info.txt");
480 setup_requirements(data, sz);
481
482 fname = find_item("boot", product);
483 data = load_file(fname, &sz);
484 if (data == 0) die("could not load boot.img");
485 do_send_signature(fname);
486 fb_queue_flash("boot", data, sz);
487
488 fname = find_item("recovery", product);
489 data = load_file(fname, &sz);
490 if (data != 0) {
491 do_send_signature(fname);
492 fb_queue_flash("recovery", data, sz);
493 }
494
495 fname = find_item("system", product);
496 data = load_file(fname, &sz);
497 if (data == 0) die("could not load system.img");
498 do_send_signature(fname);
499 fb_queue_flash("system", data, sz);
500 }
501
502 #define skip(n) do { argc -= (n); argv += (n); } while (0)
503 #define require(n) do { if (argc < (n)) usage(); } while (0)
504
505 int do_oem_command(int argc, char **argv)
506 {
507 int i;
508 char command[256];
509 if (argc <= 1) return 0;
510
511 command[0] = 0;
512 while(1) {
513 strcat(command,*argv);
514 skip(1);
515 if(argc == 0) break;
516 strcat(command," ");
517 }
518
519 fb_queue_command(command,"");
520 return 0;
521 }
522
523 int main(int argc, char **argv)
524 {
525 int wants_wipe = 0;
526 int wants_reboot = 0;
527 int wants_reboot_bootloader = 0;
528 void *data;
529 unsigned sz;
530
531 skip(1);
532 if (argc == 0) {
533 usage();
534 return 0;
535 }
536
537 if (!strcmp(*argv, "devices")) {
538 list_devices();
539 return 0;
540 }
541
542 while (argc > 0) {
543 if(!strcmp(*argv, "-w")) {
544 wants_wipe = 1;
545 skip(1);
546 } else if(!strcmp(*argv, "-s")) {
547 require(2);
548 serial = argv[1];
549 skip(2);
550 } else if(!strcmp(*argv, "-p")) {
551 require(2);
552 product = argv[1];
553 skip(2);
554 } else if(!strcmp(*argv, "-c")) {
555 require(2);
556 cmdline = argv[1];
557 skip(2);
558 } else if(!strcmp(*argv, "-i")) {
559 char *endptr = NULL;
560 unsigned long val;
561
562 require(2);
563 val = strtoul(argv[1], &endptr, 0);
564 if (!endptr || *endptr != '\0' || (val & ~0xffff))
565 die("invalid vendor id '%s'", argv[1]);
566 vendor_id = (unsigned short)val;
567 skip(2);
568 } else if(!strcmp(*argv, "getvar")) {
569 require(2);
570 fb_queue_display(argv[1], argv[1]);
571 skip(2);
572 } else if(!strcmp(*argv, "erase")) {
573 require(2);
574 fb_queue_erase(argv[1]);
575 skip(2);
576 } else if(!strcmp(*argv, "signature")) {
577 require(2);
578 data = load_file(argv[1], &sz);
579 if (data == 0) die("could not load '%s'", argv[1]);
580 if (sz != 256) die("signature must be 256 bytes");
581 fb_queue_download("signature", data, sz);
582 fb_queue_command("signature", "installing signature");
583 skip(2);
584 } else if(!strcmp(*argv, "reboot")) {
585 wants_reboot = 1;
586 skip(1);
587 } else if(!strcmp(*argv, "reboot-bootloader")) {
588 wants_reboot_bootloader = 1;
589 skip(1);
590 } else if (!strcmp(*argv, "continue")) {
591 fb_queue_command("continue", "resuming boot");
592 skip(1);
593 } else if(!strcmp(*argv, "boot")) {
594 char *kname = 0;
595 char *rname = 0;
596 skip(1);
597 if (argc > 0) {
598 kname = argv[0];
599 skip(1);
600 }
601 if (argc > 0) {
602 rname = argv[0];
603 skip(1);
604 }
605 data = load_bootable_image(kname, rname, &sz, cmdline);
606 if (data == 0) return 1;
607 fb_queue_download("boot.img", data, sz);
608 fb_queue_command("boot", "booting");
609 } else if(!strcmp(*argv, "flash")) {
610 char *pname = argv[1];
611 char *fname = 0;
612 require(2);
613 if (argc > 2) {
614 fname = argv[2];
615 skip(3);
616 } else {
617 fname = find_item(pname, product);
618 skip(2);
619 }
620 if (fname == 0) die("cannot determine image filename for '%s'", pname);
621 data = load_file(fname, &sz);
622 if (data == 0) die("cannot load '%s'\n", fname);
623 fb_queue_flash(pname, data, sz);
624 } else if(!strcmp(*argv, "flash:raw")) {
625 char *pname = argv[1];
626 char *kname = argv[2];
627 char *rname = 0;
628 require(3);
629 if(argc > 3) {
630 rname = argv[3];
631 skip(4);
632 } else {
633 skip(3);
634 }
635 data = load_bootable_image(kname, rname, &sz, cmdline);
636 if (data == 0) die("cannot load bootable image");
637 fb_queue_flash(pname, data, sz);
638 } else if(!strcmp(*argv, "flashall")) {
639 skip(1);
640 do_flashall();
641 wants_reboot = 1;
642 } else if(!strcmp(*argv, "update")) {
643 if (argc > 1) {
644 do_update(argv[1]);
645 skip(2);
646 } else {
647 do_update("update.zip");
648 skip(1);
649 }
650 wants_reboot = 1;
651 } else if(!strcmp(*argv, "oem")) {
652 argc = do_oem_command(argc, argv);
653 } else {
654 usage();
655 }
656 }
657
658 if (wants_wipe) {
659 fb_queue_erase("userdata");
660 fb_queue_erase("cache");
661 }
662 if (wants_reboot) {
663 fb_queue_reboot();
664 } else if (wants_reboot_bootloader) {
665 fb_queue_command("reboot-bootloader", "rebooting into bootloader");
666 }
667
668 usb = open_device();
669
670 fb_execute_queue(usb);
671 return 0;
672 }
+0
-57
fastboot/fastboot.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #ifndef _FASTBOOT_H_
29 #define _FASTBOOT_H_
30
31 #include "usb.h"
32
33 /* protocol.c - fastboot protocol */
34 int fb_command(usb_handle *usb, const char *cmd);
35 int fb_command_response(usb_handle *usb, const char *cmd, char *response);
36 int fb_download_data(usb_handle *usb, const void *data, unsigned size);
37 char *fb_get_error(void);
38
39 #define FB_COMMAND_SZ 64
40 #define FB_RESPONSE_SZ 64
41
42 /* engine.c - high level command queue engine */
43 void fb_queue_flash(const char *ptn, void *data, unsigned sz);;
44 void fb_queue_erase(const char *ptn);
45 void fb_queue_require(const char *var, int invert, unsigned nvalues, const char **value);
46 void fb_queue_display(const char *var, const char *prettyname);
47 void fb_queue_reboot(void);
48 void fb_queue_command(const char *cmd, const char *msg);
49 void fb_queue_download(const char *name, void *data, unsigned size);
50 void fb_queue_notice(const char *notice);
51 void fb_execute_queue(usb_handle *usb);
52
53 /* util stuff */
54 void die(const char *fmt, ...);
55
56 #endif
+0
-25
fastboot/genkey.sh less more
0 #!/bin/bash
1
2 if [ $# -ne 2 ]
3 then
4 echo "Usage: $0 alias \"pass phrase\""
5 exit -1
6 fi
7
8 # Generate a 2048 bit RSA key with public exponent 3.
9 # Encrypt private key with provided password.
10 openssl genrsa -3 -out $1.pem -passout pass:"$2" 2048
11
12 # Create a self-signed cert for this key.
13 openssl req -new -x509 -key $1.pem -passin pass:"$2" \
14 -out $1-cert.pem \
15 -batch -days 10000
16
17 # Create a PKCS12 store containing the generated private key.
18 # Protect the keystore and the private key with the provided password.
19 openssl pkcs12 -export -in $1-cert.pem -inkey $1.pem -passin pass:"$2" \
20 -out $1.p12 -name $1 -passout pass:"$2"
21
22 rm $1.pem
23 rm $1-cert.pem
24
+0
-9
fastboot/p12topem.sh less more
0 #!/bin/bash
1
2 if [ $# -ne 2 ]
3 then
4 echo "Usage: $0 alias passphrase"
5 exit -1
6 fi
7
8 openssl pkcs12 -passin pass:"$2" -passout pass:"$2" -in $1.p12 -out $1.pem
+0
-181
fastboot/protocol.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #include "fastboot.h"
34
35 static char ERROR[128];
36
37 char *fb_get_error(void)
38 {
39 return ERROR;
40 }
41
42 static int check_response(usb_handle *usb, unsigned size,
43 unsigned data_okay, char *response)
44 {
45 unsigned char status[65];
46 int r;
47
48 for(;;) {
49 r = usb_read(usb, status, 64);
50 if(r < 0) {
51 sprintf(ERROR, "status read failed (%s)", strerror(errno));
52 usb_close(usb);
53 return -1;
54 }
55 status[r] = 0;
56
57 if(r < 4) {
58 sprintf(ERROR, "status malformed (%d bytes)", r);
59 usb_close(usb);
60 return -1;
61 }
62
63 if(!memcmp(status, "INFO", 4)) {
64 fprintf(stderr,"%s\n", status);
65 continue;
66 }
67
68 if(!memcmp(status, "OKAY", 4)) {
69 if(response) {
70 strcpy(response, (char*) status + 4);
71 }
72 return 0;
73 }
74
75 if(!memcmp(status, "FAIL", 4)) {
76 if(r > 4) {
77 sprintf(ERROR, "remote: %s", status + 4);
78 } else {
79 strcpy(ERROR, "remote failure");
80 }
81 return -1;
82 }
83
84 if(!memcmp(status, "DATA", 4) && data_okay){
85 unsigned dsize = strtoul((char*) status + 4, 0, 16);
86 if(dsize > size) {
87 strcpy(ERROR, "data size too large");
88 usb_close(usb);
89 return -1;
90 }
91 return dsize;
92 }
93
94 strcpy(ERROR,"unknown status code");
95 usb_close(usb);
96 break;
97 }
98
99 return -1;
100 }
101
102 static int _command_send(usb_handle *usb, const char *cmd,
103 const void *data, unsigned size,
104 char *response)
105 {
106 int cmdsize = strlen(cmd);
107 int r;
108
109 if(response) {
110 response[0] = 0;
111 }
112
113 if(cmdsize > 64) {
114 sprintf(ERROR,"command too large");
115 return -1;
116 }
117
118 if(usb_write(usb, cmd, cmdsize) != cmdsize) {
119 sprintf(ERROR,"command write failed (%s)", strerror(errno));
120 usb_close(usb);
121 return -1;
122 }
123
124 if(data == 0) {
125 return check_response(usb, size, 0, response);
126 }
127
128 r = check_response(usb, size, 1, 0);
129 if(r < 0) {
130 return -1;
131 }
132 size = r;
133
134 if(size) {
135 r = usb_write(usb, data, size);
136 if(r < 0) {
137 sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
138 usb_close(usb);
139 return -1;
140 }
141 if(r != ((int) size)) {
142 sprintf(ERROR, "data transfer failure (short transfer)");
143 usb_close(usb);
144 return -1;
145 }
146 }
147
148 r = check_response(usb, 0, 0, 0);
149 if(r < 0) {
150 return -1;
151 } else {
152 return size;
153 }
154 }
155
156 int fb_command(usb_handle *usb, const char *cmd)
157 {
158 return _command_send(usb, cmd, 0, 0, 0);
159 }
160
161 int fb_command_response(usb_handle *usb, const char *cmd, char *response)
162 {
163 return _command_send(usb, cmd, 0, 0, response);
164 }
165
166 int fb_download_data(usb_handle *usb, const void *data, unsigned size)
167 {
168 char cmd[64];
169 int r;
170
171 sprintf(cmd, "download:%08x", size);
172 r = _command_send(usb, cmd, data, size, 0);
173
174 if(r < 0) {
175 return -1;
176 } else {
177 return 0;
178 }
179 }
180
+0
-10
fastboot/signfile.sh less more
0 #!/bin/bash
1
2 if [ $# -ne 3 ]
3 then
4 echo "Usage: $0 alias filename passpharse"
5 exit -1
6 fi
7
8 openssl dgst -passin pass:"$3" -binary -sha1 -sign $1.pem $2 > $2.sign
9
+0
-64
fastboot/usb.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #ifndef _USB_H_
29 #define _USB_H_
30
31 typedef struct usb_handle usb_handle;
32
33 typedef struct usb_ifc_info usb_ifc_info;
34
35 struct usb_ifc_info
36 {
37 /* from device descriptor */
38 unsigned short dev_vendor;
39 unsigned short dev_product;
40
41 unsigned char dev_class;
42 unsigned char dev_subclass;
43 unsigned char dev_protocol;
44
45 unsigned char ifc_class;
46 unsigned char ifc_subclass;
47 unsigned char ifc_protocol;
48
49 unsigned char has_bulk_in;
50 unsigned char has_bulk_out;
51
52 char serial_number[256];
53 };
54
55 typedef int (*ifc_match_func)(usb_ifc_info *ifc);
56
57 usb_handle *usb_open(ifc_match_func callback);
58 int usb_close(usb_handle *h);
59 int usb_read(usb_handle *h, void *_data, int len);
60 int usb_write(usb_handle *h, const void *_data, int len);
61
62
63 #endif
+0
-373
fastboot/usb_linux.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <dirent.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <pthread.h>
39 #include <ctype.h>
40
41 #include <linux/usbdevice_fs.h>
42 #include <linux/usbdevice_fs.h>
43 #include <linux/version.h>
44 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
45 #include <linux/usb/ch9.h>
46 #else
47 #include <linux/usb_ch9.h>
48 #endif
49 #include <asm/byteorder.h>
50
51 #include "usb.h"
52
53 #if TRACE_USB
54 #define DBG1(x...) fprintf(stderr, x)
55 #define DBG(x...) fprintf(stderr, x)
56 #else
57 #define DBG(x...)
58 #define DBG1(x...)
59 #endif
60
61 struct usb_handle
62 {
63 char fname[64];
64 int desc;
65 unsigned char ep_in;
66 unsigned char ep_out;
67 };
68
69 static inline int badname(const char *name)
70 {
71 while(*name) {
72 if(!isdigit(*name++)) return 1;
73 }
74 return 0;
75 }
76
77 static int check(void *_desc, int len, unsigned type, int size)
78 {
79 unsigned char *desc = _desc;
80
81 if(len < size) return -1;
82 if(desc[0] < size) return -1;
83 if(desc[0] > len) return -1;
84 if(desc[1] != type) return -1;
85
86 return 0;
87 }
88
89 static int filter_usb_device(int fd, char *ptr, int len, ifc_match_func callback,
90 int *ept_in_id, int *ept_out_id, int *ifc_id)
91 {
92 struct usb_device_descriptor *dev;
93 struct usb_config_descriptor *cfg;
94 struct usb_interface_descriptor *ifc;
95 struct usb_endpoint_descriptor *ept;
96 struct usb_ifc_info info;
97
98 int in, out;
99 unsigned i;
100 unsigned e;
101
102 if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
103 return -1;
104 dev = (void*) ptr;
105 len -= dev->bLength;
106 ptr += dev->bLength;
107
108 if(check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
109 return -1;
110 cfg = (void*) ptr;
111 len -= cfg->bLength;
112 ptr += cfg->bLength;
113
114 info.dev_vendor = dev->idVendor;
115 info.dev_product = dev->idProduct;
116 info.dev_class = dev->bDeviceClass;
117 info.dev_subclass = dev->bDeviceSubClass;
118 info.dev_protocol = dev->bDeviceProtocol;
119
120 // read device serial number (if there is one)
121 info.serial_number[0] = 0;
122 if (dev->iSerialNumber) {
123 struct usbdevfs_ctrltransfer ctrl;
124 __u16 buffer[128];
125 int result;
126
127 memset(buffer, 0, sizeof(buffer));
128
129 ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
130 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
131 ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
132 ctrl.wIndex = 0;
133 ctrl.wLength = sizeof(buffer);
134 ctrl.data = buffer;
135
136 result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
137 if (result > 0) {
138 int i;
139 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
140 result /= 2;
141 for (i = 1; i < result; i++)
142 info.serial_number[i - 1] = buffer[i];
143 info.serial_number[i - 1] = 0;
144 }
145 }
146
147 for(i = 0; i < cfg->bNumInterfaces; i++) {
148 if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
149 return -1;
150 ifc = (void*) ptr;
151 len -= ifc->bLength;
152 ptr += ifc->bLength;
153
154 in = -1;
155 out = -1;
156 info.ifc_class = ifc->bInterfaceClass;
157 info.ifc_subclass = ifc->bInterfaceSubClass;
158 info.ifc_protocol = ifc->bInterfaceProtocol;
159
160 for(e = 0; e < ifc->bNumEndpoints; e++) {
161 if(check(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
162 return -1;
163 ept = (void*) ptr;
164 len -= ept->bLength;
165 ptr += ept->bLength;
166
167 if((ept->bmAttributes & 0x03) != 0x02)
168 continue;
169
170 if(ept->bEndpointAddress & 0x80) {
171 in = ept->bEndpointAddress;
172 } else {
173 out = ept->bEndpointAddress;
174 }
175 }
176
177 info.has_bulk_in = (in != -1);
178 info.has_bulk_out = (out != -1);
179
180 if(callback(&info) == 0) {
181 *ept_in_id = in;
182 *ept_out_id = out;
183 *ifc_id = ifc->bInterfaceNumber;
184 return 0;
185 }
186 }
187
188 return -1;
189 }
190
191 static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
192 {
193 usb_handle *usb = 0;
194 char busname[64], devname[64];
195 char desc[1024];
196 int n, in, out, ifc;
197
198 DIR *busdir, *devdir;
199 struct dirent *de;
200 int fd;
201
202 busdir = opendir(base);
203 if(busdir == 0) return 0;
204
205 while((de = readdir(busdir)) && (usb == 0)) {
206 if(badname(de->d_name)) continue;
207
208 sprintf(busname, "%s/%s", base, de->d_name);
209 devdir = opendir(busname);
210 if(devdir == 0) continue;
211
212 // DBG("[ scanning %s ]\n", busname);
213 while((de = readdir(devdir)) && (usb == 0)) {
214
215 if(badname(de->d_name)) continue;
216 sprintf(devname, "%s/%s", busname, de->d_name);
217
218 // DBG("[ scanning %s ]\n", devname);
219 if((fd = open(devname, O_RDWR)) < 0) {
220 continue;
221 }
222
223 n = read(fd, desc, sizeof(desc));
224
225 if(filter_usb_device(fd, desc, n, callback, &in, &out, &ifc) == 0){
226 usb = calloc(1, sizeof(usb_handle));
227 strcpy(usb->fname, devname);
228 usb->ep_in = in;
229 usb->ep_out = out;
230 usb->desc = fd;
231
232 n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
233 if(n != 0) {
234 close(fd);
235 free(usb);
236 usb = 0;
237 continue;
238 }
239 } else {
240 close(fd);
241 }
242 }
243 closedir(devdir);
244 }
245 closedir(busdir);
246
247 return usb;
248 }
249
250 int usb_write(usb_handle *h, const void *_data, int len)
251 {
252 unsigned char *data = (unsigned char*) _data;
253 unsigned count = 0;
254 struct usbdevfs_bulktransfer bulk;
255 int n;
256
257 if(h->ep_out == 0) {
258 return -1;
259 }
260
261 if(len == 0) {
262 bulk.ep = h->ep_out;
263 bulk.len = 0;
264 bulk.data = data;
265 bulk.timeout = 0;
266
267 n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
268 if(n != 0) {
269 fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
270 n, errno, strerror(errno));
271 return -1;
272 }
273 return 0;
274 }
275
276 while(len > 0) {
277 int xfer;
278 xfer = (len > 4096) ? 4096 : len;
279
280 bulk.ep = h->ep_out;
281 bulk.len = xfer;
282 bulk.data = data;
283 bulk.timeout = 0;
284
285 n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
286 if(n != xfer) {
287 DBG("ERROR: n = %d, errno = %d (%s)\n",
288 n, errno, strerror(errno));
289 return -1;
290 }
291
292 count += xfer;
293 len -= xfer;
294 data += xfer;
295 }
296
297 return count;
298 }
299
300 int usb_read(usb_handle *h, void *_data, int len)
301 {
302 unsigned char *data = (unsigned char*) _data;
303 unsigned count = 0;
304 struct usbdevfs_bulktransfer bulk;
305 int n;
306
307 if(h->ep_in == 0) {
308 return -1;
309 }
310
311 while(len > 0) {
312 int xfer = (len > 4096) ? 4096 : len;
313
314 bulk.ep = h->ep_in;
315 bulk.len = xfer;
316 bulk.data = data;
317 bulk.timeout = 0;
318
319 DBG("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
320 n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
321 DBG("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
322
323 if(n < 0) {
324 DBG1("ERROR: n = %d, errno = %d (%s)\n",
325 n, errno, strerror(errno));
326 return -1;
327 }
328
329 count += n;
330 len -= n;
331 data += n;
332
333 if(n < xfer) {
334 break;
335 }
336 }
337
338 return count;
339 }
340
341 void usb_kick(usb_handle *h)
342 {
343 int fd;
344
345 fd = h->desc;
346 h->desc = -1;
347 if(fd >= 0) {
348 close(fd);
349 DBG("[ usb closed %d ]\n", fd);
350 }
351 }
352
353 int usb_close(usb_handle *h)
354 {
355 int fd;
356
357 fd = h->desc;
358 h->desc = -1;
359 if(fd >= 0) {
360 close(fd);
361 DBG("[ usb closed %d ]\n", fd);
362 }
363
364 return 0;
365 }
366
367 usb_handle *usb_open(ifc_match_func callback)
368 {
369 return find_usb_device("/dev/bus/usb", callback);
370 }
371
372
+0
-538
fastboot/usb_osx.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <IOKit/IOKitLib.h>
31 #include <IOKit/IOCFPlugIn.h>
32 #include <IOKit/usb/IOUSBLib.h>
33 #include <IOKit/IOMessage.h>
34 #include <mach/mach_port.h>
35
36 #include "usb.h"
37
38
39 /*
40 * Internal helper functions and associated definitions.
41 */
42
43 #if TRACE_USB
44 #define WARN(x...) fprintf(stderr, x)
45 #else
46 #define WARN(x...)
47 #endif
48
49 #define ERR(x...) fprintf(stderr, "ERROR: " x)
50
51 /** An open usb device */
52 struct usb_handle
53 {
54 int success;
55 ifc_match_func callback;
56 usb_ifc_info info;
57
58 UInt8 bulkIn;
59 UInt8 bulkOut;
60 IOUSBInterfaceInterface190 **interface;
61 unsigned int zero_mask;
62 };
63
64 /** Try out all the interfaces and see if there's a match. Returns 0 on
65 * success, -1 on failure. */
66 static int try_interfaces(IOUSBDeviceInterface **dev, usb_handle *handle) {
67 IOReturn kr;
68 IOUSBFindInterfaceRequest request;
69 io_iterator_t iterator;
70 io_service_t usbInterface;
71 IOCFPlugInInterface **plugInInterface;
72 IOUSBInterfaceInterface190 **interface = NULL;
73 HRESULT result;
74 SInt32 score;
75 UInt8 interfaceNumEndpoints;
76 UInt8 endpoint;
77 UInt8 configuration;
78
79 // Placing the constant KIOUSBFindInterfaceDontCare into the following
80 // fields of the IOUSBFindInterfaceRequest structure will allow us to
81 // find all of the interfaces
82 request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
83 request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
84 request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
85 request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
86
87 // SetConfiguration will kill an existing UMS connection, so let's
88 // not do this if not necessary.
89 configuration = 0;
90 (*dev)->GetConfiguration(dev, &configuration);
91 if (configuration != 1)
92 (*dev)->SetConfiguration(dev, 1);
93
94 // Get an iterator for the interfaces on the device
95 kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
96
97 if (kr != 0) {
98 ERR("Couldn't create a device interface iterator: (%08x)\n", kr);
99 return -1;
100 }
101
102 while ((usbInterface = IOIteratorNext(iterator))) {
103 // Create an intermediate plugin
104 kr = IOCreatePlugInInterfaceForService(
105 usbInterface,
106 kIOUSBInterfaceUserClientTypeID,
107 kIOCFPlugInInterfaceID,
108 &plugInInterface,
109 &score);
110
111 // No longer need the usbInterface object now that we have the plugin
112 (void) IOObjectRelease(usbInterface);
113
114 if ((kr != 0) || (!plugInInterface)) {
115 WARN("Unable to create plugin (%08x)\n", kr);
116 continue;
117 }
118
119 // Now create the interface interface for the interface
120 result = (*plugInInterface)->QueryInterface(
121 plugInInterface,
122 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
123 (LPVOID) &interface);
124
125 // No longer need the intermediate plugin
126 (*plugInInterface)->Release(plugInInterface);
127
128 if (result || !interface) {
129 ERR("Couldn't create interface interface: (%08x)\n",
130 (unsigned int) result);
131 // continue so we can try the next interface
132 continue;
133 }
134
135 /*
136 * Now open the interface. This will cause the pipes
137 * associated with the endpoints in the interface descriptor
138 * to be instantiated.
139 */
140
141 /*
142 * TODO: Earlier comments here indicated that it was a bad
143 * idea to just open any interface, because opening "mass
144 * storage endpoints" is bad. However, the only way to find
145 * out if an interface does bulk in or out is to open it, and
146 * the framework in this application wants to be told about
147 * bulk in / out before deciding whether it actually wants to
148 * use the interface. Maybe something needs to be done about
149 * this situation.
150 */
151
152 kr = (*interface)->USBInterfaceOpen(interface);
153
154 if (kr != 0) {
155 WARN("Could not open interface: (%08x)\n", kr);
156 (void) (*interface)->Release(interface);
157 // continue so we can try the next interface
158 continue;
159 }
160
161 // Get the number of endpoints associated with this interface.
162 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
163
164 if (kr != 0) {
165 ERR("Unable to get number of endpoints: (%08x)\n", kr);
166 goto next_interface;
167 }
168
169 // Get interface class, subclass and protocol
170 if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 ||
171 (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 ||
172 (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0)
173 {
174 ERR("Unable to get interface class, subclass and protocol\n");
175 goto next_interface;
176 }
177
178 handle->info.has_bulk_in = 0;
179 handle->info.has_bulk_out = 0;
180
181 // Iterate over the endpoints for this interface and see if there
182 // are any that do bulk in/out.
183 for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
184 UInt8 transferType;
185 UInt16 maxPacketSize;
186 UInt8 interval;
187 UInt8 number;
188 UInt8 direction;
189
190 kr = (*interface)->GetPipeProperties(interface, endpoint,
191 &direction,
192 &number, &transferType, &maxPacketSize, &interval);
193
194 if (kr == 0) {
195 if (transferType != kUSBBulk) {
196 continue;
197 }
198
199 if (direction == kUSBIn) {
200 handle->info.has_bulk_in = 1;
201 handle->bulkIn = endpoint;
202 } else if (direction == kUSBOut) {
203 handle->info.has_bulk_out = 1;
204 handle->bulkOut = endpoint;
205 }
206
207 if (handle->info.ifc_protocol == 0x01) {
208 handle->zero_mask = maxPacketSize - 1;
209 }
210 } else {
211 ERR("could not get pipe properties\n");
212 }
213
214 if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
215 break;
216 }
217 }
218
219 if (handle->callback(&handle->info) == 0) {
220 handle->interface = interface;
221 handle->success = 1;
222
223 /*
224 * Clear both the endpoints, because it has been observed
225 * that the Mac may otherwise (incorrectly) start out with
226 * them in bad state.
227 */
228
229 if (handle->info.has_bulk_in) {
230 kr = (*interface)->ClearPipeStallBothEnds(interface,
231 handle->bulkIn);
232 if (kr != 0) {
233 ERR("could not clear input pipe; result %d", kr);
234 return -1;
235 }
236 }
237
238 if (handle->info.has_bulk_out) {
239 kr = (*interface)->ClearPipeStallBothEnds(interface,
240 handle->bulkOut);
241 if (kr != 0) {
242 ERR("could not clear output pipe; result %d", kr);
243 return -1;
244 }
245 }
246
247 return 0;
248 }
249
250 next_interface:
251 (*interface)->USBInterfaceClose(interface);
252 (*interface)->Release(interface);
253 }
254
255 return 0;
256 }
257
258 /** Try out the given device and see if there's a match. Returns 0 on
259 * success, -1 on failure.
260 */
261 static int try_device(io_service_t device, usb_handle *handle) {
262 kern_return_t kr;
263 IOCFPlugInInterface **plugin = NULL;
264 IOUSBDeviceInterface182 **dev = NULL;
265 SInt32 score;
266 HRESULT result;
267 UInt8 serialIndex;
268
269 // Create an intermediate plugin.
270 kr = IOCreatePlugInInterfaceForService(device,
271 kIOUSBDeviceUserClientTypeID,
272 kIOCFPlugInInterfaceID,
273 &plugin, &score);
274
275 if ((kr != 0) || (plugin == NULL)) {
276 ERR("Unable to create a plug-in (%08x)\n", kr);
277 goto error;
278 }
279
280 // Now create the device interface.
281 result = (*plugin)->QueryInterface(plugin,
282 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
283 if ((result != 0) || (dev == NULL)) {
284 ERR("Couldn't create a device interface (%08x)\n", (int) result);
285 goto error;
286 }
287
288 /*
289 * We don't need the intermediate interface after the device interface
290 * is created.
291 */
292 IODestroyPlugInInterface(plugin);
293
294 // So, we have a device, finally. Grab its vitals.
295
296 kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
297 if (kr != 0) {
298 ERR("GetDeviceVendor");
299 goto error;
300 }
301
302 kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product);
303 if (kr != 0) {
304 ERR("GetDeviceProduct");
305 goto error;
306 }
307
308 kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class);
309 if (kr != 0) {
310 ERR("GetDeviceClass");
311 goto error;
312 }
313
314 kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass);
315 if (kr != 0) {
316 ERR("GetDeviceSubClass");
317 goto error;
318 }
319
320 kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol);
321 if (kr != 0) {
322 ERR("GetDeviceProtocol");
323 goto error;
324 }
325
326 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
327
328 if (serialIndex > 0) {
329 IOUSBDevRequest req;
330 UInt16 buffer[256];
331
332 req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
333 req.bRequest = kUSBRqGetDescriptor;
334 req.wValue = (kUSBStringDesc << 8) | serialIndex;
335 req.wIndex = 0;
336 req.pData = buffer;
337 req.wLength = sizeof(buffer);
338 kr = (*dev)->DeviceRequest(dev, &req);
339
340 if (kr == kIOReturnSuccess && req.wLenDone > 0) {
341 int i, count;
342
343 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
344 count = (req.wLenDone - 1) / 2;
345 for (i = 0; i < count; i++)
346 handle->info.serial_number[i] = buffer[i + 1];
347 handle->info.serial_number[i] = 0;
348 }
349 } else {
350 // device has no serial number
351 handle->info.serial_number[0] = 0;
352 }
353
354 if (try_interfaces(dev, handle)) {
355 goto error;
356 }
357
358 (*dev)->Release(dev);
359 return 0;
360
361 error:
362
363 if (dev != NULL) {
364 (*dev)->Release(dev);
365 }
366
367 return -1;
368 }
369
370
371 /** Initializes the USB system. Returns 0 on success, -1 on error. */
372 static int init_usb(ifc_match_func callback, usb_handle **handle) {
373 int ret = -1;
374 CFMutableDictionaryRef matchingDict;
375 kern_return_t result;
376 io_iterator_t iterator;
377 usb_handle h;
378
379 h.success = 0;
380 h.callback = callback;
381
382 /*
383 * Create our matching dictionary to find appropriate devices.
384 * IOServiceAddMatchingNotification consumes the reference, so we
385 * do not need to release it.
386 */
387 matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
388
389 if (matchingDict == NULL) {
390 ERR("Couldn't create USB matching dictionary.\n");
391 return -1;
392 }
393
394 result = IOServiceGetMatchingServices(
395 kIOMasterPortDefault, matchingDict, &iterator);
396
397 if (result != 0) {
398 ERR("Could not create iterator.");
399 return -1;
400 }
401
402 for (;;) {
403 if (! IOIteratorIsValid(iterator)) {
404 /*
405 * Apple documentation advises resetting the iterator if
406 * it should become invalid during iteration.
407 */
408 IOIteratorReset(iterator);
409 continue;
410 }
411
412 io_service_t device = IOIteratorNext(iterator);
413
414 if (device == 0) {
415 break;
416 }
417
418 usb_ifc_info info;
419
420 if (try_device(device, &h) != 0) {
421 IOObjectRelease(device);
422 ret = -1;
423 break;
424 }
425
426 if (h.success) {
427 *handle = calloc(1, sizeof(usb_handle));
428 memcpy(*handle, &h, sizeof(usb_handle));
429 ret = 0;
430 break;
431 }
432
433 IOObjectRelease(device);
434 }
435
436 IOObjectRelease(iterator);
437
438 return ret;
439 }
440
441
442
443 /*
444 * Definitions of this file's public functions.
445 */
446
447 usb_handle *usb_open(ifc_match_func callback) {
448 usb_handle *handle = NULL;
449
450 if (init_usb(callback, &handle) < 0) {
451 /* Something went wrong initializing USB. */
452 return NULL;
453 }
454
455 return handle;
456 }
457
458 int usb_close(usb_handle *h) {
459 /* TODO: Something better here? */
460 return 0;
461 }
462
463 int usb_read(usb_handle *h, void *data, int len) {
464 IOReturn result;
465 UInt32 numBytes = len;
466
467 if (len == 0) {
468 return 0;
469 }
470
471 if (h == NULL) {
472 return -1;
473 }
474
475 if (h->interface == NULL) {
476 ERR("usb_read interface was null\n");
477 return -1;
478 }
479
480 if (h->bulkIn == 0) {
481 ERR("bulkIn endpoint not assigned\n");
482 return -1;
483 }
484
485 result = (*h->interface)->ReadPipe(
486 h->interface, h->bulkIn, data, &numBytes);
487
488 if (result == 0) {
489 return (int) numBytes;
490 } else {
491 ERR("usb_read failed with status %x\n", result);
492 }
493
494 return -1;
495 }
496
497 int usb_write(usb_handle *h, const void *data, int len) {
498 IOReturn result;
499
500 if (len == 0) {
501 return 0;
502 }
503
504 if (h == NULL) {
505 return -1;
506 }
507
508 if (h->interface == NULL) {
509 ERR("usb_write interface was null\n");
510 return -1;
511 }
512
513 if (h->bulkOut == 0) {
514 ERR("bulkOut endpoint not assigned\n");
515 return -1;
516 }
517
518 result = (*h->interface)->WritePipe(
519 h->interface, h->bulkOut, (void *)data, len);
520
521 #if 0
522 if ((result == 0) && (h->zero_mask)) {
523 /* we need 0-markers and our transfer */
524 if(!(len & h->zero_mask)) {
525 result = (*h->interface)->WritePipe(
526 h->interface, h->bulkOut, (void *)data, 0);
527 }
528 }
529 #endif
530
531 if (result != 0) {
532 ERR("usb_write failed with status %x\n", result);
533 return -1;
534 }
535
536 return len;
537 }
+0
-375
fastboot/usb_windows.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <windows.h>
29 #include <winerror.h>
30 #include <errno.h>
31 #include <usb100.h>
32 #include <adb_api.h>
33 #include <stdio.h>
34
35 #include "usb.h"
36
37 //#define TRACE_USB 1
38 #if TRACE_USB
39 #define DBG(x...) fprintf(stderr, x)
40 #else
41 #define DBG(x...)
42 #endif
43
44
45 /** Structure usb_handle describes our connection to the usb device via
46 AdbWinApi.dll. This structure is returned from usb_open() routine and
47 is expected in each subsequent call that is accessing the device.
48 */
49 struct usb_handle {
50 /// Handle to USB interface
51 ADBAPIHANDLE adb_interface;
52
53 /// Handle to USB read pipe (endpoint)
54 ADBAPIHANDLE adb_read_pipe;
55
56 /// Handle to USB write pipe (endpoint)
57 ADBAPIHANDLE adb_write_pipe;
58
59 /// Interface name
60 char* interface_name;
61 };
62
63 /// Class ID assigned to the device by androidusb.sys
64 static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
65
66
67 /// Checks if interface (device) matches certain criteria
68 int recognized_device(usb_handle* handle, ifc_match_func callback);
69
70 /// Opens usb interface (device) by interface (device) name.
71 usb_handle* do_usb_open(const wchar_t* interface_name);
72
73 /// Writes data to the opened usb handle
74 int usb_write(usb_handle* handle, const void* data, int len);
75
76 /// Reads data using the opened usb handle
77 int usb_read(usb_handle *handle, void* data, int len);
78
79 /// Cleans up opened usb handle
80 void usb_cleanup_handle(usb_handle* handle);
81
82 /// Cleans up (but don't close) opened usb handle
83 void usb_kick(usb_handle* handle);
84
85 /// Closes opened usb handle
86 int usb_close(usb_handle* handle);
87
88
89 usb_handle* do_usb_open(const wchar_t* interface_name) {
90 // Allocate our handle
91 usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
92 if (NULL == ret)
93 return NULL;
94
95 // Create interface.
96 ret->adb_interface = AdbCreateInterfaceByName(interface_name);
97
98 if (NULL == ret->adb_interface) {
99 free(ret);
100 errno = GetLastError();
101 return NULL;
102 }
103
104 // Open read pipe (endpoint)
105 ret->adb_read_pipe =
106 AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
107 AdbOpenAccessTypeReadWrite,
108 AdbOpenSharingModeReadWrite);
109 if (NULL != ret->adb_read_pipe) {
110 // Open write pipe (endpoint)
111 ret->adb_write_pipe =
112 AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
113 AdbOpenAccessTypeReadWrite,
114 AdbOpenSharingModeReadWrite);
115 if (NULL != ret->adb_write_pipe) {
116 // Save interface name
117 unsigned long name_len = 0;
118
119 // First get expected name length
120 AdbGetInterfaceName(ret->adb_interface,
121 NULL,
122 &name_len,
123 true);
124 if (0 != name_len) {
125 ret->interface_name = (char*)malloc(name_len);
126
127 if (NULL != ret->interface_name) {
128 // Now save the name
129 if (AdbGetInterfaceName(ret->adb_interface,
130 ret->interface_name,
131 &name_len,
132 true)) {
133 // We're done at this point
134 return ret;
135 }
136 } else {
137 SetLastError(ERROR_OUTOFMEMORY);
138 }
139 }
140 }
141 }
142
143 // Something went wrong.
144 errno = GetLastError();
145 usb_cleanup_handle(ret);
146 free(ret);
147 SetLastError(errno);
148
149 return NULL;
150 }
151
152 int usb_write(usb_handle* handle, const void* data, int len) {
153 unsigned long time_out = 500 + len * 8;
154 unsigned long written = 0;
155 unsigned count = 0;
156 int ret;
157
158 DBG("usb_write %d\n", len);
159 if (NULL != handle) {
160 // Perform write
161 while(len > 0) {
162 int xfer = (len > 4096) ? 4096 : len;
163 ret = AdbWriteEndpointSync(handle->adb_write_pipe,
164 (void*)data,
165 (unsigned long)xfer,
166 &written,
167 time_out);
168 errno = GetLastError();
169 DBG("AdbWriteEndpointSync returned %d, errno: %d\n", ret, errno);
170 if (ret == 0) {
171 // assume ERROR_INVALID_HANDLE indicates we are disconnected
172 if (errno == ERROR_INVALID_HANDLE)
173 usb_kick(handle);
174 return -1;
175 }
176
177 count += written;
178 len -= written;
179 data += written;
180
181 if (len == 0)
182 return count;
183 }
184 } else {
185 DBG("usb_write NULL handle\n");
186 SetLastError(ERROR_INVALID_HANDLE);
187 }
188
189 DBG("usb_write failed: %d\n", errno);
190
191 return -1;
192 }
193
194 int usb_read(usb_handle *handle, void* data, int len) {
195 unsigned long time_out = 500 + len * 8;
196 unsigned long read = 0;
197 int ret;
198
199 DBG("usb_read %d\n", len);
200 if (NULL != handle) {
201 while (1) {
202 int xfer = (len > 4096) ? 4096 : len;
203
204 ret = AdbReadEndpointSync(handle->adb_read_pipe,
205 (void*)data,
206 (unsigned long)xfer,
207 &read,
208 time_out);
209 errno = GetLastError();
210 DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
211 if (ret) {
212 return read;
213 } else if (errno != ERROR_SEM_TIMEOUT) {
214 // assume ERROR_INVALID_HANDLE indicates we are disconnected
215 if (errno == ERROR_INVALID_HANDLE)
216 usb_kick(handle);
217 break;
218 }
219 // else we timed out - try again
220 }
221 } else {
222 DBG("usb_read NULL handle\n");
223 SetLastError(ERROR_INVALID_HANDLE);
224 }
225
226 DBG("usb_read failed: %d\n", errno);
227
228 return -1;
229 }
230
231 void usb_cleanup_handle(usb_handle* handle) {
232 if (NULL != handle) {
233 if (NULL != handle->interface_name)
234 free(handle->interface_name);
235 if (NULL != handle->adb_write_pipe)
236 AdbCloseHandle(handle->adb_write_pipe);
237 if (NULL != handle->adb_read_pipe)
238 AdbCloseHandle(handle->adb_read_pipe);
239 if (NULL != handle->adb_interface)
240 AdbCloseHandle(handle->adb_interface);
241
242 handle->interface_name = NULL;
243 handle->adb_write_pipe = NULL;
244 handle->adb_read_pipe = NULL;
245 handle->adb_interface = NULL;
246 }
247 }
248
249 void usb_kick(usb_handle* handle) {
250 if (NULL != handle) {
251 usb_cleanup_handle(handle);
252 } else {
253 SetLastError(ERROR_INVALID_HANDLE);
254 errno = ERROR_INVALID_HANDLE;
255 }
256 }
257
258 int usb_close(usb_handle* handle) {
259 DBG("usb_close\n");
260
261 if (NULL != handle) {
262 // Cleanup handle
263 usb_cleanup_handle(handle);
264 free(handle);
265 }
266
267 return 0;
268 }
269
270 int recognized_device(usb_handle* handle, ifc_match_func callback) {
271 struct usb_ifc_info info;
272 USB_DEVICE_DESCRIPTOR device_desc;
273 USB_INTERFACE_DESCRIPTOR interf_desc;
274
275 if (NULL == handle)
276 return 0;
277
278 // Check vendor and product id first
279 if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
280 &device_desc)) {
281 return 0;
282 }
283
284 // Then check interface properties
285 if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
286 &interf_desc)) {
287 return 0;
288 }
289
290 // Must have two endpoints
291 if (2 != interf_desc.bNumEndpoints) {
292 return 0;
293 }
294
295 info.dev_vendor = device_desc.idVendor;
296 info.dev_product = device_desc.idProduct;
297 info.dev_class = device_desc.bDeviceClass;
298 info.dev_subclass = device_desc.bDeviceSubClass;
299 info.dev_protocol = device_desc.bDeviceProtocol;
300 info.ifc_class = interf_desc.bInterfaceClass;
301 info.ifc_subclass = interf_desc.bInterfaceSubClass;
302 info.ifc_protocol = interf_desc.bInterfaceProtocol;
303
304 // read serial number (if there is one)
305 unsigned long serial_number_len = sizeof(info.serial_number);
306 if (!AdbGetSerialNumber(handle->adb_interface, info.serial_number,
307 &serial_number_len, true)) {
308 info.serial_number[0] = 0;
309 }
310
311 if (callback(&info) == 0) {
312 return 1;
313 }
314
315 return 0;
316 }
317
318 static usb_handle *find_usb_device(ifc_match_func callback) {
319 usb_handle* handle = NULL;
320 char entry_buffer[2048];
321 char interf_name[2048];
322 AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
323 unsigned long entry_buffer_size = sizeof(entry_buffer);
324 char* copy_name;
325
326 // Enumerate all present and active interfaces.
327 ADBAPIHANDLE enum_handle =
328 AdbEnumInterfaces(usb_class_id, true, true, true);
329
330 if (NULL == enum_handle)
331 return NULL;
332
333 while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
334 // TODO(vchtchetkine): FIXME - temp hack converting wchar_t into char.
335 // It would be better to change AdbNextInterface so it will return
336 // interface name as single char string.
337 const wchar_t* wchar_name = next_interface->device_name;
338 for(copy_name = interf_name;
339 L'\0' != *wchar_name;
340 wchar_name++, copy_name++) {
341 *copy_name = (char)(*wchar_name);
342 }
343 *copy_name = '\0';
344
345 handle = do_usb_open(next_interface->device_name);
346 if (NULL != handle) {
347 // Lets see if this interface (device) belongs to us
348 if (recognized_device(handle, callback)) {
349 // found it!
350 break;
351 } else {
352 usb_cleanup_handle(handle);
353 free(handle);
354 handle = NULL;
355 }
356 }
357
358 entry_buffer_size = sizeof(entry_buffer);
359 }
360
361 AdbCloseHandle(enum_handle);
362 return handle;
363 }
364
365 usb_handle *usb_open(ifc_match_func callback)
366 {
367 return find_usb_device(callback);
368 }
369
370 // called from fastboot.c
371 void sleep(int seconds)
372 {
373 Sleep(seconds * 1000);
374 }
+0
-212
fastboot/usbtest.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #include <sys/time.h>
34
35 #include "usb.h"
36
37 static unsigned arg_size = 4096;
38 static unsigned arg_count = 4096;
39
40 long long NOW(void)
41 {
42 struct timeval tv;
43 gettimeofday(&tv, 0);
44
45 return (((long long) tv.tv_sec) * ((long long) 1000000)) +
46 (((long long) tv.tv_usec));
47 }
48
49 int printifc(usb_ifc_info *info)
50 {
51 printf("dev: csp=%02x/%02x/%02x v=%04x p=%04x ",
52 info->dev_class, info->dev_subclass, info->dev_protocol,
53 info->dev_vendor, info->dev_product);
54 printf("ifc: csp=%02x/%02x/%02x%s%s\n",
55 info->ifc_class, info->ifc_subclass, info->ifc_protocol,
56 info->has_bulk_in ? " in" : "",
57 info->has_bulk_out ? " out" : "");
58 return -1;
59 }
60
61 int match_null(usb_ifc_info *info)
62 {
63 if(info->dev_vendor != 0x18d1) return -1;
64 if(info->ifc_class != 0xff) return -1;
65 if(info->ifc_subclass != 0xfe) return -1;
66 if(info->ifc_protocol != 0x01) return -1;
67 return 0;
68 }
69
70 int match_zero(usb_ifc_info *info)
71 {
72 if(info->dev_vendor != 0x18d1) return -1;
73 if(info->ifc_class != 0xff) return -1;
74 if(info->ifc_subclass != 0xfe) return -1;
75 if(info->ifc_protocol != 0x02) return -1;
76 return 0;
77 }
78
79 int match_loop(usb_ifc_info *info)
80 {
81 if(info->dev_vendor != 0x18d1) return -1;
82 if(info->ifc_class != 0xff) return -1;
83 if(info->ifc_subclass != 0xfe) return -1;
84 if(info->ifc_protocol != 0x03) return -1;
85 return 0;
86 }
87
88 int test_null(usb_handle *usb)
89 {
90 int i;
91 unsigned char buf[4096];
92 memset(buf, 0xee, 4096);
93 long long t0, t1;
94
95 t0 = NOW();
96 for(i = 0; i < arg_count; i++) {
97 if(usb_write(usb, buf, arg_size) != arg_size) {
98 fprintf(stderr,"write failed (%s)\n", strerror(errno));
99 return -1;
100 }
101 }
102 t1 = NOW();
103 fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
104 return 0;
105 }
106
107 int test_zero(usb_handle *usb)
108 {
109 int i;
110 unsigned char buf[4096];
111 long long t0, t1;
112
113 t0 = NOW();
114 for(i = 0; i < arg_count; i++) {
115 if(usb_read(usb, buf, arg_size) != arg_size) {
116 fprintf(stderr,"read failed (%s)\n", strerror(errno));
117 return -1;
118 }
119 }
120 t1 = NOW();
121 fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0));
122 return 0;
123 }
124
125 struct
126 {
127 const char *cmd;
128 ifc_match_func match;
129 int (*test)(usb_handle *usb);
130 const char *help;
131 } tests[] = {
132 { "list", printifc, 0, "list interfaces" },
133 { "send", match_null, test_null, "send to null interface" },
134 { "recv", match_zero, test_zero, "recv from zero interface" },
135 { "loop", match_loop, 0, "exercise loopback interface" },
136 {},
137 };
138
139 int usage(void)
140 {
141 int i;
142
143 fprintf(stderr,"usage: usbtest <testname>\n\navailable tests:\n");
144 for(i = 0; tests[i].cmd; i++) {
145 fprintf(stderr," %-8s %s\n", tests[i].cmd, tests[i].help);
146 }
147 return -1;
148 }
149
150 int process_args(int argc, char **argv)
151 {
152 while(argc-- > 0) {
153 char *arg = *argv++;
154 if(!strncmp(arg,"count=",6)) {
155 arg_count = atoi(arg + 6);
156 } else if(!strncmp(arg,"size=",5)) {
157 arg_size = atoi(arg + 5);
158 } else {
159 fprintf(stderr,"unknown argument: %s\n", arg);
160 return -1;
161 }
162 }
163
164 if(arg_count == 0) {
165 fprintf(stderr,"count may not be zero\n");
166 return -1;
167 }
168
169 if(arg_size > 4096) {
170 fprintf(stderr,"size may not be greater than 4096\n");
171 return -1;
172 }
173
174 return 0;
175 }
176
177 int main(int argc, char **argv)
178 {
179 usb_handle *usb;
180 int i;
181
182 if(argc < 2)
183 return usage();
184
185 if(argc > 2) {
186 if(process_args(argc - 2, argv + 2))
187 return -1;
188 }
189
190 for(i = 0; tests[i].cmd; i++) {
191 if(!strcmp(argv[1], tests[i].cmd)) {
192 usb = usb_open(tests[i].match);
193 if(tests[i].test) {
194 if(usb == 0) {
195 fprintf(stderr,"usbtest: %s: could not find interface\n",
196 tests[i].cmd);
197 return -1;
198 }
199 if(tests[i].test(usb)) {
200 fprintf(stderr,"usbtest: %s: FAIL\n", tests[i].cmd);
201 return -1;
202 } else {
203 fprintf(stderr,"usbtest: %s: OKAY\n", tests[i].cmd);
204 }
205 }
206 return 0;
207 }
208 }
209
210 return usage();
211 }
+0
-52
fastboot/util_linux.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <limits.h>
35
36 void get_my_path(char *path)
37 {
38 char proc[64];
39 char *x;
40
41 sprintf(proc, "/proc/%d/exe", getpid());
42 int err = readlink(proc, path, PATH_MAX - 1);
43
44 if(err <= 0) {
45 path[0] = 0;
46 } else {
47 path[err] = 0;
48 x = strrchr(path,'/');
49 if(x) x[1] = 0;
50 }
51 }
+0
-47
fastboot/util_osx.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <utils/executablepath.h>
29 #import <Carbon/Carbon.h>
30 #include <unistd.h>
31
32 void get_my_path(char s[PATH_MAX])
33 {
34 char *x;
35 ProcessSerialNumber psn;
36 GetCurrentProcess(&psn);
37 CFDictionaryRef dict;
38 dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
39 CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
40 CFSTR("CFBundleExecutable"));
41 CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
42 x = strrchr(s, '/');
43 if(x) x[1] = 0;
44 }
45
46
+0
-93
fastboot/util_windows.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
21 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <limits.h>
35
36 #include <windows.h>
37
38 void get_my_path(char exe[PATH_MAX])
39 {
40 char* r;
41
42 GetModuleFileName( NULL, exe, PATH_MAX-1 );
43 exe[PATH_MAX-1] = 0;
44 r = strrchr( exe, '\\' );
45 if (r)
46 *r = 0;
47 }
48
49
50 void *load_file(const char *fn, unsigned *_sz)
51 {
52 HANDLE file;
53 char *data;
54 DWORD file_size;
55
56 file = CreateFile( fn,
57 GENERIC_READ,
58 FILE_SHARE_READ,
59 NULL,
60 OPEN_EXISTING,
61 0,
62 NULL );
63
64 if (file == INVALID_HANDLE_VALUE)
65 return NULL;
66
67 file_size = GetFileSize( file, NULL );
68 data = NULL;
69
70 if (file_size > 0) {
71 data = (char*) malloc( file_size );
72 if (data == NULL) {
73 fprintf(stderr, "load_file: could not allocate %ld bytes\n", file_size );
74 file_size = 0;
75 } else {
76 DWORD out_bytes;
77
78 if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
79 out_bytes != file_size )
80 {
81 fprintf(stderr, "load_file: could not read %ld bytes from '%s'\n", file_size, fn);
82 free(data);
83 data = NULL;
84 file_size = 0;
85 }
86 }
87 }
88 CloseHandle( file );
89
90 *_sz = (unsigned) file_size;
91 return data;
92 }
+0
-260
include/arch/darwin-x86/AndroidConfig.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * Android config -- "Darwin". Used for PPC Mac OS X.
18 *
19 * TODO: split this into "x86" and "ppc" versions
20 */
21 #ifndef _ANDROID_CONFIG_H
22 #define _ANDROID_CONFIG_H
23
24 /*
25 * ===========================================================================
26 * !!! IMPORTANT !!!
27 * ===========================================================================
28 *
29 * This file is included by ALL C/C++ source files. Don't put anything in
30 * here unless you are absolutely certain it can't go anywhere else.
31 *
32 * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
33 * comments.
34 */
35
36 /*
37 * Threading model. Choose one:
38 *
39 * HAVE_PTHREADS - use the pthreads library.
40 * HAVE_WIN32_THREADS - use Win32 thread primitives.
41 * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
42 */
43 #define HAVE_PTHREADS
44
45 /*
46 * Do we have the futex syscall?
47 */
48
49 /* #define HAVE_FUTEX */
50
51 /*
52 * Process creation model. Choose one:
53 *
54 * HAVE_FORKEXEC - use fork() and exec()
55 * HAVE_WIN32_PROC - use CreateProcess()
56 */
57 #define HAVE_FORKEXEC
58
59 /*
60 * Process out-of-memory adjustment. Set if running on Linux,
61 * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
62 * badness adjustment.
63 */
64 /* #define HAVE_OOM_ADJ */
65
66 /*
67 * IPC model. Choose one:
68 *
69 * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
70 * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
71 * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
72 * HAVE_ANDROID_IPC - use Android versions (?, mmap).
73 */
74 #define HAVE_MACOSX_IPC
75
76 /*
77 * Memory-mapping model. Choose one:
78 *
79 * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
80 * HAVE_WIN32_FILEMAP - use Win32 filemaps
81 */
82 #define HAVE_POSIX_FILEMAP
83
84 /*
85 * Define this if you have <termio.h>
86 */
87 #define HAVE_TERMIO_H
88
89 /*
90 * Define this if you build against MSVCRT.DLL
91 */
92 /* #define HAVE_MS_C_RUNTIME */
93
94 /*
95 * Define this if you have sys/uio.h
96 */
97 #define HAVE_SYS_UIO_H
98
99 /*
100 * Define this if your platforms implements symbolic links
101 * in its filesystems
102 */
103 #define HAVE_SYMLINKS
104
105 /*
106 * Define this if we have localtime_r().
107 */
108 #define HAVE_LOCALTIME_R
109
110 /*
111 * Define this if we have gethostbyname_r().
112 */
113 /* #define HAVE_GETHOSTBYNAME_R */
114
115 /*
116 * Define this if we have ioctl().
117 */
118 /* #define HAVE_IOCTL */
119
120 /*
121 * Define this if we want to use WinSock.
122 */
123 /* #define HAVE_WINSOCK */
124
125 /*
126 * Define this if have clock_gettime() and friends
127 */
128 /* #define HAVE_POSIX_CLOCKS */
129
130 /*
131 * Define this if we have pthread_cond_timedwait_monotonic() and
132 * clock_gettime(CLOCK_MONOTONIC).
133 */
134 /* #define HAVE_TIMEDWAIT_MONOTONIC */
135
136 /*
137 * Endianness of the target machine. Choose one:
138 *
139 * HAVE_ENDIAN_H -- have endian.h header we can include.
140 * HAVE_LITTLE_ENDIAN -- we are little endian.
141 * HAVE_BIG_ENDIAN -- we are big endian.
142 */
143 #if (defined(__ppc__) || defined(__ppc64__))
144 # define HAVE_BIG_ENDIAN
145 #elif defined(__i386__)
146 # define HAVE_LITTLE_ENDIAN
147 #endif
148
149 /*
150 * We need to choose between 32-bit and 64-bit off_t. All of our code should
151 * agree on the same size. For desktop systems, use 64-bit values,
152 * because some of our libraries (e.g. wxWidgets) expect to be built that way.
153 */
154 #define _FILE_OFFSET_BITS 64
155 #define _LARGEFILE_SOURCE 1
156
157 /*
158 * Defined if we have the backtrace() call for retrieving a stack trace.
159 * Needed for CallStack to operate; if not defined, CallStack is
160 * non-functional.
161 */
162 #define HAVE_BACKTRACE 0
163
164 /*
165 * Defined if we have the dladdr() call for retrieving the symbol associated
166 * with a memory address. If not defined, stack crawls will not have symbolic
167 * information.
168 */
169 #define HAVE_DLADDR 0
170
171 /*
172 * Defined if we have the cxxabi.h header for demangling C++ symbols. If
173 * not defined, stack crawls will be displayed with raw mangled symbols
174 */
175 #define HAVE_CXXABI 0
176
177 /*
178 * Defined if we have the gettid() system call.
179 */
180 /* #define HAVE_GETTID */
181
182
183 /*
184 * Add any extra platform-specific defines here.
185 */
186 #define _THREAD_SAFE
187
188 /*
189 * Define if we have <malloc.h> header
190 */
191 /* #define HAVE_MALLOC_H */
192
193 /*
194 * Define if tm struct has tm_gmtoff field
195 */
196 #define HAVE_TM_GMTOFF 1
197
198 /*
199 * Define if dirent struct has d_type field
200 */
201 #define HAVE_DIRENT_D_TYPE 1
202
203 /*
204 * Define if we have madvise() in <sys/mman.h>
205 */
206 #define HAVE_MADVISE 1
207
208 /*
209 * Define if we include <sys/mount.h> for statfs()
210 */
211 #define INCLUDE_SYS_MOUNT_FOR_STATFS 1
212
213 /*
214 * What CPU architecture does this platform use?
215 */
216 #if (defined(__ppc__) || defined(__ppc64__))
217 # define ARCH_PPC
218 #elif defined(__i386__)
219 # define ARCH_X86
220 #endif
221
222 /*
223 * sprintf() format string for shared library naming.
224 */
225 #define OS_SHARED_LIB_FORMAT_STR "lib%s.dylib"
226
227 /*
228 * type for the third argument to mincore().
229 */
230 #define MINCORE_POINTER_TYPE char *
231
232 /*
233 * The default path separator for the platform
234 */
235 #define OS_PATH_SEPARATOR '/'
236
237 /*
238 * Is the filesystem case sensitive?
239 *
240 * For tools apps, we'll treat is as not case sensitive.
241 */
242 /* #define OS_CASE_SENSITIVE */
243
244 /*
245 * Define if <sys/socket.h> exists.
246 */
247 #define HAVE_SYS_SOCKET_H 1
248
249 /*
250 * Define if the strlcpy() function exists on the system.
251 */
252 #define HAVE_STRLCPY 1
253
254 /*
255 * Define if writev() exists
256 */
257 #define HAVE_WRITEV 1
258
259 #endif /*_ANDROID_CONFIG_H*/
+0
-305
include/arch/linux-arm/AndroidConfig.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * Android config -- "android-arm". Used for ARM device builds.
18 */
19 #ifndef _ANDROID_CONFIG_H
20 #define _ANDROID_CONFIG_H
21
22 /*
23 * ===========================================================================
24 * !!! IMPORTANT !!!
25 * ===========================================================================
26 *
27 * This file is included by ALL C/C++ source files. Don't put anything in
28 * here unless you are absolutely certain it can't go anywhere else.
29 *
30 * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
31 * comments.
32 */
33
34 /*
35 * Threading model. Choose one:
36 *
37 * HAVE_PTHREADS - use the pthreads library.
38 * HAVE_WIN32_THREADS - use Win32 thread primitives.
39 * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
40 */
41 #define HAVE_PTHREADS
42
43 /*
44 * Do we have the futex syscall?
45 */
46
47 #define HAVE_FUTEX
48
49 /*
50 * Define if we already have the futex wrapper functions defined. Yes if
51 * compiling against bionic.
52 */
53 #define HAVE_FUTEX_WRAPPERS 1
54
55 /*
56 * Process creation model. Choose one:
57 *
58 * HAVE_FORKEXEC - use fork() and exec()
59 * HAVE_WIN32_PROC - use CreateProcess()
60 */
61 #define HAVE_FORKEXEC
62
63 /*
64 * Process out-of-memory adjustment. Set if running on Linux,
65 * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
66 * badness adjustment.
67 */
68 #define HAVE_OOM_ADJ
69
70 /*
71 * IPC model. Choose one:
72 *
73 * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
74 * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
75 * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
76 * HAVE_ANDROID_IPC - use Android versions (?, mmap).
77 */
78 #define HAVE_ANDROID_IPC
79
80 /*
81 * Memory-mapping model. Choose one:
82 *
83 * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
84 * HAVE_WIN32_FILEMAP - use Win32 filemaps
85 */
86 #define HAVE_POSIX_FILEMAP
87
88 /*
89 * Define this if you have <termio.h>
90 */
91 #define HAVE_TERMIO_H
92
93 /*
94 * Define this if you build against MSVCRT.DLL
95 */
96 /* #define HAVE_MS_C_RUNTIME */
97
98 /*
99 * Define this if you have sys/uio.h
100 */
101 #define HAVE_SYS_UIO_H
102
103 /*
104 * Define this if your platforms implements symbolic links
105 * in its filesystems
106 */
107 #define HAVE_SYMLINKS
108
109 /*
110 * Define this if we have localtime_r().
111 */
112 /* #define HAVE_LOCALTIME_R */
113
114 /*
115 * Define this if we have gethostbyname_r().
116 */
117 /* #define HAVE_GETHOSTBYNAME_R */
118
119 /*
120 * Define this if we have ioctl().
121 */
122 #define HAVE_IOCTL
123
124 /*
125 * Define this if we want to use WinSock.
126 */
127 /* #define HAVE_WINSOCK */
128
129 /*
130 * Define this if have clock_gettime() and friends
131 */
132 #define HAVE_POSIX_CLOCKS
133
134 /*
135 * Define this if we have pthread_cond_timedwait_monotonic() and
136 * clock_gettime(CLOCK_MONOTONIC).
137 */
138 #define HAVE_TIMEDWAIT_MONOTONIC
139
140 /*
141 * Define this if we have linux style epoll()
142 */
143 #define HAVE_EPOLL
144
145 /*
146 * Endianness of the target machine. Choose one:
147 *
148 * HAVE_ENDIAN_H -- have endian.h header we can include.
149 * HAVE_LITTLE_ENDIAN -- we are little endian.
150 * HAVE_BIG_ENDIAN -- we are big endian.
151 */
152 #define HAVE_ENDIAN_H
153 #define HAVE_LITTLE_ENDIAN
154
155 /*
156 * We need to choose between 32-bit and 64-bit off_t. All of our code should
157 * agree on the same size. For desktop systems, use 64-bit values,
158 * because some of our libraries (e.g. wxWidgets) expect to be built that way.
159 */
160 /* #define _FILE_OFFSET_BITS 64 */
161 /* #define _LARGEFILE_SOURCE 1 */
162
163 /*
164 * Defined if we have the backtrace() call for retrieving a stack trace.
165 * Needed for CallStack to operate; if not defined, CallStack is
166 * non-functional.
167 */
168 #define HAVE_BACKTRACE 0
169
170 /*
171 * Defined if we have the dladdr() call for retrieving the symbol associated
172 * with a memory address. If not defined, stack crawls will not have symbolic
173 * information.
174 */
175 #define HAVE_DLADDR 0
176
177 /*
178 * Defined if we have the cxxabi.h header for demangling C++ symbols. If
179 * not defined, stack crawls will be displayed with raw mangled symbols
180 */
181 #define HAVE_CXXABI 0
182
183 /*
184 * Defined if we have the gettid() system call.
185 */
186 #define HAVE_GETTID
187
188 /*
189 * Defined if we have the sched_setscheduler() call
190 */
191 #define HAVE_SCHED_SETSCHEDULER
192
193 /*
194 * Add any extra platform-specific defines here.
195 */
196 #define __linux__
197
198 /*
199 * Define if we have <malloc.h> header
200 */
201 #define HAVE_MALLOC_H
202
203 /*
204 * Define if we're running on *our* linux on device or emulator.
205 */
206 #define HAVE_ANDROID_OS 1
207
208 /*
209 * Define if we have Linux-style non-filesystem Unix Domain Sockets
210 */
211 #define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
212
213 /*
214 * Define if we have Linux's inotify in <sys/inotify.h>.
215 */
216 #define HAVE_INOTIFY 1
217
218 /*
219 * Define if we have madvise() in <sys/mman.h>
220 */
221 #define HAVE_MADVISE 1
222
223 /*
224 * Define if tm struct has tm_gmtoff field
225 */
226 #define HAVE_TM_GMTOFF 1
227
228 /*
229 * Define if dirent struct has d_type field
230 */
231 #define HAVE_DIRENT_D_TYPE 1
232
233 /*
234 * Define if libc includes Android system properties implementation.
235 */
236 #define HAVE_LIBC_SYSTEM_PROPERTIES 1
237
238 /*
239 * Define if system provides a system property server (should be
240 * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
241 */
242 /* #define HAVE_SYSTEM_PROPERTY_SERVER */
243
244 /*
245 * What CPU architecture does this platform use?
246 */
247 #define ARCH_ARM
248
249 /*
250 * Define if the size of enums is as short as possible,
251 */
252 /* #define HAVE_SHORT_ENUMS */
253
254 /*
255 * sprintf() format string for shared library naming.
256 */
257 #define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
258
259 /*
260 * Do we have __memcmp16()?
261 */
262 #define HAVE__MEMCMP16 1
263
264 /*
265 * type for the third argument to mincore().
266 */
267 #define MINCORE_POINTER_TYPE unsigned char *
268
269 /*
270 * Do we have the sigaction flag SA_NOCLDWAIT?
271 */
272 #define HAVE_SA_NOCLDWAIT
273
274 /*
275 * The default path separator for the platform
276 */
277 #define OS_PATH_SEPARATOR '/'
278
279 /*
280 * Is the filesystem case sensitive?
281 */
282 #define OS_CASE_SENSITIVE
283
284 /*
285 * Define if <sys/socket.h> exists.
286 */
287 #define HAVE_SYS_SOCKET_H 1
288
289 /*
290 * Define if the strlcpy() function exists on the system.
291 */
292 #define HAVE_STRLCPY 1
293
294 /*
295 * Define if prctl() exists
296 */
297 #define HAVE_PRCTL 1
298
299 /*
300 * Define if writev() exists
301 */
302 #define HAVE_WRITEV 1
303
304 #endif /* _ANDROID_CONFIG_H */
+0
-286
include/arch/linux-x86/AndroidConfig.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * Android config -- "Linux". Used for desktop x86 Linux.
18 */
19 #ifndef _ANDROID_CONFIG_H
20 #define _ANDROID_CONFIG_H
21
22 /*
23 * ===========================================================================
24 * !!! IMPORTANT !!!
25 * ===========================================================================
26 *
27 * This file is included by ALL C/C++ source files. Don't put anything in
28 * here unless you are absolutely certain it can't go anywhere else.
29 *
30 * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
31 * comments.
32 */
33
34 /*
35 * Threading model. Choose one:
36 *
37 * HAVE_PTHREADS - use the pthreads library.
38 * HAVE_WIN32_THREADS - use Win32 thread primitives.
39 * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
40 */
41 #define HAVE_PTHREADS
42
43 /*
44 * Do we have the futex syscall?
45 */
46
47 #define HAVE_FUTEX
48
49 /*
50 * Process creation model. Choose one:
51 *
52 * HAVE_FORKEXEC - use fork() and exec()
53 * HAVE_WIN32_PROC - use CreateProcess()
54 */
55 #define HAVE_FORKEXEC
56
57 /*
58 * Process out-of-memory adjustment. Set if running on Linux,
59 * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
60 * badness adjustment.
61 */
62 #define HAVE_OOM_ADJ
63
64 /*
65 * IPC model. Choose one:
66 *
67 * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
68 * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
69 * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
70 * HAVE_ANDROID_IPC - use Android versions (?, mmap).
71 */
72 #define HAVE_SYSV_IPC
73
74 /*
75 * Memory-mapping model. Choose one:
76 *
77 * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
78 * HAVE_WIN32_FILEMAP - use Win32 filemaps
79 */
80 #define HAVE_POSIX_FILEMAP
81
82 /*
83 * Define this if you have <termio.h>
84 */
85 #define HAVE_TERMIO_H
86
87 /*
88 * Define this if you build against MSVCRT.DLL
89 */
90 /* #define HAVE_MS_C_RUNTIME */
91
92 /*
93 * Define this if you have sys/uio.h
94 */
95 #define HAVE_SYS_UIO_H
96
97 /*
98 * Define this if your platforms implements symbolic links
99 * in its filesystems
100 */
101 #define HAVE_SYMLINKS
102
103 /*
104 * Define this if we have localtime_r().
105 */
106 #define HAVE_LOCALTIME_R
107
108 /*
109 * Define this if we have gethostbyname_r().
110 */
111 #define HAVE_GETHOSTBYNAME_R
112
113 /*
114 * Define this if we have ioctl().
115 */
116 #define HAVE_IOCTL
117
118 /*
119 * Define this if we want to use WinSock.
120 */
121 /* #define HAVE_WINSOCK */
122
123 /*
124 * Define this if have clock_gettime() and friends
125 *
126 * Desktop Linux has this in librt, but it's broken in goobuntu, yielding
127 * mildly or wildly inaccurate results.
128 */
129 /*#define HAVE_POSIX_CLOCKS*/
130
131 /*
132 * Define this if we have pthread_cond_timedwait_monotonic() and
133 * clock_gettime(CLOCK_MONOTONIC).
134 */
135 /* #define HAVE_TIMEDWAIT_MONOTONIC */
136
137 /*
138 * Define this if we have linux style epoll()
139 */
140 #define HAVE_EPOLL
141
142 /*
143 * Endianness of the target machine. Choose one:
144 *
145 * HAVE_ENDIAN_H -- have endian.h header we can include.
146 * HAVE_LITTLE_ENDIAN -- we are little endian.
147 * HAVE_BIG_ENDIAN -- we are big endian.
148 */
149 #define HAVE_ENDIAN_H
150 #define HAVE_LITTLE_ENDIAN
151
152 /*
153 * We need to choose between 32-bit and 64-bit off_t. All of our code should
154 * agree on the same size. For desktop systems, use 64-bit values,
155 * because some of our libraries (e.g. wxWidgets) expect to be built that way.
156 */
157 #define _FILE_OFFSET_BITS 64
158 #define _LARGEFILE_SOURCE 1
159
160 /*
161 * Defined if we have the backtrace() call for retrieving a stack trace.
162 * Needed for CallStack to operate; if not defined, CallStack is
163 * non-functional.
164 */
165 #define HAVE_BACKTRACE 1
166
167 /*
168 * Defined if we have the dladdr() call for retrieving the symbol associated
169 * with a memory address. If not defined, stack crawls will not have symbolic
170 * information.
171 */
172 #define HAVE_DLADDR 1
173
174 /*
175 * Defined if we have the cxxabi.h header for demangling C++ symbols. If
176 * not defined, stack crawls will be displayed with raw mangled symbols
177 */
178 #define HAVE_CXXABI 0
179
180 /*
181 * Defined if we have the gettid() system call.
182 */
183 /* #define HAVE_GETTID */
184
185 /*
186 * Defined if we have the sched_setscheduler() call
187 */
188 #define HAVE_SCHED_SETSCHEDULER
189
190 /*
191 * Add any extra platform-specific defines here.
192 */
193
194 /*
195 * Define if we have <malloc.h> header
196 */
197 #define HAVE_MALLOC_H
198
199 /*
200 * Define if we have Linux-style non-filesystem Unix Domain Sockets
201 */
202
203 /*
204 * What CPU architecture does this platform use?
205 */
206 #define ARCH_X86
207
208
209 /*
210 * Define if we have Linux's inotify in <sys/inotify.h>.
211 */
212 /*#define HAVE_INOTIFY 1*/
213
214 /*
215 * Define if we have madvise() in <sys/mman.h>
216 */
217 #define HAVE_MADVISE 1
218
219 /*
220 * Define if tm struct has tm_gmtoff field
221 */
222 #define HAVE_TM_GMTOFF 1
223
224 /*
225 * Define if dirent struct has d_type field
226 */
227 #define HAVE_DIRENT_D_TYPE 1
228
229 /*
230 * Define if libc includes Android system properties implementation.
231 */
232 /* #define HAVE_LIBC_SYSTEM_PROPERTIES */
233
234 /*
235 * Define if system provides a system property server (should be
236 * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
237 */
238 #define HAVE_SYSTEM_PROPERTY_SERVER
239
240 /*
241 * sprintf() format string for shared library naming.
242 */
243 #define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
244
245 /*
246 * type for the third argument to mincore().
247 */
248 #define MINCORE_POINTER_TYPE unsigned char *
249
250 /*
251 * Do we have the sigaction flag SA_NOCLDWAIT?
252 */
253 #define HAVE_SA_NOCLDWAIT
254
255 /*
256 * The default path separator for the platform
257 */
258 #define OS_PATH_SEPARATOR '/'
259
260 /*
261 * Is the filesystem case sensitive?
262 */
263 #define OS_CASE_SENSITIVE
264
265 /*
266 * Define if <sys/socket.h> exists.
267 */
268 #define HAVE_SYS_SOCKET_H 1
269
270 /*
271 * Define if the strlcpy() function exists on the system.
272 */
273 /* #define HAVE_STRLCPY 1 */
274
275 /*
276 * Define if prctl() exists
277 */
278 #define HAVE_PRCTL 1
279
280 /*
281 * Define if writev() exists
282 */
283 #define HAVE_WRITEV 1
284
285 #endif /*_ANDROID_CONFIG_H*/
+0
-296
include/arch/target_linux-x86/AndroidConfig.h less more
0 /*
1 * Copyright 2005 The Android Open Source Project
2 *
3 * Android config -- "target_linux-x86". Used for x86 linux target devices.
4 */
5 #ifndef _ANDROID_CONFIG_H
6 #define _ANDROID_CONFIG_H
7
8 /*
9 * ===========================================================================
10 * !!! IMPORTANT !!!
11 * ===========================================================================
12 *
13 * This file is included by ALL C/C++ source files. Don't put anything in
14 * here unless you are absolutely certain it can't go anywhere else.
15 *
16 * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
17 * comments.
18 */
19
20 /*
21 * Threading model. Choose one:
22 *
23 * HAVE_PTHREADS - use the pthreads library.
24 * HAVE_WIN32_THREADS - use Win32 thread primitives.
25 * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
26 */
27 #define HAVE_PTHREADS
28
29 /*
30 * Do we have the futex syscall?
31 */
32
33 #define HAVE_FUTEX
34
35 /*
36 * Define if we already have the futex wrapper functions defined. Yes if
37 * compiling against bionic.
38 */
39 #define HAVE_FUTEX_WRAPPERS 1
40
41 /*
42 * Process creation model. Choose one:
43 *
44 * HAVE_FORKEXEC - use fork() and exec()
45 * HAVE_WIN32_PROC - use CreateProcess()
46 */
47 #define HAVE_FORKEXEC
48
49 /*
50 * Process out-of-memory adjustment. Set if running on Linux,
51 * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
52 * badness adjustment.
53 */
54 #define HAVE_OOM_ADJ
55
56 /*
57 * IPC model. Choose one:
58 *
59 * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
60 * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
61 * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
62 * HAVE_ANDROID_IPC - use Android versions (?, mmap).
63 */
64 #define HAVE_ANDROID_IPC 1
65
66 /*
67 * Memory-mapping model. Choose one:
68 *
69 * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
70 * HAVE_WIN32_FILEMAP - use Win32 filemaps
71 */
72 #define HAVE_POSIX_FILEMAP 1
73
74 /*
75 * Define this if you have <termio.h>
76 */
77 #define HAVE_TERMIO_H 1
78
79 /*
80 * Define this if you build against have Microsoft C runtime (MSVCRT.DLL)
81 */
82 /* #define HAVE_MS_C_RUNTIME */
83
84 /*
85 * Define this if you have sys/uio.h
86 */
87 #define HAVE_SYS_UIO_H 1
88
89 /*
90 * Define this if your platforms implements symbolic links
91 * in its filesystems
92 */
93 #define HAVE_SYMLINKS 1
94
95 /*
96 * Define this if we have localtime_r().
97 */
98 /* #define HAVE_LOCALTIME_R */
99
100 /*
101 * Define this if we have gethostbyname_r().
102 */
103 /* #define HAVE_GETHOSTBYNAME_R */
104
105 /*
106 * Define this if we have ioctl().
107 */
108 #define HAVE_IOCTL
109
110 /*
111 * Define this if we want to use WinSock.
112 */
113 /* #define HAVE_WINSOCK */
114
115 /*
116 * Define this if have clock_gettime() and friends
117 *
118 */
119 #define HAVE_POSIX_CLOCKS
120
121 /*
122 * Define this if we have pthread_cond_timedwait_monotonic() and
123 * clock_gettime(CLOCK_MONOTONIC).
124 */
125 #define HAVE_TIMEDWAIT_MONOTONIC
126
127 /*
128 * Define this if we have linux style epoll()
129 */
130 #define HAVE_EPOLL
131
132 /*
133 * Endianness of the target machine. Choose one:
134 *
135 * HAVE_ENDIAN_H -- have endian.h header we can include.
136 * HAVE_LITTLE_ENDIAN -- we are little endian.
137 * HAVE_BIG_ENDIAN -- we are big endian.
138 */
139 #define HAVE_ENDIAN_H
140 #define HAVE_LITTLE_ENDIAN
141
142 /*
143 * We need to choose between 32-bit and 64-bit off_t. All of our code should
144 * agree on the same size. For desktop systems, use 64-bit values,
145 * because some of our libraries (e.g. wxWidgets) expect to be built that way.
146 */
147 /*
148 * #define _FILE_OFFSET_BITS 64
149 * #define _LARGEFILE_SOURCE 1
150 */
151
152 /*
153 * Defined if we have the backtrace() call for retrieving a stack trace.
154 * Needed for CallStack to operate; if not defined, CallStack is
155 * non-functional.
156 */
157 #define HAVE_BACKTRACE 0
158
159 /*
160 * Defined if we have the dladdr() call for retrieving the symbol associated
161 * with a memory address. If not defined, stack crawls will not have symbolic
162 * information.
163 */
164 #define HAVE_DLADDR 0
165
166 /*
167 * Defined if we have the cxxabi.h header for demangling C++ symbols. If
168 * not defined, stack crawls will be displayed with raw mangled symbols
169 */
170 #define HAVE_CXXABI 0
171
172 /*
173 * Defined if we have the gettid() system call.
174 */
175 #define HAVE_GETTID
176
177 /*
178 * Defined if we have the sched_setscheduler() call
179 */
180 #define HAVE_SCHED_SETSCHEDULER
181
182 /*
183 * Add any extra platform-specific defines here.
184 */
185 #ifndef __linux__
186 #define __linux__
187 #endif
188
189 /*
190 * Define if we have <malloc.h> header
191 */
192 #define HAVE_MALLOC_H
193
194 /*
195 * Define if we're running on *our* linux on device or emulator.
196 */
197 #define HAVE_ANDROID_OS 1
198
199 /*
200 * Define if we have Linux-style non-filesystem Unix Domain Sockets
201 */
202 #define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
203
204 /*
205 * Define if we have Linux's inotify in <sys/inotify.h>.
206 */
207 #define HAVE_INOTIFY 1
208
209 /*
210 * Define if we have madvise() in <sys/mman.h>
211 */
212 #define HAVE_MADVISE 1
213
214 /*
215 * Define if we have Linux's dbus
216 */
217 #define HAVE_DBUS 1
218
219 /*
220 * Define if tm struct has tm_gmtoff field
221 */
222 #define HAVE_TM_GMTOFF 1
223
224 /*
225 * Define if dirent struct has d_type field
226 */
227 #define HAVE_DIRENT_D_TYPE 1
228
229 /*
230 * Define if libc includes Android system properties implementation.
231 */
232 #define HAVE_LIBC_SYSTEM_PROPERTIES 1
233
234 /*
235 * Define if system provides a system property server (should be
236 * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
237 */
238 /* #define HAVE_SYSTEM_PROPERTY_SERVER */
239
240 /*
241 * What CPU architecture does this platform use?
242 */
243 #define ARCH_X86
244
245 /*
246 * sprintf() format string for shared library naming.
247 */
248 #define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
249
250 /*
251 * Do we have __memcmp16()?
252 */
253 /* #define HAVE__MEMCMP16 1 */
254
255 /*
256 * type for the third argument to mincore().
257 */
258 #define MINCORE_POINTER_TYPE unsigned char *
259
260 /*
261 * Do we have the sigaction flag SA_NOCLDWAIT?
262 */
263 #define HAVE_SA_NOCLDWAIT
264
265 /*
266 * The default path separator for the platform
267 */
268 #define OS_PATH_SEPARATOR '/'
269
270 /*
271 * Is the filesystem case sensitive?
272 */
273 #define OS_CASE_SENSITIVE
274
275 /*
276 * Define if <sys/socket.h> exists.
277 */
278 #define HAVE_SYS_SOCKET_H 1
279
280 /*
281 * Define if the strlcpy() function exists on the system.
282 */
283 #define HAVE_STRLCPY 1
284
285 /*
286 * Define if prctl() exists
287 */
288 #define HAVE_PRCTL 1
289
290 /*
291 * Whether or not _Unwind_Context is defined as a struct.
292 */
293 #define HAVE_UNWIND_CONTEXT_STRUCT
294
295 #endif /* _ANDROID_CONFIG_H */
+0
-290
include/arch/windows/AndroidConfig.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * Android config -- "CYGWIN_NT-5.1".
18 *
19 * Cygwin has pthreads, but GDB seems to get confused if you use it to
20 * create threads. By "confused", I mean it freezes up the first time the
21 * debugged process creates a thread, even if you use CreateThread. The
22 * mere presence of pthreads linkage seems to cause problems.
23 */
24 #ifndef _ANDROID_CONFIG_H
25 #define _ANDROID_CONFIG_H
26
27 /*
28 * ===========================================================================
29 * !!! IMPORTANT !!!
30 * ===========================================================================
31 *
32 * This file is included by ALL C/C++ source files. Don't put anything in
33 * here unless you are absolutely certain it can't go anywhere else.
34 *
35 * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
36 * comments.
37 */
38
39 /*
40 * Threading model. Choose one:
41 *
42 * HAVE_PTHREADS - use the pthreads library.
43 * HAVE_WIN32_THREADS - use Win32 thread primitives.
44 */
45 #define HAVE_WIN32_THREADS
46
47 /*
48 * Do we have the futex syscall?
49 */
50
51 /* #define HAVE_FUTEX */
52
53
54 /*
55 * Process creation model. Choose one:
56 *
57 * HAVE_FORKEXEC - use fork() and exec()
58 * HAVE_WIN32_PROC - use CreateProcess()
59 */
60 #ifdef __CYGWIN__
61 # define HAVE_FORKEXEC
62 #else
63 # define HAVE_WIN32_PROC
64 #endif
65
66 /*
67 * Process out-of-memory adjustment. Set if running on Linux,
68 * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
69 * badness adjustment.
70 */
71 /* #define HAVE_OOM_ADJ */
72
73 /*
74 * IPC model. Choose one:
75 *
76 * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
77 * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
78 * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
79 * HAVE_ANDROID_IPC - use Android versions (?, mmap).
80 */
81 #define HAVE_WIN32_IPC
82
83 /*
84 * Memory-mapping model. Choose one:
85 *
86 * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
87 * HAVE_WIN32_FILEMAP - use Win32 filemaps
88 */
89 #ifdef __CYGWIN__
90 #define HAVE_POSIX_FILEMAP
91 #else
92 #define HAVE_WIN32_FILEMAP
93 #endif
94
95 /*
96 * Define this if you have <termio.h>
97 */
98 #ifdef __CYGWIN__
99 # define HAVE_TERMIO_H
100 #endif
101
102 /*
103 * Define this if you build against MSVCRT.DLL
104 */
105 #ifndef __CYGWIN__
106 # define HAVE_MS_C_RUNTIME
107 #endif
108
109 /*
110 * Define this if you have sys/uio.h
111 */
112 #ifdef __CYGWIN__
113 #define HAVE_SYS_UIO_H
114 #endif
115
116
117 /*
118 * Define this if we have localtime_r().
119 */
120 /* #define HAVE_LOCALTIME_R */
121
122 /*
123 * Define this if we have gethostbyname_r().
124 */
125 /* #define HAVE_GETHOSTBYNAME_R */
126
127 /*
128 * Define this if we have ioctl().
129 */
130 /* #define HAVE_IOCTL */
131
132 /*
133 * Define this if we want to use WinSock.
134 */
135 #ifndef __CYGWIN__
136 #define HAVE_WINSOCK
137 #endif
138
139 /*
140 * Define this if your platforms implements symbolic links
141 * in its filesystems
142 */
143 /* #define HAVE_SYMLINKS */
144
145 /*
146 * Define this if have clock_gettime() and friends
147 */
148 /* #define HAVE_POSIX_CLOCKS */
149
150 /*
151 * Endianness of the target machine. Choose one:
152 *
153 * HAVE_ENDIAN_H -- have endian.h header we can include.
154 * HAVE_LITTLE_ENDIAN -- we are little endian.
155 * HAVE_BIG_ENDIAN -- we are big endian.
156 */
157 #ifdef __CYGWIN__
158 #define HAVE_ENDIAN_H
159 #endif
160
161 #define HAVE_LITTLE_ENDIAN
162
163 /*
164 * We need to choose between 32-bit and 64-bit off_t. All of our code should
165 * agree on the same size. For desktop systems, use 64-bit values,
166 * because some of our libraries (e.g. wxWidgets) expect to be built that way.
167 */
168 #define _FILE_OFFSET_BITS 64
169 #define _LARGEFILE_SOURCE 1
170
171 /*
172 * Defined if we have the backtrace() call for retrieving a stack trace.
173 * Needed for CallStack to operate; if not defined, CallStack is
174 * non-functional.
175 */
176 #define HAVE_BACKTRACE 0
177
178 /*
179 * Defined if we have the dladdr() call for retrieving the symbol associated
180 * with a memory address. If not defined, stack crawls will not have symbolic
181 * information.
182 */
183 #define HAVE_DLADDR 0
184
185 /*
186 * Defined if we have the cxxabi.h header for demangling C++ symbols. If
187 * not defined, stack crawls will be displayed with raw mangled symbols
188 */
189 #define HAVE_CXXABI 0
190
191 /*
192 * Define if tm struct has tm_gmtoff field
193 */
194 /* #define HAVE_TM_GMTOFF 1 */
195
196 /*
197 * Define if dirent struct has d_type field
198 */
199 /* #define HAVE_DIRENT_D_TYPE 1 */
200
201 /*
202 * Define if libc includes Android system properties implementation.
203 */
204 /* #define HAVE_LIBC_SYSTEM_PROPERTIES */
205
206 /*
207 * Define if system provides a system property server (should be
208 * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
209 */
210 /* #define HAVE_SYSTEM_PROPERTY_SERVER */
211
212 /*
213 * Define if we have madvise() in <sys/mman.h>
214 */
215 /*#define HAVE_MADVISE 1*/
216
217 /*
218 * Add any extra platform-specific defines here.
219 */
220 #define WIN32 1 /* stock Cygwin doesn't define these */
221 #define _WIN32 1
222 #define _WIN32_WINNT 0x0500 /* admit to using >= Win2K */
223
224 #define HAVE_WINDOWS_PATHS /* needed by simulator */
225
226 /*
227 * What CPU architecture does this platform use?
228 */
229 #define ARCH_X86
230
231 /*
232 * sprintf() format string for shared library naming.
233 */
234 #define OS_SHARED_LIB_FORMAT_STR "lib%s.dll"
235
236 /*
237 * type for the third argument to mincore().
238 */
239 #define MINCORE_POINTER_TYPE unsigned char *
240
241 /*
242 * The default path separator for the platform
243 */
244 #define OS_PATH_SEPARATOR '\\'
245
246 /*
247 * Is the filesystem case sensitive?
248 */
249 /* #define OS_CASE_SENSITIVE */
250
251 /*
252 * Define if <sys/socket.h> exists.
253 * Cygwin has it, but not MinGW.
254 */
255 #ifdef USE_MINGW
256 /* #define HAVE_SYS_SOCKET_H */
257 #else
258 #define HAVE_SYS_SOCKET_H 1
259 #endif
260
261 /*
262 * Define if the strlcpy() function exists on the system.
263 */
264 /* #define HAVE_STRLCPY 1 */
265
266 /*
267 * Define if <winsock2.h> exists.
268 * Only MinGW has it.
269 */
270 #ifdef USE_MINGW
271 #define HAVE_WINSOCK2_H 1
272 #else
273 /* #define HAVE_WINSOCK2_H */
274 #endif
275
276 /*
277 * Various definitions missing in MinGW
278 */
279 #ifdef USE_MINGW
280 #define S_IRGRP 0
281 #define sleep _sleep
282 #endif
283
284 /*
285 * Define if writev() exists.
286 */
287 /* #define HAVE_WRITEV */
288
289 #endif /*_ANDROID_CONFIG_H*/
+0
-70
include/ctest/ctest.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Very simple unit testing framework.
18 */
19
20 #ifndef __CUTILS_TEST_H
21 #define __CUTILS_TEST_H
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 /**
28 * Adds a test to the test suite.
29 */
30 #define addTest(test) addNamedTest(#test, &test)
31
32 /**
33 * Asserts that a condition is true. The test fails if it isn't.
34 */
35 #define assertTrue(value, message) assertTrueWithSource(value, __FILE__, __LINE__, message);
36
37 /**
38 * Asserts that a condition is false. The test fails if the value is true.
39 */
40 #define assertFalse(value, message) assertTrueWithSource(!value, __FILE__, __LINE__, message);
41
42 /** Fails a test with the given message. */
43 #define fail(message) assertTrueWithSource(0, __FILE__, __LINE__, message);
44
45 /**
46 * Asserts that two values are ==.
47 */
48 #define assertSame(a, b) assertTrueWithSource(a == b, __FILE__, __LINE__, "Expected same value.");
49
50 /**
51 * Asserts that two values are !=.
52 */
53 #define assertNotSame(a, b) assertTrueWithSource(a != b, __FILE__, __LINE__,\
54 "Expected different values");
55
56 /**
57 * Runs a test suite.
58 */
59 void runTests(void);
60
61 // Do not call these functions directly. Use macros above instead.
62 void addNamedTest(const char* name, void (*test)(void));
63 void assertTrueWithSource(int value, const char* file, int line, char* message);
64
65 #ifdef __cplusplus
66 }
67 #endif
68
69 #endif /* __CUTILS_TEST_H */
+0
-35
include/cutils/adb_networking.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _ADB_NETWORKING_H
17 #define _ADB_NETWORKING_H 1
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <sys/socket.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 extern int adb_networking_connect_fd(int fd, struct sockaddr_in *p_address);
27 extern int adb_networking_gethostbyname(const char *name, struct in_addr *p_out_addr);
28
29 #ifdef __cplusplus
30 }
31 #endif
32
33 #endif /*_ADB_NETWORKING_H*/
34
+0
-67
include/cutils/array.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * A pointer array which intelligently expands its capacity ad needed.
18 */
19
20 #ifndef __ARRAY_H
21 #define __ARRAY_H
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 #include <stdlib.h>
28
29 /** An array. */
30 typedef struct Array Array;
31
32 /** Constructs a new array. Returns NULL if we ran out of memory. */
33 Array* arrayCreate();
34
35 /** Frees an array. Does not free elements themselves. */
36 void arrayFree(Array* array);
37
38 /** Adds a pointer. Returns 0 is successful, < 0 otherwise. */
39 int arrayAdd(Array* array, void* pointer);
40
41 /** Gets the pointer at the specified index. */
42 void* arrayGet(Array* array, int index);
43
44 /** Removes the pointer at the given index and returns it. */
45 void* arrayRemove(Array* array, int index);
46
47 /** Sets pointer at the given index. Returns old pointer. */
48 void* arraySet(Array* array, int index, void* pointer);
49
50 /** Sets the array size. Sets new pointers to NULL. Returns 0 if successful, < 0 otherwise . */
51 int arraySetSize(Array* array, int size);
52
53 /** Returns the size of the given array. */
54 int arraySize(Array* array);
55
56 /**
57 * Returns a pointer to a C-style array which will be valid until this array
58 * changes.
59 */
60 const void** arrayUnwrap(Array* array);
61
62 #ifdef __cplusplus
63 }
64 #endif
65
66 #endif /* __ARRAY_H */
+0
-42
include/cutils/ashmem.h less more
0 /* cutils/ashmem.h
1 **
2 ** Copyright 2008 The Android Open Source Project
3 **
4 ** This file is dual licensed. It may be redistributed and/or modified
5 ** under the terms of the Apache 2.0 License OR version 2 of the GNU
6 ** General Public License.
7 */
8
9 #ifndef _CUTILS_ASHMEM_H
10 #define _CUTILS_ASHMEM_H
11
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15
16 int ashmem_create_region(const char *name, size_t size);
17 int ashmem_set_prot_region(int fd, int prot);
18 int ashmem_pin_region(int fd, size_t offset, size_t len);
19 int ashmem_unpin_region(int fd, size_t offset, size_t len);
20
21 #ifdef __cplusplus
22 }
23 #endif
24
25 #ifndef __ASHMEMIOC /* in case someone included <linux/ashmem.h> too */
26
27 #define ASHMEM_NAME_LEN 256
28
29 #define ASHMEM_NAME_DEF "dev/ashmem"
30
31 /* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
32 #define ASHMEM_NOT_PURGED 0
33 #define ASHMEM_WAS_PURGED 1
34
35 /* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
36 #define ASHMEM_IS_UNPINNED 0
37 #define ASHMEM_IS_PINNED 1
38
39 #endif /* ! __ASHMEMIOC */
40
41 #endif /* _CUTILS_ASHMEM_H */
+0
-79
include/cutils/atomic.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ANDROID_CUTILS_ATOMIC_H
17 #define ANDROID_CUTILS_ATOMIC_H
18
19 #include <stdint.h>
20 #include <sys/types.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 /*
27 * NOTE: memory shared between threads is synchronized by all atomic operations
28 * below, this means that no explicit memory barrier is required: all reads or
29 * writes issued before android_atomic_* operations are guaranteed to complete
30 * before the atomic operation takes place.
31 */
32
33 void android_atomic_write(int32_t value, volatile int32_t* addr);
34
35 /*
36 * all these atomic operations return the previous value
37 */
38
39
40 int32_t android_atomic_inc(volatile int32_t* addr);
41 int32_t android_atomic_dec(volatile int32_t* addr);
42
43 int32_t android_atomic_add(int32_t value, volatile int32_t* addr);
44 int32_t android_atomic_and(int32_t value, volatile int32_t* addr);
45 int32_t android_atomic_or(int32_t value, volatile int32_t* addr);
46
47 int32_t android_atomic_swap(int32_t value, volatile int32_t* addr);
48
49 /*
50 * NOTE: Two "quasiatomic" operations on the exact same memory address
51 * are guaranteed to operate atomically with respect to each other,
52 * but no guarantees are made about quasiatomic operations mixed with
53 * non-quasiatomic operations on the same address, nor about
54 * quasiatomic operations that are performed on partially-overlapping
55 * memory.
56 */
57
58 int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr);
59 int64_t android_quasiatomic_read_64(volatile int64_t* addr);
60
61 /*
62 * cmpxchg return a non zero value if the exchange was NOT performed,
63 * in other words if oldvalue != *addr
64 */
65
66 int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue,
67 volatile int32_t* addr);
68
69 int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
70 volatile int64_t* addr);
71
72
73
74 #ifdef __cplusplus
75 } // extern "C"
76 #endif
77
78 #endif // ANDROID_CUTILS_ATOMIC_H
+0
-61
include/cutils/config_utils.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_CONFIG_UTILS_H
17 #define __CUTILS_CONFIG_UTILS_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 typedef struct cnode cnode;
24
25
26 struct cnode
27 {
28 cnode *next;
29 cnode *first_child;
30 cnode *last_child;
31 const char *name;
32 const char *value;
33 };
34
35 /* parse a text string into a config node tree */
36 void config_load(cnode *root, char *data);
37
38 /* parse a file into a config node tree */
39 void config_load_file(cnode *root, const char *fn);
40
41 /* create a single config node */
42 cnode* config_node(const char *name, const char *value);
43
44 /* locate a named child of a config node */
45 cnode* config_find(cnode *root, const char *name);
46
47 /* look up a child by name and return the boolean value */
48 int config_bool(cnode *root, const char *name, int _default);
49
50 /* look up a child by name and return the string value */
51 const char* config_str(cnode *root, const char *name, const char *_default);
52
53 /* add a named child to a config node (or modify it if it already exists) */
54 void config_set(cnode *root, const char *name, const char *value);
55
56 #ifdef __cplusplus
57 }
58 #endif
59
60 #endif
+0
-34
include/cutils/cpu_info.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_CPU_INFO_H
17 #define __CUTILS_CPU_INFO_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 /* returns a string contiaining an ASCII representation of the CPU serial number,
24 ** or NULL if cpu info not available.
25 ** The string is a static variable, so don't call free() on it.
26 */
27 extern const char* get_cpu_serial_number(void);
28
29 #ifdef __cplusplus
30 }
31 #endif
32
33 #endif /* __CUTILS_CPU_INFO_H */
+0
-26
include/cutils/dir_hash.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 typedef enum {
17 SHA_1,
18 } HashAlgorithm;
19
20 int get_file_hash(HashAlgorithm algorithm, const char *path,
21 char *output_string, size_t max_output_string);
22
23 int get_recursive_hash_manifest(HashAlgorithm algorithm,
24 const char *directory_path,
25 char **output_string);
+0
-50
include/cutils/event_tag_map.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _LIBS_CUTILS_EVENTTAGMAP_H
17 #define _LIBS_CUTILS_EVENTTAGMAP_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 #define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
24
25 struct EventTagMap;
26 typedef struct EventTagMap EventTagMap;
27
28 /*
29 * Open the specified file as an event log tag map.
30 *
31 * Returns NULL on failure.
32 */
33 EventTagMap* android_openEventTagMap(const char* fileName);
34
35 /*
36 * Close the map.
37 */
38 void android_closeEventTagMap(EventTagMap* map);
39
40 /*
41 * Look up a tag by index. Returns the tag string, or NULL if not found.
42 */
43 const char* android_lookupEventTag(const EventTagMap* map, int tag);
44
45 #ifdef __cplusplus
46 }
47 #endif
48
49 #endif /*_LIBS_CUTILS_EVENTTAGMAP_H*/
+0
-74
include/cutils/fdevent.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __FDEVENT_H
17 #define __FDEVENT_H
18
19 /* events that may be observed */
20 #define FDE_READ 0x0001
21 #define FDE_WRITE 0x0002
22 #define FDE_ERROR 0x0004
23
24 /* features that may be set (via the events set/add/del interface) */
25 #define FDE_DONT_CLOSE 0x0080
26
27 typedef struct fdevent fdevent;
28
29 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
30
31 /* Allocate and initialize a new fdevent object
32 */
33 fdevent *fdevent_create(int fd, fd_func func, void *arg);
34
35 /* Uninitialize and deallocate an fdevent object that was
36 ** created by fdevent_create()
37 */
38 void fdevent_destroy(fdevent *fde);
39
40 /* Initialize an fdevent object that was externally allocated
41 */
42 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
43
44 /* Uninitialize an fdevent object that was initialized by
45 ** fdevent_install()
46 */
47 void fdevent_remove(fdevent *item);
48
49 /* Change which events should cause notifications
50 */
51 void fdevent_set(fdevent *fde, unsigned events);
52 void fdevent_add(fdevent *fde, unsigned events);
53 void fdevent_del(fdevent *fde, unsigned events);
54
55 /* loop forever, handling events.
56 */
57 void fdevent_loop();
58
59 struct fdevent
60 {
61 fdevent *next;
62 fdevent *prev;
63
64 int fd;
65 unsigned short state;
66 unsigned short events;
67
68 fd_func func;
69 void *arg;
70 };
71
72
73 #endif
+0
-150
include/cutils/hashmap.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Hash map.
18 */
19
20 #ifndef __HASHMAP_H
21 #define __HASHMAP_H
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29
30 /** A hash map. */
31 typedef struct Hashmap Hashmap;
32
33 /**
34 * Creates a new hash map. Returns NULL if memory allocation fails.
35 *
36 * @param initialCapacity number of expected entries
37 * @param hash function which hashes keys
38 * @param equals function which compares keys for equality
39 */
40 Hashmap* hashmapCreate(size_t initialCapacity,
41 int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB));
42
43 /**
44 * Frees the hash map. Does not free the keys or values themselves.
45 */
46 void hashmapFree(Hashmap* map);
47
48 /**
49 * Hashes the memory pointed to by key with the given size. Useful for
50 * implementing hash functions.
51 */
52 int hashmapHash(void* key, size_t keySize);
53
54 /**
55 * Puts value for the given key in the map. Returns pre-existing value if
56 * any.
57 *
58 * If memory allocation fails, this function returns NULL, the map's size
59 * does not increase, and errno is set to ENOMEM.
60 */
61 void* hashmapPut(Hashmap* map, void* key, void* value);
62
63 /**
64 * Gets a value from the map. Returns NULL if no entry for the given key is
65 * found or if the value itself is NULL.
66 */
67 void* hashmapGet(Hashmap* map, void* key);
68
69 /**
70 * Returns true if the map contains an entry for the given key.
71 */
72 bool hashmapContainsKey(Hashmap* map, void* key);
73
74 /**
75 * Gets the value for a key. If a value is not found, this function gets a
76 * value and creates an entry using the given callback.
77 *
78 * If memory allocation fails, the callback is not called, this function
79 * returns NULL, and errno is set to ENOMEM.
80 */
81 void* hashmapMemoize(Hashmap* map, void* key,
82 void* (*initialValue)(void* key, void* context), void* context);
83
84 /**
85 * Removes an entry from the map. Returns the removed value or NULL if no
86 * entry was present.
87 */
88 void* hashmapRemove(Hashmap* map, void* key);
89
90 /**
91 * Gets the number of entries in this map.
92 */
93 size_t hashmapSize(Hashmap* map);
94
95 /**
96 * Invokes the given callback on each entry in the map. Stops iterating if
97 * the callback returns false.
98 */
99 void hashmapForEach(Hashmap* map,
100 bool (*callback)(void* key, void* value, void* context),
101 void* context);
102
103 /**
104 * Concurrency support.
105 */
106
107 /**
108 * Locks the hash map so only the current thread can access it.
109 */
110 void hashmapLock(Hashmap* map);
111
112 /**
113 * Unlocks the hash map so other threads can access it.
114 */
115 void hashmapUnlock(Hashmap* map);
116
117 /**
118 * Key utilities.
119 */
120
121 /**
122 * Hashes int keys. 'key' is a pointer to int.
123 */
124 int hashmapIntHash(void* key);
125
126 /**
127 * Compares two int keys for equality.
128 */
129 bool hashmapIntEquals(void* keyA, void* keyB);
130
131 /**
132 * For debugging.
133 */
134
135 /**
136 * Gets current capacity.
137 */
138 size_t hashmapCurrentCapacity(Hashmap* map);
139
140 /**
141 * Counts the number of entry collisions.
142 */
143 size_t hashmapCountCollisions(Hashmap* map);
144
145 #ifdef __cplusplus
146 }
147 #endif
148
149 #endif /* __HASHMAP_H */
+0
-43
include/cutils/jstring.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_STRING16_H
17 #define __CUTILS_STRING16_H
18
19 #include <stdint.h>
20 #include <stddef.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 typedef uint16_t char16_t;
27
28 extern char * strndup16to8 (const char16_t* s, size_t n);
29 extern size_t strnlen16to8 (const char16_t* s, size_t n);
30 extern char * strncpy16to8 (char *dest, const char16_t*s, size_t n);
31
32 extern char16_t * strdup8to16 (const char* s, size_t *out_len);
33 extern size_t strlen8to16 (const char* utf8Str);
34 extern char16_t * strcpy8to16 (char16_t *dest, const char*s, size_t *out_len);
35 extern char16_t * strcpylen8to16 (char16_t *dest, const char*s, int length,
36 size_t *out_len);
37
38 #ifdef __cplusplus
39 }
40 #endif
41
42 #endif /* __CUTILS_STRING16_H */
+0
-346
include/cutils/log.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 //
17 // C/C++ logging functions. See the logging documentation for API details.
18 //
19 // We'd like these to be available from C code (in case we import some from
20 // somewhere), so this has a C interface.
21 //
22 // The output will be correct when the log file is shared between multiple
23 // threads and/or multiple processes so long as the operating system
24 // supports O_APPEND. These calls have mutex-protected data structures
25 // and so are NOT reentrant. Do not use LOG in a signal handler.
26 //
27 #ifndef _LIBS_CUTILS_LOG_H
28 #define _LIBS_CUTILS_LOG_H
29
30 #include <stdio.h>
31 #include <time.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #ifdef HAVE_PTHREADS
35 #include <pthread.h>
36 #endif
37 #include <stdarg.h>
38
39 #include <cutils/uio.h>
40 #include <cutils/logd.h>
41
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45
46 // ---------------------------------------------------------------------
47
48 /*
49 * Normally we strip LOGV (VERBOSE messages) from release builds.
50 * You can modify this (for example with "#define LOG_NDEBUG 0"
51 * at the top of your source file) to change that behavior.
52 */
53 #ifndef LOG_NDEBUG
54 #ifdef NDEBUG
55 #define LOG_NDEBUG 1
56 #else
57 #define LOG_NDEBUG 0
58 #endif
59 #endif
60
61 /*
62 * This is the local tag used for the following simplified
63 * logging macros. You can change this preprocessor definition
64 * before using the other macros to change the tag.
65 */
66 #ifndef LOG_TAG
67 #define LOG_TAG NULL
68 #endif
69
70 // ---------------------------------------------------------------------
71
72 /*
73 * Simplified macro to send a verbose log message using the current LOG_TAG.
74 */
75 #ifndef LOGV
76 #if LOG_NDEBUG
77 #define LOGV(...) ((void)0)
78 #else
79 #define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
80 #endif
81 #endif
82
83 #define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
84
85 #ifndef LOGV_IF
86 #if LOG_NDEBUG
87 #define LOGV_IF(cond, ...) ((void)0)
88 #else
89 #define LOGV_IF(cond, ...) \
90 ( (CONDITION(cond)) \
91 ? ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
92 : (void)0 )
93 #endif
94 #endif
95
96 /*
97 * Simplified macro to send a debug log message using the current LOG_TAG.
98 */
99 #ifndef LOGD
100 #define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
101 #endif
102
103 #ifndef LOGD_IF
104 #define LOGD_IF(cond, ...) \
105 ( (CONDITION(cond)) \
106 ? ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
107 : (void)0 )
108 #endif
109
110 /*
111 * Simplified macro to send an info log message using the current LOG_TAG.
112 */
113 #ifndef LOGI
114 #define LOGI(...) ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
115 #endif
116
117 #ifndef LOGI_IF
118 #define LOGI_IF(cond, ...) \
119 ( (CONDITION(cond)) \
120 ? ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
121 : (void)0 )
122 #endif
123
124 /*
125 * Simplified macro to send a warning log message using the current LOG_TAG.
126 */
127 #ifndef LOGW
128 #define LOGW(...) ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
129 #endif
130
131 #ifndef LOGW_IF
132 #define LOGW_IF(cond, ...) \
133 ( (CONDITION(cond)) \
134 ? ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
135 : (void)0 )
136 #endif
137
138 /*
139 * Simplified macro to send an error log message using the current LOG_TAG.
140 */
141 #ifndef LOGE
142 #define LOGE(...) ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
143 #endif
144
145 #ifndef LOGE_IF
146 #define LOGE_IF(cond, ...) \
147 ( (CONDITION(cond)) \
148 ? ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
149 : (void)0 )
150 #endif
151
152 // ---------------------------------------------------------------------
153
154 /*
155 * Conditional based on whether the current LOG_TAG is enabled at
156 * verbose priority.
157 */
158 #ifndef IF_LOGV
159 #if LOG_NDEBUG
160 #define IF_LOGV() if (false)
161 #else
162 #define IF_LOGV() IF_LOG(LOG_VERBOSE, LOG_TAG)
163 #endif
164 #endif
165
166 /*
167 * Conditional based on whether the current LOG_TAG is enabled at
168 * debug priority.
169 */
170 #ifndef IF_LOGD
171 #define IF_LOGD() IF_LOG(LOG_DEBUG, LOG_TAG)
172 #endif
173
174 /*
175 * Conditional based on whether the current LOG_TAG is enabled at
176 * info priority.
177 */
178 #ifndef IF_LOGI
179 #define IF_LOGI() IF_LOG(LOG_INFO, LOG_TAG)
180 #endif
181
182 /*
183 * Conditional based on whether the current LOG_TAG is enabled at
184 * warn priority.
185 */
186 #ifndef IF_LOGW
187 #define IF_LOGW() IF_LOG(LOG_WARN, LOG_TAG)
188 #endif
189
190 /*
191 * Conditional based on whether the current LOG_TAG is enabled at
192 * error priority.
193 */
194 #ifndef IF_LOGE
195 #define IF_LOGE() IF_LOG(LOG_ERROR, LOG_TAG)
196 #endif
197
198 // ---------------------------------------------------------------------
199
200 /*
201 * Log a fatal error. If the given condition fails, this stops program
202 * execution like a normal assertion, but also generating the given message.
203 * It is NOT stripped from release builds. Note that the condition test
204 * is -inverted- from the normal assert() semantics.
205 */
206 #define LOG_ALWAYS_FATAL_IF(cond, ...) \
207 ( (CONDITION(cond)) \
208 ? ((void)android_printAssert(#cond, LOG_TAG, __VA_ARGS__)) \
209 : (void)0 )
210
211 #define LOG_ALWAYS_FATAL(...) \
212 ( ((void)android_printAssert(NULL, LOG_TAG, __VA_ARGS__)) )
213
214 /*
215 * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
216 * are stripped out of release builds.
217 */
218 #if LOG_NDEBUG
219
220 #define LOG_FATAL_IF(cond, ...) ((void)0)
221 #define LOG_FATAL(...) ((void)0)
222
223 #else
224
225 #define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__)
226 #define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
227
228 #endif
229
230 /*
231 * Assertion that generates a log message when the assertion fails.
232 * Stripped out of release builds. Uses the current LOG_TAG.
233 */
234 #define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), __VA_ARGS__)
235 //#define LOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
236
237 // ---------------------------------------------------------------------
238
239 /*
240 * Basic log message macro.
241 *
242 * Example:
243 * LOG(LOG_WARN, NULL, "Failed with error %d", errno);
244 *
245 * The second argument may be NULL or "" to indicate the "global" tag.
246 */
247 #ifndef LOG
248 #define LOG(priority, tag, ...) \
249 LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
250 #endif
251
252 /*
253 * Log macro that allows you to specify a number for the priority.
254 */
255 #ifndef LOG_PRI
256 #define LOG_PRI(priority, tag, ...) \
257 android_printLog(priority, tag, __VA_ARGS__)
258 #endif
259
260 /*
261 * Log macro that allows you to pass in a varargs ("args" is a va_list).
262 */
263 #ifndef LOG_PRI_VA
264 #define LOG_PRI_VA(priority, tag, fmt, args) \
265 android_vprintLog(priority, NULL, tag, fmt, args)
266 #endif
267
268 /*
269 * Conditional given a desired logging priority and tag.
270 */
271 #ifndef IF_LOG
272 #define IF_LOG(priority, tag) \
273 if (android_testLog(ANDROID_##priority, tag))
274 #endif
275
276 // ---------------------------------------------------------------------
277
278 /*
279 * Event logging.
280 */
281
282 /*
283 * Event log entry types. These must match up with the declarations in
284 * java/android/android/util/EventLog.java.
285 */
286 typedef enum {
287 EVENT_TYPE_INT = 0,
288 EVENT_TYPE_LONG = 1,
289 EVENT_TYPE_STRING = 2,
290 EVENT_TYPE_LIST = 3,
291 } AndroidEventLogType;
292
293
294 #define LOG_EVENT_INT(_tag, _value) { \
295 int intBuf = _value; \
296 (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
297 sizeof(intBuf)); \
298 }
299 #define LOG_EVENT_LONG(_tag, _value) { \
300 long long longBuf = _value; \
301 (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
302 sizeof(longBuf)); \
303 }
304 #define LOG_EVENT_STRING(_tag, _value) \
305 ((void) 0) /* not implemented -- must combine len with string */
306 /* TODO: something for LIST */
307
308 /*
309 * ===========================================================================
310 *
311 * The stuff in the rest of this file should not be used directly.
312 */
313
314 #define android_printLog(prio, tag, fmt...) \
315 __android_log_print(prio, tag, fmt)
316
317 #define android_vprintLog(prio, cond, tag, fmt...) \
318 __android_log_vprint(prio, tag, fmt)
319
320 #define android_printAssert(cond, tag, fmt...) \
321 __android_log_assert(cond, tag, fmt)
322
323 #define android_writeLog(prio, tag, text) \
324 __android_log_write(prio, tag, text)
325
326 #define android_bWriteLog(tag, payload, len) \
327 __android_log_bwrite(tag, payload, len)
328 #define android_btWriteLog(tag, type, payload, len) \
329 __android_log_btwrite(tag, type, payload, len)
330
331 // TODO: remove these prototypes and their users
332 #define android_testLog(prio, tag) (1)
333 #define android_writevLog(vec,num) do{}while(0)
334 #define android_write1Log(str,len) do{}while (0)
335 #define android_setMinPriority(tag, prio) do{}while(0)
336 //#define android_logToCallback(func) do{}while(0)
337 #define android_logToFile(tag, file) (0)
338 #define android_logToFd(tag, fd) (0)
339
340
341 #ifdef __cplusplus
342 }
343 #endif
344
345 #endif // _LIBS_CUTILS_LOG_H
+0
-78
include/cutils/logd.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _ANDROID_CUTILS_LOGD_H
17 #define _ANDROID_CUTILS_LOGD_H
18
19 #include <time.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdint.h>
23 #include <sys/types.h>
24 #ifdef HAVE_PTHREADS
25 #include <pthread.h>
26 #endif
27 #include <cutils/uio.h>
28 #include <stdarg.h>
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 /*
35 * Priority values, in ascending priority order.
36 */
37 typedef enum android_LogPriority {
38 ANDROID_LOG_UNKNOWN = 0,
39 ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
40 ANDROID_LOG_VERBOSE,
41 ANDROID_LOG_DEBUG,
42 ANDROID_LOG_INFO,
43 ANDROID_LOG_WARN,
44 ANDROID_LOG_ERROR,
45 ANDROID_LOG_FATAL,
46 ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
47 } android_LogPriority;
48
49 int __android_log_write(int prio, const char *tag, const char *text);
50
51 int __android_log_vprint(int prio, const char *tag,
52 const char *fmt, va_list ap);
53
54 int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
55 int __android_log_btwrite(int32_t tag, char type, const void *payload,
56 size_t len);
57
58 int __android_log_print(int prio, const char *tag, const char *fmt, ...)
59 #if defined(__GNUC__)
60 __attribute__ ((format(printf, 3, 4)))
61 #endif
62 ;
63
64
65 void __android_log_assert(const char *cond, const char *tag,
66 const char *fmt, ...)
67 #if defined(__GNUC__)
68 __attribute__ ((noreturn))
69 __attribute__ ((format(printf, 3, 4)))
70 #endif
71 ;
72
73 #ifdef __cplusplus
74 }
75 #endif
76
77 #endif /* _LOGD_H */
+0
-46
include/cutils/logger.h less more
0 /* utils/logger.h
1 **
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** This file is dual licensed. It may be redistributed and/or modified
5 ** under the terms of the Apache 2.0 License OR version 2 of the GNU
6 ** General Public License.
7 */
8
9 #ifndef _UTILS_LOGGER_H
10 #define _UTILS_LOGGER_H
11
12 #include <stdint.h>
13
14 struct logger_entry {
15 uint16_t len; /* length of the payload */
16 uint16_t __pad; /* no matter what, we get 2 bytes of padding */
17 int32_t pid; /* generating process's pid */
18 int32_t tid; /* generating process's tid */
19 int32_t sec; /* seconds since Epoch */
20 int32_t nsec; /* nanoseconds */
21 char msg[0]; /* the entry's payload */
22 };
23
24 #define LOGGER_LOG_MAIN "log/main"
25 #define LOGGER_LOG_RADIO "log/radio"
26 #define LOGGER_LOG_EVENTS "log/events"
27
28 #define LOGGER_ENTRY_MAX_LEN (4*1024)
29 #define LOGGER_ENTRY_MAX_PAYLOAD \
30 (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
31
32 #ifdef HAVE_IOCTL
33
34 #include <sys/ioctl.h>
35
36 #define __LOGGERIO 0xAE
37
38 #define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
39 #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
40 #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
41 #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
42
43 #endif // HAVE_IOCTL
44
45 #endif /* _UTILS_LOGGER_H */
+0
-156
include/cutils/logprint.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _LOGPRINT_H
17 #define _LOGPRINT_H
18
19 #include <cutils/log.h>
20 #include <cutils/logger.h>
21 #include <cutils/event_tag_map.h>
22 #include <pthread.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 typedef enum {
29 FORMAT_OFF = 0,
30 FORMAT_BRIEF,
31 FORMAT_PROCESS,
32 FORMAT_TAG,
33 FORMAT_THREAD,
34 FORMAT_RAW,
35 FORMAT_TIME,
36 FORMAT_THREADTIME,
37 FORMAT_LONG,
38 } AndroidLogPrintFormat;
39
40 typedef struct AndroidLogFormat_t AndroidLogFormat;
41
42 typedef struct AndroidLogEntry_t {
43 time_t tv_sec;
44 long tv_nsec;
45 android_LogPriority priority;
46 pid_t pid;
47 pthread_t tid;
48 const char * tag;
49 size_t messageLen;
50 const char * message;
51 } AndroidLogEntry;
52
53 AndroidLogFormat *android_log_format_new();
54
55 void android_log_format_free(AndroidLogFormat *p_format);
56
57 void android_log_setPrintFormat(AndroidLogFormat *p_format,
58 AndroidLogPrintFormat format);
59
60 /**
61 * Returns FORMAT_OFF on invalid string
62 */
63 AndroidLogPrintFormat android_log_formatFromString(const char *s);
64
65 /**
66 * filterExpression: a single filter expression
67 * eg "AT:d"
68 *
69 * returns 0 on success and -1 on invalid expression
70 *
71 * Assumes single threaded execution
72 *
73 */
74
75 int android_log_addFilterRule(AndroidLogFormat *p_format,
76 const char *filterExpression);
77
78
79 /**
80 * filterString: a whitespace-separated set of filter expressions
81 * eg "AT:d *:i"
82 *
83 * returns 0 on success and -1 on invalid expression
84 *
85 * Assumes single threaded execution
86 *
87 */
88
89 int android_log_addFilterString(AndroidLogFormat *p_format,
90 const char *filterString);
91
92
93 /**
94 * returns 1 if this log line should be printed based on its priority
95 * and tag, and 0 if it should not
96 */
97 int android_log_shouldPrintLine (
98 AndroidLogFormat *p_format, const char *tag, android_LogPriority pri);
99
100
101 /**
102 * Splits a wire-format buffer into an AndroidLogEntry
103 * entry allocated by caller. Pointers will point directly into buf
104 *
105 * Returns 0 on success and -1 on invalid wire format (entry will be
106 * in unspecified state)
107 */
108 int android_log_processLogBuffer(struct logger_entry *buf,
109 AndroidLogEntry *entry);
110
111 /**
112 * Like android_log_processLogBuffer, but for binary logs.
113 *
114 * If "map" is non-NULL, it will be used to convert the log tag number
115 * into a string.
116 */
117 int android_log_processBinaryLogBuffer(struct logger_entry *buf,
118 AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
119 int messageBufLen);
120
121
122 /**
123 * Formats a log message into a buffer
124 *
125 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
126 * If return value != defaultBuffer, caller must call free()
127 * Returns NULL on malloc error
128 */
129
130 char *android_log_formatLogLine (
131 AndroidLogFormat *p_format,
132 char *defaultBuffer,
133 size_t defaultBufferSize,
134 const AndroidLogEntry *p_line,
135 size_t *p_outLength);
136
137
138 /**
139 * Either print or do not print log line, based on filter
140 *
141 * Assumes single threaded execution
142 *
143 */
144 int android_log_filterAndPrintLogLine(
145 AndroidLogFormat *p_format,
146 int fd,
147 const AndroidLogEntry *entry);
148
149
150 #ifdef __cplusplus
151 }
152 #endif
153
154
155 #endif /*_LOGPRINT_H*/
+0
-42
include/cutils/memory.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ANDROID_CUTILS_MEMORY_H
17 #define ANDROID_CUTILS_MEMORY_H
18
19 #include <stdint.h>
20 #include <sys/types.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 /* size is given in bytes and must be multiple of 2 */
27 void android_memset16(uint16_t* dst, uint16_t value, size_t size);
28
29 /* size is given in bytes and must be multiple of 4 */
30 void android_memset32(uint32_t* dst, uint32_t value, size_t size);
31
32 #if !HAVE_STRLCPY
33 /* Declaration of strlcpy() for platforms that don't already have it. */
34 size_t strlcpy(char *dst, const char *src, size_t size);
35 #endif
36
37 #ifdef __cplusplus
38 } // extern "C"
39 #endif
40
41 #endif // ANDROID_CUTILS_MEMORY_H
+0
-48
include/cutils/misc.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_MISC_H
17 #define __CUTILS_MISC_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 /* Load an entire file into a malloc'd chunk of memory
24 * that is length_of_file + 1 (null terminator). If
25 * sz is non-zero, return the size of the file via sz.
26 * Returns 0 on failure.
27 */
28 extern void *load_file(const char *fn, unsigned *sz);
29
30 /* Connects your process to the system debugger daemon
31 * so that on a crash it may be logged or interactively
32 * debugged (depending on system settings).
33 */
34 extern void debuggerd_connect(void);
35
36
37 /* This is the range of UIDs (and GIDs) that are reserved
38 * for assigning to applications.
39 */
40 #define FIRST_APPLICATION_UID 10000
41 #define LAST_APPLICATION_UID 99999
42
43 #ifdef __cplusplus
44 }
45 #endif
46
47 #endif /* __CUTILS_MISC_H */
+0
-124
include/cutils/mq.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * IPC messaging library.
18 */
19
20 #ifndef __MQ_H
21 #define __MQ_H
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 /** A message. */
28 typedef struct MqMessage MqMessage;
29
30 /** A destination to which messages can be sent. */
31 typedef struct MqDestination MqDestination;
32
33 /* Array of bytes. */
34 typedef struct MqBytes MqBytes;
35
36 /**
37 * Hears messages.
38 *
39 * @param destination to which the message was sent
40 * @param message the message to hear
41 */
42 typedef void MqMessageListener(MqDestination* destination, MqMessage* message);
43
44 /**
45 * Hears a destination close.
46 *
47 * @param destination that closed
48 */
49 typedef void MqCloseListener(MqDestination* destination);
50
51 /** Message functions. */
52
53 /**
54 * Creates a new Message.
55 *
56 * @param header as defined by user
57 * @param body as defined by user
58 * @param replyTo destination to which replies should be sent, NULL if none
59 */
60 MqMessage* mqCreateMessage(MqBytes header, MqBytes body,
61 MqDestination* replyTo);
62
63 /** Sends a message to a destination. */
64 void mqSendMessage(MqMessage* message, MqDestination* destination);
65
66 /** Destination functions. */
67
68 /**
69 * Creates a new destination. Acquires a reference implicitly.
70 *
71 * @param messageListener function to call when a message is recieved
72 * @param closeListener function to call when the destination closes
73 * @param userData user-specific data to associate with the destination.
74 * Retrieve using mqGetDestinationUserData().
75 */
76 MqDestination* mqCreateDestination(MqMessageListener* messageListener,
77 MqCloseListener* closeListener, void* userData);
78
79 /**
80 * Gets user data which was associated with the given destination at
81 * construction time.
82 *
83 * It is only valid to call this function in the same process that the
84 * given destination was created in.
85 * This function returns a null pointer if you call it on a destination
86 * created in a remote process.
87 */
88 void* mqGetUserData(MqDestination* destination);
89
90 /**
91 * Returns 1 if the destination was created in this process, or 0 if
92 * the destination was created in a different process, in which case you have
93 * a remote stub.
94 */
95 int mqIsDestinationLocal(MqDestination* destination);
96
97 /**
98 * Increments the destination's reference count.
99 */
100 void mqKeepDestination(MqDesintation* destination);
101
102 /**
103 * Decrements the destination's reference count.
104 */
105 void mqFreeDestination(MqDestination* desintation);
106
107 /** Registry API. */
108
109 /**
110 * Gets the destination bound to a name.
111 */
112 MqDestination* mqGetDestination(char* name);
113
114 /**
115 * Binds a destination to a name.
116 */
117 void mqPutDestination(char* name, MqDestination* desintation);
118
119 #ifdef __cplusplus
120 }
121 #endif
122
123 #endif /* __MQ_H */
+0
-117
include/cutils/mspace.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* A wrapper file for dlmalloc.h that defines prototypes for the
17 * mspace_*() functions, which provide an interface for creating
18 * multiple heaps.
19 */
20
21 #ifndef MSPACE_H_
22 #define MSPACE_H_
23
24 /* It's a pain getting the mallinfo stuff to work
25 * with Linux, OSX, and klibc, so just turn it off
26 * for now.
27 * TODO: make mallinfo work
28 */
29 #define NO_MALLINFO 1
30
31 /* Allow setting the maximum heap footprint.
32 */
33 #define USE_MAX_ALLOWED_FOOTPRINT 1
34
35 #define USE_CONTIGUOUS_MSPACES 1
36 #if USE_CONTIGUOUS_MSPACES
37 #define HAVE_MMAP 0
38 #define HAVE_MORECORE 1
39 #define MORECORE_CONTIGUOUS 0
40 #endif
41
42 #define MSPACES 1
43 #define ONLY_MSPACES 1
44 #include "../../../../bionic/libc/bionic/dlmalloc.h"
45
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49
50 /*
51 mspace_usable_size(void* p);
52
53 Returns the number of bytes you can actually use in
54 an allocated chunk, which may be more than you requested (although
55 often not) due to alignment and minimum size constraints.
56 You can use this many bytes without worrying about
57 overwriting other allocated objects. This is not a particularly great
58 programming practice. mspace_usable_size can be more useful in
59 debugging and assertions, for example:
60
61 p = mspace_malloc(msp, n);
62 assert(mspace_usable_size(msp, p) >= 256);
63 */
64 size_t mspace_usable_size(mspace, const void*);
65
66 #if USE_CONTIGUOUS_MSPACES
67 /*
68 Similar to create_mspace(), but the underlying memory is
69 guaranteed to be contiguous. No more than max_capacity
70 bytes is ever allocated to the mspace.
71 */
72 mspace create_contiguous_mspace(size_t starting_capacity, size_t max_capacity,
73 int locked);
74
75 /*
76 Identical to create_contiguous_mspace, but labels the mapping 'mspace/name'
77 instead of 'mspace'
78 */
79 mspace create_contiguous_mspace_with_name(size_t starting_capacity,
80 size_t max_capacity, int locked, const char *name);
81
82 size_t destroy_contiguous_mspace(mspace msp);
83 #endif
84
85 /*
86 Call the handler for each block in the specified mspace.
87 chunkptr and chunklen refer to the heap-level chunk including
88 the chunk overhead, and userptr and userlen refer to the
89 user-usable part of the chunk. If the chunk is free, userptr
90 will be NULL and userlen will be 0. userlen is not guaranteed
91 to be the same value passed into malloc() for a given chunk;
92 it is >= the requested size.
93 */
94 void mspace_walk_heap(mspace msp,
95 void(*handler)(const void *chunkptr, size_t chunklen,
96 const void *userptr, size_t userlen, void *arg), void *harg);
97
98 /*
99 mspace_walk_free_pages(handler, harg)
100
101 Calls the provided handler on each free region in the specified
102 mspace. The memory between start and end are guaranteed not to
103 contain any important data, so the handler is free to alter the
104 contents in any way. This can be used to advise the OS that large
105 free regions may be swapped out.
106
107 The value in harg will be passed to each call of the handler.
108 */
109 void mspace_walk_free_pages(mspace msp,
110 void(*handler)(void *start, void *end, void *arg), void *harg);
111
112 #ifdef __cplusplus
113 }; /* end of extern "C" */
114 #endif
115
116 #endif /* MSPACE_H_ */
+0
-28
include/cutils/native_handle.h less more
0 /*
1 * Copyright (C) 2009 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef NATIVE_HANDLE_H_
17 #define NATIVE_HANDLE_H_
18
19 typedef struct
20 {
21 int version; /* sizeof(native_handle) */
22 int numFds; /* number of file-descriptors at &data[0] */
23 int numInts; /* number of ints at &data[numFds] */
24 int data[0]; /* numFds + numInts ints */
25 } native_handle;
26
27 #endif /* NATIVE_HANDLE_H_ */
+0
-42
include/cutils/process_name.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Gives the current process a name.
18 */
19
20 #ifndef __PROCESS_NAME_H
21 #define __PROCESS_NAME_H
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 /**
28 * Sets the current process name.
29 *
30 * Warning: This leaks a string every time you call it. Use judiciously!
31 */
32 void set_process_name(const char* process_name);
33
34 /** Gets the current process name. */
35 const char* get_process_name(void);
36
37 #ifdef __cplusplus
38 }
39 #endif
40
41 #endif /* __PROCESS_NAME_H */
+0
-70
include/cutils/properties.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_PROPERTIES_H
17 #define __CUTILS_PROPERTIES_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 /* System properties are *small* name value pairs managed by the
24 ** property service. If your data doesn't fit in the provided
25 ** space it is not appropriate for a system property.
26 **
27 ** WARNING: system/bionic/include/sys/system_properties.h also defines
28 ** these, but with different names. (TODO: fix that)
29 */
30 #define PROPERTY_KEY_MAX 32
31 #define PROPERTY_VALUE_MAX 92
32
33 /* property_get: returns the length of the value which will never be
34 ** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
35 ** (the length does not include the terminating zero).
36 **
37 ** If the property read fails or returns an empty value, the default
38 ** value is used (if nonnull).
39 */
40 int property_get(const char *key, char *value, const char *default_value);
41
42 /* property_set: returns 0 on success, < 0 on failure
43 */
44 int property_set(const char *key, const char *value);
45
46 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
47
48
49 #ifdef HAVE_SYSTEM_PROPERTY_SERVER
50 /*
51 * We have an external property server instead of built-in libc support.
52 * Used by the simulator.
53 */
54 #define SYSTEM_PROPERTY_PIPE_NAME "/tmp/android-sysprop"
55
56 enum {
57 kSystemPropertyUnknown = 0,
58 kSystemPropertyGet,
59 kSystemPropertySet,
60 kSystemPropertyList
61 };
62 #endif /*HAVE_SYSTEM_PROPERTY_SERVER*/
63
64
65 #ifdef __cplusplus
66 }
67 #endif
68
69 #endif
+0
-43
include/cutils/record_stream.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * A simple utility for reading fixed records out of a stream fd
18 */
19
20 #ifndef _CUTILS_RECORD_STREAM_H
21 #define _CUTILS_RECORD_STREAM_H
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27
28 typedef struct RecordStream RecordStream;
29
30 extern RecordStream *record_stream_new(int fd, size_t maxRecordLen);
31 extern void record_stream_free(RecordStream *p_rs);
32
33 extern int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
34 size_t *p_outRecordLen);
35
36 #ifdef __cplusplus
37 }
38 #endif
39
40
41 #endif /*_CUTILS_RECORD_STREAM_H*/
42
+0
-130
include/cutils/selector.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Framework for multiplexing I/O. A selector manages a set of file
18 * descriptors and calls out to user-provided callback functions to read and
19 * write data and handle errors.
20 */
21
22 #ifndef __SELECTOR_H
23 #define __SELECTOR_H
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 #include <stdbool.h>
30
31 /**
32 * Manages SelectableFds and invokes their callbacks at appropriate times.
33 */
34 typedef struct Selector Selector;
35
36 /**
37 * A selectable descriptor. Contains callbacks which the selector can invoke
38 * before calling select(), when the descriptor is readable or writable, and
39 * when the descriptor contains out-of-band data. Simply set a callback to
40 * NULL if you're not interested in that particular event.
41 *
42 * A selectable descriptor can indicate that it needs to be removed from the
43 * selector by setting the 'remove' flag. The selector will remove the
44 * descriptor at a later time and invoke the onRemove() callback.
45 *
46 * SelectableFd fields should only be modified from the selector loop.
47 */
48 typedef struct SelectableFd SelectableFd;
49 struct SelectableFd {
50
51 /** The file descriptor itself. */
52 int fd;
53
54 /** Pointer to user-specific data. Can be NULL. */
55 void* data;
56
57 /**
58 * Set this flag when you no longer wish to be selected. The selector
59 * will invoke onRemove() when the descriptor is actually removed.
60 */
61 bool remove;
62
63 /**
64 * Invoked by the selector before calling select. You can set up other
65 * callbacks from here as necessary.
66 */
67 void (*beforeSelect)(SelectableFd* self);
68
69 /**
70 * Invoked by the selector when the descriptor has data available. Set to
71 * NULL to indicate that you're not interested in reading.
72 */
73 void (*onReadable)(SelectableFd* self);
74
75 /**
76 * Invoked by the selector when the descriptor can accept data. Set to
77 * NULL to indicate that you're not interested in writing.
78 */
79 void (*onWritable)(SelectableFd* self);
80
81 /**
82 * Invoked by the selector when out-of-band (OOB) data is available. Set to
83 * NULL to indicate that you're not interested in OOB data.
84 */
85 void (*onExcept)(SelectableFd* self);
86
87 /**
88 * Invoked by the selector after the descriptor is removed from the
89 * selector but before the selector frees the SelectableFd memory.
90 */
91 void (*onRemove)(SelectableFd* self);
92
93 /**
94 * The selector which selected this fd. Set by the selector itself.
95 */
96 Selector* selector;
97 };
98
99 /**
100 * Creates a new selector.
101 */
102 Selector* selectorCreate(void);
103
104 /**
105 * Creates a new selectable fd, adds it to the given selector and returns a
106 * pointer. Outside of 'selector' and 'fd', all fields are set to 0 or NULL
107 * by default.
108 *
109 * The selectable fd should only be modified from the selector loop thread.
110 */
111 SelectableFd* selectorAdd(Selector* selector, int fd);
112
113 /**
114 * Wakes up the selector even though no I/O events occurred. Use this
115 * to indicate that you're ready to write to a descriptor.
116 */
117 void selectorWakeUp(Selector* selector);
118
119 /**
120 * Loops continuously selecting file descriptors and firing events.
121 * Does not return.
122 */
123 void selectorLoop(Selector* selector);
124
125 #ifdef __cplusplus
126 }
127 #endif
128
129 #endif /* __SELECTOR_H */
+0
-100
include/cutils/sockets.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_SOCKETS_H
17 #define __CUTILS_SOCKETS_H
18
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #ifdef HAVE_WINSOCK
24 #include <winsock2.h>
25 typedef int socklen_t;
26 #elif HAVE_SYS_SOCKET_H
27 #include <sys/socket.h>
28 #endif
29
30 #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
31 #define ANDROID_SOCKET_DIR "/dev/socket"
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36
37 /*
38 * android_get_control_socket - simple helper function to get the file
39 * descriptor of our init-managed Unix domain socket. `name' is the name of the
40 * socket, as given in init.rc. Returns -1 on error.
41 *
42 * This is inline and not in libcutils proper because we want to use this in
43 * third-party daemons with minimal modification.
44 */
45 static inline int android_get_control_socket(const char *name)
46 {
47 char key[64] = ANDROID_SOCKET_ENV_PREFIX;
48 const char *val;
49 int fd;
50
51 /* build our environment variable, counting cycles like a wolf ... */
52 #if HAVE_STRLCPY
53 strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
54 name,
55 sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
56 #else /* for the host, which may lack the almightly strncpy ... */
57 strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
58 name,
59 sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
60 key[sizeof(key)-1] = '\0';
61 #endif
62
63 val = getenv(key);
64 if (!val)
65 return -1;
66
67 errno = 0;
68 fd = strtol(val, NULL, 10);
69 if (errno)
70 return -1;
71
72 return fd;
73 }
74
75 /*
76 * See also android.os.LocalSocketAddress.Namespace
77 */
78 // Linux "abstract" (non-filesystem) namespace
79 #define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
80 // Android "reserved" (/dev/socket) namespace
81 #define ANDROID_SOCKET_NAMESPACE_RESERVED 1
82 // Normal filesystem namespace
83 #define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
84
85 extern int socket_loopback_client(int port, int type);
86 extern int socket_network_client(const char *host, int port, int type);
87 extern int socket_loopback_server(int port, int type);
88 extern int socket_local_server(const char *name, int namespaceId, int type);
89 extern int socket_local_server_bind(int s, const char *name, int namespaceId);
90 extern int socket_local_client_connect(int fd,
91 const char *name, int namespaceId, int type);
92 extern int socket_local_client(const char *name, int namespaceId, int type);
93 extern int socket_inaddr_any_server(int port, int type);
94
95 #ifdef __cplusplus
96 }
97 #endif
98
99 #endif /* __CUTILS_SOCKETS_H */
+0
-146
include/cutils/threads.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _LIBS_CUTILS_THREADS_H
17 #define _LIBS_CUTILS_THREADS_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 /***********************************************************************/
24 /***********************************************************************/
25 /***** *****/
26 /***** local thread storage *****/
27 /***** *****/
28 /***********************************************************************/
29 /***********************************************************************/
30
31 #ifdef HAVE_PTHREADS
32
33 #include <pthread.h>
34
35 typedef struct {
36 pthread_mutex_t lock;
37 int has_tls;
38 pthread_key_t tls;
39
40 } thread_store_t;
41
42 #define THREAD_STORE_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
43
44 #elif defined HAVE_WIN32_THREADS
45
46 #include <windows.h>
47
48 typedef struct {
49 int lock_init;
50 int has_tls;
51 DWORD tls;
52 CRITICAL_SECTION lock;
53
54 } thread_store_t;
55
56 #define THREAD_STORE_INITIALIZER { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
57
58 #else
59 # error "no thread_store_t implementation for your platform !!"
60 #endif
61
62 typedef void (*thread_store_destruct_t)(void* value);
63
64 extern void* thread_store_get(thread_store_t* store);
65
66 extern void thread_store_set(thread_store_t* store,
67 void* value,
68 thread_store_destruct_t destroy);
69
70 /***********************************************************************/
71 /***********************************************************************/
72 /***** *****/
73 /***** mutexes *****/
74 /***** *****/
75 /***********************************************************************/
76 /***********************************************************************/
77
78 #ifdef HAVE_PTHREADS
79
80 typedef pthread_mutex_t mutex_t;
81
82 #define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
83
84 static __inline__ void mutex_lock(mutex_t* lock)
85 {
86 pthread_mutex_lock(lock);
87 }
88 static __inline__ void mutex_unlock(mutex_t* lock)
89 {
90 pthread_mutex_unlock(lock);
91 }
92 static __inline__ int mutex_init(mutex_t* lock)
93 {
94 return pthread_mutex_init(lock, NULL);
95 }
96 static __inline__ void mutex_destroy(mutex_t* lock)
97 {
98 pthread_mutex_destroy(lock);
99 }
100 #endif
101
102 #ifdef HAVE_WIN32_THREADS
103 typedef struct {
104 int init;
105 CRITICAL_SECTION lock[1];
106 } mutex_t;
107
108 #define MUTEX_INITIALIZER { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
109
110 static __inline__ void mutex_lock(mutex_t* lock)
111 {
112 if (!lock->init) {
113 lock->init = 1;
114 InitializeCriticalSection( lock->lock );
115 lock->init = 2;
116 } else while (lock->init != 2)
117 Sleep(10);
118
119 EnterCriticalSection(lock->lock);
120 }
121
122 static __inline__ void mutex_unlock(mutex_t* lock)
123 {
124 LeaveCriticalSection(lock->lock);
125 }
126 static __inline__ int mutex_init(mutex_t* lock)
127 {
128 InitializeCriticalSection(lock->lock);
129 lock->init = 2;
130 return 0;
131 }
132 static __inline__ void mutex_destroy(mutex_t* lock)
133 {
134 if (lock->init) {
135 lock->init = 0;
136 DeleteCriticalSection(lock->lock);
137 }
138 }
139 #endif
140
141 #ifdef __cplusplus
142 }
143 #endif
144
145 #endif /* _LIBS_CUTILS_THREADS_H */
+0
-47
include/cutils/tztime.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _CUTILS_TZTIME_H
17 #define _CUTILS_TZTIME_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 time_t mktime_tz(struct tm * const tmp, char const * tz);
24 void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
25
26 struct strftime_locale {
27 const char *mon[12]; /* short names */
28 const char *month[12]; /* long names */
29 const char *wday[7]; /* short names */
30 const char *weekday[7]; /* long names */
31 const char *X_fmt;
32 const char *x_fmt;
33 const char *c_fmt;
34 const char *am;
35 const char *pm;
36 const char *date_fmt;
37 };
38
39 size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
40
41 #ifdef __cplusplus
42 }
43 #endif
44
45 #endif /* __CUTILS_TZTIME_H */
46
+0
-48
include/cutils/uio.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 //
17 // implementation of sys/uio.h for platforms that don't have it (Win32)
18 //
19 #ifndef _LIBS_CUTILS_UIO_H
20 #define _LIBS_CUTILS_UIO_H
21
22 #ifdef HAVE_SYS_UIO_H
23 #include <sys/uio.h>
24 #else
25
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29
30 #include <stddef.h>
31
32 struct iovec {
33 const void* iov_base;
34 size_t iov_len;
35 };
36
37 extern int readv( int fd, struct iovec* vecs, int count );
38 extern int writev( int fd, const struct iovec* vecs, int count );
39
40 #ifdef __cplusplus
41 }
42 #endif
43
44 #endif /* !HAVE_SYS_UIO_H */
45
46 #endif /* _LIBS_UTILS_UIO_H */
47
+0
-32
include/cutils/zygote.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __CUTILS_ZYGOTE_H
17 #define __CUTILS_ZYGOTE_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
24 int zygote_run(int argc, const char **argv);
25 int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int));
26
27 #ifdef __cplusplus
28 }
29 #endif
30
31 #endif /* __CUTILS_ZYGOTE_H */
+0
-56
include/mincrypt/rsa.h less more
0 /* rsa.h
1 **
2 ** Copyright 2008, The Android Open Source Project
3 **
4 ** Redistribution and use in source and binary forms, with or without
5 ** modification, are permitted provided that the following conditions are met:
6 ** * Redistributions of source code must retain the above copyright
7 ** notice, this list of conditions and the following disclaimer.
8 ** * Redistributions in binary form must reproduce the above copyright
9 ** notice, this list of conditions and the following disclaimer in the
10 ** documentation and/or other materials provided with the distribution.
11 ** * Neither the name of Google Inc. nor the names of its contributors may
12 ** be used to endorse or promote products derived from this software
13 ** without specific prior written permission.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
16 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #ifndef _EMBEDDED_RSA_H_
28 #define _EMBEDDED_RSA_H_
29
30 #include <inttypes.h>
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 #define RSANUMBYTES 256 /* 2048 bit key length */
37 #define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
38
39 typedef struct RSAPublicKey {
40 int len; /* Length of n[] in number of uint32_t */
41 uint32_t n0inv; /* -1 / n[0] mod 2^32 */
42 uint32_t n[RSANUMWORDS]; /* modulus as little endian array */
43 uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
44 } RSAPublicKey;
45
46 int RSA_verify(const RSAPublicKey *key,
47 const uint8_t* signature,
48 const int len,
49 const uint8_t* sha);
50
51 #ifdef __cplusplus
52 }
53 #endif
54
55 #endif
+0
-56
include/mincrypt/sha.h less more
0 /* sha.h
1 **
2 ** Copyright 2008, The Android Open Source Project
3 **
4 ** Redistribution and use in source and binary forms, with or without
5 ** modification, are permitted provided that the following conditions are met:
6 ** * Redistributions of source code must retain the above copyright
7 ** notice, this list of conditions and the following disclaimer.
8 ** * Redistributions in binary form must reproduce the above copyright
9 ** notice, this list of conditions and the following disclaimer in the
10 ** documentation and/or other materials provided with the distribution.
11 ** * Neither the name of Google Inc. nor the names of its contributors may
12 ** be used to endorse or promote products derived from this software
13 ** without specific prior written permission.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
16 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #ifndef _EMBEDDED_SHA_H_
28 #define _EMBEDDED_SHA_H_
29
30 #include <inttypes.h>
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 typedef struct SHA_CTX {
37 uint64_t count;
38 uint8_t buf[64];
39 uint32_t state[5];
40 } SHA_CTX;
41
42 void SHA_init(SHA_CTX *ctx);
43 void SHA_update(SHA_CTX *ctx, const void* data, int len);
44 const uint8_t* SHA_final(SHA_CTX *ctx);
45
46 /* Convenience method. Returns digest parameter value. */
47 const uint8_t* SHA(const void *data, int len, uint8_t *digest);
48
49 #define SHA_DIGEST_SIZE 20
50
51 #ifdef __cplusplus
52 }
53 #endif
54
55 #endif
+0
-134
include/pixelflinger/format.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ANDROID_PIXELFLINGER_FORMAT_H
17 #define ANDROID_PIXELFLINGER_FORMAT_H
18
19 #include <stdint.h>
20 #include <sys/types.h>
21
22 enum GGLPixelFormat {
23 // these constants need to match those
24 // in graphics/PixelFormat.java, ui/PixelFormat.h, BlitHardware.h
25 GGL_PIXEL_FORMAT_UNKNOWN = 0,
26 GGL_PIXEL_FORMAT_NONE = 0,
27
28 GGL_PIXEL_FORMAT_RGBA_8888 = 1, // 4x8-bit ARGB
29 GGL_PIXEL_FORMAT_RGBX_8888 = 2, // 3x8-bit RGB stored in 32-bit chunks
30 GGL_PIXEL_FORMAT_RGB_888 = 3, // 3x8-bit RGB
31 GGL_PIXEL_FORMAT_RGB_565 = 4, // 16-bit RGB
32 GGL_PIXEL_FORMAT_BGRA_8888 = 5, // 4x8-bit BGRA
33 GGL_PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit RGBA
34 GGL_PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit RGBA
35
36 GGL_PIXEL_FORMAT_A_8 = 8, // 8-bit A
37 GGL_PIXEL_FORMAT_L_8 = 9, // 8-bit L (R=G=B = L)
38 GGL_PIXEL_FORMAT_LA_88 = 0xA, // 16-bit LA
39 GGL_PIXEL_FORMAT_RGB_332 = 0xB, // 8-bit RGB (non paletted)
40
41 // YCbCr formats (SP=semi-planar, P=planar)
42 GGL_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
43 GGL_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
44 GGL_PIXEL_FORMAT_YCbCr_422_P = 0x12,
45 GGL_PIXEL_FORMAT_YCbCr_420_P = 0x13,
46 GGL_PIXEL_FORMAT_YCbCr_422_I = 0x14,
47 GGL_PIXEL_FORMAT_YCbCr_420_I = 0x15,
48
49 // reserved/special formats
50 GGL_PIXEL_FORMAT_Z_16 = 0x18,
51 GGL_PIXEL_FORMAT_S_8 = 0x19,
52 GGL_PIXEL_FORMAT_SZ_24 = 0x1A,
53 GGL_PIXEL_FORMAT_SZ_8 = 0x1B,
54 };
55
56 enum GGLFormatComponents {
57 GGL_STENCIL_INDEX = 0x1901,
58 GGL_DEPTH_COMPONENT = 0x1902,
59 GGL_ALPHA = 0x1906,
60 GGL_RGB = 0x1907,
61 GGL_RGBA = 0x1908,
62 GGL_LUMINANCE = 0x1909,
63 GGL_LUMINANCE_ALPHA = 0x190A,
64 GGL_Y_CB_CR_SP = 0x8000,
65 GGL_Y_CB_CR = GGL_Y_CB_CR_SP,
66 GGL_Y_CB_CR_P = 0x8001,
67 GGL_Y_CB_CR_I = 0x8002,
68 };
69
70 enum GGLFormatComponentIndex {
71 GGL_INDEX_ALPHA = 0,
72 GGL_INDEX_RED = 1,
73 GGL_INDEX_GREEN = 2,
74 GGL_INDEX_BLUE = 3,
75 GGL_INDEX_STENCIL = 0,
76 GGL_INDEX_DEPTH = 1,
77 GGL_INDEX_Y = 0,
78 GGL_INDEX_CB = 1,
79 GGL_INDEX_CR = 2,
80 };
81
82 typedef struct {
83 #ifdef __cplusplus
84 enum {
85 ALPHA = GGL_INDEX_ALPHA,
86 RED = GGL_INDEX_RED,
87 GREEN = GGL_INDEX_GREEN,
88 BLUE = GGL_INDEX_BLUE,
89 STENCIL = GGL_INDEX_STENCIL,
90 DEPTH = GGL_INDEX_DEPTH,
91 LUMA = GGL_INDEX_Y,
92 CHROMAB = GGL_INDEX_CB,
93 CHROMAR = GGL_INDEX_CR,
94 };
95 inline uint32_t mask(int i) const {
96 return ((1<<(c[i].h-c[i].l))-1)<<c[i].l;
97 }
98 inline uint32_t bits(int i) const {
99 return c[i].h - c[i].l;
100 }
101 #endif
102 uint8_t size; // bytes per pixel
103 uint8_t bitsPerPixel;
104 union {
105 struct {
106 uint8_t ah; // alpha high bit position + 1
107 uint8_t al; // alpha low bit position
108 uint8_t rh; // red high bit position + 1
109 uint8_t rl; // red low bit position
110 uint8_t gh; // green high bit position + 1
111 uint8_t gl; // green low bit position
112 uint8_t bh; // blue high bit position + 1
113 uint8_t bl; // blue low bit position
114 };
115 struct {
116 uint8_t h;
117 uint8_t l;
118 } __attribute__((__packed__)) c[4];
119 } __attribute__((__packed__));
120 uint16_t components; // GGLFormatComponents
121 } GGLFormat;
122
123
124 #ifdef __cplusplus
125 extern "C" const GGLFormat* gglGetPixelFormatTable(size_t* numEntries = 0);
126 #else
127 const GGLFormat* gglGetPixelFormatTable(size_t* numEntries);
128 #endif
129
130
131 // ----------------------------------------------------------------------------
132
133 #endif // ANDROID_PIXELFLINGER_FORMAT_H
+0
-330
include/pixelflinger/pixelflinger.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ANDROID_PIXELFLINGER_H
17 #define ANDROID_PIXELFLINGER_H
18
19 #include <stdint.h>
20 #include <sys/types.h>
21
22 #include <pixelflinger/format.h>
23
24 // GGL types
25
26 typedef int8_t GGLbyte; // b
27 typedef int16_t GGLshort; // s
28 typedef int32_t GGLint; // i
29 typedef ssize_t GGLsizei; // i
30 typedef int32_t GGLfixed; // x
31 typedef int32_t GGLclampx; // x
32 typedef float GGLfloat; // f
33 typedef float GGLclampf; // f
34 typedef double GGLdouble; // d
35 typedef double GGLclampd; // d
36 typedef uint8_t GGLubyte; // ub
37 typedef uint8_t GGLboolean; // ub
38 typedef uint16_t GGLushort; // us
39 typedef uint32_t GGLuint; // ui
40 typedef unsigned int GGLenum; // ui
41 typedef unsigned int GGLbitfield; // ui
42 typedef void GGLvoid;
43 typedef int32_t GGLfixed32;
44 typedef int32_t GGLcolor;
45 typedef int32_t GGLcoord;
46
47 // ----------------------------------------------------------------------------
48
49 #define GGL_MAX_VIEWPORT_DIMS 4096
50 #define GGL_MAX_TEXTURE_SIZE 4096
51 #define GGL_MAX_ALIASED_POINT_SIZE 0x7FFFFFF
52 #define GGL_MAX_SMOOTH_POINT_SIZE 2048
53 #define GGL_MAX_SMOOTH_LINE_WIDTH 2048
54
55 // ----------------------------------------------------------------------------
56
57 // All these names are compatible with their OpenGL equivalents
58 // some of them are listed only for completeness
59 enum GGLNames {
60 GGL_FALSE = 0,
61 GGL_TRUE = 1,
62
63 // enable/disable
64 GGL_SCISSOR_TEST = 0x0C11,
65 GGL_TEXTURE_2D = 0x0DE1,
66 GGL_ALPHA_TEST = 0x0BC0,
67 GGL_BLEND = 0x0BE2,
68 GGL_COLOR_LOGIC_OP = 0x0BF2,
69 GGL_DITHER = 0x0BD0,
70 GGL_STENCIL_TEST = 0x0B90,
71 GGL_DEPTH_TEST = 0x0B71,
72 GGL_AA = 0x80000001,
73 GGL_W_LERP = 0x80000004,
74 GGL_POINT_SMOOTH_NICE = 0x80000005,
75
76 // buffers, pixel drawing/reading
77 GGL_COLOR = 0x1800,
78
79 // fog
80 GGL_FOG = 0x0B60,
81
82 // shade model
83 GGL_FLAT = 0x1D00,
84 GGL_SMOOTH = 0x1D01,
85
86 // Texture parameter name
87 GGL_TEXTURE_MIN_FILTER = 0x2801,
88 GGL_TEXTURE_MAG_FILTER = 0x2800,
89 GGL_TEXTURE_WRAP_S = 0x2802,
90 GGL_TEXTURE_WRAP_T = 0x2803,
91 GGL_TEXTURE_WRAP_R = 0x2804,
92
93 // Texture Filter
94 GGL_NEAREST = 0x2600,
95 GGL_LINEAR = 0x2601,
96 GGL_NEAREST_MIPMAP_NEAREST = 0x2700,
97 GGL_LINEAR_MIPMAP_NEAREST = 0x2701,
98 GGL_NEAREST_MIPMAP_LINEAR = 0x2702,
99 GGL_LINEAR_MIPMAP_LINEAR = 0x2703,
100
101 // Texture Wrap Mode
102 GGL_CLAMP = 0x2900,
103 GGL_REPEAT = 0x2901,
104 GGL_CLAMP_TO_EDGE = 0x812F,
105
106 // Texture Env Mode
107 GGL_REPLACE = 0x1E01,
108 GGL_MODULATE = 0x2100,
109 GGL_DECAL = 0x2101,
110 GGL_ADD = 0x0104,
111
112 // Texture Env Parameter
113 GGL_TEXTURE_ENV_MODE = 0x2200,
114 GGL_TEXTURE_ENV_COLOR = 0x2201,
115
116 // Texture Env Target
117 GGL_TEXTURE_ENV = 0x2300,
118
119 // Texture coord generation
120 GGL_TEXTURE_GEN_MODE = 0x2500,
121 GGL_S = 0x2000,
122 GGL_T = 0x2001,
123 GGL_R = 0x2002,
124 GGL_Q = 0x2003,
125 GGL_ONE_TO_ONE = 0x80000002,
126 GGL_AUTOMATIC = 0x80000003,
127
128 // AlphaFunction
129 GGL_NEVER = 0x0200,
130 GGL_LESS = 0x0201,
131 GGL_EQUAL = 0x0202,
132 GGL_LEQUAL = 0x0203,
133 GGL_GREATER = 0x0204,
134 GGL_NOTEQUAL = 0x0205,
135 GGL_GEQUAL = 0x0206,
136 GGL_ALWAYS = 0x0207,
137
138 // LogicOp
139 GGL_CLEAR = 0x1500, // 0
140 GGL_AND = 0x1501, // s & d
141 GGL_AND_REVERSE = 0x1502, // s & ~d
142 GGL_COPY = 0x1503, // s
143 GGL_AND_INVERTED = 0x1504, // ~s & d
144 GGL_NOOP = 0x1505, // d
145 GGL_XOR = 0x1506, // s ^ d
146 GGL_OR = 0x1507, // s | d
147 GGL_NOR = 0x1508, // ~(s | d)
148 GGL_EQUIV = 0x1509, // ~(s ^ d)
149 GGL_INVERT = 0x150A, // ~d
150 GGL_OR_REVERSE = 0x150B, // s | ~d
151 GGL_COPY_INVERTED = 0x150C, // ~s
152 GGL_OR_INVERTED = 0x150D, // ~s | d
153 GGL_NAND = 0x150E, // ~(s & d)
154 GGL_SET = 0x150F, // 1
155
156 // blending equation & function
157 GGL_ZERO = 0, // SD
158 GGL_ONE = 1, // SD
159 GGL_SRC_COLOR = 0x0300, // D
160 GGL_ONE_MINUS_SRC_COLOR = 0x0301, // D
161 GGL_SRC_ALPHA = 0x0302, // SD
162 GGL_ONE_MINUS_SRC_ALPHA = 0x0303, // SD
163 GGL_DST_ALPHA = 0x0304, // SD
164 GGL_ONE_MINUS_DST_ALPHA = 0x0305, // SD
165 GGL_DST_COLOR = 0x0306, // S
166 GGL_ONE_MINUS_DST_COLOR = 0x0307, // S
167 GGL_SRC_ALPHA_SATURATE = 0x0308, // S
168
169 // clear bits
170 GGL_DEPTH_BUFFER_BIT = 0x00000100,
171 GGL_STENCIL_BUFFER_BIT = 0x00000400,
172 GGL_COLOR_BUFFER_BIT = 0x00004000,
173
174 // errors
175 GGL_NO_ERROR = 0,
176 GGL_INVALID_ENUM = 0x0500,
177 GGL_INVALID_VALUE = 0x0501,
178 GGL_INVALID_OPERATION = 0x0502,
179 GGL_STACK_OVERFLOW = 0x0503,
180 GGL_STACK_UNDERFLOW = 0x0504,
181 GGL_OUT_OF_MEMORY = 0x0505
182 };
183
184 // ----------------------------------------------------------------------------
185
186 typedef struct {
187 GGLsizei version; // always set to sizeof(GGLSurface)
188 GGLuint width; // width in pixels
189 GGLuint height; // height in pixels
190 GGLint stride; // stride in pixels
191 GGLubyte* data; // pointer to the bits
192 GGLubyte format; // pixel format
193 GGLubyte rfu[3]; // must be zero
194 // these values are dependent on the used format
195 union {
196 GGLint compressedFormat;
197 GGLint vstride;
198 };
199 void* reserved;
200 } GGLSurface;
201
202
203 typedef struct {
204 // immediate rendering
205 void (*pointx)(void *con, const GGLcoord* v, GGLcoord r);
206 void (*linex)(void *con,
207 const GGLcoord* v0, const GGLcoord* v1, GGLcoord width);
208 void (*recti)(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
209 void (*trianglex)(void* c,
210 GGLcoord const* v0, GGLcoord const* v1, GGLcoord const* v2);
211
212 // scissor
213 void (*scissor)(void* c, GGLint x, GGLint y, GGLsizei width, GGLsizei height);
214
215 // Set the textures and color buffers
216 void (*activeTexture)(void* c, GGLuint tmu);
217 void (*bindTexture)(void* c, const GGLSurface* surface);
218 void (*colorBuffer)(void* c, const GGLSurface* surface);
219 void (*readBuffer)(void* c, const GGLSurface* surface);
220 void (*depthBuffer)(void* c, const GGLSurface* surface);
221 void (*bindTextureLod)(void* c, GGLuint tmu, const GGLSurface* surface);
222
223 // enable/disable features
224 void (*enable)(void* c, GGLenum name);
225 void (*disable)(void* c, GGLenum name);
226 void (*enableDisable)(void* c, GGLenum name, GGLboolean en);
227
228 // specify the fragment's color
229 void (*shadeModel)(void* c, GGLenum mode);
230 void (*color4xv)(void* c, const GGLclampx* color);
231 // specify color iterators (16.16)
232 void (*colorGrad12xv)(void* c, const GGLcolor* grad);
233
234 // specify Z coordinate iterators (0.32)
235 void (*zGrad3xv)(void* c, const GGLfixed32* grad);
236
237 // specify W coordinate iterators (16.16)
238 void (*wGrad3xv)(void* c, const GGLfixed* grad);
239
240 // specify fog iterator & color (16.16)
241 void (*fogGrad3xv)(void* c, const GGLfixed* grad);
242 void (*fogColor3xv)(void* c, const GGLclampx* color);
243
244 // specify blending parameters
245 void (*blendFunc)(void* c, GGLenum src, GGLenum dst);
246 void (*blendFuncSeparate)(void* c, GGLenum src, GGLenum dst,
247 GGLenum srcAlpha, GGLenum dstAplha);
248
249 // texture environnement (REPLACE / MODULATE / DECAL / BLEND)
250 void (*texEnvi)(void* c, GGLenum target,
251 GGLenum pname,
252 GGLint param);
253
254 void (*texEnvxv)(void* c, GGLenum target,
255 GGLenum pname, const GGLfixed* params);
256
257 // texture parameters (Wrapping, filter)
258 void (*texParameteri)(void* c, GGLenum target,
259 GGLenum pname,
260 GGLint param);
261
262 // texture iterators (16.16)
263 void (*texCoord2i)(void* c, GGLint s, GGLint t);
264 void (*texCoord2x)(void* c, GGLfixed s, GGLfixed t);
265
266 // s, dsdx, dsdy, scale, t, dtdx, dtdy, tscale
267 // This api uses block floating-point for S and T texture coordinates.
268 // All values are given in 16.16, scaled by 'scale'. In other words,
269 // set scale to 0, for 16.16 values.
270 void (*texCoordGradScale8xv)(void* c, GGLint tmu, const int32_t* grad8);
271
272 void (*texGeni)(void* c, GGLenum coord, GGLenum pname, GGLint param);
273
274 // masking
275 void (*colorMask)(void* c, GGLboolean red,
276 GGLboolean green,
277 GGLboolean blue,
278 GGLboolean alpha);
279
280 void (*depthMask)(void* c, GGLboolean flag);
281
282 void (*stencilMask)(void* c, GGLuint mask);
283
284 // alpha func
285 void (*alphaFuncx)(void* c, GGLenum func, GGLclampx ref);
286
287 // depth func
288 void (*depthFunc)(void* c, GGLenum func);
289
290 // logic op
291 void (*logicOp)(void* c, GGLenum opcode);
292
293 // clear
294 void (*clear)(void* c, GGLbitfield mask);
295 void (*clearColorx)(void* c,
296 GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);
297 void (*clearDepthx)(void* c, GGLclampx depth);
298 void (*clearStencil)(void* c, GGLint s);
299
300 // framebuffer operations
301 void (*copyPixels)(void* c, GGLint x, GGLint y,
302 GGLsizei width, GGLsizei height, GGLenum type);
303 void (*rasterPos2x)(void* c, GGLfixed x, GGLfixed y);
304 void (*rasterPos2i)(void* c, GGLint x, GGLint y);
305 } GGLContext;
306
307 // ----------------------------------------------------------------------------
308
309 #ifdef __cplusplus
310 extern "C" {
311 #endif
312
313 // construct / destroy the context
314 ssize_t gglInit(GGLContext** context);
315 ssize_t gglUninit(GGLContext* context);
316
317 GGLint gglBitBlti(
318 GGLContext* c,
319 int tmu,
320 GGLint crop[4],
321 GGLint where[4]);
322
323 #ifdef __cplusplus
324 };
325 #endif
326
327 // ----------------------------------------------------------------------------
328
329 #endif // ANDROID_PIXELFLINGER_H
+0
-211
include/private/android_filesystem_config.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* This file is used to define the properties of the filesystem
17 ** images generated by build tools (mkbootfs and mkyaffs2image) and
18 ** by the device side of adb.
19 */
20
21 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
22 #define _ANDROID_FILESYSTEM_CONFIG_H_
23
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 /* This is the master Users and Groups config for the platform.
29 ** DO NOT EVER RENUMBER.
30 */
31
32 #define AID_ROOT 0 /* traditional unix root user */
33
34 #define AID_SYSTEM 1000 /* system server */
35
36 #define AID_RADIO 1001 /* telephony subsystem, RIL */
37 #define AID_BLUETOOTH 1002 /* bluetooth subsystem */
38 #define AID_GRAPHICS 1003 /* graphics devices */
39 #define AID_INPUT 1004 /* input devices */
40 #define AID_AUDIO 1005 /* audio devices */
41 #define AID_CAMERA 1006 /* camera devices */
42 #define AID_LOG 1007 /* log devices */
43 #define AID_COMPASS 1008 /* compass device */
44 #define AID_MOUNT 1009 /* mountd socket */
45 #define AID_WIFI 1010 /* wifi subsystem */
46 #define AID_ADB 1011 /* android debug bridge (adbd) */
47 #define AID_INSTALL 1012 /* group for installing packages */
48 #define AID_MEDIA 1013 /* mediaserver process */
49 #define AID_DHCP 1014 /* dhcp client */
50
51 #define AID_SHELL 2000 /* adb and debug shell user */
52 #define AID_CACHE 2001 /* cache access */
53 #define AID_DIAG 2002 /* access to diagnostic resources */
54
55 /* The 3000 series are intended for use as supplemental group id's only.
56 * They indicate special Android capabilities that the kernel is aware of. */
57 #define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
58 #define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
59 #define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
60 #define AID_NET_RAW 3004 /* can create raw INET sockets */
61
62 #define AID_MISC 9998 /* access to misc storage */
63 #define AID_NOBODY 9999
64
65 #define AID_APP 10000 /* first app user */
66
67 #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
68 struct android_id_info {
69 const char *name;
70 unsigned aid;
71 };
72
73 static struct android_id_info android_ids[] = {
74 { "root", AID_ROOT, },
75 { "system", AID_SYSTEM, },
76 { "radio", AID_RADIO, },
77 { "bluetooth", AID_BLUETOOTH, },
78 { "graphics", AID_GRAPHICS, },
79 { "input", AID_INPUT, },
80 { "audio", AID_AUDIO, },
81 { "camera", AID_CAMERA, },
82 { "log", AID_LOG, },
83 { "compass", AID_COMPASS, },
84 { "mount", AID_MOUNT, },
85 { "wifi", AID_WIFI, },
86 { "dhcp", AID_DHCP, },
87 { "adb", AID_ADB, },
88 { "install", AID_INSTALL, },
89 { "media", AID_MEDIA, },
90 { "shell", AID_SHELL, },
91 { "cache", AID_CACHE, },
92 { "diag", AID_DIAG, },
93 { "net_bt_admin", AID_NET_BT_ADMIN, },
94 { "net_bt", AID_NET_BT, },
95 { "inet", AID_INET, },
96 { "net_raw", AID_NET_RAW, },
97 { "misc", AID_MISC, },
98 { "nobody", AID_NOBODY, },
99 };
100
101 #define android_id_count \
102 (sizeof(android_ids) / sizeof(android_ids[0]))
103
104 struct fs_path_config {
105 unsigned mode;
106 unsigned uid;
107 unsigned gid;
108 const char *prefix;
109 };
110
111 /* Rules for directories.
112 ** These rules are applied based on "first match", so they
113 ** should start with the most specific path and work their
114 ** way up to the root.
115 */
116
117 static struct fs_path_config android_dirs[] = {
118 { 00770, AID_SYSTEM, AID_CACHE, "cache" },
119 { 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },
120 { 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },
121 { 00771, AID_SYSTEM, AID_SYSTEM, "data/dalvik-cache" },
122 { 00771, AID_SYSTEM, AID_SYSTEM, "data/data" },
123 { 00771, AID_SHELL, AID_SHELL, "data/local/tmp" },
124 { 00771, AID_SHELL, AID_SHELL, "data/local" },
125 { 01771, AID_SYSTEM, AID_MISC, "data/misc" },
126 { 00770, AID_DHCP, AID_DHCP, "data/misc/dhcp" },
127 { 00771, AID_SYSTEM, AID_SYSTEM, "data" },
128 { 00750, AID_ROOT, AID_SHELL, "sbin" },
129 { 00755, AID_ROOT, AID_SHELL, "system/bin" },
130 { 00755, AID_ROOT, AID_SHELL, "system/xbin" },
131 { 00777, AID_ROOT, AID_ROOT, "system/etc/ppp" }, /* REMOVE */
132 { 00777, AID_ROOT, AID_ROOT, "sdcard" },
133 { 00755, AID_ROOT, AID_ROOT, 0 },
134 };
135
136 /* Rules for files.
137 ** These rules are applied based on "first match", so they
138 ** should start with the most specific path and work their
139 ** way up to the root. Prefixes ending in * denotes wildcard
140 ** and will allow partial matches.
141 */
142 static struct fs_path_config android_files[] = {
143 { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/ip-up" },
144 { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/ip-down" },
145 { 00440, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.rc" },
146 { 00550, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.sh" },
147 { 00440, AID_ROOT, AID_SHELL, "system/etc/init.trout.rc" },
148 { 00550, AID_ROOT, AID_SHELL, "system/etc/init.ril" },
149 { 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },
150 { 00550, AID_ROOT, AID_SHELL, "system/etc/init.gprs-pppd" },
151 { 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },
152 { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
153 { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/hcid.conf" },
154 { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" },
155 { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" },
156 { 00440, AID_RADIO, AID_AUDIO, "/system/etc/AudioPara4.csv" },
157 { 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" },
158 { 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" },
159 { 00644, AID_APP, AID_APP, "data/data/*" },
160 /* the following two files are INTENTIONALLY set-gid and not set-uid.
161 * Do not change. */
162 { 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" },
163 { 02755, AID_ROOT, AID_INET, "system/bin/netcfg" },
164 /* the following four files are INTENTIONALLY set-uid, but they
165 * are NOT included on user builds. */
166 { 06755, AID_ROOT, AID_ROOT, "system/xbin/su" },
167 { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" },
168 { 06755, AID_ROOT, AID_ROOT, "system/xbin/procrank" },
169 { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" },
170 { 00755, AID_ROOT, AID_SHELL, "system/bin/*" },
171 { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" },
172 { 00750, AID_ROOT, AID_SHELL, "sbin/*" },
173 { 00755, AID_ROOT, AID_ROOT, "bin/*" },
174 { 00750, AID_ROOT, AID_SHELL, "init*" },
175 { 00644, AID_ROOT, AID_ROOT, 0 },
176 };
177
178 static inline void fs_config(const char *path, int dir,
179 unsigned *uid, unsigned *gid, unsigned *mode)
180 {
181 struct fs_path_config *pc;
182 int plen;
183
184 pc = dir ? android_dirs : android_files;
185 plen = strlen(path);
186 for(; pc->prefix; pc++){
187 int len = strlen(pc->prefix);
188 if (dir) {
189 if(plen < len) continue;
190 if(!strncmp(pc->prefix, path, len)) break;
191 continue;
192 }
193 /* If name ends in * then allow partial matches. */
194 if (pc->prefix[len -1] == '*') {
195 if(!strncmp(pc->prefix, path, len - 1)) break;
196 } else if (plen == len){
197 if(!strncmp(pc->prefix, path, len)) break;
198 }
199 }
200 *uid = pc->uid;
201 *gid = pc->gid;
202 *mode = (*mode & (~07777)) | pc->mode;
203
204 #if 0
205 fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
206 path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
207 #endif
208 }
209 #endif
210 #endif
+0
-544
include/private/pixelflinger/ggl_context.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ANDROID_GGL_CONTEXT_H
17 #define ANDROID_GGL_CONTEXT_H
18
19 #include <stdint.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <sys/types.h>
23
24 #include <utils/Endian.h>
25 #include <pixelflinger/pixelflinger.h>
26 #include <private/pixelflinger/ggl_fixed.h>
27
28 namespace android {
29
30 // ----------------------------------------------------------------------------
31
32 #if BYTE_ORDER == LITTLE_ENDIAN
33
34 inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) {
35 return v;
36 }
37 inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) {
38 return v;
39 }
40
41 #else
42
43 inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) {
44 return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
45 }
46 inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) {
47 return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
48 }
49
50 #endif
51
52 // ----------------------------------------------------------------------------
53
54 const int GGL_DITHER_BITS = 6; // dither weights stored on 6 bits
55 const int GGL_DITHER_ORDER_SHIFT= 3;
56 const int GGL_DITHER_ORDER = (1<<GGL_DITHER_ORDER_SHIFT);
57 const int GGL_DITHER_SIZE = GGL_DITHER_ORDER * GGL_DITHER_ORDER;
58 const int GGL_DITHER_MASK = GGL_DITHER_ORDER-1;
59
60 // ----------------------------------------------------------------------------
61
62 const int GGL_SUBPIXEL_BITS = 4;
63
64 // TRI_FRACTION_BITS defines the number of bits we want to use
65 // for the sub-pixel coordinates during the edge stepping, the
66 // value shouldn't be more than 7, or bad things are going to
67 // happen when drawing large triangles (8 doesn't work because
68 // 32 bit muls will loose the sign bit)
69
70 #define TRI_FRACTION_BITS (GGL_SUBPIXEL_BITS)
71 #define TRI_ONE (1 << TRI_FRACTION_BITS)
72 #define TRI_HALF (1 << (TRI_FRACTION_BITS-1))
73 #define TRI_FROM_INT(x) ((x) << TRI_FRACTION_BITS)
74 #define TRI_FRAC(x) ((x) & (TRI_ONE-1))
75 #define TRI_FLOOR(x) ((x) & ~(TRI_ONE-1))
76 #define TRI_CEIL(x) (((x) + (TRI_ONE-1)) & ~(TRI_ONE-1))
77 #define TRI_ROUND(x) (((x) + TRI_HALF ) & ~(TRI_ONE-1))
78
79 #define TRI_ROUDNING (1 << (16 - TRI_FRACTION_BITS - 1))
80 #define TRI_FROM_FIXED(x) (((x)+TRI_ROUDNING) >> (16-TRI_FRACTION_BITS))
81
82 #define TRI_SNAP_NEXT_HALF(x) (TRI_CEIL((x)+TRI_HALF) - TRI_HALF)
83 #define TRI_SNAP_PREV_HALF(x) (TRI_CEIL((x)-TRI_HALF) - TRI_HALF)
84
85 // ----------------------------------------------------------------------------
86
87 const int GGL_COLOR_BITS = 24;
88
89 // To maintain 8-bits color chanels, with a maximum GGLSurface
90 // size of 4096 and GGL_SUBPIXEL_BITS=4, we need 8 + 12 + 4 = 24 bits
91 // for encoding the color iterators
92
93 inline GGLcolor gglFixedToIteratedColor(GGLfixed c) {
94 return (c << 8) - c;
95 }
96
97 // ----------------------------------------------------------------------------
98
99 template<bool> struct CTA;
100 template<> struct CTA<true> { };
101
102 #define GGL_CONTEXT(con, c) context_t *con = static_cast<context_t *>(c)
103 #define GGL_OFFSETOF(field) int(&(((context_t*)0)->field))
104 #define GGL_INIT_PROC(p, f) p.f = ggl_ ## f;
105 #define GGL_BETWEEN(x, L, H) (uint32_t((x)-(L)) <= ((H)-(L)))
106
107 #define ggl_likely(x) __builtin_expect(!!(x), 1)
108 #define ggl_unlikely(x) __builtin_expect(!!(x), 0)
109
110 const int GGL_TEXTURE_UNIT_COUNT = 2;
111 const int GGL_TMU_STATE = 0x00000001;
112 const int GGL_CB_STATE = 0x00000002;
113 const int GGL_PIXEL_PIPELINE_STATE = 0x00000004;
114
115 // ----------------------------------------------------------------------------
116
117 #define GGL_RESERVE_NEEDS(name, l, s) \
118 const uint32_t GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<l); \
119 const uint32_t GGL_NEEDS_##name##_SHIFT = (l);
120
121 #define GGL_BUILD_NEEDS(val, name) \
122 (((val)<<(GGL_NEEDS_##name##_SHIFT)) & GGL_NEEDS_##name##_MASK)
123
124 #define GGL_READ_NEEDS(name, n) \
125 (uint32_t(n & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
126
127 #define GGL_NEED_MASK(name) (uint32_t(GGL_NEEDS_##name##_MASK))
128 #define GGL_NEED(name, val) GGL_BUILD_NEEDS(val, name)
129
130 GGL_RESERVE_NEEDS( CB_FORMAT, 0, 6 )
131 GGL_RESERVE_NEEDS( SHADE, 6, 1 )
132 GGL_RESERVE_NEEDS( W, 7, 1 )
133 GGL_RESERVE_NEEDS( BLEND_SRC, 8, 4 )
134 GGL_RESERVE_NEEDS( BLEND_DST, 12, 4 )
135 GGL_RESERVE_NEEDS( BLEND_SRCA, 16, 4 )
136 GGL_RESERVE_NEEDS( BLEND_DSTA, 20, 4 )
137 GGL_RESERVE_NEEDS( LOGIC_OP, 24, 4 )
138 GGL_RESERVE_NEEDS( MASK_ARGB, 28, 4 )
139
140 GGL_RESERVE_NEEDS( P_ALPHA_TEST, 0, 3 )
141 GGL_RESERVE_NEEDS( P_AA, 3, 1 )
142 GGL_RESERVE_NEEDS( P_DEPTH_TEST, 4, 3 )
143 GGL_RESERVE_NEEDS( P_MASK_Z, 7, 1 )
144 GGL_RESERVE_NEEDS( P_DITHER, 8, 1 )
145 GGL_RESERVE_NEEDS( P_FOG, 9, 1 )
146 GGL_RESERVE_NEEDS( P_RESERVED1, 10,22 )
147
148 GGL_RESERVE_NEEDS( T_FORMAT, 0, 6 )
149 GGL_RESERVE_NEEDS( T_RESERVED0, 6, 1 )
150 GGL_RESERVE_NEEDS( T_POT, 7, 1 )
151 GGL_RESERVE_NEEDS( T_S_WRAP, 8, 2 )
152 GGL_RESERVE_NEEDS( T_T_WRAP, 10, 2 )
153 GGL_RESERVE_NEEDS( T_ENV, 12, 3 )
154 GGL_RESERVE_NEEDS( T_LINEAR, 15, 1 )
155
156 const int GGL_NEEDS_WRAP_CLAMP_TO_EDGE = 0;
157 const int GGL_NEEDS_WRAP_REPEAT = 1;
158 const int GGL_NEEDS_WRAP_11 = 2;
159
160 inline uint32_t ggl_wrap_to_needs(uint32_t e) {
161 switch (e) {
162 case GGL_CLAMP: return GGL_NEEDS_WRAP_CLAMP_TO_EDGE;
163 case GGL_REPEAT: return GGL_NEEDS_WRAP_REPEAT;
164 }
165 return 0;
166 }
167
168 inline uint32_t ggl_blendfactor_to_needs(uint32_t b) {
169 if (b <= 1) return b;
170 return (b & 0xF)+2;
171 }
172
173 inline uint32_t ggl_needs_to_blendfactor(uint32_t n) {
174 if (n <= 1) return n;
175 return (n - 2) + 0x300;
176 }
177
178 inline uint32_t ggl_env_to_needs(uint32_t e) {
179 switch (e) {
180 case GGL_REPLACE: return 0;
181 case GGL_MODULATE: return 1;
182 case GGL_DECAL: return 2;
183 case GGL_BLEND: return 3;
184 case GGL_ADD: return 4;
185 }
186 return 0;
187 }
188
189 inline uint32_t ggl_needs_to_env(uint32_t n) {
190 const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE,
191 GGL_DECAL, GGL_BLEND, GGL_ADD };
192 return envs[n];
193
194 }
195
196 // ----------------------------------------------------------------------------
197
198 enum {
199 GGL_ENABLE_BLENDING = 0x00000001,
200 GGL_ENABLE_SMOOTH = 0x00000002,
201 GGL_ENABLE_AA = 0x00000004,
202 GGL_ENABLE_LOGIC_OP = 0x00000008,
203 GGL_ENABLE_ALPHA_TEST = 0x00000010,
204 GGL_ENABLE_SCISSOR_TEST = 0x00000020,
205 GGL_ENABLE_TMUS = 0x00000040,
206 GGL_ENABLE_DEPTH_TEST = 0x00000080,
207 GGL_ENABLE_STENCIL_TEST = 0x00000100,
208 GGL_ENABLE_W = 0x00000200,
209 GGL_ENABLE_DITHER = 0x00000400,
210 GGL_ENABLE_FOG = 0x00000800,
211 GGL_ENABLE_POINT_AA_NICE= 0x00001000
212 };
213
214 // ----------------------------------------------------------------------------
215
216 class needs_filter_t;
217 struct needs_t {
218 inline int match(const needs_filter_t& filter);
219 inline bool operator == (const needs_t& rhs) const {
220 return (n==rhs.n) &&
221 (p==rhs.p) &&
222 (t[0]==rhs.t[0]) &&
223 (t[1]==rhs.t[1]);
224 }
225 inline bool operator != (const needs_t& rhs) const {
226 return !operator == (rhs);
227 }
228 uint32_t n;
229 uint32_t p;
230 uint32_t t[GGL_TEXTURE_UNIT_COUNT];
231 };
232
233 inline int compare_type(const needs_t& lhs, const needs_t& rhs) {
234 return memcmp(&lhs, &rhs, sizeof(needs_t));
235 }
236
237 struct needs_filter_t {
238 needs_t value;
239 needs_t mask;
240 };
241
242 int needs_t::match(const needs_filter_t& filter) {
243 uint32_t result =
244 ((filter.value.n ^ n) & filter.mask.n) |
245 ((filter.value.p ^ p) & filter.mask.p) |
246 ((filter.value.t[0] ^ t[0]) & filter.mask.t[0]) |
247 ((filter.value.t[1] ^ t[1]) & filter.mask.t[1]);
248 return (result == 0);
249 }
250
251 // ----------------------------------------------------------------------------
252
253 struct context_t;
254 class Assembly;
255
256 struct blend_state_t {
257 uint32_t src;
258 uint32_t dst;
259 uint32_t src_alpha;
260 uint32_t dst_alpha;
261 uint8_t reserved;
262 uint8_t alpha_separate;
263 uint8_t operation;
264 uint8_t equation;
265 };
266
267 struct mask_state_t {
268 uint8_t color;
269 uint8_t depth;
270 uint32_t stencil;
271 };
272
273 struct clear_state_t {
274 GGLclampx r;
275 GGLclampx g;
276 GGLclampx b;
277 GGLclampx a;
278 GGLclampx depth;
279 GGLint stencil;
280 uint32_t colorPacked;
281 uint32_t depthPacked;
282 uint32_t stencilPacked;
283 uint32_t dirty;
284 };
285
286 struct fog_state_t {
287 uint8_t color[3];
288 uint8_t reserved;
289 };
290
291 struct logic_op_state_t {
292 uint16_t opcode;
293 };
294
295 struct alpha_test_state_t {
296 uint16_t func;
297 GGLcolor ref;
298 };
299
300 struct depth_test_state_t {
301 uint16_t func;
302 GGLclampx clearValue;
303 };
304
305 struct scissor_t {
306 uint32_t user_left;
307 uint32_t user_right;
308 uint32_t user_top;
309 uint32_t user_bottom;
310 uint32_t left;
311 uint32_t right;
312 uint32_t top;
313 uint32_t bottom;
314 };
315
316 struct pixel_t {
317 uint32_t c[4];
318 uint8_t s[4];
319 };
320
321 struct surface_t {
322 union {
323 GGLSurface s;
324 struct {
325 uint32_t reserved;
326 uint32_t width;
327 uint32_t height;
328 int32_t stride;
329 uint8_t* data;
330 uint8_t format;
331 uint8_t dirty;
332 uint8_t pad[2];
333 };
334 };
335 void (*read) (const surface_t* s, context_t* c,
336 uint32_t x, uint32_t y, pixel_t* pixel);
337 void (*write)(const surface_t* s, context_t* c,
338 uint32_t x, uint32_t y, const pixel_t* pixel);
339 };
340
341 // ----------------------------------------------------------------------------
342
343 struct texture_shade_t {
344 union {
345 struct {
346 int32_t is0;
347 int32_t idsdx;
348 int32_t idsdy;
349 int sscale;
350 int32_t it0;
351 int32_t idtdx;
352 int32_t idtdy;
353 int tscale;
354 };
355 struct {
356 int32_t v;
357 int32_t dx;
358 int32_t dy;
359 int scale;
360 } st[2];
361 };
362 };
363
364 struct texture_iterators_t {
365 // these are not encoded in the same way than in the
366 // texture_shade_t structure
367 union {
368 struct {
369 GGLfixed ydsdy;
370 GGLfixed dsdx;
371 GGLfixed dsdy;
372 int sscale;
373 GGLfixed ydtdy;
374 GGLfixed dtdx;
375 GGLfixed dtdy;
376 int tscale;
377 };
378 struct {
379 GGLfixed ydvdy;
380 GGLfixed dvdx;
381 GGLfixed dvdy;
382 int scale;
383 } st[2];
384 };
385 };
386
387 struct texture_t {
388 surface_t surface;
389 texture_iterators_t iterators;
390 texture_shade_t shade;
391 uint32_t s_coord;
392 uint32_t t_coord;
393 uint16_t s_wrap;
394 uint16_t t_wrap;
395 uint16_t min_filter;
396 uint16_t mag_filter;
397 uint16_t env;
398 uint8_t env_color[4];
399 uint8_t enable;
400 uint8_t dirty;
401 };
402
403 struct raster_t {
404 GGLfixed x;
405 GGLfixed y;
406 };
407
408 struct framebuffer_t {
409 surface_t color;
410 surface_t read;
411 surface_t depth;
412 surface_t stencil;
413 int16_t *coverage;
414 size_t coverageBufferSize;
415 };
416
417 // ----------------------------------------------------------------------------
418
419 struct iterators_t {
420 int32_t xl;
421 int32_t xr;
422 int32_t y;
423 GGLcolor ydady;
424 GGLcolor ydrdy;
425 GGLcolor ydgdy;
426 GGLcolor ydbdy;
427 GGLfixed ydzdy;
428 GGLfixed ydwdy;
429 GGLfixed ydfdy;
430 };
431
432 struct shade_t {
433 GGLcolor a0;
434 GGLcolor dadx;
435 GGLcolor dady;
436 GGLcolor r0;
437 GGLcolor drdx;
438 GGLcolor drdy;
439 GGLcolor g0;
440 GGLcolor dgdx;
441 GGLcolor dgdy;
442 GGLcolor b0;
443 GGLcolor dbdx;
444 GGLcolor dbdy;
445 uint32_t z0;
446 GGLfixed32 dzdx;
447 GGLfixed32 dzdy;
448 GGLfixed w0;
449 GGLfixed dwdx;
450 GGLfixed dwdy;
451 uint32_t f0;
452 GGLfixed dfdx;
453 GGLfixed dfdy;
454 };
455
456 // these are used in the generated code
457 // we use this mirror structure to improve
458 // data locality in the pixel pipeline
459 struct generated_tex_vars_t {
460 uint32_t width;
461 uint32_t height;
462 uint32_t stride;
463 int32_t data;
464 int32_t dsdx;
465 int32_t dtdx;
466 int32_t spill[2];
467 };
468
469 struct generated_vars_t {
470 struct {
471 int32_t c;
472 int32_t dx;
473 } argb[4];
474 int32_t aref;
475 int32_t dzdx;
476 int32_t zbase;
477 int32_t f;
478 int32_t dfdx;
479 int32_t spill[3];
480 generated_tex_vars_t texture[GGL_TEXTURE_UNIT_COUNT];
481 int32_t rt;
482 int32_t lb;
483 };
484
485 // ----------------------------------------------------------------------------
486
487 struct state_t {
488 framebuffer_t buffers;
489 texture_t texture[GGL_TEXTURE_UNIT_COUNT];
490 scissor_t scissor;
491 raster_t raster;
492 blend_state_t blend;
493 alpha_test_state_t alpha_test;
494 depth_test_state_t depth_test;
495 mask_state_t mask;
496 clear_state_t clear;
497 fog_state_t fog;
498 logic_op_state_t logic_op;
499 uint32_t enables;
500 uint32_t enabled_tmu;
501 needs_t needs;
502 };
503
504 // ----------------------------------------------------------------------------
505
506 struct context_t {
507 GGLContext procs;
508 state_t state;
509 shade_t shade;
510 iterators_t iterators;
511 generated_vars_t generated_vars __attribute__((aligned(32)));
512 uint8_t ditherMatrix[GGL_DITHER_SIZE] __attribute__((aligned(32)));
513 uint32_t packed;
514 uint32_t packed8888;
515 const GGLFormat* formats;
516 uint32_t dirty;
517 texture_t* activeTMU;
518 uint32_t activeTMUIndex;
519
520 void (*init_y)(context_t* c, int32_t y);
521 void (*step_y)(context_t* c);
522 void (*scanline)(context_t* c);
523 void (*span)(context_t* c);
524 void (*rect)(context_t* c, size_t yc);
525
526 void* base;
527 Assembly* scanline_as;
528 GGLenum error;
529 };
530
531 // ----------------------------------------------------------------------------
532
533 void ggl_init_context(context_t* context);
534 void ggl_uninit_context(context_t* context);
535 void ggl_error(context_t* c, GGLenum error);
536 int64_t ggl_system_time();
537
538 // ----------------------------------------------------------------------------
539
540 };
541
542 #endif // ANDROID_GGL_CONTEXT_H
543
+0
-302
include/private/pixelflinger/ggl_fixed.h less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ANDROID_GGL_FIXED_H
17 #define ANDROID_GGL_FIXED_H
18
19 #include <math.h>
20 #include <pixelflinger/pixelflinger.h>
21
22 // ----------------------------------------------------------------------------
23
24 #define CONST __attribute__((const))
25 #define ALWAYS_INLINE __attribute__((always_inline))
26
27 const GGLfixed FIXED_BITS = 16;
28 const GGLfixed FIXED_EPSILON = 1;
29 const GGLfixed FIXED_ONE = 1L<<FIXED_BITS;
30 const GGLfixed FIXED_HALF = 1L<<(FIXED_BITS-1);
31 const GGLfixed FIXED_MIN = 0x80000000L;
32 const GGLfixed FIXED_MAX = 0x7FFFFFFFL;
33
34 inline GGLfixed gglIntToFixed(GGLfixed i) ALWAYS_INLINE ;
35 inline GGLfixed gglFixedToIntRound(GGLfixed f) ALWAYS_INLINE ;
36 inline GGLfixed gglFixedToIntFloor(GGLfixed f) ALWAYS_INLINE ;
37 inline GGLfixed gglFixedToIntCeil(GGLfixed f) ALWAYS_INLINE ;
38 inline GGLfixed gglFracx(GGLfixed v) ALWAYS_INLINE ;
39 inline GGLfixed gglFloorx(GGLfixed v) ALWAYS_INLINE ;
40 inline GGLfixed gglCeilx(GGLfixed v) ALWAYS_INLINE ;
41 inline GGLfixed gglCenterx(GGLfixed v) ALWAYS_INLINE ;
42 inline GGLfixed gglRoundx(GGLfixed v) ALWAYS_INLINE ;
43
44 GGLfixed gglIntToFixed(GGLfixed i) {
45 return i<<FIXED_BITS;
46 }
47 GGLfixed gglFixedToIntRound(GGLfixed f) {
48 return (f + FIXED_HALF)>>FIXED_BITS;
49 }
50 GGLfixed gglFixedToIntFloor(GGLfixed f) {
51 return f>>FIXED_BITS;
52 }
53 GGLfixed gglFixedToIntCeil(GGLfixed f) {
54 return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS;
55 }
56
57 GGLfixed gglFracx(GGLfixed v) {
58 return v & ((1<<FIXED_BITS)-1);
59 }
60 GGLfixed gglFloorx(GGLfixed v) {
61 return gglFixedToIntFloor(v)<<FIXED_BITS;
62 }
63 GGLfixed gglCeilx(GGLfixed v) {
64 return gglFixedToIntCeil(v)<<FIXED_BITS;
65 }
66 GGLfixed gglCenterx(GGLfixed v) {
67 return gglFloorx(v + FIXED_HALF) | FIXED_HALF;
68 }
69 GGLfixed gglRoundx(GGLfixed v) {
70 return gglFixedToIntRound(v)<<FIXED_BITS;
71 }
72
73 // conversion from (unsigned) int, short, byte to fixed...
74 #define GGL_B_TO_X(_x) GGLfixed( ((int32_t(_x)+1)>>1)<<10 )
75 #define GGL_S_TO_X(_x) GGLfixed( ((int32_t(_x)+1)>>1)<<2 )
76 #define GGL_I_TO_X(_x) GGLfixed( ((int32_t(_x)>>1)+1)>>14 )
77 #define GGL_UB_TO_X(_x) GGLfixed( uint32_t(_x) + \
78 (uint32_t(_x)<<8) + \
79 (uint32_t(_x)>>7) )
80 #define GGL_US_TO_X(_x) GGLfixed( (_x) + ((_x)>>15) )
81 #define GGL_UI_TO_X(_x) GGLfixed( (((_x)>>1)+1)>>15 )
82
83 // ----------------------------------------------------------------------------
84
85 GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
86 GGLfixed gglSqrtx(GGLfixed a) CONST;
87 GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
88 GGLfixed gglFastDivx(GGLfixed n, GGLfixed d) CONST;
89 int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
90
91 int32_t gglRecipQNormalized(int32_t x, int* exponent);
92 int32_t gglRecipQ(GGLfixed x, int q) CONST;
93
94 inline GGLfixed gglRecip(GGLfixed x) CONST;
95 inline GGLfixed gglRecip(GGLfixed x) {
96 return gglRecipQ(x, 16);
97 }
98
99 inline GGLfixed gglRecip28(GGLfixed x) CONST;
100 int32_t gglRecip28(GGLfixed x) {
101 return gglRecipQ(x, 28);
102 }
103
104 // ----------------------------------------------------------------------------
105
106 #if defined(__arm__) && !defined(__thumb__)
107
108 // inline ARM implementations
109 inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
110 inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) {
111 GGLfixed result, t;
112 if (__builtin_constant_p(shift)) {
113 asm("smull %[lo], %[hi], %[x], %[y] \n"
114 "movs %[lo], %[lo], lsr %[rshift] \n"
115 "adc %[lo], %[lo], %[hi], lsl %[lshift] \n"
116 : [lo]"=r"(result), [hi]"=r"(t), [x]"=r"(x)
117 : "%[x]"(x), [y]"r"(y), [lshift] "I"(32-shift), [rshift] "I"(shift)
118 : "cc"
119 );
120 } else {
121 asm("smull %[lo], %[hi], %[x], %[y] \n"
122 "movs %[lo], %[lo], lsr %[rshift] \n"
123 "adc %[lo], %[lo], %[hi], lsl %[lshift] \n"
124 : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
125 : "%[x]"(x), [y]"r"(y), [lshift] "r"(32-shift), [rshift] "r"(shift)
126 : "cc"
127 );
128 }
129 return result;
130 }
131
132 inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
133 inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) {
134 GGLfixed result, t;
135 if (__builtin_constant_p(shift)) {
136 asm("smull %[lo], %[hi], %[x], %[y] \n"
137 "add %[lo], %[a], %[lo], lsr %[rshift] \n"
138 "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
139 : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
140 : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
141 );
142 } else {
143 asm("smull %[lo], %[hi], %[x], %[y] \n"
144 "add %[lo], %[a], %[lo], lsr %[rshift] \n"
145 "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
146 : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
147 : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift)
148 );
149 }
150 return result;
151 }
152
153 inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
154 inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) {
155 GGLfixed result, t;
156 if (__builtin_constant_p(shift)) {
157 asm("smull %[lo], %[hi], %[x], %[y] \n"
158 "rsb %[lo], %[a], %[lo], lsr %[rshift] \n"
159 "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
160 : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
161 : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
162 );
163 } else {
164 asm("smull %[lo], %[hi], %[x], %[y] \n"
165 "rsb %[lo], %[a], %[lo], lsr %[rshift] \n"
166 "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
167 : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
168 : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift)
169 );
170 }
171 return result;
172 }
173
174 inline int64_t gglMulii(int32_t x, int32_t y) CONST;
175 inline int64_t gglMulii(int32_t x, int32_t y)
176 {
177 // 64-bits result: r0=low, r1=high
178 union {
179 struct {
180 int32_t lo;
181 int32_t hi;
182 } s;
183 int64_t res;
184 };
185 asm("smull %0, %1, %2, %3 \n"
186 : "=r"(s.lo), "=&r"(s.hi)
187 : "%r"(x), "r"(y)
188 :
189 );
190 return res;
191 }
192
193 #else // ----------------------------------------------------------------------
194
195 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
196 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
197 return GGLfixed((int64_t(a)*b + (1<<(shift-1)))>>shift);
198 }
199 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
200 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
201 return GGLfixed((int64_t(a)*b)>>shift) + c;
202 }
203 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
204 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
205 return GGLfixed((int64_t(a)*b)>>shift) - c;
206 }
207 inline int64_t gglMulii(int32_t a, int32_t b) CONST;
208 inline int64_t gglMulii(int32_t a, int32_t b) {
209 return int64_t(a)*b;
210 }
211
212 #endif
213
214 // ------------------------------------------------------------------------
215
216 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) CONST;
217 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) {
218 return gglMulx(a, b, 16);
219 }
220 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
221 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) {
222 return gglMulAddx(a, b, c, 16);
223 }
224 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
225 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) {
226 return gglMulSubx(a, b, c, 16);
227 }
228
229 // ------------------------------------------------------------------------
230
231 inline int32_t gglClz(int32_t x) CONST;
232 inline int32_t gglClz(int32_t x)
233 {
234 #if defined(__arm__) && !defined(__thumb__)
235 return __builtin_clz(x);
236 #else
237 if (!x) return 32;
238 int32_t exp = 31;
239 if (x & 0xFFFF0000) { exp -=16; x >>= 16; }
240 if (x & 0x0000ff00) { exp -= 8; x >>= 8; }
241 if (x & 0x000000f0) { exp -= 4; x >>= 4; }
242 if (x & 0x0000000c) { exp -= 2; x >>= 2; }
243 if (x & 0x00000002) { exp -= 1; }
244 return exp;
245 #endif
246 }
247
248 // ------------------------------------------------------------------------
249
250 int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i) CONST;
251
252 inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) CONST;
253 inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) {
254 return gglDivQ(n, d, 16);
255 }
256
257 inline int32_t gglDivx(GGLfixed n, GGLfixed d) CONST;
258 inline int32_t gglDivx(GGLfixed n, GGLfixed d) {
259 return gglDivQ(n, d, 16);
260 }
261
262 // ------------------------------------------------------------------------
263
264 inline GGLfixed gglRecipFast(GGLfixed x) CONST;
265 inline GGLfixed gglRecipFast(GGLfixed x)
266 {
267 // This is a really bad approximation of 1/x, but it's also
268 // very fast. x must be strictly positive.
269 // if x between [0.5, 1[ , then 1/x = 3-2*x
270 // (we use 2.30 fixed-point)
271 const int32_t lz = gglClz(x);
272 return (0xC0000000 - (x << (lz - 1))) >> (30-lz);
273 }
274
275 // ------------------------------------------------------------------------
276
277 inline GGLfixed gglClampx(GGLfixed c) CONST;
278 inline GGLfixed gglClampx(GGLfixed c)
279 {
280 #if defined(__thumb__)
281 // clamp without branches
282 c &= ~(c>>31); c = FIXED_ONE - c;
283 c &= ~(c>>31); c = FIXED_ONE - c;
284 #else
285 #if defined(__arm__)
286 // I don't know why gcc thinks its smarter than me! The code below
287 // clamps to zero in one instruction, but gcc won't generate it and
288 // replace it by a cmp + movlt (it's quite amazing actually).
289 asm("bic %0, %1, %1, asr #31\n" : "=r"(c) : "r"(c));
290 #else
291 c &= ~(c>>31);
292 #endif
293 if (c>FIXED_ONE)
294 c = FIXED_ONE;
295 #endif
296 return c;
297 }
298
299 // ------------------------------------------------------------------------
300
301 #endif // ANDROID_GGL_FIXED_H
+0
-58
include/zipfile/zipfile.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _ZIPFILE_ZIPFILE_H
17 #define _ZIPFILE_ZIPFILE_H
18
19 #include <stddef.h>
20
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24
25 typedef void* zipfile_t;
26 typedef void* zipentry_t;
27
28 // Provide a buffer. Returns NULL on failure.
29 zipfile_t init_zipfile(const void* data, size_t size);
30
31 // Release the zipfile resources.
32 void release_zipfile(zipfile_t file);
33
34 // Get a named entry object. Returns NULL if it doesn't exist
35 // or if we won't be able to decompress it. The zipentry_t is
36 // freed by release_zipfile()
37 zipentry_t lookup_zipentry(zipfile_t file, const char* entryName);
38
39 // Return the size of the entry.
40 size_t get_zipentry_size(zipentry_t entry);
41
42 // return the filename of this entry, you own the memory returned
43 char* get_zipentry_name(zipentry_t entry);
44
45 // The buffer must be 1.001 times the buffer size returned
46 // by get_zipentry_size. Returns nonzero on failure.
47 int decompress_zipentry(zipentry_t entry, void* buf, int bufsize);
48
49 // iterate through the entries in the zip file. pass a pointer to
50 // a void* initialized to NULL to start. Returns NULL when done
51 zipentry_t iterate_zipfile(zipfile_t file, void** cookie);
52
53 #ifdef __cplusplus
54 } // extern "C"
55 #endif
56
57 #endif // _ZIPFILE_ZIPFILE_H
+0
-33
init/Android.mk less more
0 # Copyright 2005 The Android Open Source Project
1
2 LOCAL_PATH:= $(call my-dir)
3 include $(CLEAR_VARS)
4
5 LOCAL_SRC_FILES:= \
6 builtins.c \
7 init.c \
8 devices.c \
9 property_service.c \
10 util.c \
11 parser.c \
12 logo.c
13
14 ifeq ($(strip $(INIT_BOOTCHART)),true)
15 LOCAL_SRC_FILES += bootchart.c
16 LOCAL_CFLAGS += -DBOOTCHART=1
17 endif
18
19 LOCAL_MODULE:= init
20
21 LOCAL_FORCE_STATIC_EXECUTABLE := true
22 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
23 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
24
25 LOCAL_STATIC_LIBRARIES := libcutils libc
26
27 #LOCAL_STATIC_LIBRARIES := libcutils libc libminui libpixelflinger_static
28 #LOCAL_STATIC_LIBRARIES += libminzip libunz libamend libmtdutils libmincrypt
29 #LOCAL_STATIC_LIBRARIES += libstdc++_static
30
31 include $(BUILD_EXECUTABLE)
32
+0
-0
init/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
init/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-52
init/README.BOOTCHART less more
0 This version of init contains code to perform "bootcharting", i.e. generating log
1 files that can be later processed by the tools provided by www.bootchart.org.
2
3 To activate it, you need to define build 'init' with the INIT_BOOTCHART environment
4 variable defined to 'true', for example:
5
6 touch system/init/init.c
7 m INIT_BOOTCHART=true
8
9 On the emulator, use the new -bootchart <timeout> option to boot with bootcharting
10 activated for <timeout> seconds.
11
12 Otherwise, flash your device, and start it. Then create a file on the /data partition
13 with a command like the following:
14
15 adb shell 'echo $TIMEOUT > /data/bootchart-start'
16
17 Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds;
18 for example, to bootchart for 2 minutes, do:
19
20 adb shell 'echo 120 > /data/bootchart-start'
21
22 Reboot your device, bootcharting will begin and stop after the period you gave.
23 You can also stop the bootcharting at any moment by doing the following:
24
25 adb shell 'echo 1 > /data/bootchart-stop'
26
27 Note that /data/bootchart-stop is deleted automatically by init at the end of the
28 bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it
29 when you're done collecting data:
30
31 adb shell rm /data/bootchart-start
32
33 The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh
34 which will use ADB to retrieve them and create a bootchart.tgz file that can be used with
35 the bootchart parser/renderer, or even uploaded directly to the form located at:
36
37 http://www.bootchart.org/download.html
38
39 NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an
40 image on your machine by doing the following:
41
42 1/ download the sources from www.bootchart.org
43 2/ unpack them
44 3/ in the source directory, type 'ant' to build the bootchart program
45 4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz
46
47 technical note:
48
49 this implementation of bootcharting does use the 'bootchartd' script provided by
50 www.bootchart.org, but a C re-implementation that is directly compiled into our init
51 program.
+0
-378
init/bootchart.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* this code is used to generate a boot sequence profile that can be used
17 * with the 'bootchart' graphics generation tool. see www.bootchart.org
18 * note that unlike the original bootchartd, this is not a Bash script but
19 * some C code that is run right from the init script.
20 */
21
22 #include <stdio.h>
23 #include <time.h>
24 #include <dirent.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 #include "bootchart.h"
35
36 #define VERSION "0.8"
37 #define SAMPLE_PERIOD 0.2
38 #define LOG_ROOT "/data/bootchart"
39 #define LOG_STAT LOG_ROOT"/proc_stat.log"
40 #define LOG_PROCS LOG_ROOT"/proc_ps.log"
41 #define LOG_DISK LOG_ROOT"/proc_diskstats.log"
42 #define LOG_HEADER LOG_ROOT"/header"
43 #define LOG_ACCT LOG_ROOT"/kernel_pacct"
44
45 #define LOG_STARTFILE "/data/bootchart-start"
46 #define LOG_STOPFILE "/data/bootchart-stop"
47
48 static int
49 unix_read(int fd, void* buff, int len)
50 {
51 int ret;
52 do { ret = read(fd, buff, len); } while (ret < 0 && errno == EINTR);
53 return ret;
54 }
55
56 static int
57 unix_write(int fd, const void* buff, int len)
58 {
59 int ret;
60 do { ret = write(fd, buff, len); } while (ret < 0 && errno == EINTR);
61 return ret;
62 }
63
64 static int
65 proc_read(const char* filename, char* buff, size_t buffsize)
66 {
67 int len = 0;
68 int fd = open(filename, O_RDONLY);
69 if (fd >= 0) {
70 len = unix_read(fd, buff, buffsize-1);
71 close(fd);
72 }
73 buff[len > 0 ? len : 0] = 0;
74 return len;
75 }
76
77 #define FILE_BUFF_SIZE 65536
78
79 typedef struct {
80 int count;
81 int fd;
82 char data[FILE_BUFF_SIZE];
83 } FileBuffRec, *FileBuff;
84
85 static void
86 file_buff_open( FileBuff buff, const char* path )
87 {
88 buff->count = 0;
89 buff->fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0755);
90 }
91
92 static void
93 file_buff_write( FileBuff buff, const void* src, int len )
94 {
95 while (len > 0) {
96 int avail = sizeof(buff->data) - buff->count;
97 if (avail > len)
98 avail = len;
99
100 memcpy( buff->data + buff->count, src, avail );
101 len -= avail;
102 src = (char*)src + avail;
103
104 buff->count += avail;
105 if (buff->count == FILE_BUFF_SIZE) {
106 unix_write( buff->fd, buff->data, buff->count );
107 buff->count = 0;
108 }
109 }
110 }
111
112 static void
113 file_buff_done( FileBuff buff )
114 {
115 if (buff->count > 0) {
116 unix_write( buff->fd, buff->data, buff->count );
117 buff->count = 0;
118 }
119 }
120
121 static void
122 log_header(void)
123 {
124 FILE* out;
125 char cmdline[1024];
126 char uname[128];
127 char cpuinfo[128];
128 char* cpu;
129 char date[32];
130 time_t now_t = time(NULL);
131 struct tm now = *localtime(&now_t);
132 strftime(date, sizeof(date), "%x %X", &now);
133
134 out = fopen( LOG_HEADER, "w" );
135 if (out == NULL)
136 return;
137
138 proc_read("/proc/cmdline", cmdline, sizeof(cmdline));
139 proc_read("/proc/version", uname, sizeof(uname));
140 proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo));
141
142 cpu = strchr( cpuinfo, ':' );
143 if (cpu) {
144 char* p = strchr(cpu, '\n');
145 cpu += 2;
146 if (p)
147 *p = 0;
148 }
149
150 fprintf(out, "version = %s\n", VERSION);
151 fprintf(out, "title = Boot chart for Android ( %s )\n", date);
152 fprintf(out, "system.uname = %s\n", uname);
153 fprintf(out, "system.release = 0.0\n");
154 fprintf(out, "system.cpu = %s\n", cpu);
155 fprintf(out, "system.kernel.options = %s\n", cmdline);
156 fclose(out);
157 }
158
159 static void
160 close_on_exec(int fd)
161 {
162 fcntl(fd, F_SETFD, FD_CLOEXEC);
163 }
164
165 static void
166 open_log_file(int* plogfd, const char* logfile)
167 {
168 int logfd = *plogfd;
169
170 /* create log file if needed */
171 if (logfd < 0)
172 {
173 logfd = open(logfile,O_WRONLY|O_CREAT|O_TRUNC,0755);
174 if (logfd < 0) {
175 *plogfd = -2;
176 return;
177 }
178 close_on_exec(logfd);
179 *plogfd = logfd;
180 }
181 }
182
183 static void
184 do_log_uptime(FileBuff log)
185 {
186 char buff[65];
187 int fd, ret, len;
188
189 fd = open("/proc/uptime",O_RDONLY);
190 if (fd >= 0) {
191 int ret;
192 ret = unix_read(fd, buff, 64);
193 close(fd);
194 buff[64] = 0;
195 if (ret >= 0) {
196 long long jiffies = 100LL*strtod(buff,NULL);
197 int len;
198 snprintf(buff,sizeof(buff),"%lld\n",jiffies);
199 len = strlen(buff);
200 file_buff_write(log, buff, len);
201 }
202 }
203 }
204
205 static void
206 do_log_ln(FileBuff log)
207 {
208 file_buff_write(log, "\n", 1);
209 }
210
211
212 static void
213 do_log_file(FileBuff log, const char* procfile)
214 {
215 char buff[1024];
216 int fd;
217
218 do_log_uptime(log);
219
220 /* append file content */
221 fd = open(procfile,O_RDONLY);
222 if (fd >= 0) {
223 close_on_exec(fd);
224 for (;;) {
225 int ret;
226 ret = unix_read(fd, buff, sizeof(buff));
227 if (ret <= 0)
228 break;
229
230 file_buff_write(log, buff, ret);
231 if (ret < (int)sizeof(buff))
232 break;
233 }
234 close(fd);
235 }
236
237 do_log_ln(log);
238 }
239
240 static void
241 do_log_procs(FileBuff log)
242 {
243 DIR* dir = opendir("/proc");
244 struct dirent* entry;
245
246 do_log_uptime(log);
247
248 while ((entry = readdir(dir)) != NULL) {
249 /* only match numeric values */
250 char* end;
251 int pid = strtol( entry->d_name, &end, 10);
252 if (end != NULL && end > entry->d_name && *end == 0) {
253 char filename[32];
254 char buff[1024];
255 char cmdline[1024];
256 int len;
257 int fd;
258
259 /* read command line and extract program name */
260 snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid);
261 proc_read(filename, cmdline, sizeof(cmdline));
262
263 /* read process stat line */
264 snprintf(filename,sizeof(filename),"/proc/%d/stat",pid);
265 fd = open(filename,O_RDONLY);
266 if (fd >= 0) {
267 len = unix_read(fd, buff, sizeof(buff)-1);
268 close(fd);
269 if (len > 0) {
270 int len2 = strlen(cmdline);
271 if (len2 > 0) {
272 /* we want to substitute the process name with its real name */
273 const char* p1;
274 const char* p2;
275 buff[len] = 0;
276 p1 = strchr(buff, '(');
277 p2 = strchr(p1, ')');
278 file_buff_write(log, buff, p1+1-buff);
279 file_buff_write(log, cmdline, strlen(cmdline));
280 file_buff_write(log, p2, strlen(p2));
281 } else {
282 /* no substitution */
283 file_buff_write(log,buff,len);
284 }
285 }
286 }
287 }
288 }
289 closedir(dir);
290 do_log_ln(log);
291 }
292
293 static FileBuffRec log_stat[1];
294 static FileBuffRec log_procs[1];
295 static FileBuffRec log_disks[1];
296
297 /* called to setup bootcharting */
298 int bootchart_init( void )
299 {
300 int ret;
301 char buff[4];
302 int timeout = 0, count = 0;
303
304 buff[0] = 0;
305 proc_read( LOG_STARTFILE, buff, sizeof(buff) );
306 if (buff[0] != 0) {
307 timeout = atoi(buff);
308 }
309 else {
310 /* when running with emulator, androidboot.bootchart=<timeout>
311 * might be passed by as kernel parameters to specify the bootchart
312 * timeout. this is useful when using -wipe-data since the /data
313 * partition is fresh
314 */
315 char cmdline[1024];
316 char* s;
317 #define KERNEL_OPTION "androidboot.bootchart="
318 proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );
319 s = strstr(cmdline, KERNEL_OPTION);
320 if (s) {
321 s += sizeof(KERNEL_OPTION)-1;
322 timeout = atoi(s);
323 }
324 }
325 if (timeout == 0)
326 return 0;
327
328 if (timeout > BOOTCHART_MAX_TIME_SEC)
329 timeout = BOOTCHART_MAX_TIME_SEC;
330
331 count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
332
333 do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR);
334
335 file_buff_open(log_stat, LOG_STAT);
336 file_buff_open(log_procs, LOG_PROCS);
337 file_buff_open(log_disks, LOG_DISK);
338
339 /* create kernel process accounting file */
340 {
341 int fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC,0644);
342 if (fd >= 0) {
343 close(fd);
344 acct( LOG_ACCT );
345 }
346 }
347
348 log_header();
349 return count;
350 }
351
352 /* called each time you want to perform a bootchart sampling op */
353 int bootchart_step( void )
354 {
355 do_log_file(log_stat, "/proc/stat");
356 do_log_file(log_disks, "/proc/diskstats");
357 do_log_procs(log_procs);
358
359 /* we stop when /data/bootchart-stop contains 1 */
360 {
361 char buff[2];
362 if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') {
363 return -1;
364 }
365 }
366
367 return 0;
368 }
369
370 void bootchart_finish( void )
371 {
372 unlink( LOG_STOPFILE );
373 file_buff_done(log_stat);
374 file_buff_done(log_disks);
375 file_buff_done(log_procs);
376 acct(NULL);
377 }
+0
-36
init/bootchart.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _BOOTCHART_H
17 #define _BOOTCHART_H
18
19 #ifndef BOOTCHART
20 # define BOOTCHART 0
21 #endif
22
23 #if BOOTCHART
24
25 extern int bootchart_init(void);
26 extern int bootchart_step(void);
27 extern void bootchart_finish(void);
28
29 # define BOOTCHART_POLLING_MS 200 /* polling period in ms */
30 # define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */
31 # define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */
32
33 #endif /* BOOTCHART */
34
35 #endif /* _BOOTCHART_H */
+0
-442
init/builtins.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <linux/kd.h>
23 #include <errno.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <linux/if.h>
27 #include <arpa/inet.h>
28 #include <stdlib.h>
29 #include <sys/mount.h>
30 #include <sys/resource.h>
31
32 #include "init.h"
33 #include "keywords.h"
34 #include "property_service.h"
35 #include "devices.h"
36
37 #include <private/android_filesystem_config.h>
38
39 void add_environment(const char *name, const char *value);
40
41 extern int init_module(void *, unsigned long, const char *);
42
43 static int write_file(const char *path, const char *value)
44 {
45 int fd, ret, len;
46
47 fd = open(path, O_WRONLY|O_CREAT, 0622);
48
49 if (fd < 0)
50 return -1;
51
52 len = strlen(value);
53
54 do {
55 ret = write(fd, value, len);
56 } while (ret < 0 && errno == EINTR);
57
58 close(fd);
59 if (ret < 0) {
60 return -1;
61 } else {
62 return 0;
63 }
64 }
65
66 static int insmod(const char *filename, char *options)
67 {
68 void *module;
69 unsigned size;
70 int ret;
71
72 module = read_file(filename, &size);
73 if (!module)
74 return -1;
75
76 ret = init_module(module, size, options);
77
78 free(module);
79
80 return ret;
81 }
82
83 static int setkey(struct kbentry *kbe)
84 {
85 int fd, ret;
86
87 fd = open("/dev/tty0", O_RDWR | O_SYNC);
88 if (fd < 0)
89 return -1;
90
91 ret = ioctl(fd, KDSKBENT, kbe);
92
93 close(fd);
94 return ret;
95 }
96
97 static int __ifupdown(const char *interface, int up)
98 {
99 struct ifreq ifr;
100 int s, ret;
101
102 strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
103
104 s = socket(AF_INET, SOCK_DGRAM, 0);
105 if (s < 0)
106 return -1;
107
108 ret = ioctl(s, SIOCGIFFLAGS, &ifr);
109 if (ret < 0) {
110 goto done;
111 }
112
113 if (up)
114 ifr.ifr_flags |= IFF_UP;
115 else
116 ifr.ifr_flags &= ~IFF_UP;
117
118 ret = ioctl(s, SIOCSIFFLAGS, &ifr);
119
120 done:
121 close(s);
122 return ret;
123 }
124
125 static void service_start_if_not_disabled(struct service *svc)
126 {
127 if (!(svc->flags & SVC_DISABLED)) {
128 service_start(svc);
129 }
130 }
131
132 int do_class_start(int nargs, char **args)
133 {
134 /* Starting a class does not start services
135 * which are explicitly disabled. They must
136 * be started individually.
137 */
138 service_for_each_class(args[1], service_start_if_not_disabled);
139 return 0;
140 }
141
142 int do_class_stop(int nargs, char **args)
143 {
144 service_for_each_class(args[1], service_stop);
145 return 0;
146 }
147
148 int do_domainname(int nargs, char **args)
149 {
150 return write_file("/proc/sys/kernel/domainname", args[1]);
151 }
152
153 int do_exec(int nargs, char **args)
154 {
155 return -1;
156 }
157
158 int do_export(int nargs, char **args)
159 {
160 add_environment(args[1], args[2]);
161 return 0;
162 }
163
164 int do_hostname(int nargs, char **args)
165 {
166 return write_file("/proc/sys/kernel/hostname", args[1]);
167 }
168
169 int do_ifup(int nargs, char **args)
170 {
171 return __ifupdown(args[1], 1);
172 }
173
174
175 static int do_insmod_inner(int nargs, char **args, int opt_len)
176 {
177 char options[opt_len + 1];
178 int i;
179
180 options[0] = '\0';
181 if (nargs > 2) {
182 strcpy(options, args[2]);
183 for (i = 3; i < nargs; ++i) {
184 strcat(options, " ");
185 strcat(options, args[i]);
186 }
187 }
188
189 return insmod(args[1], options);
190 }
191
192 int do_insmod(int nargs, char **args)
193 {
194 int i;
195 int size = 0;
196
197 if (nargs > 2) {
198 for (i = 2; i < nargs; ++i)
199 size += strlen(args[i]) + 1;
200 }
201
202 return do_insmod_inner(nargs, args, size);
203 }
204
205 int do_import(int nargs, char **args)
206 {
207 return -1;
208 }
209
210 int do_mkdir(int nargs, char **args)
211 {
212 mode_t mode = 0755;
213
214 /* mkdir <path> [mode] [owner] [group] */
215
216 if (nargs >= 3) {
217 mode = strtoul(args[2], 0, 8);
218 }
219
220 if (mkdir(args[1], mode)) {
221 return -errno;
222 }
223
224 if (nargs >= 4) {
225 uid_t uid = decode_uid(args[3]);
226 gid_t gid = -1;
227
228 if (nargs == 5) {
229 gid = decode_uid(args[4]);
230 }
231
232 if (chown(args[1], uid, gid)) {
233 return -errno;
234 }
235 }
236
237 return 0;
238 }
239
240 static struct {
241 const char *name;
242 unsigned flag;
243 } mount_flags[] = {
244 { "noatime", MS_NOATIME },
245 { "nosuid", MS_NOSUID },
246 { "nodev", MS_NODEV },
247 { "nodiratime", MS_NODIRATIME },
248 { "ro", MS_RDONLY },
249 { "rw", 0 },
250 { "remount", MS_REMOUNT },
251 { "defaults", 0 },
252 { 0, 0 },
253 };
254
255 /* mount <type> <device> <path> <flags ...> <options> */
256 int do_mount(int nargs, char **args)
257 {
258 char tmp[64];
259 char *source;
260 char *options = NULL;
261 unsigned flags = 0;
262 int n, i;
263
264 for (n = 4; n < nargs; n++) {
265 for (i = 0; mount_flags[i].name; i++) {
266 if (!strcmp(args[n], mount_flags[i].name)) {
267 flags |= mount_flags[i].flag;
268 break;
269 }
270 }
271
272 /* if our last argument isn't a flag, wolf it up as an option string */
273 if (n + 1 == nargs && !mount_flags[i].name)
274 options = args[n];
275 }
276
277 source = args[2];
278 if (!strncmp(source, "mtd@", 4)) {
279 n = mtd_name_to_number(source + 4);
280 if (n >= 0) {
281 sprintf(tmp, "/dev/block/mtdblock%d", n);
282 source = tmp;
283 }
284 }
285 return mount(source, args[3], args[1], flags, options);
286 }
287
288 int do_setkey(int nargs, char **args)
289 {
290 struct kbentry kbe;
291 kbe.kb_table = strtoul(args[1], 0, 0);
292 kbe.kb_index = strtoul(args[2], 0, 0);
293 kbe.kb_value = strtoul(args[3], 0, 0);
294 return setkey(&kbe);
295 }
296
297 int do_setprop(int nargs, char **args)
298 {
299 property_set(args[1], args[2]);
300 return 0;
301 }
302
303 int do_setrlimit(int nargs, char **args)
304 {
305 struct rlimit limit;
306 int resource;
307 resource = atoi(args[1]);
308 limit.rlim_cur = atoi(args[2]);
309 limit.rlim_max = atoi(args[3]);
310 return setrlimit(resource, &limit);
311 }
312
313 int do_start(int nargs, char **args)
314 {
315 struct service *svc;
316 svc = service_find_by_name(args[1]);
317 if (svc) {
318 service_start(svc);
319 }
320 return 0;
321 }
322
323 int do_stop(int nargs, char **args)
324 {
325 struct service *svc;
326 svc = service_find_by_name(args[1]);
327 if (svc) {
328 service_stop(svc);
329 }
330 return 0;
331 }
332
333 int do_restart(int nargs, char **args)
334 {
335 struct service *svc;
336 svc = service_find_by_name(args[1]);
337 if (svc) {
338 service_stop(svc);
339 service_start(svc);
340 }
341 return 0;
342 }
343
344 int do_trigger(int nargs, char **args)
345 {
346 return 0;
347 }
348
349 int do_symlink(int nargs, char **args)
350 {
351 return symlink(args[1], args[2]);
352 }
353
354 int do_sysclktz(int nargs, char **args)
355 {
356 struct timezone tz;
357
358 if (nargs != 2)
359 return -1;
360
361 memset(&tz, 0, sizeof(tz));
362 tz.tz_minuteswest = atoi(args[1]);
363 if (settimeofday(NULL, &tz))
364 return -1;
365 return 0;
366 }
367
368 int do_write(int nargs, char **args)
369 {
370 return write_file(args[1], args[2]);
371 }
372
373 int do_chown(int nargs, char **args) {
374 /* GID is optional. */
375 if (nargs == 3) {
376 if (chown(args[2], decode_uid(args[1]), -1) < 0)
377 return -errno;
378 } else if (nargs == 4) {
379 if (chown(args[3], decode_uid(args[1]), decode_uid(args[2])))
380 return -errno;
381 } else {
382 return -1;
383 }
384 return 0;
385 }
386
387 static mode_t get_mode(const char *s) {
388 mode_t mode = 0;
389 while (*s) {
390 if (*s >= '0' && *s <= '7') {
391 mode = (mode<<3) | (*s-'0');
392 } else {
393 return -1;
394 }
395 s++;
396 }
397 return mode;
398 }
399
400 int do_chmod(int nargs, char **args) {
401 mode_t mode = get_mode(args[1]);
402 if (chmod(args[2], mode) < 0) {
403 return -errno;
404 }
405 return 0;
406 }
407
408 int do_loglevel(int nargs, char **args) {
409 if (nargs == 2) {
410 log_set_level(atoi(args[1]));
411 return 0;
412 }
413 return -1;
414 }
415
416 int do_device(int nargs, char **args) {
417 int len;
418 char tmp[64];
419 char *source = args[1];
420 int prefix = 0;
421
422 if (nargs != 5)
423 return -1;
424 /* Check for wildcard '*' at the end which indicates a prefix. */
425 len = strlen(args[1]) - 1;
426 if (args[1][len] == '*') {
427 args[1][len] = '\0';
428 prefix = 1;
429 }
430 /* If path starts with mtd@ lookup the mount number. */
431 if (!strncmp(source, "mtd@", 4)) {
432 int n = mtd_name_to_number(source + 4);
433 if (n >= 0) {
434 snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n);
435 source = tmp;
436 }
437 }
438 add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]),
439 decode_uid(args[4]), prefix);
440 return 0;
441 }
+0
-626
init/devices.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #include <fcntl.h>
23 #include <dirent.h>
24 #include <unistd.h>
25 #include <string.h>
26
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <linux/netlink.h>
30 #include <private/android_filesystem_config.h>
31 #include <sys/time.h>
32 #include <asm/page.h>
33
34 #include "init.h"
35 #include "devices.h"
36
37 #define CMDLINE_PREFIX "/dev"
38 #define SYSFS_PREFIX "/sys"
39 #define FIRMWARE_DIR "/etc/firmware"
40 #define MAX_QEMU_PERM 6
41
42 struct uevent {
43 const char *action;
44 const char *path;
45 const char *subsystem;
46 const char *firmware;
47 int major;
48 int minor;
49 };
50
51 static int open_uevent_socket(void)
52 {
53 struct sockaddr_nl addr;
54 int sz = 64*1024; // XXX larger? udev uses 16MB!
55 int s;
56
57 memset(&addr, 0, sizeof(addr));
58 addr.nl_family = AF_NETLINK;
59 addr.nl_pid = getpid();
60 addr.nl_groups = 0xffffffff;
61
62 s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
63 if(s < 0)
64 return -1;
65
66 setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
67
68 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
69 close(s);
70 return -1;
71 }
72
73 return s;
74 }
75
76 struct perms_ {
77 char *name;
78 mode_t perm;
79 unsigned int uid;
80 unsigned int gid;
81 unsigned short prefix;
82 };
83 static struct perms_ devperms[] = {
84 { "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },
85 { "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },
86 { "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },
87 { "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },
88 { "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },
89 { "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },
90 { "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },
91 { "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },
92 { "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },
93
94 /* logger should be world writable (for logging) but not readable */
95 { "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },
96
97 /* these should not be world writable */
98 { "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 },
99 { "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },
100 { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
101 { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
102 { "/dev/uinput", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
103 { "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },
104 { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 },
105 { "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },
106 { "/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
107 { "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },
108 { "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },
109 { "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },
110 { "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
111 { "/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 },
112 { "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },
113 { "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },
114 { "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },
115 { "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
116 { "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },
117 { "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
118 { "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
119 { "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },
120 { "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },
121 { "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },
122 { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },
123 { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 },
124 { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },
125 { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 },
126 { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 },
127 { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
128 { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },
129 { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },
130 { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
131 { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
132 { NULL, 0, 0, 0, 0 },
133 };
134
135 /* devperms_partners list and perm_node are for hardware specific /dev entries */
136 struct perm_node {
137 struct perms_ dp;
138 struct listnode plist;
139 };
140 list_declare(devperms_partners);
141
142 /*
143 * Permission override when in emulator mode, must be parsed before
144 * system properties is initalized.
145 */
146 static int qemu_perm_count;
147 static struct perms_ qemu_perms[MAX_QEMU_PERM + 1];
148
149 int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
150 unsigned int gid, unsigned short prefix) {
151 int size;
152 struct perm_node *node = malloc(sizeof (struct perm_node));
153 if (!node)
154 return -ENOMEM;
155
156 size = strlen(name) + 1;
157 if ((node->dp.name = malloc(size)) == NULL)
158 return -ENOMEM;
159
160 memcpy(node->dp.name, name, size);
161 node->dp.perm = perm;
162 node->dp.uid = uid;
163 node->dp.gid = gid;
164 node->dp.prefix = prefix;
165
166 list_add_tail(&devperms_partners, &node->plist);
167 return 0;
168 }
169
170 void qemu_init(void) {
171 qemu_perm_count = 0;
172 memset(&qemu_perms, 0, sizeof(qemu_perms));
173 }
174
175 static int qemu_perm(const char* name, mode_t perm, unsigned int uid,
176 unsigned int gid, unsigned short prefix)
177 {
178 char *buf;
179 if (qemu_perm_count == MAX_QEMU_PERM)
180 return -ENOSPC;
181
182 buf = malloc(strlen(name) + 1);
183 if (!buf)
184 return -errno;
185
186 strlcpy(buf, name, strlen(name) + 1);
187 qemu_perms[qemu_perm_count].name = buf;
188 qemu_perms[qemu_perm_count].perm = perm;
189 qemu_perms[qemu_perm_count].uid = uid;
190 qemu_perms[qemu_perm_count].gid = gid;
191 qemu_perms[qemu_perm_count].prefix = prefix;
192
193 qemu_perm_count++;
194 return 0;
195 }
196
197 /* Permission overrides for emulator that are parsed from /proc/cmdline. */
198 void qemu_cmdline(const char* name, const char *value)
199 {
200 char *buf;
201 if (!strcmp(name, "android.ril")) {
202 /* cmd line params currently assume /dev/ prefix */
203 if (asprintf(&buf, CMDLINE_PREFIX"/%s", value) == -1) {
204 return;
205 }
206 INFO("nani- buf:: %s\n", buf);
207 qemu_perm(buf, 0660, AID_RADIO, AID_ROOT, 0);
208 }
209 }
210
211 static int get_device_perm_inner(struct perms_ *perms, const char *path,
212 unsigned *uid, unsigned *gid, mode_t *perm)
213 {
214 int i;
215 for(i = 0; perms[i].name; i++) {
216
217 if(perms[i].prefix) {
218 if(strncmp(path, perms[i].name, strlen(perms[i].name)))
219 continue;
220 } else {
221 if(strcmp(path, perms[i].name))
222 continue;
223 }
224 *uid = perms[i].uid;
225 *gid = perms[i].gid;
226 *perm = perms[i].perm;
227 return 0;
228 }
229 return -1;
230 }
231
232 /* First checks for emulator specific permissions specified in /proc/cmdline. */
233 static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
234 {
235 mode_t perm;
236
237 if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
238 return perm;
239 } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) {
240 return perm;
241 } else {
242 struct listnode *node;
243 struct perm_node *perm_node;
244 struct perms_ *dp;
245
246 /* Check partners list. */
247 list_for_each(node, &devperms_partners) {
248 perm_node = node_to_item(node, struct perm_node, plist);
249 dp = &perm_node->dp;
250
251 if (dp->prefix) {
252 if (strncmp(path, dp->name, strlen(dp->name)))
253 continue;
254 } else {
255 if (strcmp(path, dp->name))
256 continue;
257 }
258 /* Found perm in partner list. */
259 *uid = dp->uid;
260 *gid = dp->gid;
261 return dp->perm;
262 }
263 /* Default if nothing found. */
264 *uid = 0;
265 *gid = 0;
266 return 0600;
267 }
268 }
269
270 static void make_device(const char *path, int block, int major, int minor)
271 {
272 unsigned uid;
273 unsigned gid;
274 mode_t mode;
275 dev_t dev;
276
277 if(major > 255 || minor > 255)
278 return;
279
280 mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
281 dev = (major << 8) | minor;
282 mknod(path, mode, dev);
283 chown(path, uid, gid);
284 }
285
286 #ifdef LOG_UEVENTS
287
288 static inline suseconds_t get_usecs(void)
289 {
290 struct timeval tv;
291 gettimeofday(&tv, 0);
292 return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
293 }
294
295 #define log_event_print(x...) INFO(x)
296
297 #else
298
299 #define log_event_print(fmt, args...) do { } while (0)
300 #define get_usecs() 0
301
302 #endif
303
304 static void parse_event(const char *msg, struct uevent *uevent)
305 {
306 uevent->action = "";
307 uevent->path = "";
308 uevent->subsystem = "";
309 uevent->firmware = "";
310 uevent->major = -1;
311 uevent->minor = -1;
312
313 /* currently ignoring SEQNUM */
314 while(*msg) {
315 if(!strncmp(msg, "ACTION=", 7)) {
316 msg += 7;
317 uevent->action = msg;
318 } else if(!strncmp(msg, "DEVPATH=", 8)) {
319 msg += 8;
320 uevent->path = msg;
321 } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
322 msg += 10;
323 uevent->subsystem = msg;
324 } else if(!strncmp(msg, "FIRMWARE=", 9)) {
325 msg += 9;
326 uevent->firmware = msg;
327 } else if(!strncmp(msg, "MAJOR=", 6)) {
328 msg += 6;
329 uevent->major = atoi(msg);
330 } else if(!strncmp(msg, "MINOR=", 6)) {
331 msg += 6;
332 uevent->minor = atoi(msg);
333 }
334
335 /* advance to after the next \0 */
336 while(*msg++)
337 ;
338 }
339
340 log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n",
341 uevent->action, uevent->path, uevent->subsystem,
342 uevent->firmware, uevent->major, uevent->minor);
343 }
344
345 static void handle_device_event(struct uevent *uevent)
346 {
347 char devpath[96];
348 char *base, *name;
349 int block;
350
351 /* if it's not a /dev device, nothing to do */
352 if((uevent->major < 0) || (uevent->minor < 0))
353 return;
354
355 /* do we have a name? */
356 name = strrchr(uevent->path, '/');
357 if(!name)
358 return;
359 name++;
360
361 /* too-long names would overrun our buffer */
362 if(strlen(name) > 64)
363 return;
364
365 /* are we block or char? where should we live? */
366 if(!strncmp(uevent->subsystem, "block", 5)) {
367 block = 1;
368 base = "/dev/block/";
369 mkdir(base, 0755);
370 } else {
371 block = 0;
372 /* this should probably be configurable somehow */
373 if(!strncmp(uevent->subsystem, "graphics", 8)) {
374 base = "/dev/graphics/";
375 mkdir(base, 0755);
376 } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
377 base = "/dev/oncrpc/";
378 mkdir(base, 0755);
379 } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
380 base = "/dev/adsp/";
381 mkdir(base, 0755);
382 } else if(!strncmp(uevent->subsystem, "input", 5)) {
383 base = "/dev/input/";
384 mkdir(base, 0755);
385 } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
386 base = "/dev/mtd/";
387 mkdir(base, 0755);
388 } else if(!strncmp(uevent->subsystem, "misc", 4) &&
389 !strncmp(name, "log_", 4)) {
390 base = "/dev/log/";
391 mkdir(base, 0755);
392 name += 4;
393 } else
394 base = "/dev/";
395 }
396
397 snprintf(devpath, sizeof(devpath), "%s%s", base, name);
398
399 if(!strcmp(uevent->action, "add")) {
400 make_device(devpath, block, uevent->major, uevent->minor);
401 return;
402 }
403
404 if(!strcmp(uevent->action, "remove")) {
405 unlink(devpath);
406 return;
407 }
408 }
409
410 static int load_firmware(int fw_fd, int loading_fd, int data_fd)
411 {
412 struct stat st;
413 long len_to_copy;
414 int ret = 0;
415
416 if(fstat(fw_fd, &st) < 0)
417 return -1;
418 len_to_copy = st.st_size;
419
420 write(loading_fd, "1", 1); /* start transfer */
421
422 while (len_to_copy > 0) {
423 char buf[PAGE_SIZE];
424 ssize_t nr;
425
426 nr = read(fw_fd, buf, sizeof(buf));
427 if(!nr)
428 break;
429 if(nr < 0) {
430 ret = -1;
431 break;
432 }
433
434 len_to_copy -= nr;
435 while (nr > 0) {
436 ssize_t nw = 0;
437
438 nw = write(data_fd, buf + nw, nr);
439 if(nw <= 0) {
440 ret = -1;
441 goto out;
442 }
443 nr -= nw;
444 }
445 }
446
447 out:
448 if(!ret)
449 write(loading_fd, "0", 1); /* successful end of transfer */
450 else
451 write(loading_fd, "-1", 2); /* abort transfer */
452
453 return ret;
454 }
455
456 static void process_firmware_event(struct uevent *uevent)
457 {
458 char *root, *loading, *data, *file;
459 int l, loading_fd, data_fd, fw_fd;
460
461 log_event_print("firmware event { '%s', '%s' }\n",
462 uevent->path, uevent->firmware);
463
464 l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
465 if (l == -1)
466 return;
467
468 l = asprintf(&loading, "%sloading", root);
469 if (l == -1)
470 goto root_free_out;
471
472 l = asprintf(&data, "%sdata", root);
473 if (l == -1)
474 goto loading_free_out;
475
476 l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware);
477 if (l == -1)
478 goto data_free_out;
479
480 loading_fd = open(loading, O_WRONLY);
481 if(loading_fd < 0)
482 goto file_free_out;
483
484 data_fd = open(data, O_WRONLY);
485 if(data_fd < 0)
486 goto loading_close_out;
487
488 fw_fd = open(file, O_RDONLY);
489 if(fw_fd < 0)
490 goto data_close_out;
491
492 if(!load_firmware(fw_fd, loading_fd, data_fd))
493 log_event_print("firmware copy success { '%s', '%s' }\n", root, file);
494 else
495 log_event_print("firmware copy failure { '%s', '%s' }\n", root, file);
496
497 close(fw_fd);
498 data_close_out:
499 close(data_fd);
500 loading_close_out:
501 close(loading_fd);
502 file_free_out:
503 free(file);
504 data_free_out:
505 free(data);
506 loading_free_out:
507 free(loading);
508 root_free_out:
509 free(root);
510 }
511
512 static void handle_firmware_event(struct uevent *uevent)
513 {
514 pid_t pid;
515
516 if(strcmp(uevent->subsystem, "firmware"))
517 return;
518
519 if(strcmp(uevent->action, "add"))
520 return;
521
522 /* we fork, to avoid making large memory allocations in init proper */
523 pid = fork();
524 if (!pid) {
525 process_firmware_event(uevent);
526 exit(EXIT_SUCCESS);
527 }
528 }
529
530 #define UEVENT_MSG_LEN 1024
531 void handle_device_fd(int fd)
532 {
533 char msg[UEVENT_MSG_LEN+2];
534 int n;
535
536 while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
537 struct uevent uevent;
538
539 if(n == UEVENT_MSG_LEN) /* overflow -- discard */
540 continue;
541
542 msg[n] = '\0';
543 msg[n+1] = '\0';
544
545 parse_event(msg, &uevent);
546
547 handle_device_event(&uevent);
548 handle_firmware_event(&uevent);
549 }
550 }
551
552 /* Coldboot walks parts of the /sys tree and pokes the uevent files
553 ** to cause the kernel to regenerate device add events that happened
554 ** before init's device manager was started
555 **
556 ** We drain any pending events from the netlink socket every time
557 ** we poke another uevent file to make sure we don't overrun the
558 ** socket's buffer.
559 */
560
561 static void do_coldboot(int event_fd, DIR *d)
562 {
563 struct dirent *de;
564 int dfd, fd;
565
566 dfd = dirfd(d);
567
568 fd = openat(dfd, "uevent", O_WRONLY);
569 if(fd >= 0) {
570 write(fd, "add\n", 4);
571 close(fd);
572 handle_device_fd(event_fd);
573 }
574
575 while((de = readdir(d))) {
576 DIR *d2;
577
578 if(de->d_type != DT_DIR || de->d_name[0] == '.')
579 continue;
580
581 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
582 if(fd < 0)
583 continue;
584
585 d2 = fdopendir(fd);
586 if(d2 == 0)
587 close(fd);
588 else {
589 do_coldboot(event_fd, d2);
590 closedir(d2);
591 }
592 }
593 }
594
595 static void coldboot(int event_fd, const char *path)
596 {
597 DIR *d = opendir(path);
598 if(d) {
599 do_coldboot(event_fd, d);
600 closedir(d);
601 }
602 }
603
604 int device_init(void)
605 {
606 suseconds_t t0, t1;
607 int fd;
608
609 fd = open_uevent_socket();
610 if(fd < 0)
611 return -1;
612
613 fcntl(fd, F_SETFD, FD_CLOEXEC);
614 fcntl(fd, F_SETFL, O_NONBLOCK);
615
616 t0 = get_usecs();
617 coldboot(fd, "/sys/class");
618 coldboot(fd, "/sys/block");
619 coldboot(fd, "/sys/devices");
620 t1 = get_usecs();
621
622 log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
623
624 return fd;
625 }
+0
-27
init/devices.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _INIT_DEVICES_H
17 #define _INIT_DEVICES_H
18
19 extern void handle_device_fd(int fd);
20 extern int device_init(void);
21 extern void qemu_init(void);
22 extern void qemu_cmdline(const char* name, const char *value);
23 extern int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
24 unsigned int gid, unsigned short prefix);
25
26 #endif /* _INIT_DEVICES_H */
+0
-22
init/grab-bootchart.sh less more
0 #!/bin/sh
1 #
2 # this script is used to retrieve the bootchart log generated
3 # by init when compiled with INIT_BOOTCHART=true.
4 #
5 # for all details, see //device/system/init/README.BOOTCHART
6 #
7 TMPDIR=/tmp/android-bootchart
8 rm -rf $TMPDIR
9 mkdir -p $TMPDIR
10
11 LOGROOT=/data/bootchart
12 TARBALL=bootchart.tgz
13
14 FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
15
16 for f in $FILES; do
17 adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
18 done
19 (cd $TMPDIR && tar -czf $TARBALL $FILES)
20 cp -f $TMPDIR/$TARBALL ./$TARBALL
21 echo "look at $TARBALL"
+0
-989
init/init.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 #include <signal.h>
23 #include <sys/wait.h>
24 #include <sys/mount.h>
25 #include <sys/stat.h>
26 #include <sys/poll.h>
27 #include <time.h>
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <mtd/mtd-user.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <sys/reboot.h>
35
36 #include <cutils/sockets.h>
37 #include <termios.h>
38 #include <linux/kd.h>
39 #include <linux/keychord.h>
40
41 #include <sys/system_properties.h>
42
43 #include "devices.h"
44 #include "init.h"
45 #include "property_service.h"
46 #include "bootchart.h"
47
48 static int property_triggers_enabled = 0;
49
50 #if BOOTCHART
51 static int bootchart_count;
52 #endif
53
54 static char console[32];
55 static char serialno[32];
56 static char bootmode[32];
57 static char baseband[32];
58 static char carrier[32];
59 static char bootloader[32];
60 static char hardware[32];
61 static unsigned revision = 0;
62 static char qemu[32];
63 static struct input_keychord *keychords = 0;
64 static int keychords_count = 0;
65 static int keychords_length = 0;
66
67 static void drain_action_queue(void);
68
69 static void notify_service_state(const char *name, const char *state)
70 {
71 char pname[PROP_NAME_MAX];
72 int len = strlen(name);
73 if ((len + 10) > PROP_NAME_MAX)
74 return;
75 snprintf(pname, sizeof(pname), "init.svc.%s", name);
76 property_set(pname, state);
77 }
78
79 static int have_console;
80 static char *console_name = "/dev/console";
81 static time_t process_needs_restart;
82
83 static const char *ENV[32];
84
85 /* add_environment - add "key=value" to the current environment */
86 int add_environment(const char *key, const char *val)
87 {
88 int n;
89
90 for (n = 0; n < 31; n++) {
91 if (!ENV[n]) {
92 size_t len = strlen(key) + strlen(val) + 2;
93 char *entry = malloc(len);
94 snprintf(entry, len, "%s=%s", key, val);
95 ENV[n] = entry;
96 return 0;
97 }
98 }
99
100 return 1;
101 }
102
103 static void zap_stdio(void)
104 {
105 int fd;
106 fd = open("/dev/null", O_RDWR);
107 dup2(fd, 0);
108 dup2(fd, 1);
109 dup2(fd, 2);
110 close(fd);
111 }
112
113 static void open_console()
114 {
115 int fd;
116 if ((fd = open(console_name, O_RDWR)) < 0) {
117 fd = open("/dev/null", O_RDWR);
118 }
119 dup2(fd, 0);
120 dup2(fd, 1);
121 dup2(fd, 2);
122 close(fd);
123 }
124
125 /*
126 * gettime() - returns the time in seconds of the system's monotonic clock or
127 * zero on error.
128 */
129 static time_t gettime(void)
130 {
131 struct timespec ts;
132 int ret;
133
134 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
135 if (ret < 0) {
136 ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
137 return 0;
138 }
139
140 return ts.tv_sec;
141 }
142
143 static void publish_socket(const char *name, int fd)
144 {
145 char key[64] = ANDROID_SOCKET_ENV_PREFIX;
146 char val[64];
147
148 strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
149 name,
150 sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
151 snprintf(val, sizeof(val), "%d", fd);
152 add_environment(key, val);
153
154 /* make sure we don't close-on-exec */
155 fcntl(fd, F_SETFD, 0);
156 }
157
158 void service_start(struct service *svc)
159 {
160 struct stat s;
161 pid_t pid;
162 int needs_console;
163 int n;
164
165 /* starting a service removes it from the disabled
166 * state and immediately takes it out of the restarting
167 * state if it was in there
168 */
169 svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));
170 svc->time_started = 0;
171
172 /* running processes require no additional work -- if
173 * they're in the process of exiting, we've ensured
174 * that they will immediately restart on exit, unless
175 * they are ONESHOT
176 */
177 if (svc->flags & SVC_RUNNING) {
178 return;
179 }
180
181 needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
182 if (needs_console && (!have_console)) {
183 ERROR("service '%s' requires console\n", svc->name);
184 svc->flags |= SVC_DISABLED;
185 return;
186 }
187
188 if (stat(svc->args[0], &s) != 0) {
189 ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
190 svc->flags |= SVC_DISABLED;
191 return;
192 }
193
194 NOTICE("starting '%s'\n", svc->name);
195
196 pid = fork();
197
198 if (pid == 0) {
199 struct socketinfo *si;
200 struct svcenvinfo *ei;
201 char tmp[32];
202 int fd, sz;
203
204 get_property_workspace(&fd, &sz);
205 sprintf(tmp, "%d,%d", dup(fd), sz);
206 add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
207
208 for (ei = svc->envvars; ei; ei = ei->next)
209 add_environment(ei->name, ei->value);
210
211 for (si = svc->sockets; si; si = si->next) {
212 int s = create_socket(si->name,
213 !strcmp(si->type, "dgram") ?
214 SOCK_DGRAM : SOCK_STREAM,
215 si->perm, si->uid, si->gid);
216 if (s >= 0) {
217 publish_socket(si->name, s);
218 }
219 }
220
221 if (needs_console) {
222 setsid();
223 open_console();
224 } else {
225 zap_stdio();
226 }
227
228 #if 0
229 for (n = 0; svc->args[n]; n++) {
230 INFO("args[%d] = '%s'\n", n, svc->args[n]);
231 }
232 for (n = 0; ENV[n]; n++) {
233 INFO("env[%d] = '%s'\n", n, ENV[n]);
234 }
235 #endif
236
237 setpgid(0, getpid());
238
239 /* as requested, set our gid, supplemental gids, and uid */
240 if (svc->gid) {
241 setgid(svc->gid);
242 }
243 if (svc->nr_supp_gids) {
244 setgroups(svc->nr_supp_gids, svc->supp_gids);
245 }
246 if (svc->uid) {
247 setuid(svc->uid);
248 }
249
250 execve(svc->args[0], (char**) svc->args, (char**) ENV);
251 _exit(127);
252 }
253
254 if (pid < 0) {
255 ERROR("failed to start '%s'\n", svc->name);
256 svc->pid = 0;
257 return;
258 }
259
260 svc->time_started = gettime();
261 svc->pid = pid;
262 svc->flags |= SVC_RUNNING;
263
264 notify_service_state(svc->name, "running");
265 }
266
267 void service_stop(struct service *svc)
268 {
269 /* we are no longer running, nor should we
270 * attempt to restart
271 */
272 svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
273
274 /* if the service has not yet started, prevent
275 * it from auto-starting with its class
276 */
277 svc->flags |= SVC_DISABLED;
278
279 if (svc->pid) {
280 NOTICE("service '%s' is being killed\n", svc->name);
281 kill(-svc->pid, SIGTERM);
282 notify_service_state(svc->name, "stopping");
283 } else {
284 notify_service_state(svc->name, "stopped");
285 }
286 }
287
288 void property_changed(const char *name, const char *value)
289 {
290 if (property_triggers_enabled) {
291 queue_property_triggers(name, value);
292 drain_action_queue();
293 }
294 }
295
296 #define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
297 #define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
298
299 static int wait_for_one_process(int block)
300 {
301 pid_t pid;
302 int status;
303 struct service *svc;
304 struct socketinfo *si;
305 time_t now;
306 struct listnode *node;
307 struct command *cmd;
308
309 while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
310 if (pid <= 0) return -1;
311 INFO("waitpid returned pid %d, status = %08x\n", pid, status);
312
313 svc = service_find_by_pid(pid);
314 if (!svc) {
315 ERROR("untracked pid %d exited\n", pid);
316 return 0;
317 }
318
319 NOTICE("process '%s', pid %d exited\n", svc->name, pid);
320
321 if (!(svc->flags & SVC_ONESHOT)) {
322 kill(-pid, SIGKILL);
323 NOTICE("process '%s' killing any children in process group\n", svc->name);
324 }
325
326 /* remove any sockets we may have created */
327 for (si = svc->sockets; si; si = si->next) {
328 char tmp[128];
329 snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
330 unlink(tmp);
331 }
332
333 svc->pid = 0;
334 svc->flags &= (~SVC_RUNNING);
335
336 /* oneshot processes go into the disabled state on exit */
337 if (svc->flags & SVC_ONESHOT) {
338 svc->flags |= SVC_DISABLED;
339 }
340
341 /* disabled processes do not get restarted automatically */
342 if (svc->flags & SVC_DISABLED) {
343 notify_service_state(svc->name, "stopped");
344 return 0;
345 }
346
347 now = gettime();
348 if (svc->flags & SVC_CRITICAL) {
349 if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
350 if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
351 ERROR("critical process '%s' exited %d times in %d minutes; "
352 "rebooting into recovery mode\n", svc->name,
353 CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
354 sync();
355 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
356 LINUX_REBOOT_CMD_RESTART2, "recovery");
357 return 0;
358 }
359 } else {
360 svc->time_crashed = now;
361 svc->nr_crashed = 1;
362 }
363 }
364
365 /* Execute all onrestart commands for this service. */
366 list_for_each(node, &svc->onrestart.commands) {
367 cmd = node_to_item(node, struct command, clist);
368 cmd->func(cmd->nargs, cmd->args);
369 }
370 svc->flags |= SVC_RESTARTING;
371 notify_service_state(svc->name, "restarting");
372 return 0;
373 }
374
375 static void restart_service_if_needed(struct service *svc)
376 {
377 time_t next_start_time = svc->time_started + 5;
378
379 if (next_start_time <= gettime()) {
380 svc->flags &= (~SVC_RESTARTING);
381 service_start(svc);
382 return;
383 }
384
385 if ((next_start_time < process_needs_restart) ||
386 (process_needs_restart == 0)) {
387 process_needs_restart = next_start_time;
388 }
389 }
390
391 static void restart_processes()
392 {
393 process_needs_restart = 0;
394 service_for_each_flags(SVC_RESTARTING,
395 restart_service_if_needed);
396 }
397
398 static int signal_fd = -1;
399
400 static void sigchld_handler(int s)
401 {
402 write(signal_fd, &s, 1);
403 }
404
405 static void msg_start(const char *name)
406 {
407 struct service *svc = service_find_by_name(name);
408
409 if (svc) {
410 service_start(svc);
411 } else {
412 ERROR("no such service '%s'\n", name);
413 }
414 }
415
416 static void msg_stop(const char *name)
417 {
418 struct service *svc = service_find_by_name(name);
419
420 if (svc) {
421 service_stop(svc);
422 } else {
423 ERROR("no such service '%s'\n");
424 }
425 }
426
427 void handle_control_message(const char *msg, const char *arg)
428 {
429 if (!strcmp(msg,"start")) {
430 msg_start(arg);
431 } else if (!strcmp(msg,"stop")) {
432 msg_stop(arg);
433 } else {
434 ERROR("unknown control msg '%s'\n", msg);
435 }
436 }
437
438 #define MAX_MTD_PARTITIONS 16
439
440 static struct {
441 char name[16];
442 int number;
443 } mtd_part_map[MAX_MTD_PARTITIONS];
444
445 static int mtd_part_count = -1;
446
447 static void find_mtd_partitions(void)
448 {
449 int fd;
450 char buf[1024];
451 char *pmtdbufp;
452 ssize_t pmtdsize;
453 int r;
454
455 fd = open("/proc/mtd", O_RDONLY);
456 if (fd < 0)
457 return;
458
459 buf[sizeof(buf) - 1] = '\0';
460 pmtdsize = read(fd, buf, sizeof(buf) - 1);
461 pmtdbufp = buf;
462 while (pmtdsize > 0) {
463 int mtdnum, mtdsize, mtderasesize;
464 char mtdname[16];
465 mtdname[0] = '\0';
466 mtdnum = -1;
467 r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
468 &mtdnum, &mtdsize, &mtderasesize, mtdname);
469 if ((r == 4) && (mtdname[0] == '"')) {
470 char *x = strchr(mtdname + 1, '"');
471 if (x) {
472 *x = 0;
473 }
474 INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
475 if (mtd_part_count < MAX_MTD_PARTITIONS) {
476 strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
477 mtd_part_map[mtd_part_count].number = mtdnum;
478 mtd_part_count++;
479 } else {
480 ERROR("too many mtd partitions\n");
481 }
482 }
483 while (pmtdsize > 0 && *pmtdbufp != '\n') {
484 pmtdbufp++;
485 pmtdsize--;
486 }
487 if (pmtdsize > 0) {
488 pmtdbufp++;
489 pmtdsize--;
490 }
491 }
492 close(fd);
493 }
494
495 int mtd_name_to_number(const char *name)
496 {
497 int n;
498 if (mtd_part_count < 0) {
499 mtd_part_count = 0;
500 find_mtd_partitions();
501 }
502 for (n = 0; n < mtd_part_count; n++) {
503 if (!strcmp(name, mtd_part_map[n].name)) {
504 return mtd_part_map[n].number;
505 }
506 }
507 return -1;
508 }
509
510 static void import_kernel_nv(char *name, int in_qemu)
511 {
512 char *value = strchr(name, '=');
513
514 if (value == 0) return;
515 *value++ = 0;
516 if (*name == 0) return;
517
518 if (!in_qemu)
519 {
520 /* on a real device, white-list the kernel options */
521 if (!strcmp(name,"qemu")) {
522 strlcpy(qemu, value, sizeof(qemu));
523 } else if (!strcmp(name,"androidboot.console")) {
524 strlcpy(console, value, sizeof(console));
525 } else if (!strcmp(name,"androidboot.mode")) {
526 strlcpy(bootmode, value, sizeof(bootmode));
527 } else if (!strcmp(name,"androidboot.serialno")) {
528 strlcpy(serialno, value, sizeof(serialno));
529 } else if (!strcmp(name,"androidboot.baseband")) {
530 strlcpy(baseband, value, sizeof(baseband));
531 } else if (!strcmp(name,"androidboot.carrier")) {
532 strlcpy(carrier, value, sizeof(carrier));
533 } else if (!strcmp(name,"androidboot.bootloader")) {
534 strlcpy(bootloader, value, sizeof(bootloader));
535 } else if (!strcmp(name,"androidboot.hardware")) {
536 strlcpy(hardware, value, sizeof(hardware));
537 } else {
538 qemu_cmdline(name, value);
539 }
540 } else {
541 /* in the emulator, export any kernel option with the
542 * ro.kernel. prefix */
543 char buff[32];
544 int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
545 if (len < (int)sizeof(buff)) {
546 property_set( buff, value );
547 }
548 }
549 }
550
551 static void import_kernel_cmdline(int in_qemu)
552 {
553 char cmdline[1024];
554 char *ptr;
555 int fd;
556
557 fd = open("/proc/cmdline", O_RDONLY);
558 if (fd >= 0) {
559 int n = read(fd, cmdline, 1023);
560 if (n < 0) n = 0;
561
562 /* get rid of trailing newline, it happens */
563 if (n > 0 && cmdline[n-1] == '\n') n--;
564
565 cmdline[n] = 0;
566 close(fd);
567 } else {
568 cmdline[0] = 0;
569 }
570
571 ptr = cmdline;
572 while (ptr && *ptr) {
573 char *x = strchr(ptr, ' ');
574 if (x != 0) *x++ = 0;
575 import_kernel_nv(ptr, in_qemu);
576 ptr = x;
577 }
578
579 /* don't expose the raw commandline to nonpriv processes */
580 chmod("/proc/cmdline", 0440);
581 }
582
583 static void get_hardware_name(void)
584 {
585 char data[1024];
586 int fd, n;
587 char *x, *hw, *rev;
588
589 /* Hardware string was provided on kernel command line */
590 if (hardware[0])
591 return;
592
593 fd = open("/proc/cpuinfo", O_RDONLY);
594 if (fd < 0) return;
595
596 n = read(fd, data, 1023);
597 close(fd);
598 if (n < 0) return;
599
600 data[n] = 0;
601 hw = strstr(data, "\nHardware");
602 rev = strstr(data, "\nRevision");
603
604 if (hw) {
605 x = strstr(hw, ": ");
606 if (x) {
607 x += 2;
608 n = 0;
609 while (*x && !isspace(*x)) {
610 hardware[n++] = tolower(*x);
611 x++;
612 if (n == 31) break;
613 }
614 hardware[n] = 0;
615 }
616 }
617
618 if (rev) {
619 x = strstr(rev, ": ");
620 if (x) {
621 revision = strtoul(x + 2, 0, 16);
622 }
623 }
624 }
625
626 static void drain_action_queue(void)
627 {
628 struct listnode *node;
629 struct command *cmd;
630 struct action *act;
631 int ret;
632
633 while ((act = action_remove_queue_head())) {
634 INFO("processing action %p (%s)\n", act, act->name);
635 list_for_each(node, &act->commands) {
636 cmd = node_to_item(node, struct command, clist);
637 ret = cmd->func(cmd->nargs, cmd->args);
638 INFO("command '%s' r=%d\n", cmd->args[0], ret);
639 }
640 }
641 }
642
643 void open_devnull_stdio(void)
644 {
645 int fd;
646 static const char *name = "/dev/__null__";
647 if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
648 fd = open(name, O_RDWR);
649 unlink(name);
650 if (fd >= 0) {
651 dup2(fd, 0);
652 dup2(fd, 1);
653 dup2(fd, 2);
654 if (fd > 2) {
655 close(fd);
656 }
657 return;
658 }
659 }
660
661 exit(1);
662 }
663
664 void add_service_keycodes(struct service *svc)
665 {
666 struct input_keychord *keychord;
667 int i, size;
668
669 if (svc->keycodes) {
670 /* add a new keychord to the list */
671 size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
672 keychords = realloc(keychords, keychords_length + size);
673 if (!keychords) {
674 ERROR("could not allocate keychords\n");
675 keychords_length = 0;
676 keychords_count = 0;
677 return;
678 }
679
680 keychord = (struct input_keychord *)((char *)keychords + keychords_length);
681 keychord->version = KEYCHORD_VERSION;
682 keychord->id = keychords_count + 1;
683 keychord->count = svc->nkeycodes;
684 svc->keychord_id = keychord->id;
685
686 for (i = 0; i < svc->nkeycodes; i++) {
687 keychord->keycodes[i] = svc->keycodes[i];
688 }
689 keychords_count++;
690 keychords_length += size;
691 }
692 }
693
694 int open_keychord()
695 {
696 int fd, ret;
697
698 service_for_each(add_service_keycodes);
699
700 /* nothing to do if no services require keychords */
701 if (!keychords)
702 return -1;
703
704 fd = open("/dev/keychord", O_RDWR);
705 if (fd < 0) {
706 ERROR("could not open /dev/keychord\n");
707 return fd;
708 }
709 fcntl(fd, F_SETFD, FD_CLOEXEC);
710
711 ret = write(fd, keychords, keychords_length);
712 if (ret != keychords_length) {
713 ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
714 close(fd);
715 fd = -1;
716 }
717
718 free(keychords);
719 keychords = 0;
720
721 return fd;
722 }
723
724 void handle_keychord(int fd)
725 {
726 struct service *svc;
727 int ret;
728 __u16 id;
729
730 ret = read(fd, &id, sizeof(id));
731 if (ret != sizeof(id)) {
732 ERROR("could not read keychord id\n");
733 return;
734 }
735
736 svc = service_find_by_keychord(id);
737 if (svc) {
738 INFO("starting service %s from keychord\n", svc->name);
739 service_start(svc);
740 } else {
741 ERROR("service for keychord %d not found\n", id);
742 }
743 }
744
745 int main(int argc, char **argv)
746 {
747 int device_fd = -1;
748 int property_set_fd = -1;
749 int signal_recv_fd = -1;
750 int keychord_fd = -1;
751 int fd_count;
752 int s[2];
753 int fd;
754 struct sigaction act;
755 char tmp[PROP_VALUE_MAX];
756 struct pollfd ufds[4];
757 char *tmpdev;
758 char* debuggable;
759
760 act.sa_handler = sigchld_handler;
761 act.sa_flags = SA_NOCLDSTOP;
762 act.sa_mask = 0;
763 act.sa_restorer = NULL;
764 sigaction(SIGCHLD, &act, 0);
765
766 /* clear the umask */
767 umask(0);
768
769 /* Get the basic filesystem setup we need put
770 * together in the initramdisk on / and then we'll
771 * let the rc file figure out the rest.
772 */
773 mkdir("/dev", 0755);
774 mkdir("/proc", 0755);
775 mkdir("/sys", 0755);
776
777 mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
778 mkdir("/dev/pts", 0755);
779 mkdir("/dev/socket", 0755);
780 mount("devpts", "/dev/pts", "devpts", 0, NULL);
781 mount("proc", "/proc", "proc", 0, NULL);
782 mount("sysfs", "/sys", "sysfs", 0, NULL);
783
784 /* We must have some place other than / to create the
785 * device nodes for kmsg and null, otherwise we won't
786 * be able to remount / read-only later on.
787 * Now that tmpfs is mounted on /dev, we can actually
788 * talk to the outside world.
789 */
790 open_devnull_stdio();
791 log_init();
792
793 INFO("reading config file\n");
794 parse_config_file("/init.rc");
795
796 /* pull the kernel commandline and ramdisk properties file in */
797 qemu_init();
798 import_kernel_cmdline(0);
799
800 get_hardware_name();
801 snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
802 parse_config_file(tmp);
803
804 action_for_each_trigger("early-init", action_add_queue_tail);
805 drain_action_queue();
806
807 INFO("device init\n");
808 device_fd = device_init();
809
810 property_init();
811
812 // only listen for keychords if ro.debuggable is true
813 debuggable = property_get("ro.debuggable");
814 if (debuggable && !strcmp(debuggable, "1")) {
815 keychord_fd = open_keychord();
816 }
817
818 if (console[0]) {
819 snprintf(tmp, sizeof(tmp), "/dev/%s", console);
820 console_name = strdup(tmp);
821 }
822
823 fd = open(console_name, O_RDWR);
824 if (fd >= 0)
825 have_console = 1;
826 close(fd);
827
828 if( load_565rle_image(INIT_IMAGE_FILE) ) {
829 fd = open("/dev/tty0", O_WRONLY);
830 if (fd >= 0) {
831 const char *msg;
832 msg = "\n"
833 "\n"
834 "\n"
835 "\n"
836 "\n"
837 "\n"
838 "\n" // console is 40 cols x 30 lines
839 "\n"
840 "\n"
841 "\n"
842 "\n"
843 "\n"
844 "\n"
845 "\n"
846 " A N D R O I D ";
847 write(fd, msg, strlen(msg));
848 close(fd);
849 }
850 }
851
852 if (qemu[0])
853 import_kernel_cmdline(1);
854
855 if (!strcmp(bootmode,"factory"))
856 property_set("ro.factorytest", "1");
857 else if (!strcmp(bootmode,"factory2"))
858 property_set("ro.factorytest", "2");
859 else
860 property_set("ro.factorytest", "0");
861
862 property_set("ro.serialno", serialno[0] ? serialno : "");
863 property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
864 property_set("ro.baseband", baseband[0] ? baseband : "unknown");
865 property_set("ro.carrier", carrier[0] ? carrier : "unknown");
866 property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
867
868 property_set("ro.hardware", hardware);
869 snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
870 property_set("ro.revision", tmp);
871
872 /* execute all the boot actions to get us started */
873 action_for_each_trigger("init", action_add_queue_tail);
874 drain_action_queue();
875
876 /* read any property files on system or data and
877 * fire up the property service. This must happen
878 * after the ro.foo properties are set above so
879 * that /data/local.prop cannot interfere with them.
880 */
881 property_set_fd = start_property_service();
882
883 /* create a signalling mechanism for the sigchld handler */
884 if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
885 signal_fd = s[0];
886 signal_recv_fd = s[1];
887 fcntl(s[0], F_SETFD, FD_CLOEXEC);
888 fcntl(s[0], F_SETFL, O_NONBLOCK);
889 fcntl(s[1], F_SETFD, FD_CLOEXEC);
890 fcntl(s[1], F_SETFL, O_NONBLOCK);
891 }
892
893 /* make sure we actually have all the pieces we need */
894 if ((device_fd < 0) ||
895 (property_set_fd < 0) ||
896 (signal_recv_fd < 0)) {
897 ERROR("init startup failure\n");
898 return 1;
899 }
900
901 /* execute all the boot actions to get us started */
902 action_for_each_trigger("early-boot", action_add_queue_tail);
903 action_for_each_trigger("boot", action_add_queue_tail);
904 drain_action_queue();
905
906 /* run all property triggers based on current state of the properties */
907 queue_all_property_triggers();
908 drain_action_queue();
909
910 /* enable property triggers */
911 property_triggers_enabled = 1;
912
913 ufds[0].fd = device_fd;
914 ufds[0].events = POLLIN;
915 ufds[1].fd = property_set_fd;
916 ufds[1].events = POLLIN;
917 ufds[2].fd = signal_recv_fd;
918 ufds[2].events = POLLIN;
919 fd_count = 3;
920
921 if (keychord_fd > 0) {
922 ufds[3].fd = keychord_fd;
923 ufds[3].events = POLLIN;
924 fd_count++;
925 } else {
926 ufds[3].events = 0;
927 ufds[3].revents = 0;
928 }
929
930 #if BOOTCHART
931 bootchart_count = bootchart_init();
932 if (bootchart_count < 0) {
933 ERROR("bootcharting init failure\n");
934 } else if (bootchart_count > 0) {
935 NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
936 } else {
937 NOTICE("bootcharting ignored\n");
938 }
939 #endif
940
941 for(;;) {
942 int nr, i, timeout = -1;
943
944 for (i = 0; i < fd_count; i++)
945 ufds[i].revents = 0;
946
947 drain_action_queue();
948 restart_processes();
949
950 if (process_needs_restart) {
951 timeout = (process_needs_restart - gettime()) * 1000;
952 if (timeout < 0)
953 timeout = 0;
954 }
955
956 #if BOOTCHART
957 if (bootchart_count > 0) {
958 if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
959 timeout = BOOTCHART_POLLING_MS;
960 if (bootchart_step() < 0 || --bootchart_count == 0) {
961 bootchart_finish();
962 bootchart_count = 0;
963 }
964 }
965 #endif
966 nr = poll(ufds, fd_count, timeout);
967 if (nr <= 0)
968 continue;
969
970 if (ufds[2].revents == POLLIN) {
971 /* we got a SIGCHLD - reap and restart as needed */
972 read(signal_recv_fd, tmp, sizeof(tmp));
973 while (!wait_for_one_process(0))
974 ;
975 continue;
976 }
977
978 if (ufds[0].revents == POLLIN)
979 handle_device_fd(device_fd);
980
981 if (ufds[1].revents == POLLIN)
982 handle_property_set_fd(property_set_fd);
983 if (ufds[3].revents == POLLIN)
984 handle_keychord(keychord_fd);
985 }
986
987 return 0;
988 }
+0
-174
init/init.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _INIT_INIT_H
17 #define _INIT_INIT_H
18
19 int mtd_name_to_number(const char *name);
20
21 void handle_control_message(const char *msg, const char *arg);
22
23 int create_socket(const char *name, int type, mode_t perm,
24 uid_t uid, gid_t gid);
25
26 void *read_file(const char *fn, unsigned *_sz);
27
28 void log_init(void);
29 void log_set_level(int level);
30 void log_close(void);
31 void log_write(int level, const char *fmt, ...);
32
33 #define ERROR(x...) log_write(3, "<3>init: " x)
34 #define NOTICE(x...) log_write(5, "<5>init: " x)
35 #define INFO(x...) log_write(6, "<6>init: " x)
36
37 #define LOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */
38 #define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */
39
40 unsigned int decode_uid(const char *s);
41
42 struct listnode
43 {
44 struct listnode *next;
45 struct listnode *prev;
46 };
47
48 #define node_to_item(node, container, member) \
49 (container *) (((char*) (node)) - offsetof(container, member))
50
51 #define list_declare(name) \
52 struct listnode name = { \
53 .next = &name, \
54 .prev = &name, \
55 }
56
57 #define list_for_each(node, list) \
58 for (node = (list)->next; node != (list); node = node->next)
59
60 void list_init(struct listnode *list);
61 void list_add_tail(struct listnode *list, struct listnode *item);
62 void list_remove(struct listnode *item);
63
64 #define list_empty(list) ((list) == (list)->next)
65 #define list_head(list) ((list)->next)
66 #define list_tail(list) ((list)->prev)
67
68 struct command
69 {
70 /* list of commands in an action */
71 struct listnode clist;
72
73 int (*func)(int nargs, char **args);
74 int nargs;
75 char *args[1];
76 };
77
78 struct action {
79 /* node in list of all actions */
80 struct listnode alist;
81 /* node in the queue of pending actions */
82 struct listnode qlist;
83 /* node in list of actions for a trigger */
84 struct listnode tlist;
85
86 unsigned hash;
87 const char *name;
88
89 struct listnode commands;
90 struct command *current;
91 };
92
93 struct socketinfo {
94 struct socketinfo *next;
95 const char *name;
96 const char *type;
97 uid_t uid;
98 gid_t gid;
99 int perm;
100 };
101
102 struct svcenvinfo {
103 struct svcenvinfo *next;
104 const char *name;
105 const char *value;
106 };
107
108 #define SVC_DISABLED 0x01 /* do not autostart with class */
109 #define SVC_ONESHOT 0x02 /* do not restart on exit */
110 #define SVC_RUNNING 0x04 /* currently active */
111 #define SVC_RESTARTING 0x08 /* waiting to restart */
112 #define SVC_CONSOLE 0x10 /* requires console */
113 #define SVC_CRITICAL 0x20 /* will reboot into recovery if keeps crashing */
114
115 #define NR_SVC_SUPP_GIDS 6 /* six supplementary groups */
116
117 struct service {
118 /* list of all services */
119 struct listnode slist;
120
121 const char *name;
122 const char *classname;
123
124 unsigned flags;
125 pid_t pid;
126 time_t time_started; /* time of last start */
127 time_t time_crashed; /* first crash within inspection window */
128 int nr_crashed; /* number of times crashed within window */
129
130 uid_t uid;
131 gid_t gid;
132 gid_t supp_gids[NR_SVC_SUPP_GIDS];
133 size_t nr_supp_gids;
134
135 struct socketinfo *sockets;
136 struct svcenvinfo *envvars;
137
138 int nargs;
139 char *args[1];
140 struct action onrestart; /* Actions to execute on restart. */
141
142 /* keycodes for triggering this service via /dev/keychord */
143 int *keycodes;
144 int nkeycodes;
145 int keychord_id;
146 };
147
148 int parse_config_file(const char *fn);
149
150 struct service *service_find_by_name(const char *name);
151 struct service *service_find_by_pid(pid_t pid);
152 struct service *service_find_by_keychord(int keychord_id);
153 void service_for_each(void (*func)(struct service *svc));
154 void service_for_each_class(const char *classname,
155 void (*func)(struct service *svc));
156 void service_for_each_flags(unsigned matchflags,
157 void (*func)(struct service *svc));
158 void service_stop(struct service *svc);
159 void service_start(struct service *svc);
160 void property_changed(const char *name, const char *value);
161
162 struct action *action_remove_queue_head(void);
163 void action_add_queue_tail(struct action *act);
164 void action_for_each_trigger(const char *trigger,
165 void (*func)(struct action *act));
166 void queue_property_triggers(const char *name, const char *value);
167 void queue_all_property_triggers();
168
169 #define INIT_IMAGE_FILE "/initlogo.rle"
170
171 int load_565rle_image( char *file_name );
172
173 #endif /* _INIT_INIT_H */
+0
-78
init/keywords.h less more
0
1 #ifndef KEYWORD
2 int do_class_start(int nargs, char **args);
3 int do_class_stop(int nargs, char **args);
4 int do_domainname(int nargs, char **args);
5 int do_exec(int nargs, char **args);
6 int do_export(int nargs, char **args);
7 int do_hostname(int nargs, char **args);
8 int do_ifup(int nargs, char **args);
9 int do_insmod(int nargs, char **args);
10 int do_import(int nargs, char **args);
11 int do_mkdir(int nargs, char **args);
12 int do_mount(int nargs, char **args);
13 int do_restart(int nargs, char **args);
14 int do_setkey(int nargs, char **args);
15 int do_setprop(int nargs, char **args);
16 int do_setrlimit(int nargs, char **args);
17 int do_start(int nargs, char **args);
18 int do_stop(int nargs, char **args);
19 int do_trigger(int nargs, char **args);
20 int do_symlink(int nargs, char **args);
21 int do_sysclktz(int nargs, char **args);
22 int do_write(int nargs, char **args);
23 int do_chown(int nargs, char **args);
24 int do_chmod(int nargs, char **args);
25 int do_loglevel(int nargs, char **args);
26 int do_device(int nargs, char **args);
27 #define __MAKE_KEYWORD_ENUM__
28 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
29 enum {
30 K_UNKNOWN,
31 #endif
32 KEYWORD(capability, OPTION, 0, 0)
33 KEYWORD(class, OPTION, 0, 0)
34 KEYWORD(class_start, COMMAND, 1, do_class_start)
35 KEYWORD(class_stop, COMMAND, 1, do_class_stop)
36 KEYWORD(console, OPTION, 0, 0)
37 KEYWORD(critical, OPTION, 0, 0)
38 KEYWORD(disabled, OPTION, 0, 0)
39 KEYWORD(domainname, COMMAND, 1, do_domainname)
40 KEYWORD(exec, COMMAND, 1, do_exec)
41 KEYWORD(export, COMMAND, 2, do_export)
42 KEYWORD(group, OPTION, 0, 0)
43 KEYWORD(hostname, COMMAND, 1, do_hostname)
44 KEYWORD(ifup, COMMAND, 1, do_ifup)
45 KEYWORD(insmod, COMMAND, 1, do_insmod)
46 KEYWORD(import, COMMAND, 1, do_import)
47 KEYWORD(keycodes, OPTION, 0, 0)
48 KEYWORD(mkdir, COMMAND, 1, do_mkdir)
49 KEYWORD(mount, COMMAND, 3, do_mount)
50 KEYWORD(on, SECTION, 0, 0)
51 KEYWORD(oneshot, OPTION, 0, 0)
52 KEYWORD(onrestart, OPTION, 0, 0)
53 KEYWORD(restart, COMMAND, 1, do_restart)
54 KEYWORD(service, SECTION, 0, 0)
55 KEYWORD(setenv, OPTION, 2, 0)
56 KEYWORD(setkey, COMMAND, 0, do_setkey)
57 KEYWORD(setprop, COMMAND, 2, do_setprop)
58 KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
59 KEYWORD(socket, OPTION, 0, 0)
60 KEYWORD(start, COMMAND, 1, do_start)
61 KEYWORD(stop, COMMAND, 1, do_stop)
62 KEYWORD(trigger, COMMAND, 1, do_trigger)
63 KEYWORD(symlink, COMMAND, 1, do_symlink)
64 KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
65 KEYWORD(user, OPTION, 0, 0)
66 KEYWORD(write, COMMAND, 2, do_write)
67 KEYWORD(chown, COMMAND, 2, do_chown)
68 KEYWORD(chmod, COMMAND, 2, do_chmod)
69 KEYWORD(loglevel, COMMAND, 1, do_loglevel)
70 KEYWORD(device, COMMAND, 4, do_device)
71 #ifdef __MAKE_KEYWORD_ENUM__
72 KEYWORD_COUNT,
73 };
74 #undef __MAKE_KEYWORD_ENUM__
75 #undef KEYWORD
76 #endif
77
+0
-163
init/logo.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #include <linux/fb.h>
25 #include <linux/kd.h>
26
27 #include "init.h"
28
29 #ifdef ANDROID
30 #include <cutils/memory.h>
31 #else
32 void android_memset16(void *_ptr, unsigned short val, unsigned count)
33 {
34 unsigned short *ptr = _ptr;
35 count >>= 1;
36 while(count--)
37 *ptr++ = val;
38 }
39 #endif
40
41 struct FB {
42 unsigned short *bits;
43 unsigned size;
44 int fd;
45 struct fb_fix_screeninfo fi;
46 struct fb_var_screeninfo vi;
47 };
48
49 #define fb_width(fb) ((fb)->vi.xres)
50 #define fb_height(fb) ((fb)->vi.yres)
51 #define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2)
52
53 static int fb_open(struct FB *fb)
54 {
55 fb->fd = open("/dev/graphics/fb0", O_RDWR);
56 if (fb->fd < 0)
57 return -1;
58
59 if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
60 goto fail;
61 if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
62 goto fail;
63
64 fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE,
65 MAP_SHARED, fb->fd, 0);
66 if (fb->bits == MAP_FAILED)
67 goto fail;
68
69 return 0;
70
71 fail:
72 close(fb->fd);
73 return -1;
74 }
75
76 static void fb_close(struct FB *fb)
77 {
78 munmap(fb->bits, fb_size(fb));
79 close(fb->fd);
80 }
81
82 /* there's got to be a more portable way to do this ... */
83 static void fb_update(struct FB *fb)
84 {
85 fb->vi.yoffset = 1;
86 ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
87 fb->vi.yoffset = 0;
88 ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
89 }
90
91 static int vt_set_mode(int graphics)
92 {
93 int fd, r;
94 fd = open("/dev/tty0", O_RDWR | O_SYNC);
95 if (fd < 0)
96 return -1;
97 r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
98 close(fd);
99 return r;
100 }
101
102 /* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
103
104 int load_565rle_image(char *fn)
105 {
106 struct FB fb;
107 struct stat s;
108 unsigned short *data, *bits, *ptr;
109 unsigned count, max;
110 int fd;
111
112 if (vt_set_mode(1))
113 return -1;
114
115 fd = open(fn, O_RDONLY);
116 if (fd < 0) {
117 ERROR("cannot open '%s'\n", fn);
118 goto fail_restore_text;
119 }
120
121 if (fstat(fd, &s) < 0) {
122 goto fail_close_file;
123 }
124
125 data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
126 if (data == MAP_FAILED)
127 goto fail_close_file;
128
129 if (fb_open(&fb))
130 goto fail_unmap_data;
131
132 max = fb_width(&fb) * fb_height(&fb);
133 ptr = data;
134 count = s.st_size;
135 bits = fb.bits;
136 while (count > 3) {
137 unsigned n = ptr[0];
138 if (n > max)
139 break;
140 android_memset16(bits, ptr[1], n << 1);
141 bits += n;
142 max -= n;
143 ptr += 2;
144 count -= 4;
145 }
146
147 munmap(data, s.st_size);
148 fb_update(&fb);
149 fb_close(&fb);
150 close(fd);
151 unlink(fn);
152 return 0;
153
154 fail_unmap_data:
155 munmap(data, s.st_size);
156 fail_close_file:
157 close(fd);
158 fail_restore_text:
159 vt_set_mode(0);
160 return -1;
161 }
162
+0
-797
init/parser.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <stddef.h>
7 #include <ctype.h>
8
9 #include "init.h"
10 #include "property_service.h"
11
12 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
13 #include <sys/_system_properties.h>
14
15 static list_declare(service_list);
16 static list_declare(action_list);
17 static list_declare(action_queue);
18
19 #define RAW(x...) log_write(6, x)
20
21 void DUMP(void)
22 {
23 #if 0
24 struct service *svc;
25 struct action *act;
26 struct command *cmd;
27 struct listnode *node;
28 struct listnode *node2;
29 struct socketinfo *si;
30 int n;
31
32 list_for_each(node, &service_list) {
33 svc = node_to_item(node, struct service, slist);
34 RAW("service %s\n", svc->name);
35 RAW(" class '%s'\n", svc->classname);
36 RAW(" exec");
37 for (n = 0; n < svc->nargs; n++) {
38 RAW(" '%s'", svc->args[n]);
39 }
40 RAW("\n");
41 for (si = svc->sockets; si; si = si->next) {
42 RAW(" socket %s %s 0%o\n", si->name, si->type, si->perm);
43 }
44 }
45
46 list_for_each(node, &action_list) {
47 act = node_to_item(node, struct action, alist);
48 RAW("on %s\n", act->name);
49 list_for_each(node2, &act->commands) {
50 cmd = node_to_item(node2, struct command, clist);
51 RAW(" %p", cmd->func);
52 for (n = 0; n < cmd->nargs; n++) {
53 RAW(" %s", cmd->args[n]);
54 }
55 RAW("\n");
56 }
57 RAW("\n");
58 }
59 #endif
60 }
61
62 #define MAXARGS 64
63
64 #define T_EOF 0
65 #define T_TEXT 1
66 #define T_NEWLINE 2
67
68 struct parse_state
69 {
70 char *ptr;
71 char *text;
72 int line;
73 int nexttoken;
74 void *context;
75 void (*parse_line)(struct parse_state *state, int nargs, char **args);
76 const char *filename;
77 };
78
79 static void *parse_service(struct parse_state *state, int nargs, char **args);
80 static void parse_line_service(struct parse_state *state, int nargs, char **args);
81
82 static void *parse_action(struct parse_state *state, int nargs, char **args);
83 static void parse_line_action(struct parse_state *state, int nargs, char **args);
84
85 void parse_error(struct parse_state *state, const char *fmt, ...)
86 {
87 va_list ap;
88 char buf[128];
89 int off;
90
91 snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
92 buf[127] = 0;
93 off = strlen(buf);
94
95 va_start(ap, fmt);
96 vsnprintf(buf + off, 128 - off, fmt, ap);
97 va_end(ap);
98 buf[127] = 0;
99 ERROR("%s", buf);
100 }
101
102 #define SECTION 0x01
103 #define COMMAND 0x02
104 #define OPTION 0x04
105
106 #include "keywords.h"
107
108 #define KEYWORD(symbol, flags, nargs, func) \
109 [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
110
111 struct {
112 const char *name;
113 int (*func)(int nargs, char **args);
114 unsigned char nargs;
115 unsigned char flags;
116 } keyword_info[KEYWORD_COUNT] = {
117 [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
118 #include "keywords.h"
119 };
120 #undef KEYWORD
121
122 #define kw_is(kw, type) (keyword_info[kw].flags & (type))
123 #define kw_name(kw) (keyword_info[kw].name)
124 #define kw_func(kw) (keyword_info[kw].func)
125 #define kw_nargs(kw) (keyword_info[kw].nargs)
126
127 int lookup_keyword(const char *s)
128 {
129 switch (*s++) {
130 case 'c':
131 if (!strcmp(s, "apability")) return K_capability;
132 if (!strcmp(s, "lass")) return K_class;
133 if (!strcmp(s, "lass_start")) return K_class_start;
134 if (!strcmp(s, "lass_stop")) return K_class_stop;
135 if (!strcmp(s, "onsole")) return K_console;
136 if (!strcmp(s, "hown")) return K_chown;
137 if (!strcmp(s, "hmod")) return K_chmod;
138 if (!strcmp(s, "ritical")) return K_critical;
139 break;
140 case 'd':
141 if (!strcmp(s, "isabled")) return K_disabled;
142 if (!strcmp(s, "omainname")) return K_domainname;
143 if (!strcmp(s, "evice")) return K_device;
144 break;
145 case 'e':
146 if (!strcmp(s, "xec")) return K_exec;
147 if (!strcmp(s, "xport")) return K_export;
148 break;
149 case 'g':
150 if (!strcmp(s, "roup")) return K_group;
151 break;
152 case 'h':
153 if (!strcmp(s, "ostname")) return K_hostname;
154 break;
155 case 'i':
156 if (!strcmp(s, "fup")) return K_ifup;
157 if (!strcmp(s, "nsmod")) return K_insmod;
158 if (!strcmp(s, "mport")) return K_import;
159 break;
160 case 'k':
161 if (!strcmp(s, "eycodes")) return K_keycodes;
162 break;
163 case 'l':
164 if (!strcmp(s, "oglevel")) return K_loglevel;
165 break;
166 case 'm':
167 if (!strcmp(s, "kdir")) return K_mkdir;
168 if (!strcmp(s, "ount")) return K_mount;
169 break;
170 case 'o':
171 if (!strcmp(s, "n")) return K_on;
172 if (!strcmp(s, "neshot")) return K_oneshot;
173 if (!strcmp(s, "nrestart")) return K_onrestart;
174 break;
175 case 'r':
176 if (!strcmp(s, "estart")) return K_restart;
177 break;
178 case 's':
179 if (!strcmp(s, "ervice")) return K_service;
180 if (!strcmp(s, "etenv")) return K_setenv;
181 if (!strcmp(s, "etkey")) return K_setkey;
182 if (!strcmp(s, "etprop")) return K_setprop;
183 if (!strcmp(s, "etrlimit")) return K_setrlimit;
184 if (!strcmp(s, "ocket")) return K_socket;
185 if (!strcmp(s, "tart")) return K_start;
186 if (!strcmp(s, "top")) return K_stop;
187 if (!strcmp(s, "ymlink")) return K_symlink;
188 if (!strcmp(s, "ysclktz")) return K_sysclktz;
189 break;
190 case 't':
191 if (!strcmp(s, "rigger")) return K_trigger;
192 break;
193 case 'u':
194 if (!strcmp(s, "ser")) return K_user;
195 break;
196 case 'w':
197 if (!strcmp(s, "rite")) return K_write;
198 break;
199 }
200 return K_UNKNOWN;
201 }
202
203 void parse_line_no_op(struct parse_state *state, int nargs, char **args)
204 {
205 }
206
207 int next_token(struct parse_state *state)
208 {
209 char *x = state->ptr;
210 char *s;
211
212 if (state->nexttoken) {
213 int t = state->nexttoken;
214 state->nexttoken = 0;
215 return t;
216 }
217
218 for (;;) {
219 switch (*x) {
220 case 0:
221 state->ptr = x;
222 return T_EOF;
223 case '\n':
224 state->line++;
225 x++;
226 state->ptr = x;
227 return T_NEWLINE;
228 case ' ':
229 case '\t':
230 case '\r':
231 x++;
232 continue;
233 case '#':
234 while (*x && (*x != '\n')) x++;
235 state->line++;
236 state->ptr = x;
237 return T_NEWLINE;
238 default:
239 goto text;
240 }
241 }
242
243 textdone:
244 state->ptr = x;
245 *s = 0;
246 return T_TEXT;
247 text:
248 state->text = s = x;
249 textresume:
250 for (;;) {
251 switch (*x) {
252 case 0:
253 goto textdone;
254 case ' ':
255 case '\t':
256 case '\r':
257 x++;
258 goto textdone;
259 case '\n':
260 state->nexttoken = T_NEWLINE;
261 x++;
262 goto textdone;
263 case '"':
264 x++;
265 for (;;) {
266 switch (*x) {
267 case 0:
268 /* unterminated quoted thing */
269 state->ptr = x;
270 return T_EOF;
271 case '"':
272 x++;
273 goto textresume;
274 default:
275 *s++ = *x++;
276 }
277 }
278 break;
279 case '\\':
280 x++;
281 switch (*x) {
282 case 0:
283 goto textdone;
284 case 'n':
285 *s++ = '\n';
286 break;
287 case 'r':
288 *s++ = '\r';
289 break;
290 case 't':
291 *s++ = '\t';
292 break;
293 case '\\':
294 *s++ = '\\';
295 break;
296 case '\r':
297 /* \ <cr> <lf> -> line continuation */
298 if (x[1] != '\n') {
299 x++;
300 continue;
301 }
302 case '\n':
303 /* \ <lf> -> line continuation */
304 state->line++;
305 x++;
306 /* eat any extra whitespace */
307 while((*x == ' ') || (*x == '\t')) x++;
308 continue;
309 default:
310 /* unknown escape -- just copy */
311 *s++ = *x++;
312 }
313 continue;
314 default:
315 *s++ = *x++;
316 }
317 }
318 return T_EOF;
319 }
320
321 void parse_line(int nargs, char **args)
322 {
323 int n;
324 int id = lookup_keyword(args[0]);
325 printf("%s(%d)", args[0], id);
326 for (n = 1; n < nargs; n++) {
327 printf(" '%s'", args[n]);
328 }
329 printf("\n");
330 }
331
332 void parse_new_section(struct parse_state *state, int kw,
333 int nargs, char **args)
334 {
335 printf("[ %s %s ]\n", args[0],
336 nargs > 1 ? args[1] : "");
337 switch(kw) {
338 case K_service:
339 state->context = parse_service(state, nargs, args);
340 if (state->context) {
341 state->parse_line = parse_line_service;
342 return;
343 }
344 break;
345 case K_on:
346 state->context = parse_action(state, nargs, args);
347 if (state->context) {
348 state->parse_line = parse_line_action;
349 return;
350 }
351 break;
352 }
353 state->parse_line = parse_line_no_op;
354 }
355
356 static void parse_config(const char *fn, char *s)
357 {
358 struct parse_state state;
359 char *args[MAXARGS];
360 int nargs;
361
362 nargs = 0;
363 state.filename = fn;
364 state.line = 1;
365 state.ptr = s;
366 state.nexttoken = 0;
367 state.parse_line = parse_line_no_op;
368 for (;;) {
369 switch (next_token(&state)) {
370 case T_EOF:
371 state.parse_line(&state, 0, 0);
372 return;
373 case T_NEWLINE:
374 if (nargs) {
375 int kw = lookup_keyword(args[0]);
376 if (kw_is(kw, SECTION)) {
377 state.parse_line(&state, 0, 0);
378 parse_new_section(&state, kw, nargs, args);
379 } else {
380 state.parse_line(&state, nargs, args);
381 }
382 nargs = 0;
383 }
384 break;
385 case T_TEXT:
386 if (nargs < MAXARGS) {
387 args[nargs++] = state.text;
388 }
389 break;
390 }
391 }
392 }
393
394 int parse_config_file(const char *fn)
395 {
396 char *data;
397 data = read_file(fn, 0);
398 if (!data) return -1;
399
400 parse_config(fn, data);
401 DUMP();
402 return 0;
403 }
404
405 static int valid_name(const char *name)
406 {
407 if (strlen(name) > 16) {
408 return 0;
409 }
410 while (*name) {
411 if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
412 return 0;
413 }
414 name++;
415 }
416 return 1;
417 }
418
419 struct service *service_find_by_name(const char *name)
420 {
421 struct listnode *node;
422 struct service *svc;
423 list_for_each(node, &service_list) {
424 svc = node_to_item(node, struct service, slist);
425 if (!strcmp(svc->name, name)) {
426 return svc;
427 }
428 }
429 return 0;
430 }
431
432 struct service *service_find_by_pid(pid_t pid)
433 {
434 struct listnode *node;
435 struct service *svc;
436 list_for_each(node, &service_list) {
437 svc = node_to_item(node, struct service, slist);
438 if (svc->pid == pid) {
439 return svc;
440 }
441 }
442 return 0;
443 }
444
445 struct service *service_find_by_keychord(int keychord_id)
446 {
447 struct listnode *node;
448 struct service *svc;
449 list_for_each(node, &service_list) {
450 svc = node_to_item(node, struct service, slist);
451 if (svc->keychord_id == keychord_id) {
452 return svc;
453 }
454 }
455 return 0;
456 }
457
458 void service_for_each(void (*func)(struct service *svc))
459 {
460 struct listnode *node;
461 struct service *svc;
462 list_for_each(node, &service_list) {
463 svc = node_to_item(node, struct service, slist);
464 func(svc);
465 }
466 }
467
468 void service_for_each_class(const char *classname,
469 void (*func)(struct service *svc))
470 {
471 struct listnode *node;
472 struct service *svc;
473 list_for_each(node, &service_list) {
474 svc = node_to_item(node, struct service, slist);
475 if (!strcmp(svc->classname, classname)) {
476 func(svc);
477 }
478 }
479 }
480
481 void service_for_each_flags(unsigned matchflags,
482 void (*func)(struct service *svc))
483 {
484 struct listnode *node;
485 struct service *svc;
486 list_for_each(node, &service_list) {
487 svc = node_to_item(node, struct service, slist);
488 if (svc->flags & matchflags) {
489 func(svc);
490 }
491 }
492 }
493
494 void action_for_each_trigger(const char *trigger,
495 void (*func)(struct action *act))
496 {
497 struct listnode *node;
498 struct action *act;
499 list_for_each(node, &action_list) {
500 act = node_to_item(node, struct action, alist);
501 if (!strcmp(act->name, trigger)) {
502 func(act);
503 }
504 }
505 }
506
507 void queue_property_triggers(const char *name, const char *value)
508 {
509 struct listnode *node;
510 struct action *act;
511 list_for_each(node, &action_list) {
512 act = node_to_item(node, struct action, alist);
513 if (!strncmp(act->name, "property:", strlen("property:"))) {
514 const char *test = act->name + strlen("property:");
515 int name_length = strlen(name);
516
517 if (!strncmp(name, test, name_length) &&
518 test[name_length] == '=' &&
519 !strcmp(test + name_length + 1, value)) {
520 action_add_queue_tail(act);
521 }
522 }
523 }
524 }
525
526 void queue_all_property_triggers()
527 {
528 struct listnode *node;
529 struct action *act;
530 list_for_each(node, &action_list) {
531 act = node_to_item(node, struct action, alist);
532 if (!strncmp(act->name, "property:", strlen("property:"))) {
533 /* parse property name and value
534 syntax is property:<name>=<value> */
535 const char* name = act->name + strlen("property:");
536 const char* equals = strchr(name, '=');
537 if (equals) {
538 char* prop_name[PROP_NAME_MAX + 1];
539 const char* value;
540 int length = equals - name;
541 if (length > PROP_NAME_MAX) {
542 ERROR("property name too long in trigger %s", act->name);
543 } else {
544 memcpy(prop_name, name, length);
545 prop_name[length] = 0;
546
547 /* does the property exist, and match the trigger value? */
548 value = property_get((const char *)&prop_name[0]);
549 if (value && !strcmp(equals + 1, value)) {
550 action_add_queue_tail(act);
551 }
552 }
553 }
554 }
555 }
556 }
557
558 void action_add_queue_tail(struct action *act)
559 {
560 list_add_tail(&action_queue, &act->qlist);
561 }
562
563 struct action *action_remove_queue_head(void)
564 {
565 if (list_empty(&action_queue)) {
566 return 0;
567 } else {
568 struct listnode *node = list_head(&action_queue);
569 struct action *act = node_to_item(node, struct action, qlist);
570 list_remove(node);
571 return act;
572 }
573 }
574
575 static void *parse_service(struct parse_state *state, int nargs, char **args)
576 {
577 struct service *svc;
578 if (nargs < 3) {
579 parse_error(state, "services must have a name and a program\n");
580 return 0;
581 }
582 if (!valid_name(args[1])) {
583 parse_error(state, "invalid service name '%s'\n", args[1]);
584 return 0;
585 }
586
587 svc = service_find_by_name(args[1]);
588 if (svc) {
589 parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
590 return 0;
591 }
592
593 nargs -= 2;
594 svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
595 if (!svc) {
596 parse_error(state, "out of memory\n");
597 return 0;
598 }
599 svc->name = args[1];
600 svc->classname = "default";
601 memcpy(svc->args, args + 2, sizeof(char*) * nargs);
602 svc->args[nargs] = 0;
603 svc->nargs = nargs;
604 svc->onrestart.name = "onrestart";
605 list_init(&svc->onrestart.commands);
606 list_add_tail(&service_list, &svc->slist);
607 return svc;
608 }
609
610 static void parse_line_service(struct parse_state *state, int nargs, char **args)
611 {
612 struct service *svc = state->context;
613 struct command *cmd;
614 int i, kw, kw_nargs;
615
616 if (nargs == 0) {
617 return;
618 }
619
620 kw = lookup_keyword(args[0]);
621 switch (kw) {
622 case K_capability:
623 break;
624 case K_class:
625 if (nargs != 2) {
626 parse_error(state, "class option requires a classname\n");
627 } else {
628 svc->classname = args[1];
629 }
630 break;
631 case K_console:
632 svc->flags |= SVC_CONSOLE;
633 break;
634 case K_disabled:
635 svc->flags |= SVC_DISABLED;
636 break;
637 case K_group:
638 if (nargs < 2) {
639 parse_error(state, "group option requires a group id\n");
640 } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
641 parse_error(state, "group option accepts at most %d supp. groups\n",
642 NR_SVC_SUPP_GIDS);
643 } else {
644 int n;
645 svc->gid = decode_uid(args[1]);
646 for (n = 2; n < nargs; n++) {
647 svc->supp_gids[n-2] = decode_uid(args[n]);
648 }
649 svc->nr_supp_gids = n - 2;
650 }
651 break;
652 case K_keycodes:
653 if (nargs < 2) {
654 parse_error(state, "keycodes option requires atleast one keycode\n");
655 } else {
656 svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
657 if (!svc->keycodes) {
658 parse_error(state, "could not allocate keycodes\n");
659 } else {
660 svc->nkeycodes = nargs - 1;
661 for (i = 1; i < nargs; i++) {
662 svc->keycodes[i - 1] = atoi(args[i]);
663 }
664 }
665 }
666 break;
667 case K_oneshot:
668 svc->flags |= SVC_ONESHOT;
669 break;
670 case K_onrestart:
671 nargs--;
672 args++;
673 kw = lookup_keyword(args[0]);
674 if (!kw_is(kw, COMMAND)) {
675 parse_error(state, "invalid command '%s'\n", args[0]);
676 break;
677 }
678 kw_nargs = kw_nargs(kw);
679 if (nargs < kw_nargs) {
680 parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
681 kw_nargs > 2 ? "arguments" : "argument");
682 break;
683 }
684
685 cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
686 cmd->func = kw_func(kw);
687 cmd->nargs = nargs;
688 memcpy(cmd->args, args, sizeof(char*) * nargs);
689 list_add_tail(&svc->onrestart.commands, &cmd->clist);
690 break;
691 case K_critical:
692 svc->flags |= SVC_CRITICAL;
693 break;
694 case K_setenv: { /* name value */
695 struct svcenvinfo *ei;
696 if (nargs < 2) {
697 parse_error(state, "setenv option requires name and value arguments\n");
698 break;
699 }
700 ei = calloc(1, sizeof(*ei));
701 if (!ei) {
702 parse_error(state, "out of memory\n");
703 break;
704 }
705 ei->name = args[1];
706 ei->value = args[2];
707 ei->next = svc->envvars;
708 svc->envvars = ei;
709 break;
710 }
711 case K_socket: {/* name type perm [ uid gid ] */
712 struct socketinfo *si;
713 if (nargs < 4) {
714 parse_error(state, "socket option requires name, type, perm arguments\n");
715 break;
716 }
717 if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")) {
718 parse_error(state, "socket type must be 'dgram' or 'stream'\n");
719 break;
720 }
721 si = calloc(1, sizeof(*si));
722 if (!si) {
723 parse_error(state, "out of memory\n");
724 break;
725 }
726 si->name = args[1];
727 si->type = args[2];
728 si->perm = strtoul(args[3], 0, 8);
729 if (nargs > 4)
730 si->uid = decode_uid(args[4]);
731 if (nargs > 5)
732 si->gid = decode_uid(args[5]);
733 si->next = svc->sockets;
734 svc->sockets = si;
735 break;
736 }
737 case K_user:
738 if (nargs != 2) {
739 parse_error(state, "user option requires a user id\n");
740 } else {
741 svc->uid = decode_uid(args[1]);
742 }
743 break;
744 default:
745 parse_error(state, "invalid option '%s'\n", args[0]);
746 }
747 }
748
749 static void *parse_action(struct parse_state *state, int nargs, char **args)
750 {
751 struct action *act;
752 if (nargs < 2) {
753 parse_error(state, "actions must have a trigger\n");
754 return 0;
755 }
756 if (nargs > 2) {
757 parse_error(state, "actions may not have extra parameters\n");
758 return 0;
759 }
760 act = calloc(1, sizeof(*act));
761 act->name = args[1];
762 list_init(&act->commands);
763 list_add_tail(&action_list, &act->alist);
764 /* XXX add to hash */
765 return act;
766 }
767
768 static void parse_line_action(struct parse_state* state, int nargs, char **args)
769 {
770 struct command *cmd;
771 struct action *act = state->context;
772 int (*func)(int nargs, char **args);
773 int kw, n;
774
775 if (nargs == 0) {
776 return;
777 }
778
779 kw = lookup_keyword(args[0]);
780 if (!kw_is(kw, COMMAND)) {
781 parse_error(state, "invalid command '%s'\n", args[0]);
782 return;
783 }
784
785 n = kw_nargs(kw);
786 if (nargs < n) {
787 parse_error(state, "%s requires %d %s\n", args[0], n - 1,
788 n > 2 ? "arguments" : "argument");
789 return;
790 }
791 cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
792 cmd->func = kw_func(kw);
793 cmd->nargs = nargs;
794 memcpy(cmd->args, args, sizeof(char*) * nargs);
795 list_add_tail(&act->commands, &cmd->clist);
796 }
+0
-502
init/property_service.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <fcntl.h>
22 #include <stdarg.h>
23 #include <dirent.h>
24 #include <limits.h>
25 #include <errno.h>
26
27 #include <cutils/misc.h>
28 #include <cutils/sockets.h>
29 #include <cutils/ashmem.h>
30
31 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
32 #include <sys/_system_properties.h>
33
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <sys/select.h>
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <sys/mman.h>
40 #include <sys/atomics.h>
41 #include <private/android_filesystem_config.h>
42
43 #include "property_service.h"
44 #include "init.h"
45
46 #define PERSISTENT_PROPERTY_DIR "/data/property"
47
48 static int persistent_properties_loaded = 0;
49
50 /* White list of permissions for setting property services. */
51 struct {
52 const char *prefix;
53 unsigned int uid;
54 } property_perms[] = {
55 { "net.rmnet0.", AID_RADIO },
56 { "net.gprs.", AID_RADIO },
57 { "ril.", AID_RADIO },
58 { "gsm.", AID_RADIO },
59 { "net.dns", AID_RADIO },
60 { "net.", AID_SYSTEM },
61 { "dev.", AID_SYSTEM },
62 { "runtime.", AID_SYSTEM },
63 { "hw.", AID_SYSTEM },
64 { "sys.", AID_SYSTEM },
65 { "service.", AID_SYSTEM },
66 { "wlan.", AID_SYSTEM },
67 { "dhcp.", AID_SYSTEM },
68 { "dhcp.", AID_DHCP },
69 { "debug.", AID_SHELL },
70 { "log.", AID_SHELL },
71 { "persist.sys.", AID_SYSTEM },
72 { "persist.service.", AID_SYSTEM },
73 { NULL, 0 }
74 };
75
76 /*
77 * White list of UID that are allowed to start/stop services.
78 * Currently there are no user apps that require.
79 */
80 struct {
81 const char *service;
82 unsigned int uid;
83 } control_perms[] = {
84 {NULL, 0 }
85 };
86
87 typedef struct {
88 void *data;
89 size_t size;
90 int fd;
91 } workspace;
92
93 static int init_workspace(workspace *w, size_t size)
94 {
95 void *data;
96 int fd;
97
98 fd = ashmem_create_region("system_properties", size);
99 if(fd < 0)
100 return -1;
101
102 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
103 if(data == MAP_FAILED)
104 goto out;
105
106 /* allow the wolves we share with to do nothing but read */
107 ashmem_set_prot_region(fd, PROT_READ);
108
109 w->data = data;
110 w->size = size;
111 w->fd = fd;
112
113 return 0;
114
115 out:
116 close(fd);
117 return -1;
118 }
119
120 /* (8 header words + 247 toc words) = 1020 bytes */
121 /* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
122
123 #define PA_COUNT_MAX 247
124 #define PA_INFO_START 1024
125 #define PA_SIZE 32768
126
127 static workspace pa_workspace;
128 static prop_info *pa_info_array;
129
130 extern prop_area *__system_property_area__;
131
132 static int init_property_area(void)
133 {
134 prop_area *pa;
135
136 if(pa_info_array)
137 return -1;
138
139 if(init_workspace(&pa_workspace, PA_SIZE))
140 return -1;
141
142 fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
143
144 pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
145
146 pa = pa_workspace.data;
147 memset(pa, 0, PA_SIZE);
148 pa->magic = PROP_AREA_MAGIC;
149 pa->version = PROP_AREA_VERSION;
150
151 /* plug into the lib property services */
152 __system_property_area__ = pa;
153
154 return 0;
155 }
156
157 static void update_prop_info(prop_info *pi, const char *value, unsigned len)
158 {
159 pi->serial = pi->serial | 1;
160 memcpy(pi->value, value, len + 1);
161 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
162 __futex_wake(&pi->serial, INT32_MAX);
163 }
164
165 static int property_write(prop_info *pi, const char *value)
166 {
167 int valuelen = strlen(value);
168 if(valuelen >= PROP_VALUE_MAX) return -1;
169 update_prop_info(pi, value, valuelen);
170 return 0;
171 }
172
173
174 /*
175 * Checks permissions for starting/stoping system services.
176 * AID_SYSTEM and AID_ROOT are always allowed.
177 *
178 * Returns 1 if uid allowed, 0 otherwise.
179 */
180 static int check_control_perms(const char *name, int uid) {
181 int i;
182 if (uid == AID_SYSTEM || uid == AID_ROOT)
183 return 1;
184
185 /* Search the ACL */
186 for (i = 0; control_perms[i].service; i++) {
187 if (strcmp(control_perms[i].service, name) == 0) {
188 if (control_perms[i].uid == uid)
189 return 1;
190 }
191 }
192 return 0;
193 }
194
195 /*
196 * Checks permissions for setting system properties.
197 * Returns 1 if uid allowed, 0 otherwise.
198 */
199 static int check_perms(const char *name, unsigned int uid)
200 {
201 int i;
202 if (uid == 0)
203 return 1;
204
205 if(!strncmp(name, "ro.", 3))
206 name +=3;
207
208 for (i = 0; property_perms[i].prefix; i++) {
209 int tmp;
210 if (strncmp(property_perms[i].prefix, name,
211 strlen(property_perms[i].prefix)) == 0) {
212 if (property_perms[i].uid == uid) {
213 return 1;
214 }
215 }
216 }
217
218 return 0;
219 }
220
221 const char* property_get(const char *name)
222 {
223 prop_info *pi;
224
225 if(strlen(name) >= PROP_NAME_MAX) return 0;
226
227 pi = (prop_info*) __system_property_find(name);
228
229 if(pi != 0) {
230 return pi->value;
231 } else {
232 return 0;
233 }
234 }
235
236 static void write_peristent_property(const char *name, const char *value)
237 {
238 const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp";
239 char path[PATH_MAX];
240 int fd, length;
241
242 snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
243
244 fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600);
245 if (fd < 0) {
246 ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
247 return;
248 }
249 write(fd, value, strlen(value));
250 close(fd);
251
252 if (rename(tempPath, path)) {
253 unlink(tempPath);
254 ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
255 }
256 }
257
258 int property_set(const char *name, const char *value)
259 {
260 prop_area *pa;
261 prop_info *pi;
262
263 int namelen = strlen(name);
264 int valuelen = strlen(value);
265
266 if(namelen >= PROP_NAME_MAX) return -1;
267 if(valuelen >= PROP_VALUE_MAX) return -1;
268 if(namelen < 1) return -1;
269
270 pi = (prop_info*) __system_property_find(name);
271
272 if(pi != 0) {
273 /* ro.* properties may NEVER be modified once set */
274 if(!strncmp(name, "ro.", 3)) return -1;
275
276 pa = __system_property_area__;
277 update_prop_info(pi, value, valuelen);
278 pa->serial++;
279 __futex_wake(&pa->serial, INT32_MAX);
280 } else {
281 pa = __system_property_area__;
282 if(pa->count == PA_COUNT_MAX) return -1;
283
284 pi = pa_info_array + pa->count;
285 pi->serial = (valuelen << 24);
286 memcpy(pi->name, name, namelen + 1);
287 memcpy(pi->value, value, valuelen + 1);
288
289 pa->toc[pa->count] =
290 (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
291
292 pa->count++;
293 pa->serial++;
294 __futex_wake(&pa->serial, INT32_MAX);
295 }
296 /* If name starts with "net." treat as a DNS property. */
297 if (strncmp("net.", name, sizeof("net.") - 1) == 0) {
298 if (strcmp("net.change", name) == 0) {
299 return 0;
300 }
301 /*
302 * The 'net.change' property is a special property used track when any
303 * 'net.*' property name is updated. It is _ONLY_ updated here. Its value
304 * contains the last updated 'net.*' property.
305 */
306 property_set("net.change", name);
307 } else if (persistent_properties_loaded &&
308 strncmp("persist.", name, sizeof("persist.") - 1) == 0) {
309 /*
310 * Don't write properties to disk until after we have read all default properties
311 * to prevent them from being overwritten by default values.
312 */
313 write_peristent_property(name, value);
314 }
315 property_changed(name, value);
316 return 0;
317 }
318
319 static int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
320 void *cookie)
321 {
322 char name[PROP_NAME_MAX];
323 char value[PROP_VALUE_MAX];
324 const prop_info *pi;
325 unsigned n;
326
327 for(n = 0; (pi = __system_property_find_nth(n)); n++) {
328 __system_property_read(pi, name, value);
329 propfn(name, value, cookie);
330 }
331 return 0;
332 }
333
334 void handle_property_set_fd(int fd)
335 {
336 prop_msg msg;
337 int s;
338 int r;
339 int res;
340 struct ucred cr;
341 struct sockaddr_un addr;
342 socklen_t addr_size = sizeof(addr);
343 socklen_t cr_size = sizeof(cr);
344
345 if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
346 return;
347 }
348
349 /* Check socket options here */
350 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
351 close(s);
352 ERROR("Unable to recieve socket options\n");
353 return;
354 }
355
356 r = recv(s, &msg, sizeof(msg), 0);
357 close(s);
358 if(r != sizeof(prop_msg)) {
359 ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n",
360 r, sizeof(prop_msg));
361 return;
362 }
363
364 switch(msg.cmd) {
365 case PROP_MSG_SETPROP:
366 msg.name[PROP_NAME_MAX-1] = 0;
367 msg.value[PROP_VALUE_MAX-1] = 0;
368
369 if(memcmp(msg.name,"ctl.",4) == 0) {
370 if (check_control_perms(msg.value, cr.uid)) {
371 handle_control_message((char*) msg.name + 4, (char*) msg.value);
372 } else {
373 ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
374 msg.name + 4, msg.value, cr.uid, cr.pid);
375 }
376 } else {
377 if (check_perms(msg.name, cr.uid)) {
378 property_set((char*) msg.name, (char*) msg.value);
379 } else {
380 ERROR("sys_prop: permission denied uid:%d name:%s\n",
381 cr.uid, msg.name);
382 }
383 }
384 break;
385
386 default:
387 break;
388 }
389 }
390
391 void get_property_workspace(int *fd, int *sz)
392 {
393 *fd = pa_workspace.fd;
394 *sz = pa_workspace.size;
395 }
396
397 static void load_properties(char *data)
398 {
399 char *key, *value, *eol, *sol, *tmp;
400
401 sol = data;
402 while((eol = strchr(sol, '\n'))) {
403 key = sol;
404 *eol++ = 0;
405 sol = eol;
406
407 value = strchr(key, '=');
408 if(value == 0) continue;
409 *value++ = 0;
410
411 while(isspace(*key)) key++;
412 if(*key == '#') continue;
413 tmp = value - 2;
414 while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
415
416 while(isspace(*value)) value++;
417 tmp = eol - 2;
418 while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
419
420 property_set(key, value);
421 }
422 }
423
424 static void load_properties_from_file(const char *fn)
425 {
426 char *data;
427 unsigned sz;
428
429 data = read_file(fn, &sz);
430
431 if(data != 0) {
432 load_properties(data);
433 free(data);
434 }
435 }
436
437 static void load_persistent_properties()
438 {
439 DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
440 struct dirent* entry;
441 char path[PATH_MAX];
442 char value[PROP_VALUE_MAX];
443 int fd, length;
444
445 if (dir) {
446 while ((entry = readdir(dir)) != NULL) {
447 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") ||
448 strncmp("persist.", entry->d_name, sizeof("persist.") - 1))
449 continue;
450 #if HAVE_DIRENT_D_TYPE
451 if (entry->d_type != DT_REG)
452 continue;
453 #endif
454 /* open the file and read the property value */
455 snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, entry->d_name);
456 fd = open(path, O_RDONLY);
457 if (fd >= 0) {
458 length = read(fd, value, sizeof(value) - 1);
459 if (length >= 0) {
460 value[length] = 0;
461 property_set(entry->d_name, value);
462 } else {
463 ERROR("Unable to read persistent property file %s errno: %d\n", path, errno);
464 }
465 close(fd);
466 } else {
467 ERROR("Unable to open persistent property file %s errno: %d\n", path, errno);
468 }
469 }
470 closedir(dir);
471 } else {
472 ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno);
473 }
474
475 persistent_properties_loaded = 1;
476 }
477
478 void property_init(void)
479 {
480 init_property_area();
481 load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
482 }
483
484 int start_property_service(void)
485 {
486 int fd;
487
488 load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
489 load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
490 load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
491 /* Read persistent properties after all default values have been loaded. */
492 load_persistent_properties();
493
494 fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
495 if(fd < 0) return -1;
496 fcntl(fd, F_SETFD, FD_CLOEXEC);
497 fcntl(fd, F_SETFL, O_NONBLOCK);
498
499 listen(fd, 8);
500 return fd;
501 }
+0
-28
init/property_service.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _INIT_PROPERTY_H
17 #define _INIT_PROPERTY_H
18
19 extern void handle_property_fd(int fd);
20 extern void handle_property_set_fd(int fd);
21 extern void property_init(void);
22 extern int start_property_service(void);
23 void get_property_workspace(int *fd, int *sz);
24 extern const char* property_get(const char *name);
25 extern int property_set(const char *name, const char *value);
26
27 #endif /* _INIT_PROPERTY_H */
+0
-293
init/readme.txt less more
0
1 Android Init Language
2 ---------------------
3
4 The Android Init Language consists of four broad classes of statements,
5 which are Actions, Commands, Services, and Options.
6
7 All of these are line-oriented, consisting of tokens separated by
8 whitespace. The c-style backslash escapes may be used to insert
9 whitespace into a token. Double quotes may also be used to prevent
10 whitespace from breaking text into multiple tokens. The backslash,
11 when it is the last character on a line, may be used for line-folding.
12
13 Lines which start with a # (leading whitespace allowed) are comments.
14
15 Actions and Services implicitly declare a new section. All commands
16 or options belong to the section most recently declared. Commands
17 or options before the first section are ignored.
18
19 Actions and Services have unique names. If a second Action or Service
20 is declared with the same name as an existing one, it is ignored as
21 an error. (??? should we override instead)
22
23
24 Actions
25 -------
26 Actions are named sequences of commands. Actions have a trigger which
27 is used to determine when the action should occur. When an event
28 occurs which matches an action's trigger, that action is added to
29 the tail of a to-be-executed queue (unless it is already on the
30 queue).
31
32 Each action in the queue is dequeued in sequence and each command in
33 that action is executed in sequence. Init handles other activities
34 (device creation/destruction, property setting, process restarting)
35 "between" the execution of the commands in activities.
36
37 Actions take the form of:
38
39 on <trigger>
40 <command>
41 <command>
42 <command>
43
44
45 Services
46 --------
47 Services are programs which init launches and (optionally) restarts
48 when they exit. Services take the form of:
49
50 service <name> <pathname> [ <argument> ]*
51 <option>
52 <option>
53 ...
54
55
56 Options
57 -------
58 Options are modifiers to services. They affect how and when init
59 runs the service.
60
61 critical
62 This is a device-critical service. If it exits more than four times in
63 four minutes, the device will reboot into recovery mode.
64
65 disabled
66 This service will not automatically start with its class.
67 It must be explicitly started by name.
68
69 setenv <name> <value>
70 Set the environment variable <name> to <value> in the launched process.
71
72 socket <name> <type> <perm> [ <user> [ <group> ] ]
73 Create a unix domain socket named /dev/socket/<name> and pass
74 its fd to the launched process. <type> must be "dgram" or "stream".
75 User and group default to 0.
76
77 user <username>
78 Change to username before exec'ing this service.
79 Currently defaults to root. (??? probably should default to nobody)
80 Currently, if your process requires linux capabilities then you cannot use
81 this command. You must instead request the capabilities in-process while
82 still root, and then drop to your desired uid.
83
84 group <groupname> [ <groupname> ]*
85 Change to groupname before exec'ing this service. Additional
86 groupnames beyond the (required) first one are used to set the
87 supplemental groups of the process (via setgroups()).
88 Currently defaults to root. (??? probably should default to nobody)
89
90 oneshot
91 Do not restart the service when it exits.
92
93 class <name>
94 Specify a class name for the service. All services in a
95 named class may be started or stopped together. A service
96 is in the class "default" if one is not specified via the
97 class option.
98
99 onrestart
100 Execute a Command (see below) when service restarts.
101
102 Triggers
103 --------
104 Triggers are strings which can be used to match certain kinds
105 of events and used to cause an action to occur.
106
107 boot
108 This is the first trigger that will occur when init starts
109 (after /init.conf is loaded)
110
111 <name>=<value>
112 Triggers of this form occur when the property <name> is set
113 to the specific value <value>.
114
115 device-added-<path>
116 device-removed-<path>
117 Triggers of these forms occur when a device node is added
118 or removed.
119
120 service-exited-<name>
121 Triggers of this form occur when the specified service exits.
122
123
124 Commands
125 --------
126
127 exec <path> [ <argument> ]*
128 Fork and execute a program (<path>). This will block until
129 the program completes execution. It is best to avoid exec
130 as unlike the builtin commands, it runs the risk of getting
131 init "stuck". (??? maybe there should be a timeout?)
132
133 export <name> <value>
134 Set the environment variable <name> equal to <value> in the
135 global environment (which will be inherited by all processes
136 started after this command is executed)
137
138 ifup <interface>
139 Bring the network interface <interface> online.
140
141 import <filename>
142 Parse an init config file, extending the current configuration.
143
144 hostname <name>
145 Set the host name.
146
147 chmod <octal-mode> <path>
148 Change file access permissions.
149
150 chown <owner> <group> <path>
151 Change file owner and group.
152
153 class_start <serviceclass>
154 Start all services of the specified class if they are
155 not already running.
156
157 class_stop <serviceclass>
158 Stop all services of the specified class if they are
159 currently running.
160
161 domainname <name>
162 Set the domain name.
163
164 insmod <path>
165 Install the module at <path>
166
167 mkdir <path> [mode] [owner] [group]
168 Create a directory at <path>, optionally with the given mode, owner, and
169 group. If not provided, the directory is created with permissions 755 and
170 owned by the root user and root group.
171
172 mount <type> <device> <dir> [ <mountoption> ]*
173 Attempt to mount the named device at the directory <dir>
174 <device> may be of the form mtd@name to specify a mtd block
175 device by name.
176 <mountoption>s include "ro", "rw", "remount", "noatime", ...
177
178 setkey
179 TBD
180
181 setprop <name> <value>
182 Set system property <name> to <value>.
183
184 setrlimit <resource> <cur> <max>
185 Set the rlimit for a resource.
186
187 start <service>
188 Start a service running if it is not already running.
189
190 stop <service>
191 Stop a service from running if it is currently running.
192
193 symlink <target> <path>
194 Create a symbolic link at <path> with the value <target>
195
196 sysclktz <mins_west_of_gmt>
197 Set the system clock base (0 if system clock ticks in GMT)
198
199 trigger <event>
200 Trigger an event. Used to queue an action from another
201 action.
202
203 write <path> <string> [ <string> ]*
204 Open the file at <path> and write one or more strings
205 to it with write(2)
206
207
208 Properties
209 ----------
210 Init updates some system properties to provide some insight into
211 what it's doing:
212
213 init.action
214 Equal to the name of the action currently being executed or "" if none
215
216 init.command
217 Equal to the command being executed or "" if none.
218
219 init.svc.<name>
220 State of a named service ("stopped", "running", "restarting")
221
222
223 Example init.conf
224 -----------------
225
226 # not complete -- just providing some examples of usage
227 #
228 on boot
229 export PATH /sbin:/system/sbin:/system/bin
230 export LD_LIBRARY_PATH /system/lib
231
232 mkdir /dev
233 mkdir /proc
234 mkdir /sys
235
236 mount tmpfs tmpfs /dev
237 mkdir /dev/pts
238 mkdir /dev/socket
239 mount devpts devpts /dev/pts
240 mount proc proc /proc
241 mount sysfs sysfs /sys
242
243 write /proc/cpu/alignment 4
244
245 ifup lo
246
247 hostname localhost
248 domainname localhost
249
250 mount yaffs2 mtd@system /system
251 mount yaffs2 mtd@userdata /data
252
253 import /system/etc/init.conf
254
255 class_start default
256
257 service adbd /sbin/adbd
258 user adb
259 group adb
260
261 service usbd /system/bin/usbd -r
262 user usbd
263 group usbd
264 socket usbd 666
265
266 service zygote /system/bin/app_process -Xzygote /system/bin --zygote
267 socket zygote 666
268
269 service runtime /system/bin/runtime
270 user system
271 group system
272
273 on device-added-/dev/compass
274 start akmd
275
276 on device-removed-/dev/compass
277 stop akmd
278
279 service akmd /sbin/akmd
280 disabled
281 user akmd
282 group akmd
283
284 Debugging notes
285 ---------------
286 By default, programs executed by init will drop stdout and stderr into
287 /dev/null. To help with debugging, you can execute your program via the
288 Andoird program logwrapper. This will redirect stdout/stderr into the
289 Android logging system (accessed via logcat).
290
291 For example
292 service akmd /system/bin/logwrapper /sbin/akmd
+0
-211
init/util.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdarg.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 #include <errno.h>
23
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28
29 /* for ANDROID_SOCKET_* */
30 #include <cutils/sockets.h>
31
32 #include <private/android_filesystem_config.h>
33
34 #include "init.h"
35
36 static int log_fd = -1;
37 /* Inital log level before init.rc is parsed and this this is reset. */
38 static int log_level = LOG_DEFAULT_LEVEL;
39
40
41 void log_set_level(int level) {
42 log_level = level;
43 }
44
45 void log_init(void)
46 {
47 static const char *name = "/dev/__kmsg__";
48 if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
49 log_fd = open(name, O_WRONLY);
50 fcntl(log_fd, F_SETFD, FD_CLOEXEC);
51 unlink(name);
52 }
53 }
54
55 #define LOG_BUF_MAX 512
56
57 void log_write(int level, const char *fmt, ...)
58 {
59 char buf[LOG_BUF_MAX];
60 va_list ap;
61
62 if (level > log_level) return;
63 if (log_fd < 0) return;
64
65 va_start(ap, fmt);
66 vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
67 buf[LOG_BUF_MAX - 1] = 0;
68 va_end(ap);
69 write(log_fd, buf, strlen(buf));
70 }
71
72 /*
73 * android_name_to_id - returns the integer uid/gid associated with the given
74 * name, or -1U on error.
75 */
76 static unsigned int android_name_to_id(const char *name)
77 {
78 struct android_id_info *info = android_ids;
79 unsigned int n;
80
81 for (n = 0; n < android_id_count; n++) {
82 if (!strcmp(info[n].name, name))
83 return info[n].aid;
84 }
85
86 return -1U;
87 }
88
89 /*
90 * decode_uid - decodes and returns the given string, which can be either the
91 * numeric or name representation, into the integer uid or gid. Returns -1U on
92 * error.
93 */
94 unsigned int decode_uid(const char *s)
95 {
96 unsigned int v;
97
98 if (!s || *s == '\0')
99 return -1U;
100 if (isalpha(s[0]))
101 return android_name_to_id(s);
102
103 errno = 0;
104 v = (unsigned int) strtoul(s, 0, 0);
105 if (errno)
106 return -1U;
107 return v;
108 }
109
110 /*
111 * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR
112 * ("/dev/socket") as dictated in init.rc. This socket is inherited by the
113 * daemon. We communicate the file descriptor's value via the environment
114 * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
115 */
116 int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
117 {
118 struct sockaddr_un addr;
119 int fd, ret;
120
121 fd = socket(PF_UNIX, type, 0);
122 if (fd < 0) {
123 ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
124 return -1;
125 }
126
127 memset(&addr, 0 , sizeof(addr));
128 addr.sun_family = AF_UNIX;
129 snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
130 name);
131
132 ret = unlink(addr.sun_path);
133 if (ret != 0 && errno != ENOENT) {
134 ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
135 goto out_close;
136 }
137
138 ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
139 if (ret) {
140 ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
141 goto out_unlink;
142 }
143
144 chown(addr.sun_path, uid, gid);
145 chmod(addr.sun_path, perm);
146
147 INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
148 addr.sun_path, perm, uid, gid);
149
150 return fd;
151
152 out_unlink:
153 unlink(addr.sun_path);
154 out_close:
155 close(fd);
156 return -1;
157 }
158
159 /* reads a file, making sure it is terminated with \n \0 */
160 void *read_file(const char *fn, unsigned *_sz)
161 {
162 char *data;
163 int sz;
164 int fd;
165
166 data = 0;
167 fd = open(fn, O_RDONLY);
168 if(fd < 0) return 0;
169
170 sz = lseek(fd, 0, SEEK_END);
171 if(sz < 0) goto oops;
172
173 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
174
175 data = (char*) malloc(sz + 2);
176 if(data == 0) goto oops;
177
178 if(read(fd, data, sz) != sz) goto oops;
179 close(fd);
180 data[sz] = '\n';
181 data[sz+1] = 0;
182 if(_sz) *_sz = sz;
183 return data;
184
185 oops:
186 close(fd);
187 if(data != 0) free(data);
188 return 0;
189 }
190
191 void list_init(struct listnode *node)
192 {
193 node->next = node;
194 node->prev = node;
195 }
196
197 void list_add_tail(struct listnode *head, struct listnode *item)
198 {
199 item->next = head;
200 item->prev = head->prev;
201 head->prev->next = item;
202 head->prev = item;
203 }
204
205 void list_remove(struct listnode *item)
206 {
207 item->next->prev = item->prev;
208 item->prev->next = item->next;
209 }
210
+0
-7
libctest/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 LOCAL_MODULE:= libctest
4 LOCAL_SRC_FILES := ctest.c
5
6 include $(BUILD_SHARED_LIBRARY)
+0
-161
libctest/ctest.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <assert.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <ctest/ctest.h>
23
24 #define MAX_TESTS 255
25
26 /** Semi-random number used to identify assertion errors. */
27 #define ASSERTION_ERROR 42
28
29 typedef void TestCase();
30
31 /** A suite of tests. */
32 typedef struct {
33 int size;
34 const char* testNames[MAX_TESTS];
35 TestCase* tests[MAX_TESTS];
36 int currentTest;
37 FILE* out;
38 } TestSuite;
39
40 /** Gets the test suite. Creates it if necessary. */
41 static TestSuite* getTestSuite() {
42 static TestSuite* suite = NULL;
43
44 if (suite != NULL) {
45 return suite;
46 }
47
48 suite = calloc(1, sizeof(TestSuite));
49 assert(suite != NULL);
50
51 suite->out = tmpfile();
52 assert(suite->out != NULL);
53
54 return suite;
55 }
56
57 void addNamedTest(const char* name, TestCase* test) {
58 TestSuite* testSuite = getTestSuite();
59 assert(testSuite->size <= MAX_TESTS);
60
61 int index = testSuite->size;
62 testSuite->testNames[index] = name;
63 testSuite->tests[index] = test;
64
65 testSuite->size++;
66 }
67
68 /** Prints failures to stderr. */
69 static void printFailures(int failures) {
70 TestSuite* suite = getTestSuite();
71
72 fprintf(stderr, "FAILURE! %d of %d tests failed. Failures:\n",
73 failures, suite->size);
74
75 // Copy test output to stdout.
76 rewind(suite->out);
77 char buffer[512];
78 size_t read;
79 while ((read = fread(buffer, sizeof(char), 512, suite->out)) > 0) {
80 // TODO: Make sure we actually wrote 'read' bytes.
81 fwrite(buffer, sizeof(char), read, stderr);
82 }
83 }
84
85 /** Runs a single test case. */
86 static int runCurrentTest() {
87 TestSuite* suite = getTestSuite();
88
89 pid_t pid = fork();
90 if (pid == 0) {
91 // Child process. Runs test case.
92 suite->tests[suite->currentTest]();
93
94 // Exit successfully.
95 exit(0);
96 } else if (pid < 0) {
97 fprintf(stderr, "Fork failed.");
98 exit(1);
99 } else {
100 // Parent process. Wait for child.
101 int status;
102 waitpid(pid, &status, 0);
103
104 if (!WIFEXITED(status)) {
105 return -1;
106 }
107
108 return WEXITSTATUS(status);
109 }
110 }
111
112 void runTests() {
113 TestSuite* suite = getTestSuite();
114
115 int failures = 0;
116 for (suite->currentTest = 0; suite->currentTest < suite->size;
117 suite->currentTest++) {
118 // Flush stdout before forking.
119 fflush(stdout);
120
121 int result = runCurrentTest();
122
123 if (result != 0) {
124 printf("X");
125
126 failures++;
127
128 // Handle errors other than assertions.
129 if (result != ASSERTION_ERROR) {
130 // TODO: Report file name.
131 fprintf(suite->out, "Process failed: [%s] status: %d\n",
132 suite->testNames[suite->currentTest], result);
133 fflush(suite->out);
134 }
135 } else {
136 printf(".");
137 }
138 }
139
140 printf("\n");
141
142 if (failures > 0) {
143 printFailures(failures);
144 } else {
145 printf("SUCCESS! %d tests ran successfully.\n", suite->size);
146 }
147 }
148
149 void assertTrueWithSource(int value, const char* file, int line, char* message) {
150 if (!value) {
151 TestSuite* suite = getTestSuite();
152
153 fprintf(suite->out, "Assertion failed: [%s:%d] %s: %s\n", file, line,
154 suite->testNames[suite->currentTest], message);
155 fflush(suite->out);
156
157 // Exit the process for this test case.
158 exit(ASSERTION_ERROR);
159 }
160 }
+0
-113
libcutils/Android.mk less more
0 #
1 # Copyright (C) 2008 The Android Open Source Project
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 LOCAL_PATH := $(my-dir)
16 include $(CLEAR_VARS)
17
18 commonSources := \
19 array.c \
20 hashmap.c \
21 atomic.c \
22 buffer.c \
23 socket_inaddr_any_server.c \
24 socket_local_client.c \
25 socket_local_server.c \
26 socket_loopback_client.c \
27 socket_loopback_server.c \
28 socket_network_client.c \
29 config_utils.c \
30 cpu_info.c \
31 load_file.c \
32 strdup16to8.c \
33 strdup8to16.c \
34 record_stream.c \
35 process_name.c \
36 properties.c \
37 threads.c
38
39 # some files must not be compiled when building against Mingw
40 # they correspond to features not used by our host development tools
41 # which are also hard or even impossible to port to native Win32
42 WITH_MINGW :=
43 ifeq ($(HOST_OS),windows)
44 ifeq ($(strip $(USE_CYGWIN)),)
45 WITH_MINGW := 1
46 endif
47 endif
48 # USE_MINGW is defined when we build against Mingw on Linux
49 ifneq ($(strip $(USE_MINGW)),)
50 WITH_MINGW := 1
51 endif
52
53 ifeq ($(WITH_MINGW),1)
54 commonSources += \
55 uio.c
56 else
57 commonSources += \
58 mspace.c \
59 selector.c \
60 fdevent.c \
61 tztime.c \
62 tzstrftime.c \
63 adb_networking.c \
64 zygote.c
65 endif
66
67
68 # Static library for host
69 # ========================================================
70 LOCAL_MODULE := libcutils
71 LOCAL_SRC_FILES := $(commonSources) ashmem-host.c
72 LOCAL_LDLIBS := -lpthread
73 LOCAL_STATIC_LIBRARIES := liblog
74 include $(BUILD_HOST_STATIC_LIBRARY)
75
76
77 ifeq ($(TARGET_SIMULATOR),true)
78
79 # Shared library for simulator
80 # ========================================================
81 include $(CLEAR_VARS)
82 LOCAL_MODULE := libcutils
83 LOCAL_SRC_FILES := $(commonSources) memory.c dlmalloc_stubs.c ashmem-host.c
84 LOCAL_LDLIBS := -lpthread
85 LOCAL_SHARED_LIBRARIES := liblog
86 include $(BUILD_SHARED_LIBRARY)
87
88 else #!sim
89
90 # Shared and static library for target
91 # ========================================================
92 include $(CLEAR_VARS)
93 LOCAL_MODULE := libcutils
94 LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c
95
96 ifeq ($(TARGET_ARCH),arm)
97 LOCAL_SRC_FILES += memset32.S atomic-android-arm.S
98 else # !arm
99 LOCAL_SRC_FILES += memory.c
100 endif # !arm
101
102 LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
103 LOCAL_STATIC_LIBRARIES := liblog
104 include $(BUILD_STATIC_LIBRARY)
105
106 include $(CLEAR_VARS)
107 LOCAL_MODULE := libcutils
108 LOCAL_WHOLE_STATIC_LIBRARIES := libcutils
109 LOCAL_SHARED_LIBRARIES := liblog
110 include $(BUILD_SHARED_LIBRARY)
111
112 endif #!sim
+0
-0
libcutils/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
libcutils/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-172
libcutils/adb_networking.c less more
0 /* libs/utils/adb_networking.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #define ADB_PORT 5037
18
19 #define _GNU_SOURCE /* for asprintf */
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <string.h>
27
28 #include <cutils/adb_networking.h>
29 #include <cutils/sockets.h>
30 #include <cutils/properties.h>
31
32 #define ADB_RESPONSE_SIZE 4
33
34 /**
35 * Unfortunately, java.net.Socket wants to create it's filedescriptor early
36 * So, this function takes an fd that must be an unconnected
37 * PF_LOCAL SOCK_STREAM
38 */
39 int adb_networking_connect_fd(int fd, struct sockaddr_in *p_address)
40 {
41 struct sockaddr_in local_addr;
42 socklen_t alen;
43 char *cmd;
44 char buf[ADB_RESPONSE_SIZE + 1];
45 ssize_t count_read;
46 int ret;
47 int err;
48 /* for impl of inet_ntoa below*/
49 union {
50 uint8_t b[4];
51 uint32_t l;
52 } a;
53
54 /* First, connect to adb */
55
56 memset(&local_addr, 0, sizeof(local_addr));
57 local_addr.sin_family = AF_INET;
58 local_addr.sin_port = htons(ADB_PORT);
59 local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
60
61 do {
62 err = connect(fd, (struct sockaddr *) &local_addr, sizeof(local_addr));
63 } while (err < 0 && errno == EINTR);
64
65 if (err < 0) {
66 return -1;
67 }
68
69 a.l = p_address->sin_addr.s_addr;
70
71 // compose the command
72 asprintf(&cmd, "tcp:%u:%u.%u.%u.%u",
73 (unsigned int)ntohs(p_address->sin_port),
74 a.b[0],a.b[1],a.b[2],a.b[3]);
75
76 // buf is now the ascii hex length of cmd
77 snprintf(buf, sizeof(buf), "%04X", strlen(cmd));
78
79 // write the 4-byte length
80 do {
81 err = write(fd, buf, 4);
82 } while (err < 0 && errno == EINTR);
83
84 // write the command
85 do {
86 err = write(fd, cmd, strlen(cmd));
87 } while (err < 0 && errno == EINTR);
88
89 // read the result
90 do {
91 count_read = read(fd, buf, sizeof(buf) - 1);
92 } while (count_read < 0 && errno != EINTR);
93
94 if (count_read == ADB_RESPONSE_SIZE
95 && 0 == strncmp(buf, "OKAY", ADB_RESPONSE_SIZE)) {
96 ret = 0;
97 } else {
98 /* what errno here? <shrug? */
99 errno = ENETUNREACH;
100 ret = -1;
101 }
102
103 free(cmd);
104
105 return ret;
106 }
107
108 /**
109 * Fills in *p_out_addr and returns 0 on success
110 * Memset's *p_out_addr and returns -1 on fail
111 */
112
113 int adb_networking_gethostbyname(const char *name, struct in_addr *p_out_addr)
114 {
115 int fd;
116 char *cmd = NULL;
117 char buf[ADB_RESPONSE_SIZE + 1];
118 int err;
119 ssize_t count_read;
120
121 fd = socket_loopback_client(ADB_PORT, SOCK_STREAM);
122
123 if (fd < 0) {
124 return -1;
125 }
126
127 // compose the command
128 asprintf(&cmd, "dns:%s", name);
129
130 // buf is now the ascii hex length of cmd
131 snprintf(buf, sizeof(buf), "%04X", strlen(cmd));
132
133 // write the 4-byte length
134 do {
135 err = write(fd, buf, 4);
136 } while (err < 0 && errno == EINTR);
137
138 // write the command
139 do {
140 err = write(fd, cmd, strlen(cmd));
141 } while (err < 0 && errno == EINTR);
142
143 // read the result
144 do {
145 count_read = read(fd, buf, ADB_RESPONSE_SIZE);
146 } while (count_read < 0 && errno != EINTR);
147
148 if (count_read != ADB_RESPONSE_SIZE
149 || 0 != strncmp(buf, "OKAY", ADB_RESPONSE_SIZE)) {
150 goto error;
151 }
152
153 // read the actual IP address
154 do {
155 count_read = read(fd, &(p_out_addr->s_addr), sizeof(p_out_addr->s_addr));
156 } while (count_read < 0 && errno != EINTR);
157
158 if (count_read != 4) {
159 goto error;
160 }
161
162 free(cmd);
163 close(fd);
164 return 0;
165 error:
166 free(cmd);
167 close(fd);
168 memset(p_out_addr, 0, sizeof(struct in_addr));
169 return -1;
170 }
171
+0
-155
libcutils/array.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cutils/array.h>
17 #include <assert.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #define INITIAL_CAPACITY (4)
22
23 struct Array {
24 void** contents;
25 int size;
26 int capacity;
27 };
28
29 Array* arrayCreate() {
30 return calloc(1, sizeof(struct Array));
31 }
32
33 void arrayFree(Array* array) {
34 assert(array != NULL);
35
36 // Free internal array.
37 free(array->contents);
38
39 // Free the Array itself.
40 free(array);
41 }
42
43 /** Returns 0 if successful, < 0 otherwise.. */
44 static int ensureCapacity(Array* array, int capacity) {
45 int oldCapacity = array->capacity;
46 if (capacity > oldCapacity) {
47 int newCapacity = (oldCapacity == 0) ? INITIAL_CAPACITY : oldCapacity * 2;
48
49 // Keep doubling capacity until we surpass necessary capacity.
50 while (newCapacity < capacity) {
51 newCapacity *= 2;
52 }
53
54 void** newContents;
55 if (array->contents == NULL) {
56 // Allocate new array.
57 newContents = malloc(newCapacity * sizeof(void*));
58 if (newContents == NULL) {
59 return -1;
60 }
61 } else {
62 // Expand existing array.
63 newContents = realloc(array->contents, sizeof(void*) * newCapacity);
64 if (newContents == NULL) {
65 return -1;
66 }
67 }
68
69 array->capacity = newCapacity;
70 array->contents = newContents;
71 }
72
73 return 0;
74 }
75
76 int arrayAdd(Array* array, void* pointer) {
77 assert(array != NULL);
78 int size = array->size;
79 int result = ensureCapacity(array, size + 1);
80 if (result < 0) {
81 return result;
82 }
83 array->contents[size] = pointer;
84 array->size++;
85 return 0;
86 }
87
88 static inline void checkBounds(Array* array, int index) {
89 assert(array != NULL);
90 assert(index < array->size);
91 assert(index >= 0);
92 }
93
94 void* arrayGet(Array* array, int index) {
95 checkBounds(array, index);
96 return array->contents[index];
97 }
98
99 void* arrayRemove(Array* array, int index) {
100 checkBounds(array, index);
101
102 void* pointer = array->contents[index];
103
104 int newSize = array->size - 1;
105
106 // Shift entries left.
107 if (index != newSize) {
108 memmove(array->contents + index, array->contents + index + 1,
109 (sizeof(void*)) * (newSize - index));
110 }
111
112 array->size = newSize;
113
114 return pointer;
115 }
116
117 void* arraySet(Array* array, int index, void* pointer) {
118 checkBounds(array, index);
119 void* old = array->contents[index];
120 array->contents[index] = pointer;
121 return old;
122 }
123
124 int arraySetSize(Array* array, int newSize) {
125 assert(array != NULL);
126 assert(newSize >= 0);
127
128 int oldSize = array->size;
129
130 if (newSize > oldSize) {
131 // Expand.
132 int result = ensureCapacity(array, newSize);
133 if (result < 0) {
134 return result;
135 }
136
137 // Zero out new entries.
138 memset(array->contents + sizeof(void*) * oldSize, 0,
139 sizeof(void*) * (newSize - oldSize));
140 }
141
142 array->size = newSize;
143
144 return 0;
145 }
146
147 int arraySize(Array* array) {
148 assert(array != NULL);
149 return array->size;
150 }
151
152 const void** arrayUnwrap(Array* array) {
153 return array->contents;
154 }
+0
-85
libcutils/ashmem-dev.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * Implementation of the user-space ashmem API for devices, which have our
18 * ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
19 * used by the simulator.
20 */
21
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/ioctl.h>
27 #include <fcntl.h>
28
29 #include <linux/ashmem.h>
30 #include <cutils/ashmem.h>
31
32 #define ASHMEM_DEVICE "/dev/ashmem"
33
34 /*
35 * ashmem_create_region - creates a new ashmem region and returns the file
36 * descriptor, or <0 on error
37 *
38 * `name' is an optional label to give the region (visible in /proc/pid/maps)
39 * `size' is the size of the region, in page-aligned bytes
40 */
41 int ashmem_create_region(const char *name, size_t size)
42 {
43 int fd, ret;
44
45 fd = open(ASHMEM_DEVICE, O_RDWR);
46 if (fd < 0)
47 return fd;
48
49 if (name) {
50 char buf[ASHMEM_NAME_LEN];
51
52 strlcpy(buf, name, sizeof(buf));
53 ret = ioctl(fd, ASHMEM_SET_NAME, buf);
54 if (ret < 0)
55 goto error;
56 }
57
58 ret = ioctl(fd, ASHMEM_SET_SIZE, size);
59 if (ret < 0)
60 goto error;
61
62 return fd;
63
64 error:
65 close(fd);
66 return ret;
67 }
68
69 int ashmem_set_prot_region(int fd, int prot)
70 {
71 return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
72 }
73
74 int ashmem_pin_region(int fd, size_t offset, size_t len)
75 {
76 struct ashmem_pin pin = { offset, len };
77 return ioctl(fd, ASHMEM_PIN, &pin);
78 }
79
80 int ashmem_unpin_region(int fd, size_t offset, size_t len)
81 {
82 struct ashmem_pin pin = { offset, len };
83 return ioctl(fd, ASHMEM_UNPIN, &pin);
84 }
+0
-94
libcutils/ashmem-host.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * Implementation of the user-space ashmem API for the simulator, which lacks
18 * an ashmem-enabled kernel. See ashmem-dev.c for the real ashmem-based version.
19 */
20
21 #include <unistd.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <limits.h>
31
32 #include <cutils/ashmem.h>
33
34 int ashmem_create_region(const char *ignored, size_t size)
35 {
36 static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
37 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
38 char name[64];
39 unsigned int retries = 0;
40 pid_t pid = getpid();
41 int fd;
42
43 srand(time(NULL) + pid);
44
45 retry:
46 /* not beautiful, its just wolf-like loop unrolling */
47 snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
48 pid,
49 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
50 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
51 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
52 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
53 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
54 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
55 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
56 txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
57
58 /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
59 fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
60 if (fd == -1) {
61 /* unlikely, but if we failed because `name' exists, retry */
62 if (errno == EEXIST && ++retries < 6)
63 goto retry;
64 return -1;
65 }
66
67 /* truncate the file to `len' bytes */
68 if (ftruncate(fd, size) == -1)
69 goto error;
70
71 if (unlink(name) == -1)
72 goto error;
73
74 return fd;
75 error:
76 close(fd);
77 return -1;
78 }
79
80 int ashmem_set_prot_region(int fd, int prot)
81 {
82 return 0;
83 }
84
85 int ashmem_pin_region(int fd, size_t offset, size_t len)
86 {
87 return ASHMEM_NOT_PURGED;
88 }
89
90 int ashmem_unpin_region(int fd, size_t offset, size_t len)
91 {
92 return ASHMEM_IS_UNPINNED;
93 }
+0
-274
libcutils/atomic-android-arm.S less more
0 /*
1 * Copyright (C) 2005 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <machine/cpu-features.h>
17
18 /*
19 * NOTE: these atomic operations are SMP safe on all architectures,
20 * except swap(), see below.
21 */
22
23 .text
24 .align
25
26 .global android_atomic_write
27
28 .global android_atomic_inc
29 .global android_atomic_dec
30
31 .global android_atomic_add
32 .global android_atomic_and
33 .global android_atomic_or
34
35 .global android_atomic_swap
36
37 .global android_atomic_cmpxchg
38
39 /*
40 * ----------------------------------------------------------------------------
41 * int __kernel_cmpxchg(int oldval, int newval, int *ptr)
42 * clobbered: r3, ip, flags
43 * return 0 if a swap was made, non-zero otherwise.
44 */
45
46 .equ kernel_cmpxchg, 0xFFFF0FC0
47 .equ kernel_atomic_base, 0xFFFF0FFF
48
49 /*
50 * ----------------------------------------------------------------------------
51 * android_atomic_write
52 * input: r0=value, r1=address
53 * output: void
54 */
55
56 android_atomic_write:
57 stmdb sp!, {r4, lr}
58 mov r2, r1
59 mov r1, r0
60 1: @ android_atomic_write
61 ldr r0, [r2]
62 mov r3, #kernel_atomic_base
63 #ifdef __ARM_HAVE_PC_INTERWORK
64 add lr, pc, #4
65 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
66 #else
67 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
68 mov lr, pc
69 bx r3
70 #endif
71 bcc 1b
72 ldmia sp!, {r4, lr}
73 bx lr
74
75 /*
76 * ----------------------------------------------------------------------------
77 * android_atomic_inc
78 * input: r0 = address
79 * output: r0 = old value
80 */
81
82 android_atomic_inc:
83 stmdb sp!, {r4, lr}
84 mov r2, r0
85 1: @ android_atomic_inc
86 ldr r0, [r2]
87 mov r3, #kernel_atomic_base
88 #ifdef __ARM_HAVE_PC_INTERWORK
89 add lr, pc, #4
90 add r1, r0, #1
91 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
92 #else
93 add r1, r0, #1
94 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
95 mov lr, pc
96 bx r3
97 #endif
98 bcc 1b
99 sub r0, r1, #1
100 ldmia sp!, {r4, lr}
101 bx lr
102
103 /*
104 * ----------------------------------------------------------------------------
105 * android_atomic_dec
106 * input: r0=address
107 * output: r0 = old value
108 */
109
110 android_atomic_dec:
111 stmdb sp!, {r4, lr}
112 mov r2, r0
113 1: @ android_atomic_dec
114 ldr r0, [r2]
115 mov r3, #kernel_atomic_base
116 #ifdef __ARM_HAVE_PC_INTERWORK
117 add lr, pc, #4
118 sub r1, r0, #1
119 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
120 #else
121 sub r1, r0, #1
122 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
123 mov lr, pc
124 bx r3
125 #endif
126 bcc 1b
127 add r0, r1, #1
128 ldmia sp!, {r4, lr}
129 bx lr
130
131 /*
132 * ----------------------------------------------------------------------------
133 * android_atomic_add
134 * input: r0=value, r1=address
135 * output: r0 = old value
136 */
137
138 android_atomic_add:
139 stmdb sp!, {r4, lr}
140 mov r2, r1
141 mov r4, r0
142 1: @ android_atomic_add
143 ldr r0, [r2]
144 mov r3, #kernel_atomic_base
145 #ifdef __ARM_HAVE_PC_INTERWORK
146 add lr, pc, #4
147 add r1, r0, r4
148 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
149 #else
150 add r1, r0, r4
151 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
152 mov lr, pc
153 bx r3
154 #endif
155 bcc 1b
156 sub r0, r1, r4
157 ldmia sp!, {r4, lr}
158 bx lr
159
160
161 /*
162 * ----------------------------------------------------------------------------
163 * android_atomic_and
164 * input: r0=value, r1=address
165 * output: r0 = old value
166 */
167
168 android_atomic_and:
169 stmdb sp!, {r4, r5, lr}
170 mov r2, r1 /* r2 = address */
171 mov r4, r0 /* r4 = the value */
172 1: @ android_atomic_and
173 ldr r0, [r2] /* r0 = address[0] */
174 mov r3, #kernel_atomic_base
175 #ifdef __ARM_HAVE_PC_INTERWORK
176 add lr, pc, #8
177 mov r5, r0 /* r5 = save address[0] */
178 and r1, r0, r4 /* r1 = new value */
179 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
180 #else
181 mov r5, r0 /* r5 = save address[0] */
182 and r1, r0, r4 /* r1 = new value */
183 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
184 mov lr, pc
185 bx r3
186 #endif
187 bcc 1b
188 mov r0, r5
189 ldmia sp!, {r4, r5, lr}
190 bx lr
191
192 /*
193 * ----------------------------------------------------------------------------
194 * android_atomic_or
195 * input: r0=value, r1=address
196 * output: r0 = old value
197 */
198
199 android_atomic_or:
200 stmdb sp!, {r4, r5, lr}
201 mov r2, r1 /* r2 = address */
202 mov r4, r0 /* r4 = the value */
203 1: @ android_atomic_or
204 ldr r0, [r2] /* r0 = address[0] */
205 mov r3, #kernel_atomic_base
206 #ifdef __ARM_HAVE_PC_INTERWORK
207 add lr, pc, #8
208 mov r5, r0 /* r5 = save address[0] */
209 orr r1, r0, r4 /* r1 = new value */
210 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
211 #else
212 mov r5, r0 /* r5 = save address[0] */
213 orr r1, r0, r4 /* r1 = new value */
214 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
215 mov lr, pc
216 bx r3
217 #endif
218 bcc 1b
219 mov r0, r5
220 ldmia sp!, {r4, r5, lr}
221 bx lr
222
223 /*
224 * ----------------------------------------------------------------------------
225 * android_atomic_swap
226 * input: r0=value, r1=address
227 * output: r0 = old value
228 */
229
230 /* FIXME: this is not safe on SMP systems
231 * a general way to do it is to use kernel_cmpxchg */
232
233 android_atomic_swap:
234 swp r0, r0, [r1]
235 bx lr
236
237 /*
238 * ----------------------------------------------------------------------------
239 * android_atomic_cmpxchg
240 * input: r0=oldvalue, r1=newvalue, r2=address
241 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
242 */
243
244 android_atomic_cmpxchg:
245 stmdb sp!, {r4, lr}
246 mov r4, r0 /* r4 = save oldvalue */
247 1: @ android_atomic_cmpxchg
248 mov r3, #kernel_atomic_base
249 #ifdef __ARM_HAVE_PC_INTERWORK
250 add lr, pc, #4
251 mov r0, r4 /* r0 = oldvalue */
252 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
253 #else
254 mov r0, r4 /* r0 = oldvalue */
255 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
256 mov lr, pc
257 bx r3
258 #endif
259 bcs 2f /* swap was made. we're good, return. */
260 ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
261 cmp r3, r4
262 beq 1b
263 2: @ android_atomic_cmpxchg
264 ldmia sp!, {r4, lr}
265 bx lr
266
267 /*
268 * ----------------------------------------------------------------------------
269 * android_atomic_cmpxchg_64
270 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
271 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
272 */
273 /* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */
+0
-169
libcutils/atomic-android-armv6.S less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17 .text
18 .align
19
20 .global android_atomic_write
21
22 .global android_atomic_inc
23 .global android_atomic_dec
24
25 .global android_atomic_add
26 .global android_atomic_and
27 .global android_atomic_or
28
29 .global android_atomic_swap
30
31 .global android_atomic_cmpxchg
32
33
34
35 /* FIXME: On SMP systems memory barriers may be needed */
36 #warning "this file is not safe with SMP systems"
37
38
39 /*
40 * ----------------------------------------------------------------------------
41 * android_atomic_write
42 * input: r0=value, r1=address
43 * output: void
44 */
45
46 android_atomic_write:
47 1: ldrex r12, [r1]
48 strex r12, r0, [r1]
49 cmp r12, #0
50 bne 1b
51 bx lr
52
53 /*
54 * ----------------------------------------------------------------------------
55 * android_atomic_inc
56 * input: r0 = address
57 * output: r0 = old value
58 */
59
60 android_atomic_inc:
61 mov r12, r0
62 1: ldrex r0, [r12]
63 add r2, r0, #1
64 strex r1, r2, [r12]
65 cmp r1, #0
66 bxeq lr
67 b 1b
68
69 /*
70 * ----------------------------------------------------------------------------
71 * android_atomic_dec
72 * input: r0=address
73 * output: r0 = old value
74 */
75
76 android_atomic_dec:
77 mov r12, r0
78 1: ldrex r0, [r12]
79 sub r2, r0, #1
80 strex r1, r2, [r12]
81 cmp r1, #0
82 bxeq lr
83 b 1b
84
85
86 /*
87 * ----------------------------------------------------------------------------
88 * android_atomic_add
89 * input: r0=value, r1=address
90 * output: r0 = old value
91 */
92
93 android_atomic_add:
94 mov r12, r0
95 1: ldrex r0, [r1]
96 add r2, r0, r12
97 strex r3, r2, [r1]
98 cmp r3, #0
99 bxeq lr
100 b 1b
101
102 /*
103 * ----------------------------------------------------------------------------
104 * android_atomic_and
105 * input: r0=value, r1=address
106 * output: r0 = old value
107 */
108
109 android_atomic_and:
110 mov r12, r0
111 1: ldrex r0, [r1]
112 and r2, r0, r12
113 strex r3, r2, [r1]
114 cmp r3, #0
115 bxeq lr
116 b 1b
117
118
119 /*
120 * ----------------------------------------------------------------------------
121 * android_atomic_or
122 * input: r0=value, r1=address
123 * output: r0 = old value
124 */
125
126 android_atomic_or:
127 mov r12, r0
128 1: ldrex r0, [r1]
129 orr r2, r0, r12
130 strex r3, r2, [r1]
131 cmp r3, #0
132 bxeq lr
133 b 1b
134
135 /*
136 * ----------------------------------------------------------------------------
137 * android_atomic_swap
138 * input: r0=value, r1=address
139 * output: r0 = old value
140 */
141
142 android_atomic_swap:
143 swp r0, r0, [r1]
144 bx lr
145
146 /*
147 * ----------------------------------------------------------------------------
148 * android_atomic_cmpxchg
149 * input: r0=oldvalue, r1=newvalue, r2=address
150 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
151 */
152
153 android_atomic_cmpxchg:
154 mov r12, r1
155 ldrex r3, [r2]
156 eors r0, r0, r3
157 strexeq r0, r12, [r2]
158 bx lr
159
160
161
162 /*
163 * ----------------------------------------------------------------------------
164 * android_atomic_cmpxchg_64
165 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
166 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
167 */
168 /* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */
+0
-335
libcutils/atomic.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cutils/atomic.h>
17 #ifdef HAVE_WIN32_THREADS
18 #include <windows.h>
19 #else
20 #include <sched.h>
21 #endif
22
23 /*****************************************************************************/
24 #if defined(HAVE_MACOSX_IPC)
25
26 #include <libkern/OSAtomic.h>
27
28 void android_atomic_write(int32_t value, volatile int32_t* addr) {
29 int32_t oldValue;
30 do {
31 oldValue = *addr;
32 } while (OSAtomicCompareAndSwap32Barrier(oldValue, value, (int32_t*)addr) == 0);
33 }
34
35 int32_t android_atomic_inc(volatile int32_t* addr) {
36 return OSAtomicIncrement32Barrier((int32_t*)addr)-1;
37 }
38
39 int32_t android_atomic_dec(volatile int32_t* addr) {
40 return OSAtomicDecrement32Barrier((int32_t*)addr)+1;
41 }
42
43 int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
44 return OSAtomicAdd32Barrier(value, (int32_t*)addr)-value;
45 }
46
47 int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
48 int32_t oldValue;
49 do {
50 oldValue = *addr;
51 } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue&value, (int32_t*)addr) == 0);
52 return oldValue;
53 }
54
55 int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
56 int32_t oldValue;
57 do {
58 oldValue = *addr;
59 } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue|value, (int32_t*)addr) == 0);
60 return oldValue;
61 }
62
63 int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
64 int32_t oldValue;
65 do {
66 oldValue = *addr;
67 } while (android_atomic_cmpxchg(oldValue, value, addr));
68 return oldValue;
69 }
70
71 int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
72 return OSAtomicCompareAndSwap32Barrier(oldvalue, newvalue, (int32_t*)addr) == 0;
73 }
74
75 #if defined(__ppc__) \
76 || defined(__PPC__) \
77 || defined(__powerpc__) \
78 || defined(__powerpc) \
79 || defined(__POWERPC__) \
80 || defined(_M_PPC) \
81 || defined(__PPC)
82 #define NEED_QUASIATOMICS 1
83 #else
84
85 int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
86 volatile int64_t* addr) {
87 return OSAtomicCompareAndSwap64Barrier(oldvalue, newvalue,
88 (int64_t*)addr) == 0;
89 }
90
91 int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
92 int64_t oldValue;
93 do {
94 oldValue = *addr;
95 } while (android_quasiatomic_cmpxchg_64(oldValue, value, addr));
96 return oldValue;
97 }
98
99 int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
100 return OSAtomicAdd64Barrier(0, addr);
101 }
102
103 #endif
104
105
106 /*****************************************************************************/
107 #elif defined(__i386__) || defined(__x86_64__)
108
109 void android_atomic_write(int32_t value, volatile int32_t* addr) {
110 int32_t oldValue;
111 do {
112 oldValue = *addr;
113 } while (android_atomic_cmpxchg(oldValue, value, addr));
114 }
115
116 int32_t android_atomic_inc(volatile int32_t* addr) {
117 int32_t oldValue;
118 do {
119 oldValue = *addr;
120 } while (android_atomic_cmpxchg(oldValue, oldValue+1, addr));
121 return oldValue;
122 }
123
124 int32_t android_atomic_dec(volatile int32_t* addr) {
125 int32_t oldValue;
126 do {
127 oldValue = *addr;
128 } while (android_atomic_cmpxchg(oldValue, oldValue-1, addr));
129 return oldValue;
130 }
131
132 int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
133 int32_t oldValue;
134 do {
135 oldValue = *addr;
136 } while (android_atomic_cmpxchg(oldValue, oldValue+value, addr));
137 return oldValue;
138 }
139
140 int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
141 int32_t oldValue;
142 do {
143 oldValue = *addr;
144 } while (android_atomic_cmpxchg(oldValue, oldValue&value, addr));
145 return oldValue;
146 }
147
148 int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
149 int32_t oldValue;
150 do {
151 oldValue = *addr;
152 } while (android_atomic_cmpxchg(oldValue, oldValue|value, addr));
153 return oldValue;
154 }
155
156 int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
157 int32_t oldValue;
158 do {
159 oldValue = *addr;
160 } while (android_atomic_cmpxchg(oldValue, value, addr));
161 return oldValue;
162 }
163
164 int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
165 int xchg;
166 asm volatile
167 (
168 " lock; cmpxchg %%ecx, (%%edx);"
169 " setne %%al;"
170 " andl $1, %%eax"
171 : "=a" (xchg)
172 : "a" (oldvalue), "c" (newvalue), "d" (addr)
173 );
174 return xchg;
175 }
176
177 #define NEED_QUASIATOMICS 1
178
179 /*****************************************************************************/
180 #elif __arm__
181 // Most of the implementation is in atomic-android-arm.s.
182
183 // on the device, we implement the 64-bit atomic operations through
184 // mutex locking. normally, this is bad because we must initialize
185 // a pthread_mutex_t before being able to use it, and this means
186 // having to do an initialization check on each function call, and
187 // that's where really ugly things begin...
188 //
189 // BUT, as a special twist, we take advantage of the fact that in our
190 // pthread library, a mutex is simply a volatile word whose value is always
191 // initialized to 0. In other words, simply declaring a static mutex
192 // object initializes it !
193 //
194 // another twist is that we use a small array of mutexes to dispatch
195 // the contention locks from different memory addresses
196 //
197
198 #include <pthread.h>
199
200 #define SWAP_LOCK_COUNT 32U
201 static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT];
202
203 #define SWAP_LOCK(addr) \
204 &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
205
206
207 int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
208 int64_t oldValue;
209 pthread_mutex_t* lock = SWAP_LOCK(addr);
210
211 pthread_mutex_lock(lock);
212
213 oldValue = *addr;
214 *addr = value;
215
216 pthread_mutex_unlock(lock);
217 return oldValue;
218 }
219
220 int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
221 volatile int64_t* addr) {
222 int result;
223 pthread_mutex_t* lock = SWAP_LOCK(addr);
224
225 pthread_mutex_lock(lock);
226
227 if (*addr == oldvalue) {
228 *addr = newvalue;
229 result = 0;
230 } else {
231 result = 1;
232 }
233 pthread_mutex_unlock(lock);
234 return result;
235 }
236
237 int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
238 int64_t result;
239 pthread_mutex_t* lock = SWAP_LOCK(addr);
240
241 pthread_mutex_lock(lock);
242 result = *addr;
243 pthread_mutex_unlock(lock);
244 return result;
245 }
246
247 #else
248
249 #error "Unsupported atomic operations for this platform"
250
251 #endif
252
253
254
255 #if NEED_QUASIATOMICS
256
257 /* Note that a spinlock is *not* a good idea in general
258 * since they can introduce subtle issues. For example,
259 * a real-time thread trying to acquire a spinlock already
260 * acquired by another thread will never yeld, making the
261 * CPU loop endlessly!
262 *
263 * However, this code is only used on the Linux simulator
264 * so it's probably ok for us.
265 *
266 * The alternative is to use a pthread mutex, but
267 * these must be initialized before being used, and
268 * then you have the problem of lazily initializing
269 * a mutex without any other synchronization primitive.
270 */
271
272 /* global spinlock for all 64-bit quasiatomic operations */
273 static int32_t quasiatomic_spinlock = 0;
274
275 int android_quasiatomic_cmpxchg_64(int64_t oldvalue, int64_t newvalue,
276 volatile int64_t* addr) {
277 int result;
278
279 while (android_atomic_cmpxchg(0, 1, &quasiatomic_spinlock)) {
280 #ifdef HAVE_WIN32_THREADS
281 Sleep(0);
282 #else
283 sched_yield();
284 #endif
285 }
286
287 if (*addr == oldvalue) {
288 *addr = newvalue;
289 result = 0;
290 } else {
291 result = 1;
292 }
293
294 android_atomic_swap(0, &quasiatomic_spinlock);
295
296 return result;
297 }
298
299 int64_t android_quasiatomic_read_64(volatile int64_t* addr) {
300 int64_t result;
301
302 while (android_atomic_cmpxchg(0, 1, &quasiatomic_spinlock)) {
303 #ifdef HAVE_WIN32_THREADS
304 Sleep(0);
305 #else
306 sched_yield();
307 #endif
308 }
309
310 result = *addr;
311 android_atomic_swap(0, &quasiatomic_spinlock);
312
313 return result;
314 }
315
316 int64_t android_quasiatomic_swap_64(int64_t value, volatile int64_t* addr) {
317 int64_t result;
318
319 while (android_atomic_cmpxchg(0, 1, &quasiatomic_spinlock)) {
320 #ifdef HAVE_WIN32_THREADS
321 Sleep(0);
322 #else
323 sched_yield();
324 #endif
325 }
326
327 result = *addr;
328 *addr = value;
329 android_atomic_swap(0, &quasiatomic_spinlock);
330
331 return result;
332 }
333
334 #endif
+0
-116
libcutils/buffer.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "buffer"
17
18 #include <assert.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22
23 #include "buffer.h"
24 #include "loghack.h"
25
26 Buffer* bufferCreate(size_t capacity) {
27 Buffer* buffer = malloc(sizeof(Buffer));
28 if (buffer == NULL) {
29 return NULL;
30 }
31 buffer->capacity = capacity;
32 buffer->expected = 0;
33 buffer->data = malloc(capacity);
34 if (buffer->data == NULL) {
35 free(buffer);
36 return NULL;
37 }
38 return buffer;
39 }
40
41 void bufferFree(Buffer* buffer) {
42 free(buffer->data);
43 free(buffer);
44 }
45
46 Buffer* bufferWrap(char* data, size_t capacity, size_t size) {
47 Buffer* buffer = malloc(sizeof(Buffer));
48 if (buffer == NULL) {
49 return NULL;
50 }
51
52 buffer->data = data;
53 buffer->capacity = capacity;
54 buffer->size = size;
55 buffer->expected = 0;
56 return buffer;
57 }
58
59 int bufferPrepareForRead(Buffer* buffer, size_t expected) {
60 if (expected > buffer->capacity) {
61 // Expand buffer.
62 char* expanded = realloc(buffer->data, expected);
63 if (expanded == NULL) {
64 errno = ENOMEM;
65 return -1;
66 }
67 buffer->capacity = expected;
68 buffer->data = expanded;
69 }
70
71 buffer->size = 0;
72 buffer->expected = expected;
73 return 0;
74 }
75
76 ssize_t bufferRead(Buffer* buffer, int fd) {
77 assert(buffer->size < buffer->expected);
78
79 ssize_t bytesRead = read(fd,
80 buffer->data + buffer->size,
81 buffer->expected - buffer->size);
82
83 if (bytesRead > 0) {
84 buffer->size += bytesRead;
85 return buffer->size;
86 }
87
88 return bytesRead;
89 }
90
91 void bufferPrepareForWrite(Buffer* buffer) {
92 buffer->remaining = buffer->size;
93 }
94
95 ssize_t bufferWrite(Buffer* buffer, int fd) {
96 assert(buffer->remaining > 0);
97 assert(buffer->remaining <= buffer->size);
98
99 ssize_t bytesWritten = write(fd,
100 buffer->data + buffer->size - buffer->remaining,
101 buffer->remaining);
102
103 if (bytesWritten >= 0) {
104 buffer->remaining -= bytesWritten;
105
106 LOGD("Buffer bytes written: %d", (int) bytesWritten);
107 LOGD("Buffer size: %d", (int) buffer->size);
108 LOGD("Buffer remaining: %d", (int) buffer->remaining);
109
110 return buffer->remaining;
111 }
112
113 return bytesWritten;
114 }
115
+0
-112
libcutils/buffer.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Byte buffer utilities.
18 */
19
20 #ifndef __BUFFER_H
21 #define __BUFFER_H
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 #include <stdlib.h>
28
29 /**
30 * Byte buffer of known size. Keeps track of how much data has been read
31 * into or written out of the buffer.
32 */
33 typedef struct {
34 /** Buffered data. */
35 char* data;
36
37 union {
38 /** For reading. # of bytes we expect. */
39 size_t expected;
40
41 /** For writing. # of bytes to write. */
42 size_t remaining;
43 };
44
45 /** Actual # of bytes in the buffer. */
46 size_t size;
47
48 /** Amount of memory allocated for this buffer. */
49 size_t capacity;
50 } Buffer;
51
52 /**
53 * Returns true if all data has been read into the buffer.
54 */
55 #define bufferReadComplete(buffer) (buffer->expected == buffer->size)
56
57 /**
58 * Returns true if the buffer has been completely written.
59 */
60 #define bufferWriteComplete(buffer) (buffer->remaining == 0)
61
62 /**
63 * Creates a new buffer with the given initial capacity.
64 */
65 Buffer* bufferCreate(size_t initialCapacity);
66
67 /**
68 * Wraps an existing byte array.
69 */
70 Buffer* bufferWrap(char* data, size_t capacity, size_t size);
71
72 /**
73 * Frees and its data.
74 */
75 void bufferFree(Buffer* buffer);
76
77 /**
78 * Prepares buffer to read 'expected' number of bytes. Expands capacity if
79 * necessary. Returns 0 if successful or -1 if an error occurs allocating
80 * memory.
81 */
82 int bufferPrepareForRead(Buffer* buffer, size_t expected);
83
84 /**
85 * Reads some data into a buffer. Returns -1 in case of an error and sets
86 * errno (see read()). Returns 0 for EOF. Updates buffer->size and returns
87 * the new size after a succesful read.
88 *
89 * Precondition: buffer->size < buffer->expected
90 */
91 ssize_t bufferRead(Buffer* buffer, int fd);
92
93 /**
94 * Prepares a buffer to be written out.
95 */
96 void bufferPrepareForWrite(Buffer* buffer);
97
98 /**
99 * Writes data from buffer to the given fd. Returns -1 and sets errno in case
100 * of an error. Updates buffer->remaining and returns the number of remaining
101 * bytes to be written after a successful write.
102 *
103 * Precondition: buffer->remaining > 0
104 */
105 ssize_t bufferWrite(Buffer* buffer, int fd);
106
107 #ifdef __cplusplus
108 }
109 #endif
110
111 #endif /* __BUFFER_H */
+0
-317
libcutils/config_utils.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <ctype.h>
18 #include <stdlib.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21
22 #include <cutils/config_utils.h>
23 #include <cutils/misc.h>
24
25 cnode* config_node(const char *name, const char *value)
26 {
27 cnode *node;
28
29 node = calloc(sizeof(cnode), 1);
30 if(node) {
31 node->name = name ? name : "";
32 node->value = value ? value : "";
33 }
34
35 return node;
36 }
37
38 cnode* config_find(cnode *root, const char *name)
39 {
40 cnode *node, *match = NULL;
41
42 /* we walk the whole list, as we need to return the last (newest) entry */
43 for(node = root->first_child; node; node = node->next)
44 if(!strcmp(node->name, name))
45 match = node;
46
47 return match;
48 }
49
50 static cnode* _config_create(cnode *root, const char *name)
51 {
52 cnode *node;
53
54 node = config_node(name, NULL);
55
56 if(root->last_child)
57 root->last_child->next = node;
58 else
59 root->first_child = node;
60
61 root->last_child = node;
62
63 return node;
64 }
65
66 int config_bool(cnode *root, const char *name, int _default)
67 {
68 cnode *node;
69
70 node = config_find(root, name);
71 if(!node)
72 return _default;
73
74 switch(node->value[0]) {
75 case 'y':
76 case 'Y':
77 case '1':
78 return 1;
79 default:
80 return 0;
81 }
82 }
83
84 const char* config_str(cnode *root, const char *name, const char *_default)
85 {
86 cnode *node;
87
88 node = config_find(root, name);
89 if(!node)
90 return _default;
91 return node->value;
92 }
93
94 void config_set(cnode *root, const char *name, const char *value)
95 {
96 cnode *node;
97
98 node = config_find(root, name);
99 if(node)
100 node->value = value;
101 else {
102 node = _config_create(root, name);
103 node->value = value;
104 }
105 }
106
107 #define T_EOF 0
108 #define T_TEXT 1
109 #define T_DOT 2
110 #define T_OBRACE 3
111 #define T_CBRACE 4
112
113 typedef struct
114 {
115 char *data;
116 char *text;
117 int len;
118 char next;
119 } cstate;
120
121 static int _lex(cstate *cs, int value)
122 {
123 char c;
124 char *s;
125 char *data;
126
127 data = cs->data;
128
129 if(cs->next != 0) {
130 c = cs->next;
131 cs->next = 0;
132 goto got_c;
133 }
134
135 restart:
136 for(;;) {
137 c = *data++;
138 got_c:
139 if(isspace(c))
140 continue;
141
142 switch(c) {
143 case 0:
144 return T_EOF;
145
146 case '#':
147 for(;;) {
148 switch(*data) {
149 case 0:
150 cs->data = data;
151 return T_EOF;
152 case '\n':
153 cs->data = data + 1;
154 goto restart;
155 default:
156 data++;
157 }
158 }
159 break;
160
161 case '.':
162 cs->data = data;
163 return T_DOT;
164
165 case '{':
166 cs->data = data;
167 return T_OBRACE;
168
169 case '}':
170 cs->data = data;
171 return T_CBRACE;
172
173 default:
174 s = data - 1;
175
176 if(value) {
177 for(;;) {
178 if(*data == 0) {
179 cs->data = data;
180 break;
181 }
182 if(*data == '\n') {
183 cs->data = data + 1;
184 *data-- = 0;
185 break;
186 }
187 data++;
188 }
189
190 /* strip trailing whitespace */
191 while(data > s){
192 if(!isspace(*data)) break;
193 *data-- = 0;
194 }
195
196 goto got_text;
197 } else {
198 for(;;) {
199 if(isspace(*data)) {
200 *data = 0;
201 cs->data = data + 1;
202 goto got_text;
203 }
204 switch(*data) {
205 case 0:
206 cs->data = data;
207 goto got_text;
208 case '.':
209 case '{':
210 case '}':
211 cs->next = *data;
212 *data = 0;
213 cs->data = data + 1;
214 goto got_text;
215 default:
216 data++;
217 }
218 }
219 }
220 }
221 }
222
223 got_text:
224 cs->text = s;
225 return T_TEXT;
226 }
227
228 #if 0
229 char *TOKENNAMES[] = { "EOF", "TEXT", "DOT", "OBRACE", "CBRACE" };
230
231 static int lex(cstate *cs, int value)
232 {
233 int tok = _lex(cs, value);
234 printf("TOKEN(%d) %s %s\n", value, TOKENNAMES[tok],
235 tok == T_TEXT ? cs->text : "");
236 return tok;
237 }
238 #else
239 #define lex(cs,v) _lex(cs,v)
240 #endif
241
242 static int parse_expr(cstate *cs, cnode *node);
243
244 static int parse_block(cstate *cs, cnode *node)
245 {
246 for(;;){
247 switch(lex(cs, 0)){
248 case T_TEXT:
249 if(parse_expr(cs, node)) return -1;
250 continue;
251
252 case T_CBRACE:
253 return 0;
254
255 default:
256 return -1;
257 }
258 }
259 }
260
261 static int parse_expr(cstate *cs, cnode *root)
262 {
263 cnode *node;
264
265 /* last token was T_TEXT */
266 node = config_find(root, cs->text);
267 if(!node || *node->value)
268 node = _config_create(root, cs->text);
269
270 for(;;) {
271 switch(lex(cs, 1)) {
272 case T_DOT:
273 if(lex(cs, 0) != T_TEXT)
274 return -1;
275 node = _config_create(node, cs->text);
276 continue;
277
278 case T_TEXT:
279 node->value = cs->text;
280 return 0;
281
282 case T_OBRACE:
283 return parse_block(cs, node);
284
285 default:
286 return -1;
287 }
288 }
289 }
290
291 void config_load(cnode *root, char *data)
292 {
293 if(data != 0) {
294 cstate cs;
295 cs.data = data;
296 cs.next = 0;
297
298 for(;;) {
299 switch(lex(&cs, 0)) {
300 case T_TEXT:
301 if(parse_expr(&cs, root))
302 return;
303 break;
304 default:
305 return;
306 }
307 }
308 }
309 }
310
311 void config_load_file(cnode *root, const char *fn)
312 {
313 char *data;
314 data = load_file(fn, 0);
315 config_load(root, data);
316 }
+0
-83
libcutils/cpu_info.c less more
0 /* libs/cutils/cpu_info.c
1 **
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/cpu_info.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 // we cache the serial number here.
23 // this is also used as a fgets() line buffer when we are reading /proc/cpuinfo
24 static char serial_number[100] = { 0 };
25
26 extern const char* get_cpu_serial_number(void)
27 {
28 if (serial_number[0] == 0)
29 {
30 FILE* file;
31 char* chp, *end;
32 char* whitespace;
33 int length;
34
35 // read serial number from /proc/cpuinfo
36 file = fopen("proc/cpuinfo", "r");
37 if (! file)
38 return NULL;
39
40 while ((chp = fgets(serial_number, sizeof(serial_number), file)) != NULL)
41 {
42 // look for something like "Serial : 999206122a03591c"
43
44 if (strncmp(chp, "Serial", 6) != 0)
45 continue;
46
47 chp = strchr(chp, ':');
48 if (!chp)
49 continue;
50
51 // skip colon and whitespace
52 while ( *(++chp) == ' ') {}
53
54 // truncate trailing whitespace
55 end = chp;
56 while (*end && *end != ' ' && *end != '\t' && *end != '\n' && *end != '\r')
57 ++end;
58 *end = 0;
59
60 whitespace = strchr(chp, ' ');
61 if (whitespace)
62 *whitespace = 0;
63 whitespace = strchr(chp, '\t');
64 if (whitespace)
65 *whitespace = 0;
66 whitespace = strchr(chp, '\r');
67 if (whitespace)
68 *whitespace = 0;
69 whitespace = strchr(chp, '\n');
70 if (whitespace)
71 *whitespace = 0;
72
73 // shift serial number to beginning of the buffer
74 memmove(serial_number, chp, strlen(chp) + 1);
75 break;
76 }
77
78 fclose(file);
79 }
80
81 return (serial_number[0] ? serial_number : NULL);
82 }
+0
-334
libcutils/dir_hash.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <dirent.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sha1.h>
22 #include <unistd.h>
23 #include <limits.h>
24
25 #include <sys/stat.h>
26
27 #include <netinet/in.h>
28 #include <resolv.h>
29
30 #include <cutils/dir_hash.h>
31
32 /**
33 * Copies, if it fits within max_output_string bytes, into output_string
34 * a hash of the contents, size, permissions, uid, and gid of the file
35 * specified by path, using the specified algorithm. Returns the length
36 * of the output string, or a negative number if the buffer is too short.
37 */
38 int get_file_hash(HashAlgorithm algorithm, const char *path,
39 char *output_string, size_t max_output_string) {
40 SHA1_CTX context;
41 struct stat sb;
42 unsigned char md[SHA1_DIGEST_LENGTH];
43 int used;
44 size_t n;
45
46 if (algorithm != SHA_1) {
47 errno = EINVAL;
48 return -1;
49 }
50
51 if (stat(path, &sb) != 0) {
52 return -1;
53 }
54
55 if (S_ISLNK(sb.st_mode)) {
56 char buf[PATH_MAX];
57 int len;
58
59 len = readlink(path, buf, sizeof(buf));
60 if (len < 0) {
61 return -1;
62 }
63
64 SHA1Init(&context);
65 SHA1Update(&context, (unsigned char *) buf, len);
66 SHA1Final(md, &context);
67 } else if (S_ISREG(sb.st_mode)) {
68 char buf[10000];
69 FILE *f = fopen(path, "rb");
70 int len;
71
72 if (f == NULL) {
73 return -1;
74 }
75
76 SHA1Init(&context);
77
78 while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
79 SHA1Update(&context, (unsigned char *) buf, len);
80 }
81
82 if (ferror(f)) {
83 fclose(f);
84 return -1;
85 }
86
87 fclose(f);
88 SHA1Final(md, &context);
89 }
90
91 if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
92 used = b64_ntop(md, SHA1_DIGEST_LENGTH,
93 output_string, max_output_string);
94 if (used < 0) {
95 errno = ENOSPC;
96 return -1;
97 }
98
99 n = snprintf(output_string + used, max_output_string - used,
100 " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
101 (int) sb.st_uid, (int) sb.st_gid);
102 } else {
103 n = snprintf(output_string, max_output_string,
104 "- - 0%o %d %d", sb.st_mode,
105 (int) sb.st_uid, (int) sb.st_gid);
106 }
107
108 if (n >= max_output_string - used) {
109 errno = ENOSPC;
110 return -(used + n);
111 }
112
113 return used + n;
114 }
115
116 struct list {
117 char *name;
118 struct list *next;
119 };
120
121 static int cmp(const void *a, const void *b) {
122 struct list *const *ra = a;
123 struct list *const *rb = b;
124
125 return strcmp((*ra)->name, (*rb)->name);
126 }
127
128 static int recurse(HashAlgorithm algorithm, const char *directory_path,
129 struct list **out) {
130 struct list *list = NULL;
131 struct list *f;
132
133 struct dirent *de;
134 DIR *d = opendir(directory_path);
135
136 if (d == NULL) {
137 return -1;
138 }
139
140 while ((de = readdir(d)) != NULL) {
141 if (strcmp(de->d_name, ".") == 0) {
142 continue;
143 }
144 if (strcmp(de->d_name, "..") == 0) {
145 continue;
146 }
147
148 char *name = malloc(strlen(de->d_name) + 1);
149 struct list *node = malloc(sizeof(struct list));
150
151 if (name == NULL || node == NULL) {
152 struct list *next;
153 for (f = list; f != NULL; f = next) {
154 next = f->next;
155 free(f->name);
156 free(f);
157 }
158
159 free(name);
160 free(node);
161 return -1;
162 }
163
164 strcpy(name, de->d_name);
165
166 node->name = name;
167 node->next = list;
168 list = node;
169 }
170
171 closedir(d);
172
173 for (f = list; f != NULL; f = f->next) {
174 struct stat sb;
175 char *name;
176 char outstr[NAME_MAX + 100];
177 char *keep;
178 struct list *res;
179
180 name = malloc(strlen(f->name) + strlen(directory_path) + 2);
181 if (name == NULL) {
182 struct list *next;
183 for (f = list; f != NULL; f = f->next) {
184 next = f->next;
185 free(f->name);
186 free(f);
187 }
188 for (f = *out; f != NULL; f = f->next) {
189 next = f->next;
190 free(f->name);
191 free(f);
192 }
193 *out = NULL;
194 return -1;
195 }
196
197 sprintf(name, "%s/%s", directory_path, f->name);
198
199 int len = get_file_hash(algorithm, name,
200 outstr, sizeof(outstr));
201 if (len < 0) {
202 // should not happen
203 return -1;
204 }
205
206 keep = malloc(len + strlen(name) + 3);
207 res = malloc(sizeof(struct list));
208
209 if (keep == NULL || res == NULL) {
210 struct list *next;
211 for (f = list; f != NULL; f = f->next) {
212 next = f->next;
213 free(f->name);
214 free(f);
215 }
216 for (f = *out; f != NULL; f = f->next) {
217 next = f->next;
218 free(f->name);
219 free(f);
220 }
221 *out = NULL;
222
223 free(keep);
224 free(res);
225 return -1;
226 }
227
228 sprintf(keep, "%s %s\n", name, outstr);
229
230 res->name = keep;
231 res->next = *out;
232 *out = res;
233
234 if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
235 if (recurse(algorithm, name, out) < 0) {
236 struct list *next;
237 for (f = list; f != NULL; f = next) {
238 next = f->next;
239 free(f->name);
240 free(f);
241 }
242
243 return -1;
244 }
245 }
246 }
247
248 struct list *next;
249 for (f = list; f != NULL; f = next) {
250 next = f->next;
251
252 free(f->name);
253 free(f);
254 }
255 }
256
257 /**
258 * Allocates a string containing the names and hashes of all files recursively
259 * reached under the specified directory_path, using the specified algorithm.
260 * The string is returned as *output_string; the return value is the length
261 * of the string, or a negative number if there was a failure.
262 */
263 int get_recursive_hash_manifest(HashAlgorithm algorithm,
264 const char *directory_path,
265 char **output_string) {
266 struct list *out = NULL;
267 struct list *r;
268 struct list **list;
269 int count = 0;
270 int len = 0;
271 int retlen = 0;
272 int i;
273 char *buf;
274
275 if (recurse(algorithm, directory_path, &out) < 0) {
276 return -1;
277 }
278
279 for (r = out; r != NULL; r = r->next) {
280 count++;
281 len += strlen(r->name);
282 }
283
284 list = malloc(count * sizeof(struct list *));
285 if (list == NULL) {
286 struct list *next;
287 for (r = out; r != NULL; r = next) {
288 next = r->next;
289 free(r->name);
290 free(r);
291 }
292 return -1;
293 }
294
295 count = 0;
296 for (r = out; r != NULL; r = r->next) {
297 list[count++] = r;
298 }
299
300 qsort(list, count, sizeof(struct list *), cmp);
301
302 buf = malloc(len + 1);
303 if (buf == NULL) {
304 struct list *next;
305 for (r = out; r != NULL; r = next) {
306 next = r->next;
307 free(r->name);
308 free(r);
309 }
310 free(list);
311 return -1;
312 }
313
314 for (i = 0; i < count; i++) {
315 int n = strlen(list[i]->name);
316
317 strcpy(buf + retlen, list[i]->name);
318 retlen += n;
319 }
320
321 free(list);
322
323 struct list *next;
324 for (r = out; r != NULL; r = next) {
325 next = r->next;
326
327 free(r->name);
328 free(r);
329 }
330
331 *output_string = buf;
332 return retlen;
333 }
+0
-29
libcutils/dlmalloc_stubs.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* No-op stubs for functions defined in system/bionic/bionic/dlmalloc.c.
17 */
18 void dlmalloc_walk_free_pages()
19 {
20 }
21
22 void dlmalloc_walk_heap()
23 {
24 }
25
26 void dlmalloc_trim()
27 {
28 }
+0
-506
libcutils/fdevent.c less more
0 /* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
1 **
2 ** Copyright 2006, Brian Swetland <swetland@frotz.net>
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <errno.h>
22
23 #include <fcntl.h>
24
25 #include <stdarg.h>
26 #include <stddef.h>
27
28 #include <cutils/fdevent.h>
29
30 #define TRACE(x...) fprintf(stderr,x)
31
32 #define DEBUG 0
33
34 static void fatal(const char *fn, const char *fmt, ...)
35 {
36 va_list ap;
37 va_start(ap, fmt);
38 fprintf(stderr, "%s:", fn);
39 vfprintf(stderr, fmt, ap);
40 va_end(ap);
41 abort();
42 }
43
44 #define FATAL(x...) fatal(__FUNCTION__, x)
45
46 #if DEBUG
47 static void dump_fde(fdevent *fde, const char *info)
48 {
49 fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
50 fde->state & FDE_READ ? 'R' : ' ',
51 fde->state & FDE_WRITE ? 'W' : ' ',
52 fde->state & FDE_ERROR ? 'E' : ' ',
53 info);
54 }
55 #else
56 #define dump_fde(fde, info) do { } while(0)
57 #endif
58
59 #define FDE_EVENTMASK 0x00ff
60 #define FDE_STATEMASK 0xff00
61
62 #define FDE_ACTIVE 0x0100
63 #define FDE_PENDING 0x0200
64 #define FDE_CREATED 0x0400
65
66 static void fdevent_plist_enqueue(fdevent *node);
67 static void fdevent_plist_remove(fdevent *node);
68 static fdevent *fdevent_plist_dequeue(void);
69
70 static fdevent list_pending = {
71 .next = &list_pending,
72 .prev = &list_pending,
73 };
74
75 static fdevent **fd_table = 0;
76 static int fd_table_max = 0;
77
78 #ifdef CRAPTASTIC
79 //HAVE_EPOLL
80
81 #include <sys/epoll.h>
82
83 static int epoll_fd = -1;
84
85 static void fdevent_init()
86 {
87 /* XXX: what's a good size for the passed in hint? */
88 epoll_fd = epoll_create(256);
89
90 if(epoll_fd < 0) {
91 perror("epoll_create() failed");
92 exit(1);
93 }
94
95 /* mark for close-on-exec */
96 fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
97 }
98
99 static void fdevent_connect(fdevent *fde)
100 {
101 struct epoll_event ev;
102
103 memset(&ev, 0, sizeof(ev));
104 ev.events = 0;
105 ev.data.ptr = fde;
106
107 #if 0
108 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
109 perror("epoll_ctl() failed\n");
110 exit(1);
111 }
112 #endif
113 }
114
115 static void fdevent_disconnect(fdevent *fde)
116 {
117 struct epoll_event ev;
118
119 memset(&ev, 0, sizeof(ev));
120 ev.events = 0;
121 ev.data.ptr = fde;
122
123 /* technically we only need to delete if we
124 ** were actively monitoring events, but let's
125 ** be aggressive and do it anyway, just in case
126 ** something's out of sync
127 */
128 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
129 }
130
131 static void fdevent_update(fdevent *fde, unsigned events)
132 {
133 struct epoll_event ev;
134 int active;
135
136 active = (fde->state & FDE_EVENTMASK) != 0;
137
138 memset(&ev, 0, sizeof(ev));
139 ev.events = 0;
140 ev.data.ptr = fde;
141
142 if(events & FDE_READ) ev.events |= EPOLLIN;
143 if(events & FDE_WRITE) ev.events |= EPOLLOUT;
144 if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
145
146 fde->state = (fde->state & FDE_STATEMASK) | events;
147
148 if(active) {
149 /* we're already active. if we're changing to *no*
150 ** events being monitored, we need to delete, otherwise
151 ** we need to just modify
152 */
153 if(ev.events) {
154 if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
155 perror("epoll_ctl() failed\n");
156 exit(1);
157 }
158 } else {
159 if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
160 perror("epoll_ctl() failed\n");
161 exit(1);
162 }
163 }
164 } else {
165 /* we're not active. if we're watching events, we need
166 ** to add, otherwise we can just do nothing
167 */
168 if(ev.events) {
169 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
170 perror("epoll_ctl() failed\n");
171 exit(1);
172 }
173 }
174 }
175 }
176
177 static void fdevent_process()
178 {
179 struct epoll_event events[256];
180 fdevent *fde;
181 int i, n;
182
183 n = epoll_wait(epoll_fd, events, 256, -1);
184
185 if(n < 0) {
186 if(errno == EINTR) return;
187 perror("epoll_wait");
188 exit(1);
189 }
190
191 for(i = 0; i < n; i++) {
192 struct epoll_event *ev = events + i;
193 fde = ev->data.ptr;
194
195 if(ev->events & EPOLLIN) {
196 fde->events |= FDE_READ;
197 }
198 if(ev->events & EPOLLOUT) {
199 fde->events |= FDE_WRITE;
200 }
201 if(ev->events & (EPOLLERR | EPOLLHUP)) {
202 fde->events |= FDE_ERROR;
203 }
204 if(fde->events) {
205 if(fde->state & FDE_PENDING) continue;
206 fde->state |= FDE_PENDING;
207 fdevent_plist_enqueue(fde);
208 }
209 }
210 }
211
212 #else /* USE_SELECT */
213
214 #ifdef HAVE_WINSOCK
215 #include <winsock2.h>
216 #else
217 #include <sys/select.h>
218 #endif
219
220 static fd_set read_fds;
221 static fd_set write_fds;
222 static fd_set error_fds;
223
224 static int select_n = 0;
225
226 static void fdevent_init(void)
227 {
228 FD_ZERO(&read_fds);
229 FD_ZERO(&write_fds);
230 FD_ZERO(&error_fds);
231 }
232
233 static void fdevent_connect(fdevent *fde)
234 {
235 if(fde->fd >= select_n) {
236 select_n = fde->fd + 1;
237 }
238 }
239
240 static void fdevent_disconnect(fdevent *fde)
241 {
242 int i, n;
243
244 FD_CLR(fde->fd, &read_fds);
245 FD_CLR(fde->fd, &write_fds);
246 FD_CLR(fde->fd, &error_fds);
247
248 for(n = 0, i = 0; i < select_n; i++) {
249 if(fd_table[i] != 0) n = i;
250 }
251 select_n = n + 1;
252 }
253
254 static void fdevent_update(fdevent *fde, unsigned events)
255 {
256 if(events & FDE_READ) {
257 FD_SET(fde->fd, &read_fds);
258 } else {
259 FD_CLR(fde->fd, &read_fds);
260 }
261 if(events & FDE_WRITE) {
262 FD_SET(fde->fd, &write_fds);
263 } else {
264 FD_CLR(fde->fd, &write_fds);
265 }
266 if(events & FDE_ERROR) {
267 FD_SET(fde->fd, &error_fds);
268 } else {
269 FD_CLR(fde->fd, &error_fds);
270 }
271
272 fde->state = (fde->state & FDE_STATEMASK) | events;
273 }
274
275 static void fdevent_process()
276 {
277 int i, n;
278 fdevent *fde;
279 unsigned events;
280 fd_set rfd, wfd, efd;
281
282 memcpy(&rfd, &read_fds, sizeof(fd_set));
283 memcpy(&wfd, &write_fds, sizeof(fd_set));
284 memcpy(&efd, &error_fds, sizeof(fd_set));
285
286 n = select(select_n, &rfd, &wfd, &efd, 0);
287
288 if(n < 0) {
289 if(errno == EINTR) return;
290 perror("select");
291 return;
292 }
293
294 for(i = 0; (i < select_n) && (n > 0); i++) {
295 events = 0;
296 if(FD_ISSET(i, &rfd)) events |= FDE_READ;
297 if(FD_ISSET(i, &wfd)) events |= FDE_WRITE;
298 if(FD_ISSET(i, &efd)) events |= FDE_ERROR;
299
300 if(events) {
301 n--;
302
303 fde = fd_table[i];
304 if(fde == 0) FATAL("missing fde for fd %d\n", i);
305
306 fde->events |= events;
307
308 if(fde->state & FDE_PENDING) continue;
309 fde->state |= FDE_PENDING;
310 fdevent_plist_enqueue(fde);
311 }
312 }
313 }
314
315 #endif
316
317 static void fdevent_register(fdevent *fde)
318 {
319 if(fde->fd < 0) {
320 FATAL("bogus negative fd (%d)\n", fde->fd);
321 }
322
323 if(fde->fd >= fd_table_max) {
324 int oldmax = fd_table_max;
325 if(fde->fd > 32000) {
326 FATAL("bogus huuuuge fd (%d)\n", fde->fd);
327 }
328 if(fd_table_max == 0) {
329 fdevent_init();
330 fd_table_max = 256;
331 }
332 while(fd_table_max <= fde->fd) {
333 fd_table_max *= 2;
334 }
335 fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
336 if(fd_table == 0) {
337 FATAL("could not expand fd_table to %d entries\n", fd_table_max);
338 }
339 memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
340 }
341
342 fd_table[fde->fd] = fde;
343 }
344
345 static void fdevent_unregister(fdevent *fde)
346 {
347 if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
348 FATAL("fd out of range (%d)\n", fde->fd);
349 }
350
351 if(fd_table[fde->fd] != fde) {
352 FATAL("fd_table out of sync");
353 }
354
355 fd_table[fde->fd] = 0;
356
357 if(!(fde->state & FDE_DONT_CLOSE)) {
358 dump_fde(fde, "close");
359 close(fde->fd);
360 }
361 }
362
363 static void fdevent_plist_enqueue(fdevent *node)
364 {
365 fdevent *list = &list_pending;
366
367 node->next = list;
368 node->prev = list->prev;
369 node->prev->next = node;
370 list->prev = node;
371 }
372
373 static void fdevent_plist_remove(fdevent *node)
374 {
375 node->prev->next = node->next;
376 node->next->prev = node->prev;
377 node->next = 0;
378 node->prev = 0;
379 }
380
381 static fdevent *fdevent_plist_dequeue(void)
382 {
383 fdevent *list = &list_pending;
384 fdevent *node = list->next;
385
386 if(node == list) return 0;
387
388 list->next = node->next;
389 list->next->prev = list;
390 node->next = 0;
391 node->prev = 0;
392
393 return node;
394 }
395
396 fdevent *fdevent_create(int fd, fd_func func, void *arg)
397 {
398 fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
399 if(fde == 0) return 0;
400 fdevent_install(fde, fd, func, arg);
401 fde->state |= FDE_CREATED;
402 return fde;
403 }
404
405 void fdevent_destroy(fdevent *fde)
406 {
407 if(fde == 0) return;
408 if(!(fde->state & FDE_CREATED)) {
409 FATAL("fde %p not created by fdevent_create()\n", fde);
410 }
411 fdevent_remove(fde);
412 }
413
414 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
415 {
416 memset(fde, 0, sizeof(fdevent));
417 fde->state = FDE_ACTIVE;
418 fde->fd = fd;
419 fde->func = func;
420 fde->arg = arg;
421
422 #ifndef HAVE_WINSOCK
423 fcntl(fd, F_SETFL, O_NONBLOCK);
424 #endif
425 fdevent_register(fde);
426 dump_fde(fde, "connect");
427 fdevent_connect(fde);
428 fde->state |= FDE_ACTIVE;
429 }
430
431 void fdevent_remove(fdevent *fde)
432 {
433 if(fde->state & FDE_PENDING) {
434 fdevent_plist_remove(fde);
435 }
436
437 if(fde->state & FDE_ACTIVE) {
438 fdevent_disconnect(fde);
439 dump_fde(fde, "disconnect");
440 fdevent_unregister(fde);
441 }
442
443 fde->state = 0;
444 fde->events = 0;
445 }
446
447
448 void fdevent_set(fdevent *fde, unsigned events)
449 {
450 events &= FDE_EVENTMASK;
451
452 if((fde->state & FDE_EVENTMASK) == events) return;
453
454 if(fde->state & FDE_ACTIVE) {
455 fdevent_update(fde, events);
456 dump_fde(fde, "update");
457 }
458
459 fde->state = (fde->state & FDE_STATEMASK) | events;
460
461 if(fde->state & FDE_PENDING) {
462 /* if we're pending, make sure
463 ** we don't signal an event that
464 ** is no longer wanted.
465 */
466 fde->events &= (~events);
467 if(fde->events == 0) {
468 fdevent_plist_remove(fde);
469 fde->state &= (~FDE_PENDING);
470 }
471 }
472 }
473
474 void fdevent_add(fdevent *fde, unsigned events)
475 {
476 fdevent_set(
477 fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
478 }
479
480 void fdevent_del(fdevent *fde, unsigned events)
481 {
482 fdevent_set(
483 fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
484 }
485
486 void fdevent_loop()
487 {
488 fdevent *fde;
489
490 for(;;) {
491 #if DEBUG
492 fprintf(stderr,"--- ---- waiting for events\n");
493 #endif
494 fdevent_process();
495
496 while((fde = fdevent_plist_dequeue())) {
497 unsigned events = fde->events;
498 fde->events = 0;
499 fde->state &= (~FDE_PENDING);
500 dump_fde(fde, "callback");
501 fde->func(fde->fd, events, fde->arg);
502 }
503 }
504 }
505
+0
-350
libcutils/hashmap.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cutils/hashmap.h>
17 #include <assert.h>
18 #include <errno.h>
19 #include <cutils/threads.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdbool.h>
23 #include <sys/types.h>
24
25 typedef struct Entry Entry;
26 struct Entry {
27 void* key;
28 int hash;
29 void* value;
30 Entry* next;
31 };
32
33 struct Hashmap {
34 Entry** buckets;
35 size_t bucketCount;
36 int (*hash)(void* key);
37 bool (*equals)(void* keyA, void* keyB);
38 mutex_t lock;
39 size_t size;
40 };
41
42 Hashmap* hashmapCreate(size_t initialCapacity,
43 int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
44 assert(hash != NULL);
45 assert(equals != NULL);
46
47 Hashmap* map = malloc(sizeof(Hashmap));
48 if (map == NULL) {
49 return NULL;
50 }
51
52 // 0.75 load factor.
53 size_t minimumBucketCount = initialCapacity * 4 / 3;
54 map->bucketCount = 1;
55 while (map->bucketCount <= minimumBucketCount) {
56 // Bucket count must be power of 2.
57 map->bucketCount <<= 1;
58 }
59
60 map->buckets = calloc(map->bucketCount, sizeof(Entry*));
61 if (map->buckets == NULL) {
62 free(map);
63 return NULL;
64 }
65
66 map->size = 0;
67
68 map->hash = hash;
69 map->equals = equals;
70
71 mutex_init(&map->lock);
72
73 return map;
74 }
75
76 /**
77 * Hashes the given key.
78 */
79 static inline int hashKey(Hashmap* map, void* key) {
80 int h = map->hash(key);
81
82 // We apply this secondary hashing discovered by Doug Lea to defend
83 // against bad hashes.
84 h += ~(h << 9);
85 h ^= (((unsigned int) h) >> 14);
86 h += (h << 4);
87 h ^= (((unsigned int) h) >> 10);
88
89 return h;
90 }
91
92 size_t hashmapSize(Hashmap* map) {
93 return map->size;
94 }
95
96 static inline size_t calculateIndex(size_t bucketCount, int hash) {
97 return ((size_t) hash) & (bucketCount - 1);
98 }
99
100 static void expandIfNecessary(Hashmap* map) {
101 // If the load factor exceeds 0.75...
102 if (map->size > (map->bucketCount * 3 / 4)) {
103 // Start off with a 0.33 load factor.
104 size_t newBucketCount = map->bucketCount << 1;
105 Entry** newBuckets = calloc(newBucketCount, sizeof(Entry*));
106 if (newBuckets == NULL) {
107 // Abort expansion.
108 return;
109 }
110
111 // Move over existing entries.
112 size_t i;
113 for (i = 0; i < map->bucketCount; i++) {
114 Entry* entry = map->buckets[i];
115 while (entry != NULL) {
116 Entry* next = entry->next;
117 size_t index = calculateIndex(newBucketCount, entry->hash);
118 entry->next = newBuckets[index];
119 newBuckets[index] = entry;
120 entry = next;
121 }
122 }
123
124 // Copy over internals.
125 free(map->buckets);
126 map->buckets = newBuckets;
127 map->bucketCount = newBucketCount;
128 }
129 }
130
131 void hashmapLock(Hashmap* map) {
132 mutex_lock(&map->lock);
133 }
134
135 void hashmapUnlock(Hashmap* map) {
136 mutex_unlock(&map->lock);
137 }
138
139 void hashmapFree(Hashmap* map) {
140 size_t i;
141 for (i = 0; i < map->bucketCount; i++) {
142 Entry* entry = map->buckets[i];
143 while (entry != NULL) {
144 Entry* next = entry->next;
145 free(entry);
146 entry = next;
147 }
148 }
149 free(map->buckets);
150 mutex_destroy(&map->lock);
151 free(map);
152 }
153
154 int hashmapHash(void* key, size_t keySize) {
155 int h = keySize;
156 char* data = (char*) key;
157 size_t i;
158 for (i = 0; i < keySize; i++) {
159 h = h * 31 + *data;
160 data++;
161 }
162 return h;
163 }
164
165 static Entry* createEntry(void* key, int hash, void* value) {
166 Entry* entry = malloc(sizeof(Entry));
167 if (entry == NULL) {
168 return NULL;
169 }
170 entry->key = key;
171 entry->hash = hash;
172 entry->value = value;
173 entry->next = NULL;
174 return entry;
175 }
176
177 static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB,
178 bool (*equals)(void*, void*)) {
179 if (keyA == keyB) {
180 return true;
181 }
182 if (hashA != hashB) {
183 return false;
184 }
185 return equals(keyA, keyB);
186 }
187
188 void* hashmapPut(Hashmap* map, void* key, void* value) {
189 int hash = hashKey(map, key);
190 size_t index = calculateIndex(map->bucketCount, hash);
191
192 Entry** p = &(map->buckets[index]);
193 while (true) {
194 Entry* current = *p;
195
196 // Add a new entry.
197 if (current == NULL) {
198 *p = createEntry(key, hash, value);
199 if (*p == NULL) {
200 errno = ENOMEM;
201 return NULL;
202 }
203 map->size++;
204 expandIfNecessary(map);
205 return NULL;
206 }
207
208 // Replace existing entry.
209 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
210 void* oldValue = current->value;
211 current->value = value;
212 return oldValue;
213 }
214
215 // Move to next entry.
216 p = &current->next;
217 }
218 }
219
220 void* hashmapGet(Hashmap* map, void* key) {
221 int hash = hashKey(map, key);
222 size_t index = calculateIndex(map->bucketCount, hash);
223
224 Entry* entry = map->buckets[index];
225 while (entry != NULL) {
226 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
227 return entry->value;
228 }
229 entry = entry->next;
230 }
231
232 return NULL;
233 }
234
235 bool hashmapContainsKey(Hashmap* map, void* key) {
236 int hash = hashKey(map, key);
237 size_t index = calculateIndex(map->bucketCount, hash);
238
239 Entry* entry = map->buckets[index];
240 while (entry != NULL) {
241 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
242 return true;
243 }
244 entry = entry->next;
245 }
246
247 return false;
248 }
249
250 void* hashmapMemoize(Hashmap* map, void* key,
251 void* (*initialValue)(void* key, void* context), void* context) {
252 int hash = hashKey(map, key);
253 size_t index = calculateIndex(map->bucketCount, hash);
254
255 Entry** p = &(map->buckets[index]);
256 while (true) {
257 Entry* current = *p;
258
259 // Add a new entry.
260 if (current == NULL) {
261 *p = createEntry(key, hash, NULL);
262 if (*p == NULL) {
263 errno = ENOMEM;
264 return NULL;
265 }
266 void* value = initialValue(key, context);
267 (*p)->value = value;
268 map->size++;
269 expandIfNecessary(map);
270 return value;
271 }
272
273 // Return existing value.
274 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
275 return current->value;
276 }
277
278 // Move to next entry.
279 p = &current->next;
280 }
281 }
282
283 void* hashmapRemove(Hashmap* map, void* key) {
284 int hash = hashKey(map, key);
285 size_t index = calculateIndex(map->bucketCount, hash);
286
287 // Pointer to the current entry.
288 Entry** p = &(map->buckets[index]);
289 Entry* current;
290 while ((current = *p) != NULL) {
291 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
292 void* value = current->value;
293 *p = current->next;
294 free(current);
295 map->size--;
296 return value;
297 }
298
299 p = &current->next;
300 }
301
302 return NULL;
303 }
304
305 void hashmapForEach(Hashmap* map,
306 bool (*callback)(void* key, void* value, void* context),
307 void* context) {
308 size_t i;
309 for (i = 0; i < map->bucketCount; i++) {
310 Entry* entry = map->buckets[i];
311 while (entry != NULL) {
312 if (!callback(entry->key, entry->value, context)) {
313 return;
314 }
315 entry = entry->next;
316 }
317 }
318 }
319
320 size_t hashmapCurrentCapacity(Hashmap* map) {
321 size_t bucketCount = map->bucketCount;
322 return bucketCount * 3 / 4;
323 }
324
325 size_t hashmapCountCollisions(Hashmap* map) {
326 size_t collisions = 0;
327 size_t i;
328 for (i = 0; i < map->bucketCount; i++) {
329 Entry* entry = map->buckets[i];
330 while (entry != NULL) {
331 if (entry->next != NULL) {
332 collisions++;
333 }
334 entry = entry->next;
335 }
336 }
337 return collisions;
338 }
339
340 int hashmapIntHash(void* key) {
341 // Return the key value itself.
342 return *((int*) key);
343 }
344
345 bool hashmapIntEquals(void* keyA, void* keyB) {
346 int a = *((int*) keyA);
347 int b = *((int*) keyB);
348 return a == b;
349 }
+0
-51
libcutils/load_file.c less more
0 /* libs/cutils/load_file.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 void *load_file(const char *fn, unsigned *_sz)
22 {
23 char *data;
24 int sz;
25 int fd;
26
27 data = 0;
28 fd = open(fn, O_RDONLY);
29 if(fd < 0) return 0;
30
31 sz = lseek(fd, 0, SEEK_END);
32 if(sz < 0) goto oops;
33
34 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
35
36 data = (char*) malloc(sz + 1);
37 if(data == 0) goto oops;
38
39 if(read(fd, data, sz) != sz) goto oops;
40 close(fd);
41 data[sz] = 0;
42
43 if(_sz) *_sz = sz;
44 return data;
45
46 oops:
47 close(fd);
48 if(data != 0) free(data);
49 return 0;
50 }
+0
-38
libcutils/loghack.h less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * This is a temporary hack to enable logging from cutils.
18 */
19
20 #ifndef _CUTILS_LOGHACK_H
21 #define _CUTILS_LOGHACK_H
22
23 #ifdef HAVE_ANDROID_OS
24 #include <cutils/log.h>
25 #else
26 #include <stdio.h>
27 #define LOG(level, ...) \
28 ((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__))
29 #define LOGV(...) LOG("V", __VA_ARGS__)
30 #define LOGD(...) LOG("D", __VA_ARGS__)
31 #define LOGI(...) LOG("I", __VA_ARGS__)
32 #define LOGW(...) LOG("W", __VA_ARGS__)
33 #define LOGE(...) LOG("E", __VA_ARGS__)
34 #define LOG_ALWAYS_FATAL(...) do { LOGE(__VA_ARGS__); exit(1); } while (0)
35 #endif
36
37 #endif // _CUTILS_LOGHACK_H
+0
-87
libcutils/memory.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cutils/memory.h>
17
18 void android_memset16(uint16_t* dst, uint16_t value, size_t size)
19 {
20 size >>= 1;
21 while (size--) {
22 *dst++ = value;
23 }
24 }
25
26 void android_memset32(uint32_t* dst, uint32_t value, size_t size)
27 {
28 size >>= 2;
29 while (size--) {
30 *dst++ = value;
31 }
32 }
33
34 #if !HAVE_STRLCPY
35 /*
36 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
37 *
38 * Permission to use, copy, modify, and distribute this software for any
39 * purpose with or without fee is hereby granted, provided that the above
40 * copyright notice and this permission notice appear in all copies.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 */
50
51 #include <sys/types.h>
52 #include <string.h>
53
54 /* Implementation of strlcpy() for platforms that don't already have it. */
55
56 /*
57 * Copy src to string dst of size siz. At most siz-1 characters
58 * will be copied. Always NUL terminates (unless siz == 0).
59 * Returns strlen(src); if retval >= siz, truncation occurred.
60 */
61 size_t
62 strlcpy(char *dst, const char *src, size_t siz)
63 {
64 char *d = dst;
65 const char *s = src;
66 size_t n = siz;
67
68 /* Copy as many bytes as will fit */
69 if (n != 0) {
70 while (--n != 0) {
71 if ((*d++ = *s++) == '\0')
72 break;
73 }
74 }
75
76 /* Not enough room in dst, add NUL and traverse rest of src */
77 if (n == 0) {
78 if (siz != 0)
79 *d = '\0'; /* NUL-terminate dst */
80 while (*s++)
81 ;
82 }
83
84 return(s - src - 1); /* count does not include NUL */
85 }
86 #endif
+0
-93
libcutils/memset32.S less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 /*
16 * memset32.S
17 *
18 */
19
20 .text
21 .align
22
23 .global android_memset32
24 .type android_memset32, %function
25 .global android_memset16
26 .type android_memset16, %function
27
28 /*
29 * Optimized memset32 and memset16 for ARM.
30 *
31 * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
32 * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
33 *
34 */
35
36 android_memset16:
37 .fnstart
38 cmp r2, #1
39 bxle lr
40
41 /* expand the data to 32 bits */
42 mov r1, r1, lsl #16
43 orr r1, r1, r1, lsr #16
44
45 /* align to 32 bits */
46 tst r0, #2
47 strneh r1, [r0], #2
48 subne r2, r2, #2
49 .fnend
50
51 android_memset32:
52 .fnstart
53 .save {lr}
54 str lr, [sp, #-4]!
55
56 /* align the destination to a cache-line */
57 mov r12, r1
58 mov lr, r1
59 rsb r3, r0, #0
60 ands r3, r3, #0x1C
61 beq .Laligned32
62 cmp r3, r2
63 andhi r3, r2, #0x1C
64 sub r2, r2, r3
65
66 /* conditionally writes 0 to 7 words (length in r3) */
67 movs r3, r3, lsl #28
68 stmcsia r0!, {r1, lr}
69 stmcsia r0!, {r1, lr}
70 stmmiia r0!, {r1, lr}
71 movs r3, r3, lsl #2
72 strcs r1, [r0], #4
73
74 .Laligned32:
75 mov r3, r1
76 1: subs r2, r2, #32
77 stmhsia r0!, {r1,r3,r12,lr}
78 stmhsia r0!, {r1,r3,r12,lr}
79 bhs 1b
80 add r2, r2, #32
81
82 /* conditionally stores 0 to 30 bytes */
83 movs r2, r2, lsl #28
84 stmcsia r0!, {r1,r3,r12,lr}
85 stmmiia r0!, {r1,lr}
86 movs r2, r2, lsl #2
87 strcs r1, [r0], #4
88 strmih lr, [r0], #2
89
90 ldr lr, [sp], #4
91 bx lr
92 .fnend
+0
-1357
libcutils/mq.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "mq"
17
18 #include <assert.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include <sys/un.h>
29 #include <sys/uio.h>
30
31 #include <cutils/array.h>
32 #include <cutils/hashmap.h>
33 #include <cutils/selector.h>
34
35 #include "loghack.h"
36 #include "buffer.h"
37
38 /** Number of dead peers to remember. */
39 #define PEER_HISTORY (16)
40
41 typedef struct sockaddr SocketAddress;
42 typedef struct sockaddr_un UnixAddress;
43
44 /**
45 * Process/user/group ID. We don't use ucred directly because it's only
46 * available on Linux.
47 */
48 typedef struct {
49 pid_t pid;
50 uid_t uid;
51 gid_t gid;
52 } Credentials;
53
54 /** Listens for bytes coming from remote peers. */
55 typedef void BytesListener(Credentials credentials, char* bytes, size_t size);
56
57 /** Listens for the deaths of remote peers. */
58 typedef void DeathListener(pid_t pid);
59
60 /** Types of packets. */
61 typedef enum {
62 /** Request for a connection to another peer. */
63 CONNECTION_REQUEST,
64
65 /** A connection to another peer. */
66 CONNECTION,
67
68 /** Reports a failed connection attempt. */
69 CONNECTION_ERROR,
70
71 /** A generic packet of bytes. */
72 BYTES,
73 } PacketType;
74
75 typedef enum {
76 /** Reading a packet header. */
77 READING_HEADER,
78
79 /** Waiting for a connection from the master. */
80 ACCEPTING_CONNECTION,
81
82 /** Reading bytes. */
83 READING_BYTES,
84 } InputState;
85
86 /** A packet header. */
87 // TODO: Use custom headers for master->peer, peer->master, peer->peer.
88 typedef struct {
89 PacketType type;
90 union {
91 /** Packet size. Used for BYTES. */
92 size_t size;
93
94 /** Credentials. Used for CONNECTION and CONNECTION_REQUEST. */
95 Credentials credentials;
96 };
97 } Header;
98
99 /** A packet which will be sent to a peer. */
100 typedef struct OutgoingPacket OutgoingPacket;
101 struct OutgoingPacket {
102 /** Packet header. */
103 Header header;
104
105 union {
106 /** Connection to peer. Used with CONNECTION. */
107 int socket;
108
109 /** Buffer of bytes. Used with BYTES. */
110 Buffer* bytes;
111 };
112
113 /** Frees all resources associated with this packet. */
114 void (*free)(OutgoingPacket* packet);
115
116 /** Optional context. */
117 void* context;
118
119 /** Next packet in the queue. */
120 OutgoingPacket* nextPacket;
121 };
122
123 /** Represents a remote peer. */
124 typedef struct PeerProxy PeerProxy;
125
126 /** Local peer state. You typically have one peer per process. */
127 typedef struct {
128 /** This peer's PID. */
129 pid_t pid;
130
131 /**
132 * Map from pid to peer proxy. The peer has a peer proxy for each remote
133 * peer it's connected to.
134 *
135 * Acquire mutex before use.
136 */
137 Hashmap* peerProxies;
138
139 /** Manages I/O. */
140 Selector* selector;
141
142 /** Used to synchronize operations with the selector thread. */
143 pthread_mutex_t mutex;
144
145 /** Is this peer the master? */
146 bool master;
147
148 /** Peer proxy for the master. */
149 PeerProxy* masterProxy;
150
151 /** Listens for packets from remote peers. */
152 BytesListener* onBytes;
153
154 /** Listens for deaths of remote peers. */
155 DeathListener* onDeath;
156
157 /** Keeps track of recently dead peers. Requires mutex. */
158 pid_t deadPeers[PEER_HISTORY];
159 size_t deadPeerCursor;
160 } Peer;
161
162 struct PeerProxy {
163 /** Credentials of the remote process. */
164 Credentials credentials;
165
166 /** Keeps track of data coming in from the remote peer. */
167 InputState inputState;
168 Buffer* inputBuffer;
169 PeerProxy* connecting;
170
171 /** File descriptor for this peer. */
172 SelectableFd* fd;
173
174 /**
175 * Queue of packets to be written out to the remote peer.
176 *
177 * Requires mutex.
178 */
179 // TODO: Limit queue length.
180 OutgoingPacket* currentPacket;
181 OutgoingPacket* lastPacket;
182
183 /** Used to write outgoing header. */
184 Buffer outgoingHeader;
185
186 /** True if this is the master's proxy. */
187 bool master;
188
189 /** Reference back to the local peer. */
190 Peer* peer;
191
192 /**
193 * Used in master only. Maps this peer proxy to other peer proxies to
194 * which the peer has been connected to. Maps pid to PeerProxy. Helps
195 * keep track of which connections we've sent to whom.
196 */
197 Hashmap* connections;
198 };
199
200 /** Server socket path. */
201 static const char* MASTER_PATH = "/master.peer";
202
203 /** Credentials of the master peer. */
204 static const Credentials MASTER_CREDENTIALS = {0, 0, 0};
205
206 /** Creates a peer proxy and adds it to the peer proxy map. */
207 static PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials);
208
209 /** Sets the non-blocking flag on a descriptor. */
210 static void setNonBlocking(int fd) {
211 int flags;
212 if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
213 LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno));
214 }
215 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
216 LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno));
217 }
218 }
219
220 /** Closes a fd and logs a warning if the close fails. */
221 static void closeWithWarning(int fd) {
222 int result = close(fd);
223 if (result == -1) {
224 LOGW("close() error: %s", strerror(errno));
225 }
226 }
227
228 /** Hashes pid_t keys. */
229 static int pidHash(void* key) {
230 pid_t* pid = (pid_t*) key;
231 return (int) (*pid);
232 }
233
234 /** Compares pid_t keys. */
235 static bool pidEquals(void* keyA, void* keyB) {
236 pid_t* a = (pid_t*) keyA;
237 pid_t* b = (pid_t*) keyB;
238 return *a == *b;
239 }
240
241 /** Gets the master address. Not thread safe. */
242 static UnixAddress* getMasterAddress() {
243 static UnixAddress masterAddress;
244 static bool initialized = false;
245 if (initialized == false) {
246 masterAddress.sun_family = AF_LOCAL;
247 strcpy(masterAddress.sun_path, MASTER_PATH);
248 initialized = true;
249 }
250 return &masterAddress;
251 }
252
253 /** Gets exclusive access to the peer for this thread. */
254 static void peerLock(Peer* peer) {
255 pthread_mutex_lock(&peer->mutex);
256 }
257
258 /** Releases exclusive access to the peer. */
259 static void peerUnlock(Peer* peer) {
260 pthread_mutex_unlock(&peer->mutex);
261 }
262
263 /** Frees a simple, i.e. header-only, outgoing packet. */
264 static void outgoingPacketFree(OutgoingPacket* packet) {
265 LOGD("Freeing outgoing packet.");
266 free(packet);
267 }
268
269 /**
270 * Prepare to read a new packet from the peer.
271 */
272 static void peerProxyExpectHeader(PeerProxy* peerProxy) {
273 peerProxy->inputState = READING_HEADER;
274 bufferPrepareForRead(peerProxy->inputBuffer, sizeof(Header));
275 }
276
277 /** Sets up the buffer for the outgoing header. */
278 static void peerProxyPrepareOutgoingHeader(PeerProxy* peerProxy) {
279 peerProxy->outgoingHeader.data
280 = (char*) &(peerProxy->currentPacket->header);
281 peerProxy->outgoingHeader.size = sizeof(Header);
282 bufferPrepareForWrite(&peerProxy->outgoingHeader);
283 }
284
285 /** Adds a packet to the end of the queue. Callers must have the mutex. */
286 static void peerProxyEnqueueOutgoingPacket(PeerProxy* peerProxy,
287 OutgoingPacket* newPacket) {
288 newPacket->nextPacket = NULL; // Just in case.
289 if (peerProxy->currentPacket == NULL) {
290 // The queue is empty.
291 peerProxy->currentPacket = newPacket;
292 peerProxy->lastPacket = newPacket;
293
294 peerProxyPrepareOutgoingHeader(peerProxy);
295 } else {
296 peerProxy->lastPacket->nextPacket = newPacket;
297 }
298 }
299
300 /** Takes the peer lock and enqueues the given packet. */
301 static void peerProxyLockAndEnqueueOutgoingPacket(PeerProxy* peerProxy,
302 OutgoingPacket* newPacket) {
303 Peer* peer = peerProxy->peer;
304 peerLock(peer);
305 peerProxyEnqueueOutgoingPacket(peerProxy, newPacket);
306 peerUnlock(peer);
307 }
308
309 /**
310 * Frees current packet and moves to the next one. Returns true if there is
311 * a next packet or false if the queue is empty.
312 */
313 static bool peerProxyNextPacket(PeerProxy* peerProxy) {
314 Peer* peer = peerProxy->peer;
315 peerLock(peer);
316
317 OutgoingPacket* current = peerProxy->currentPacket;
318
319 if (current == NULL) {
320 // The queue is already empty.
321 peerUnlock(peer);
322 return false;
323 }
324
325 OutgoingPacket* next = current->nextPacket;
326 peerProxy->currentPacket = next;
327 current->nextPacket = NULL;
328 current->free(current);
329 if (next == NULL) {
330 // The queue is empty.
331 peerProxy->lastPacket = NULL;
332 peerUnlock(peer);
333 return false;
334 } else {
335 peerUnlock(peer);
336 peerProxyPrepareOutgoingHeader(peerProxy);
337
338 // TODO: Start writing next packet? It would reduce the number of
339 // system calls, but we could also starve other peers.
340 return true;
341 }
342 }
343
344 /**
345 * Checks whether a peer died recently.
346 */
347 static bool peerIsDead(Peer* peer, pid_t pid) {
348 size_t i;
349 for (i = 0; i < PEER_HISTORY; i++) {
350 pid_t deadPeer = peer->deadPeers[i];
351 if (deadPeer == 0) {
352 return false;
353 }
354 if (deadPeer == pid) {
355 return true;
356 }
357 }
358 return false;
359 }
360
361 /**
362 * Cleans up connection information.
363 */
364 static bool peerProxyRemoveConnection(void* key, void* value, void* context) {
365 PeerProxy* deadPeer = (PeerProxy*) context;
366 PeerProxy* otherPeer = (PeerProxy*) value;
367 hashmapRemove(otherPeer->connections, &(deadPeer->credentials.pid));
368 return true;
369 }
370
371 /**
372 * Called when the peer dies.
373 */
374 static void peerProxyKill(PeerProxy* peerProxy, bool errnoIsSet) {
375 if (errnoIsSet) {
376 LOGI("Peer %d died. errno: %s", peerProxy->credentials.pid,
377 strerror(errno));
378 } else {
379 LOGI("Peer %d died.", peerProxy->credentials.pid);
380 }
381
382 // If we lost the master, we're up a creek. We can't let this happen.
383 if (peerProxy->master) {
384 LOG_ALWAYS_FATAL("Lost connection to master.");
385 }
386
387 Peer* localPeer = peerProxy->peer;
388 pid_t pid = peerProxy->credentials.pid;
389
390 peerLock(localPeer);
391
392 // Remember for awhile that the peer died.
393 localPeer->deadPeers[localPeer->deadPeerCursor]
394 = peerProxy->credentials.pid;
395 localPeer->deadPeerCursor++;
396 if (localPeer->deadPeerCursor == PEER_HISTORY) {
397 localPeer->deadPeerCursor = 0;
398 }
399
400 // Remove from peer map.
401 hashmapRemove(localPeer->peerProxies, &pid);
402
403 // External threads can no longer get to this peer proxy, so we don't
404 // need the lock anymore.
405 peerUnlock(localPeer);
406
407 // Remove the fd from the selector.
408 if (peerProxy->fd != NULL) {
409 peerProxy->fd->remove = true;
410 }
411
412 // Clear outgoing packet queue.
413 while (peerProxyNextPacket(peerProxy)) {}
414
415 bufferFree(peerProxy->inputBuffer);
416
417 // This only applies to the master.
418 if (peerProxy->connections != NULL) {
419 // We can't leave these other maps pointing to freed memory.
420 hashmapForEach(peerProxy->connections, &peerProxyRemoveConnection,
421 peerProxy);
422 hashmapFree(peerProxy->connections);
423 }
424
425 // Invoke death listener.
426 localPeer->onDeath(pid);
427
428 // Free the peer proxy itself.
429 free(peerProxy);
430 }
431
432 static void peerProxyHandleError(PeerProxy* peerProxy, char* functionName) {
433 if (errno == EINTR) {
434 // Log interruptions but otherwise ignore them.
435 LOGW("%s() interrupted.", functionName);
436 } else if (errno == EAGAIN) {
437 LOGD("EWOULDBLOCK");
438 // Ignore.
439 } else {
440 LOGW("Error returned by %s().", functionName);
441 peerProxyKill(peerProxy, true);
442 }
443 }
444
445 /**
446 * Buffers output sent to a peer. May be called multiple times until the entire
447 * buffer is filled. Returns true when the buffer is empty.
448 */
449 static bool peerProxyWriteFromBuffer(PeerProxy* peerProxy, Buffer* outgoing) {
450 ssize_t size = bufferWrite(outgoing, peerProxy->fd->fd);
451 if (size < 0) {
452 peerProxyHandleError(peerProxy, "write");
453 return false;
454 } else {
455 return bufferWriteComplete(outgoing);
456 }
457 }
458
459 /** Writes packet bytes to peer. */
460 static void peerProxyWriteBytes(PeerProxy* peerProxy) {
461 Buffer* buffer = peerProxy->currentPacket->bytes;
462 if (peerProxyWriteFromBuffer(peerProxy, buffer)) {
463 LOGD("Bytes written.");
464 peerProxyNextPacket(peerProxy);
465 }
466 }
467
468 /** Sends a socket to the peer. */
469 static void peerProxyWriteConnection(PeerProxy* peerProxy) {
470 int socket = peerProxy->currentPacket->socket;
471
472 // Why does sending and receiving fds have to be such a PITA?
473 struct msghdr msg;
474 struct iovec iov[1];
475
476 union {
477 struct cmsghdr cm;
478 char control[CMSG_SPACE(sizeof(int))];
479 } control_un;
480
481 struct cmsghdr *cmptr;
482
483 msg.msg_control = control_un.control;
484 msg.msg_controllen = sizeof(control_un.control);
485 cmptr = CMSG_FIRSTHDR(&msg);
486 cmptr->cmsg_len = CMSG_LEN(sizeof(int));
487 cmptr->cmsg_level = SOL_SOCKET;
488 cmptr->cmsg_type = SCM_RIGHTS;
489
490 // Store the socket in the message.
491 *((int *) CMSG_DATA(cmptr)) = peerProxy->currentPacket->socket;
492
493 msg.msg_name = NULL;
494 msg.msg_namelen = 0;
495 iov[0].iov_base = "";
496 iov[0].iov_len = 1;
497 msg.msg_iov = iov;
498 msg.msg_iovlen = 1;
499
500 ssize_t result = sendmsg(peerProxy->fd->fd, &msg, 0);
501
502 if (result < 0) {
503 peerProxyHandleError(peerProxy, "sendmsg");
504 } else {
505 // Success. Queue up the next packet.
506 peerProxyNextPacket(peerProxy);
507
508 }
509 }
510
511 /**
512 * Writes some outgoing data.
513 */
514 static void peerProxyWrite(SelectableFd* fd) {
515 // TODO: Try to write header and body with one system call.
516
517 PeerProxy* peerProxy = (PeerProxy*) fd->data;
518 OutgoingPacket* current = peerProxy->currentPacket;
519
520 if (current == NULL) {
521 // We have nothing left to write.
522 return;
523 }
524
525 // Write the header.
526 Buffer* outgoingHeader = &peerProxy->outgoingHeader;
527 bool headerWritten = bufferWriteComplete(outgoingHeader);
528 if (!headerWritten) {
529 LOGD("Writing header...");
530 headerWritten = peerProxyWriteFromBuffer(peerProxy, outgoingHeader);
531 if (headerWritten) {
532 LOGD("Header written.");
533 }
534 }
535
536 // Write body.
537 if (headerWritten) {
538 PacketType type = current->header.type;
539 switch (type) {
540 case CONNECTION:
541 peerProxyWriteConnection(peerProxy);
542 break;
543 case BYTES:
544 peerProxyWriteBytes(peerProxy);
545 break;
546 case CONNECTION_REQUEST:
547 case CONNECTION_ERROR:
548 // These packets consist solely of a header.
549 peerProxyNextPacket(peerProxy);
550 break;
551 default:
552 LOG_ALWAYS_FATAL("Unknown packet type: %d", type);
553 }
554 }
555 }
556
557 /**
558 * Sets up a peer proxy's fd before we try to select() it.
559 */
560 static void peerProxyBeforeSelect(SelectableFd* fd) {
561 LOGD("Before select...");
562
563 PeerProxy* peerProxy = (PeerProxy*) fd->data;
564
565 peerLock(peerProxy->peer);
566 bool hasPackets = peerProxy->currentPacket != NULL;
567 peerUnlock(peerProxy->peer);
568
569 if (hasPackets) {
570 LOGD("Packets found. Setting onWritable().");
571
572 fd->onWritable = &peerProxyWrite;
573 } else {
574 // We have nothing to write.
575 fd->onWritable = NULL;
576 }
577 }
578
579 /** Prepare to read bytes from the peer. */
580 static void peerProxyExpectBytes(PeerProxy* peerProxy, Header* header) {
581 LOGD("Expecting %d bytes.", header->size);
582
583 peerProxy->inputState = READING_BYTES;
584 if (bufferPrepareForRead(peerProxy->inputBuffer, header->size) == -1) {
585 LOGW("Couldn't allocate memory for incoming data. Size: %u",
586 (unsigned int) header->size);
587
588 // TODO: Ignore the packet and log a warning?
589 peerProxyKill(peerProxy, false);
590 }
591 }
592
593 /**
594 * Gets a peer proxy for the given ID. Creates a peer proxy if necessary.
595 * Sends a connection request to the master if desired.
596 *
597 * Returns NULL if an error occurs. Sets errno to EHOSTDOWN if the peer died
598 * or ENOMEM if memory couldn't be allocated.
599 */
600 static PeerProxy* peerProxyGetOrCreate(Peer* peer, pid_t pid,
601 bool requestConnection) {
602 if (pid == peer->pid) {
603 errno = EINVAL;
604 return NULL;
605 }
606
607 if (peerIsDead(peer, pid)) {
608 errno = EHOSTDOWN;
609 return NULL;
610 }
611
612 PeerProxy* peerProxy = hashmapGet(peer->peerProxies, &pid);
613 if (peerProxy != NULL) {
614 return peerProxy;
615 }
616
617 // If this is the master peer, we already know about all peers.
618 if (peer->master) {
619 errno = EHOSTDOWN;
620 return NULL;
621 }
622
623 // Try to create a peer proxy.
624 Credentials credentials;
625 credentials.pid = pid;
626
627 // Fake gid and uid until we have the real thing. The real creds are
628 // filled in by masterProxyExpectConnection(). These fake creds will
629 // never be exposed to the user.
630 credentials.uid = 0;
631 credentials.gid = 0;
632
633 // Make sure we can allocate the connection request packet.
634 OutgoingPacket* packet = NULL;
635 if (requestConnection) {
636 packet = calloc(1, sizeof(OutgoingPacket));
637 if (packet == NULL) {
638 errno = ENOMEM;
639 return NULL;
640 }
641
642 packet->header.type = CONNECTION_REQUEST;
643 packet->header.credentials = credentials;
644 packet->free = &outgoingPacketFree;
645 }
646
647 peerProxy = peerProxyCreate(peer, credentials);
648 if (peerProxy == NULL) {
649 free(packet);
650 errno = ENOMEM;
651 return NULL;
652 } else {
653 // Send a connection request to the master.
654 if (requestConnection) {
655 PeerProxy* masterProxy = peer->masterProxy;
656 peerProxyEnqueueOutgoingPacket(masterProxy, packet);
657 }
658
659 return peerProxy;
660 }
661 }
662
663 /**
664 * Switches the master peer proxy into a state where it's waiting for a
665 * connection from the master.
666 */
667 static void masterProxyExpectConnection(PeerProxy* masterProxy,
668 Header* header) {
669 // TODO: Restructure things so we don't need this check.
670 // Verify that this really is the master.
671 if (!masterProxy->master) {
672 LOGW("Non-master process %d tried to send us a connection.",
673 masterProxy->credentials.pid);
674 // Kill off the evil peer.
675 peerProxyKill(masterProxy, false);
676 return;
677 }
678
679 masterProxy->inputState = ACCEPTING_CONNECTION;
680 Peer* localPeer = masterProxy->peer;
681
682 // Create a peer proxy so we have somewhere to stash the creds.
683 // See if we already have a proxy set up.
684 pid_t pid = header->credentials.pid;
685 peerLock(localPeer);
686 PeerProxy* peerProxy = peerProxyGetOrCreate(localPeer, pid, false);
687 if (peerProxy == NULL) {
688 LOGW("Peer proxy creation failed: %s", strerror(errno));
689 } else {
690 // Fill in full credentials.
691 peerProxy->credentials = header->credentials;
692 }
693 peerUnlock(localPeer);
694
695 // Keep track of which peer proxy we're accepting a connection for.
696 masterProxy->connecting = peerProxy;
697 }
698
699 /**
700 * Reads input from a peer process.
701 */
702 static void peerProxyRead(SelectableFd* fd);
703
704 /** Sets up fd callbacks. */
705 static void peerProxySetFd(PeerProxy* peerProxy, SelectableFd* fd) {
706 peerProxy->fd = fd;
707 fd->data = peerProxy;
708 fd->onReadable = &peerProxyRead;
709 fd->beforeSelect = &peerProxyBeforeSelect;
710
711 // Make the socket non-blocking.
712 setNonBlocking(fd->fd);
713 }
714
715 /**
716 * Accepts a connection sent by the master proxy.
717 */
718 static void masterProxyAcceptConnection(PeerProxy* masterProxy) {
719 struct msghdr msg;
720 struct iovec iov[1];
721 ssize_t size;
722 char ignored;
723 int incomingFd;
724
725 // TODO: Reuse code which writes the connection. Who the heck designed
726 // this API anyway?
727 union {
728 struct cmsghdr cm;
729 char control[CMSG_SPACE(sizeof(int))];
730 } control_un;
731 struct cmsghdr *cmptr;
732 msg.msg_control = control_un.control;
733 msg.msg_controllen = sizeof(control_un.control);
734
735 msg.msg_name = NULL;
736 msg.msg_namelen = 0;
737
738 // We sent 1 byte of data so we can detect EOF.
739 iov[0].iov_base = &ignored;
740 iov[0].iov_len = 1;
741 msg.msg_iov = iov;
742 msg.msg_iovlen = 1;
743
744 size = recvmsg(masterProxy->fd->fd, &msg, 0);
745 if (size < 0) {
746 if (errno == EINTR) {
747 // Log interruptions but otherwise ignore them.
748 LOGW("recvmsg() interrupted.");
749 return;
750 } else if (errno == EAGAIN) {
751 // Keep waiting for the connection.
752 return;
753 } else {
754 LOG_ALWAYS_FATAL("Error reading connection from master: %s",
755 strerror(errno));
756 }
757 } else if (size == 0) {
758 // EOF.
759 LOG_ALWAYS_FATAL("Received EOF from master.");
760 }
761
762 // Extract fd from message.
763 if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
764 && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
765 if (cmptr->cmsg_level != SOL_SOCKET) {
766 LOG_ALWAYS_FATAL("Expected SOL_SOCKET.");
767 }
768 if (cmptr->cmsg_type != SCM_RIGHTS) {
769 LOG_ALWAYS_FATAL("Expected SCM_RIGHTS.");
770 }
771 incomingFd = *((int*) CMSG_DATA(cmptr));
772 } else {
773 LOG_ALWAYS_FATAL("Expected fd.");
774 }
775
776 // The peer proxy this connection is for.
777 PeerProxy* peerProxy = masterProxy->connecting;
778 if (peerProxy == NULL) {
779 LOGW("Received connection for unknown peer.");
780 closeWithWarning(incomingFd);
781 } else {
782 Peer* peer = masterProxy->peer;
783
784 SelectableFd* selectableFd = selectorAdd(peer->selector, incomingFd);
785 if (selectableFd == NULL) {
786 LOGW("Error adding fd to selector for %d.",
787 peerProxy->credentials.pid);
788 closeWithWarning(incomingFd);
789 peerProxyKill(peerProxy, false);
790 }
791
792 peerProxySetFd(peerProxy, selectableFd);
793 }
794
795 peerProxyExpectHeader(masterProxy);
796 }
797
798 /**
799 * Frees an outgoing packet containing a connection.
800 */
801 static void outgoingPacketFreeSocket(OutgoingPacket* packet) {
802 closeWithWarning(packet->socket);
803 outgoingPacketFree(packet);
804 }
805
806 /**
807 * Connects two known peers.
808 */
809 static void masterConnectPeers(PeerProxy* peerA, PeerProxy* peerB) {
810 int sockets[2];
811 int result = socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets);
812 if (result == -1) {
813 LOGW("socketpair() error: %s", strerror(errno));
814 // TODO: Send CONNECTION_FAILED packets to peers.
815 return;
816 }
817
818 OutgoingPacket* packetA = calloc(1, sizeof(OutgoingPacket));
819 OutgoingPacket* packetB = calloc(1, sizeof(OutgoingPacket));
820 if (packetA == NULL || packetB == NULL) {
821 free(packetA);
822 free(packetB);
823 LOGW("malloc() error. Failed to tell process %d that process %d is"
824 " dead.", peerA->credentials.pid, peerB->credentials.pid);
825 return;
826 }
827
828 packetA->header.type = CONNECTION;
829 packetB->header.type = CONNECTION;
830
831 packetA->header.credentials = peerB->credentials;
832 packetB->header.credentials = peerA->credentials;
833
834 packetA->socket = sockets[0];
835 packetB->socket = sockets[1];
836
837 packetA->free = &outgoingPacketFreeSocket;
838 packetB->free = &outgoingPacketFreeSocket;
839
840 peerLock(peerA->peer);
841 peerProxyEnqueueOutgoingPacket(peerA, packetA);
842 peerProxyEnqueueOutgoingPacket(peerB, packetB);
843 peerUnlock(peerA->peer);
844 }
845
846 /**
847 * Informs a peer that the peer they're trying to connect to couldn't be
848 * found.
849 */
850 static void masterReportConnectionError(PeerProxy* peerProxy,
851 Credentials credentials) {
852 OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
853 if (packet == NULL) {
854 LOGW("malloc() error. Failed to tell process %d that process %d is"
855 " dead.", peerProxy->credentials.pid, credentials.pid);
856 return;
857 }
858
859 packet->header.type = CONNECTION_ERROR;
860 packet->header.credentials = credentials;
861 packet->free = &outgoingPacketFree;
862
863 peerProxyLockAndEnqueueOutgoingPacket(peerProxy, packet);
864 }
865
866 /**
867 * Handles a request to be connected to another peer.
868 */
869 static void masterHandleConnectionRequest(PeerProxy* peerProxy,
870 Header* header) {
871 Peer* master = peerProxy->peer;
872 pid_t targetPid = header->credentials.pid;
873 if (!hashmapContainsKey(peerProxy->connections, &targetPid)) {
874 // We haven't connected these peers yet.
875 PeerProxy* targetPeer
876 = (PeerProxy*) hashmapGet(master->peerProxies, &targetPid);
877 if (targetPeer == NULL) {
878 // Unknown process.
879 masterReportConnectionError(peerProxy, header->credentials);
880 } else {
881 masterConnectPeers(peerProxy, targetPeer);
882 }
883 }
884
885 // This packet is complete. Get ready for the next one.
886 peerProxyExpectHeader(peerProxy);
887 }
888
889 /**
890 * The master told us this peer is dead.
891 */
892 static void masterProxyHandleConnectionError(PeerProxy* masterProxy,
893 Header* header) {
894 Peer* peer = masterProxy->peer;
895
896 // Look up the peer proxy.
897 pid_t pid = header->credentials.pid;
898 PeerProxy* peerProxy = NULL;
899 peerLock(peer);
900 peerProxy = hashmapGet(peer->peerProxies, &pid);
901 peerUnlock(peer);
902
903 if (peerProxy != NULL) {
904 LOGI("Couldn't connect to %d.", pid);
905 peerProxyKill(peerProxy, false);
906 } else {
907 LOGW("Peer proxy for %d not found. This shouldn't happen.", pid);
908 }
909
910 peerProxyExpectHeader(masterProxy);
911 }
912
913 /**
914 * Handles a packet header.
915 */
916 static void peerProxyHandleHeader(PeerProxy* peerProxy, Header* header) {
917 switch (header->type) {
918 case CONNECTION_REQUEST:
919 masterHandleConnectionRequest(peerProxy, header);
920 break;
921 case CONNECTION:
922 masterProxyExpectConnection(peerProxy, header);
923 break;
924 case CONNECTION_ERROR:
925 masterProxyHandleConnectionError(peerProxy, header);
926 break;
927 case BYTES:
928 peerProxyExpectBytes(peerProxy, header);
929 break;
930 default:
931 LOGW("Invalid packet type from %d: %d", peerProxy->credentials.pid,
932 header->type);
933 peerProxyKill(peerProxy, false);
934 }
935 }
936
937 /**
938 * Buffers input sent by peer. May be called multiple times until the entire
939 * buffer is filled. Returns true when the buffer is full.
940 */
941 static bool peerProxyBufferInput(PeerProxy* peerProxy) {
942 Buffer* in = peerProxy->inputBuffer;
943 ssize_t size = bufferRead(in, peerProxy->fd->fd);
944 if (size < 0) {
945 peerProxyHandleError(peerProxy, "read");
946 return false;
947 } else if (size == 0) {
948 // EOF.
949 LOGI("EOF");
950 peerProxyKill(peerProxy, false);
951 return false;
952 } else if (bufferReadComplete(in)) {
953 // We're done!
954 return true;
955 } else {
956 // Continue reading.
957 return false;
958 }
959 }
960
961 /**
962 * Reads input from a peer process.
963 */
964 static void peerProxyRead(SelectableFd* fd) {
965 LOGD("Reading...");
966 PeerProxy* peerProxy = (PeerProxy*) fd->data;
967 int state = peerProxy->inputState;
968 Buffer* in = peerProxy->inputBuffer;
969 switch (state) {
970 case READING_HEADER:
971 if (peerProxyBufferInput(peerProxy)) {
972 LOGD("Header read.");
973 // We've read the complete header.
974 Header* header = (Header*) in->data;
975 peerProxyHandleHeader(peerProxy, header);
976 }
977 break;
978 case READING_BYTES:
979 LOGD("Reading bytes...");
980 if (peerProxyBufferInput(peerProxy)) {
981 LOGD("Bytes read.");
982 // We have the complete packet. Notify bytes listener.
983 peerProxy->peer->onBytes(peerProxy->credentials,
984 in->data, in->size);
985
986 // Get ready for the next packet.
987 peerProxyExpectHeader(peerProxy);
988 }
989 break;
990 case ACCEPTING_CONNECTION:
991 masterProxyAcceptConnection(peerProxy);
992 break;
993 default:
994 LOG_ALWAYS_FATAL("Unknown state: %d", state);
995 }
996 }
997
998 static PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials) {
999 PeerProxy* peerProxy = calloc(1, sizeof(PeerProxy));
1000 if (peerProxy == NULL) {
1001 return NULL;
1002 }
1003
1004 peerProxy->inputBuffer = bufferCreate(sizeof(Header));
1005 if (peerProxy->inputBuffer == NULL) {
1006 free(peerProxy);
1007 return NULL;
1008 }
1009
1010 peerProxy->peer = peer;
1011 peerProxy->credentials = credentials;
1012
1013 // Initial state == expecting a header.
1014 peerProxyExpectHeader(peerProxy);
1015
1016 // Add this proxy to the map. Make sure the key points to the stable memory
1017 // inside of the peer proxy itself.
1018 pid_t* pid = &(peerProxy->credentials.pid);
1019 hashmapPut(peer->peerProxies, pid, peerProxy);
1020 return peerProxy;
1021 }
1022
1023 /** Accepts a connection to the master peer. */
1024 static void masterAcceptConnection(SelectableFd* listenerFd) {
1025 // Accept connection.
1026 int socket = accept(listenerFd->fd, NULL, NULL);
1027 if (socket == -1) {
1028 LOGW("accept() error: %s", strerror(errno));
1029 return;
1030 }
1031
1032 LOGD("Accepted connection as fd %d.", socket);
1033
1034 // Get credentials.
1035 Credentials credentials;
1036 struct ucred ucredentials;
1037 socklen_t credentialsSize = sizeof(struct ucred);
1038 int result = getsockopt(socket, SOL_SOCKET, SO_PEERCRED,
1039 &ucredentials, &credentialsSize);
1040 // We might want to verify credentialsSize.
1041 if (result == -1) {
1042 LOGW("getsockopt() error: %s", strerror(errno));
1043 closeWithWarning(socket);
1044 return;
1045 }
1046
1047 // Copy values into our own structure so we know we have the types right.
1048 credentials.pid = ucredentials.pid;
1049 credentials.uid = ucredentials.uid;
1050 credentials.gid = ucredentials.gid;
1051
1052 LOGI("Accepted connection from process %d.", credentials.pid);
1053
1054 Peer* masterPeer = (Peer*) listenerFd->data;
1055
1056 peerLock(masterPeer);
1057
1058 // Make sure we don't already have a connection from that process.
1059 PeerProxy* peerProxy
1060 = hashmapGet(masterPeer->peerProxies, &credentials.pid);
1061 if (peerProxy != NULL) {
1062 peerUnlock(masterPeer);
1063 LOGW("Alread connected to process %d.", credentials.pid);
1064 closeWithWarning(socket);
1065 return;
1066 }
1067
1068 // Add connection to the selector.
1069 SelectableFd* socketFd = selectorAdd(masterPeer->selector, socket);
1070 if (socketFd == NULL) {
1071 peerUnlock(masterPeer);
1072 LOGW("malloc() failed.");
1073 closeWithWarning(socket);
1074 return;
1075 }
1076
1077 // Create a peer proxy.
1078 peerProxy = peerProxyCreate(masterPeer, credentials);
1079 peerUnlock(masterPeer);
1080 if (peerProxy == NULL) {
1081 LOGW("malloc() failed.");
1082 socketFd->remove = true;
1083 closeWithWarning(socket);
1084 }
1085 peerProxy->connections = hashmapCreate(10, &pidHash, &pidEquals);
1086 peerProxySetFd(peerProxy, socketFd);
1087 }
1088
1089 /**
1090 * Creates the local peer.
1091 */
1092 static Peer* peerCreate() {
1093 Peer* peer = calloc(1, sizeof(Peer));
1094 if (peer == NULL) {
1095 LOG_ALWAYS_FATAL("malloc() error.");
1096 }
1097 peer->peerProxies = hashmapCreate(10, &pidHash, &pidEquals);
1098 peer->selector = selectorCreate();
1099
1100 pthread_mutexattr_t attributes;
1101 if (pthread_mutexattr_init(&attributes) != 0) {
1102 LOG_ALWAYS_FATAL("pthread_mutexattr_init() error.");
1103 }
1104 if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) {
1105 LOG_ALWAYS_FATAL("pthread_mutexattr_settype() error.");
1106 }
1107 if (pthread_mutex_init(&peer->mutex, &attributes) != 0) {
1108 LOG_ALWAYS_FATAL("pthread_mutex_init() error.");
1109 }
1110
1111 peer->pid = getpid();
1112 return peer;
1113 }
1114
1115 /** The local peer. */
1116 static Peer* localPeer;
1117
1118 /** Frees a packet of bytes. */
1119 static void outgoingPacketFreeBytes(OutgoingPacket* packet) {
1120 LOGD("Freeing outgoing packet.");
1121 bufferFree(packet->bytes);
1122 free(packet);
1123 }
1124
1125 /**
1126 * Sends a packet of bytes to a remote peer. Returns 0 on success.
1127 *
1128 * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be
1129 * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno
1130 * to EINVAL if pid is the same as the local pid.
1131 */
1132 int peerSendBytes(pid_t pid, const char* bytes, size_t size) {
1133 Peer* peer = localPeer;
1134 assert(peer != NULL);
1135
1136 OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
1137 if (packet == NULL) {
1138 errno = ENOMEM;
1139 return -1;
1140 }
1141
1142 Buffer* copy = bufferCreate(size);
1143 if (copy == NULL) {
1144 free(packet);
1145 errno = ENOMEM;
1146 return -1;
1147 }
1148
1149 // Copy data.
1150 memcpy(copy->data, bytes, size);
1151 copy->size = size;
1152
1153 packet->bytes = copy;
1154 packet->header.type = BYTES;
1155 packet->header.size = size;
1156 packet->free = outgoingPacketFreeBytes;
1157 bufferPrepareForWrite(packet->bytes);
1158
1159 peerLock(peer);
1160
1161 PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true);
1162 if (peerProxy == NULL) {
1163 // The peer is already dead or we couldn't alloc memory. Either way,
1164 // errno is set.
1165 peerUnlock(peer);
1166 packet->free(packet);
1167 return -1;
1168 } else {
1169 peerProxyEnqueueOutgoingPacket(peerProxy, packet);
1170 peerUnlock(peer);
1171 selectorWakeUp(peer->selector);
1172 return 0;
1173 }
1174 }
1175
1176 /** Keeps track of how to free shared bytes. */
1177 typedef struct {
1178 void (*free)(void* context);
1179 void* context;
1180 } SharedBytesFreer;
1181
1182 /** Frees shared bytes. */
1183 static void outgoingPacketFreeSharedBytes(OutgoingPacket* packet) {
1184 SharedBytesFreer* sharedBytesFreer
1185 = (SharedBytesFreer*) packet->context;
1186 sharedBytesFreer->free(sharedBytesFreer->context);
1187 free(sharedBytesFreer);
1188 free(packet);
1189 }
1190
1191 /**
1192 * Sends a packet of bytes to a remote peer without copying the bytes. Calls
1193 * free() with context after the bytes have been sent.
1194 *
1195 * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be
1196 * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno
1197 * to EINVAL if pid is the same as the local pid.
1198 */
1199 int peerSendSharedBytes(pid_t pid, char* bytes, size_t size,
1200 void (*free)(void* context), void* context) {
1201 Peer* peer = localPeer;
1202 assert(peer != NULL);
1203
1204 OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
1205 if (packet == NULL) {
1206 errno = ENOMEM;
1207 return -1;
1208 }
1209
1210 Buffer* wrapper = bufferWrap(bytes, size, size);
1211 if (wrapper == NULL) {
1212 free(packet);
1213 errno = ENOMEM;
1214 return -1;
1215 }
1216
1217 SharedBytesFreer* sharedBytesFreer = malloc(sizeof(SharedBytesFreer));
1218 if (sharedBytesFreer == NULL) {
1219 free(packet);
1220 free(wrapper);
1221 errno = ENOMEM;
1222 return -1;
1223 }
1224 sharedBytesFreer->free = free;
1225 sharedBytesFreer->context = context;
1226
1227 packet->bytes = wrapper;
1228 packet->context = sharedBytesFreer;
1229 packet->header.type = BYTES;
1230 packet->header.size = size;
1231 packet->free = &outgoingPacketFreeSharedBytes;
1232 bufferPrepareForWrite(packet->bytes);
1233
1234 peerLock(peer);
1235
1236 PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true);
1237 if (peerProxy == NULL) {
1238 // The peer is already dead or we couldn't alloc memory. Either way,
1239 // errno is set.
1240 peerUnlock(peer);
1241 packet->free(packet);
1242 return -1;
1243 } else {
1244 peerProxyEnqueueOutgoingPacket(peerProxy, packet);
1245 peerUnlock(peer);
1246 selectorWakeUp(peer->selector);
1247 return 0;
1248 }
1249 }
1250
1251 /**
1252 * Starts the master peer. The master peer differs from other peers in that
1253 * it is responsible for connecting the other peers. You can only have one
1254 * master peer.
1255 *
1256 * Goes into an I/O loop and does not return.
1257 */
1258 void masterPeerInitialize(BytesListener* bytesListener,
1259 DeathListener* deathListener) {
1260 // Create and bind socket.
1261 int listenerSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
1262 if (listenerSocket == -1) {
1263 LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno));
1264 }
1265 unlink(MASTER_PATH);
1266 int result = bind(listenerSocket, (SocketAddress*) getMasterAddress(),
1267 sizeof(UnixAddress));
1268 if (result == -1) {
1269 LOG_ALWAYS_FATAL("bind() error: %s", strerror(errno));
1270 }
1271
1272 LOGD("Listener socket: %d", listenerSocket);
1273
1274 // Queue up to 16 connections.
1275 result = listen(listenerSocket, 16);
1276 if (result != 0) {
1277 LOG_ALWAYS_FATAL("listen() error: %s", strerror(errno));
1278 }
1279
1280 // Make socket non-blocking.
1281 setNonBlocking(listenerSocket);
1282
1283 // Create the peer for this process. Fail if we already have one.
1284 if (localPeer != NULL) {
1285 LOG_ALWAYS_FATAL("Peer is already initialized.");
1286 }
1287 localPeer = peerCreate();
1288 if (localPeer == NULL) {
1289 LOG_ALWAYS_FATAL("malloc() failed.");
1290 }
1291 localPeer->master = true;
1292 localPeer->onBytes = bytesListener;
1293 localPeer->onDeath = deathListener;
1294
1295 // Make listener socket selectable.
1296 SelectableFd* listenerFd = selectorAdd(localPeer->selector, listenerSocket);
1297 if (listenerFd == NULL) {
1298 LOG_ALWAYS_FATAL("malloc() error.");
1299 }
1300 listenerFd->data = localPeer;
1301 listenerFd->onReadable = &masterAcceptConnection;
1302 }
1303
1304 /**
1305 * Starts a local peer.
1306 *
1307 * Goes into an I/O loop and does not return.
1308 */
1309 void peerInitialize(BytesListener* bytesListener,
1310 DeathListener* deathListener) {
1311 // Connect to master peer.
1312 int masterSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
1313 if (masterSocket == -1) {
1314 LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno));
1315 }
1316 int result = connect(masterSocket, (SocketAddress*) getMasterAddress(),
1317 sizeof(UnixAddress));
1318 if (result != 0) {
1319 LOG_ALWAYS_FATAL("connect() error: %s", strerror(errno));
1320 }
1321
1322 // Create the peer for this process. Fail if we already have one.
1323 if (localPeer != NULL) {
1324 LOG_ALWAYS_FATAL("Peer is already initialized.");
1325 }
1326 localPeer = peerCreate();
1327 if (localPeer == NULL) {
1328 LOG_ALWAYS_FATAL("malloc() failed.");
1329 }
1330 localPeer->onBytes = bytesListener;
1331 localPeer->onDeath = deathListener;
1332
1333 // Make connection selectable.
1334 SelectableFd* masterFd = selectorAdd(localPeer->selector, masterSocket);
1335 if (masterFd == NULL) {
1336 LOG_ALWAYS_FATAL("malloc() error.");
1337 }
1338
1339 // Create a peer proxy for the master peer.
1340 PeerProxy* masterProxy = peerProxyCreate(localPeer, MASTER_CREDENTIALS);
1341 if (masterProxy == NULL) {
1342 LOG_ALWAYS_FATAL("malloc() error.");
1343 }
1344 peerProxySetFd(masterProxy, masterFd);
1345 masterProxy->master = true;
1346 localPeer->masterProxy = masterProxy;
1347 }
1348
1349 /** Starts the master peer I/O loop. Doesn't return. */
1350 void peerLoop() {
1351 assert(localPeer != NULL);
1352
1353 // Start selector.
1354 selectorLoop(localPeer->selector);
1355 }
1356
+0
-246
libcutils/mspace.c less more
0 /* Copyright 2006 The Android Open Source Project */
1
2 /* A wrapper file for dlmalloc.c that compiles in the
3 * mspace_*() functions, which provide an interface for
4 * creating multiple heaps.
5 */
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <stdint.h>
11 #include <sys/ioctl.h>
12
13 #include <cutils/ashmem.h>
14
15 /* It's a pain getting the mallinfo stuff to work
16 * with Linux, OSX, and klibc, so just turn it off
17 * for now.
18 * TODO: make mallinfo work
19 */
20 #define NO_MALLINFO 1
21
22 /* Allow setting the maximum heap footprint.
23 */
24 #define USE_MAX_ALLOWED_FOOTPRINT 1
25
26 /* Don't try to trim memory.
27 * TODO: support this.
28 */
29 #define MORECORE_CANNOT_TRIM 1
30
31 /* Use mmap()d anonymous memory to guarantee
32 * that an mspace is contiguous.
33 *
34 * create_mspace() won't work right if this is
35 * defined, so hide the definition of it and
36 * break any users at build time.
37 */
38 #define USE_CONTIGUOUS_MSPACES 1
39 #if USE_CONTIGUOUS_MSPACES
40 /* This combination of settings forces sys_alloc()
41 * to always use MORECORE(). It won't expect the
42 * results to be contiguous, but we'll guarantee
43 * that they are.
44 */
45 #define HAVE_MMAP 0
46 #define HAVE_MORECORE 1
47 #define MORECORE_CONTIGUOUS 0
48 /* m is always the appropriate local when MORECORE() is called. */
49 #define MORECORE(S) contiguous_mspace_morecore(m, S)
50 #define create_mspace HIDDEN_create_mspace_HIDDEN
51 #define destroy_mspace HIDDEN_destroy_mspace_HIDDEN
52 typedef struct malloc_state *mstate0;
53 static void *contiguous_mspace_morecore(mstate0 m, ssize_t nb);
54 #endif
55
56 #define MSPACES 1
57 #define ONLY_MSPACES 1
58 #include "../../../bionic/libc/bionic/dlmalloc.c"
59
60 #ifndef PAGESIZE
61 #define PAGESIZE mparams.page_size
62 #endif
63
64 #define ALIGN_UP(p, alignment) \
65 (((uintptr_t)(p) + (alignment)-1) & ~((alignment)-1))
66
67 /* A direct copy of dlmalloc_usable_size(),
68 * which isn't compiled in when ONLY_MSPACES is set.
69 * The mspace parameter isn't actually necessary,
70 * but we include it to be consistent with the
71 * rest of the mspace_*() functions.
72 */
73 size_t mspace_usable_size(mspace _unused, const void* mem) {
74 if (mem != 0) {
75 const mchunkptr p = mem2chunk(mem);
76 if (cinuse(p))
77 return chunksize(p) - overhead_for(p);
78 }
79 return 0;
80 }
81
82 #if USE_CONTIGUOUS_MSPACES
83 #include <sys/mman.h>
84 #include <limits.h>
85
86 #define CONTIG_STATE_MAGIC 0xf00dd00d
87 struct mspace_contig_state {
88 unsigned int magic;
89 char *brk;
90 char *top;
91 mspace m;
92 };
93
94 static void *contiguous_mspace_morecore(mstate m, ssize_t nb) {
95 struct mspace_contig_state *cs;
96 char *oldbrk;
97 const unsigned int pagesize = PAGESIZE;
98
99 cs = (struct mspace_contig_state *)((uintptr_t)m & ~(pagesize-1));
100 assert(cs->magic == CONTIG_STATE_MAGIC);
101 assert(cs->m == m);
102 assert(nb >= 0); //xxx deal with the trim case
103
104 oldbrk = cs->brk;
105 if (nb > 0) {
106 /* Break to the first page boundary that satisfies the request.
107 */
108 char *newbrk = (char *)ALIGN_UP(oldbrk + nb, pagesize);
109 if (newbrk > cs->top)
110 return CMFAIL;
111
112 /* Update the protection on the underlying memory.
113 * Pages we've given to dlmalloc are read/write, and
114 * pages we haven't are not accessable (read or write
115 * will cause a seg fault).
116 */
117 if (mprotect(cs, newbrk - (char *)cs, PROT_READ | PROT_WRITE) < 0)
118 return CMFAIL;
119 if (newbrk != cs->top) {
120 if (mprotect(newbrk, cs->top - newbrk, PROT_NONE) < 0)
121 return CMFAIL;
122 }
123
124 cs->brk = newbrk;
125
126 /* Make sure that dlmalloc will merge this block with the
127 * initial block that was passed to create_mspace_with_base().
128 * We don't care about extern vs. non-extern, so just clear it.
129 */
130 m->seg.sflags &= ~EXTERN_BIT;
131 }
132
133 return oldbrk;
134 }
135
136 mspace create_contiguous_mspace_with_name(size_t starting_capacity,
137 size_t max_capacity, int locked, char const * name) {
138 int fd, ret;
139 struct mspace_contig_state *cs;
140 char buf[ASHMEM_NAME_LEN] = "mspace";
141 void *base;
142 unsigned int pagesize;
143 mstate m;
144
145 if (starting_capacity > max_capacity)
146 return (mspace)0;
147
148 init_mparams();
149 pagesize = PAGESIZE;
150
151 /* Create the anonymous memory that will back the mspace.
152 * This reserves all of the virtual address space we could
153 * ever need. Physical pages will be mapped as the memory
154 * is touched.
155 *
156 * Align max_capacity to a whole page.
157 */
158 max_capacity = (size_t)ALIGN_UP(max_capacity, pagesize);
159
160 if (name)
161 snprintf(buf, sizeof(buf), "mspace/%s", name);
162 fd = ashmem_create_region(buf, max_capacity);
163 if (fd < 0)
164 return (mspace)0;
165
166 base = mmap(NULL, max_capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
167 close(fd);
168 if (base == MAP_FAILED)
169 return (mspace)0;
170
171 /* Make sure that base is at the beginning of a page.
172 */
173 assert(((uintptr_t)base & (pagesize-1)) == 0);
174
175 /* Reserve some space for the information that our MORECORE needs.
176 */
177 cs = base;
178
179 /* Create the mspace, pointing to the memory we just reserved.
180 */
181 m = create_mspace_with_base(base + sizeof(*cs), starting_capacity, locked);
182 if (m == (mspace)0)
183 goto error;
184
185 /* Make sure that m is in the same page as cs.
186 */
187 assert(((uintptr_t)m & (uintptr_t)~(pagesize-1)) == (uintptr_t)base);
188
189 /* Find out exactly how much of the memory the mspace
190 * is using.
191 */
192 cs->brk = m->seg.base + m->seg.size;
193 cs->top = (char *)base + max_capacity;
194 assert((char *)base <= cs->brk);
195 assert(cs->brk <= cs->top);
196
197 /* Prevent access to the memory we haven't handed out yet.
198 */
199 if (cs->brk != cs->top) {
200 /* mprotect() requires page-aligned arguments, but it's possible
201 * for cs->brk not to be page-aligned at this point.
202 */
203 char *prot_brk = (char *)ALIGN_UP(cs->brk, pagesize);
204 if (mprotect(prot_brk, cs->top - prot_brk, PROT_NONE) < 0)
205 goto error;
206 }
207
208 cs->m = m;
209 cs->magic = CONTIG_STATE_MAGIC;
210
211 return (mspace)m;
212
213 error:
214 munmap(base, max_capacity);
215 return (mspace)0;
216 }
217
218 mspace create_contiguous_mspace(size_t starting_capacity,
219 size_t max_capacity, int locked) {
220 return create_contiguous_mspace_with_name(starting_capacity,
221 max_capacity, locked, NULL);
222 }
223
224 size_t destroy_contiguous_mspace(mspace msp) {
225 mstate ms = (mstate)msp;
226
227 if (ok_magic(ms)) {
228 struct mspace_contig_state *cs;
229 size_t length;
230 const unsigned int pagesize = PAGESIZE;
231
232 cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
233 assert(cs->magic == CONTIG_STATE_MAGIC);
234 assert(cs->m == ms);
235
236 length = cs->top - (char *)cs;
237 if (munmap((char *)cs, length) != 0)
238 return length;
239 }
240 else {
241 USAGE_ERROR_ACTION(ms, ms);
242 }
243 return 0;
244 }
245 #endif
+0
-368
libcutils/private.h less more
0 #ifndef PRIVATE_H
1
2 #define PRIVATE_H
3
4 /*
5 ** This file is in the public domain, so clarified as of
6 ** 1996-06-05 by Arthur David Olson.
7 */
8
9 /*
10 ** This header is for use ONLY with the time conversion code.
11 ** There is no guarantee that it will remain unchanged,
12 ** or that it will remain at all.
13 ** Do NOT copy it to any system include directory.
14 ** Thank you!
15 */
16
17 /*
18 ** ID
19 */
20
21 #ifndef lint
22 #ifndef NOID
23 static char privatehid[] = "@(#)private.h 8.2";
24 #endif /* !defined NOID */
25 #endif /* !defined lint */
26
27 #define GRANDPARENTED "Local time zone must be set--see zic manual page"
28
29 /*
30 ** Defaults for preprocessor symbols.
31 ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
32 */
33
34 #ifndef HAVE_ADJTIME
35 #define HAVE_ADJTIME 1
36 #endif /* !defined HAVE_ADJTIME */
37
38 #ifndef HAVE_GETTEXT
39 #define HAVE_GETTEXT 0
40 #endif /* !defined HAVE_GETTEXT */
41
42 #ifndef HAVE_INCOMPATIBLE_CTIME_R
43 #define HAVE_INCOMPATIBLE_CTIME_R 0
44 #endif /* !defined INCOMPATIBLE_CTIME_R */
45
46 #ifndef HAVE_SETTIMEOFDAY
47 #define HAVE_SETTIMEOFDAY 3
48 #endif /* !defined HAVE_SETTIMEOFDAY */
49
50 #ifndef HAVE_STRERROR
51 #define HAVE_STRERROR 1
52 #endif /* !defined HAVE_STRERROR */
53
54 #ifndef HAVE_SYMLINK
55 #define HAVE_SYMLINK 1
56 #endif /* !defined HAVE_SYMLINK */
57
58 #ifndef HAVE_SYS_STAT_H
59 #define HAVE_SYS_STAT_H 1
60 #endif /* !defined HAVE_SYS_STAT_H */
61
62 #ifndef HAVE_SYS_WAIT_H
63 #define HAVE_SYS_WAIT_H 1
64 #endif /* !defined HAVE_SYS_WAIT_H */
65
66 #ifndef HAVE_UNISTD_H
67 #define HAVE_UNISTD_H 1
68 #endif /* !defined HAVE_UNISTD_H */
69
70 #ifndef HAVE_UTMPX_H
71 #define HAVE_UTMPX_H 0
72 #endif /* !defined HAVE_UTMPX_H */
73
74 #ifndef LOCALE_HOME
75 #define LOCALE_HOME "/usr/lib/locale"
76 #endif /* !defined LOCALE_HOME */
77
78 #if HAVE_INCOMPATIBLE_CTIME_R
79 #define asctime_r _incompatible_asctime_r
80 #define ctime_r _incompatible_ctime_r
81 #endif /* HAVE_INCOMPATIBLE_CTIME_R */
82
83 /*
84 ** Nested includes
85 */
86
87 #include "sys/types.h" /* for time_t */
88 #include "stdio.h"
89 #include "errno.h"
90 #include "string.h"
91 #include "limits.h" /* for CHAR_BIT et al. */
92 #include "time.h"
93 #include "stdlib.h"
94
95 #if HAVE_GETTEXT
96 #include "libintl.h"
97 #endif /* HAVE_GETTEXT */
98
99 #if HAVE_SYS_WAIT_H
100 #include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
101 #endif /* HAVE_SYS_WAIT_H */
102
103 #ifndef WIFEXITED
104 #define WIFEXITED(status) (((status) & 0xff) == 0)
105 #endif /* !defined WIFEXITED */
106 #ifndef WEXITSTATUS
107 #define WEXITSTATUS(status) (((status) >> 8) & 0xff)
108 #endif /* !defined WEXITSTATUS */
109
110 #if HAVE_UNISTD_H
111 #include "unistd.h" /* for F_OK and R_OK */
112 #endif /* HAVE_UNISTD_H */
113
114 #if !HAVE_UNISTD_H
115 #ifndef F_OK
116 #define F_OK 0
117 #endif /* !defined F_OK */
118 #ifndef R_OK
119 #define R_OK 4
120 #endif /* !defined R_OK */
121 #endif /* !HAVE_UNISTD_H */
122
123 /* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
124 #define is_digit(c) ((unsigned)(c) - '0' <= 9)
125
126 /*
127 ** Define HAVE_STDINT_H's default value here, rather than at the
128 ** start, since __GLIBC__'s value depends on previously-included
129 ** files.
130 ** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
131 */
132 #ifndef HAVE_STDINT_H
133 #define HAVE_STDINT_H \
134 (199901 <= __STDC_VERSION__ || \
135 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
136 #endif /* !defined HAVE_STDINT_H */
137
138 #if HAVE_STDINT_H
139 #include "stdint.h"
140 #endif /* !HAVE_STDINT_H */
141
142 #ifndef INT_FAST64_MAX
143 /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
144 #if defined LLONG_MAX || defined __LONG_LONG_MAX__
145 typedef long long int_fast64_t;
146 #else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
147 #if (LONG_MAX >> 31) < 0xffffffff
148 Please use a compiler that supports a 64-bit integer type (or wider);
149 you may need to compile with "-DHAVE_STDINT_H".
150 #endif /* (LONG_MAX >> 31) < 0xffffffff */
151 typedef long int_fast64_t;
152 #endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
153 #endif /* !defined INT_FAST64_MAX */
154
155 #ifndef INT32_MAX
156 #define INT32_MAX 0x7fffffff
157 #endif /* !defined INT32_MAX */
158 #ifndef INT32_MIN
159 #define INT32_MIN (-1 - INT32_MAX)
160 #endif /* !defined INT32_MIN */
161
162 /*
163 ** Workarounds for compilers/systems.
164 */
165
166 /*
167 ** If your compiler lacks prototypes, "#define P(x) ()".
168 */
169
170 #ifndef P
171 #define P(x) x
172 #endif /* !defined P */
173
174 /*
175 ** SunOS 4.1.1 headers lack EXIT_SUCCESS.
176 */
177
178 #ifndef EXIT_SUCCESS
179 #define EXIT_SUCCESS 0
180 #endif /* !defined EXIT_SUCCESS */
181
182 /*
183 ** SunOS 4.1.1 headers lack EXIT_FAILURE.
184 */
185
186 #ifndef EXIT_FAILURE
187 #define EXIT_FAILURE 1
188 #endif /* !defined EXIT_FAILURE */
189
190 /*
191 ** SunOS 4.1.1 headers lack FILENAME_MAX.
192 */
193
194 #ifndef FILENAME_MAX
195
196 #ifndef MAXPATHLEN
197 #ifdef unix
198 #include "sys/param.h"
199 #endif /* defined unix */
200 #endif /* !defined MAXPATHLEN */
201
202 #ifdef MAXPATHLEN
203 #define FILENAME_MAX MAXPATHLEN
204 #endif /* defined MAXPATHLEN */
205 #ifndef MAXPATHLEN
206 #define FILENAME_MAX 1024 /* Pure guesswork */
207 #endif /* !defined MAXPATHLEN */
208
209 #endif /* !defined FILENAME_MAX */
210
211 /*
212 ** SunOS 4.1.1 libraries lack remove.
213 */
214
215 #ifndef remove
216 extern int unlink P((const char * filename));
217 #define remove unlink
218 #endif /* !defined remove */
219
220 /*
221 ** Some ancient errno.h implementations don't declare errno.
222 ** But some newer errno.h implementations define it as a macro.
223 ** Fix the former without affecting the latter.
224 */
225
226 #ifndef errno
227 extern int errno;
228 #endif /* !defined errno */
229
230 /*
231 ** Some time.h implementations don't declare asctime_r.
232 ** Others might define it as a macro.
233 ** Fix the former without affecting the latter.
234 */
235
236 #ifndef asctime_r
237 extern char * asctime_r();
238 #endif
239
240 /*
241 ** Private function declarations.
242 */
243
244 char * icalloc P((int nelem, int elsize));
245 char * icatalloc P((char * old, const char * new));
246 char * icpyalloc P((const char * string));
247 char * imalloc P((int n));
248 void * irealloc P((void * pointer, int size));
249 void icfree P((char * pointer));
250 void ifree P((char * pointer));
251 const char * scheck P((const char * string, const char * format));
252
253 /*
254 ** Finally, some convenience items.
255 */
256
257 #ifndef TRUE
258 #define TRUE 1
259 #endif /* !defined TRUE */
260
261 #ifndef FALSE
262 #define FALSE 0
263 #endif /* !defined FALSE */
264
265 #ifndef TYPE_BIT
266 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
267 #endif /* !defined TYPE_BIT */
268
269 #ifndef TYPE_SIGNED
270 #define TYPE_SIGNED(type) (((type) -1) < 0)
271 #endif /* !defined TYPE_SIGNED */
272
273 /*
274 ** Since the definition of TYPE_INTEGRAL contains floating point numbers,
275 ** it cannot be used in preprocessor directives.
276 */
277
278 #ifndef TYPE_INTEGRAL
279 #define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
280 #endif /* !defined TYPE_INTEGRAL */
281
282 #ifndef INT_STRLEN_MAXIMUM
283 /*
284 ** 302 / 1000 is log10(2.0) rounded up.
285 ** Subtract one for the sign bit if the type is signed;
286 ** add one for integer division truncation;
287 ** add one more for a minus sign if the type is signed.
288 */
289 #define INT_STRLEN_MAXIMUM(type) \
290 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
291 1 + TYPE_SIGNED(type))
292 #endif /* !defined INT_STRLEN_MAXIMUM */
293
294 /*
295 ** INITIALIZE(x)
296 */
297
298 #ifndef GNUC_or_lint
299 #ifdef lint
300 #define GNUC_or_lint
301 #endif /* defined lint */
302 #ifndef lint
303 #ifdef __GNUC__
304 #define GNUC_or_lint
305 #endif /* defined __GNUC__ */
306 #endif /* !defined lint */
307 #endif /* !defined GNUC_or_lint */
308
309 #ifndef INITIALIZE
310 #ifdef GNUC_or_lint
311 #define INITIALIZE(x) ((x) = 0)
312 #endif /* defined GNUC_or_lint */
313 #ifndef GNUC_or_lint
314 #define INITIALIZE(x)
315 #endif /* !defined GNUC_or_lint */
316 #endif /* !defined INITIALIZE */
317
318 /*
319 ** For the benefit of GNU folk...
320 ** `_(MSGID)' uses the current locale's message library string for MSGID.
321 ** The default is to use gettext if available, and use MSGID otherwise.
322 */
323
324 #ifndef _
325 #if HAVE_GETTEXT
326 #define _(msgid) gettext(msgid)
327 #else /* !HAVE_GETTEXT */
328 #define _(msgid) msgid
329 #endif /* !HAVE_GETTEXT */
330 #endif /* !defined _ */
331
332 #ifndef TZ_DOMAIN
333 #define TZ_DOMAIN "tz"
334 #endif /* !defined TZ_DOMAIN */
335
336 #if HAVE_INCOMPATIBLE_CTIME_R
337 #undef asctime_r
338 #undef ctime_r
339 char *asctime_r P((struct tm const *, char *));
340 char *ctime_r P((time_t const *, char *));
341 #endif /* HAVE_INCOMPATIBLE_CTIME_R */
342
343 #ifndef YEARSPERREPEAT
344 #define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
345 #endif /* !defined YEARSPERREPEAT */
346
347 /*
348 ** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
349 */
350
351 #ifndef AVGSECSPERYEAR
352 #define AVGSECSPERYEAR 31556952L
353 #endif /* !defined AVGSECSPERYEAR */
354
355 #ifndef SECSPERREPEAT
356 #define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
357 #endif /* !defined SECSPERREPEAT */
358
359 #ifndef SECSPERREPEAT_BITS
360 #define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
361 #endif /* !defined SECSPERREPEAT_BITS */
362
363 /*
364 ** UNIX was a registered trademark of The Open Group in 2003.
365 */
366
367 #endif /* !defined PRIVATE_H */
+0
-75
libcutils/process_name.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <cutils/process_name.h>
18 #include <cutils/properties.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23
24 #define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
25
26 static const char* process_name = "unknown";
27 static int running_in_emulator = -1;
28
29 void set_process_name(const char* new_name) {
30 char propBuf[PROPERTY_VALUE_MAX];
31
32 if (new_name == NULL) {
33 return;
34 }
35
36 // We never free the old name. Someone else could be using it.
37 char* copy = (char*) malloc(strlen(new_name) + 1);
38 strcpy(copy, new_name);
39 process_name = (const char*) copy;
40
41 // If we know we are not running in the emulator, then return.
42 if (running_in_emulator == 0) {
43 return;
44 }
45
46 // If the "running_in_emulator" variable has not been initialized,
47 // then do it now.
48 if (running_in_emulator == -1) {
49 property_get("ro.kernel.qemu", propBuf, "");
50 if (propBuf[0] == '1') {
51 running_in_emulator = 1;
52 } else {
53 running_in_emulator = 0;
54 return;
55 }
56 }
57
58 // If the emulator was started with the "-trace file" command line option
59 // then we want to record the process name in the trace even if we are
60 // not currently tracing instructions (so that we will know the process
61 // name when we do start tracing instructions). We do not need to execute
62 // this code if we are just running in the emulator without the "-trace"
63 // command line option, but we don't know that here and this function
64 // isn't called frequently enough to bother optimizing that case.
65 int fd = open(PROCESS_NAME_DEVICE, O_RDWR);
66 if (fd < 0)
67 return;
68 write(fd, process_name, strlen(process_name) + 1);
69 close(fd);
70 }
71
72 const char* get_process_name(void) {
73 return process_name;
74 }
+0
-368
libcutils/properties.c less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "properties"
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <cutils/sockets.h>
22 #include <errno.h>
23 #include <assert.h>
24
25 #include <cutils/properties.h>
26 #include "loghack.h"
27
28 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
29
30 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
31 #include <sys/_system_properties.h>
32
33 static int send_prop_msg(prop_msg *msg)
34 {
35 int s;
36 int r;
37
38 s = socket_local_client(PROP_SERVICE_NAME,
39 ANDROID_SOCKET_NAMESPACE_RESERVED,
40 SOCK_STREAM);
41 if(s < 0) return -1;
42
43 while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {
44 if((errno == EINTR) || (errno == EAGAIN)) continue;
45 break;
46 }
47
48 if(r == sizeof(prop_msg)) {
49 r = 0;
50 } else {
51 r = -1;
52 }
53
54 close(s);
55 return r;
56 }
57
58 int property_set(const char *key, const char *value)
59 {
60 prop_msg msg;
61 unsigned resp;
62
63 if(key == 0) return -1;
64 if(value == 0) value = "";
65
66 if(strlen(key) >= PROP_NAME_MAX) return -1;
67 if(strlen(value) >= PROP_VALUE_MAX) return -1;
68
69 msg.cmd = PROP_MSG_SETPROP;
70 strcpy((char*) msg.name, key);
71 strcpy((char*) msg.value, value);
72
73 return send_prop_msg(&msg);
74 }
75
76 int property_get(const char *key, char *value, const char *default_value)
77 {
78 int len;
79
80 len = __system_property_get(key, value);
81 if(len > 0) {
82 return len;
83 }
84
85 if(default_value) {
86 len = strlen(default_value);
87 memcpy(value, default_value, len + 1);
88 }
89 return len;
90 }
91
92 int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
93 void *cookie)
94 {
95 char name[PROP_NAME_MAX];
96 char value[PROP_VALUE_MAX];
97 const prop_info *pi;
98 unsigned n;
99
100 for(n = 0; (pi = __system_property_find_nth(n)); n++) {
101 __system_property_read(pi, name, value);
102 propfn(name, value, cookie);
103 }
104 return 0;
105 }
106
107 #elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
108
109 /*
110 * The Linux simulator provides a "system property server" that uses IPC
111 * to set/get/list properties. The file descriptor is shared by all
112 * threads in the process, so we use a mutex to ensure that requests
113 * from multiple threads don't get interleaved.
114 */
115 #include <stdio.h>
116 #include <sys/types.h>
117 #include <sys/socket.h>
118 #include <sys/un.h>
119 #include <pthread.h>
120
121 static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
122 static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
123 static int gPropFd = -1;
124
125 /*
126 * Connect to the properties server.
127 *
128 * Returns the socket descriptor on success.
129 */
130 static int connectToServer(const char* fileName)
131 {
132 int sock = -1;
133 int cc;
134
135 struct sockaddr_un addr;
136
137 sock = socket(AF_UNIX, SOCK_STREAM, 0);
138 if (sock < 0) {
139 LOGW("UNIX domain socket create failed (errno=%d)\n", errno);
140 return -1;
141 }
142
143 /* connect to socket; fails if file doesn't exist */
144 strcpy(addr.sun_path, fileName); // max 108 bytes
145 addr.sun_family = AF_UNIX;
146 cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
147 if (cc < 0) {
148 // ENOENT means socket file doesn't exist
149 // ECONNREFUSED means socket exists but nobody is listening
150 //LOGW("AF_UNIX connect failed for '%s': %s\n",
151 // fileName, strerror(errno));
152 close(sock);
153 return -1;
154 }
155
156 return sock;
157 }
158
159 /*
160 * Perform one-time initialization.
161 */
162 static void init(void)
163 {
164 assert(gPropFd == -1);
165
166 gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
167 if (gPropFd < 0) {
168 //LOGW("not connected to system property server\n");
169 } else {
170 //LOGV("Connected to system property server\n");
171 }
172 }
173
174 int property_get(const char *key, char *value, const char *default_value)
175 {
176 char sendBuf[1+PROPERTY_KEY_MAX];
177 char recvBuf[1+PROPERTY_VALUE_MAX];
178 int len = -1;
179
180 //LOGV("PROPERTY GET [%s]\n", key);
181
182 pthread_once(&gInitOnce, init);
183 if (gPropFd < 0) {
184 /* this mimics the behavior of the device implementation */
185 if (default_value != NULL) {
186 strcpy(value, default_value);
187 len = strlen(value);
188 }
189 return len;
190 }
191
192 if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
193
194 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
195
196 sendBuf[0] = (char) kSystemPropertyGet;
197 strcpy(sendBuf+1, key);
198
199 pthread_mutex_lock(&gPropertyFdLock);
200 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
201 pthread_mutex_unlock(&gPropertyFdLock);
202 return -1;
203 }
204 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
205 pthread_mutex_unlock(&gPropertyFdLock);
206 return -1;
207 }
208 pthread_mutex_unlock(&gPropertyFdLock);
209
210 /* first byte is 0 if value not defined, 1 if found */
211 if (recvBuf[0] == 0) {
212 if (default_value != NULL) {
213 strcpy(value, default_value);
214 len = strlen(value);
215 } else {
216 /*
217 * If the value isn't defined, hand back an empty string and
218 * a zero length, rather than a failure. This seems wrong,
219 * since you can't tell the difference between "undefined" and
220 * "defined but empty", but it's what the device does.
221 */
222 value[0] = '\0';
223 len = 0;
224 }
225 } else if (recvBuf[0] == 1) {
226 strcpy(value, recvBuf+1);
227 len = strlen(value);
228 } else {
229 LOGE("Got strange response to property_get request (%d)\n",
230 recvBuf[0]);
231 assert(0);
232 return -1;
233 }
234 //LOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
235 // recvBuf[0], default_value, len, key, value);
236
237 return len;
238 }
239
240
241 int property_set(const char *key, const char *value)
242 {
243 char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
244 char recvBuf[1];
245 int result = -1;
246
247 //LOGV("PROPERTY SET [%s]: [%s]\n", key, value);
248
249 pthread_once(&gInitOnce, init);
250 if (gPropFd < 0)
251 return -1;
252
253 if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
254 if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
255
256 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
257
258 sendBuf[0] = (char) kSystemPropertySet;
259 strcpy(sendBuf+1, key);
260 strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
261
262 pthread_mutex_lock(&gPropertyFdLock);
263 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
264 pthread_mutex_unlock(&gPropertyFdLock);
265 return -1;
266 }
267 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
268 pthread_mutex_unlock(&gPropertyFdLock);
269 return -1;
270 }
271 pthread_mutex_unlock(&gPropertyFdLock);
272
273 if (recvBuf[0] != 1)
274 return -1;
275 return 0;
276 }
277
278 int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
279 void *cookie)
280 {
281 //LOGV("PROPERTY LIST\n");
282 pthread_once(&gInitOnce, init);
283 if (gPropFd < 0)
284 return -1;
285
286 return 0;
287 }
288
289 #else
290
291 /* SUPER-cheesy place-holder implementation for Win32 */
292
293 #include <cutils/threads.h>
294
295 static mutex_t env_lock = MUTEX_INITIALIZER;
296
297 int property_get(const char *key, char *value, const char *default_value)
298 {
299 char ename[PROPERTY_KEY_MAX + 6];
300 char *p;
301 int len;
302
303 len = strlen(key);
304 if(len >= PROPERTY_KEY_MAX) return -1;
305 memcpy(ename, "PROP_", 5);
306 memcpy(ename + 5, key, len + 1);
307
308 mutex_lock(&env_lock);
309
310 p = getenv(ename);
311 if(p == 0) p = "";
312 len = strlen(p);
313 if(len >= PROPERTY_VALUE_MAX) {
314 len = PROPERTY_VALUE_MAX - 1;
315 }
316
317 if((len == 0) && default_value) {
318 len = strlen(default_value);
319 memcpy(value, default_value, len + 1);
320 } else {
321 memcpy(value, p, len);
322 value[len] = 0;
323 }
324
325 mutex_unlock(&env_lock);
326
327 return len;
328 }
329
330
331 int property_set(const char *key, const char *value)
332 {
333 char ename[PROPERTY_KEY_MAX + 6];
334 char *p;
335 int len;
336 int r;
337
338 if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
339
340 len = strlen(key);
341 if(len >= PROPERTY_KEY_MAX) return -1;
342 memcpy(ename, "PROP_", 5);
343 memcpy(ename + 5, key, len + 1);
344
345 mutex_lock(&env_lock);
346 #ifdef HAVE_MS_C_RUNTIME
347 {
348 char temp[256];
349 snprintf( temp, sizeof(temp), "%s=%s", ename, value);
350 putenv(temp);
351 r = 0;
352 }
353 #else
354 r = setenv(ename, value, 1);
355 #endif
356 mutex_unlock(&env_lock);
357
358 return r;
359 }
360
361 int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
362 void *cookie)
363 {
364 return 0;
365 }
366
367 #endif
+0
-186
libcutils/record_stream.c less more
0 /* libs/cutils/record_stream.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <cutils/record_stream.h>
22 #include <string.h>
23 #include <stdint.h>
24 #ifdef HAVE_WINSOCK
25 #include <winsock2.h> /* for ntohl */
26 #else
27 #include <netinet/in.h>
28 #endif
29
30 #define HEADER_SIZE 4
31
32 struct RecordStream {
33 int fd;
34 size_t maxRecordLen;
35
36 unsigned char *buffer;
37
38 unsigned char *unconsumed;
39 unsigned char *read_end;
40 unsigned char *buffer_end;
41 };
42
43
44 extern RecordStream *record_stream_new(int fd, size_t maxRecordLen)
45 {
46 RecordStream *ret;
47
48 assert (maxRecordLen <= 0xffff);
49
50 ret = (RecordStream *)calloc(1, sizeof(RecordStream));
51
52 ret->fd = fd;
53 ret->maxRecordLen = maxRecordLen;
54 ret->buffer = (unsigned char *)malloc (maxRecordLen + HEADER_SIZE);
55
56 ret->unconsumed = ret->buffer;
57 ret->read_end = ret->buffer;
58 ret->buffer_end = ret->buffer + maxRecordLen + HEADER_SIZE;
59
60 return ret;
61 }
62
63
64 extern void record_stream_free(RecordStream *rs)
65 {
66 free(rs->buffer);
67 free(rs);
68 }
69
70
71 /* returns NULL; if there isn't a full record in the buffer */
72 static unsigned char * getEndOfRecord (unsigned char *p_begin,
73 unsigned char *p_end)
74 {
75 size_t len;
76 unsigned char * p_ret;
77
78 if (p_end < p_begin + HEADER_SIZE) {
79 return NULL;
80 }
81
82 //First four bytes are length
83 len = ntohl(*((uint32_t *)p_begin));
84
85 p_ret = p_begin + HEADER_SIZE + len;
86
87 if (p_end < p_ret) {
88 return NULL;
89 }
90
91 return p_ret;
92 }
93
94 static void *getNextRecord (RecordStream *p_rs, size_t *p_outRecordLen)
95 {
96 unsigned char *record_start, *record_end;
97
98 record_end = getEndOfRecord (p_rs->unconsumed, p_rs->read_end);
99
100 if (record_end != NULL) {
101 /* one full line in the buffer */
102 record_start = p_rs->unconsumed + HEADER_SIZE;
103 p_rs->unconsumed = record_end;
104
105 *p_outRecordLen = record_end - record_start;
106
107 return record_start;
108 }
109
110 return NULL;
111 }
112
113 /**
114 * Reads the next record from stream fd
115 * Records are prefixed by a 16-bit big endian length value
116 * Records may not be larger than maxRecordLen
117 *
118 * Doesn't guard against EINTR
119 *
120 * p_outRecord and p_outRecordLen may not be NULL
121 *
122 * Return 0 on success, -1 on fail
123 * Returns 0 with *p_outRecord set to NULL on end of stream
124 * Returns -1 / errno = EAGAIN if it needs to read again
125 */
126 int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
127 size_t *p_outRecordLen)
128 {
129 void *ret;
130
131 ssize_t countRead;
132
133 /* is there one record already in the buffer? */
134 ret = getNextRecord (p_rs, p_outRecordLen);
135
136 if (ret != NULL) {
137 *p_outRecord = ret;
138 return 0;
139 }
140
141 // if the buffer is full and we don't have a full record
142 if (p_rs->unconsumed == p_rs->buffer
143 && p_rs->read_end == p_rs->buffer_end
144 ) {
145 // this should never happen
146 //LOGE("max record length exceeded\n");
147 assert (0);
148 errno = EFBIG;
149 return -1;
150 }
151
152 if (p_rs->unconsumed != p_rs->buffer) {
153 // move remainder to the beginning of the buffer
154 size_t toMove;
155
156 toMove = p_rs->read_end - p_rs->unconsumed;
157 if (toMove) {
158 memmove(p_rs->buffer, p_rs->unconsumed, toMove);
159 }
160
161 p_rs->read_end = p_rs->buffer + toMove;
162 p_rs->unconsumed = p_rs->buffer;
163 }
164
165 countRead = read (p_rs->fd, p_rs->read_end, p_rs->buffer_end - p_rs->read_end);
166
167 if (countRead <= 0) {
168 /* note: end-of-stream drops through here too */
169 *p_outRecord = NULL;
170 return countRead;
171 }
172
173 p_rs->read_end += countRead;
174
175 ret = getNextRecord (p_rs, p_outRecordLen);
176
177 if (ret == NULL) {
178 /* not enough of a buffer to for a whole command */
179 errno = EAGAIN;
180 return -1;
181 }
182
183 *p_outRecord = ret;
184 return 0;
185 }
+0
-263
libcutils/selector.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "selector"
17
18 #include <assert.h>
19 #include <errno.h>
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <cutils/array.h>
27 #include <cutils/selector.h>
28
29 #include "loghack.h"
30
31 struct Selector {
32 Array* selectableFds;
33 bool looping;
34 fd_set readFds;
35 fd_set writeFds;
36 fd_set exceptFds;
37 int maxFd;
38 int wakeupPipe[2];
39 SelectableFd* wakeupFd;
40
41 bool inSelect;
42 pthread_mutex_t inSelectLock;
43 };
44
45 /** Reads and ignores wake up data. */
46 static void eatWakeupData(SelectableFd* wakeupFd) {
47 static char garbage[64];
48 if (read(wakeupFd->fd, garbage, sizeof(garbage)) < 0) {
49 if (errno == EINTR) {
50 LOGI("read() interrupted.");
51 } else {
52 LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
53 }
54 }
55 }
56
57 static void setInSelect(Selector* selector, bool inSelect) {
58 pthread_mutex_lock(&selector->inSelectLock);
59 selector->inSelect = inSelect;
60 pthread_mutex_unlock(&selector->inSelectLock);
61 }
62
63 static bool isInSelect(Selector* selector) {
64 pthread_mutex_lock(&selector->inSelectLock);
65 bool inSelect = selector->inSelect;
66 pthread_mutex_unlock(&selector->inSelectLock);
67 return inSelect;
68 }
69
70 void selectorWakeUp(Selector* selector) {
71 if (!isInSelect(selector)) {
72 // We only need to write wake-up data if we're blocked in select().
73 return;
74 }
75
76 static char garbage[1];
77 if (write(selector->wakeupPipe[1], garbage, sizeof(garbage)) < 0) {
78 if (errno == EINTR) {
79 LOGI("read() interrupted.");
80 } else {
81 LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
82 }
83 }
84 }
85
86 Selector* selectorCreate(void) {
87 Selector* selector = calloc(1, sizeof(Selector));
88 if (selector == NULL) {
89 LOG_ALWAYS_FATAL("malloc() error.");
90 }
91 selector->selectableFds = arrayCreate();
92
93 // Set up wake-up pipe.
94 if (pipe(selector->wakeupPipe) < 0) {
95 LOG_ALWAYS_FATAL("pipe() error: %s", strerror(errno));
96 }
97
98 LOGD("Wakeup fd: %d", selector->wakeupPipe[0]);
99
100 SelectableFd* wakeupFd = selectorAdd(selector, selector->wakeupPipe[0]);
101 if (wakeupFd == NULL) {
102 LOG_ALWAYS_FATAL("malloc() error.");
103 }
104 wakeupFd->onReadable = &eatWakeupData;
105
106 pthread_mutex_init(&selector->inSelectLock, NULL);
107
108 return selector;
109 }
110
111 SelectableFd* selectorAdd(Selector* selector, int fd) {
112 assert(selector != NULL);
113
114 SelectableFd* selectableFd = calloc(1, sizeof(SelectableFd));
115 if (selectableFd != NULL) {
116 selectableFd->selector = selector;
117 selectableFd->fd = fd;
118
119 arrayAdd(selector->selectableFds, selectableFd);
120 }
121
122 return selectableFd;
123 }
124
125 /**
126 * Adds an fd to the given set if the callback is non-null. Returns true
127 * if the fd was added.
128 */
129 static inline bool maybeAdd(SelectableFd* selectableFd,
130 void (*callback)(SelectableFd*), fd_set* fdSet) {
131 if (callback != NULL) {
132 FD_SET(selectableFd->fd, fdSet);
133 return true;
134 }
135 return false;
136 }
137
138 /**
139 * Removes stale file descriptors and initializes file descriptor sets.
140 */
141 static void prepareForSelect(Selector* selector) {
142 fd_set* exceptFds = &selector->exceptFds;
143 fd_set* readFds = &selector->readFds;
144 fd_set* writeFds = &selector->writeFds;
145
146 FD_ZERO(exceptFds);
147 FD_ZERO(readFds);
148 FD_ZERO(writeFds);
149
150 Array* selectableFds = selector->selectableFds;
151 int i = 0;
152 selector->maxFd = 0;
153 int size = arraySize(selectableFds);
154 while (i < size) {
155 SelectableFd* selectableFd = arrayGet(selectableFds, i);
156 if (selectableFd->remove) {
157 // This descriptor should be removed.
158 arrayRemove(selectableFds, i);
159 size--;
160 if (selectableFd->onRemove != NULL) {
161 selectableFd->onRemove(selectableFd);
162 }
163 free(selectableFd);
164 } else {
165 if (selectableFd->beforeSelect != NULL) {
166 selectableFd->beforeSelect(selectableFd);
167 }
168
169 bool inSet = false;
170 if (maybeAdd(selectableFd, selectableFd->onExcept, exceptFds)) {
171 LOGD("Selecting fd %d for writing...", selectableFd->fd);
172 inSet = true;
173 }
174 if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
175 LOGD("Selecting fd %d for reading...", selectableFd->fd);
176 inSet = true;
177 }
178 if (maybeAdd(selectableFd, selectableFd->onWritable, writeFds)) {
179 inSet = true;
180 }
181
182 if (inSet) {
183 // If the fd is in a set, check it against max.
184 int fd = selectableFd->fd;
185 if (fd > selector->maxFd) {
186 selector->maxFd = fd;
187 }
188 }
189
190 // Move to next descriptor.
191 i++;
192 }
193 }
194 }
195
196 /**
197 * Invokes a callback if the callback is non-null and the fd is in the given
198 * set.
199 */
200 static inline void maybeInvoke(SelectableFd* selectableFd,
201 void (*callback)(SelectableFd*), fd_set* fdSet) {
202 if (callback != NULL && !selectableFd->remove &&
203 FD_ISSET(selectableFd->fd, fdSet)) {
204 LOGD("Selected fd %d.", selectableFd->fd);
205 callback(selectableFd);
206 }
207 }
208
209 /**
210 * Notifies user if file descriptors are readable or writable, or if
211 * out-of-band data is present.
212 */
213 static void fireEvents(Selector* selector) {
214 Array* selectableFds = selector->selectableFds;
215 int size = arraySize(selectableFds);
216 int i;
217 for (i = 0; i < size; i++) {
218 SelectableFd* selectableFd = arrayGet(selectableFds, i);
219 maybeInvoke(selectableFd, selectableFd->onExcept,
220 &selector->exceptFds);
221 maybeInvoke(selectableFd, selectableFd->onReadable,
222 &selector->readFds);
223 maybeInvoke(selectableFd, selectableFd->onWritable,
224 &selector->writeFds);
225 }
226 }
227
228 void selectorLoop(Selector* selector) {
229 // Make sure we're not already looping.
230 if (selector->looping) {
231 LOG_ALWAYS_FATAL("Already looping.");
232 }
233 selector->looping = true;
234
235 while (true) {
236 setInSelect(selector, true);
237
238 prepareForSelect(selector);
239
240 LOGD("Entering select().");
241
242 // Select file descriptors.
243 int result = select(selector->maxFd + 1, &selector->readFds,
244 &selector->writeFds, &selector->exceptFds, NULL);
245
246 LOGD("Exiting select().");
247
248 setInSelect(selector, false);
249
250 if (result == -1) {
251 // Abort on everything except EINTR.
252 if (errno == EINTR) {
253 LOGI("select() interrupted.");
254 } else {
255 LOG_ALWAYS_FATAL("select() error: %s",
256 strerror(errno));
257 }
258 } else if (result > 0) {
259 fireEvents(selector);
260 }
261 }
262 }
+0
-70
libcutils/socket_inaddr_any_server.c less more
0 /* libs/cutils/socket_inaddr_any_server.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/sockets.h>
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stddef.h>
24
25 #ifndef HAVE_WINSOCK
26 #include <sys/socket.h>
27 #include <sys/select.h>
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #endif
31
32 #define LISTEN_BACKLOG 4
33
34 /* open listen() port on any interface */
35 int socket_inaddr_any_server(int port, int type)
36 {
37 struct sockaddr_in addr;
38 size_t alen;
39 int s, n;
40
41 memset(&addr, 0, sizeof(addr));
42 addr.sin_family = AF_INET;
43 addr.sin_port = htons(port);
44 addr.sin_addr.s_addr = htonl(INADDR_ANY);
45
46 s = socket(AF_INET, type, 0);
47 if(s < 0) return -1;
48
49 n = 1;
50 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
51
52 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
53 close(s);
54 return -1;
55 }
56
57 if (type == SOCK_STREAM) {
58 int ret;
59
60 ret = listen(s, LISTEN_BACKLOG);
61
62 if (ret < 0) {
63 close(s);
64 return -1;
65 }
66 }
67
68 return s;
69 }
+0
-39
libcutils/socket_local.h less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef __SOCKET_LOCAL_H
17 #define __SOCKET_LOCAL_H
18
19 #define FILESYSTEM_SOCKET_PREFIX "/tmp/"
20 #define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
21
22 /*
23 * Set up a given sockaddr_un, to have it refer to the given
24 * name in the given namespace. The namespace must be one
25 * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
26 * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
27 * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
28 * the pointed at sockaddr_un is filled in and the pointed at
29 * socklen_t is set to indicate the final length. This function
30 * will fail if the namespace is invalid (not one of the indicated
31 * constants) or if the name is too long.
32 *
33 * @return 0 on success or -1 on failure
34 */
35 int socket_make_sockaddr_un(const char *name, int namespaceId,
36 struct sockaddr_un *p_addr, socklen_t *alen);
37
38 #endif
+0
-167
libcutils/socket_local_client.c less more
0 /*
1 * Copyright (C) 2006 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cutils/sockets.h>
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <stddef.h>
23
24 #ifdef HAVE_WINSOCK
25
26 int socket_local_client(const char *name, int namespaceId, int type)
27 {
28 errno = ENOSYS;
29 return -1;
30 }
31
32 #else /* !HAVE_WINSOCK */
33
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <sys/select.h>
37 #include <sys/types.h>
38
39 #include "socket_local.h"
40
41 #define LISTEN_BACKLOG 4
42
43 /* Documented in header file. */
44 int socket_make_sockaddr_un(const char *name, int namespaceId,
45 struct sockaddr_un *p_addr, socklen_t *alen)
46 {
47 memset (p_addr, 0, sizeof (*p_addr));
48 size_t namelen;
49
50 switch (namespaceId) {
51 case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
52 #ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
53 namelen = strlen(name);
54
55 // Test with length +1 for the *initial* '\0'.
56 if ((namelen + 1) > sizeof(p_addr->sun_path)) {
57 goto error;
58 }
59
60 /*
61 * Note: The path in this case is *not* supposed to be
62 * '\0'-terminated. ("man 7 unix" for the gory details.)
63 */
64
65 p_addr->sun_path[0] = 0;
66 memcpy(p_addr->sun_path + 1, name, namelen);
67 #else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
68 /* this OS doesn't have the Linux abstract namespace */
69
70 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
71 /* unix_path_max appears to be missing on linux */
72 if (namelen > sizeof(*p_addr)
73 - offsetof(struct sockaddr_un, sun_path) - 1) {
74 goto error;
75 }
76
77 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
78 strcat(p_addr->sun_path, name);
79 #endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
80 break;
81
82 case ANDROID_SOCKET_NAMESPACE_RESERVED:
83 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
84 /* unix_path_max appears to be missing on linux */
85 if (namelen > sizeof(*p_addr)
86 - offsetof(struct sockaddr_un, sun_path) - 1) {
87 goto error;
88 }
89
90 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
91 strcat(p_addr->sun_path, name);
92 break;
93
94 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
95 namelen = strlen(name);
96 /* unix_path_max appears to be missing on linux */
97 if (namelen > sizeof(*p_addr)
98 - offsetof(struct sockaddr_un, sun_path) - 1) {
99 goto error;
100 }
101
102 strcpy(p_addr->sun_path, name);
103 break;
104 default:
105 // invalid namespace id
106 return -1;
107 }
108
109 p_addr->sun_family = AF_LOCAL;
110 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
111 return 0;
112 error:
113 return -1;
114 }
115
116 /**
117 * connect to peer named "name" on fd
118 * returns same fd or -1 on error.
119 * fd is not closed on error. that's your job.
120 *
121 * Used by AndroidSocketImpl
122 */
123 int socket_local_client_connect(int fd, const char *name, int namespaceId,
124 int type)
125 {
126 struct sockaddr_un addr;
127 socklen_t alen;
128 size_t namelen;
129 int err;
130
131 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
132
133 if (err < 0) {
134 goto error;
135 }
136
137 if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
138 goto error;
139 }
140
141 return fd;
142
143 error:
144 return -1;
145 }
146
147 /**
148 * connect to peer named "name"
149 * returns fd or -1 on error
150 */
151 int socket_local_client(const char *name, int namespaceId, int type)
152 {
153 int s;
154
155 s = socket(AF_LOCAL, type, 0);
156 if(s < 0) return -1;
157
158 if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
159 close(s);
160 return -1;
161 }
162
163 return s;
164 }
165
166 #endif /* !HAVE_WINSOCK */
+0
-124
libcutils/socket_local_server.c less more
0 /* libs/cutils/socket_local_server.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/sockets.h>
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stddef.h>
24
25 #ifdef HAVE_WINSOCK
26
27 int socket_local_server(const char *name, int namespaceId, int type)
28 {
29 errno = ENOSYS;
30 return -1;
31 }
32
33 #else /* !HAVE_WINSOCK */
34
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 #include <sys/select.h>
38 #include <sys/types.h>
39 #include <netinet/in.h>
40
41 #include "socket_local.h"
42
43 #define LISTEN_BACKLOG 4
44
45
46 /**
47 * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
48 * returns 's' on success, -1 on fail
49 *
50 * Does not call listen()
51 */
52 int socket_local_server_bind(int s, const char *name, int namespaceId)
53 {
54 struct sockaddr_un addr;
55 socklen_t alen;
56 int n;
57 int err;
58
59 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
60
61 if (err < 0) {
62 return -1;
63 }
64
65 /* basically: if this is a filesystem path, unlink first */
66 #ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
67 if (1) {
68 #else
69 if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED
70 || namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
71 #endif
72 /*ignore ENOENT*/
73 unlink(addr.sun_path);
74 }
75
76 n = 1;
77 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
78
79 if(bind(s, (struct sockaddr *) &addr, alen) < 0) {
80 return -1;
81 }
82
83 return s;
84
85 }
86
87
88 /** Open a server-side UNIX domain datagram socket in the Linux non-filesystem
89 * namespace
90 *
91 * Returns fd on success, -1 on fail
92 */
93
94 int socket_local_server(const char *name, int namespace, int type)
95 {
96 int err;
97 int s;
98
99 s = socket(AF_LOCAL, type, 0);
100 if (s < 0) return -1;
101
102 err = socket_local_server_bind(s, name, namespace);
103
104 if (err < 0) {
105 close(s);
106 return -1;
107 }
108
109 if (type == SOCK_STREAM) {
110 int ret;
111
112 ret = listen(s, LISTEN_BACKLOG);
113
114 if (ret < 0) {
115 close(s);
116 return -1;
117 }
118 }
119
120 return s;
121 }
122
123 #endif /* !HAVE_WINSOCK */
+0
-59
libcutils/socket_loopback_client.c less more
0 /* libs/cutils/socket_loopback_client.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/sockets.h>
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stddef.h>
24
25 #ifndef HAVE_WINSOCK
26 #include <sys/socket.h>
27 #include <sys/select.h>
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #endif
31
32 /* Connect to port on the loopback IP interface. type is
33 * SOCK_STREAM or SOCK_DGRAM.
34 * return is a file descriptor or -1 on error
35 */
36 int socket_loopback_client(int port, int type)
37 {
38 struct sockaddr_in addr;
39 socklen_t alen;
40 int s;
41
42 memset(&addr, 0, sizeof(addr));
43 addr.sin_family = AF_INET;
44 addr.sin_port = htons(port);
45 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
46
47 s = socket(AF_INET, type, 0);
48 if(s < 0) return -1;
49
50 if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
51 close(s);
52 return -1;
53 }
54
55 return s;
56
57 }
58
+0
-71
libcutils/socket_loopback_server.c less more
0 /* libs/cutils/socket_loopback_server.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/sockets.h>
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stddef.h>
24
25 #define LISTEN_BACKLOG 4
26
27 #ifndef HAVE_WINSOCK
28 #include <sys/socket.h>
29 #include <sys/select.h>
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #endif
33
34 /* open listen() port on loopback interface */
35 int socket_loopback_server(int port, int type)
36 {
37 struct sockaddr_in addr;
38 size_t alen;
39 int s, n;
40
41 memset(&addr, 0, sizeof(addr));
42 addr.sin_family = AF_INET;
43 addr.sin_port = htons(port);
44 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
45
46 s = socket(AF_INET, type, 0);
47 if(s < 0) return -1;
48
49 n = 1;
50 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
51
52 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
53 close(s);
54 return -1;
55 }
56
57 if (type == SOCK_STREAM) {
58 int ret;
59
60 ret = listen(s, LISTEN_BACKLOG);
61
62 if (ret < 0) {
63 close(s);
64 return -1;
65 }
66 }
67
68 return s;
69 }
70
+0
-65
libcutils/socket_network_client.c less more
0 /* libs/cutils/socket_network_client.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/sockets.h>
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stddef.h>
24
25 #ifndef HAVE_WINSOCK
26 #include <sys/socket.h>
27 #include <sys/select.h>
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #include <netdb.h>
31 #endif
32
33
34 /* Connect to port on the IP interface. type is
35 * SOCK_STREAM or SOCK_DGRAM.
36 * return is a file descriptor or -1 on error
37 */
38 int socket_network_client(const char *host, int port, int type)
39 {
40 struct hostent *hp;
41 struct sockaddr_in addr;
42 socklen_t alen;
43 int s;
44
45 hp = gethostbyname(host);
46 if(hp == 0) return -1;
47
48 memset(&addr, 0, sizeof(addr));
49 addr.sin_family = hp->h_addrtype;
50 addr.sin_port = htons(port);
51 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
52
53 s = socket(hp->h_addrtype, type, 0);
54 if(s < 0) return -1;
55
56 if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
57 close(s);
58 return -1;
59 }
60
61 return s;
62
63 }
64
+0
-104
libcutils/strdup16to8.c less more
0 /* libs/cutils/strdup16to8.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/jstring.h>
18 #include <assert.h>
19 #include <stdlib.h>
20
21
22 /**
23 * Given a UTF-16 string, compute the length of the corresponding UTF-8
24 * string in bytes.
25 */
26 extern size_t strnlen16to8(const char16_t* utf16Str, size_t len)
27 {
28 size_t utf8Len = 0;
29
30 while (len--) {
31 unsigned int uic = *utf16Str++;
32
33 if (uic > 0x07ff)
34 utf8Len += 3;
35 else if (uic > 0x7f || uic == 0)
36 utf8Len += 2;
37 else
38 utf8Len++;
39 }
40 return utf8Len;
41 }
42
43
44 /**
45 * Convert a Java-Style UTF-16 string + length to a JNI-Style UTF-8 string.
46 *
47 * This basically means: embedded \0's in the UTF-16 string are encoded
48 * as "0xc0 0x80"
49 *
50 * Make sure you allocate "utf8Str" with the result of strlen16to8() + 1,
51 * not just "len".
52 *
53 * Please note, a terminated \0 is always added, so your result will always
54 * be "strlen16to8() + 1" bytes long.
55 */
56 extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len)
57 {
58 char* utf8cur = utf8Str;
59
60 while (len--) {
61 unsigned int uic = *utf16Str++;
62
63 if (uic > 0x07ff) {
64 *utf8cur++ = (uic >> 12) | 0xe0;
65 *utf8cur++ = ((uic >> 6) & 0x3f) | 0x80;
66 *utf8cur++ = (uic & 0x3f) | 0x80;
67 } else if (uic > 0x7f || uic == 0) {
68 *utf8cur++ = (uic >> 6) | 0xc0;
69 *utf8cur++ = (uic & 0x3f) | 0x80;
70 } else {
71 *utf8cur++ = uic;
72
73 if (uic == 0) {
74 break;
75 }
76 }
77 }
78
79 *utf8cur = '\0';
80
81 return utf8Str;
82 }
83
84 /**
85 * Convert a UTF-16 string to UTF-8.
86 *
87 * Make sure you allocate "dest" with the result of strblen16to8(),
88 * not just "strlen16()".
89 */
90 char * strndup16to8 (const char16_t* s, size_t n)
91 {
92 char *ret;
93
94 if (s == NULL) {
95 return NULL;
96 }
97
98 ret = malloc(strnlen16to8(s, n) + 1);
99
100 strncpy16to8 (ret, s, n);
101
102 return ret;
103 }
+0
-209
libcutils/strdup8to16.c less more
0 /* libs/cutils/strdup8to16.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/jstring.h>
18 #include <assert.h>
19 #include <stdlib.h>
20
21 /* See http://www.unicode.org/reports/tr22/ for discussion
22 * on invalid sequences
23 */
24
25 #define UTF16_REPLACEMENT_CHAR 0xfffd
26
27 /* Clever trick from Dianne that returns 1-4 depending on leading bit sequence*/
28 #define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1)
29
30 /* note: macro expands to multiple lines */
31 #define UTF8_SHIFT_AND_MASK(unicode, byte) \
32 (unicode)<<=6; (unicode) |= (0x3f & (byte));
33
34 #define UNICODE_UPPER_LIMIT 0x10fffd
35
36 /**
37 * out_len is an out parameter (which may not be null) containing the
38 * length of the UTF-16 string (which may contain embedded \0's)
39 */
40
41 extern char16_t * strdup8to16 (const char* s, size_t *out_len)
42 {
43 char16_t *ret;
44 size_t len;
45
46 if (s == NULL) return NULL;
47
48 len = strlen8to16(s);
49
50 // no plus-one here. UTF-16 strings are not null terminated
51 ret = (char16_t *) malloc (sizeof(char16_t) * len);
52
53 return strcpy8to16 (ret, s, out_len);
54 }
55
56 /**
57 * Like "strlen", but for strings encoded with Java's modified UTF-8.
58 *
59 * The value returned is the number of UTF-16 characters required
60 * to represent this string.
61 */
62 extern size_t strlen8to16 (const char* utf8Str)
63 {
64 size_t len = 0;
65 int ic;
66 int expected = 0;
67
68 while ((ic = *utf8Str++) != '\0') {
69 /* bytes that start 0? or 11 are lead bytes and count as characters.*/
70 /* bytes that start 10 are extention bytes and are not counted */
71
72 if ((ic & 0xc0) == 0x80) {
73 /* count the 0x80 extention bytes. if we have more than
74 * expected, then start counting them because strcpy8to16
75 * will insert UTF16_REPLACEMENT_CHAR's
76 */
77 expected--;
78 if (expected < 0) {
79 len++;
80 }
81 } else {
82 len++;
83 expected = UTF8_SEQ_LENGTH(ic) - 1;
84
85 /* this will result in a surrogate pair */
86 if (expected == 3) {
87 len++;
88 }
89 }
90 }
91
92 return len;
93 }
94
95
96
97 /*
98 * Retrieve the next UTF-32 character from a UTF-8 string.
99 *
100 * Stops at inner \0's
101 *
102 * Returns UTF16_REPLACEMENT_CHAR if an invalid sequence is encountered
103 *
104 * Advances "*pUtf8Ptr" to the start of the next character.
105 */
106 static inline uint32_t getUtf32FromUtf8(const char** pUtf8Ptr)
107 {
108 uint32_t ret;
109 int seq_len;
110 int i;
111
112 /* Mask for leader byte for lengths 1, 2, 3, and 4 respectively*/
113 static const char leaderMask[4] = {0xff, 0x1f, 0x0f, 0x07};
114
115 /* Bytes that start with bits "10" are not leading characters. */
116 if (((**pUtf8Ptr) & 0xc0) == 0x80) {
117 (*pUtf8Ptr)++;
118 return UTF16_REPLACEMENT_CHAR;
119 }
120
121 /* note we tolerate invalid leader 11111xxx here */
122 seq_len = UTF8_SEQ_LENGTH(**pUtf8Ptr);
123
124 ret = (**pUtf8Ptr) & leaderMask [seq_len - 1];
125
126 if (**pUtf8Ptr == '\0') return ret;
127
128 (*pUtf8Ptr)++;
129 for (i = 1; i < seq_len ; i++, (*pUtf8Ptr)++) {
130 if ((**pUtf8Ptr) == '\0') return UTF16_REPLACEMENT_CHAR;
131 if (((**pUtf8Ptr) & 0xc0) != 0x80) return UTF16_REPLACEMENT_CHAR;
132
133 UTF8_SHIFT_AND_MASK(ret, **pUtf8Ptr);
134 }
135
136 return ret;
137 }
138
139
140 /**
141 * out_len is an out parameter (which may not be null) containing the
142 * length of the UTF-16 string (which may contain embedded \0's)
143 */
144
145 extern char16_t * strcpy8to16 (char16_t *utf16Str, const char*utf8Str,
146 size_t *out_len)
147 {
148 char16_t *dest = utf16Str;
149
150 while (*utf8Str != '\0') {
151 uint32_t ret;
152
153 ret = getUtf32FromUtf8(&utf8Str);
154
155 if (ret <= 0xffff) {
156 *dest++ = (char16_t) ret;
157 } else if (ret <= UNICODE_UPPER_LIMIT) {
158 /* Create surrogate pairs */
159 /* See http://en.wikipedia.org/wiki/UTF-16/UCS-2#Method_for_code_points_in_Plane_1.2C_Plane_2 */
160
161 *dest++ = 0xd800 | ((ret - 0x10000) >> 10);
162 *dest++ = 0xdc00 | ((ret - 0x10000) & 0x3ff);
163 } else {
164 *dest++ = UTF16_REPLACEMENT_CHAR;
165 }
166 }
167
168 *out_len = dest - utf16Str;
169
170 return utf16Str;
171 }
172
173 /**
174 * length is the number of characters in the UTF-8 string.
175 * out_len is an out parameter (which may not be null) containing the
176 * length of the UTF-16 string (which may contain embedded \0's)
177 */
178
179 extern char16_t * strcpylen8to16 (char16_t *utf16Str, const char*utf8Str,
180 int length, size_t *out_len)
181 {
182 /* TODO: Share more of this code with the method above. Only 2 lines changed. */
183
184 char16_t *dest = utf16Str;
185
186 const char *end = utf8Str + length; /* This line */
187 while (utf8Str < end) { /* and this line changed. */
188 uint32_t ret;
189
190 ret = getUtf32FromUtf8(&utf8Str);
191
192 if (ret <= 0xffff) {
193 *dest++ = (char16_t) ret;
194 } else if (ret <= UNICODE_UPPER_LIMIT) {
195 /* Create surrogate pairs */
196 /* See http://en.wikipedia.org/wiki/UTF-16/UCS-2#Method_for_code_points_in_Plane_1.2C_Plane_2 */
197
198 *dest++ = 0xd800 | ((ret - 0x10000) >> 10);
199 *dest++ = 0xdc00 | ((ret - 0x10000) & 0x3ff);
200 } else {
201 *dest++ = UTF16_REPLACEMENT_CHAR;
202 }
203 }
204
205 *out_len = dest - utf16Str;
206
207 return utf16Str;
208 }
+0
-84
libcutils/threads.c less more
0 /* libs/cutils/threads.c
1 **
2 ** Copyright (C) 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16 #include <cutils/threads.h>
17
18 #ifdef HAVE_PTHREADS
19 void* thread_store_get( thread_store_t* store )
20 {
21 const pthread_key_t k = store->tls;
22
23 if (!store->has_tls)
24 return NULL;
25
26 return pthread_getspecific( store->tls );
27 }
28
29 extern void thread_store_set( thread_store_t* store,
30 void* value,
31 thread_store_destruct_t destroy)
32 {
33 pthread_mutex_lock( &store->lock );
34 if (!store->has_tls) {
35 if (pthread_key_create( &store->tls, destroy) != 0) {
36 pthread_mutex_unlock(&store->lock);
37 return;
38 }
39 store->has_tls = 1;
40 }
41 pthread_mutex_unlock( &store->lock );
42
43 pthread_setspecific( store->tls, value );
44 }
45
46 #endif
47
48 #ifdef HAVE_WIN32_THREADS
49 void* thread_store_get( thread_store_t* store )
50 {
51 if (!store->has_tls)
52 return NULL;
53
54 return (void*) TlsGetValue( store->tls );
55 }
56
57 void thread_store_set( thread_store_t* store,
58 void* value,
59 thread_store_destruct_t destroy )
60 {
61 /* XXX: can't use destructor on thread exit */
62 if (!store->lock_init) {
63 store->lock_init = -1;
64 InitializeCriticalSection( &store->lock );
65 store->lock_init = -2;
66 } else while (store->lock_init != -2) {
67 Sleep(10); /* 10ms */
68 }
69
70 EnterCriticalSection( &store->lock );
71 if (!store->has_tls) {
72 store->tls = TlsAlloc();
73 if (store->tls == TLS_OUT_OF_INDEXES) {
74 LeaveCriticalSection( &store->lock );
75 return;
76 }
77 store->has_tls = 1;
78 }
79 LeaveCriticalSection( &store->lock );
80
81 TlsSetValue( store->tls, value );
82 }
83 #endif
+0
-180
libcutils/tzfile.h less more
0 #ifndef TZFILE_H
1
2 #define TZFILE_H
3
4 /*
5 ** This file is in the public domain, so clarified as of
6 ** 1996-06-05 by Arthur David Olson.
7 */
8
9 /*
10 ** This header is for use ONLY with the time conversion code.
11 ** There is no guarantee that it will remain unchanged,
12 ** or that it will remain at all.
13 ** Do NOT copy it to any system include directory.
14 ** Thank you!
15 */
16
17 /*
18 ** ID
19 */
20
21 #ifndef lint
22 #ifndef NOID
23 static char tzfilehid[] = "@(#)tzfile.h 8.1";
24 #endif /* !defined NOID */
25 #endif /* !defined lint */
26
27 /*
28 ** Information about time zone files.
29 */
30
31 #ifndef TZDIR
32 #define TZDIR "/usr/share/zoneinfo" /* "/android/usr/share/zoneinfo" */ /* Time zone object file directory */
33 #endif /* !defined TZDIR */
34
35 #ifndef TZDEFAULT
36 #define TZDEFAULT "localtime"
37 #endif /* !defined TZDEFAULT */
38
39 #ifndef TZDEFRULES
40 #define TZDEFRULES "posixrules"
41 #endif /* !defined TZDEFRULES */
42
43 /*
44 ** Each file begins with. . .
45 */
46
47 #define TZ_MAGIC "TZif"
48
49 struct tzhead {
50 char tzh_magic[4]; /* TZ_MAGIC */
51 char tzh_version[1]; /* '\0' or '2' as of 2005 */
52 char tzh_reserved[15]; /* reserved--must be zero */
53 char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
54 char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
55 char tzh_leapcnt[4]; /* coded number of leap seconds */
56 char tzh_timecnt[4]; /* coded number of transition times */
57 char tzh_typecnt[4]; /* coded number of local time types */
58 char tzh_charcnt[4]; /* coded number of abbr. chars */
59 };
60
61 /*
62 ** . . .followed by. . .
63 **
64 ** tzh_timecnt (char [4])s coded transition times a la time(2)
65 ** tzh_timecnt (unsigned char)s types of local time starting at above
66 ** tzh_typecnt repetitions of
67 ** one (char [4]) coded UTC offset in seconds
68 ** one (unsigned char) used to set tm_isdst
69 ** one (unsigned char) that's an abbreviation list index
70 ** tzh_charcnt (char)s '\0'-terminated zone abbreviations
71 ** tzh_leapcnt repetitions of
72 ** one (char [4]) coded leap second transition times
73 ** one (char [4]) total correction after above
74 ** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
75 ** time is standard time, if FALSE,
76 ** transition time is wall clock time
77 ** if absent, transition times are
78 ** assumed to be wall clock time
79 ** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
80 ** time is UTC, if FALSE,
81 ** transition time is local time
82 ** if absent, transition times are
83 ** assumed to be local time
84 */
85
86 /*
87 ** If tzh_version is '2' or greater, the above is followed by a second instance
88 ** of tzhead and a second instance of the data in which each coded transition
89 ** time uses 8 rather than 4 chars,
90 ** then a POSIX-TZ-environment-variable-style string for use in handling
91 ** instants after the last transition time stored in the file
92 ** (with nothing between the newlines if there is no POSIX representation for
93 ** such instants).
94 */
95
96 /*
97 ** In the current implementation, "tzset()" refuses to deal with files that
98 ** exceed any of the limits below.
99 */
100
101 #ifndef TZ_MAX_TIMES
102 #define TZ_MAX_TIMES 1200
103 #endif /* !defined TZ_MAX_TIMES */
104
105 #ifndef TZ_MAX_TYPES
106 #ifndef NOSOLAR
107 #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
108 #endif /* !defined NOSOLAR */
109 #ifdef NOSOLAR
110 /*
111 ** Must be at least 14 for Europe/Riga as of Jan 12 1995,
112 ** as noted by Earl Chew.
113 */
114 #define TZ_MAX_TYPES 20 /* Maximum number of local time types */
115 #endif /* !defined NOSOLAR */
116 #endif /* !defined TZ_MAX_TYPES */
117
118 #ifndef TZ_MAX_CHARS
119 #define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
120 /* (limited by what unsigned chars can hold) */
121 #endif /* !defined TZ_MAX_CHARS */
122
123 #ifndef TZ_MAX_LEAPS
124 #define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
125 #endif /* !defined TZ_MAX_LEAPS */
126
127 #define SECSPERMIN 60
128 #define MINSPERHOUR 60
129 #define HOURSPERDAY 24
130 #define DAYSPERWEEK 7
131 #define DAYSPERNYEAR 365
132 #define DAYSPERLYEAR 366
133 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
134 #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
135 #define MONSPERYEAR 12
136
137 #define TM_SUNDAY 0
138 #define TM_MONDAY 1
139 #define TM_TUESDAY 2
140 #define TM_WEDNESDAY 3
141 #define TM_THURSDAY 4
142 #define TM_FRIDAY 5
143 #define TM_SATURDAY 6
144
145 #define TM_JANUARY 0
146 #define TM_FEBRUARY 1
147 #define TM_MARCH 2
148 #define TM_APRIL 3
149 #define TM_MAY 4
150 #define TM_JUNE 5
151 #define TM_JULY 6
152 #define TM_AUGUST 7
153 #define TM_SEPTEMBER 8
154 #define TM_OCTOBER 9
155 #define TM_NOVEMBER 10
156 #define TM_DECEMBER 11
157
158 #define TM_YEAR_BASE 1900
159
160 #define EPOCH_YEAR 1970
161 #define EPOCH_WDAY TM_THURSDAY
162
163 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
164
165 /*
166 ** Since everything in isleap is modulo 400 (or a factor of 400), we know that
167 ** isleap(y) == isleap(y % 400)
168 ** and so
169 ** isleap(a + b) == isleap((a + b) % 400)
170 ** or
171 ** isleap(a + b) == isleap(a % 400 + b % 400)
172 ** This is true even if % means modulo rather than Fortran remainder
173 ** (which is allowed by C89 but not C99).
174 ** We use this to avoid addition overflow problems.
175 */
176
177 #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
178
179 #endif /* !defined TZFILE_H */
+0
-834
libcutils/tzstrftime.c less more
0 #ifndef lint
1 #ifndef NOID
2 static char elsieid[] = "@(#)strftime.c 8.1";
3 /*
4 ** Based on the UCB version with the ID appearing below.
5 ** This is ANSIish only when "multibyte character == plain character".
6 */
7 #endif /* !defined NOID */
8 #endif /* !defined lint */
9
10 #include <time.h>
11 #include <tzfile.h>
12 #include <limits.h>
13 #include <cutils/tztime.h>
14
15 /*
16 ** Copyright (c) 1989 The Regents of the University of California.
17 ** All rights reserved.
18 **
19 ** Redistribution and use in source and binary forms are permitted
20 ** provided that the above copyright notice and this paragraph are
21 ** duplicated in all such forms and that any documentation,
22 ** advertising materials, and other materials related to such
23 ** distribution and use acknowledge that the software was developed
24 ** by the University of California, Berkeley. The name of the
25 ** University may not be used to endorse or promote products derived
26 ** from this software without specific prior written permission.
27 ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
28 ** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
29 ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 */
31
32 #ifndef LIBC_SCCS
33 #ifndef lint
34 static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
35 #endif /* !defined lint */
36 #endif /* !defined LIBC_SCCS */
37
38 #include <ctype.h>
39
40 #define P(x) x
41
42 static char * _add P((const char *, char *, const char *, int));
43 static char * _conv P((int, const char *, char *, const char *));
44 static char * _fmt P((const char *, const struct tm *, char *, const char *,
45 int *, const struct strftime_locale *Locale));
46 static char * _yconv P((int, int, int, int, char *, const char *, int));
47 static char * getformat P((int, char *, char *, char *, char *));
48
49 extern char * tzname[];
50
51
52
53
54
55 /* from private.h */
56
57 #ifndef TYPE_BIT
58 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
59 #endif /* !defined TYPE_BIT */
60
61 #ifndef TYPE_SIGNED
62 #define TYPE_SIGNED(type) (((type) -1) < 0)
63 #endif /* !defined TYPE_SIGNED */
64
65 #ifndef INT_STRLEN_MAXIMUM
66 /*
67 * ** 302 / 1000 is log10(2.0) rounded up.
68 * ** Subtract one for the sign bit if the type is signed;
69 * ** add one for integer division truncation;
70 * ** add one more for a minus sign if the type is signed.
71 * */
72 #define INT_STRLEN_MAXIMUM(type) \
73 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
74 1 + TYPE_SIGNED(type))
75 #endif /* !defined INT_STRLEN_MAXIMUM */
76
77 /* end of part from private.h */
78
79
80
81
82 #ifndef YEAR_2000_NAME
83 #define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
84 #endif /* !defined YEAR_2000_NAME */
85
86 #define IN_NONE 0
87 #define IN_SOME 1
88 #define IN_THIS 2
89 #define IN_ALL 3
90
91 #define FORCE_LOWER_CASE 0x100
92
93 size_t
94 strftime_tz(s, maxsize, format, t, Locale)
95 char * const s;
96 const size_t maxsize;
97 const char * const format;
98 const struct tm * const t;
99 const struct strftime_locale *Locale;
100 {
101 char * p;
102 int warn;
103
104 warn = IN_NONE;
105 p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
106 #if 0
107 if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
108 (void) fprintf(stderr, "\n");
109 if (format == NULL)
110 (void) fprintf(stderr, "NULL strftime format ");
111 else (void) fprintf(stderr, "strftime format \"%s\" ",
112 format);
113 (void) fprintf(stderr, "yields only two digits of years in ");
114 if (warn == IN_SOME)
115 (void) fprintf(stderr, "some locales");
116 else if (warn == IN_THIS)
117 (void) fprintf(stderr, "the current locale");
118 else (void) fprintf(stderr, "all locales");
119 (void) fprintf(stderr, "\n");
120 }
121 #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
122 if (p == s + maxsize)
123 return 0;
124 *p = '\0';
125 return p - s;
126 }
127
128 static char *getformat(int modifier, char *normal, char *underscore,
129 char *dash, char *zero) {
130 switch (modifier) {
131 case '_':
132 return underscore;
133
134 case '-':
135 return dash;
136
137 case '0':
138 return zero;
139 }
140
141 return normal;
142 }
143
144 static char *
145 _fmt(format, t, pt, ptlim, warnp, Locale)
146 const char * format;
147 const struct tm * const t;
148 char * pt;
149 const char * const ptlim;
150 int * warnp;
151 const struct strftime_locale *Locale;
152 {
153 for ( ; *format; ++format) {
154 if (*format == '%') {
155 int modifier = 0;
156 label:
157 switch (*++format) {
158 case '\0':
159 --format;
160 break;
161 case 'A':
162 pt = _add((t->tm_wday < 0 ||
163 t->tm_wday >= DAYSPERWEEK) ?
164 "?" : Locale->weekday[t->tm_wday],
165 pt, ptlim, modifier);
166 continue;
167 case 'a':
168 pt = _add((t->tm_wday < 0 ||
169 t->tm_wday >= DAYSPERWEEK) ?
170 "?" : Locale->wday[t->tm_wday],
171 pt, ptlim, modifier);
172 continue;
173 case 'B':
174 pt = _add((t->tm_mon < 0 ||
175 t->tm_mon >= MONSPERYEAR) ?
176 "?" : Locale->month[t->tm_mon],
177 pt, ptlim, modifier);
178 continue;
179 case 'b':
180 case 'h':
181 pt = _add((t->tm_mon < 0 ||
182 t->tm_mon >= MONSPERYEAR) ?
183 "?" : Locale->mon[t->tm_mon],
184 pt, ptlim, modifier);
185 continue;
186 case 'C':
187 /*
188 ** %C used to do a...
189 ** _fmt("%a %b %e %X %Y", t);
190 ** ...whereas now POSIX 1003.2 calls for
191 ** something completely different.
192 ** (ado, 1993-05-24)
193 */
194 pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
195 pt, ptlim, modifier);
196 continue;
197 case 'c':
198 {
199 int warn2 = IN_SOME;
200
201 pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
202 if (warn2 == IN_ALL)
203 warn2 = IN_THIS;
204 if (warn2 > *warnp)
205 *warnp = warn2;
206 }
207 continue;
208 case 'D':
209 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
210 continue;
211 case 'd':
212 pt = _conv(t->tm_mday,
213 getformat(modifier, "%02d",
214 "%2d", "%d", "%02d"),
215 pt, ptlim);
216 continue;
217 case 'E':
218 case 'O':
219 /*
220 ** C99 locale modifiers.
221 ** The sequences
222 ** %Ec %EC %Ex %EX %Ey %EY
223 ** %Od %oe %OH %OI %Om %OM
224 ** %OS %Ou %OU %OV %Ow %OW %Oy
225 ** are supposed to provide alternate
226 ** representations.
227 */
228 goto label;
229 case '_':
230 case '-':
231 case '0':
232 case '^':
233 case '#':
234 modifier = *format;
235 goto label;
236 case 'e':
237 pt = _conv(t->tm_mday,
238 getformat(modifier, "%2d",
239 "%2d", "%d", "%02d"),
240 pt, ptlim);
241 continue;
242 case 'F':
243 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
244 continue;
245 case 'H':
246 pt = _conv(t->tm_hour,
247 getformat(modifier, "%02d",
248 "%2d", "%d", "%02d"),
249 pt, ptlim);
250 continue;
251 case 'I':
252 pt = _conv((t->tm_hour % 12) ?
253 (t->tm_hour % 12) : 12,
254 getformat(modifier, "%02d",
255 "%2d", "%d", "%02d"),
256 pt, ptlim);
257 continue;
258 case 'j':
259 pt = _conv(t->tm_yday + 1,
260 getformat(modifier, "%03d", "%3d", "%d", "%03d"),
261 pt, ptlim);
262 continue;
263 case 'k':
264 /*
265 ** This used to be...
266 ** _conv(t->tm_hour % 12 ?
267 ** t->tm_hour % 12 : 12, 2, ' ');
268 ** ...and has been changed to the below to
269 ** match SunOS 4.1.1 and Arnold Robbins'
270 ** strftime version 3.0. That is, "%k" and
271 ** "%l" have been swapped.
272 ** (ado, 1993-05-24)
273 */
274 pt = _conv(t->tm_hour,
275 getformat(modifier, "%2d",
276 "%2d", "%d", "%02d"),
277 pt, ptlim);
278 continue;
279 #ifdef KITCHEN_SINK
280 case 'K':
281 /*
282 ** After all this time, still unclaimed!
283 */
284 pt = _add("kitchen sink", pt, ptlim, modifier);
285 continue;
286 #endif /* defined KITCHEN_SINK */
287 case 'l':
288 /*
289 ** This used to be...
290 ** _conv(t->tm_hour, 2, ' ');
291 ** ...and has been changed to the below to
292 ** match SunOS 4.1.1 and Arnold Robbin's
293 ** strftime version 3.0. That is, "%k" and
294 ** "%l" have been swapped.
295 ** (ado, 1993-05-24)
296 */
297 pt = _conv((t->tm_hour % 12) ?
298 (t->tm_hour % 12) : 12,
299 getformat(modifier, "%2d",
300 "%2d", "%d", "%02d"),
301 pt, ptlim);
302 continue;
303 case 'M':
304 pt = _conv(t->tm_min,
305 getformat(modifier, "%02d",
306 "%2d", "%d", "%02d"),
307 pt, ptlim);
308 continue;
309 case 'm':
310 pt = _conv(t->tm_mon + 1,
311 getformat(modifier, "%02d",
312 "%2d", "%d", "%02d"),
313 pt, ptlim);
314 continue;
315 case 'n':
316 pt = _add("\n", pt, ptlim, modifier);
317 continue;
318 case 'p':
319 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
320 Locale->pm :
321 Locale->am,
322 pt, ptlim, modifier);
323 continue;
324 case 'P':
325 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
326 Locale->pm :
327 Locale->am,
328 pt, ptlim, FORCE_LOWER_CASE);
329 continue;
330 case 'R':
331 pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
332 continue;
333 case 'r':
334 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
335 continue;
336 case 'S':
337 pt = _conv(t->tm_sec,
338 getformat(modifier, "%02d",
339 "%2d", "%d", "%02d"),
340 pt, ptlim);
341 continue;
342 case 's':
343 {
344 struct tm tm;
345 char buf[INT_STRLEN_MAXIMUM(
346 time_t) + 1];
347 time_t mkt;
348
349 tm = *t;
350 mkt = mktime(&tm);
351 if (TYPE_SIGNED(time_t))
352 (void) sprintf(buf, "%ld",
353 (long) mkt);
354 else (void) sprintf(buf, "%lu",
355 (unsigned long) mkt);
356 pt = _add(buf, pt, ptlim, modifier);
357 }
358 continue;
359 case 'T':
360 pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
361 continue;
362 case 't':
363 pt = _add("\t", pt, ptlim, modifier);
364 continue;
365 case 'U':
366 pt = _conv((t->tm_yday + DAYSPERWEEK -
367 t->tm_wday) / DAYSPERWEEK,
368 getformat(modifier, "%02d",
369 "%2d", "%d", "%02d"),
370 pt, ptlim);
371 continue;
372 case 'u':
373 /*
374 ** From Arnold Robbins' strftime version 3.0:
375 ** "ISO 8601: Weekday as a decimal number
376 ** [1 (Monday) - 7]"
377 ** (ado, 1993-05-24)
378 */
379 pt = _conv((t->tm_wday == 0) ?
380 DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
381 continue;
382 case 'V': /* ISO 8601 week number */
383 case 'G': /* ISO 8601 year (four digits) */
384 case 'g': /* ISO 8601 year (two digits) */
385 /*
386 ** From Arnold Robbins' strftime version 3.0: "the week number of the
387 ** year (the first Monday as the first day of week 1) as a decimal number
388 ** (01-53)."
389 ** (ado, 1993-05-24)
390 **
391 ** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
392 ** "Week 01 of a year is per definition the first week which has the
393 ** Thursday in this year, which is equivalent to the week which contains
394 ** the fourth day of January. In other words, the first week of a new year
395 ** is the week which has the majority of its days in the new year. Week 01
396 ** might also contain days from the previous year and the week before week
397 ** 01 of a year is the last week (52 or 53) of the previous year even if
398 ** it contains days from the new year. A week starts with Monday (day 1)
399 ** and ends with Sunday (day 7). For example, the first week of the year
400 ** 1997 lasts from 1996-12-30 to 1997-01-05..."
401 ** (ado, 1996-01-02)
402 */
403 {
404 int year;
405 int base;
406 int yday;
407 int wday;
408 int w;
409
410 year = t->tm_year;
411 base = TM_YEAR_BASE;
412 yday = t->tm_yday;
413 wday = t->tm_wday;
414 for ( ; ; ) {
415 int len;
416 int bot;
417 int top;
418
419 len = isleap_sum(year, base) ?
420 DAYSPERLYEAR :
421 DAYSPERNYEAR;
422 /*
423 ** What yday (-3 ... 3) does
424 ** the ISO year begin on?
425 */
426 bot = ((yday + 11 - wday) %
427 DAYSPERWEEK) - 3;
428 /*
429 ** What yday does the NEXT
430 ** ISO year begin on?
431 */
432 top = bot -
433 (len % DAYSPERWEEK);
434 if (top < -3)
435 top += DAYSPERWEEK;
436 top += len;
437 if (yday >= top) {
438 ++base;
439 w = 1;
440 break;
441 }
442 if (yday >= bot) {
443 w = 1 + ((yday - bot) /
444 DAYSPERWEEK);
445 break;
446 }
447 --base;
448 yday += isleap_sum(year, base) ?
449 DAYSPERLYEAR :
450 DAYSPERNYEAR;
451 }
452 #ifdef XPG4_1994_04_09
453 if ((w == 52 &&
454 t->tm_mon == TM_JANUARY) ||
455 (w == 1 &&
456 t->tm_mon == TM_DECEMBER))
457 w = 53;
458 #endif /* defined XPG4_1994_04_09 */
459 if (*format == 'V')
460 pt = _conv(w,
461 getformat(modifier,
462 "%02d",
463 "%2d",
464 "%d",
465 "%02d"),
466 pt, ptlim);
467 else if (*format == 'g') {
468 *warnp = IN_ALL;
469 pt = _yconv(year, base, 0, 1,
470 pt, ptlim, modifier);
471 } else pt = _yconv(year, base, 1, 1,
472 pt, ptlim, modifier);
473 }
474 continue;
475 case 'v':
476 /*
477 ** From Arnold Robbins' strftime version 3.0:
478 ** "date as dd-bbb-YYYY"
479 ** (ado, 1993-05-24)
480 */
481 pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
482 continue;
483 case 'W':
484 pt = _conv((t->tm_yday + DAYSPERWEEK -
485 (t->tm_wday ?
486 (t->tm_wday - 1) :
487 (DAYSPERWEEK - 1))) / DAYSPERWEEK,
488 getformat(modifier, "%02d",
489 "%2d", "%d", "%02d"),
490 pt, ptlim);
491 continue;
492 case 'w':
493 pt = _conv(t->tm_wday, "%d", pt, ptlim);
494 continue;
495 case 'X':
496 pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
497 continue;
498 case 'x':
499 {
500 int warn2 = IN_SOME;
501
502 pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
503 if (warn2 == IN_ALL)
504 warn2 = IN_THIS;
505 if (warn2 > *warnp)
506 *warnp = warn2;
507 }
508 continue;
509 case 'y':
510 *warnp = IN_ALL;
511 pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
512 pt, ptlim, modifier);
513 continue;
514 case 'Y':
515 pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
516 pt, ptlim, modifier);
517 continue;
518 case 'Z':
519 #ifdef TM_ZONE
520 if (t->TM_ZONE != NULL)
521 pt = _add(t->TM_ZONE, pt, ptlim,
522 modifier);
523 else
524 #endif /* defined TM_ZONE */
525 if (t->tm_isdst >= 0)
526 pt = _add(tzname[t->tm_isdst != 0],
527 pt, ptlim, modifier);
528 /*
529 ** C99 says that %Z must be replaced by the
530 ** empty string if the time zone is not
531 ** determinable.
532 */
533 continue;
534 case 'z':
535 {
536 int diff;
537 char const * sign;
538
539 if (t->tm_isdst < 0)
540 continue;
541 #ifdef TM_GMTOFF
542 diff = t->TM_GMTOFF;
543 #else /* !defined TM_GMTOFF */
544 /*
545 ** C99 says that the UTC offset must
546 ** be computed by looking only at
547 ** tm_isdst. This requirement is
548 ** incorrect, since it means the code
549 ** must rely on magic (in this case
550 ** altzone and timezone), and the
551 ** magic might not have the correct
552 ** offset. Doing things correctly is
553 ** tricky and requires disobeying C99;
554 ** see GNU C strftime for details.
555 ** For now, punt and conform to the
556 ** standard, even though it's incorrect.
557 **
558 ** C99 says that %z must be replaced by the
559 ** empty string if the time zone is not
560 ** determinable, so output nothing if the
561 ** appropriate variables are not available.
562 */
563 if (t->tm_isdst == 0)
564 #ifdef USG_COMPAT
565 diff = -timezone;
566 #else /* !defined USG_COMPAT */
567 continue;
568 #endif /* !defined USG_COMPAT */
569 else
570 #ifdef ALTZONE
571 diff = -altzone;
572 #else /* !defined ALTZONE */
573 continue;
574 #endif /* !defined ALTZONE */
575 #endif /* !defined TM_GMTOFF */
576 if (diff < 0) {
577 sign = "-";
578 diff = -diff;
579 } else sign = "+";
580 pt = _add(sign, pt, ptlim, modifier);
581 diff /= SECSPERMIN;
582 diff = (diff / MINSPERHOUR) * 100 +
583 (diff % MINSPERHOUR);
584 pt = _conv(diff,
585 getformat(modifier, "%04d",
586 "%4d", "%d", "%04d"),
587 pt, ptlim);
588 }
589 continue;
590 case '+':
591 pt = _fmt(Locale->date_fmt, t, pt, ptlim,
592 warnp, Locale);
593 continue;
594 case '%':
595 /*
596 ** X311J/88-090 (4.12.3.5): if conversion char is
597 ** undefined, behavior is undefined. Print out the
598 ** character itself as printf(3) also does.
599 */
600 default:
601 break;
602 }
603 }
604 if (pt == ptlim)
605 break;
606 *pt++ = *format;
607 }
608 return pt;
609 }
610
611 static char *
612 _conv(n, format, pt, ptlim)
613 const int n;
614 const char * const format;
615 char * const pt;
616 const char * const ptlim;
617 {
618 char buf[INT_STRLEN_MAXIMUM(int) + 1];
619
620 (void) sprintf(buf, format, n);
621 return _add(buf, pt, ptlim, 0);
622 }
623
624 static char *
625 _add(str, pt, ptlim, modifier)
626 const char * str;
627 char * pt;
628 const char * const ptlim;
629 int modifier;
630 {
631 int c;
632
633 switch (modifier) {
634 case FORCE_LOWER_CASE:
635 while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
636 ++pt;
637 }
638 break;
639
640 case '^':
641 while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
642 ++pt;
643 }
644 break;
645
646 case '#':
647 while (pt < ptlim && (c = *str++) != '\0') {
648 if (isupper(c)) {
649 c = tolower(c);
650 } else if (islower(c)) {
651 c = toupper(c);
652 }
653 *pt = c;
654 ++pt;
655 }
656
657 break;
658
659 default:
660 while (pt < ptlim && (*pt = *str++) != '\0') {
661 ++pt;
662 }
663 }
664
665 return pt;
666 }
667
668 /*
669 ** POSIX and the C Standard are unclear or inconsistent about
670 ** what %C and %y do if the year is negative or exceeds 9999.
671 ** Use the convention that %C concatenated with %y yields the
672 ** same output as %Y, and that %Y contains at least 4 bytes,
673 ** with more only if necessary.
674 */
675
676 static char *
677 _yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
678 const int a;
679 const int b;
680 const int convert_top;
681 const int convert_yy;
682 char * pt;
683 const char * const ptlim;
684 int modifier;
685 {
686 register int lead;
687 register int trail;
688
689 #define DIVISOR 100
690 trail = a % DIVISOR + b % DIVISOR;
691 lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
692 trail %= DIVISOR;
693 if (trail < 0 && lead > 0) {
694 trail += DIVISOR;
695 --lead;
696 } else if (lead < 0 && trail > 0) {
697 trail -= DIVISOR;
698 ++lead;
699 }
700 if (convert_top) {
701 if (lead == 0 && trail < 0)
702 pt = _add("-0", pt, ptlim, modifier);
703 else pt = _conv(lead, getformat(modifier, "%02d",
704 "%2d", "%d", "%02d"),
705 pt, ptlim);
706 }
707 if (convert_yy)
708 pt = _conv(((trail < 0) ? -trail : trail),
709 getformat(modifier, "%02d", "%2d", "%d", "%02d"),
710 pt, ptlim);
711 return pt;
712 }
713
714 #ifdef LOCALE_HOME
715 static struct lc_time_T *
716 _loc P((void))
717 {
718 static const char locale_home[] = LOCALE_HOME;
719 static const char lc_time[] = "LC_TIME";
720 static char * locale_buf;
721
722 int fd;
723 int oldsun; /* "...ain't got nothin' to do..." */
724 char * lbuf;
725 char * name;
726 char * p;
727 const char ** ap;
728 const char * plim;
729 char filename[FILENAME_MAX];
730 struct stat st;
731 size_t namesize;
732 size_t bufsize;
733
734 /*
735 ** Use localebuf.mon[0] to signal whether locale is already set up.
736 */
737 if (localebuf.mon[0])
738 return &localebuf;
739 name = setlocale(LC_TIME, (char *) NULL);
740 if (name == NULL || *name == '\0')
741 goto no_locale;
742 /*
743 ** If the locale name is the same as our cache, use the cache.
744 */
745 lbuf = locale_buf;
746 if (lbuf != NULL && strcmp(name, lbuf) == 0) {
747 p = lbuf;
748 for (ap = (const char **) &localebuf;
749 ap < (const char **) (&localebuf + 1);
750 ++ap)
751 *ap = p += strlen(p) + 1;
752 return &localebuf;
753 }
754 /*
755 ** Slurp the locale file into the cache.
756 */
757 namesize = strlen(name) + 1;
758 if (sizeof filename <
759 ((sizeof locale_home) + namesize + (sizeof lc_time)))
760 goto no_locale;
761 oldsun = 0;
762 (void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
763 fd = open(filename, O_RDONLY);
764 if (fd < 0) {
765 /*
766 ** Old Sun systems have a different naming and data convention.
767 */
768 oldsun = 1;
769 (void) sprintf(filename, "%s/%s/%s", locale_home,
770 lc_time, name);
771 fd = open(filename, O_RDONLY);
772 if (fd < 0)
773 goto no_locale;
774 }
775 if (fstat(fd, &st) != 0)
776 goto bad_locale;
777 if (st.st_size <= 0)
778 goto bad_locale;
779 bufsize = namesize + st.st_size;
780 locale_buf = NULL;
781 lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
782 if (lbuf == NULL)
783 goto bad_locale;
784 (void) strcpy(lbuf, name);
785 p = lbuf + namesize;
786 plim = p + st.st_size;
787 if (read(fd, p, (size_t) st.st_size) != st.st_size)
788 goto bad_lbuf;
789 if (close(fd) != 0)
790 goto bad_lbuf;
791 /*
792 ** Parse the locale file into localebuf.
793 */
794 if (plim[-1] != '\n')
795 goto bad_lbuf;
796 for (ap = (const char **) &localebuf;
797 ap < (const char **) (&localebuf + 1);
798 ++ap) {
799 if (p == plim)
800 goto bad_lbuf;
801 *ap = p;
802 while (*p != '\n')
803 ++p;
804 *p++ = '\0';
805 }
806 if (oldsun) {
807 /*
808 ** SunOS 4 used an obsolescent format; see localdtconv(3).
809 ** c_fmt had the ``short format for dates and times together''
810 ** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
811 ** date_fmt had the ``long format for dates''
812 ** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
813 ** Discard the latter in favor of the former.
814 */
815 localebuf.date_fmt = localebuf.c_fmt;
816 }
817 /*
818 ** Record the successful parse in the cache.
819 */
820 locale_buf = lbuf;
821
822 return &localebuf;
823
824 bad_lbuf:
825 free(lbuf);
826 bad_locale:
827 (void) close(fd);
828 no_locale:
829 localebuf = C_time_locale;
830 locale_buf = NULL;
831 return &localebuf;
832 }
833 #endif /* defined LOCALE_HOME */
+0
-1915
libcutils/tztime.c less more
0 /*
1 ** This file is in the public domain, so clarified as of
2 ** 1996-06-05 by Arthur David Olson.
3 */
4
5 #include <stdio.h>
6
7 #ifndef lint
8 #ifndef NOID
9 static char elsieid[] = "@(#)localtime.c 8.3";
10 #endif /* !defined NOID */
11 #endif /* !defined lint */
12
13 /*
14 ** Leap second handling from Bradley White.
15 ** POSIX-style TZ environment variable handling from Guy Harris.
16 */
17
18 /*LINTLIBRARY*/
19
20 #include "private.h"
21 #include "tzfile.h"
22 #include "fcntl.h"
23 #include "float.h" /* for FLT_MAX and DBL_MAX */
24
25 #ifndef TZ_ABBR_MAX_LEN
26 #define TZ_ABBR_MAX_LEN 16
27 #endif /* !defined TZ_ABBR_MAX_LEN */
28
29 #ifndef TZ_ABBR_CHAR_SET
30 #define TZ_ABBR_CHAR_SET \
31 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
32 #endif /* !defined TZ_ABBR_CHAR_SET */
33
34 #ifndef TZ_ABBR_ERR_CHAR
35 #define TZ_ABBR_ERR_CHAR '_'
36 #endif /* !defined TZ_ABBR_ERR_CHAR */
37
38 #define INDEXFILE "/system/usr/share/zoneinfo/zoneinfo.idx"
39 #define DATAFILE "/system/usr/share/zoneinfo/zoneinfo.dat"
40 #define NAMELEN 40
41 #define INTLEN 4
42 #define READLEN (NAMELEN + 3 * INTLEN)
43
44 /*
45 ** SunOS 4.1.1 headers lack O_BINARY.
46 */
47
48 #ifdef O_BINARY
49 #define OPEN_MODE (O_RDONLY | O_BINARY)
50 #endif /* defined O_BINARY */
51 #ifndef O_BINARY
52 #define OPEN_MODE O_RDONLY
53 #endif /* !defined O_BINARY */
54
55 #ifndef WILDABBR
56 /*
57 ** Someone might make incorrect use of a time zone abbreviation:
58 ** 1. They might reference tzname[0] before calling tzset (explicitly
59 ** or implicitly).
60 ** 2. They might reference tzname[1] before calling tzset (explicitly
61 ** or implicitly).
62 ** 3. They might reference tzname[1] after setting to a time zone
63 ** in which Daylight Saving Time is never observed.
64 ** 4. They might reference tzname[0] after setting to a time zone
65 ** in which Standard Time is never observed.
66 ** 5. They might reference tm.TM_ZONE after calling offtime.
67 ** What's best to do in the above cases is open to debate;
68 ** for now, we just set things up so that in any of the five cases
69 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
70 ** string "tzname[0] used before set", and similarly for the other cases.
71 ** And another: initialize tzname[0] to "ERA", with an explanation in the
72 ** manual page of what this "time zone abbreviation" means (doing this so
73 ** that tzname[0] has the "normal" length of three characters).
74 */
75 #define WILDABBR " "
76 #endif /* !defined WILDABBR */
77
78 static char wildabbr[] = WILDABBR;
79
80 static const char gmt[] = "GMT";
81
82 /*
83 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
84 ** We default to US rules as of 1999-08-17.
85 ** POSIX 1003.1 section 8.1.1 says that the default DST rules are
86 ** implementation dependent; for historical reasons, US rules are a
87 ** common default.
88 */
89 #ifndef TZDEFRULESTRING
90 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
91 #endif /* !defined TZDEFDST */
92
93 struct ttinfo { /* time type information */
94 long tt_gmtoff; /* UTC offset in seconds */
95 int tt_isdst; /* used to set tm_isdst */
96 int tt_abbrind; /* abbreviation list index */
97 int tt_ttisstd; /* TRUE if transition is std time */
98 int tt_ttisgmt; /* TRUE if transition is UTC */
99 };
100
101 struct lsinfo { /* leap second information */
102 time_t ls_trans; /* transition time */
103 long ls_corr; /* correction to apply */
104 };
105
106 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
107
108 #ifdef TZNAME_MAX
109 #define MY_TZNAME_MAX TZNAME_MAX
110 #endif /* defined TZNAME_MAX */
111 #ifndef TZNAME_MAX
112 #define MY_TZNAME_MAX 255
113 #endif /* !defined TZNAME_MAX */
114
115 struct state {
116 int leapcnt;
117 int timecnt;
118 int typecnt;
119 int charcnt;
120 int goback;
121 int goahead;
122 time_t ats[TZ_MAX_TIMES];
123 unsigned char types[TZ_MAX_TIMES];
124 struct ttinfo ttis[TZ_MAX_TYPES];
125 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
126 (2 * (MY_TZNAME_MAX + 1)))];
127 struct lsinfo lsis[TZ_MAX_LEAPS];
128 };
129
130 struct rule {
131 int r_type; /* type of rule--see below */
132 int r_day; /* day number of rule */
133 int r_week; /* week number of rule */
134 int r_mon; /* month number of rule */
135 long r_time; /* transition time of rule */
136 };
137
138 #define JULIAN_DAY 0 /* Jn - Julian day */
139 #define DAY_OF_YEAR 1 /* n - day of year */
140 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
141
142 /*
143 ** Prototypes for static functions.
144 */
145
146 static long detzcode P((const char * codep));
147 static time_t detzcode64 P((const char * codep));
148 static int differ_by_repeat P((time_t t1, time_t t0));
149 static const char * getzname P((const char * strp));
150 static const char * getqzname P((const char * strp, const int delim));
151 static const char * getnum P((const char * strp, int * nump, int min,
152 int max));
153 static const char * getsecs P((const char * strp, long * secsp));
154 static const char * getoffset P((const char * strp, long * offsetp));
155 static const char * getrule P((const char * strp, struct rule * rulep));
156 static void gmtload P((struct state * sp));
157 static struct tm * gmtsub P((const time_t * timep, long offset,
158 struct tm * tmp));
159 static struct tm * localsub P((const time_t * timep, long offset,
160 struct tm * tmp, struct state *sp));
161 static int increment_overflow P((int * number, int delta));
162 static int leaps_thru_end_of P((int y));
163 static int long_increment_overflow P((long * number, int delta));
164 static int long_normalize_overflow P((long * tensptr,
165 int * unitsptr, int base));
166 static int normalize_overflow P((int * tensptr, int * unitsptr,
167 int base));
168 static void settzname P((void));
169 static time_t time1 P((struct tm * tmp,
170 struct tm * (*funcp) P((const time_t *,
171 long, struct tm *, const struct state* sp)),
172 long offset, const struct state * sp));
173 static time_t time2 P((struct tm *tmp,
174 struct tm * (*funcp) P((const time_t *,
175 long, struct tm*, const struct state* sp)),
176 long offset, int * okayp, const struct state * sp));
177 static time_t time2sub P((struct tm *tmp,
178 struct tm * (*funcp) P((const time_t*, long, struct tm*,const struct state *sp)),
179 long offset, int * okayp, int do_norm_secs,
180 const struct state *sp));
181 static struct tm * timesub P((const time_t * timep, long offset,
182 const struct state * sp, struct tm * tmp));
183 static int tmcomp P((const struct tm * atmp,
184 const struct tm * btmp));
185 static time_t transtime P((time_t janfirst, int year,
186 const struct rule * rulep, long offset));
187 static int tzload P((const char * name, struct state * sp,
188 int doextend));
189 static int tzload_uncached P((const char * name, struct state * sp,
190 int doextend));
191 static int tzparse P((const char * name, struct state * sp,
192 int lastditch));
193
194 #ifdef ALL_STATE
195 static struct state * gmtptr;
196 #endif /* defined ALL_STATE */
197
198 #ifndef ALL_STATE
199 static struct state gmtmem;
200 #define gmtptr (&gmtmem)
201 #endif /* State Farm */
202
203 #define CACHE_COUNT 4
204 static char * g_cacheNames[CACHE_COUNT] = {0,0};
205 static struct state g_cacheStates[CACHE_COUNT];
206 static int g_lastCache = 0;
207 static struct state g_utc;
208 unsigned char g_utcSet = 0;
209
210
211 #ifndef TZ_STRLEN_MAX
212 #define TZ_STRLEN_MAX 255
213 #endif /* !defined TZ_STRLEN_MAX */
214
215 static char lcl_TZname[TZ_STRLEN_MAX + 1];
216 static int lcl_is_set;
217 static int gmt_is_set;
218
219 char * tzname[2] = {
220 wildabbr,
221 wildabbr
222 };
223
224 /*
225 ** Section 4.12.3 of X3.159-1989 requires that
226 ** Except for the strftime function, these functions [asctime,
227 ** ctime, gmtime, localtime] return values in one of two static
228 ** objects: a broken-down time structure and an array of char.
229 ** Thanks to Paul Eggert for noting this.
230 */
231
232 static struct tm tm;
233
234 #ifdef USG_COMPAT
235 time_t timezone = 0;
236 int daylight = 0;
237 #endif /* defined USG_COMPAT */
238
239 #ifdef ALTZONE
240 time_t altzone = 0;
241 #endif /* defined ALTZONE */
242
243 static long
244 detzcode(codep)
245 const char * const codep;
246 {
247 register long result;
248 register int i;
249
250 result = (codep[0] & 0x80) ? ~0L : 0;
251 for (i = 0; i < 4; ++i)
252 result = (result << 8) | (codep[i] & 0xff);
253 return result;
254 }
255
256 static time_t
257 detzcode64(codep)
258 const char * const codep;
259 {
260 register time_t result;
261 register int i;
262
263 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
264 for (i = 0; i < 8; ++i)
265 result = result * 256 + (codep[i] & 0xff);
266 return result;
267 }
268
269 static int
270 differ_by_repeat(t1, t0)
271 const time_t t1;
272 const time_t t0;
273 {
274 if (TYPE_INTEGRAL(time_t) &&
275 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
276 return 0;
277 return t1 - t0 == SECSPERREPEAT;
278 }
279
280 static int toint(unsigned char *s) {
281 return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
282 }
283
284 static int
285 tzload(const char *name, struct state * const sp, const int doextend)
286 {
287 if (name) {
288 int i, err;
289 if (0 == strcmp(name, "UTC")) {
290 if (!g_utcSet) {
291 tzload_uncached(name, &g_utc, 1);
292 g_utcSet = 1;
293 }
294 //printf("tzload: utc\n");
295 *sp = g_utc;
296 return 0;
297 }
298 for (i=0; i<CACHE_COUNT; i++) {
299 if (g_cacheNames[i] && 0 == strcmp(name, g_cacheNames[i])) {
300 *sp = g_cacheStates[i];
301 //printf("tzload: hit: %s\n", name);
302 return 0;
303 }
304 }
305 //printf("tzload: miss: %s\n", name);
306 g_lastCache++;
307 if (g_lastCache >= CACHE_COUNT) {
308 g_lastCache = 0;
309 }
310 i = g_lastCache;
311 if (g_cacheNames[i]) {
312 free(g_cacheNames[i]);
313 }
314 err = tzload_uncached(name, &(g_cacheStates[i]), 1);
315 if (err == 0) {
316 g_cacheNames[i] = strdup(name);
317 *sp = g_cacheStates[i];
318 return 0;
319 } else {
320 g_cacheNames[i] = NULL;
321 return err;
322 }
323 }
324 return tzload_uncached(name, sp, doextend);
325 }
326
327 static int
328 tzload_uncached(name, sp, doextend)
329 register const char * name;
330 register struct state * const sp;
331 register const int doextend;
332 {
333 register const char * p;
334 register int i;
335 register int fid;
336 register int stored;
337 register int nread;
338 union {
339 struct tzhead tzhead;
340 char buf[2 * sizeof(struct tzhead) +
341 2 * sizeof *sp +
342 4 * TZ_MAX_TIMES];
343 } u;
344 int toread = sizeof u.buf;
345
346 if (name == NULL && (name = TZDEFAULT) == NULL)
347 return -1;
348 {
349 register int doaccess;
350 /*
351 ** Section 4.9.1 of the C standard says that
352 ** "FILENAME_MAX expands to an integral constant expression
353 ** that is the size needed for an array of char large enough
354 ** to hold the longest file name string that the implementation
355 ** guarantees can be opened."
356 */
357 char fullname[FILENAME_MAX + 1];
358 const char *origname = name;
359
360 if (name[0] == ':')
361 ++name;
362 doaccess = name[0] == '/';
363 if (!doaccess) {
364 if ((p = TZDIR) == NULL)
365 return -1;
366 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
367 return -1;
368 (void) strcpy(fullname, p);
369 (void) strcat(fullname, "/");
370 (void) strcat(fullname, name);
371 /*
372 ** Set doaccess if '.' (as in "../") shows up in name.
373 */
374 if (strchr(name, '.') != NULL)
375 doaccess = TRUE;
376 name = fullname;
377 }
378 if (doaccess && access(name, R_OK) != 0)
379 return -1;
380 if ((fid = open(name, OPEN_MODE)) == -1) {
381 char buf[READLEN];
382 char name[NAMELEN + 1];
383 int fidix = open(INDEXFILE, OPEN_MODE);
384 int off = -1;
385
386 if (fidix < 0) {
387 return -1;
388 }
389
390 while (read(fidix, buf, sizeof(buf)) == sizeof(buf)) {
391 memcpy(name, buf, NAMELEN);
392 name[NAMELEN] = '\0';
393
394 if (strcmp(name, origname) == 0) {
395 off = toint((unsigned char *) buf + NAMELEN);
396 toread = toint((unsigned char *) buf + NAMELEN + INTLEN);
397 break;
398 }
399 }
400
401 close(fidix);
402
403 if (off < 0)
404 return -1;
405
406 fid = open(DATAFILE, OPEN_MODE);
407
408 if (fid < 0) {
409 return -1;
410 }
411
412 if (lseek(fid, off, SEEK_SET) < 0) {
413 return -1;
414 }
415 }
416 }
417 nread = read(fid, u.buf, toread);
418 if (close(fid) < 0 || nread <= 0)
419 return -1;
420 for (stored = 4; stored <= 8; stored *= 2) {
421 int ttisstdcnt;
422 int ttisgmtcnt;
423
424 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
425 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
426 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
427 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
428 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
429 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
430 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
431 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
432 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
433 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
434 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
435 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
436 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
437 return -1;
438 if (nread - (p - u.buf) <
439 sp->timecnt * stored + /* ats */
440 sp->timecnt + /* types */
441 sp->typecnt * 6 + /* ttinfos */
442 sp->charcnt + /* chars */
443 sp->leapcnt * (stored + 4) + /* lsinfos */
444 ttisstdcnt + /* ttisstds */
445 ttisgmtcnt) /* ttisgmts */
446 return -1;
447 for (i = 0; i < sp->timecnt; ++i) {
448 sp->ats[i] = (stored == 4) ?
449 detzcode(p) : detzcode64(p);
450 p += stored;
451 }
452 for (i = 0; i < sp->timecnt; ++i) {
453 sp->types[i] = (unsigned char) *p++;
454 if (sp->types[i] >= sp->typecnt)
455 return -1;
456 }
457 for (i = 0; i < sp->typecnt; ++i) {
458 register struct ttinfo * ttisp;
459
460 ttisp = &sp->ttis[i];
461 ttisp->tt_gmtoff = detzcode(p);
462 p += 4;
463 ttisp->tt_isdst = (unsigned char) *p++;
464 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
465 return -1;
466 ttisp->tt_abbrind = (unsigned char) *p++;
467 if (ttisp->tt_abbrind < 0 ||
468 ttisp->tt_abbrind > sp->charcnt)
469 return -1;
470 }
471 for (i = 0; i < sp->charcnt; ++i)
472 sp->chars[i] = *p++;
473 sp->chars[i] = '\0'; /* ensure '\0' at end */
474 for (i = 0; i < sp->leapcnt; ++i) {
475 register struct lsinfo * lsisp;
476
477 lsisp = &sp->lsis[i];
478 lsisp->ls_trans = (stored == 4) ?
479 detzcode(p) : detzcode64(p);
480 p += stored;
481 lsisp->ls_corr = detzcode(p);
482 p += 4;
483 }
484 for (i = 0; i < sp->typecnt; ++i) {
485 register struct ttinfo * ttisp;
486
487 ttisp = &sp->ttis[i];
488 if (ttisstdcnt == 0)
489 ttisp->tt_ttisstd = FALSE;
490 else {
491 ttisp->tt_ttisstd = *p++;
492 if (ttisp->tt_ttisstd != TRUE &&
493 ttisp->tt_ttisstd != FALSE)
494 return -1;
495 }
496 }
497 for (i = 0; i < sp->typecnt; ++i) {
498 register struct ttinfo * ttisp;
499
500 ttisp = &sp->ttis[i];
501 if (ttisgmtcnt == 0)
502 ttisp->tt_ttisgmt = FALSE;
503 else {
504 ttisp->tt_ttisgmt = *p++;
505 if (ttisp->tt_ttisgmt != TRUE &&
506 ttisp->tt_ttisgmt != FALSE)
507 return -1;
508 }
509 }
510 /*
511 ** Out-of-sort ats should mean we're running on a
512 ** signed time_t system but using a data file with
513 ** unsigned values (or vice versa).
514 */
515 for (i = 0; i < sp->timecnt - 2; ++i)
516 if (sp->ats[i] > sp->ats[i + 1]) {
517 ++i;
518 if (TYPE_SIGNED(time_t)) {
519 /*
520 ** Ignore the end (easy).
521 */
522 sp->timecnt = i;
523 } else {
524 /*
525 ** Ignore the beginning (harder).
526 */
527 register int j;
528
529 for (j = 0; j + i < sp->timecnt; ++j) {
530 sp->ats[j] = sp->ats[j + i];
531 sp->types[j] = sp->types[j + i];
532 }
533 sp->timecnt = j;
534 }
535 break;
536 }
537 /*
538 ** If this is an old file, we're done.
539 */
540 if (u.tzhead.tzh_version[0] == '\0')
541 break;
542 nread -= p - u.buf;
543 for (i = 0; i < nread; ++i)
544 u.buf[i] = p[i];
545 /*
546 ** If this is a narrow integer time_t system, we're done.
547 */
548 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
549 break;
550 }
551 if (doextend && nread > 2 &&
552 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
553 sp->typecnt + 2 <= TZ_MAX_TYPES) {
554 struct state ts;
555 register int result;
556
557 u.buf[nread - 1] = '\0';
558 result = tzparse(&u.buf[1], &ts, FALSE);
559 if (result == 0 && ts.typecnt == 2 &&
560 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
561 for (i = 0; i < 2; ++i)
562 ts.ttis[i].tt_abbrind +=
563 sp->charcnt;
564 for (i = 0; i < ts.charcnt; ++i)
565 sp->chars[sp->charcnt++] =
566 ts.chars[i];
567 i = 0;
568 while (i < ts.timecnt &&
569 ts.ats[i] <=
570 sp->ats[sp->timecnt - 1])
571 ++i;
572 while (i < ts.timecnt &&
573 sp->timecnt < TZ_MAX_TIMES) {
574 sp->ats[sp->timecnt] =
575 ts.ats[i];
576 sp->types[sp->timecnt] =
577 sp->typecnt +
578 ts.types[i];
579 ++sp->timecnt;
580 ++i;
581 }
582 sp->ttis[sp->typecnt++] = ts.ttis[0];
583 sp->ttis[sp->typecnt++] = ts.ttis[1];
584 }
585 }
586 i = 2 * YEARSPERREPEAT;
587 sp->goback = sp->goahead = sp->timecnt > i;
588 sp->goback &= sp->types[i] == sp->types[0] &&
589 differ_by_repeat(sp->ats[i], sp->ats[0]);
590 sp->goahead &=
591 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
592 differ_by_repeat(sp->ats[sp->timecnt - 1],
593 sp->ats[sp->timecnt - 1 - i]);
594 return 0;
595 }
596
597 static const int mon_lengths[2][MONSPERYEAR] = {
598 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
599 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
600 };
601
602 static const int year_lengths[2] = {
603 DAYSPERNYEAR, DAYSPERLYEAR
604 };
605
606 /*
607 ** Given a pointer into a time zone string, scan until a character that is not
608 ** a valid character in a zone name is found. Return a pointer to that
609 ** character.
610 */
611
612 static const char *
613 getzname(strp)
614 register const char * strp;
615 {
616 register char c;
617
618 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
619 c != '+')
620 ++strp;
621 return strp;
622 }
623
624 /*
625 ** Given a pointer into an extended time zone string, scan until the ending
626 ** delimiter of the zone name is located. Return a pointer to the delimiter.
627 **
628 ** As with getzname above, the legal character set is actually quite
629 ** restricted, with other characters producing undefined results.
630 ** We don't do any checking here; checking is done later in common-case code.
631 */
632
633 static const char *
634 getqzname(register const char *strp, const int delim)
635 {
636 register int c;
637
638 while ((c = *strp) != '\0' && c != delim)
639 ++strp;
640 return strp;
641 }
642
643 /*
644 ** Given a pointer into a time zone string, extract a number from that string.
645 ** Check that the number is within a specified range; if it is not, return
646 ** NULL.
647 ** Otherwise, return a pointer to the first character not part of the number.
648 */
649
650 static const char *
651 getnum(strp, nump, min, max)
652 register const char * strp;
653 int * const nump;
654 const int min;
655 const int max;
656 {
657 register char c;
658 register int num;
659
660 if (strp == NULL || !is_digit(c = *strp))
661 return NULL;
662 num = 0;
663 do {
664 num = num * 10 + (c - '0');
665 if (num > max)
666 return NULL; /* illegal value */
667 c = *++strp;
668 } while (is_digit(c));
669 if (num < min)
670 return NULL; /* illegal value */
671 *nump = num;
672 return strp;
673 }
674
675 /*
676 ** Given a pointer into a time zone string, extract a number of seconds,
677 ** in hh[:mm[:ss]] form, from the string.
678 ** If any error occurs, return NULL.
679 ** Otherwise, return a pointer to the first character not part of the number
680 ** of seconds.
681 */
682
683 static const char *
684 getsecs(strp, secsp)
685 register const char * strp;
686 long * const secsp;
687 {
688 int num;
689
690 /*
691 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
692 ** "M10.4.6/26", which does not conform to Posix,
693 ** but which specifies the equivalent of
694 ** ``02:00 on the first Sunday on or after 23 Oct''.
695 */
696 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
697 if (strp == NULL)
698 return NULL;
699 *secsp = num * (long) SECSPERHOUR;
700 if (*strp == ':') {
701 ++strp;
702 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
703 if (strp == NULL)
704 return NULL;
705 *secsp += num * SECSPERMIN;
706 if (*strp == ':') {
707 ++strp;
708 /* `SECSPERMIN' allows for leap seconds. */
709 strp = getnum(strp, &num, 0, SECSPERMIN);
710 if (strp == NULL)
711 return NULL;
712 *secsp += num;
713 }
714 }
715 return strp;
716 }
717
718 /*
719 ** Given a pointer into a time zone string, extract an offset, in
720 ** [+-]hh[:mm[:ss]] form, from the string.
721 ** If any error occurs, return NULL.
722 ** Otherwise, return a pointer to the first character not part of the time.
723 */
724
725 static const char *
726 getoffset(strp, offsetp)
727 register const char * strp;
728 long * const offsetp;
729 {
730 register int neg = 0;
731
732 if (*strp == '-') {
733 neg = 1;
734 ++strp;
735 } else if (*strp == '+')
736 ++strp;
737 strp = getsecs(strp, offsetp);
738 if (strp == NULL)
739 return NULL; /* illegal time */
740 if (neg)
741 *offsetp = -*offsetp;
742 return strp;
743 }
744
745 /*
746 ** Given a pointer into a time zone string, extract a rule in the form
747 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
748 ** If a valid rule is not found, return NULL.
749 ** Otherwise, return a pointer to the first character not part of the rule.
750 */
751
752 static const char *
753 getrule(strp, rulep)
754 const char * strp;
755 register struct rule * const rulep;
756 {
757 if (*strp == 'J') {
758 /*
759 ** Julian day.
760 */
761 rulep->r_type = JULIAN_DAY;
762 ++strp;
763 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
764 } else if (*strp == 'M') {
765 /*
766 ** Month, week, day.
767 */
768 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
769 ++strp;
770 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
771 if (strp == NULL)
772 return NULL;
773 if (*strp++ != '.')
774 return NULL;
775 strp = getnum(strp, &rulep->r_week, 1, 5);
776 if (strp == NULL)
777 return NULL;
778 if (*strp++ != '.')
779 return NULL;
780 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
781 } else if (is_digit(*strp)) {
782 /*
783 ** Day of year.
784 */
785 rulep->r_type = DAY_OF_YEAR;
786 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
787 } else return NULL; /* invalid format */
788 if (strp == NULL)
789 return NULL;
790 if (*strp == '/') {
791 /*
792 ** Time specified.
793 */
794 ++strp;
795 strp = getsecs(strp, &rulep->r_time);
796 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
797 return strp;
798 }
799
800 /*
801 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
802 ** year, a rule, and the offset from UTC at the time that rule takes effect,
803 ** calculate the Epoch-relative time that rule takes effect.
804 */
805
806 static time_t
807 transtime(janfirst, year, rulep, offset)
808 const time_t janfirst;
809 const int year;
810 register const struct rule * const rulep;
811 const long offset;
812 {
813 register int leapyear;
814 register time_t value;
815 register int i;
816 int d, m1, yy0, yy1, yy2, dow;
817
818 INITIALIZE(value);
819 leapyear = isleap(year);
820 switch (rulep->r_type) {
821
822 case JULIAN_DAY:
823 /*
824 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
825 ** years.
826 ** In non-leap years, or if the day number is 59 or less, just
827 ** add SECSPERDAY times the day number-1 to the time of
828 ** January 1, midnight, to get the day.
829 */
830 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
831 if (leapyear && rulep->r_day >= 60)
832 value += SECSPERDAY;
833 break;
834
835 case DAY_OF_YEAR:
836 /*
837 ** n - day of year.
838 ** Just add SECSPERDAY times the day number to the time of
839 ** January 1, midnight, to get the day.
840 */
841 value = janfirst + rulep->r_day * SECSPERDAY;
842 break;
843
844 case MONTH_NTH_DAY_OF_WEEK:
845 /*
846 ** Mm.n.d - nth "dth day" of month m.
847 */
848 value = janfirst;
849 for (i = 0; i < rulep->r_mon - 1; ++i)
850 value += mon_lengths[leapyear][i] * SECSPERDAY;
851
852 /*
853 ** Use Zeller's Congruence to get day-of-week of first day of
854 ** month.
855 */
856 m1 = (rulep->r_mon + 9) % 12 + 1;
857 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
858 yy1 = yy0 / 100;
859 yy2 = yy0 % 100;
860 dow = ((26 * m1 - 2) / 10 +
861 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
862 if (dow < 0)
863 dow += DAYSPERWEEK;
864
865 /*
866 ** "dow" is the day-of-week of the first day of the month. Get
867 ** the day-of-month (zero-origin) of the first "dow" day of the
868 ** month.
869 */
870 d = rulep->r_day - dow;
871 if (d < 0)
872 d += DAYSPERWEEK;
873 for (i = 1; i < rulep->r_week; ++i) {
874 if (d + DAYSPERWEEK >=
875 mon_lengths[leapyear][rulep->r_mon - 1])
876 break;
877 d += DAYSPERWEEK;
878 }
879
880 /*
881 ** "d" is the day-of-month (zero-origin) of the day we want.
882 */
883 value += d * SECSPERDAY;
884 break;
885 }
886
887 /*
888 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
889 ** question. To get the Epoch-relative time of the specified local
890 ** time on that day, add the transition time and the current offset
891 ** from UTC.
892 */
893 return value + rulep->r_time + offset;
894 }
895
896 /*
897 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
898 ** appropriate.
899 */
900
901 static int
902 tzparse(name, sp, lastditch)
903 const char * name;
904 register struct state * const sp;
905 const int lastditch;
906 {
907 const char * stdname;
908 const char * dstname;
909 size_t stdlen;
910 size_t dstlen;
911 long stdoffset;
912 long dstoffset;
913 register time_t * atp;
914 register unsigned char * typep;
915 register char * cp;
916 register int load_result;
917
918 INITIALIZE(dstname);
919 stdname = name;
920 if (lastditch) {
921 stdlen = strlen(name); /* length of standard zone name */
922 name += stdlen;
923 if (stdlen >= sizeof sp->chars)
924 stdlen = (sizeof sp->chars) - 1;
925 stdoffset = 0;
926 } else {
927 if (*name == '<') {
928 name++;
929 stdname = name;
930 name = getqzname(name, '>');
931 if (*name != '>')
932 return (-1);
933 stdlen = name - stdname;
934 name++;
935 } else {
936 name = getzname(name);
937 stdlen = name - stdname;
938 }
939 if (*name == '\0')
940 return -1;
941 name = getoffset(name, &stdoffset);
942 if (name == NULL)
943 return -1;
944 }
945 load_result = tzload(TZDEFRULES, sp, FALSE);
946 if (load_result != 0)
947 sp->leapcnt = 0; /* so, we're off a little */
948 sp->timecnt = 0;
949 if (*name != '\0') {
950 if (*name == '<') {
951 dstname = ++name;
952 name = getqzname(name, '>');
953 if (*name != '>')
954 return -1;
955 dstlen = name - dstname;
956 name++;
957 } else {
958 dstname = name;
959 name = getzname(name);
960 dstlen = name - dstname; /* length of DST zone name */
961 }
962 if (*name != '\0' && *name != ',' && *name != ';') {
963 name = getoffset(name, &dstoffset);
964 if (name == NULL)
965 return -1;
966 } else dstoffset = stdoffset - SECSPERHOUR;
967 if (*name == '\0' && load_result != 0)
968 name = TZDEFRULESTRING;
969 if (*name == ',' || *name == ';') {
970 struct rule start;
971 struct rule end;
972 register int year;
973 register time_t janfirst;
974 time_t starttime;
975 time_t endtime;
976
977 ++name;
978 if ((name = getrule(name, &start)) == NULL)
979 return -1;
980 if (*name++ != ',')
981 return -1;
982 if ((name = getrule(name, &end)) == NULL)
983 return -1;
984 if (*name != '\0')
985 return -1;
986 sp->typecnt = 2; /* standard time and DST */
987 /*
988 ** Two transitions per year, from EPOCH_YEAR forward.
989 */
990 sp->ttis[0].tt_gmtoff = -dstoffset;
991 sp->ttis[0].tt_isdst = 1;
992 sp->ttis[0].tt_abbrind = stdlen + 1;
993 sp->ttis[1].tt_gmtoff = -stdoffset;
994 sp->ttis[1].tt_isdst = 0;
995 sp->ttis[1].tt_abbrind = 0;
996 atp = sp->ats;
997 typep = sp->types;
998 janfirst = 0;
999 for (year = EPOCH_YEAR;
1000 sp->timecnt + 2 <= TZ_MAX_TIMES;
1001 ++year) {
1002 time_t newfirst;
1003
1004 starttime = transtime(janfirst, year, &start,
1005 stdoffset);
1006 endtime = transtime(janfirst, year, &end,
1007 dstoffset);
1008 if (starttime > endtime) {
1009 *atp++ = endtime;
1010 *typep++ = 1; /* DST ends */
1011 *atp++ = starttime;
1012 *typep++ = 0; /* DST begins */
1013 } else {
1014 *atp++ = starttime;
1015 *typep++ = 0; /* DST begins */
1016 *atp++ = endtime;
1017 *typep++ = 1; /* DST ends */
1018 }
1019 sp->timecnt += 2;
1020 newfirst = janfirst;
1021 newfirst += year_lengths[isleap(year)] *
1022 SECSPERDAY;
1023 if (newfirst <= janfirst)
1024 break;
1025 janfirst = newfirst;
1026 }
1027 } else {
1028 register long theirstdoffset;
1029 register long theirdstoffset;
1030 register long theiroffset;
1031 register int isdst;
1032 register int i;
1033 register int j;
1034
1035 if (*name != '\0')
1036 return -1;
1037 /*
1038 ** Initial values of theirstdoffset and theirdstoffset.
1039 */
1040 theirstdoffset = 0;
1041 for (i = 0; i < sp->timecnt; ++i) {
1042 j = sp->types[i];
1043 if (!sp->ttis[j].tt_isdst) {
1044 theirstdoffset =
1045 -sp->ttis[j].tt_gmtoff;
1046 break;
1047 }
1048 }
1049 theirdstoffset = 0;
1050 for (i = 0; i < sp->timecnt; ++i) {
1051 j = sp->types[i];
1052 if (sp->ttis[j].tt_isdst) {
1053 theirdstoffset =
1054 -sp->ttis[j].tt_gmtoff;
1055 break;
1056 }
1057 }
1058 /*
1059 ** Initially we're assumed to be in standard time.
1060 */
1061 isdst = FALSE;
1062 theiroffset = theirstdoffset;
1063 /*
1064 ** Now juggle transition times and types
1065 ** tracking offsets as you do.
1066 */
1067 for (i = 0; i < sp->timecnt; ++i) {
1068 j = sp->types[i];
1069 sp->types[i] = sp->ttis[j].tt_isdst;
1070 if (sp->ttis[j].tt_ttisgmt) {
1071 /* No adjustment to transition time */
1072 } else {
1073 /*
1074 ** If summer time is in effect, and the
1075 ** transition time was not specified as
1076 ** standard time, add the summer time
1077 ** offset to the transition time;
1078 ** otherwise, add the standard time
1079 ** offset to the transition time.
1080 */
1081 /*
1082 ** Transitions from DST to DDST
1083 ** will effectively disappear since
1084 ** POSIX provides for only one DST
1085 ** offset.
1086 */
1087 if (isdst && !sp->ttis[j].tt_ttisstd) {
1088 sp->ats[i] += dstoffset -
1089 theirdstoffset;
1090 } else {
1091 sp->ats[i] += stdoffset -
1092 theirstdoffset;
1093 }
1094 }
1095 theiroffset = -sp->ttis[j].tt_gmtoff;
1096 if (sp->ttis[j].tt_isdst)
1097 theirdstoffset = theiroffset;
1098 else theirstdoffset = theiroffset;
1099 }
1100 /*
1101 ** Finally, fill in ttis.
1102 ** ttisstd and ttisgmt need not be handled.
1103 */
1104 sp->ttis[0].tt_gmtoff = -stdoffset;
1105 sp->ttis[0].tt_isdst = FALSE;
1106 sp->ttis[0].tt_abbrind = 0;
1107 sp->ttis[1].tt_gmtoff = -dstoffset;
1108 sp->ttis[1].tt_isdst = TRUE;
1109 sp->ttis[1].tt_abbrind = stdlen + 1;
1110 sp->typecnt = 2;
1111 }
1112 } else {
1113 dstlen = 0;
1114 sp->typecnt = 1; /* only standard time */
1115 sp->timecnt = 0;
1116 sp->ttis[0].tt_gmtoff = -stdoffset;
1117 sp->ttis[0].tt_isdst = 0;
1118 sp->ttis[0].tt_abbrind = 0;
1119 }
1120 sp->charcnt = stdlen + 1;
1121 if (dstlen != 0)
1122 sp->charcnt += dstlen + 1;
1123 if ((size_t) sp->charcnt > sizeof sp->chars)
1124 return -1;
1125 cp = sp->chars;
1126 (void) strncpy(cp, stdname, stdlen);
1127 cp += stdlen;
1128 *cp++ = '\0';
1129 if (dstlen != 0) {
1130 (void) strncpy(cp, dstname, dstlen);
1131 *(cp + dstlen) = '\0';
1132 }
1133 return 0;
1134 }
1135
1136 static void
1137 gmtload(sp)
1138 struct state * const sp;
1139 {
1140 if (tzload(gmt, sp, TRUE) != 0)
1141 (void) tzparse(gmt, sp, TRUE);
1142 }
1143
1144 /*
1145 ** The easy way to behave "as if no library function calls" localtime
1146 ** is to not call it--so we drop its guts into "localsub", which can be
1147 ** freely called. (And no, the PANS doesn't require the above behavior--
1148 ** but it *is* desirable.)
1149 **
1150 ** The unused offset argument is for the benefit of mktime variants.
1151 */
1152
1153 /*ARGSUSED*/
1154 static struct tm *
1155 localsub(timep, offset, tmp, sp)
1156 const time_t * const timep;
1157 const long offset;
1158 struct tm * const tmp;
1159 struct state * sp;
1160 {
1161 register const struct ttinfo * ttisp;
1162 register int i;
1163 register struct tm * result;
1164 const time_t t = *timep;
1165
1166 #ifdef ALL_STATE
1167 if (sp == NULL)
1168 return gmtsub(timep, offset, tmp);
1169 #endif /* defined ALL_STATE */
1170 if ((sp->goback && t < sp->ats[0]) ||
1171 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1172 time_t newt = t;
1173 register time_t seconds;
1174 register time_t tcycles;
1175 register int_fast64_t icycles;
1176
1177 if (t < sp->ats[0])
1178 seconds = sp->ats[0] - t;
1179 else seconds = t - sp->ats[sp->timecnt - 1];
1180 --seconds;
1181 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1182 ++tcycles;
1183 icycles = tcycles;
1184 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1185 return NULL;
1186 seconds = icycles;
1187 seconds *= YEARSPERREPEAT;
1188 seconds *= AVGSECSPERYEAR;
1189 if (t < sp->ats[0])
1190 newt += seconds;
1191 else newt -= seconds;
1192 if (newt < sp->ats[0] ||
1193 newt > sp->ats[sp->timecnt - 1])
1194 return NULL; /* "cannot happen" */
1195 result = localsub(&newt, offset, tmp, sp);
1196 if (result == tmp) {
1197 register time_t newy;
1198
1199 newy = tmp->tm_year;
1200 if (t < sp->ats[0])
1201 newy -= icycles * YEARSPERREPEAT;
1202 else newy += icycles * YEARSPERREPEAT;
1203 tmp->tm_year = newy;
1204 if (tmp->tm_year != newy)
1205 return NULL;
1206 }
1207 return result;
1208 }
1209 if (sp->timecnt == 0 || t < sp->ats[0]) {
1210 i = 0;
1211 while (sp->ttis[i].tt_isdst)
1212 if (++i >= sp->typecnt) {
1213 i = 0;
1214 break;
1215 }
1216 } else {
1217 register int lo = 1;
1218 register int hi = sp->timecnt;
1219
1220 while (lo < hi) {
1221 register int mid = (lo + hi) >> 1;
1222
1223 if (t < sp->ats[mid])
1224 hi = mid;
1225 else lo = mid + 1;
1226 }
1227 i = (int) sp->types[lo - 1];
1228 }
1229 ttisp = &sp->ttis[i];
1230 /*
1231 ** To get (wrong) behavior that's compatible with System V Release 2.0
1232 ** you'd replace the statement below with
1233 ** t += ttisp->tt_gmtoff;
1234 ** timesub(&t, 0L, sp, tmp);
1235 */
1236 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1237 tmp->tm_isdst = ttisp->tt_isdst;
1238 #ifdef HAVE_TM_GMTOFF
1239 tmp->tm_gmtoff = ttisp->tt_gmtoff;
1240 #endif
1241 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1242 #ifdef TM_ZONE
1243 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1244 #endif /* defined TM_ZONE */
1245 return result;
1246 }
1247
1248
1249 // ============================================================================
1250 #if 0
1251 struct tm *
1252 localtime(timep)
1253 const time_t * const timep;
1254 {
1255 tzset();
1256 return localsub(timep, 0L, &tm);
1257 }
1258 #endif
1259
1260 /*
1261 ** Re-entrant version of localtime.
1262 */
1263
1264 // ============================================================================
1265 void
1266 localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz)
1267 {
1268 struct state st;
1269 if (tzload(tz, &st, TRUE) != 0) {
1270 // not sure what's best here, but for now, we fall back to gmt
1271 gmtload(&st);
1272 }
1273
1274 localsub(timep, 0L, tmp, &st);
1275 }
1276
1277 /*
1278 ** gmtsub is to gmtime as localsub is to localtime.
1279 */
1280
1281 static struct tm *
1282 gmtsub(timep, offset, tmp)
1283 const time_t * const timep;
1284 const long offset;
1285 struct tm * const tmp;
1286 {
1287 register struct tm * result;
1288
1289 if (!gmt_is_set) {
1290 gmt_is_set = TRUE;
1291 #ifdef ALL_STATE
1292 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1293 if (gmtptr != NULL)
1294 #endif /* defined ALL_STATE */
1295 gmtload(gmtptr);
1296 }
1297 result = timesub(timep, offset, gmtptr, tmp);
1298 #ifdef TM_ZONE
1299 /*
1300 ** Could get fancy here and deliver something such as
1301 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1302 ** but this is no time for a treasure hunt.
1303 */
1304 if (offset != 0)
1305 tmp->TM_ZONE = wildabbr;
1306 else {
1307 #ifdef ALL_STATE
1308 if (gmtptr == NULL)
1309 tmp->TM_ZONE = gmt;
1310 else tmp->TM_ZONE = gmtptr->chars;
1311 #endif /* defined ALL_STATE */
1312 #ifndef ALL_STATE
1313 tmp->TM_ZONE = gmtptr->chars;
1314 #endif /* State Farm */
1315 }
1316 #endif /* defined TM_ZONE */
1317 return result;
1318 }
1319
1320 // ============================================================================
1321 #if 0
1322 struct tm *
1323 gmtime(timep)
1324 const time_t * const timep;
1325 {
1326 return gmtsub(timep, 0L, &tm);
1327 }
1328 #endif
1329
1330 /*
1331 * Re-entrant version of gmtime.
1332 */
1333
1334 // ============================================================================
1335 #if 0
1336 struct tm *
1337 gmtime_r(timep, tmp)
1338 const time_t * const timep;
1339 struct tm * tmp;
1340 {
1341 return gmtsub(timep, 0L, tmp);
1342 }
1343 #endif
1344
1345 #ifdef STD_INSPIRED
1346
1347 // ============================================================================
1348 #if 0
1349 struct tm *
1350 offtime(timep, offset)
1351 const time_t * const timep;
1352 const long offset;
1353 {
1354 return gmtsub(timep, offset, &tm);
1355 }
1356 #endif
1357
1358 #endif /* defined STD_INSPIRED */
1359
1360 /*
1361 ** Return the number of leap years through the end of the given year
1362 ** where, to make the math easy, the answer for year zero is defined as zero.
1363 */
1364
1365 static int
1366 leaps_thru_end_of(y)
1367 register const int y;
1368 {
1369 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1370 -(leaps_thru_end_of(-(y + 1)) + 1);
1371 }
1372
1373 static struct tm *
1374 timesub(timep, offset, sp, tmp)
1375 const time_t * const timep;
1376 const long offset;
1377 register const struct state * const sp;
1378 register struct tm * const tmp;
1379 {
1380 register const struct lsinfo * lp;
1381 register time_t tdays;
1382 register int idays; /* unsigned would be so 2003 */
1383 register long rem;
1384 int y;
1385 register const int * ip;
1386 register long corr;
1387 register int hit;
1388 register int i;
1389
1390 corr = 0;
1391 hit = 0;
1392 #ifdef ALL_STATE
1393 i = (sp == NULL) ? 0 : sp->leapcnt;
1394 #endif /* defined ALL_STATE */
1395 #ifndef ALL_STATE
1396 i = sp->leapcnt;
1397 #endif /* State Farm */
1398 while (--i >= 0) {
1399 lp = &sp->lsis[i];
1400 if (*timep >= lp->ls_trans) {
1401 if (*timep == lp->ls_trans) {
1402 hit = ((i == 0 && lp->ls_corr > 0) ||
1403 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1404 if (hit)
1405 while (i > 0 &&
1406 sp->lsis[i].ls_trans ==
1407 sp->lsis[i - 1].ls_trans + 1 &&
1408 sp->lsis[i].ls_corr ==
1409 sp->lsis[i - 1].ls_corr + 1) {
1410 ++hit;
1411 --i;
1412 }
1413 }
1414 corr = lp->ls_corr;
1415 break;
1416 }
1417 }
1418 y = EPOCH_YEAR;
1419 tdays = *timep / SECSPERDAY;
1420 rem = *timep - tdays * SECSPERDAY;
1421 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1422 int newy;
1423 register time_t tdelta;
1424 register int idelta;
1425 register int leapdays;
1426
1427 tdelta = tdays / DAYSPERLYEAR;
1428 idelta = tdelta;
1429 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1430 return NULL;
1431 if (idelta == 0)
1432 idelta = (tdays < 0) ? -1 : 1;
1433 newy = y;
1434 if (increment_overflow(&newy, idelta))
1435 return NULL;
1436 leapdays = leaps_thru_end_of(newy - 1) -
1437 leaps_thru_end_of(y - 1);
1438 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1439 tdays -= leapdays;
1440 y = newy;
1441 }
1442 {
1443 register long seconds;
1444
1445 seconds = tdays * SECSPERDAY + 0.5;
1446 tdays = seconds / SECSPERDAY;
1447 rem += seconds - tdays * SECSPERDAY;
1448 }
1449 /*
1450 ** Given the range, we can now fearlessly cast...
1451 */
1452 idays = tdays;
1453 rem += offset - corr;
1454 while (rem < 0) {
1455 rem += SECSPERDAY;
1456 --idays;
1457 }
1458 while (rem >= SECSPERDAY) {
1459 rem -= SECSPERDAY;
1460 ++idays;
1461 }
1462 while (idays < 0) {
1463 if (increment_overflow(&y, -1))
1464 return NULL;
1465 idays += year_lengths[isleap(y)];
1466 }
1467 while (idays >= year_lengths[isleap(y)]) {
1468 idays -= year_lengths[isleap(y)];
1469 if (increment_overflow(&y, 1))
1470 return NULL;
1471 }
1472 tmp->tm_year = y;
1473 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1474 return NULL;
1475 tmp->tm_yday = idays;
1476 /*
1477 ** The "extra" mods below avoid overflow problems.
1478 */
1479 tmp->tm_wday = EPOCH_WDAY +
1480 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1481 (DAYSPERNYEAR % DAYSPERWEEK) +
1482 leaps_thru_end_of(y - 1) -
1483 leaps_thru_end_of(EPOCH_YEAR - 1) +
1484 idays;
1485 tmp->tm_wday %= DAYSPERWEEK;
1486 if (tmp->tm_wday < 0)
1487 tmp->tm_wday += DAYSPERWEEK;
1488 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1489 rem %= SECSPERHOUR;
1490 tmp->tm_min = (int) (rem / SECSPERMIN);
1491 /*
1492 ** A positive leap second requires a special
1493 ** representation. This uses "... ??:59:60" et seq.
1494 */
1495 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1496 ip = mon_lengths[isleap(y)];
1497 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1498 idays -= ip[tmp->tm_mon];
1499 tmp->tm_mday = (int) (idays + 1);
1500 tmp->tm_isdst = 0;
1501 #ifdef TM_GMTOFF
1502 tmp->TM_GMTOFF = offset;
1503 #endif /* defined TM_GMTOFF */
1504 return tmp;
1505 }
1506
1507 // ============================================================================
1508 #if 0
1509 char *
1510 ctime(timep)
1511 const time_t * const timep;
1512 {
1513 /*
1514 ** Section 4.12.3.2 of X3.159-1989 requires that
1515 ** The ctime function converts the calendar time pointed to by timer
1516 ** to local time in the form of a string. It is equivalent to
1517 ** asctime(localtime(timer))
1518 */
1519 return asctime(localtime(timep));
1520 }
1521 #endif
1522
1523 // ============================================================================
1524 #if 0
1525 char *
1526 ctime_r(timep, buf)
1527 const time_t * const timep;
1528 char * buf;
1529 {
1530 struct tm mytm;
1531
1532 return asctime_r(localtime_r(timep, &mytm), buf);
1533 }
1534 #endif
1535
1536 /*
1537 ** Adapted from code provided by Robert Elz, who writes:
1538 ** The "best" way to do mktime I think is based on an idea of Bob
1539 ** Kridle's (so its said...) from a long time ago.
1540 ** It does a binary search of the time_t space. Since time_t's are
1541 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1542 ** would still be very reasonable).
1543 */
1544
1545 #ifndef WRONG
1546 #define WRONG (-1)
1547 #endif /* !defined WRONG */
1548
1549 /*
1550 ** Simplified normalize logic courtesy Paul Eggert.
1551 */
1552
1553 static int
1554 increment_overflow(number, delta)
1555 int * number;
1556 int delta;
1557 {
1558 int number0;
1559
1560 number0 = *number;
1561 *number += delta;
1562 return (*number < number0) != (delta < 0);
1563 }
1564
1565 static int
1566 long_increment_overflow(number, delta)
1567 long * number;
1568 int delta;
1569 {
1570 long number0;
1571
1572 number0 = *number;
1573 *number += delta;
1574 return (*number < number0) != (delta < 0);
1575 }
1576
1577 static int
1578 normalize_overflow(tensptr, unitsptr, base)
1579 int * const tensptr;
1580 int * const unitsptr;
1581 const int base;
1582 {
1583 register int tensdelta;
1584
1585 tensdelta = (*unitsptr >= 0) ?
1586 (*unitsptr / base) :
1587 (-1 - (-1 - *unitsptr) / base);
1588 *unitsptr -= tensdelta * base;
1589 return increment_overflow(tensptr, tensdelta);
1590 }
1591
1592 static int
1593 long_normalize_overflow(tensptr, unitsptr, base)
1594 long * const tensptr;
1595 int * const unitsptr;
1596 const int base;
1597 {
1598 register int tensdelta;
1599
1600 tensdelta = (*unitsptr >= 0) ?
1601 (*unitsptr / base) :
1602 (-1 - (-1 - *unitsptr) / base);
1603 *unitsptr -= tensdelta * base;
1604 return long_increment_overflow(tensptr, tensdelta);
1605 }
1606
1607 static int
1608 tmcomp(atmp, btmp)
1609 register const struct tm * const atmp;
1610 register const struct tm * const btmp;
1611 {
1612 register int result;
1613
1614 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1615 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1616 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1617 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1618 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1619 result = atmp->tm_sec - btmp->tm_sec;
1620 return result;
1621 }
1622
1623 static time_t
1624 time2sub(tmp, funcp, offset, okayp, do_norm_secs, sp)
1625 struct tm * const tmp;
1626 struct tm * (* const funcp) P((const time_t*, long, struct tm*,const struct state *sp));
1627 const long offset;
1628 int * const okayp;
1629 const int do_norm_secs;
1630 const struct state * sp;
1631 {
1632 register int dir;
1633 register int i, j;
1634 register int saved_seconds;
1635 register long li;
1636 register time_t lo;
1637 register time_t hi;
1638 long y;
1639 time_t newt;
1640 time_t t;
1641 struct tm yourtm, mytm;
1642
1643 *okayp = FALSE;
1644 yourtm = *tmp;
1645 if (do_norm_secs) {
1646 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1647 SECSPERMIN))
1648 return WRONG;
1649 }
1650 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1651 return WRONG;
1652 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1653 return WRONG;
1654 y = yourtm.tm_year;
1655 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
1656 return WRONG;
1657 /*
1658 ** Turn y into an actual year number for now.
1659 ** It is converted back to an offset from TM_YEAR_BASE later.
1660 */
1661 if (long_increment_overflow(&y, TM_YEAR_BASE))
1662 return WRONG;
1663 while (yourtm.tm_mday <= 0) {
1664 if (long_increment_overflow(&y, -1))
1665 return WRONG;
1666 li = y + (1 < yourtm.tm_mon);
1667 yourtm.tm_mday += year_lengths[isleap(li)];
1668 }
1669 while (yourtm.tm_mday > DAYSPERLYEAR) {
1670 li = y + (1 < yourtm.tm_mon);
1671 yourtm.tm_mday -= year_lengths[isleap(li)];
1672 if (long_increment_overflow(&y, 1))
1673 return WRONG;
1674 }
1675 for ( ; ; ) {
1676 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1677 if (yourtm.tm_mday <= i)
1678 break;
1679 yourtm.tm_mday -= i;
1680 if (++yourtm.tm_mon >= MONSPERYEAR) {
1681 yourtm.tm_mon = 0;
1682 if (long_increment_overflow(&y, 1))
1683 return WRONG;
1684 }
1685 }
1686 if (long_increment_overflow(&y, -TM_YEAR_BASE))
1687 return WRONG;
1688 yourtm.tm_year = y;
1689 if (yourtm.tm_year != y)
1690 return WRONG;
1691 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1692 saved_seconds = 0;
1693 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1694 /*
1695 ** We can't set tm_sec to 0, because that might push the
1696 ** time below the minimum representable time.
1697 ** Set tm_sec to 59 instead.
1698 ** This assumes that the minimum representable time is
1699 ** not in the same minute that a leap second was deleted from,
1700 ** which is a safer assumption than using 58 would be.
1701 */
1702 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1703 return WRONG;
1704 saved_seconds = yourtm.tm_sec;
1705 yourtm.tm_sec = SECSPERMIN - 1;
1706 } else {
1707 saved_seconds = yourtm.tm_sec;
1708 yourtm.tm_sec = 0;
1709 }
1710 /*
1711 ** Do a binary search (this works whatever time_t's type is).
1712 */
1713 if (!TYPE_SIGNED(time_t)) {
1714 lo = 0;
1715 hi = lo - 1;
1716 } else if (!TYPE_INTEGRAL(time_t)) {
1717 if (sizeof(time_t) > sizeof(float))
1718 hi = (time_t) DBL_MAX;
1719 else hi = (time_t) FLT_MAX;
1720 lo = -hi;
1721 } else {
1722 lo = 1;
1723 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1724 lo *= 2;
1725 hi = -(lo + 1);
1726 }
1727 for ( ; ; ) {
1728 t = lo / 2 + hi / 2;
1729 if (t < lo)
1730 t = lo;
1731 else if (t > hi)
1732 t = hi;
1733 if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
1734 /*
1735 ** Assume that t is too extreme to be represented in
1736 ** a struct tm; arrange things so that it is less
1737 ** extreme on the next pass.
1738 */
1739 dir = (t > 0) ? 1 : -1;
1740 } else dir = tmcomp(&mytm, &yourtm);
1741 if (dir != 0) {
1742 if (t == lo) {
1743 ++t;
1744 if (t <= lo)
1745 return WRONG;
1746 ++lo;
1747 } else if (t == hi) {
1748 --t;
1749 if (t >= hi)
1750 return WRONG;
1751 --hi;
1752 }
1753 if (lo > hi)
1754 return WRONG;
1755 if (dir > 0)
1756 hi = t;
1757 else lo = t;
1758 continue;
1759 }
1760 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1761 break;
1762 /*
1763 ** Right time, wrong type.
1764 ** Hunt for right time, right type.
1765 ** It's okay to guess wrong since the guess
1766 ** gets checked.
1767 */
1768 /*
1769 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1770 */
1771 #ifdef ALL_STATE
1772 if (sp == NULL)
1773 return WRONG;
1774 #endif /* defined ALL_STATE */
1775 for (i = sp->typecnt - 1; i >= 0; --i) {
1776 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1777 continue;
1778 for (j = sp->typecnt - 1; j >= 0; --j) {
1779 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1780 continue;
1781 newt = t + sp->ttis[j].tt_gmtoff -
1782 sp->ttis[i].tt_gmtoff;
1783 if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
1784 continue;
1785 if (tmcomp(&mytm, &yourtm) != 0)
1786 continue;
1787 if (mytm.tm_isdst != yourtm.tm_isdst)
1788 continue;
1789 /*
1790 ** We have a match.
1791 */
1792 t = newt;
1793 goto label;
1794 }
1795 }
1796 return WRONG;
1797 }
1798 label:
1799 newt = t + saved_seconds;
1800 if ((newt < t) != (saved_seconds < 0))
1801 return WRONG;
1802 t = newt;
1803 if ((*funcp)(&t, offset, tmp, sp))
1804 *okayp = TRUE;
1805 return t;
1806 }
1807
1808 static time_t
1809 time2(tmp, funcp, offset, okayp, sp)
1810 struct tm * const tmp;
1811 struct tm * (* const funcp) P((const time_t*, long, struct tm*,
1812 const struct state* sp));
1813 const long offset;
1814 int * const okayp;
1815 const struct state * sp;
1816 {
1817 time_t t;
1818
1819 /*
1820 ** First try without normalization of seconds
1821 ** (in case tm_sec contains a value associated with a leap second).
1822 ** If that fails, try with normalization of seconds.
1823 */
1824 t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
1825 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
1826 }
1827
1828 static time_t
1829 time1(tmp, funcp, offset, sp)
1830 struct tm * const tmp;
1831 struct tm * (* const funcp) P((const time_t *, long, struct tm *, const struct state* sp));
1832 const long offset;
1833 const struct state * sp;
1834 {
1835 register time_t t;
1836 register int samei, otheri;
1837 register int sameind, otherind;
1838 register int i;
1839 register int nseen;
1840 int seen[TZ_MAX_TYPES];
1841 int types[TZ_MAX_TYPES];
1842 int okay;
1843
1844 if (tmp->tm_isdst > 1)
1845 tmp->tm_isdst = 1;
1846 t = time2(tmp, funcp, offset, &okay, sp);
1847 #define PCTS 1
1848 #ifdef PCTS
1849 /*
1850 ** PCTS code courtesy Grant Sullivan.
1851 */
1852 if (okay)
1853 return t;
1854 if (tmp->tm_isdst < 0)
1855 tmp->tm_isdst = 0; /* reset to std and try again */
1856 #endif /* defined PCTS */
1857 #ifndef PCTS
1858 if (okay || tmp->tm_isdst < 0)
1859 return t;
1860 #endif /* !defined PCTS */
1861 /*
1862 ** We're supposed to assume that somebody took a time of one type
1863 ** and did some math on it that yielded a "struct tm" that's bad.
1864 ** We try to divine the type they started from and adjust to the
1865 ** type they need.
1866 */
1867 /*
1868 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1869 */
1870 #ifdef ALL_STATE
1871 if (sp == NULL)
1872 return WRONG;
1873 #endif /* defined ALL_STATE */
1874 for (i = 0; i < sp->typecnt; ++i)
1875 seen[i] = FALSE;
1876 nseen = 0;
1877 for (i = sp->timecnt - 1; i >= 0; --i)
1878 if (!seen[sp->types[i]]) {
1879 seen[sp->types[i]] = TRUE;
1880 types[nseen++] = sp->types[i];
1881 }
1882 for (sameind = 0; sameind < nseen; ++sameind) {
1883 samei = types[sameind];
1884 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1885 continue;
1886 for (otherind = 0; otherind < nseen; ++otherind) {
1887 otheri = types[otherind];
1888 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1889 continue;
1890 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1891 sp->ttis[samei].tt_gmtoff;
1892 tmp->tm_isdst = !tmp->tm_isdst;
1893 t = time2(tmp, funcp, offset, &okay, sp);
1894 if (okay)
1895 return t;
1896 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1897 sp->ttis[samei].tt_gmtoff;
1898 tmp->tm_isdst = !tmp->tm_isdst;
1899 }
1900 }
1901 return WRONG;
1902 }
1903
1904 // ============================================================================
1905 time_t
1906 mktime_tz(struct tm * const tmp, char const * tz)
1907 {
1908 struct state st;
1909 if (tzload(tz, &st, TRUE) != 0) {
1910 // not sure what's best here, but for now, we fall back to gmt
1911 gmtload(&st);
1912 }
1913 return time1(tmp, localsub, 0L, &st);
1914 }
+0
-76
libcutils/uio.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef HAVE_SYS_UIO_H
17
18 #include <cutils/uio.h>
19 #include <unistd.h>
20
21 int readv( int fd, struct iovec* vecs, int count )
22 {
23 int total = 0;
24
25 for ( ; count > 0; count--, vecs++ ) {
26 const char* buf = vecs->iov_base;
27 int len = vecs->iov_len;
28
29 while (len > 0) {
30 int ret = read( fd, buf, len );
31 if (ret < 0) {
32 if (total == 0)
33 total = -1;
34 goto Exit;
35 }
36 if (ret == 0)
37 goto Exit;
38
39 total += ret;
40 buf += ret;
41 len -= ret;
42 }
43 }
44 Exit:
45 return total;
46 }
47
48 int writev( int fd, const struct iovec* vecs, int count )
49 {
50 int total = 0;
51
52 for ( ; count > 0; count--, vecs++ ) {
53 const char* buf = (const char*)vecs->iov_base;
54 int len = (int)vecs->iov_len;
55
56 while (len > 0) {
57 int ret = write( fd, buf, len );
58 if (ret < 0) {
59 if (total == 0)
60 total = -1;
61 goto Exit;
62 }
63 if (ret == 0)
64 goto Exit;
65
66 total += ret;
67 buf += ret;
68 len -= ret;
69 }
70 }
71 Exit:
72 return total;
73 }
74
75 #endif /* !HAVE_SYS_UIO_H */
+0
-267
libcutils/zygote.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "Zygote"
17
18 #include <cutils/sockets.h>
19 #include <cutils/zygote.h>
20 #include <cutils/log.h>
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <arpa/inet.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32
33 #define ZYGOTE_SOCKET "zygote"
34
35 #define ZYGOTE_RETRY_COUNT 1000
36 #define ZYGOTE_RETRY_MILLIS 500
37
38 static void replace_nl(char *str);
39
40 /*
41 * If sendStdio is non-zero, the current process's stdio file descriptors
42 * will be sent and inherited by the spawned process.
43 */
44 static int send_request(int fd, int sendStdio, int argc, const char **argv)
45 {
46 #ifndef HAVE_ANDROID_OS
47 // not supported on simulator targets
48 //LOGE("zygote_* not supported on simulator targets");
49 return -1;
50 #else /* HAVE_ANDROID_OS */
51 uint32_t pid;
52 int i;
53 struct iovec ivs[2];
54 struct msghdr msg;
55 char argc_buffer[12];
56 const char *newline_string = "\n";
57 struct cmsghdr *cmsg;
58 char msgbuf[CMSG_SPACE(sizeof(int) * 3)];
59 int *cmsg_payload;
60 ssize_t ret;
61
62 memset(&msg, 0, sizeof(msg));
63 memset(&ivs, 0, sizeof(ivs));
64
65 // First line is arg count
66 snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc);
67
68 ivs[0].iov_base = argc_buffer;
69 ivs[0].iov_len = strlen(argc_buffer);
70
71 msg.msg_iov = ivs;
72 msg.msg_iovlen = 1;
73
74 if (sendStdio != 0) {
75 // Pass the file descriptors with the first write
76 msg.msg_control = msgbuf;
77 msg.msg_controllen = sizeof msgbuf;
78
79 cmsg = CMSG_FIRSTHDR(&msg);
80
81 cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
82 cmsg->cmsg_level = SOL_SOCKET;
83 cmsg->cmsg_type = SCM_RIGHTS;
84
85 cmsg_payload = (int *)CMSG_DATA(cmsg);
86 cmsg_payload[0] = STDIN_FILENO;
87 cmsg_payload[1] = STDOUT_FILENO;
88 cmsg_payload[2] = STDERR_FILENO;
89 }
90
91 do {
92 ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
93 } while (ret < 0 && errno == EINTR);
94
95 if (ret < 0) {
96 return -1;
97 }
98
99 // Only send the fd's once
100 msg.msg_control = NULL;
101 msg.msg_controllen = 0;
102
103 // replace any newlines with spaces and send the args
104 for (i = 0; i < argc; i++) {
105 char *tofree = NULL;
106 const char *toprint;
107
108 toprint = argv[i];
109
110 if (strchr(toprint, '\n') != NULL) {
111 tofree = strdup(toprint);
112 toprint = tofree;
113 replace_nl(tofree);
114 }
115
116 ivs[0].iov_base = (char *)toprint;
117 ivs[0].iov_len = strlen(toprint);
118 ivs[1].iov_base = (char *)newline_string;
119 ivs[1].iov_len = 1;
120
121 msg.msg_iovlen = 2;
122
123 do {
124 ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
125 } while (ret < 0 && errno == EINTR);
126
127 if (tofree != NULL) {
128 free(tofree);
129 }
130
131 if (ret < 0) {
132 return -1;
133 }
134 }
135
136 // Read the pid, as a 4-byte network-order integer
137
138 ivs[0].iov_base = &pid;
139 ivs[0].iov_len = sizeof(pid);
140 msg.msg_iovlen = 1;
141
142 do {
143 do {
144 ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL);
145 } while (ret < 0 && errno == EINTR);
146
147 if (ret < 0) {
148 return -1;
149 }
150
151 ivs[0].iov_len -= ret;
152 ivs[0].iov_base += ret;
153 } while (ivs[0].iov_len > 0);
154
155 pid = ntohl(pid);
156
157 return pid;
158 #endif /* HAVE_ANDROID_OS */
159 }
160
161 int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int))
162 {
163 int fd;
164 int pid;
165 int err;
166 const char *newargv[argc + 1];
167
168 fd = socket_local_client(ZYGOTE_SOCKET,
169 ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL);
170
171 if (fd < 0) {
172 return -1;
173 }
174
175 // The command socket is passed to the peer as close-on-exec
176 // and will close when the peer dies
177 newargv[0] = "--peer-wait";
178 memcpy(newargv + 1, argv, argc * sizeof(*argv));
179
180 pid = send_request(fd, 1, argc + 1, newargv);
181
182 if (pid > 0 && post_run_func != NULL) {
183 post_run_func(pid);
184 }
185
186 // Wait for socket to close
187 do {
188 int dummy;
189 err = read(fd, &dummy, sizeof(dummy));
190 } while ((err < 0 && errno == EINTR) || err != 0);
191
192 do {
193 err = close(fd);
194 } while (err < 0 && errno == EINTR);
195
196 return 0;
197 }
198
199 /**
200 * Spawns a new dalvik instance via the Zygote process. The non-zygote
201 * arguments are passed to com.android.internal.os.RuntimeInit(). The
202 * first non-option argument should be a class name in the system class path.
203 *
204 * The arg list may start with zygote params such as --set-uid.
205 *
206 * If sendStdio is non-zero, the current process's stdio file descriptors
207 * will be sent and inherited by the spawned process.
208 *
209 * The pid of the child process is returned, or -1 if an error was
210 * encountered.
211 *
212 * zygote_run_oneshot waits up to ZYGOTE_RETRY_COUNT *
213 * ZYGOTE_RETRY_MILLIS for the zygote socket to be available.
214 */
215 int zygote_run_oneshot(int sendStdio, int argc, const char **argv)
216 {
217 int fd = -1;
218 int err;
219 int i;
220 int retries;
221 int pid;
222 const char **newargv = argv;
223 const int newargc = argc;
224
225 for (retries = 0; (fd < 0) && (retries < ZYGOTE_RETRY_COUNT); retries++) {
226 if (retries > 0) {
227 struct timespec ts;
228
229 memset(&ts, 0, sizeof(ts));
230 ts.tv_nsec = ZYGOTE_RETRY_MILLIS * 1000 * 1000;
231
232 do {
233 err = nanosleep (&ts, &ts);
234 } while (err < 0 && errno == EINTR);
235 }
236 fd = socket_local_client(ZYGOTE_SOCKET, AF_LOCAL,
237 ANDROID_SOCKET_NAMESPACE_RESERVED);
238 }
239
240 if (fd < 0) {
241 return -1;
242 }
243
244 pid = send_request(fd, 0, newargc, newargv);
245
246 do {
247 err = close(fd);
248 } while (err < 0 && errno == EINTR);
249
250 return pid;
251 }
252
253 /**
254 * Replaces all occurrances of newline with space.
255 */
256 static void replace_nl(char *str)
257 {
258 for(; *str; str++) {
259 if (*str == '\n') {
260 *str = ' ';
261 }
262 }
263 }
264
265
266
+0
-72
liblog/Android.mk less more
0 #
1 # Copyright (C) 2008 The Android Open Source Project
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 LOCAL_PATH := $(my-dir)
16 include $(CLEAR_VARS)
17
18 liblog_sources := logd_write.c
19
20 # some files must not be compiled when building against Mingw
21 # they correspond to features not used by our host development tools
22 # which are also hard or even impossible to port to native Win32
23 WITH_MINGW :=
24 ifeq ($(HOST_OS),windows)
25 ifeq ($(strip $(USE_CYGWIN)),)
26 WITH_MINGW := true
27 endif
28 endif
29 # USE_MINGW is defined when we build against Mingw on Linux
30 ifneq ($(strip $(USE_MINGW)),)
31 WITH_MINGW := true
32 endif
33
34 ifndef WITH_MINGW
35 liblog_sources += \
36 logprint.c \
37 event_tag_map.c
38 endif
39
40 liblog_host_sources := $(liblog_sources) fake_log_device.c
41
42 # Static library for host
43 # ========================================================
44 LOCAL_MODULE := liblog
45 LOCAL_SRC_FILES := $(liblog_host_sources)
46 LOCAL_LDLIBS := -lpthread
47 LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
48 include $(BUILD_HOST_STATIC_LIBRARY)
49
50 ifeq ($(TARGET_SIMULATOR),true)
51 # Shared library for simulator
52 # ========================================================
53 include $(CLEAR_VARS)
54 LOCAL_MODULE := liblog
55 LOCAL_SRC_FILES := $(liblog_host_sources)
56 LOCAL_LDLIBS := -lpthread
57 LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
58 include $(BUILD_SHARED_LIBRARY)
59 else # !sim
60 # Shared and static library for target
61 # ========================================================
62 include $(CLEAR_VARS)
63 LOCAL_MODULE := liblog
64 LOCAL_SRC_FILES := $(liblog_sources)
65 include $(BUILD_STATIC_LIBRARY)
66
67 include $(CLEAR_VARS)
68 LOCAL_MODULE := liblog
69 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
70 include $(BUILD_SHARED_LIBRARY)
71 endif # !sim
+0
-438
liblog/event_tag_map.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "cutils/event_tag_map.h"
16 #include "cutils/log.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <sys/mman.h>
22 #include <errno.h>
23 #include <assert.h>
24
25 #define OUT_TAG "EventTagMap"
26
27 /*
28 * Single entry.
29 */
30 typedef struct EventTag {
31 unsigned int tagIndex;
32 const char* tagStr;
33 } EventTag;
34
35 /*
36 * Map.
37 */
38 struct EventTagMap {
39 /* memory-mapped source file; we get strings from here */
40 void* mapAddr;
41 size_t mapLen;
42
43 /* array of event tags, sorted numerically by tag index */
44 EventTag* tagArray;
45 int numTags;
46 };
47
48 /* fwd */
49 static int processFile(EventTagMap* map);
50 static int countMapLines(const EventTagMap* map);
51 static int parseMapLines(EventTagMap* map);
52 static int scanTagLine(char** pData, EventTag* tag, int lineNum);
53 static int sortTags(EventTagMap* map);
54 static void dumpTags(const EventTagMap* map);
55
56
57 /*
58 * Open the map file and allocate a structure to manage it.
59 *
60 * We create a private mapping because we want to terminate the log tag
61 * strings with '\0'.
62 */
63 EventTagMap* android_openEventTagMap(const char* fileName)
64 {
65 EventTagMap* newTagMap;
66 off_t end;
67 int fd = -1;
68
69 newTagMap = calloc(1, sizeof(EventTagMap));
70 if (newTagMap == NULL)
71 return NULL;
72
73 fd = open(fileName, O_RDONLY);
74 if (fd < 0) {
75 fprintf(stderr, "%s: unable to open map '%s': %s\n",
76 OUT_TAG, fileName, strerror(errno));
77 goto fail;
78 }
79
80 end = lseek(fd, 0L, SEEK_END);
81 (void) lseek(fd, 0L, SEEK_SET);
82 if (end < 0) {
83 fprintf(stderr, "%s: unable to seek map '%s'\n", OUT_TAG, fileName);
84 goto fail;
85 }
86
87 newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE,
88 fd, 0);
89 if (newTagMap->mapAddr == MAP_FAILED) {
90 fprintf(stderr, "%s: mmap(%s) failed: %s\n",
91 OUT_TAG, fileName, strerror(errno));
92 goto fail;
93 }
94 newTagMap->mapLen = end;
95
96 if (processFile(newTagMap) != 0)
97 goto fail;
98
99 return newTagMap;
100
101 fail:
102 android_closeEventTagMap(newTagMap);
103 if (fd >= 0)
104 close(fd);
105 return NULL;
106 }
107
108 /*
109 * Close the map.
110 */
111 void android_closeEventTagMap(EventTagMap* map)
112 {
113 if (map == NULL)
114 return;
115
116 munmap(map->mapAddr, map->mapLen);
117 free(map);
118 }
119
120 /*
121 * Look up an entry in the map.
122 *
123 * The entries are sorted by tag number, so we can do a binary search.
124 */
125 const char* android_lookupEventTag(const EventTagMap* map, int tag)
126 {
127 int hi, lo, mid;
128
129 lo = 0;
130 hi = map->numTags-1;
131
132 while (lo <= hi) {
133 int cmp;
134
135 mid = (lo+hi)/2;
136 cmp = map->tagArray[mid].tagIndex - tag;
137 if (cmp < 0) {
138 /* tag is bigger */
139 lo = mid + 1;
140 } else if (cmp > 0) {
141 /* tag is smaller */
142 hi = mid - 1;
143 } else {
144 /* found */
145 return map->tagArray[mid].tagStr;
146 }
147 }
148
149 return NULL;
150 }
151
152
153
154 /*
155 * Determine whether "c" is a whitespace char.
156 */
157 static inline int isCharWhitespace(char c)
158 {
159 return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
160 }
161
162 /*
163 * Determine whether "c" is a valid tag char.
164 */
165 static inline int isCharValidTag(char c)
166 {
167 return ((c >= 'A' && c <= 'Z') ||
168 (c >= 'a' && c <= 'z') ||
169 (c >= '0' && c <= '9') ||
170 (c == '_'));
171 }
172
173 /*
174 * Determine whether "c" is a valid decimal digit.
175 */
176 static inline int isCharDigit(char c)
177 {
178 return (c >= '0' && c <= '9');
179 }
180
181
182 /*
183 * Crunch through the file, parsing the contents and creating a tag index.
184 */
185 static int processFile(EventTagMap* map)
186 {
187 EventTag* tagArray = NULL;
188
189 /* get a tag count */
190 map->numTags = countMapLines(map);
191 if (map->numTags < 0)
192 return -1;
193
194 //printf("+++ found %d tags\n", map->numTags);
195
196 /* allocate storage for the tag index array */
197 map->tagArray = calloc(1, sizeof(EventTag) * map->numTags);
198 if (map->tagArray == NULL)
199 return -1;
200
201 /* parse the file, null-terminating tag strings */
202 if (parseMapLines(map) != 0) {
203 fprintf(stderr, "%s: file parse failed\n", OUT_TAG);
204 return -1;
205 }
206
207 /* sort the tags and check for duplicates */
208 if (sortTags(map) != 0)
209 return -1;
210
211 return 0;
212 }
213
214 /*
215 * Run through all lines in the file, determining whether they're blank,
216 * comments, or possibly have a tag entry.
217 *
218 * This is a very "loose" scan. We don't try to detect syntax errors here.
219 * The later pass is more careful, but the number of tags found there must
220 * match the number of tags found here.
221 *
222 * Returns the number of potential tag entries found.
223 */
224 static int countMapLines(const EventTagMap* map)
225 {
226 int numTags, unknown;
227 const char* cp;
228 const char* endp;
229
230 cp = (const char*) map->mapAddr;
231 endp = cp + map->mapLen;
232
233 numTags = 0;
234 unknown = 1;
235 while (cp < endp) {
236 if (*cp == '\n') {
237 unknown = 1;
238 } else if (unknown) {
239 if (isCharDigit(*cp)) {
240 /* looks like a tag to me */
241 numTags++;
242 unknown = 0;
243 } else if (isCharWhitespace(*cp)) {
244 /* might be leading whitespace before tag num, keep going */
245 } else {
246 /* assume comment; second pass can complain in detail */
247 unknown = 0;
248 }
249 } else {
250 /* we've made up our mind; just scan to end of line */
251 }
252 cp++;
253 }
254
255 return numTags;
256 }
257
258 /*
259 * Parse the tags out of the file.
260 */
261 static int parseMapLines(EventTagMap* map)
262 {
263 int tagNum, lineStart, lineNum;
264 char* cp;
265 char* endp;
266
267 cp = (char*) map->mapAddr;
268 endp = cp + map->mapLen;
269
270 /* insist on EOL at EOF; simplifies parsing and null-termination */
271 if (*(endp-1) != '\n') {
272 fprintf(stderr, "%s: map file missing EOL on last line\n", OUT_TAG);
273 return -1;
274 }
275
276 tagNum = 0;
277 lineStart = 1;
278 lineNum = 1;
279 while (cp < endp) {
280 //printf("{%02x}", *cp); fflush(stdout);
281 if (*cp == '\n') {
282 lineStart = 1;
283 lineNum++;
284 } else if (lineStart) {
285 if (*cp == '#') {
286 /* comment; just scan to end */
287 lineStart = 0;
288 } else if (isCharDigit(*cp)) {
289 /* looks like a tag; scan it out */
290 if (tagNum >= map->numTags) {
291 fprintf(stderr,
292 "%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
293 return -1;
294 }
295 if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0)
296 return -1;
297 tagNum++;
298 lineNum++; // we eat the '\n'
299 /* leave lineStart==1 */
300 } else if (isCharWhitespace(*cp)) {
301 /* looks like leading whitespace; keep scanning */
302 } else {
303 fprintf(stderr,
304 "%s: unexpected chars (0x%02x) in tag number on line %d\n",
305 OUT_TAG, *cp, lineNum);
306 return -1;
307 }
308 } else {
309 /* this is a blank or comment line */
310 }
311 cp++;
312 }
313
314 if (tagNum != map->numTags) {
315 fprintf(stderr, "%s: parsed %d tags, expected %d\n",
316 OUT_TAG, tagNum, map->numTags);
317 return -1;
318 }
319
320 return 0;
321 }
322
323 /*
324 * Scan one tag line.
325 *
326 * "*pData" should be pointing to the first digit in the tag number. On
327 * successful return, it will be pointing to the last character in the
328 * tag line (i.e. the character before the start of the next line).
329 *
330 * Returns 0 on success, nonzero on failure.
331 */
332 static int scanTagLine(char** pData, EventTag* tag, int lineNum)
333 {
334 char* cp = *pData;
335 char* startp;
336 char* endp;
337 unsigned long val;
338
339 startp = cp;
340 while (isCharDigit(*++cp))
341 ;
342 *cp = '\0';
343
344 val = strtoul(startp, &endp, 10);
345 assert(endp == cp);
346 if (endp != cp)
347 fprintf(stderr, "ARRRRGH\n");
348
349 tag->tagIndex = val;
350
351 while (*++cp != '\n' && isCharWhitespace(*cp))
352 ;
353
354 if (*cp == '\n') {
355 fprintf(stderr,
356 "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
357 return -1;
358 }
359
360 tag->tagStr = cp;
361
362 while (isCharValidTag(*++cp))
363 ;
364
365 if (*cp == '\n') {
366 /* null terminate and return */
367 *cp = '\0';
368 } else if (isCharWhitespace(*cp)) {
369 /* CRLF or trailin spaces; zap this char, then scan for the '\n' */
370 *cp = '\0';
371
372 /* just ignore the rest of the line till \n
373 TODO: read the tag description that follows the tag name
374 */
375 while (*++cp != '\n') {
376 }
377 } else {
378 fprintf(stderr,
379 "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
380 return -1;
381 }
382
383 *pData = cp;
384
385 //printf("+++ Line %d: got %d '%s'\n", lineNum, tag->tagIndex, tag->tagStr);
386 return 0;
387 }
388
389 /*
390 * Compare two EventTags.
391 */
392 static int compareEventTags(const void* v1, const void* v2)
393 {
394 const EventTag* tag1 = (const EventTag*) v1;
395 const EventTag* tag2 = (const EventTag*) v2;
396
397 return tag1->tagIndex - tag2->tagIndex;
398 }
399
400 /*
401 * Sort the EventTag array so we can do fast lookups by tag index. After
402 * the sort we do a quick check for duplicate tag indices.
403 *
404 * Returns 0 on success.
405 */
406 static int sortTags(EventTagMap* map)
407 {
408 int i;
409
410 qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
411
412 for (i = 1; i < map->numTags; i++) {
413 if (map->tagArray[i].tagIndex == map->tagArray[i-1].tagIndex) {
414 fprintf(stderr, "%s: duplicate tag entries (%d:%s and %d:%s)\n",
415 OUT_TAG,
416 map->tagArray[i].tagIndex, map->tagArray[i].tagStr,
417 map->tagArray[i-1].tagIndex, map->tagArray[i-1].tagStr);
418 return -1;
419 }
420 }
421
422 return 0;
423 }
424
425 /*
426 * Dump the tag array for debugging.
427 */
428 static void dumpTags(const EventTagMap* map)
429 {
430 int i;
431
432 for (i = 0; i < map->numTags; i++) {
433 const EventTag* tag = &map->tagArray[i];
434 printf(" %3d: %6d '%s'\n", i, tag->tagIndex, tag->tagStr);
435 }
436 }
437
+0
-677
liblog/fake_log_device.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 /*
16 * Intercepts log messages intended for the Android log device.
17 * When running in the context of the simulator, the messages are
18 * passed on to the underlying (fake) log device. When not in the
19 * simulator, messages are printed to stderr.
20 */
21 #include "cutils/logd.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <fcntl.h>
28
29 #ifdef HAVE_PTHREADS
30 #include <pthread.h>
31 #endif
32
33 #define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
34
35 #define kTagSetSize 16 /* arbitrary */
36
37 #if 0
38 #define TRACE(...) printf("fake_log_device: " __VA_ARGS__)
39 #else
40 #define TRACE(...) ((void)0)
41 #endif
42
43 /* from the long-dead utils/Log.cpp */
44 typedef enum {
45 FORMAT_OFF = 0,
46 FORMAT_BRIEF,
47 FORMAT_PROCESS,
48 FORMAT_TAG,
49 FORMAT_THREAD,
50 FORMAT_RAW,
51 FORMAT_TIME,
52 FORMAT_THREADTIME,
53 FORMAT_LONG
54 } LogFormat;
55
56
57 /*
58 * Log driver state.
59 */
60 typedef struct LogState {
61 /* the fake fd that's seen by the user */
62 int fakeFd;
63
64 /* a printable name for this fake device */
65 char *debugName;
66
67 /* nonzero if this is a binary log */
68 int isBinary;
69
70 /* global minimum priority */
71 int globalMinPriority;
72
73 /* output format */
74 LogFormat outputFormat;
75
76 /* tags and priorities */
77 struct {
78 char tag[kMaxTagLen];
79 int minPriority;
80 } tagSet[kTagSetSize];
81 } LogState;
82
83
84 #ifdef HAVE_PTHREADS
85 /*
86 * Locking. Since we're emulating a device, we need to be prepared
87 * to have multiple callers at the same time. This lock is used
88 * to both protect the fd list and to prevent LogStates from being
89 * freed out from under a user.
90 */
91 static pthread_mutex_t fakeLogDeviceLock = PTHREAD_MUTEX_INITIALIZER;
92
93 static void lock()
94 {
95 pthread_mutex_lock(&fakeLogDeviceLock);
96 }
97
98 static void unlock()
99 {
100 pthread_mutex_unlock(&fakeLogDeviceLock);
101 }
102 #else // !HAVE_PTHREADS
103 #define lock() ((void)0)
104 #define unlock() ((void)0)
105 #endif // !HAVE_PTHREADS
106
107
108 /*
109 * File descriptor management.
110 */
111 #define FAKE_FD_BASE 10000
112 #define MAX_OPEN_LOGS 16
113 static LogState *openLogTable[MAX_OPEN_LOGS];
114
115 /*
116 * Allocate an fd and associate a new LogState with it.
117 * The fd is available via the fakeFd field of the return value.
118 */
119 static LogState *createLogState()
120 {
121 size_t i;
122
123 for (i = 0; i < sizeof(openLogTable); i++) {
124 if (openLogTable[i] == NULL) {
125 openLogTable[i] = calloc(1, sizeof(LogState));
126 openLogTable[i]->fakeFd = FAKE_FD_BASE + i;
127 return openLogTable[i];
128 }
129 }
130 return NULL;
131 }
132
133 /*
134 * Translate an fd to a LogState.
135 */
136 static LogState *fdToLogState(int fd)
137 {
138 if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) {
139 return openLogTable[fd - FAKE_FD_BASE];
140 }
141 return NULL;
142 }
143
144 /*
145 * Unregister the fake fd and free the memory it pointed to.
146 */
147 static void deleteFakeFd(int fd)
148 {
149 LogState *ls;
150
151 lock();
152
153 ls = fdToLogState(fd);
154 if (ls != NULL) {
155 openLogTable[fd - FAKE_FD_BASE] = NULL;
156 free(ls->debugName);
157 free(ls);
158 }
159
160 unlock();
161 }
162
163 /*
164 * Configure logging based on ANDROID_LOG_TAGS environment variable. We
165 * need to parse a string that looks like
166 *
167 * *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
168 *
169 * The tag (or '*' for the global level) comes first, followed by a colon
170 * and a letter indicating the minimum priority level we're expected to log.
171 * This can be used to reveal or conceal logs with specific tags.
172 *
173 * We also want to check ANDROID_PRINTF_LOG to determine how the output
174 * will look.
175 */
176 static void configureInitialState(const char* pathName, LogState* logState)
177 {
178 static const int kDevLogLen = sizeof("/dev/log/") - 1;
179
180 logState->debugName = strdup(pathName);
181
182 /* identify binary logs */
183 if (strcmp(pathName + kDevLogLen, "events") == 0) {
184 logState->isBinary = 1;
185 }
186
187 /* global min priority defaults to "info" level */
188 logState->globalMinPriority = ANDROID_LOG_INFO;
189
190 /*
191 * This is based on the the long-dead utils/Log.cpp code.
192 */
193 const char* tags = getenv("ANDROID_LOG_TAGS");
194 TRACE("Found ANDROID_LOG_TAGS='%s'\n", tags);
195 if (tags != NULL) {
196 int entry = 0;
197
198 while (*tags != '\0') {
199 char tagName[kMaxTagLen];
200 int i, minPrio;
201
202 while (isspace(*tags))
203 tags++;
204
205 i = 0;
206 while (*tags != '\0' && !isspace(*tags) && *tags != ':' &&
207 i < kMaxTagLen)
208 {
209 tagName[i++] = *tags++;
210 }
211 if (i == kMaxTagLen) {
212 TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen-1);
213 return;
214 }
215 tagName[i] = '\0';
216
217 /* default priority, if there's no ":" part; also zero out '*' */
218 minPrio = ANDROID_LOG_VERBOSE;
219 if (tagName[0] == '*' && tagName[1] == '\0') {
220 minPrio = ANDROID_LOG_DEBUG;
221 tagName[0] = '\0';
222 }
223
224 if (*tags == ':') {
225 tags++;
226 if (*tags >= '0' && *tags <= '9') {
227 if (*tags >= ('0' + ANDROID_LOG_SILENT))
228 minPrio = ANDROID_LOG_VERBOSE;
229 else
230 minPrio = *tags - '\0';
231 } else {
232 switch (*tags) {
233 case 'v': minPrio = ANDROID_LOG_VERBOSE; break;
234 case 'd': minPrio = ANDROID_LOG_DEBUG; break;
235 case 'i': minPrio = ANDROID_LOG_INFO; break;
236 case 'w': minPrio = ANDROID_LOG_WARN; break;
237 case 'e': minPrio = ANDROID_LOG_ERROR; break;
238 case 'f': minPrio = ANDROID_LOG_FATAL; break;
239 case 's': minPrio = ANDROID_LOG_SILENT; break;
240 default: minPrio = ANDROID_LOG_DEFAULT; break;
241 }
242 }
243
244 tags++;
245 if (*tags != '\0' && !isspace(*tags)) {
246 TRACE("ERROR: garbage in tag env; expected whitespace\n");
247 TRACE(" env='%s'\n", tags);
248 return;
249 }
250 }
251
252 if (tagName[0] == 0) {
253 logState->globalMinPriority = minPrio;
254 TRACE("+++ global min prio %d\n", logState->globalMinPriority);
255 } else {
256 logState->tagSet[entry].minPriority = minPrio;
257 strcpy(logState->tagSet[entry].tag, tagName);
258 TRACE("+++ entry %d: %s:%d\n",
259 entry,
260 logState->tagSet[entry].tag,
261 logState->tagSet[entry].minPriority);
262 entry++;
263 }
264 }
265 }
266
267
268 /*
269 * Taken from the long-dead utils/Log.cpp
270 */
271 const char* fstr = getenv("ANDROID_PRINTF_LOG");
272 LogFormat format;
273 if (fstr == NULL) {
274 format = FORMAT_BRIEF;
275 } else {
276 if (strcmp(fstr, "brief") == 0)
277 format = FORMAT_BRIEF;
278 else if (strcmp(fstr, "process") == 0)
279 format = FORMAT_PROCESS;
280 else if (strcmp(fstr, "tag") == 0)
281 format = FORMAT_PROCESS;
282 else if (strcmp(fstr, "thread") == 0)
283 format = FORMAT_PROCESS;
284 else if (strcmp(fstr, "raw") == 0)
285 format = FORMAT_PROCESS;
286 else if (strcmp(fstr, "time") == 0)
287 format = FORMAT_PROCESS;
288 else if (strcmp(fstr, "long") == 0)
289 format = FORMAT_PROCESS;
290 else
291 format = (LogFormat) atoi(fstr); // really?!
292 }
293
294 logState->outputFormat = format;
295 }
296
297 /*
298 * Return a human-readable string for the priority level. Always returns
299 * a valid string.
300 */
301 static const char* getPriorityString(int priority)
302 {
303 /* the first character of each string should be unique */
304 static const char* priorityStrings[] = {
305 "Verbose", "Debug", "Info", "Warn", "Error", "Assert"
306 };
307 int idx;
308
309 idx = (int) priority - (int) ANDROID_LOG_VERBOSE;
310 if (idx < 0 ||
311 idx >= (int) (sizeof(priorityStrings) / sizeof(priorityStrings[0])))
312 return "?unknown?";
313 return priorityStrings[idx];
314 }
315
316 #ifndef HAVE_WRITEV
317 /*
318 * Some platforms like WIN32 do not have writev().
319 * Make up something to replace it.
320 */
321 static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
322 int result = 0;
323 struct iovec* end = iov + iovcnt;
324 for (; iov < end; iov++) {
325 int w = write(fd, iov->iov_base, iov->iov_len);
326 if (w != iov->iov_len) {
327 if (w < 0)
328 return w;
329 return result + w;
330 }
331 result += w;
332 }
333 return result;
334 }
335
336 #define writev fake_writev
337 #endif
338
339
340 /*
341 * Write a filtered log message to stderr.
342 *
343 * Log format parsing taken from the long-dead utils/Log.cpp.
344 */
345 static void showLog(LogState *state,
346 int logPrio, const char* tag, const char* msg)
347 {
348 #if defined(HAVE_LOCALTIME_R)
349 struct tm tmBuf;
350 #endif
351 struct tm* ptm;
352 char timeBuf[32];
353 char prefixBuf[128], suffixBuf[128];
354 char priChar;
355 time_t when;
356 pid_t pid, tid;
357
358 TRACE("LOG %d: %s %s", logPrio, tag, msg);
359
360 priChar = getPriorityString(logPrio)[0];
361 when = time(NULL);
362 pid = tid = getpid(); // find gettid()?
363
364 /*
365 * Get the current date/time in pretty form
366 *
367 * It's often useful when examining a log with "less" to jump to
368 * a specific point in the file by searching for the date/time stamp.
369 * For this reason it's very annoying to have regexp meta characters
370 * in the time stamp. Don't use forward slashes, parenthesis,
371 * brackets, asterisks, or other special chars here.
372 */
373 #if defined(HAVE_LOCALTIME_R)
374 ptm = localtime_r(&when, &tmBuf);
375 #else
376 ptm = localtime(&when);
377 #endif
378 //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
379 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
380
381 /*
382 * Construct a buffer containing the log header and log message.
383 */
384 size_t prefixLen, suffixLen;
385
386 switch (state->outputFormat) {
387 case FORMAT_TAG:
388 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
389 "%c/%-8s: ", priChar, tag);
390 strcpy(suffixBuf, "\n"); suffixLen = 1;
391 break;
392 case FORMAT_PROCESS:
393 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
394 "%c(%5d) ", priChar, pid);
395 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
396 " (%s)\n", tag);
397 break;
398 case FORMAT_THREAD:
399 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
400 "%c(%5d:%p) ", priChar, pid, (void*)tid);
401 strcpy(suffixBuf, "\n"); suffixLen = 1;
402 break;
403 case FORMAT_RAW:
404 prefixBuf[0] = 0; prefixLen = 0;
405 strcpy(suffixBuf, "\n"); suffixLen = 1;
406 break;
407 case FORMAT_TIME:
408 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
409 "%s %-8s\n\t", timeBuf, tag);
410 strcpy(suffixBuf, "\n"); suffixLen = 1;
411 break;
412 case FORMAT_THREADTIME:
413 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
414 "%s %5d %5d %c %-8s \n\t", timeBuf, pid, tid, priChar, tag);
415 strcpy(suffixBuf, "\n"); suffixLen = 1;
416 break;
417 case FORMAT_LONG:
418 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
419 "[ %s %5d:%p %c/%-8s ]\n",
420 timeBuf, pid, (void*)tid, priChar, tag);
421 strcpy(suffixBuf, "\n\n"); suffixLen = 2;
422 break;
423 default:
424 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
425 "%c/%-8s(%5d): ", priChar, tag, pid);
426 strcpy(suffixBuf, "\n"); suffixLen = 1;
427 break;
428 }
429
430 /*
431 * Figure out how many lines there will be.
432 */
433 const char* end = msg + strlen(msg);
434 size_t numLines = 0;
435 const char* p = msg;
436 while (p < end) {
437 if (*p++ == '\n') numLines++;
438 }
439 if (p > msg && *(p-1) != '\n') numLines++;
440
441 /*
442 * Create an array of iovecs large enough to write all of
443 * the lines with a prefix and a suffix.
444 */
445 const size_t INLINE_VECS = 6;
446 struct iovec stackVec[INLINE_VECS];
447 struct iovec* vec = stackVec;
448
449 numLines *= 3; // 3 iovecs per line.
450 if (numLines > INLINE_VECS) {
451 vec = (struct iovec*)malloc(sizeof(struct iovec)*numLines);
452 if (vec == NULL) {
453 msg = "LOG: write failed, no memory";
454 numLines = 3;
455 }
456 }
457
458 /*
459 * Fill in the iovec pointers.
460 */
461 p = msg;
462 struct iovec* v = vec;
463 int totalLen = 0;
464 while (p < end) {
465 if (prefixLen > 0) {
466 v->iov_base = prefixBuf;
467 v->iov_len = prefixLen;
468 totalLen += prefixLen;
469 v++;
470 }
471 const char* start = p;
472 while (p < end && *p != '\n') p++;
473 if ((p-start) > 0) {
474 v->iov_base = (void*)start;
475 v->iov_len = p-start;
476 totalLen += p-start;
477 v++;
478 }
479 if (*p == '\n') p++;
480 if (suffixLen > 0) {
481 v->iov_base = suffixBuf;
482 v->iov_len = suffixLen;
483 totalLen += suffixLen;
484 v++;
485 }
486 }
487
488 /*
489 * Write the entire message to the log file with a single writev() call.
490 * We need to use this rather than a collection of printf()s on a FILE*
491 * because of multi-threading and multi-process issues.
492 *
493 * If the file was not opened with O_APPEND, this will produce interleaved
494 * output when called on the same file from multiple processes.
495 *
496 * If the file descriptor is actually a network socket, the writev()
497 * call may return with a partial write. Putting the writev() call in
498 * a loop can result in interleaved data. This can be alleviated
499 * somewhat by wrapping the writev call in the Mutex.
500 */
501
502 for(;;) {
503 int cc = writev(fileno(stderr), vec, v-vec);
504
505 if (cc == totalLen) break;
506
507 if (cc < 0) {
508 if(errno == EINTR) continue;
509
510 /* can't really log the failure; for now, throw out a stderr */
511 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
512 break;
513 } else {
514 /* shouldn't happen when writing to file or tty */
515 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen);
516 break;
517 }
518 }
519
520 /* if we allocated storage for the iovecs, free it */
521 if (vec != stackVec)
522 free(vec);
523 }
524
525
526 /*
527 * Receive a log message. We happen to know that "vector" has three parts:
528 *
529 * priority (1 byte)
530 * tag (N bytes -- null-terminated ASCII string)
531 * message (N bytes -- null-terminated ASCII string)
532 */
533 static ssize_t logWritev(int fd, const struct iovec* vector, int count)
534 {
535 LogState* state;
536
537 /* Make sure that no-one frees the LogState while we're using it.
538 * Also guarantees that only one thread is in showLog() at a given
539 * time (if it matters).
540 */
541 lock();
542
543 state = fdToLogState(fd);
544 if (state == NULL) {
545 errno = EBADF;
546 goto error;
547 }
548
549 if (state->isBinary) {
550 TRACE("%s: ignoring binary log\n", state->debugName);
551 goto bail;
552 }
553
554 if (count != 3) {
555 TRACE("%s: writevLog with count=%d not expected\n",
556 state->debugName, count);
557 goto error;
558 }
559
560 /* pull out the three fields */
561 int logPrio = *(const char*)vector[0].iov_base;
562 const char* tag = (const char*) vector[1].iov_base;
563 const char* msg = (const char*) vector[2].iov_base;
564
565 /* see if this log tag is configured */
566 int i;
567 int minPrio = state->globalMinPriority;
568 for (i = 0; i < kTagSetSize; i++) {
569 if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN)
570 break; /* reached end of configured values */
571
572 if (strcmp(state->tagSet[i].tag, tag) == 0) {
573 //TRACE("MATCH tag '%s'\n", tag);
574 minPrio = state->tagSet[i].minPriority;
575 break;
576 }
577 }
578
579 if (logPrio >= minPrio) {
580 showLog(state, logPrio, tag, msg);
581 } else {
582 //TRACE("+++ NOLOG(%d): %s %s", logPrio, tag, msg);
583 }
584
585 bail:
586 unlock();
587 return vector[0].iov_len + vector[1].iov_len + vector[2].iov_len;
588 error:
589 unlock();
590 return -1;
591 }
592
593 /*
594 * Free up our state and close the fake descriptor.
595 */
596 static int logClose(int fd)
597 {
598 deleteFakeFd(fd);
599 return 0;
600 }
601
602 /*
603 * Open a log output device and return a fake fd.
604 */
605 static int logOpen(const char* pathName, int flags)
606 {
607 LogState *logState;
608 int fd = -1;
609
610 lock();
611
612 logState = createLogState();
613 if (logState != NULL) {
614 configureInitialState(pathName, logState);
615 fd = logState->fakeFd;
616 } else {
617 errno = ENFILE;
618 }
619
620 unlock();
621
622 return fd;
623 }
624
625
626 /*
627 * Runtime redirection. If this binary is running in the simulator,
628 * just pass log messages to the emulated device. If it's running
629 * outside of the simulator, write the log messages to stderr.
630 */
631
632 static int (*redirectOpen)(const char *pathName, int flags) = NULL;
633 static int (*redirectClose)(int fd) = NULL;
634 static ssize_t (*redirectWritev)(int fd, const struct iovec* vector, int count)
635 = NULL;
636
637 static void setRedirects()
638 {
639 const char *ws;
640
641 /* Wrapsim sets this environment variable on children that it's
642 * created using its LD_PRELOAD wrapper.
643 */
644 ws = getenv("ANDROID_WRAPSIM");
645 if (ws != NULL && strcmp(ws, "1") == 0) {
646 /* We're running inside wrapsim, so we can just write to the device. */
647 redirectOpen = (int (*)(const char *pathName, int flags))open;
648 redirectClose = close;
649 redirectWritev = writev;
650 } else {
651 /* There's no device to delegate to; handle the logging ourselves. */
652 redirectOpen = logOpen;
653 redirectClose = logClose;
654 redirectWritev = logWritev;
655 }
656 }
657
658 int fakeLogOpen(const char *pathName, int flags)
659 {
660 if (redirectOpen == NULL) {
661 setRedirects();
662 }
663 return redirectOpen(pathName, flags);
664 }
665
666 int fakeLogClose(int fd)
667 {
668 /* Assume that open() was called first. */
669 return redirectClose(fd);
670 }
671
672 ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count)
673 {
674 /* Assume that open() was called first. */
675 return redirectWritev(fd, vector, count);
676 }
+0
-230
liblog/logd_write.c less more
0 /*
1 * Copyright (C) 2007 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <time.h>
16 #include <stdio.h>
17 #ifdef HAVE_PTHREADS
18 #include <pthread.h>
19 #endif
20 #include <unistd.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26
27 #include <cutils/logger.h>
28 #include <cutils/logd.h>
29
30 #define LOG_BUF_SIZE 1024
31
32 #if FAKE_LOG_DEVICE
33 // This will be defined when building for the host.
34 #define log_open(pathname, flags) fakeLogOpen(pathname, flags)
35 #define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
36 #define log_close(filedes) fakeLogClose(filedes)
37 #else
38 #define log_open(pathname, flags) open(pathname, flags)
39 #define log_writev(filedes, vector, count) writev(filedes, vector, count)
40 #define log_close(filedes) close(filedes)
41 #endif
42
43 typedef enum {
44 LOG_ID_MAIN = 0,
45 LOG_ID_RADIO,
46 LOG_ID_EVENTS,
47 LOG_ID_MAX
48 } log_id_t;
49
50 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
51 static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) =
52 __write_to_log_init;
53 #ifdef HAVE_PTHREADS
54 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
55 #endif
56
57 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1 };
58
59 /*
60 * This is used by the C++ code to decide if it should write logs through
61 * the C code. Basically, if /dev/log/... is available, we're running in
62 * the simulator rather than a desktop tool and want to use the device.
63 */
64 static enum {
65 kLogUninitialized, kLogNotAvailable, kLogAvailable
66 } g_log_status = kLogUninitialized;
67 int __android_log_dev_available(void)
68 {
69 if (g_log_status == kLogUninitialized) {
70 if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0)
71 g_log_status = kLogAvailable;
72 else
73 g_log_status = kLogNotAvailable;
74 }
75
76 return (g_log_status == kLogAvailable);
77 }
78
79 static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)
80 {
81 return -1;
82 }
83
84 static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
85 {
86 ssize_t ret;
87 int log_fd;
88
89 if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
90 log_fd = log_fds[(int)log_id];
91 } else {
92 return EBADF;
93 }
94
95 do {
96 ret = log_writev(log_fd, vec, nr);
97 } while (ret < 0 && errno == EINTR);
98
99 return ret;
100 }
101
102 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
103 {
104 #ifdef HAVE_PTHREADS
105 pthread_mutex_lock(&log_init_lock);
106 #endif
107
108 if (write_to_log == __write_to_log_init) {
109 log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
110 log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
111 log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
112
113 write_to_log = __write_to_log_kernel;
114
115 if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
116 log_fds[LOG_ID_EVENTS] < 0) {
117 log_close(log_fds[LOG_ID_MAIN]);
118 log_close(log_fds[LOG_ID_RADIO]);
119 log_close(log_fds[LOG_ID_EVENTS]);
120 log_fds[LOG_ID_MAIN] = -1;
121 log_fds[LOG_ID_RADIO] = -1;
122 log_fds[LOG_ID_EVENTS] = -1;
123 write_to_log = __write_to_log_null;
124 }
125 }
126
127 #ifdef HAVE_PTHREADS
128 pthread_mutex_unlock(&log_init_lock);
129 #endif
130
131 return write_to_log(log_id, vec, nr);
132 }
133
134 int __android_log_write(int prio, const char *tag, const char *msg)
135 {
136 struct iovec vec[3];
137 log_id_t log_id = LOG_ID_MAIN;
138
139 if (!tag)
140 tag = "";
141
142 /* XXX: This needs to go! */
143 if (!strcmp(tag, "HTC_RIL") ||
144 !strcmp(tag, "RILJ") ||
145 !strcmp(tag, "RILC") ||
146 !strcmp(tag, "RILD") ||
147 !strcmp(tag, "RIL") ||
148 !strcmp(tag, "AT") ||
149 !strcmp(tag, "GSM") ||
150 !strcmp(tag, "STK"))
151 log_id = LOG_ID_RADIO;
152
153 vec[0].iov_base = (unsigned char *) &prio;
154 vec[0].iov_len = 1;
155 vec[1].iov_base = (void *) tag;
156 vec[1].iov_len = strlen(tag) + 1;
157 vec[2].iov_base = (void *) msg;
158 vec[2].iov_len = strlen(msg) + 1;
159
160 return write_to_log(log_id, vec, 3);
161 }
162
163 int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
164 {
165 char buf[LOG_BUF_SIZE];
166
167 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
168
169 return __android_log_write(prio, tag, buf);
170 }
171
172 int __android_log_print(int prio, const char *tag, const char *fmt, ...)
173 {
174 va_list ap;
175 char buf[LOG_BUF_SIZE];
176
177 va_start(ap, fmt);
178 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
179 va_end(ap);
180
181 return __android_log_write(prio, tag, buf);
182 }
183
184 void __android_log_assert(const char *cond, const char *tag,
185 const char *fmt, ...)
186 {
187 va_list ap;
188 char buf[LOG_BUF_SIZE];
189
190 va_start(ap, fmt);
191 vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
192 va_end(ap);
193
194 __android_log_write(ANDROID_LOG_FATAL, tag, buf);
195
196 __builtin_trap(); /* trap so we have a chance to debug the situation */
197 }
198
199 int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
200 {
201 struct iovec vec[2];
202
203 vec[0].iov_base = &tag;
204 vec[0].iov_len = sizeof(tag);
205 vec[1].iov_base = (void*)payload;
206 vec[1].iov_len = len;
207
208 return write_to_log(LOG_ID_EVENTS, vec, 2);
209 }
210
211 /*
212 * Like __android_log_bwrite, but takes the type as well. Doesn't work
213 * for the general case where we're generating lists of stuff, but very
214 * handy if we just want to dump an integer into the log.
215 */
216 int __android_log_btwrite(int32_t tag, char type, const void *payload,
217 size_t len)
218 {
219 struct iovec vec[3];
220
221 vec[0].iov_base = &tag;
222 vec[0].iov_len = sizeof(tag);
223 vec[1].iov_base = &type;
224 vec[1].iov_len = sizeof(type);
225 vec[2].iov_base = (void*)payload;
226 vec[2].iov_len = len;
227
228 return write_to_log(LOG_ID_EVENTS, vec, 3);
229 }
+0
-972
liblog/logprint.c less more
0 /* //device/libs/cutils/logprint.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #define _GNU_SOURCE /* for asprintf */
18
19 #include <ctype.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <alloca.h>
26 #include <assert.h>
27 #include <arpa/inet.h>
28
29 #include <cutils/logd.h>
30 #include <cutils/logprint.h>
31
32 typedef struct FilterInfo_t {
33 char *mTag;
34 android_LogPriority mPri;
35 struct FilterInfo_t *p_next;
36 } FilterInfo;
37
38 struct AndroidLogFormat_t {
39 android_LogPriority global_pri;
40 FilterInfo *filters;
41 AndroidLogPrintFormat format;
42 };
43
44 static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
45 {
46 FilterInfo *p_ret;
47
48 p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
49 p_ret->mTag = strdup(tag);
50 p_ret->mPri = pri;
51
52 return p_ret;
53 }
54
55 static void filterinfo_free(FilterInfo *p_info)
56 {
57 if (p_info == NULL) {
58 return;
59 }
60
61 free(p_info->mTag);
62 p_info->mTag = NULL;
63 }
64
65 /*
66 * Note: also accepts 0-9 priorities
67 * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
68 */
69 static android_LogPriority filterCharToPri (char c)
70 {
71 android_LogPriority pri;
72
73 c = tolower(c);
74
75 if (c >= '0' && c <= '9') {
76 if (c >= ('0'+ANDROID_LOG_SILENT)) {
77 pri = ANDROID_LOG_VERBOSE;
78 } else {
79 pri = (android_LogPriority)(c - '0');
80 }
81 } else if (c == 'v') {
82 pri = ANDROID_LOG_VERBOSE;
83 } else if (c == 'd') {
84 pri = ANDROID_LOG_DEBUG;
85 } else if (c == 'i') {
86 pri = ANDROID_LOG_INFO;
87 } else if (c == 'w') {
88 pri = ANDROID_LOG_WARN;
89 } else if (c == 'e') {
90 pri = ANDROID_LOG_ERROR;
91 } else if (c == 'f') {
92 pri = ANDROID_LOG_FATAL;
93 } else if (c == 's') {
94 pri = ANDROID_LOG_SILENT;
95 } else if (c == '*') {
96 pri = ANDROID_LOG_DEFAULT;
97 } else {
98 pri = ANDROID_LOG_UNKNOWN;
99 }
100
101 return pri;
102 }
103
104 static char filterPriToChar (android_LogPriority pri)
105 {
106 switch (pri) {
107 case ANDROID_LOG_VERBOSE: return 'V';
108 case ANDROID_LOG_DEBUG: return 'D';
109 case ANDROID_LOG_INFO: return 'I';
110 case ANDROID_LOG_WARN: return 'W';
111 case ANDROID_LOG_ERROR: return 'E';
112 case ANDROID_LOG_FATAL: return 'F';
113 case ANDROID_LOG_SILENT: return 'S';
114
115 case ANDROID_LOG_DEFAULT:
116 case ANDROID_LOG_UNKNOWN:
117 default: return '?';
118 }
119 }
120
121 static android_LogPriority filterPriForTag(
122 AndroidLogFormat *p_format, const char *tag)
123 {
124 FilterInfo *p_curFilter;
125
126 for (p_curFilter = p_format->filters
127 ; p_curFilter != NULL
128 ; p_curFilter = p_curFilter->p_next
129 ) {
130 if (0 == strcmp(tag, p_curFilter->mTag)) {
131 if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
132 return p_format->global_pri;
133 } else {
134 return p_curFilter->mPri;
135 }
136 }
137 }
138
139 return p_format->global_pri;
140 }
141
142 /** for debugging */
143 static void dumpFilters(AndroidLogFormat *p_format)
144 {
145 FilterInfo *p_fi;
146
147 for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
148 char cPri = filterPriToChar(p_fi->mPri);
149 if (p_fi->mPri == ANDROID_LOG_DEFAULT) {
150 cPri = filterPriToChar(p_format->global_pri);
151 }
152 fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
153 }
154
155 fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
156
157 }
158
159 /**
160 * returns 1 if this log line should be printed based on its priority
161 * and tag, and 0 if it should not
162 */
163 int android_log_shouldPrintLine (
164 AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
165 {
166 return pri >= filterPriForTag(p_format, tag);
167 }
168
169 AndroidLogFormat *android_log_format_new()
170 {
171 AndroidLogFormat *p_ret;
172
173 p_ret = calloc(1, sizeof(AndroidLogFormat));
174
175 p_ret->global_pri = ANDROID_LOG_VERBOSE;
176 p_ret->format = FORMAT_BRIEF;
177
178 return p_ret;
179 }
180
181 void android_log_format_free(AndroidLogFormat *p_format)
182 {
183 FilterInfo *p_info, *p_info_old;
184
185 p_info = p_format->filters;
186
187 while (p_info != NULL) {
188 p_info_old = p_info;
189 p_info = p_info->p_next;
190
191 free(p_info_old);
192 }
193
194 free(p_format);
195 }
196
197
198
199 void android_log_setPrintFormat(AndroidLogFormat *p_format,
200 AndroidLogPrintFormat format)
201 {
202 p_format->format=format;
203 }
204
205 /**
206 * Returns FORMAT_OFF on invalid string
207 */
208 AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
209 {
210 static AndroidLogPrintFormat format;
211
212 if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
213 else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
214 else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
215 else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
216 else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
217 else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
218 else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
219 else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
220 else format = FORMAT_OFF;
221
222 return format;
223 }
224
225 /**
226 * filterExpression: a single filter expression
227 * eg "AT:d"
228 *
229 * returns 0 on success and -1 on invalid expression
230 *
231 * Assumes single threaded execution
232 */
233
234 int android_log_addFilterRule(AndroidLogFormat *p_format,
235 const char *filterExpression)
236 {
237 size_t i=0;
238 size_t tagNameLength;
239 android_LogPriority pri = ANDROID_LOG_DEFAULT;
240
241 tagNameLength = strcspn(filterExpression, ":");
242
243 if (tagNameLength == 0) {
244 goto error;
245 }
246
247 if(filterExpression[tagNameLength] == ':') {
248 pri = filterCharToPri(filterExpression[tagNameLength+1]);
249
250 if (pri == ANDROID_LOG_UNKNOWN) {
251 goto error;
252 }
253 }
254
255 if(0 == strncmp("*", filterExpression, tagNameLength)) {
256 // This filter expression refers to the global filter
257 // The default level for this is DEBUG if the priority
258 // is unspecified
259 if (pri == ANDROID_LOG_DEFAULT) {
260 pri = ANDROID_LOG_DEBUG;
261 }
262
263 p_format->global_pri = pri;
264 } else {
265 // for filter expressions that don't refer to the global
266 // filter, the default is verbose if the priority is unspecified
267 if (pri == ANDROID_LOG_DEFAULT) {
268 pri = ANDROID_LOG_VERBOSE;
269 }
270
271 char *tagName;
272
273 // Presently HAVE_STRNDUP is never defined, so the second case is always taken
274 // Darwin doesn't have strnup, everything else does
275 #ifdef HAVE_STRNDUP
276 tagName = strndup(filterExpression, tagNameLength);
277 #else
278 //a few extra bytes copied...
279 tagName = strdup(filterExpression);
280 tagName[tagNameLength] = '\0';
281 #endif /*HAVE_STRNDUP*/
282
283 FilterInfo *p_fi = filterinfo_new(tagName, pri);
284 free(tagName);
285
286 p_fi->p_next = p_format->filters;
287 p_format->filters = p_fi;
288 }
289
290 return 0;
291 error:
292 return -1;
293 }
294
295
296 /**
297 * filterString: a comma/whitespace-separated set of filter expressions
298 *
299 * eg "AT:d *:i"
300 *
301 * returns 0 on success and -1 on invalid expression
302 *
303 * Assumes single threaded execution
304 *
305 */
306
307 int android_log_addFilterString(AndroidLogFormat *p_format,
308 const char *filterString)
309 {
310 char *filterStringCopy = strdup (filterString);
311 char *p_cur = filterStringCopy;
312 char *p_ret;
313 int err;
314
315 // Yes, I'm using strsep
316 while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
317 // ignore whitespace-only entries
318 if(p_ret[0] != '\0') {
319 err = android_log_addFilterRule(p_format, p_ret);
320
321 if (err < 0) {
322 goto error;
323 }
324 }
325 }
326
327 free (filterStringCopy);
328 return 0;
329 error:
330 free (filterStringCopy);
331 return -1;
332 }
333
334 static inline char * strip_end(char *str)
335 {
336 char *end = str + strlen(str) - 1;
337
338 while (end >= str && isspace(*end))
339 *end-- = '\0';
340 return str;
341 }
342
343 /**
344 * Splits a wire-format buffer into an AndroidLogEntry
345 * entry allocated by caller. Pointers will point directly into buf
346 *
347 * Returns 0 on success and -1 on invalid wire format (entry will be
348 * in unspecified state)
349 */
350 int android_log_processLogBuffer(struct logger_entry *buf,
351 AndroidLogEntry *entry)
352 {
353 size_t tag_len;
354
355 entry->tv_sec = buf->sec;
356 entry->tv_nsec = buf->nsec;
357 entry->priority = buf->msg[0];
358 entry->pid = buf->pid;
359 entry->tid = buf->tid;
360 entry->tag = buf->msg + 1;
361 tag_len = strlen(entry->tag);
362 entry->messageLen = buf->len - tag_len - 3;
363 entry->message = entry->tag + tag_len + 1;
364
365 return 0;
366 }
367
368 /*
369 * Extract a 4-byte value from a byte stream.
370 */
371 static inline uint32_t get4LE(const uint8_t* src)
372 {
373 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
374 }
375
376 /*
377 * Extract an 8-byte value from a byte stream.
378 */
379 static inline uint64_t get8LE(const uint8_t* src)
380 {
381 uint32_t low, high;
382
383 low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
384 high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
385 return ((long long) high << 32) | (long long) low;
386 }
387
388
389 /*
390 * Recursively convert binary log data to printable form.
391 *
392 * This needs to be recursive because you can have lists of lists.
393 *
394 * If we run out of room, we stop processing immediately. It's important
395 * for us to check for space on every output element to avoid producing
396 * garbled output.
397 *
398 * Returns 0 on success, 1 on buffer full, -1 on failure.
399 */
400 static int android_log_printBinaryEvent(const unsigned char** pEventData,
401 size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
402 {
403 const unsigned char* eventData = *pEventData;
404 size_t eventDataLen = *pEventDataLen;
405 char* outBuf = *pOutBuf;
406 size_t outBufLen = *pOutBufLen;
407 unsigned char type;
408 size_t outCount;
409 int result = 0;
410
411 if (eventDataLen < 1)
412 return -1;
413 type = *eventData++;
414 eventDataLen--;
415
416 //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
417
418 switch (type) {
419 case EVENT_TYPE_INT:
420 /* 32-bit signed int */
421 {
422 int ival;
423
424 if (eventDataLen < 4)
425 return -1;
426 ival = get4LE(eventData);
427 eventData += 4;
428 eventDataLen -= 4;
429
430 outCount = snprintf(outBuf, outBufLen, "%d", ival);
431 if (outCount < outBufLen) {
432 outBuf += outCount;
433 outBufLen -= outCount;
434 } else {
435 /* halt output */
436 goto no_room;
437 }
438 }
439 break;
440 case EVENT_TYPE_LONG:
441 /* 64-bit signed long */
442 {
443 long long lval;
444
445 if (eventDataLen < 8)
446 return -1;
447 lval = get8LE(eventData);
448 eventData += 8;
449 eventDataLen -= 8;
450
451 outCount = snprintf(outBuf, outBufLen, "%lld", lval);
452 if (outCount < outBufLen) {
453 outBuf += outCount;
454 outBufLen -= outCount;
455 } else {
456 /* halt output */
457 goto no_room;
458 }
459 }
460 break;
461 case EVENT_TYPE_STRING:
462 /* UTF-8 chars, not NULL-terminated */
463 {
464 unsigned int strLen;
465
466 if (eventDataLen < 4)
467 return -1;
468 strLen = get4LE(eventData);
469 eventData += 4;
470 eventDataLen -= 4;
471
472 if (eventDataLen < strLen)
473 return -1;
474
475 if (strLen < outBufLen) {
476 memcpy(outBuf, eventData, strLen);
477 outBuf += strLen;
478 outBufLen -= strLen;
479 } else if (outBufLen > 0) {
480 /* copy what we can */
481 memcpy(outBuf, eventData, outBufLen);
482 outBuf += outBufLen;
483 outBufLen -= outBufLen;
484 goto no_room;
485 }
486 eventData += strLen;
487 eventDataLen -= strLen;
488 break;
489 }
490 case EVENT_TYPE_LIST:
491 /* N items, all different types */
492 {
493 unsigned char count;
494 int i;
495
496 if (eventDataLen < 1)
497 return -1;
498
499 count = *eventData++;
500 eventDataLen--;
501
502 if (outBufLen > 0) {
503 *outBuf++ = '[';
504 outBufLen--;
505 } else {
506 goto no_room;
507 }
508
509 for (i = 0; i < count; i++) {
510 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
511 &outBuf, &outBufLen);
512 if (result != 0)
513 goto bail;
514
515 if (i < count-1) {
516 if (outBufLen > 0) {
517 *outBuf++ = ',';
518 outBufLen--;
519 } else {
520 goto no_room;
521 }
522 }
523 }
524
525 if (outBufLen > 0) {
526 *outBuf++ = ']';
527 outBufLen--;
528 } else {
529 goto no_room;
530 }
531 }
532 break;
533 default:
534 fprintf(stderr, "Unknown binary event type %d\n", type);
535 return -1;
536 }
537
538 bail:
539 *pEventData = eventData;
540 *pEventDataLen = eventDataLen;
541 *pOutBuf = outBuf;
542 *pOutBufLen = outBufLen;
543 return result;
544
545 no_room:
546 result = 1;
547 goto bail;
548 }
549
550 /**
551 * Convert a binary log entry to ASCII form.
552 *
553 * For convenience we mimic the processLogBuffer API. There is no
554 * pre-defined output length for the binary data, since we're free to format
555 * it however we choose, which means we can't really use a fixed-size buffer
556 * here.
557 */
558 int android_log_processBinaryLogBuffer(struct logger_entry *buf,
559 AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
560 int messageBufLen)
561 {
562 size_t inCount;
563 unsigned int tagIndex;
564 const unsigned char* eventData;
565
566 entry->tv_sec = buf->sec;
567 entry->tv_nsec = buf->nsec;
568 entry->priority = ANDROID_LOG_INFO;
569 entry->pid = buf->pid;
570 entry->tid = buf->tid;
571
572 /*
573 * Pull the tag out.
574 */
575 eventData = (const unsigned char*) buf->msg;
576 inCount = buf->len;
577 if (inCount < 4)
578 return -1;
579 tagIndex = get4LE(eventData);
580 eventData += 4;
581 inCount -= 4;
582
583 if (map != NULL) {
584 entry->tag = android_lookupEventTag(map, tagIndex);
585 } else {
586 entry->tag = NULL;
587 }
588
589 /*
590 * If we don't have a map, or didn't find the tag number in the map,
591 * stuff a generated tag value into the start of the output buffer and
592 * shift the buffer pointers down.
593 */
594 if (entry->tag == NULL) {
595 int tagLen;
596
597 tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
598 entry->tag = messageBuf;
599 messageBuf += tagLen+1;
600 messageBufLen -= tagLen+1;
601 }
602
603 /*
604 * Format the event log data into the buffer.
605 */
606 char* outBuf = messageBuf;
607 size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
608 int result;
609 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
610 &outRemaining);
611 if (result < 0) {
612 fprintf(stderr, "Binary log entry conversion failed\n");
613 return -1;
614 } else if (result == 1) {
615 if (outBuf > messageBuf) {
616 /* leave an indicator */
617 *(outBuf-1) = '!';
618 } else {
619 /* no room to output anything at all */
620 *outBuf++ = '!';
621 outRemaining--;
622 }
623 /* pretend we ate all the data */
624 inCount = 0;
625 }
626
627 /* eat the silly terminating '\n' */
628 if (inCount == 1 && *eventData == '\n') {
629 eventData++;
630 inCount--;
631 }
632
633 if (inCount != 0) {
634 fprintf(stderr,
635 "Warning: leftover binary log data (%d bytes)\n", inCount);
636 }
637
638 /*
639 * Terminate the buffer. The NUL byte does not count as part of
640 * entry->messageLen.
641 */
642 *outBuf = '\0';
643 entry->messageLen = outBuf - messageBuf;
644 assert(entry->messageLen == (messageBufLen-1) - outRemaining);
645
646 entry->message = messageBuf;
647
648 return 0;
649 }
650
651 /**
652 * Formats a log message into a buffer
653 *
654 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
655 * If return value != defaultBuffer, caller must call free()
656 * Returns NULL on malloc error
657 */
658
659 char *android_log_formatLogLine (
660 AndroidLogFormat *p_format,
661 char *defaultBuffer,
662 size_t defaultBufferSize,
663 const AndroidLogEntry *entry,
664 size_t *p_outLength)
665 {
666 #if defined(HAVE_LOCALTIME_R)
667 struct tm tmBuf;
668 #endif
669 struct tm* ptm;
670 char timeBuf[32];
671 char headerBuf[128];
672 char prefixBuf[128], suffixBuf[128];
673 char priChar;
674 int prefixSuffixIsHeaderFooter = 0;
675 char * ret = NULL;
676
677 priChar = filterPriToChar(entry->priority);
678
679 /*
680 * Get the current date/time in pretty form
681 *
682 * It's often useful when examining a log with "less" to jump to
683 * a specific point in the file by searching for the date/time stamp.
684 * For this reason it's very annoying to have regexp meta characters
685 * in the time stamp. Don't use forward slashes, parenthesis,
686 * brackets, asterisks, or other special chars here.
687 */
688 #if defined(HAVE_LOCALTIME_R)
689 ptm = localtime_r(&(entry->tv_sec), &tmBuf);
690 #else
691 ptm = localtime(&(entry->tv_sec));
692 #endif
693 //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
694 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
695
696 /*
697 * Construct a buffer containing the log header and log message.
698 */
699 size_t prefixLen, suffixLen;
700
701 switch (p_format->format) {
702 case FORMAT_TAG:
703 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
704 "%c/%-8s: ", priChar, entry->tag);
705 strcpy(suffixBuf, "\n"); suffixLen = 1;
706 break;
707 case FORMAT_PROCESS:
708 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
709 "%c(%5d) ", priChar, entry->pid);
710 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
711 " (%s)\n", entry->tag);
712 break;
713 case FORMAT_THREAD:
714 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
715 "%c(%5d:%p) ", priChar, entry->pid, (void*)entry->tid);
716 strcpy(suffixBuf, "\n");
717 suffixLen = 1;
718 break;
719 case FORMAT_RAW:
720 prefixBuf[0] = 0;
721 prefixLen = 0;
722 strcpy(suffixBuf, "\n");
723 suffixLen = 1;
724 break;
725 case FORMAT_TIME:
726 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
727 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
728 priChar, entry->tag, entry->pid);
729 strcpy(suffixBuf, "\n");
730 suffixLen = 1;
731 break;
732 case FORMAT_THREADTIME:
733 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
734 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
735 (int)entry->pid, (int)entry->tid, priChar, entry->tag);
736 strcpy(suffixBuf, "\n");
737 suffixLen = 1;
738 break;
739 case FORMAT_LONG:
740 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
741 "[ %s.%03ld %5d:%p %c/%-8s ]\n",
742 timeBuf, entry->tv_nsec / 1000000, entry->pid,
743 (void*)entry->tid, priChar, entry->tag);
744 strcpy(suffixBuf, "\n\n");
745 suffixLen = 2;
746 prefixSuffixIsHeaderFooter = 1;
747 break;
748 case FORMAT_BRIEF:
749 default:
750 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
751 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
752 strcpy(suffixBuf, "\n");
753 suffixLen = 1;
754 break;
755 }
756
757 /* the following code is tragically unreadable */
758
759 size_t numLines;
760 size_t i;
761 char *p;
762 size_t bufferSize;
763 const char *pm;
764
765 if (prefixSuffixIsHeaderFooter) {
766 // we're just wrapping message with a header/footer
767 numLines = 1;
768 } else {
769 pm = entry->message;
770 numLines = 0;
771
772 // The line-end finding here must match the line-end finding
773 // in for ( ... numLines...) loop below
774 while (pm < (entry->message + entry->messageLen)) {
775 if (*pm++ == '\n') numLines++;
776 }
777 // plus one line for anything not newline-terminated at the end
778 if (pm > entry->message && *(pm-1) != '\n') numLines++;
779 }
780
781 // this is an upper bound--newlines in message may be counted
782 // extraneously
783 bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
784
785 if (defaultBufferSize >= bufferSize) {
786 ret = defaultBuffer;
787 } else {
788 ret = (char *)malloc(bufferSize);
789
790 if (ret == NULL) {
791 return ret;
792 }
793 }
794
795 ret[0] = '\0'; /* to start strcat off */
796
797 p = ret;
798 pm = entry->message;
799
800 if (prefixSuffixIsHeaderFooter) {
801 strcat(p, prefixBuf);
802 p += prefixLen;
803 strncat(p, entry->message, entry->messageLen);
804 p += entry->messageLen;
805 strcat(p, suffixBuf);
806 p += suffixLen;
807 } else {
808 while(pm < (entry->message + entry->messageLen)) {
809 const char *lineStart;
810 size_t lineLen;
811
812 lineStart = pm;
813
814 // Find the next end-of-line in message
815 while (pm < (entry->message + entry->messageLen)
816 && *pm != '\n') pm++;
817 lineLen = pm - lineStart;
818
819 strcat(p, prefixBuf);
820 p += prefixLen;
821 strncat(p, lineStart, lineLen);
822 p += lineLen;
823 strcat(p, suffixBuf);
824 p += suffixLen;
825
826 if (*pm == '\n') pm++;
827 }
828 }
829
830 if (p_outLength != NULL) {
831 *p_outLength = p - ret;
832 }
833
834 return ret;
835 }
836
837 /**
838 * Either print or do not print log line, based on filter
839 *
840 * Returns count bytes written
841 */
842
843 int android_log_filterAndPrintLogLine(
844 AndroidLogFormat *p_format,
845 int fd,
846 const AndroidLogEntry *entry)
847 {
848 int ret;
849 char defaultBuffer[512];
850 char *outBuffer = NULL;
851 size_t totalLen;
852
853 if (0 == android_log_shouldPrintLine(p_format, entry->tag,
854 entry->priority)) {
855 return 0;
856 }
857
858 outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
859 sizeof(defaultBuffer), entry, &totalLen);
860
861 if (!outBuffer)
862 return -1;
863
864 do {
865 ret = write(fd, outBuffer, totalLen);
866 } while (ret < 0 && errno == EINTR);
867
868 if (ret < 0) {
869 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
870 ret = 0;
871 goto done;
872 }
873
874 if (((size_t)ret) < totalLen) {
875 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
876 (int)totalLen);
877 goto done;
878 }
879
880 done:
881 if (outBuffer != defaultBuffer) {
882 free(outBuffer);
883 }
884
885 return ret;
886 }
887
888
889
890 void logprint_run_tests()
891 {
892 #if 0
893
894 fprintf(stderr, "tests disabled\n");
895
896 #else
897
898 int err;
899 const char *tag;
900 AndroidLogFormat *p_format;
901
902 p_format = android_log_format_new();
903
904 fprintf(stderr, "running tests\n");
905
906 tag = "random";
907
908 android_log_addFilterRule(p_format,"*:i");
909
910 assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
911 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
912 android_log_addFilterRule(p_format, "*");
913 assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
914 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
915 android_log_addFilterRule(p_format, "*:v");
916 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
917 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
918 android_log_addFilterRule(p_format, "*:i");
919 assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
920 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
921
922 android_log_addFilterRule(p_format, "random");
923 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
924 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
925 android_log_addFilterRule(p_format, "random:v");
926 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
927 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
928 android_log_addFilterRule(p_format, "random:d");
929 assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
930 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
931 android_log_addFilterRule(p_format, "random:w");
932 assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
933 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
934
935 android_log_addFilterRule(p_format, "crap:*");
936 assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
937 assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
938
939 // invalid expression
940 err = android_log_addFilterRule(p_format, "random:z");
941 assert (err < 0);
942 assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
943 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
944
945 // Issue #550946
946 err = android_log_addFilterString(p_format, " ");
947 assert(err == 0);
948 assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
949
950 // note trailing space
951 err = android_log_addFilterString(p_format, "*:s random:d ");
952 assert(err == 0);
953 assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
954
955 err = android_log_addFilterString(p_format, "*:s random:z");
956 assert(err < 0);
957
958
959 #if 0
960 char *ret;
961 char defaultBuffer[512];
962
963 ret = android_log_formatLogLine(p_format,
964 defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
965 123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
966 #endif
967
968
969 fprintf(stderr, "tests complete\n");
970 #endif
971 }
+0
-18
libmincrypt/Android.mk less more
0 # Copyright 2008 The Android Open Source Project
1 #
2 LOCAL_PATH := $(call my-dir)
3 include $(CLEAR_VARS)
4
5 LOCAL_MODULE := libmincrypt
6 LOCAL_SRC_FILES := rsa.c sha.c
7 include $(BUILD_STATIC_LIBRARY)
8
9 include $(CLEAR_VARS)
10
11 LOCAL_MODULE := libmincrypt
12 LOCAL_SRC_FILES := rsa.c sha.c
13 include $(BUILD_HOST_STATIC_LIBRARY)
14
15
16 # TODO: drop the hyphen once these are checked in
17 include $(LOCAL_PATH)/tools/Android.mk
+0
-198
libmincrypt/rsa.c less more
0 /* rsa.c
1 **
2 ** Copyright 2008, The Android Open Source Project
3 **
4 ** Redistribution and use in source and binary forms, with or without
5 ** modification, are permitted provided that the following conditions are met:
6 ** * Redistributions of source code must retain the above copyright
7 ** notice, this list of conditions and the following disclaimer.
8 ** * Redistributions in binary form must reproduce the above copyright
9 ** notice, this list of conditions and the following disclaimer in the
10 ** documentation and/or other materials provided with the distribution.
11 ** * Neither the name of Google Inc. nor the names of its contributors may
12 ** be used to endorse or promote products derived from this software
13 ** without specific prior written permission.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
16 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "mincrypt/rsa.h"
28 #include "mincrypt/sha.h"
29
30 /* a[] -= mod */
31 static void subM(const RSAPublicKey *key, uint32_t *a) {
32 int64_t A = 0;
33 int i;
34 for (i = 0; i < key->len; ++i) {
35 A += (uint64_t)a[i] - key->n[i];
36 a[i] = (uint32_t)A;
37 A >>= 32;
38 }
39 }
40
41 /* return a[] >= mod */
42 static int geM(const RSAPublicKey *key, const uint32_t *a) {
43 int i;
44 for (i = key->len; i;) {
45 --i;
46 if (a[i] < key->n[i]) return 0;
47 if (a[i] > key->n[i]) return 1;
48 }
49 return 1; /* equal */
50 }
51
52 /* montgomery c[] += a * b[] / R % mod */
53 static void montMulAdd(const RSAPublicKey *key,
54 uint32_t* c,
55 const uint32_t a,
56 const uint32_t* b) {
57 uint64_t A = (uint64_t)a * b[0] + c[0];
58 uint32_t d0 = (uint32_t)A * key->n0inv;
59 uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
60 int i;
61
62 for (i = 1; i < key->len; ++i) {
63 A = (A >> 32) + (uint64_t)a * b[i] + c[i];
64 B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
65 c[i - 1] = (uint32_t)B;
66 }
67
68 A = (A >> 32) + (B >> 32);
69
70 c[i - 1] = (uint32_t)A;
71
72 if (A >> 32) {
73 subM(key, c);
74 }
75 }
76
77 /* montgomery c[] = a[] * b[] / R % mod */
78 static void montMul(const RSAPublicKey *key,
79 uint32_t* c,
80 const uint32_t* a,
81 const uint32_t* b) {
82 int i;
83 for (i = 0; i < key->len; ++i) {
84 c[i] = 0;
85 }
86 for (i = 0; i < key->len; ++i) {
87 montMulAdd(key, c, a[i], b);
88 }
89 }
90
91 /* In-place public exponentiation.
92 ** Input and output big-endian byte array in inout.
93 */
94 static void modpow3(const RSAPublicKey *key,
95 uint8_t* inout) {
96 uint32_t a[RSANUMWORDS];
97 uint32_t aR[RSANUMWORDS];
98 uint32_t aaR[RSANUMWORDS];
99 uint32_t *aaa = aR; /* Re-use location. */
100 int i;
101
102 /* Convert from big endian byte array to little endian word array. */
103 for (i = 0; i < key->len; ++i) {
104 uint32_t tmp =
105 (inout[((key->len - 1 - i) * 4) + 0] << 24) |
106 (inout[((key->len - 1 - i) * 4) + 1] << 16) |
107 (inout[((key->len - 1 - i) * 4) + 2] << 8) |
108 (inout[((key->len - 1 - i) * 4) + 3] << 0);
109 a[i] = tmp;
110 }
111
112 montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
113 montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
114 montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
115
116 /* Make sure aaa < mod; aaa is at most 1x mod too large. */
117 if (geM(key, aaa)) {
118 subM(key, aaa);
119 }
120
121 /* Convert to bigendian byte array */
122 for (i = key->len - 1; i >= 0; --i) {
123 uint32_t tmp = aaa[i];
124 *inout++ = tmp >> 24;
125 *inout++ = tmp >> 16;
126 *inout++ = tmp >> 8;
127 *inout++ = tmp >> 0;
128 }
129 }
130
131 /* Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
132 ** Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
133 ** other flavor which omits the optional parameter entirely). This code does not
134 ** accept signatures without the optional parameter.
135 */
136 static const uint8_t padding[RSANUMBYTES - SHA_DIGEST_SIZE] = {
137 0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
138 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
139 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
140 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
141 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
142 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
143 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
144 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
145 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
146 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
147 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
148 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
149 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
150 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
151 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
152 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
153 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
154 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,
155 0x04,0x14
156 };
157
158 /* Verify a 2048 bit RSA PKCS1.5 signature against an expected SHA-1 hash.
159 ** Returns 0 on failure, 1 on success.
160 */
161 int RSA_verify(const RSAPublicKey *key,
162 const uint8_t *signature,
163 const int len,
164 const uint8_t *sha) {
165 uint8_t buf[RSANUMBYTES];
166 int i;
167
168 if (key->len != RSANUMWORDS) {
169 return 0; /* Wrong key passed in. */
170 }
171
172 if (len != sizeof(buf)) {
173 return 0; /* Wrong input length. */
174 }
175
176 for (i = 0; i < len; ++i) {
177 buf[i] = signature[i];
178 }
179
180 modpow3(key, buf);
181
182 /* Check pkcs1.5 padding bytes. */
183 for (i = 0; i < (int) sizeof(padding); ++i) {
184 if (buf[i] != padding[i]) {
185 return 0;
186 }
187 }
188
189 /* Check sha digest matches. */
190 for (; i < len; ++i) {
191 if (buf[i] != *sha++) {
192 return 0;
193 }
194 }
195
196 return 1;
197 }
+0
-142
libmincrypt/sha.c less more
0 /* sha.c
1 **
2 ** Copyright 2008, The Android Open Source Project
3 **
4 ** Redistribution and use in source and binary forms, with or without
5 ** modification, are permitted provided that the following conditions are met:
6 ** * Redistributions of source code must retain the above copyright
7 ** notice, this list of conditions and the following disclaimer.
8 ** * Redistributions in binary form must reproduce the above copyright
9 ** notice, this list of conditions and the following disclaimer in the
10 ** documentation and/or other materials provided with the distribution.
11 ** * Neither the name of Google Inc. nor the names of its contributors may
12 ** be used to endorse or promote products derived from this software
13 ** without specific prior written permission.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
16 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "mincrypt/sha.h"
28
29 #define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
30
31 static void SHA1_transform(SHA_CTX *ctx) {
32 uint32_t W[80];
33 uint32_t A, B, C, D, E;
34 uint8_t *p = ctx->buf;
35 int t;
36
37 for(t = 0; t < 16; ++t) {
38 uint32_t tmp = *p++ << 24;
39 tmp |= *p++ << 16;
40 tmp |= *p++ << 8;
41 tmp |= *p++;
42 W[t] = tmp;
43 }
44
45 for(; t < 80; t++) {
46 W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
47 }
48
49 A = ctx->state[0];
50 B = ctx->state[1];
51 C = ctx->state[2];
52 D = ctx->state[3];
53 E = ctx->state[4];
54
55 for(t = 0; t < 80; t++) {
56 uint32_t tmp = rol(5,A) + E + W[t];
57
58 if (t < 20)
59 tmp += (D^(B&(C^D))) + 0x5A827999;
60 else if ( t < 40)
61 tmp += (B^C^D) + 0x6ED9EBA1;
62 else if ( t < 60)
63 tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
64 else
65 tmp += (B^C^D) + 0xCA62C1D6;
66
67 E = D;
68 D = C;
69 C = rol(30,B);
70 B = A;
71 A = tmp;
72 }
73
74 ctx->state[0] += A;
75 ctx->state[1] += B;
76 ctx->state[2] += C;
77 ctx->state[3] += D;
78 ctx->state[4] += E;
79 }
80
81 void SHA_init(SHA_CTX *ctx) {
82 ctx->state[0] = 0x67452301;
83 ctx->state[1] = 0xEFCDAB89;
84 ctx->state[2] = 0x98BADCFE;
85 ctx->state[3] = 0x10325476;
86 ctx->state[4] = 0xC3D2E1F0;
87 ctx->count = 0;
88 }
89
90 void SHA_update(SHA_CTX *ctx, const void *data, int len) {
91 int i = ctx->count % sizeof(ctx->buf);
92 const uint8_t* p = (const uint8_t*)data;
93
94 ctx->count += len;
95
96 while (len--) {
97 ctx->buf[i++] = *p++;
98 if (i == sizeof(ctx->buf)) {
99 SHA1_transform(ctx);
100 i = 0;
101 }
102 }
103 }
104 const uint8_t *SHA_final(SHA_CTX *ctx) {
105 uint8_t *p = ctx->buf;
106 uint64_t cnt = ctx->count * 8;
107 int i;
108
109 SHA_update(ctx, (uint8_t*)"\x80", 1);
110 while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
111 SHA_update(ctx, (uint8_t*)"\0", 1);
112 }
113 for (i = 0; i < 8; ++i) {
114 uint8_t tmp = cnt >> ((7 - i) * 8);
115 SHA_update(ctx, &tmp, 1);
116 }
117
118 for (i = 0; i < 5; i++) {
119 uint32_t tmp = ctx->state[i];
120 *p++ = tmp >> 24;
121 *p++ = tmp >> 16;
122 *p++ = tmp >> 8;
123 *p++ = tmp >> 0;
124 }
125
126 return ctx->buf;
127 }
128
129 /* Convenience function */
130 const uint8_t* SHA(const void *data, int len, uint8_t *digest) {
131 const uint8_t *p;
132 int i;
133 SHA_CTX ctx;
134 SHA_init(&ctx);
135 SHA_update(&ctx, data, len);
136 p = SHA_final(&ctx);
137 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
138 digest[i] = *p++;
139 }
140 return digest;
141 }
+0
-21
libmincrypt/tools/Android.mk less more
0 # Copyright (C) 2008 The Android Open Source Project
1 #
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #
6 # http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 LOCAL_PATH := $(call my-dir)
15 include $(CLEAR_VARS)
16
17 LOCAL_MODULE := dumpkey
18 LOCAL_SRC_FILES := DumpPublicKey.java
19 LOCAL_JAR_MANIFEST := DumpPublicKey.mf
20 include $(BUILD_HOST_JAVA_LIBRARY)
+0
-130
libmincrypt/tools/DumpPublicKey.java less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.android.dumpkey;
17
18 import java.io.FileInputStream;
19 import java.math.BigInteger;
20 import java.security.cert.CertificateFactory;
21 import java.security.cert.Certificate;
22 import java.security.KeyStore;
23 import java.security.Key;
24 import java.security.PublicKey;
25 import java.security.interfaces.RSAPublicKey;
26 import sun.misc.BASE64Encoder;
27
28 /**
29 * Command line tool to extract RSA public keys from X.509 certificates
30 * and output source code with data initializers for the keys.
31 * @hide
32 */
33 class DumpPublicKey {
34 /**
35 * @param key to perform sanity checks on
36 * @throws Exception if the key has the wrong size or public exponent
37 */
38 static void check(RSAPublicKey key) throws Exception {
39 BigInteger pubexp = key.getPublicExponent();
40 BigInteger modulus = key.getModulus();
41
42 if (!pubexp.equals(BigInteger.valueOf(3)))
43 throw new Exception("Public exponent should be 3 but is " +
44 pubexp.toString(10) + ".");
45
46 if (modulus.bitLength() != 2048)
47 throw new Exception("Modulus should be 2048 bits long but is " +
48 modulus.bitLength() + " bits.");
49 }
50
51 /**
52 * @param key to output
53 * @return a C initializer representing this public key.
54 */
55 static String print(RSAPublicKey key) throws Exception {
56 check(key);
57
58 BigInteger N = key.getModulus();
59
60 StringBuilder result = new StringBuilder();
61
62 int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
63
64 result.append("{");
65 result.append(nwords);
66
67 BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32
68 BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32
69
70 result.append(",0x");
71 result.append(N0inv.toString(16));
72
73 BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
74 BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N
75
76 // Write out modulus as little endian array of integers.
77 result.append(",{");
78 for (int i = 0; i < nwords; ++i) {
79 int n = N.mod(B).intValue();
80 result.append(n);
81
82 if (i != nwords - 1) {
83 result.append(",");
84 }
85
86 N = N.divide(B);
87 }
88 result.append("}");
89
90 // Write R^2 as little endian array of integers.
91 result.append(",{");
92 for (int i = 0; i < nwords; ++i) {
93 int rr = RR.mod(B).intValue();
94 result.append(rr);
95
96 if (i != nwords - 1) {
97 result.append(",");
98 }
99
100 RR = RR.divide(B);
101 }
102 result.append("}");
103
104 result.append("}");
105 return result.toString();
106 }
107
108 public static void main(String[] args) {
109 if (args.length < 1) {
110 System.err.println("Usage: DumpPublicKey certfile ... > source.c");
111 System.exit(1);
112 }
113 try {
114 for (int i = 0; i < args.length; i++) {
115 FileInputStream input = new FileInputStream(args[i]);
116 CertificateFactory cf = CertificateFactory.getInstance("X.509");
117 Certificate cert = cf.generateCertificate(input);
118 RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey());
119 check(key);
120 System.out.print(print(key));
121 System.out.println(i < args.length - 1 ? "," : "");
122 }
123 } catch (Exception e) {
124 e.printStackTrace();
125 System.exit(1);
126 }
127 System.exit(0);
128 }
129 }
+0
-1
libmincrypt/tools/DumpPublicKey.mf less more
0 Main-Class: com.android.dumpkey.DumpPublicKey
+0
-23
libnetutils/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 LOCAL_SRC_FILES:= \
4 dhcpclient.c \
5 dhcpmsg.c \
6 dhcp_utils.c \
7 ifc_utils.c \
8 packet.c
9
10 LOCAL_SHARED_LIBRARIES := \
11 libcutils
12
13 # need "-lrt" on Linux simulator to pick up clock_gettime
14 ifeq ($(TARGET_SIMULATOR),true)
15 ifeq ($(HOST_OS),linux)
16 LOCAL_LDLIBS += -lrt -lpthread
17 endif
18 endif
19
20 LOCAL_MODULE:= libnetutils
21
22 include $(BUILD_SHARED_LIBRARY)
+0
-207
libnetutils/dhcp_utils.c less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /* Utilities for managing the dhcpcd DHCP client daemon */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23
24 #include <cutils/properties.h>
25
26 static const char DAEMON_NAME[] = "dhcpcd";
27 static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
28 static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
29 static const int NAP_TIME = 1; /* wait for 1 second at a time */
30 /* when polling for property values */
31 static char errmsg[100];
32
33 /*
34 * Wait for a system property to be assigned a specified value.
35 * If desired_value is NULL, then just wait for the property to
36 * be created with any value. maxwait is the maximum amount of
37 * time in seconds to wait before giving up.
38 */
39 static int wait_for_property(const char *name, const char *desired_value, int maxwait)
40 {
41 char value[PROPERTY_VALUE_MAX] = {'\0'};
42 int maxnaps = maxwait / NAP_TIME;
43
44 if (maxnaps < 1) {
45 maxnaps = 1;
46 }
47
48 while (maxnaps-- > 0) {
49 usleep(1000000);
50 if (property_get(name, value, NULL)) {
51 if (desired_value == NULL ||
52 strcmp(value, desired_value) == 0) {
53 return 0;
54 }
55 }
56 }
57 return -1; /* failure */
58 }
59
60 static void fill_ip_info(const char *interface,
61 in_addr_t *ipaddr,
62 in_addr_t *gateway,
63 in_addr_t *mask,
64 in_addr_t *dns1,
65 in_addr_t *dns2,
66 in_addr_t *server,
67 uint32_t *lease)
68 {
69 char prop_name[PROPERTY_KEY_MAX];
70 char prop_value[PROPERTY_VALUE_MAX];
71 struct in_addr addr;
72 in_addr_t iaddr;
73
74 snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
75 if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
76 *ipaddr = addr.s_addr;
77 } else {
78 *ipaddr = 0;
79 }
80 snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
81 if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
82 *gateway = addr.s_addr;
83 } else {
84 *gateway = 0;
85 }
86 snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
87 if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
88 *mask = addr.s_addr;
89 } else {
90 *mask = 0;
91 }
92 snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
93 if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
94 *dns1 = addr.s_addr;
95 } else {
96 *dns1 = 0;
97 }
98 snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
99 if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
100 *dns2 = addr.s_addr;
101 } else {
102 *dns2 = 0;
103 }
104 snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
105 if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
106 *server = addr.s_addr;
107 } else {
108 *server = 0;
109 }
110 snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
111 if (property_get(prop_name, prop_value, NULL)) {
112 *lease = atol(prop_value);
113 }
114 }
115
116 /*
117 * Start the dhcp client daemon, and wait for it to finish
118 * configuring the interface.
119 */
120 int dhcp_do_request(const char *interface,
121 in_addr_t *ipaddr,
122 in_addr_t *gateway,
123 in_addr_t *mask,
124 in_addr_t *dns1,
125 in_addr_t *dns2,
126 in_addr_t *server,
127 uint32_t *lease)
128 {
129 char result_prop_name[PROPERTY_KEY_MAX];
130 char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
131 const char *ctrl_prop = "ctl.start";
132 const char *desired_status = "running";
133
134 snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
135 DHCP_PROP_NAME_PREFIX,
136 interface);
137 /* Erase any previous setting of the dhcp result property */
138 property_set(result_prop_name, "");
139
140 /* Start the daemon and wait until it's ready */
141 property_set(ctrl_prop, DAEMON_NAME);
142 if (wait_for_property(DAEMON_PROP_NAME, desired_status, 10) < 0) {
143 snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
144 return -1;
145 }
146
147 /* Wait for the daemon to return a result */
148 if (wait_for_property(result_prop_name, NULL, 30) < 0) {
149 snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
150 return -1;
151 }
152
153 if (!property_get(result_prop_name, prop_value, NULL)) {
154 /* shouldn't ever happen, given the success of wait_for_property() */
155 snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
156 return -1;
157 }
158 if (strcmp(prop_value, "ok") == 0) {
159 fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
160 return 0;
161 } else {
162 snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
163 return -1;
164 }
165 }
166
167 /**
168 * Stop the DHCP client daemon.
169 */
170 int dhcp_stop(const char *interface)
171 {
172 char result_prop_name[PROPERTY_KEY_MAX];
173 const char *ctrl_prop = "ctl.stop";
174 const char *desired_status = "stopped";
175
176 snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
177 DHCP_PROP_NAME_PREFIX,
178 interface);
179 /* Stop the daemon and wait until it's reported to be stopped */
180 property_set(ctrl_prop, DAEMON_NAME);
181 if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
182 return -1;
183 }
184 property_set(result_prop_name, "failed");
185 return 0;
186 }
187
188 /**
189 * Release the current DHCP client lease.
190 */
191 int dhcp_release_lease(const char *interface)
192 {
193 const char *ctrl_prop = "ctl.stop";
194 const char *desired_status = "stopped";
195
196 /* Stop the daemon and wait until it's reported to be stopped */
197 property_set(ctrl_prop, DAEMON_NAME);
198 if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
199 return -1;
200 }
201 return 0;
202 }
203
204 char *dhcp_get_errmsg() {
205 return errmsg;
206 }
+0
-562
libnetutils/dhcpclient.c less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <string.h>
22
23 #include <time.h>
24 #include <sys/time.h>
25 #include <poll.h>
26
27 #include <sys/socket.h>
28 #include <sys/select.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31
32 #include <cutils/properties.h>
33 #define LOG_TAG "DHCP"
34 #include <cutils/log.h>
35
36 #include <dirent.h>
37
38 #include "dhcpmsg.h"
39 #include "ifc_utils.h"
40 #include "packet.h"
41
42 #define VERBOSE 2
43
44 static int verbose = 1;
45 static char errmsg[2048];
46
47 typedef unsigned long long msecs_t;
48 #if VERBOSE
49 void dump_dhcp_msg();
50 #endif
51
52 msecs_t get_msecs(void)
53 {
54 struct timespec ts;
55
56 if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
57 return 0;
58 } else {
59 return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
60 (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
61 }
62 }
63
64 void printerr(char *fmt, ...)
65 {
66 va_list ap;
67
68 va_start(ap, fmt);
69 vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
70 va_end(ap);
71
72 LOGD(errmsg);
73 }
74
75 const char *dhcp_lasterror()
76 {
77 return errmsg;
78 }
79
80 int fatal(const char *reason)
81 {
82 printerr("%s: %s\n", reason, strerror(errno));
83 return -1;
84 // exit(1);
85 }
86
87 const char *ipaddr(uint32_t addr)
88 {
89 static char buf[32];
90
91 sprintf(buf,"%d.%d.%d.%d",
92 addr & 255,
93 ((addr >> 8) & 255),
94 ((addr >> 16) & 255),
95 (addr >> 24));
96 return buf;
97 }
98
99 typedef struct dhcp_info dhcp_info;
100
101 struct dhcp_info {
102 uint32_t type;
103
104 uint32_t ipaddr;
105 uint32_t gateway;
106 uint32_t netmask;
107
108 uint32_t dns1;
109 uint32_t dns2;
110
111 uint32_t serveraddr;
112 uint32_t lease;
113 };
114
115 dhcp_info last_good_info;
116
117 void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
118 uint32_t *dns1, uint32_t *dns2, uint32_t *server,
119 uint32_t *lease)
120 {
121 *ipaddr = last_good_info.ipaddr;
122 *gateway = last_good_info.gateway;
123 *mask = last_good_info.netmask;
124 *dns1 = last_good_info.dns1;
125 *dns2 = last_good_info.dns2;
126 *server = last_good_info.serveraddr;
127 *lease = last_good_info.lease;
128 }
129
130 static int ifc_configure(const char *ifname, dhcp_info *info)
131 {
132 char dns_prop_name[PROPERTY_KEY_MAX];
133
134 if (ifc_set_addr(ifname, info->ipaddr)) {
135 printerr("failed to set ipaddr %s: %s\n", ipaddr(info->ipaddr), strerror(errno));
136 return -1;
137 }
138 if (ifc_set_mask(ifname, info->netmask)) {
139 printerr("failed to set netmask %s: %s\n", ipaddr(info->netmask), strerror(errno));
140 return -1;
141 }
142 if (ifc_create_default_route(ifname, info->gateway)) {
143 printerr("failed to set default route %s: %s\n", ipaddr(info->gateway), strerror(errno));
144 return -1;
145 }
146
147 snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
148 property_set(dns_prop_name, info->dns1 ? ipaddr(info->dns1) : "");
149 snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
150 property_set(dns_prop_name, info->dns2 ? ipaddr(info->dns2) : "");
151
152 last_good_info = *info;
153
154 return 0;
155 }
156
157 static const char *dhcp_type_to_name(uint32_t type)
158 {
159 switch(type) {
160 case DHCPDISCOVER: return "discover";
161 case DHCPOFFER: return "offer";
162 case DHCPREQUEST: return "request";
163 case DHCPDECLINE: return "decline";
164 case DHCPACK: return "ack";
165 case DHCPNAK: return "nak";
166 case DHCPRELEASE: return "release";
167 case DHCPINFORM: return "inform";
168 default: return "???";
169 }
170 }
171
172 void dump_dhcp_info(dhcp_info *info)
173 {
174 char addr[20], gway[20], mask[20];
175 LOGD("--- dhcp %s (%d) ---",
176 dhcp_type_to_name(info->type), info->type);
177 strcpy(addr, ipaddr(info->ipaddr));
178 strcpy(gway, ipaddr(info->gateway));
179 strcpy(mask, ipaddr(info->netmask));
180 LOGD("ip %s gw %s mask %s", addr, gway, mask);
181 if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
182 if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
183 LOGD("server %s, lease %d seconds",
184 ipaddr(info->serveraddr), info->lease);
185 }
186
187
188 int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
189 {
190 uint8_t *x;
191 unsigned int opt;
192 int optlen;
193
194 memset(info, 0, sizeof(dhcp_info));
195 if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
196
197 len -= (DHCP_MSG_FIXED_SIZE + 4);
198
199 if (msg->options[0] != OPT_COOKIE1) return -1;
200 if (msg->options[1] != OPT_COOKIE2) return -1;
201 if (msg->options[2] != OPT_COOKIE3) return -1;
202 if (msg->options[3] != OPT_COOKIE4) return -1;
203
204 x = msg->options + 4;
205
206 while (len > 2) {
207 opt = *x++;
208 if (opt == OPT_PAD) {
209 len--;
210 continue;
211 }
212 if (opt == OPT_END) {
213 break;
214 }
215 optlen = *x++;
216 len -= 2;
217 if (optlen > len) {
218 break;
219 }
220 switch(opt) {
221 case OPT_SUBNET_MASK:
222 if (optlen >= 4) memcpy(&info->netmask, x, 4);
223 break;
224 case OPT_GATEWAY:
225 if (optlen >= 4) memcpy(&info->gateway, x, 4);
226 break;
227 case OPT_DNS:
228 if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
229 if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
230 break;
231 case OPT_LEASE_TIME:
232 if (optlen >= 4) {
233 memcpy(&info->lease, x, 4);
234 info->lease = ntohl(info->lease);
235 }
236 break;
237 case OPT_SERVER_ID:
238 if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
239 break;
240 case OPT_MESSAGE_TYPE:
241 info->type = *x;
242 break;
243 default:
244 break;
245 }
246 x += optlen;
247 len -= optlen;
248 }
249
250 info->ipaddr = msg->yiaddr;
251
252 return 0;
253 }
254
255 #if VERBOSE
256
257 static void hex2str(char *buf, const unsigned char *array, int len)
258 {
259 int i;
260 char *cp = buf;
261
262 for (i = 0; i < len; i++) {
263 cp += sprintf(cp, " %02x ", array[i]);
264 }
265 }
266
267 void dump_dhcp_msg(dhcp_msg *msg, int len)
268 {
269 unsigned char *x;
270 unsigned int n,c;
271 int optsz;
272 const char *name;
273 char buf[2048];
274
275 LOGD("===== DHCP message:");
276 if (len < DHCP_MSG_FIXED_SIZE) {
277 LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
278 return;
279 }
280
281 len -= DHCP_MSG_FIXED_SIZE;
282
283 if (msg->op == OP_BOOTREQUEST)
284 name = "BOOTREQUEST";
285 else if (msg->op == OP_BOOTREPLY)
286 name = "BOOTREPLY";
287 else
288 name = "????";
289 LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
290 name, msg->op, msg->htype, msg->hlen, msg->hops);
291 LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
292 ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
293 LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
294 LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
295 LOGD("siaddr = %s", ipaddr(msg->siaddr));
296 LOGD("giaddr = %s", ipaddr(msg->giaddr));
297
298 c = msg->hlen > 16 ? 16 : msg->hlen;
299 hex2str(buf, msg->chaddr, c);
300 LOGD("chaddr = {%s}", buf);
301
302 for (n = 0; n < 64; n++) {
303 if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
304 if (msg->sname[n] == 0) break;
305 msg->sname[n] = '.';
306 }
307 }
308 msg->sname[63] = 0;
309
310 for (n = 0; n < 128; n++) {
311 if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
312 if (msg->file[n] == 0) break;
313 msg->file[n] = '.';
314 }
315 }
316 msg->file[127] = 0;
317
318 LOGD("sname = '%s'", msg->sname);
319 LOGD("file = '%s'", msg->file);
320
321 if (len < 4) return;
322 len -= 4;
323 x = msg->options + 4;
324
325 while (len > 2) {
326 if (*x == 0) {
327 x++;
328 len--;
329 continue;
330 }
331 if (*x == OPT_END) {
332 break;
333 }
334 len -= 2;
335 optsz = x[1];
336 if (optsz > len) break;
337 if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
338 if ((unsigned int)optsz < sizeof(buf) - 1) {
339 n = optsz;
340 } else {
341 n = sizeof(buf) - 1;
342 }
343 memcpy(buf, &x[2], n);
344 buf[n] = '\0';
345 } else {
346 hex2str(buf, &x[2], optsz);
347 }
348 if (x[0] == OPT_MESSAGE_TYPE)
349 name = dhcp_type_to_name(x[2]);
350 else
351 name = NULL;
352 LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
353 len -= optsz;
354 x = x + optsz + 2;
355 }
356 }
357
358 #endif
359
360 static int send_message(int sock, int if_index, dhcp_msg *msg, int size)
361 {
362 #if VERBOSE > 1
363 dump_dhcp_msg(msg, size);
364 #endif
365 return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
366 PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
367 }
368
369 static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
370 {
371 if (sz < DHCP_MSG_FIXED_SIZE) {
372 if (verbose) LOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
373 return 0;
374 }
375 if (reply->op != OP_BOOTREPLY) {
376 if (verbose) LOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
377 return 0;
378 }
379 if (reply->xid != msg->xid) {
380 if (verbose) LOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
381 ntohl(msg->xid));
382 return 0;
383 }
384 if (reply->htype != msg->htype) {
385 if (verbose) LOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
386 return 0;
387 }
388 if (reply->hlen != msg->hlen) {
389 if (verbose) LOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
390 return 0;
391 }
392 if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
393 if (verbose) LOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
394 return 0;
395 }
396 return 1;
397 }
398
399 #define STATE_SELECTING 1
400 #define STATE_REQUESTING 2
401
402 #define TIMEOUT_INITIAL 4000
403 #define TIMEOUT_MAX 32000
404
405 int dhcp_init_ifc(const char *ifname)
406 {
407 dhcp_msg discover_msg;
408 dhcp_msg request_msg;
409 dhcp_msg reply;
410 dhcp_msg *msg;
411 dhcp_info info;
412 int s, r, size;
413 int valid_reply;
414 uint32_t xid;
415 unsigned char hwaddr[6];
416 struct pollfd pfd;
417 unsigned int state;
418 unsigned int timeout;
419 int if_index;
420
421 xid = (uint32_t) get_msecs();
422
423 if (ifc_get_hwaddr(ifname, hwaddr)) {
424 return fatal("cannot obtain interface address");
425 }
426 if (ifc_get_ifindex(ifname, &if_index)) {
427 return fatal("cannot obtain interface index");
428 }
429
430 s = open_raw_socket(ifname, hwaddr, if_index);
431
432 timeout = TIMEOUT_INITIAL;
433 state = STATE_SELECTING;
434 info.type = 0;
435 goto transmit;
436
437 for (;;) {
438 pfd.fd = s;
439 pfd.events = POLLIN;
440 pfd.revents = 0;
441 r = poll(&pfd, 1, timeout);
442
443 if (r == 0) {
444 #if VERBOSE
445 printerr("TIMEOUT\n");
446 #endif
447 if (timeout >= TIMEOUT_MAX) {
448 printerr("timed out\n");
449 if ( info.type == DHCPOFFER ) {
450 printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
451 return ifc_configure(ifname, &info);
452 }
453 errno = ETIME;
454 close(s);
455 return -1;
456 }
457 timeout = timeout * 2;
458
459 transmit:
460 size = 0;
461 msg = NULL;
462 switch(state) {
463 case STATE_SELECTING:
464 msg = &discover_msg;
465 size = init_dhcp_discover_msg(msg, hwaddr, xid);
466 break;
467 case STATE_REQUESTING:
468 msg = &request_msg;
469 size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
470 break;
471 default:
472 r = 0;
473 }
474 if (size != 0) {
475 r = send_message(s, if_index, msg, size);
476 if (r < 0) {
477 printerr("error sending dhcp msg: %s\n", strerror(errno));
478 }
479 }
480 continue;
481 }
482
483 if (r < 0) {
484 if ((errno == EAGAIN) || (errno == EINTR)) {
485 continue;
486 }
487 return fatal("poll failed");
488 }
489
490 errno = 0;
491 r = receive_packet(s, &reply);
492 if (r < 0) {
493 if (errno != 0) {
494 LOGD("receive_packet failed (%d): %s", r, strerror(errno));
495 if (errno == ENETDOWN || errno == ENXIO) {
496 return -1;
497 }
498 }
499 continue;
500 }
501
502 #if VERBOSE > 1
503 dump_dhcp_msg(&reply, r);
504 #endif
505 decode_dhcp_msg(&reply, r, &info);
506
507 if (state == STATE_SELECTING) {
508 valid_reply = is_valid_reply(&discover_msg, &reply, r);
509 } else {
510 valid_reply = is_valid_reply(&request_msg, &reply, r);
511 }
512 if (!valid_reply) {
513 printerr("invalid reply\n");
514 continue;
515 }
516
517 if (verbose) dump_dhcp_info(&info);
518
519 switch(state) {
520 case STATE_SELECTING:
521 if (info.type == DHCPOFFER) {
522 state = STATE_REQUESTING;
523 timeout = TIMEOUT_INITIAL;
524 xid++;
525 goto transmit;
526 }
527 break;
528 case STATE_REQUESTING:
529 if (info.type == DHCPACK) {
530 printerr("configuring %s\n", ifname);
531 close(s);
532 return ifc_configure(ifname, &info);
533 } else if (info.type == DHCPNAK) {
534 printerr("configuration request denied\n");
535 close(s);
536 return -1;
537 } else {
538 printerr("ignoring %s message in state %d\n",
539 dhcp_type_to_name(info.type), state);
540 }
541 break;
542 }
543 }
544 close(s);
545 return 0;
546 }
547
548 int do_dhcp(char *iname)
549 {
550 if (ifc_set_addr(iname, 0)) {
551 printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
552 return -1;
553 }
554
555 if (ifc_up(iname)) {
556 printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
557 return -1;
558 }
559
560 return dhcp_init_ifc(iname);
561 }
+0
-100
libnetutils/dhcpmsg.c less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <netinet/in.h>
20
21 #include "dhcpmsg.h"
22
23 static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
24 {
25 uint8_t *x;
26
27 memset(msg, 0, sizeof(dhcp_msg));
28
29 msg->op = OP_BOOTREQUEST;
30 msg->htype = HTYPE_ETHER;
31 msg->hlen = 6;
32 msg->hops = 0;
33
34 msg->flags = htons(FLAGS_BROADCAST);
35
36 msg->xid = xid;
37
38 memcpy(msg->chaddr, hwaddr, 6);
39
40 x = msg->options;
41
42 *x++ = OPT_COOKIE1;
43 *x++ = OPT_COOKIE2;
44 *x++ = OPT_COOKIE3;
45 *x++ = OPT_COOKIE4;
46
47 *x++ = OPT_MESSAGE_TYPE;
48 *x++ = 1;
49 *x++ = type;
50
51 return x;
52 }
53
54 int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
55 {
56 uint8_t *x;
57
58 x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);
59
60 *x++ = OPT_PARAMETER_LIST;
61 *x++ = 4;
62 *x++ = OPT_SUBNET_MASK;
63 *x++ = OPT_GATEWAY;
64 *x++ = OPT_DNS;
65 *x++ = OPT_BROADCAST_ADDR;
66
67 *x++ = OPT_END;
68
69 return DHCP_MSG_FIXED_SIZE + (x - msg->options);
70 }
71
72 int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
73 uint32_t ipaddr, uint32_t serveraddr)
74 {
75 uint8_t *x;
76
77 x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
78
79 *x++ = OPT_PARAMETER_LIST;
80 *x++ = 4;
81 *x++ = OPT_SUBNET_MASK;
82 *x++ = OPT_GATEWAY;
83 *x++ = OPT_DNS;
84 *x++ = OPT_BROADCAST_ADDR;
85
86 *x++ = OPT_REQUESTED_IP;
87 *x++ = 4;
88 memcpy(x, &ipaddr, 4);
89 x += 4;
90
91 *x++ = OPT_SERVER_ID;
92 *x++ = 4;
93 memcpy(x, &serveraddr, 4);
94 x += 4;
95
96 *x++ = OPT_END;
97
98 return DHCP_MSG_FIXED_SIZE + (x - msg->options);
99 }
+0
-106
libnetutils/dhcpmsg.h less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _WIFI_DHCP_H_
17 #define _WIFI_DHCP_H_
18
19 #include <sys/types.h>
20
21 #define PORT_BOOTP_SERVER 67
22 #define PORT_BOOTP_CLIENT 68
23
24 /* RFC 2131 p 9 */
25 typedef struct dhcp_msg dhcp_msg;
26
27 #define OP_BOOTREQUEST 1
28 #define OP_BOOTREPLY 2
29
30 #define FLAGS_BROADCAST 0x8000
31
32 #define HTYPE_ETHER 1
33
34 struct dhcp_msg
35 {
36 uint8_t op; /* BOOTREQUEST / BOOTREPLY */
37 uint8_t htype; /* hw addr type */
38 uint8_t hlen; /* hw addr len */
39 uint8_t hops; /* client set to 0 */
40
41 uint32_t xid; /* transaction id */
42
43 uint16_t secs; /* seconds since start of acq */
44 uint16_t flags;
45
46 uint32_t ciaddr; /* client IP addr */
47 uint32_t yiaddr; /* your (client) IP addr */
48 uint32_t siaddr; /* ip addr of next server */
49 /* (DHCPOFFER and DHCPACK) */
50 uint32_t giaddr; /* relay agent IP addr */
51
52 uint8_t chaddr[16]; /* client hw addr */
53 char sname[64]; /* asciiz server hostname */
54 char file[128]; /* asciiz boot file name */
55
56 uint8_t options[1024]; /* optional parameters */
57 };
58
59 #define DHCP_MSG_FIXED_SIZE 236
60
61 /* first four bytes of options are a cookie to indicate that
62 ** the payload are DHCP options as opposed to some other BOOTP
63 ** extension.
64 */
65 #define OPT_COOKIE1 0x63
66 #define OPT_COOKIE2 0x82
67 #define OPT_COOKIE3 0x53
68 #define OPT_COOKIE4 0x63
69
70 /* BOOTP/DHCP options - see RFC 2132 */
71 #define OPT_PAD 0
72
73 #define OPT_SUBNET_MASK 1 /* 4 <ipaddr> */
74 #define OPT_TIME_OFFSET 2 /* 4 <seconds> */
75 #define OPT_GATEWAY 3 /* 4*n <ipaddr> * n */
76 #define OPT_DNS 6 /* 4*n <ipaddr> * n */
77 #define OPT_DOMAIN_NAME 15 /* n <domainnamestring> */
78 #define OPT_BROADCAST_ADDR 28 /* 4 <ipaddr> */
79
80 #define OPT_REQUESTED_IP 50 /* 4 <ipaddr> */
81 #define OPT_LEASE_TIME 51 /* 4 <seconds> */
82 #define OPT_MESSAGE_TYPE 53 /* 1 <msgtype> */
83 #define OPT_SERVER_ID 54 /* 4 <ipaddr> */
84 #define OPT_PARAMETER_LIST 55 /* n <optcode> * n */
85 #define OPT_MESSAGE 56 /* n <errorstring> */
86 #define OPT_CLASS_ID 60 /* n <opaque> */
87 #define OPT_CLIENT_ID 61 /* n <opaque> */
88 #define OPT_END 255
89
90 /* DHCP message types */
91 #define DHCPDISCOVER 1
92 #define DHCPOFFER 2
93 #define DHCPREQUEST 3
94 #define DHCPDECLINE 4
95 #define DHCPACK 5
96 #define DHCPNAK 6
97 #define DHCPRELEASE 7
98 #define DHCPINFORM 8
99
100 int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid);
101
102 int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
103 uint32_t ipaddr, uint32_t serveraddr);
104
105 #endif
+0
-428
libnetutils/ifc_utils.c less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include <sys/socket.h>
23 #include <sys/select.h>
24 #include <sys/types.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27
28 #include <linux/if.h>
29 #include <linux/sockios.h>
30 #include <linux/route.h>
31 #include <linux/wireless.h>
32
33 #ifdef ANDROID
34 #define LOG_TAG "NetUtils"
35 #include <cutils/log.h>
36 #include <cutils/properties.h>
37 #else
38 #include <stdio.h>
39 #include <string.h>
40 #define LOGD printf
41 #define LOGW printf
42 #endif
43
44 static int ifc_ctl_sock = -1;
45 void printerr(char *fmt, ...);
46
47 static const char *ipaddr_to_string(uint32_t addr)
48 {
49 struct in_addr in_addr;
50
51 in_addr.s_addr = addr;
52 return inet_ntoa(in_addr);
53 }
54
55 int ifc_init(void)
56 {
57 if (ifc_ctl_sock == -1) {
58 ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
59 if (ifc_ctl_sock < 0) {
60 printerr("socket() failed: %s\n", strerror(errno));
61 }
62 }
63 return ifc_ctl_sock < 0 ? -1 : 0;
64 }
65
66 void ifc_close(void)
67 {
68 if (ifc_ctl_sock != -1) {
69 (void)close(ifc_ctl_sock);
70 ifc_ctl_sock = -1;
71 }
72 }
73
74 static void ifc_init_ifr(const char *name, struct ifreq *ifr)
75 {
76 memset(ifr, 0, sizeof(struct ifreq));
77 strncpy(ifr->ifr_name, name, IFNAMSIZ);
78 ifr->ifr_name[IFNAMSIZ - 1] = 0;
79 }
80
81 int ifc_get_hwaddr(const char *name, void *ptr)
82 {
83 int r;
84 struct ifreq ifr;
85 ifc_init_ifr(name, &ifr);
86
87 r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
88 if(r < 0) return -1;
89
90 memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6);
91 return 0;
92 }
93
94 int ifc_get_ifindex(const char *name, int *if_indexp)
95 {
96 int r;
97 struct ifreq ifr;
98 ifc_init_ifr(name, &ifr);
99
100 r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
101 if(r < 0) return -1;
102
103 *if_indexp = ifr.ifr_ifindex;
104 return 0;
105 }
106
107 static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
108 {
109 struct ifreq ifr;
110 ifc_init_ifr(name, &ifr);
111
112 if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
113 ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
114 return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
115 }
116
117 int ifc_up(const char *name)
118 {
119 return ifc_set_flags(name, IFF_UP, 0);
120 }
121
122 int ifc_down(const char *name)
123 {
124 return ifc_set_flags(name, 0, IFF_UP);
125 }
126
127 static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
128 {
129 struct sockaddr_in *sin = (struct sockaddr_in *) sa;
130 sin->sin_family = AF_INET;
131 sin->sin_port = 0;
132 sin->sin_addr.s_addr = addr;
133 }
134
135 int ifc_set_addr(const char *name, in_addr_t addr)
136 {
137 struct ifreq ifr;
138
139 ifc_init_ifr(name, &ifr);
140 init_sockaddr_in(&ifr.ifr_addr, addr);
141
142 return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
143 }
144
145 int ifc_set_mask(const char *name, in_addr_t mask)
146 {
147 struct ifreq ifr;
148
149 ifc_init_ifr(name, &ifr);
150 init_sockaddr_in(&ifr.ifr_addr, mask);
151
152 return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
153 }
154
155 int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
156 {
157 struct ifreq ifr;
158 ifc_init_ifr(name, &ifr);
159
160 if (addr != NULL) {
161 if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
162 *addr = 0;
163 } else {
164 *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
165 }
166 }
167
168 if (mask != NULL) {
169 if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
170 *mask = 0;
171 } else {
172 *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
173 }
174 }
175
176 if (flags != NULL) {
177 if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
178 *flags = 0;
179 } else {
180 *flags = ifr.ifr_flags;
181 }
182 }
183
184 return 0;
185 }
186
187
188 int ifc_create_default_route(const char *name, in_addr_t addr)
189 {
190 struct rtentry rt;
191
192 memset(&rt, 0, sizeof(rt));
193
194 rt.rt_dst.sa_family = AF_INET;
195 rt.rt_flags = RTF_UP | RTF_GATEWAY;
196 rt.rt_dev = (void*) name;
197 init_sockaddr_in(&rt.rt_genmask, 0);
198 init_sockaddr_in(&rt.rt_gateway, addr);
199
200 return ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
201 }
202
203 int ifc_add_host_route(const char *name, in_addr_t addr)
204 {
205 struct rtentry rt;
206 int result;
207
208 memset(&rt, 0, sizeof(rt));
209
210 rt.rt_dst.sa_family = AF_INET;
211 rt.rt_flags = RTF_UP | RTF_HOST;
212 rt.rt_dev = (void*) name;
213 init_sockaddr_in(&rt.rt_dst, addr);
214 init_sockaddr_in(&rt.rt_genmask, 0);
215 init_sockaddr_in(&rt.rt_gateway, 0);
216
217 ifc_init();
218 result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
219 if (result < 0 && errno == EEXIST) {
220 result = 0;
221 }
222 ifc_close();
223 return result;
224 }
225
226 int ifc_disable(const char *ifname)
227 {
228 int result;
229
230 ifc_init();
231 result = ifc_down(ifname);
232 ifc_set_addr(ifname, 0);
233 ifc_close();
234 return result;
235 }
236
237 int ifc_reset_connections(const char *ifname)
238 {
239 #ifdef HAVE_ANDROID_OS
240 int result;
241 in_addr_t myaddr;
242 struct ifreq ifr;
243
244 ifc_init();
245 ifc_get_info(ifname, &myaddr, NULL, NULL);
246 ifc_init_ifr(ifname, &ifr);
247 init_sockaddr_in(&ifr.ifr_addr, myaddr);
248 result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
249 ifc_close();
250
251 return result;
252 #else
253 return 0;
254 #endif
255 }
256
257 /*
258 * Remove the routes associated with the named interface.
259 */
260 int ifc_remove_host_routes(const char *name)
261 {
262 char ifname[64];
263 in_addr_t dest, gway, mask;
264 int flags, refcnt, use, metric, mtu, win, irtt;
265 struct rtentry rt;
266 FILE *fp;
267 struct in_addr addr;
268
269 fp = fopen("/proc/net/route", "r");
270 if (fp == NULL)
271 return -1;
272 /* Skip the header line */
273 if (fscanf(fp, "%*[^\n]\n") < 0) {
274 fclose(fp);
275 return -1;
276 }
277 ifc_init();
278 for (;;) {
279 int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
280 ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
281 &mtu, &win, &irtt);
282 if (nread != 11) {
283 break;
284 }
285 if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
286 || strcmp(ifname, name) != 0) {
287 continue;
288 }
289 memset(&rt, 0, sizeof(rt));
290 rt.rt_dev = (void *)name;
291 init_sockaddr_in(&rt.rt_dst, dest);
292 init_sockaddr_in(&rt.rt_gateway, gway);
293 init_sockaddr_in(&rt.rt_genmask, mask);
294 addr.s_addr = dest;
295 if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
296 LOGD("failed to remove route for %s to %s: %s",
297 ifname, inet_ntoa(addr), strerror(errno));
298 }
299 }
300 fclose(fp);
301 ifc_close();
302 return 0;
303 }
304
305 /*
306 * Return the address of the default gateway
307 *
308 * TODO: factor out common code from this and remove_host_routes()
309 * so that we only scan /proc/net/route in one place.
310 */
311 int ifc_get_default_route(const char *ifname)
312 {
313 char name[64];
314 in_addr_t dest, gway, mask;
315 int flags, refcnt, use, metric, mtu, win, irtt;
316 int result;
317 FILE *fp;
318
319 fp = fopen("/proc/net/route", "r");
320 if (fp == NULL)
321 return 0;
322 /* Skip the header line */
323 if (fscanf(fp, "%*[^\n]\n") < 0) {
324 fclose(fp);
325 return 0;
326 }
327 ifc_init();
328 result = 0;
329 for (;;) {
330 int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
331 name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
332 &mtu, &win, &irtt);
333 if (nread != 11) {
334 break;
335 }
336 if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
337 && dest == 0
338 && strcmp(ifname, name) == 0) {
339 result = gway;
340 break;
341 }
342 }
343 fclose(fp);
344 ifc_close();
345 return result;
346 }
347
348 /*
349 * Sets the specified gateway as the default route for the named interface.
350 */
351 int ifc_set_default_route(const char *ifname, in_addr_t gateway)
352 {
353 struct in_addr addr;
354 int result;
355
356 ifc_init();
357 addr.s_addr = gateway;
358 if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
359 LOGD("failed to add %s as default route for %s: %s",
360 inet_ntoa(addr), ifname, strerror(errno));
361 }
362 ifc_close();
363 return result;
364 }
365
366 /*
367 * Removes the default route for the named interface.
368 */
369 int ifc_remove_default_route(const char *ifname)
370 {
371 struct rtentry rt;
372 int result;
373
374 ifc_init();
375 memset(&rt, 0, sizeof(rt));
376 rt.rt_dev = (void *)ifname;
377 rt.rt_flags = RTF_UP|RTF_GATEWAY;
378 init_sockaddr_in(&rt.rt_dst, 0);
379 if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) {
380 LOGD("failed to remove default route for %s: %s", ifname, strerror(errno));
381 }
382 ifc_close();
383 return result;
384 }
385
386 int
387 ifc_configure(const char *ifname,
388 in_addr_t address,
389 in_addr_t netmask,
390 in_addr_t gateway,
391 in_addr_t dns1,
392 in_addr_t dns2) {
393
394 char dns_prop_name[PROPERTY_KEY_MAX];
395
396 ifc_init();
397
398 if (ifc_up(ifname)) {
399 printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno));
400 ifc_close();
401 return -1;
402 }
403 if (ifc_set_addr(ifname, address)) {
404 printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno));
405 ifc_close();
406 return -1;
407 }
408 if (ifc_set_mask(ifname, netmask)) {
409 printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
410 ifc_close();
411 return -1;
412 }
413 if (ifc_create_default_route(ifname, gateway)) {
414 printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno));
415 ifc_close();
416 return -1;
417 }
418
419 ifc_close();
420
421 snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname);
422 property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
423 snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname);
424 property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
425
426 return 0;
427 }
+0
-35
libnetutils/ifc_utils.h less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _IFC_UTILS_H_
17 #define _IFC_UTILS_H_
18
19 int ifc_init(void);
20
21 int ifc_get_ifindex(const char *name, int *if_indexp);
22 int ifc_get_hwaddr(const char *name, void *ptr);
23
24 int ifc_up(const char *name);
25 int ifc_down(const char *name);
26
27 int ifc_set_addr(const char *name, unsigned addr);
28 int ifc_set_mask(const char *name, unsigned mask);
29
30 int ifc_create_default_route(const char *name, unsigned addr);
31
32 int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
33
34 #endif
+0
-239
libnetutils/packet.c less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/uio.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/ip.h>
22 #include <netinet/udp.h>
23 #include <linux/if_packet.h>
24 #include <linux/if_ether.h>
25 #include <errno.h>
26
27 #ifdef ANDROID
28 #define LOG_TAG "DHCP"
29 #include <cutils/log.h>
30 #else
31 #include <stdio.h>
32 #include <string.h>
33 #define LOGD printf
34 #define LOGW printf
35 #endif
36
37 #include "dhcpmsg.h"
38
39 int fatal();
40
41 int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index)
42 {
43 int s, flag;
44 struct sockaddr_ll bindaddr;
45
46 if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
47 return fatal("socket(PF_PACKET)");
48 }
49
50 memset(&bindaddr, 0, sizeof(bindaddr));
51 bindaddr.sll_family = AF_PACKET;
52 bindaddr.sll_protocol = htons(ETH_P_IP);
53 bindaddr.sll_halen = ETH_ALEN;
54 memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
55 bindaddr.sll_ifindex = if_index;
56
57 if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
58 return fatal("Cannot bind raw socket to interface");
59 }
60
61 return s;
62 }
63
64 static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
65 {
66 uint16_t *up = (uint16_t *)buffer;
67 uint32_t sum = startsum;
68 uint32_t upper16;
69
70 while (count > 1) {
71 sum += *up++;
72 count -= 2;
73 }
74 if (count > 0) {
75 sum += (uint16_t) *(uint8_t *)up;
76 }
77 while ((upper16 = (sum >> 16)) != 0) {
78 sum = (sum & 0xffff) + upper16;
79 }
80 return sum;
81 }
82
83 static uint32_t finish_sum(uint32_t sum)
84 {
85 return ~sum & 0xffff;
86 }
87
88 int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
89 uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
90 {
91 struct iphdr ip;
92 struct udphdr udp;
93 struct iovec iov[3];
94 uint32_t udpsum;
95 uint16_t temp;
96 struct msghdr msghdr;
97 struct sockaddr_ll destaddr;
98
99 ip.version = IPVERSION;
100 ip.ihl = sizeof(ip) >> 2;
101 ip.tos = 0;
102 ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
103 ip.id = 0;
104 ip.frag_off = 0;
105 ip.ttl = IPDEFTTL;
106 ip.protocol = IPPROTO_UDP;
107 ip.check = 0;
108 ip.saddr = saddr;
109 ip.daddr = daddr;
110 ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
111
112 udp.source = htons(sport);
113 udp.dest = htons(dport);
114 udp.len = htons(sizeof(udp) + size);
115 udp.check = 0;
116
117 /* Calculate checksum for pseudo header */
118 udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
119 udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
120 temp = htons(IPPROTO_UDP);
121 udpsum = checksum(&temp, sizeof(temp), udpsum);
122 temp = udp.len;
123 udpsum = checksum(&temp, sizeof(temp), udpsum);
124
125 /* Add in the checksum for the udp header */
126 udpsum = checksum(&udp, sizeof(udp), udpsum);
127
128 /* Add in the checksum for the data */
129 udpsum = checksum(msg, size, udpsum);
130 udp.check = finish_sum(udpsum);
131
132 iov[0].iov_base = (char *)&ip;
133 iov[0].iov_len = sizeof(ip);
134 iov[1].iov_base = (char *)&udp;
135 iov[1].iov_len = sizeof(udp);
136 iov[2].iov_base = (char *)msg;
137 iov[2].iov_len = size;
138 memset(&destaddr, 0, sizeof(destaddr));
139 destaddr.sll_family = AF_PACKET;
140 destaddr.sll_protocol = htons(ETH_P_IP);
141 destaddr.sll_ifindex = if_index;
142 destaddr.sll_halen = ETH_ALEN;
143 memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
144
145 msghdr.msg_name = &destaddr;
146 msghdr.msg_namelen = sizeof(destaddr);
147 msghdr.msg_iov = iov;
148 msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
149 msghdr.msg_flags = 0;
150 msghdr.msg_control = 0;
151 msghdr.msg_controllen = 0;
152 return sendmsg(s, &msghdr, 0);
153 }
154
155 int receive_packet(int s, struct dhcp_msg *msg)
156 {
157 int nread;
158 int is_valid;
159 struct dhcp_packet {
160 struct iphdr ip;
161 struct udphdr udp;
162 struct dhcp_msg dhcp;
163 } packet;
164 int dhcp_size;
165 uint32_t sum;
166 uint16_t temp;
167 uint32_t saddr, daddr;
168
169 nread = read(s, &packet, sizeof(packet));
170 if (nread < 0) {
171 return -1;
172 }
173 /*
174 * The raw packet interface gives us all packets received by the
175 * network interface. We need to filter out all packets that are
176 * not meant for us.
177 */
178 is_valid = 0;
179 if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr))) {
180 #if VERBOSE
181 LOGD("Packet is too small (%d) to be a UDP datagram", nread);
182 #endif
183 } else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2)) {
184 #if VERBOSE
185 LOGD("Not a valid IP packet");
186 #endif
187 } else if (nread < ntohs(packet.ip.tot_len)) {
188 #if VERBOSE
189 LOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
190 #endif
191 } else if (packet.ip.protocol != IPPROTO_UDP) {
192 #if VERBOSE
193 LOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
194 #endif
195 } else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT)) {
196 #if VERBOSE
197 LOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
198 #endif
199 } else {
200 is_valid = 1;
201 }
202
203 if (!is_valid) {
204 return -1;
205 }
206
207 /* Seems like it's probably a valid DHCP packet */
208 /* validate IP header checksum */
209 sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
210 if (sum != 0) {
211 LOGW("IP header checksum failure (0x%x)", packet.ip.check);
212 return -1;
213 }
214 /*
215 * Validate the UDP checksum.
216 * Since we don't need the IP header anymore, we "borrow" it
217 * to construct the pseudo header used in the checksum calculation.
218 */
219 dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
220 saddr = packet.ip.saddr;
221 daddr = packet.ip.daddr;
222 nread = ntohs(packet.ip.tot_len);
223 memset(&packet.ip, 0, sizeof(packet.ip));
224 packet.ip.saddr = saddr;
225 packet.ip.daddr = daddr;
226 packet.ip.protocol = IPPROTO_UDP;
227 packet.ip.tot_len = packet.udp.len;
228 temp = packet.udp.check;
229 packet.udp.check = 0;
230 sum = finish_sum(checksum(&packet, nread, 0));
231 packet.udp.check = temp;
232 if (temp != sum) {
233 LOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
234 return -1;
235 }
236 memcpy(msg, &packet.dhcp, dhcp_size);
237 return dhcp_size;
238 }
+0
-25
libnetutils/packet.h less more
0 /*
1 * Copyright 2008, The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _WIFI_PACKET_H_
17 #define _WIFI_PACKET_H_
18
19 int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
20 int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
21 uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
22 int receive_packet(int s, struct dhcp_msg *msg);
23
24 #endif
+0
-92
libpixelflinger/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 #
4 # ARMv6 specific objects
5 #
6
7 ifeq ($(TARGET_ARCH),arm)
8 LOCAL_ASFLAGS := -march=armv6
9 LOCAL_SRC_FILES := rotate90CW_4x4_16v6.S
10 LOCAL_MODULE := libpixelflinger_armv6
11 include $(BUILD_STATIC_LIBRARY)
12 endif
13
14 #
15 # C/C++ and ARMv5 objects
16 #
17
18 include $(CLEAR_VARS)
19 PIXELFLINGER_SRC_FILES:= \
20 codeflinger/ARMAssemblerInterface.cpp \
21 codeflinger/ARMAssemblerProxy.cpp \
22 codeflinger/ARMAssembler.cpp \
23 codeflinger/CodeCache.cpp \
24 codeflinger/GGLAssembler.cpp \
25 codeflinger/load_store.cpp \
26 codeflinger/blending.cpp \
27 codeflinger/texturing.cpp \
28 codeflinger/disassem.c \
29 tinyutils/SharedBuffer.cpp \
30 tinyutils/VectorImpl.cpp \
31 fixed.cpp.arm \
32 picker.cpp.arm \
33 pixelflinger.cpp.arm \
34 trap.cpp.arm \
35 scanline.cpp.arm \
36 format.cpp \
37 clear.cpp \
38 raster.cpp \
39 buffer.cpp
40
41 ifeq ($(TARGET_ARCH),arm)
42 PIXELFLINGER_SRC_FILES += t32cb16blend.S
43 endif
44
45 ifeq ($(TARGET_ARCH),arm)
46 # special optimization flags for pixelflinger
47 PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
48 endif
49
50 LOCAL_SHARED_LIBRARIES := libcutils
51
52 ifneq ($(TARGET_ARCH),arm)
53 # Required to define logging functions on the simulator.
54 # TODO: move the simulator logging functions into libcutils with
55 # the rest of the basic log stuff.
56 LOCAL_SHARED_LIBRARIES += libutils
57 endif
58
59 #
60 # Shared library
61 #
62
63 LOCAL_MODULE:= libpixelflinger
64 LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
65 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
66 ifneq ($(BUILD_TINY_ANDROID),true)
67 # Really this should go away entirely or at least not depend on
68 # libhardware, but this at least gets us built.
69 LOCAL_SHARED_LIBRARIES += libhardware_legacy
70 LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
71 endif
72 ifeq ($(TARGET_ARCH),arm)
73 LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6
74 endif
75 include $(BUILD_SHARED_LIBRARY)
76
77 #
78 # Static library version
79 #
80
81 include $(CLEAR_VARS)
82 LOCAL_MODULE:= libpixelflinger_static
83 LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
84 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
85 ifeq ($(TARGET_ARCH),arm)
86 LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6
87 endif
88 include $(BUILD_STATIC_LIBRARY)
89
90
91 include $(call all-makefiles-under,$(LOCAL_PATH))
+0
-0
libpixelflinger/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
libpixelflinger/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-384
libpixelflinger/buffer.cpp less more
0 /* libs/pixelflinger/buffer.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #include <assert.h>
19
20 #include "buffer.h"
21
22 namespace android {
23 // ----------------------------------------------------------------------------
24
25 static void read_pixel(const surface_t* s, context_t* c,
26 uint32_t x, uint32_t y, pixel_t* pixel);
27 static void write_pixel(const surface_t* s, context_t* c,
28 uint32_t x, uint32_t y, const pixel_t* pixel);
29 static void readRGB565(const surface_t* s, context_t* c,
30 uint32_t x, uint32_t y, pixel_t* pixel);
31 static void readABGR8888(const surface_t* s, context_t* c,
32 uint32_t x, uint32_t y, pixel_t* pixel);
33
34 static uint32_t logic_op(int op, uint32_t s, uint32_t d);
35 static uint32_t extract(uint32_t v, int h, int l, int bits);
36 static uint32_t expand(uint32_t v, int sbits, int dbits);
37 static uint32_t downshift_component(uint32_t in, uint32_t v,
38 int sh, int sl, int dh, int dl, int ch, int cl, int dither);
39
40 // ----------------------------------------------------------------------------
41
42 void ggl_init_texture(context_t* c)
43 {
44 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
45 texture_t& t = c->state.texture[i];
46 t.s_coord = GGL_ONE_TO_ONE;
47 t.t_coord = GGL_ONE_TO_ONE;
48 t.s_wrap = GGL_REPEAT;
49 t.t_wrap = GGL_REPEAT;
50 t.min_filter = GGL_NEAREST;
51 t.mag_filter = GGL_NEAREST;
52 t.env = GGL_MODULATE;
53 }
54 c->activeTMU = &(c->state.texture[0]);
55 }
56
57 void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src)
58 {
59 dst->width = src->width;
60 dst->height = src->height;
61 dst->stride = src->stride;
62 dst->data = src->data;
63 dst->format = src->format;
64 dst->dirty = 1;
65 if (__builtin_expect(dst->stride < 0, false)) {
66 const GGLFormat& pixelFormat(c->formats[dst->format]);
67 const int32_t bpr = -dst->stride * pixelFormat.size;
68 dst->data += bpr * (dst->height-1);
69 }
70 }
71
72 static void pick_read_write(surface_t* s)
73 {
74 // Choose best reader/writers.
75 switch (s->format) {
76 case GGL_PIXEL_FORMAT_RGBA_8888: s->read = readABGR8888; break;
77 case GGL_PIXEL_FORMAT_RGB_565: s->read = readRGB565; break;
78 default: s->read = read_pixel; break;
79 }
80 s->write = write_pixel;
81 }
82
83 void ggl_pick_texture(context_t* c)
84 {
85 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
86 surface_t& s = c->state.texture[i].surface;
87 if ((!c->state.texture[i].enable) || (!s.dirty))
88 continue;
89 s.dirty = 0;
90 pick_read_write(&s);
91 generated_tex_vars_t& gen = c->generated_vars.texture[i];
92 gen.width = s.width;
93 gen.height = s.height;
94 gen.stride = s.stride;
95 gen.data = int32_t(s.data);
96 }
97 }
98
99 void ggl_pick_cb(context_t* c)
100 {
101 surface_t& s = c->state.buffers.color;
102 if (s.dirty) {
103 s.dirty = 0;
104 pick_read_write(&s);
105 }
106 }
107
108 // ----------------------------------------------------------------------------
109
110 void read_pixel(const surface_t* s, context_t* c,
111 uint32_t x, uint32_t y, pixel_t* pixel)
112 {
113 assert((x < s->width) && (y < s->height));
114
115 const GGLFormat* f = &(c->formats[s->format]);
116 int32_t index = x + (s->stride * y);
117 uint8_t* const data = s->data + index * f->size;
118 uint32_t v = 0;
119 switch (f->size) {
120 case 1: v = *data; break;
121 case 2: v = *(uint16_t*)data; break;
122 case 3: v = (data[2]<<16)|(data[1]<<8)|data[0]; break;
123 case 4: v = GGL_RGBA_TO_HOST(*(uint32_t*)data); break;
124 }
125 for (int i=0 ; i<4 ; i++) {
126 pixel->s[i] = f->c[i].h - f->c[i].l;
127 if (pixel->s[i])
128 pixel->c[i] = extract(v, f->c[i].h, f->c[i].l, f->size*8);
129 }
130 }
131
132 void readRGB565(const surface_t* s, context_t* c,
133 uint32_t x, uint32_t y, pixel_t* pixel)
134 {
135 uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
136 pixel->c[0] = 0;
137 pixel->c[1] = v>>11;
138 pixel->c[2] = (v>>5)&0x3F;
139 pixel->c[3] = v&0x1F;
140 pixel->s[0] = 0;
141 pixel->s[1] = 5;
142 pixel->s[2] = 6;
143 pixel->s[3] = 5;
144 }
145
146 void readABGR8888(const surface_t* s, context_t* c,
147 uint32_t x, uint32_t y, pixel_t* pixel)
148 {
149 uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
150 v = GGL_RGBA_TO_HOST(v);
151 pixel->c[0] = v>>24; // A
152 pixel->c[1] = v&0xFF; // R
153 pixel->c[2] = (v>>8)&0xFF; // G
154 pixel->c[3] = (v>>16)&0xFF; // B
155 pixel->s[0] =
156 pixel->s[1] =
157 pixel->s[2] =
158 pixel->s[3] = 8;
159 }
160
161 void write_pixel(const surface_t* s, context_t* c,
162 uint32_t x, uint32_t y, const pixel_t* pixel)
163 {
164 assert((x < s->width) && (y < s->height));
165
166 int dither = -1;
167 if (c->state.enables & GGL_ENABLE_DITHER) {
168 dither = c->ditherMatrix[ (x & GGL_DITHER_MASK) +
169 ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
170 }
171
172 const GGLFormat* f = &(c->formats[s->format]);
173 int32_t index = x + (s->stride * y);
174 uint8_t* const data = s->data + index * f->size;
175
176 uint32_t mask = 0;
177 uint32_t v = 0;
178 for (int i=0 ; i<4 ; i++) {
179 const int component_mask = 1 << i;
180 if (f->components>=GGL_LUMINANCE &&
181 (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
182 // destinations L formats don't have G or B
183 continue;
184 }
185 const int l = f->c[i].l;
186 const int h = f->c[i].h;
187 if (h && (c->state.mask.color & component_mask)) {
188 mask |= (((1<<(h-l))-1)<<l);
189 uint32_t u = pixel->c[i];
190 int32_t pixelSize = pixel->s[i];
191 if (pixelSize < (h-l)) {
192 u = expand(u, pixelSize, h-l);
193 pixelSize = h-l;
194 }
195 v = downshift_component(v, u, pixelSize, 0, h, l, 0, 0, dither);
196 }
197 }
198
199 if ((c->state.mask.color != 0xF) ||
200 (c->state.enables & GGL_ENABLE_LOGIC_OP)) {
201 uint32_t d = 0;
202 switch (f->size) {
203 case 1: d = *data; break;
204 case 2: d = *(uint16_t*)data; break;
205 case 3: d = (data[2]<<16)|(data[1]<<8)|data[0]; break;
206 case 4: d = GGL_RGBA_TO_HOST(*(uint32_t*)data); break;
207 }
208 if (c->state.enables & GGL_ENABLE_LOGIC_OP) {
209 v = logic_op(c->state.logic_op.opcode, v, d);
210 v &= mask;
211 }
212 v |= (d & ~mask);
213 }
214
215 switch (f->size) {
216 case 1: *data = v; break;
217 case 2: *(uint16_t*)data = v; break;
218 case 3:
219 data[0] = v;
220 data[1] = v>>8;
221 data[2] = v>>16;
222 break;
223 case 4: *(uint32_t*)data = GGL_HOST_TO_RGBA(v); break;
224 }
225 }
226
227 static uint32_t logic_op(int op, uint32_t s, uint32_t d)
228 {
229 switch(op) {
230 case GGL_CLEAR: return 0;
231 case GGL_AND: return s & d;
232 case GGL_AND_REVERSE: return s & ~d;
233 case GGL_COPY: return s;
234 case GGL_AND_INVERTED: return ~s & d;
235 case GGL_NOOP: return d;
236 case GGL_XOR: return s ^ d;
237 case GGL_OR: return s | d;
238 case GGL_NOR: return ~(s | d);
239 case GGL_EQUIV: return ~(s ^ d);
240 case GGL_INVERT: return ~d;
241 case GGL_OR_REVERSE: return s | ~d;
242 case GGL_COPY_INVERTED: return ~s;
243 case GGL_OR_INVERTED: return ~s | d;
244 case GGL_NAND: return ~(s & d);
245 case GGL_SET: return ~0;
246 };
247 return s;
248 }
249
250
251 uint32_t ggl_expand(uint32_t v, int sbits, int dbits)
252 {
253 return expand(v, sbits, dbits);
254 }
255
256 uint32_t ggl_pack_color(context_t* c, int32_t format,
257 GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a)
258 {
259 const GGLFormat* f = &(c->formats[format]);
260 uint32_t p = 0;
261 const int32_t hbits = GGL_COLOR_BITS;
262 const int32_t lbits = GGL_COLOR_BITS - 8;
263 p = downshift_component(p, r, hbits, lbits, f->rh, f->rl, 0, 1, -1);
264 p = downshift_component(p, g, hbits, lbits, f->gh, f->gl, 0, 1, -1);
265 p = downshift_component(p, b, hbits, lbits, f->bh, f->bl, 0, 1, -1);
266 p = downshift_component(p, a, hbits, lbits, f->ah, f->al, 0, 1, -1);
267 switch (f->size) {
268 case 1: p |= p << 8; // fallthrough
269 case 2: p |= p << 16;
270 }
271 return p;
272 }
273
274 // ----------------------------------------------------------------------------
275
276 // extract a component from a word
277 uint32_t extract(uint32_t v, int h, int l, int bits)
278 {
279 assert(h);
280 if (l) {
281 v >>= l;
282 }
283 if (h != bits) {
284 v &= (1<<(h-l))-1;
285 }
286 return v;
287 }
288
289 // expand a component from sbits to dbits
290 uint32_t expand(uint32_t v, int sbits, int dbits)
291 {
292 if (dbits > sbits) {
293 assert(sbits);
294 if (sbits==1) {
295 v = (v<<dbits) - v;
296 } else {
297 if (dbits % sbits) {
298 v <<= (dbits-sbits);
299 dbits -= sbits;
300 do {
301 v |= v>>sbits;
302 dbits -= sbits;
303 sbits *= 2;
304 } while (dbits>0);
305 } else {
306 dbits -= sbits;
307 do {
308 v |= v<<sbits;
309 dbits -= sbits;
310 if (sbits*2 < dbits) {
311 sbits *= 2;
312 }
313 } while (dbits > 0);
314 }
315 }
316 }
317 return v;
318 }
319
320 // downsample a component from sbits to dbits
321 // and shift / construct the pixel
322 uint32_t downshift_component( uint32_t in, uint32_t v,
323 int sh, int sl, // src
324 int dh, int dl, // dst
325 int ch, int cl, // clear
326 int dither)
327 {
328 const int sbits = sh-sl;
329 const int dbits = dh-dl;
330
331 assert(sbits>=dbits);
332
333
334 if (sbits>dbits) {
335 if (dither>=0) {
336 v -= (v>>dbits); // fix up
337 const int shift = (GGL_DITHER_BITS - (sbits-dbits));
338 if (shift >= 0) v += (dither >> shift) << sl;
339 else v += (dither << (-shift)) << sl;
340 } else {
341 // don't do that right now, so we can reproduce the same
342 // artifacts we get on ARM (Where we don't do this)
343 // -> this is not really needed if we don't dither
344 //if (dBits > 1) { // result already OK if dBits==1
345 // v -= (v>>dbits); // fix up
346 // v += 1 << ((sbits-dbits)-1); // rounding
347 //}
348 }
349 }
350
351
352 // we need to clear the high bits of the source
353 if (ch) {
354 v <<= 32-sh;
355 sl += 32-sh;
356 sh = 32;
357 }
358
359 if (dl) {
360 if (cl || (sbits>dbits)) {
361 v >>= sh-dbits;
362 sl = 0;
363 sh = dbits;
364 in |= v<<dl;
365 } else {
366 // sbits==dbits and we don't need to clean the lower bits
367 // so we just have to shift the component to the right location
368 int shift = dh-sh;
369 in |= v<<shift;
370 }
371 } else {
372 // destination starts at bit 0
373 // ie: sh-dh == sh-dbits
374 int shift = sh-dh;
375 if (shift > 0) in |= v>>shift;
376 else if (shift < 0) in |= v<<shift;
377 else in |= v;
378 }
379 return in;
380 }
381
382 // ----------------------------------------------------------------------------
383 }; // namespace android
+0
-39
libpixelflinger/buffer.h less more
0 /* libs/pixelflinger/buffer.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_GGL_TEXTURE_H
19 #define ANDROID_GGL_TEXTURE_H
20
21 #include <private/pixelflinger/ggl_context.h>
22
23 namespace android {
24
25 void ggl_init_texture(context_t* c);
26
27 void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src);
28
29 void ggl_pick_texture(context_t* c);
30 void ggl_pick_cb(context_t* c);
31
32 uint32_t ggl_expand(uint32_t v, int sbits, int dbits);
33 uint32_t ggl_pack_color(context_t* c, int32_t format,
34 GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a);
35
36 }; // namespace android
37
38 #endif // ANDROID_GGL_TEXTURE_H
+0
-171
libpixelflinger/clear.cpp less more
0 /* libs/pixelflinger/clear.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <cutils/memory.h>
18
19 #include "clear.h"
20 #include "buffer.h"
21
22 namespace android {
23
24 // ----------------------------------------------------------------------------
25
26 static void ggl_clear(void* c, GGLbitfield mask);
27 static void ggl_clearColorx(void* c,
28 GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);
29 static void ggl_clearDepthx(void* c, GGLclampx depth);
30 static void ggl_clearStencil(void* c, GGLint s);
31
32 // ----------------------------------------------------------------------------
33
34 void ggl_init_clear(context_t* c)
35 {
36 GGLContext& procs = *(GGLContext*)c;
37 GGL_INIT_PROC(procs, clear);
38 GGL_INIT_PROC(procs, clearColorx);
39 GGL_INIT_PROC(procs, clearDepthx);
40 GGL_INIT_PROC(procs, clearStencil);
41 c->state.clear.dirty = GGL_STENCIL_BUFFER_BIT |
42 GGL_COLOR_BUFFER_BIT |
43 GGL_DEPTH_BUFFER_BIT;
44 c->state.clear.depth = FIXED_ONE;
45 }
46
47 // ----------------------------------------------------------------------------
48
49 static void memset2d(context_t* c, const surface_t& s, uint32_t packed,
50 uint32_t l, uint32_t t, uint32_t w, uint32_t h)
51 {
52 const uint32_t size = c->formats[s.format].size;
53 const int32_t stride = s.stride * size;
54 uint8_t* dst = (uint8_t*)s.data + (l + t*s.stride)*size;
55 w *= size;
56
57 if (ggl_likely(int32_t(w) == stride)) {
58 // clear the whole thing in one call
59 w *= h;
60 h = 1;
61 }
62
63 switch (size) {
64 case 1:
65 do {
66 memset(dst, packed, w);
67 dst += stride;
68 } while(--h);
69 break;
70 case 2:
71 do {
72 android_memset16((uint16_t*)dst, packed, w);
73 dst += stride;
74 } while(--h);
75 break;
76 case 3: // XXX: 24-bit clear.
77 break;
78 case 4:
79 do {
80 android_memset32((uint32_t*)dst, packed, w);
81 dst += stride;
82 } while(--h);
83 break;
84 }
85 }
86
87 static inline GGLfixed fixedToZ(GGLfixed z) {
88 return GGLfixed(((int64_t(z) << 16) - z) >> 16);
89 }
90
91 static void ggl_clear(void* con, GGLbitfield mask)
92 {
93 GGL_CONTEXT(c, con);
94
95 // XXX: rgba-dithering, rgba-masking
96 // XXX: handle all formats of Z and S
97
98 const uint32_t l = c->state.scissor.left;
99 const uint32_t t = c->state.scissor.top;
100 uint32_t w = c->state.scissor.right - l;
101 uint32_t h = c->state.scissor.bottom - t;
102
103 if (!w || !h)
104 return;
105
106 // unexsiting buffers have no effect...
107 if (c->state.buffers.color.format == 0)
108 mask &= ~GGL_COLOR_BUFFER_BIT;
109
110 if (c->state.buffers.depth.format == 0)
111 mask &= ~GGL_DEPTH_BUFFER_BIT;
112
113 if (c->state.buffers.stencil.format == 0)
114 mask &= ~GGL_STENCIL_BUFFER_BIT;
115
116 if (mask & GGL_COLOR_BUFFER_BIT) {
117 if (c->state.clear.dirty & GGL_COLOR_BUFFER_BIT) {
118 c->state.clear.dirty &= ~GGL_COLOR_BUFFER_BIT;
119
120 uint32_t colorPacked = ggl_pack_color(c,
121 c->state.buffers.color.format,
122 gglFixedToIteratedColor(c->state.clear.r),
123 gglFixedToIteratedColor(c->state.clear.g),
124 gglFixedToIteratedColor(c->state.clear.b),
125 gglFixedToIteratedColor(c->state.clear.a));
126
127 c->state.clear.colorPacked = GGL_HOST_TO_RGBA(colorPacked);
128 }
129 const uint32_t packed = c->state.clear.colorPacked;
130 memset2d(c, c->state.buffers.color, packed, l, t, w, h);
131 }
132 if (mask & GGL_DEPTH_BUFFER_BIT) {
133 if (c->state.clear.dirty & GGL_DEPTH_BUFFER_BIT) {
134 c->state.clear.dirty &= ~GGL_DEPTH_BUFFER_BIT;
135 uint32_t depth = fixedToZ(c->state.clear.depth);
136 c->state.clear.depthPacked = (depth<<16)|depth;
137 }
138 const uint32_t packed = c->state.clear.depthPacked;
139 memset2d(c, c->state.buffers.depth, packed, l, t, w, h);
140 }
141
142 // XXX: do stencil buffer
143 }
144
145 static void ggl_clearColorx(void* con,
146 GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a)
147 {
148 GGL_CONTEXT(c, con);
149 c->state.clear.r = gglClampx(r);
150 c->state.clear.g = gglClampx(g);
151 c->state.clear.b = gglClampx(b);
152 c->state.clear.a = gglClampx(a);
153 c->state.clear.dirty |= GGL_COLOR_BUFFER_BIT;
154 }
155
156 static void ggl_clearDepthx(void* con, GGLclampx depth)
157 {
158 GGL_CONTEXT(c, con);
159 c->state.clear.depth = gglClampx(depth);
160 c->state.clear.dirty |= GGL_DEPTH_BUFFER_BIT;
161 }
162
163 static void ggl_clearStencil(void* con, GGLint s)
164 {
165 GGL_CONTEXT(c, con);
166 c->state.clear.stencil = s;
167 c->state.clear.dirty |= GGL_STENCIL_BUFFER_BIT;
168 }
169
170 }; // namespace android
+0
-30
libpixelflinger/clear.h less more
0 /* libs/pixelflinger/clear.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #ifndef ANDROID_GGL_CLEAR_H
18 #define ANDROID_GGL_CLEAR_H
19
20 #include <pixelflinger/pixelflinger.h>
21 #include <private/pixelflinger/ggl_context.h>
22
23 namespace android {
24
25 void ggl_init_clear(context_t* c);
26
27 }; // namespace android
28
29 #endif // ANDROID_GGL_CLEAR_H
+0
-428
libpixelflinger/codeflinger/ARMAssembler.cpp less more
0 /* libs/pixelflinger/codeflinger/ARMAssembler.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #define LOG_TAG "ARMAssembler"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <cutils/log.h>
22 #include <cutils/properties.h>
23
24 #if defined(WITH_LIB_HARDWARE)
25 #include <hardware_legacy/qemu_tracing.h>
26 #endif
27
28 #include <private/pixelflinger/ggl_context.h>
29
30 #include "codeflinger/ARMAssembler.h"
31 #include "codeflinger/CodeCache.h"
32 #include "codeflinger/disassem.h"
33
34 // ----------------------------------------------------------------------------
35
36 namespace android {
37
38 // ----------------------------------------------------------------------------
39 #if 0
40 #pragma mark -
41 #pragma mark ARMAssembler...
42 #endif
43
44 ARMAssembler::ARMAssembler(const sp<Assembly>& assembly)
45 : ARMAssemblerInterface(),
46 mAssembly(assembly)
47 {
48 mBase = mPC = (uint32_t *)assembly->base();
49 mDuration = ggl_system_time();
50 #if defined(WITH_LIB_HARDWARE)
51 mQemuTracing = true;
52 #endif
53 }
54
55 ARMAssembler::~ARMAssembler()
56 {
57 }
58
59 uint32_t* ARMAssembler::pc() const
60 {
61 return mPC;
62 }
63
64 uint32_t* ARMAssembler::base() const
65 {
66 return mBase;
67 }
68
69 void ARMAssembler::reset()
70 {
71 mBase = mPC = (uint32_t *)mAssembly->base();
72 mBranchTargets.clear();
73 mLabels.clear();
74 mLabelsInverseMapping.clear();
75 mComments.clear();
76 }
77
78 // ----------------------------------------------------------------------------
79
80 void ARMAssembler::disassemble(const char* name)
81 {
82 if (name) {
83 printf("%s:\n", name);
84 }
85 size_t count = pc()-base();
86 uint32_t* i = base();
87 while (count--) {
88 ssize_t label = mLabelsInverseMapping.indexOfKey(i);
89 if (label >= 0) {
90 printf("%s:\n", mLabelsInverseMapping.valueAt(label));
91 }
92 ssize_t comment = mComments.indexOfKey(i);
93 if (comment >= 0) {
94 printf("; %s\n", mComments.valueAt(comment));
95 }
96 printf("%08x: %08x ", int(i), int(i[0]));
97 ::disassemble((u_int)i);
98 i++;
99 }
100 }
101
102 void ARMAssembler::comment(const char* string)
103 {
104 mComments.add(mPC, string);
105 }
106
107 void ARMAssembler::label(const char* theLabel)
108 {
109 mLabels.add(theLabel, mPC);
110 mLabelsInverseMapping.add(mPC, theLabel);
111 }
112
113 void ARMAssembler::B(int cc, const char* label)
114 {
115 mBranchTargets.add(branch_target_t(label, mPC));
116 *mPC++ = (cc<<28) | (0xA<<24) | 0;
117 }
118
119 void ARMAssembler::BL(int cc, const char* label)
120 {
121 mBranchTargets.add(branch_target_t(label, mPC));
122 *mPC++ = (cc<<28) | (0xB<<24) | 0;
123 }
124
125 #if 0
126 #pragma mark -
127 #pragma mark Prolog/Epilog & Generate...
128 #endif
129
130
131 void ARMAssembler::prolog()
132 {
133 // write dummy prolog code
134 mPrologPC = mPC;
135 STM(AL, FD, SP, 1, LSAVED);
136 }
137
138 void ARMAssembler::epilog(uint32_t touched)
139 {
140 touched &= LSAVED;
141 if (touched) {
142 // write prolog code
143 uint32_t* pc = mPC;
144 mPC = mPrologPC;
145 STM(AL, FD, SP, 1, touched | LLR);
146 mPC = pc;
147 // write epilog code
148 LDM(AL, FD, SP, 1, touched | LLR);
149 BX(AL, LR);
150 } else { // heh, no registers to save!
151 // write prolog code
152 uint32_t* pc = mPC;
153 mPC = mPrologPC;
154 MOV(AL, 0, R0, R0); // NOP
155 mPC = pc;
156 // write epilog code
157 BX(AL, LR);
158 }
159 }
160
161 int ARMAssembler::generate(const char* name)
162 {
163 // fixup all the branches
164 size_t count = mBranchTargets.size();
165 while (count--) {
166 const branch_target_t& bt = mBranchTargets[count];
167 uint32_t* target_pc = mLabels.valueFor(bt.label);
168 LOG_ALWAYS_FATAL_IF(!target_pc,
169 "error resolving branch targets, target_pc is null");
170 int32_t offset = int32_t(target_pc - (bt.pc+2));
171 *bt.pc |= offset & 0xFFFFFF;
172 }
173
174 mAssembly->resize( int(pc()-base())*4 );
175
176 // the instruction cache is flushed by CodeCache
177 const int64_t duration = ggl_system_time() - mDuration;
178 const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
179 LOGI(format, name, int(pc()-base()), base(), pc(), duration);
180
181 #if defined(WITH_LIB_HARDWARE)
182 if (__builtin_expect(mQemuTracing, 0)) {
183 int err = qemu_add_mapping(int(base()), name);
184 mQemuTracing = (err >= 0);
185 }
186 #endif
187
188 char value[PROPERTY_VALUE_MAX];
189 property_get("debug.pf.disasm", value, "0");
190 if (atoi(value) != 0) {
191 printf(format, name, int(pc()-base()), base(), pc(), duration);
192 disassemble(name);
193 }
194
195 return NO_ERROR;
196 }
197
198 uint32_t* ARMAssembler::pcForLabel(const char* label)
199 {
200 return mLabels.valueFor(label);
201 }
202
203 // ----------------------------------------------------------------------------
204
205 #if 0
206 #pragma mark -
207 #pragma mark Data Processing...
208 #endif
209
210 void ARMAssembler::dataProcessing(int opcode, int cc,
211 int s, int Rd, int Rn, uint32_t Op2)
212 {
213 *mPC++ = (cc<<28) | (opcode<<21) | (s<<20) | (Rn<<16) | (Rd<<12) | Op2;
214 }
215
216 #if 0
217 #pragma mark -
218 #pragma mark Multiply...
219 #endif
220
221 // multiply...
222 void ARMAssembler::MLA(int cc, int s,
223 int Rd, int Rm, int Rs, int Rn) {
224 if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
225 LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
226 *mPC++ = (cc<<28) | (1<<21) | (s<<20) |
227 (Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
228 }
229 void ARMAssembler::MUL(int cc, int s,
230 int Rd, int Rm, int Rs) {
231 if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
232 LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
233 *mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
234 }
235 void ARMAssembler::UMULL(int cc, int s,
236 int RdLo, int RdHi, int Rm, int Rs) {
237 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
238 "UMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
239 *mPC++ = (cc<<28) | (1<<23) | (s<<20) |
240 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
241 }
242 void ARMAssembler::UMUAL(int cc, int s,
243 int RdLo, int RdHi, int Rm, int Rs) {
244 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
245 "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
246 *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
247 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
248 }
249 void ARMAssembler::SMULL(int cc, int s,
250 int RdLo, int RdHi, int Rm, int Rs) {
251 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
252 "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
253 *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
254 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
255 }
256 void ARMAssembler::SMUAL(int cc, int s,
257 int RdLo, int RdHi, int Rm, int Rs) {
258 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
259 "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
260 *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
261 (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
262 }
263
264 #if 0
265 #pragma mark -
266 #pragma mark Branches...
267 #endif
268
269 // branches...
270 void ARMAssembler::B(int cc, uint32_t* pc)
271 {
272 int32_t offset = int32_t(pc - (mPC+2));
273 *mPC++ = (cc<<28) | (0xA<<24) | (offset & 0xFFFFFF);
274 }
275
276 void ARMAssembler::BL(int cc, uint32_t* pc)
277 {
278 int32_t offset = int32_t(pc - (mPC+2));
279 *mPC++ = (cc<<28) | (0xB<<24) | (offset & 0xFFFFFF);
280 }
281
282 void ARMAssembler::BX(int cc, int Rn)
283 {
284 *mPC++ = (cc<<28) | 0x12FFF10 | Rn;
285 }
286
287 #if 0
288 #pragma mark -
289 #pragma mark Data Transfer...
290 #endif
291
292 // data transfert...
293 void ARMAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) {
294 *mPC++ = (cc<<28) | (1<<26) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
295 }
296 void ARMAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
297 *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
298 }
299 void ARMAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) {
300 *mPC++ = (cc<<28) | (1<<26) | (Rn<<16) | (Rd<<12) | offset;
301 }
302 void ARMAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) {
303 *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (Rn<<16) | (Rd<<12) | offset;
304 }
305
306 void ARMAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
307 *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
308 }
309 void ARMAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
310 *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xD0 | offset;
311 }
312 void ARMAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
313 *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xF0 | offset;
314 }
315 void ARMAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) {
316 *mPC++ = (cc<<28) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
317 }
318
319 #if 0
320 #pragma mark -
321 #pragma mark Block Data Transfer...
322 #endif
323
324 // block data transfer...
325 void ARMAssembler::LDM(int cc, int dir,
326 int Rn, int W, uint32_t reg_list)
327 { // ED FD EA FA IB IA DB DA
328 const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
329 const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
330 *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
331 (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
332 }
333
334 void ARMAssembler::STM(int cc, int dir,
335 int Rn, int W, uint32_t reg_list)
336 { // FA EA FD ED IB IA DB DA
337 const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
338 const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
339 *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
340 (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
341 }
342
343 #if 0
344 #pragma mark -
345 #pragma mark Special...
346 #endif
347
348 // special...
349 void ARMAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
350 *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
351 }
352 void ARMAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
353 *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
354 }
355 void ARMAssembler::SWI(int cc, uint32_t comment) {
356 *mPC++ = (cc<<28) | (0xF<<24) | comment;
357 }
358
359 #if 0
360 #pragma mark -
361 #pragma mark DSP instructions...
362 #endif
363
364 // DSP instructions...
365 void ARMAssembler::PLD(int Rn, uint32_t offset) {
366 LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
367 "PLD only P=1, W=0");
368 *mPC++ = 0xF550F000 | (Rn<<16) | offset;
369 }
370
371 void ARMAssembler::CLZ(int cc, int Rd, int Rm)
372 {
373 *mPC++ = (cc<<28) | 0x16F0F10| (Rd<<12) | Rm;
374 }
375
376 void ARMAssembler::QADD(int cc, int Rd, int Rm, int Rn)
377 {
378 *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
379 }
380
381 void ARMAssembler::QDADD(int cc, int Rd, int Rm, int Rn)
382 {
383 *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
384 }
385
386 void ARMAssembler::QSUB(int cc, int Rd, int Rm, int Rn)
387 {
388 *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
389 }
390
391 void ARMAssembler::QDSUB(int cc, int Rd, int Rm, int Rn)
392 {
393 *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
394 }
395
396 void ARMAssembler::SMUL(int cc, int xy,
397 int Rd, int Rm, int Rs)
398 {
399 *mPC++ = (cc<<28) | 0x1600080 | (Rd<<16) | (Rs<<8) | (xy<<4) | Rm;
400 }
401
402 void ARMAssembler::SMULW(int cc, int y,
403 int Rd, int Rm, int Rs)
404 {
405 *mPC++ = (cc<<28) | 0x12000A0 | (Rd<<16) | (Rs<<8) | (y<<4) | Rm;
406 }
407
408 void ARMAssembler::SMLA(int cc, int xy,
409 int Rd, int Rm, int Rs, int Rn)
410 {
411 *mPC++ = (cc<<28) | 0x1000080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (xy<<4) | Rm;
412 }
413
414 void ARMAssembler::SMLAL(int cc, int xy,
415 int RdHi, int RdLo, int Rs, int Rm)
416 {
417 *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
418 }
419
420 void ARMAssembler::SMLAW(int cc, int y,
421 int Rd, int Rm, int Rs, int Rn)
422 {
423 *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
424 }
425
426 }; // namespace android
427
+0
-155
libpixelflinger/codeflinger/ARMAssembler.h less more
0 /* libs/pixelflinger/codeflinger/ARMAssembler.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #ifndef ANDROID_ARMASSEMBLER_H
18 #define ANDROID_ARMASSEMBLER_H
19
20 #include <stdint.h>
21 #include <sys/types.h>
22
23 #include <utils/Vector.h>
24 #include <utils/KeyedVector.h>
25
26 #include "tinyutils/smartpointer.h"
27 #include "codeflinger/ARMAssemblerInterface.h"
28 #include "codeflinger/CodeCache.h"
29
30 namespace android {
31
32 // ----------------------------------------------------------------------------
33
34 class ARMAssembler : public ARMAssemblerInterface
35 {
36 public:
37 ARMAssembler(const sp<Assembly>& assembly);
38 virtual ~ARMAssembler();
39
40 uint32_t* base() const;
41 uint32_t* pc() const;
42
43
44 void disassemble(const char* name);
45
46 // ------------------------------------------------------------------------
47 // ARMAssemblerInterface...
48 // ------------------------------------------------------------------------
49
50 virtual void reset();
51
52 virtual int generate(const char* name);
53
54 virtual void prolog();
55 virtual void epilog(uint32_t touched);
56 virtual void comment(const char* string);
57
58 virtual void dataProcessing(int opcode, int cc, int s,
59 int Rd, int Rn,
60 uint32_t Op2);
61 virtual void MLA(int cc, int s,
62 int Rd, int Rm, int Rs, int Rn);
63 virtual void MUL(int cc, int s,
64 int Rd, int Rm, int Rs);
65 virtual void UMULL(int cc, int s,
66 int RdLo, int RdHi, int Rm, int Rs);
67 virtual void UMUAL(int cc, int s,
68 int RdLo, int RdHi, int Rm, int Rs);
69 virtual void SMULL(int cc, int s,
70 int RdLo, int RdHi, int Rm, int Rs);
71 virtual void SMUAL(int cc, int s,
72 int RdLo, int RdHi, int Rm, int Rs);
73
74 virtual void B(int cc, uint32_t* pc);
75 virtual void BL(int cc, uint32_t* pc);
76 virtual void BX(int cc, int Rn);
77 virtual void label(const char* theLabel);
78 virtual void B(int cc, const char* label);
79 virtual void BL(int cc, const char* label);
80
81 virtual uint32_t* pcForLabel(const char* label);
82
83 virtual void LDR (int cc, int Rd,
84 int Rn, uint32_t offset = immed12_pre(0));
85 virtual void LDRB(int cc, int Rd,
86 int Rn, uint32_t offset = immed12_pre(0));
87 virtual void STR (int cc, int Rd,
88 int Rn, uint32_t offset = immed12_pre(0));
89 virtual void STRB(int cc, int Rd,
90 int Rn, uint32_t offset = immed12_pre(0));
91 virtual void LDRH (int cc, int Rd,
92 int Rn, uint32_t offset = immed8_pre(0));
93 virtual void LDRSB(int cc, int Rd,
94 int Rn, uint32_t offset = immed8_pre(0));
95 virtual void LDRSH(int cc, int Rd,
96 int Rn, uint32_t offset = immed8_pre(0));
97 virtual void STRH (int cc, int Rd,
98 int Rn, uint32_t offset = immed8_pre(0));
99 virtual void LDM(int cc, int dir,
100 int Rn, int W, uint32_t reg_list);
101 virtual void STM(int cc, int dir,
102 int Rn, int W, uint32_t reg_list);
103
104 virtual void SWP(int cc, int Rn, int Rd, int Rm);
105 virtual void SWPB(int cc, int Rn, int Rd, int Rm);
106 virtual void SWI(int cc, uint32_t comment);
107
108 virtual void PLD(int Rn, uint32_t offset);
109 virtual void CLZ(int cc, int Rd, int Rm);
110 virtual void QADD(int cc, int Rd, int Rm, int Rn);
111 virtual void QDADD(int cc, int Rd, int Rm, int Rn);
112 virtual void QSUB(int cc, int Rd, int Rm, int Rn);
113 virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
114 virtual void SMUL(int cc, int xy,
115 int Rd, int Rm, int Rs);
116 virtual void SMULW(int cc, int y,
117 int Rd, int Rm, int Rs);
118 virtual void SMLA(int cc, int xy,
119 int Rd, int Rm, int Rs, int Rn);
120 virtual void SMLAL(int cc, int xy,
121 int RdHi, int RdLo, int Rs, int Rm);
122 virtual void SMLAW(int cc, int y,
123 int Rd, int Rm, int Rs, int Rn);
124
125 private:
126 ARMAssembler(const ARMAssembler& rhs);
127 ARMAssembler& operator = (const ARMAssembler& rhs);
128
129 sp<Assembly> mAssembly;
130 uint32_t* mBase;
131 uint32_t* mPC;
132 uint32_t* mPrologPC;
133 int64_t mDuration;
134 #if defined(WITH_LIB_HARDWARE)
135 bool mQemuTracing;
136 #endif
137
138 struct branch_target_t {
139 inline branch_target_t() : label(0), pc(0) { }
140 inline branch_target_t(const char* l, uint32_t* p)
141 : label(l), pc(p) { }
142 const char* label;
143 uint32_t* pc;
144 };
145
146 Vector<branch_target_t> mBranchTargets;
147 KeyedVector< const char*, uint32_t* > mLabels;
148 KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
149 KeyedVector< uint32_t*, const char* > mComments;
150 };
151
152 }; // namespace android
153
154 #endif //ANDROID_ARMASSEMBLER_H
+0
-173
libpixelflinger/codeflinger/ARMAssemblerInterface.cpp less more
0 /* libs/pixelflinger/codeflinger/ARMAssemblerInterface.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <sys/types.h>
22
23 #include <cutils/log.h>
24 #include "codeflinger/ARMAssemblerInterface.h"
25
26 namespace android {
27
28 // ----------------------------------------------------------------------------
29
30 ARMAssemblerInterface::~ARMAssemblerInterface()
31 {
32 }
33
34 int ARMAssemblerInterface::buildImmediate(
35 uint32_t immediate, uint32_t& rot, uint32_t& imm)
36 {
37 rot = 0;
38 imm = immediate;
39 if (imm > 0x7F) { // skip the easy cases
40 while (!(imm&3) || (imm&0xFC000000)) {
41 uint32_t newval;
42 newval = imm >> 2;
43 newval |= (imm&3) << 30;
44 imm = newval;
45 rot += 2;
46 if (rot == 32) {
47 rot = 0;
48 break;
49 }
50 }
51 }
52 rot = (16 - (rot>>1)) & 0xF;
53
54 if (imm>=0x100)
55 return -EINVAL;
56
57 if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
58 return -1;
59
60 return 0;
61 }
62
63 // shifters...
64
65 bool ARMAssemblerInterface::isValidImmediate(uint32_t immediate)
66 {
67 uint32_t rot, imm;
68 return buildImmediate(immediate, rot, imm) == 0;
69 }
70
71 uint32_t ARMAssemblerInterface::imm(uint32_t immediate)
72 {
73 uint32_t rot, imm;
74 int err = buildImmediate(immediate, rot, imm);
75
76 LOG_ALWAYS_FATAL_IF(err==-EINVAL,
77 "immediate %08x cannot be encoded",
78 immediate);
79
80 LOG_ALWAYS_FATAL_IF(err,
81 "immediate (%08x) encoding bogus!",
82 immediate);
83
84 return (1<<25) | (rot<<8) | imm;
85 }
86
87 uint32_t ARMAssemblerInterface::reg_imm(int Rm, int type, uint32_t shift)
88 {
89 return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
90 }
91
92 uint32_t ARMAssemblerInterface::reg_rrx(int Rm)
93 {
94 return (ROR<<5) | (Rm&0xF);
95 }
96
97 uint32_t ARMAssemblerInterface::reg_reg(int Rm, int type, int Rs)
98 {
99 return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
100 }
101
102 // addressing modes...
103 // LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
104 uint32_t ARMAssemblerInterface::immed12_pre(int32_t immed12, int W)
105 {
106 LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
107 "LDR(B)/STR(B)/PLD immediate too big (%08x)",
108 immed12);
109 return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
110 ((W&1)<<21) | (abs(immed12)&0x7FF);
111 }
112
113 uint32_t ARMAssemblerInterface::immed12_post(int32_t immed12)
114 {
115 LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
116 "LDR(B)/STR(B)/PLD immediate too big (%08x)",
117 immed12);
118
119 return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
120 }
121
122 uint32_t ARMAssemblerInterface::reg_scale_pre(int Rm, int type,
123 uint32_t shift, int W)
124 {
125 return (1<<25) | (1<<24) |
126 (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
127 reg_imm(abs(Rm), type, shift);
128 }
129
130 uint32_t ARMAssemblerInterface::reg_scale_post(int Rm, int type, uint32_t shift)
131 {
132 return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
133 }
134
135 // LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
136 uint32_t ARMAssemblerInterface::immed8_pre(int32_t immed8, int W)
137 {
138 uint32_t offset = abs(immed8);
139
140 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
141 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
142 immed8);
143
144 return (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
145 ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
146 }
147
148 uint32_t ARMAssemblerInterface::immed8_post(int32_t immed8)
149 {
150 uint32_t offset = abs(immed8);
151
152 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
153 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
154 immed8);
155
156 return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
157 (((offset&0xF0)<<4) | (offset&0xF));
158 }
159
160 uint32_t ARMAssemblerInterface::reg_pre(int Rm, int W)
161 {
162 return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
163 }
164
165 uint32_t ARMAssemblerInterface::reg_post(int Rm)
166 {
167 return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
168 }
169
170
171 }; // namespace android
172
+0
-324
libpixelflinger/codeflinger/ARMAssemblerInterface.h less more
0 /* libs/pixelflinger/codeflinger/ARMAssemblerInterface.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_ARMASSEMBLER_INTERFACE_H
19 #define ANDROID_ARMASSEMBLER_INTERFACE_H
20
21 #include <stdint.h>
22 #include <sys/types.h>
23
24 namespace android {
25
26 // ----------------------------------------------------------------------------
27
28 class ARMAssemblerInterface
29 {
30 public:
31 virtual ~ARMAssemblerInterface();
32
33 enum {
34 EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
35 HS = CS,
36 LO = CC
37 };
38 enum {
39 S = 1
40 };
41 enum {
42 LSL, LSR, ASR, ROR
43 };
44 enum {
45 ED, FD, EA, FA,
46 IB, IA, DB, DA
47 };
48 enum {
49 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
50 SP = R13,
51 LR = R14,
52 PC = R15
53 };
54 enum {
55 #define LIST(rr) L##rr=1<<rr
56 LIST(R0), LIST(R1), LIST(R2), LIST(R3), LIST(R4), LIST(R5), LIST(R6),
57 LIST(R7), LIST(R8), LIST(R9), LIST(R10), LIST(R11), LIST(R12),
58 LIST(R13), LIST(R14), LIST(R15),
59 LIST(SP), LIST(LR), LIST(PC),
60 #undef LIST
61 LSAVED = LR4|LR5|LR6|LR7|LR8|LR9|LR10|LR11 | LLR
62 };
63
64 // -----------------------------------------------------------------------
65 // shifters and addressing modes
66 // -----------------------------------------------------------------------
67
68 // shifters...
69 static bool isValidImmediate(uint32_t immed);
70 static int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
71
72 static uint32_t imm(uint32_t immediate);
73 static uint32_t reg_imm(int Rm, int type, uint32_t shift);
74 static uint32_t reg_rrx(int Rm);
75 static uint32_t reg_reg(int Rm, int type, int Rs);
76
77 // addressing modes...
78 // LDR(B)/STR(B)/PLD
79 // (immediate and Rm can be negative, which indicates U=0)
80 static uint32_t immed12_pre(int32_t immed12, int W=0);
81 static uint32_t immed12_post(int32_t immed12);
82 static uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
83 static uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
84
85 // LDRH/LDRSB/LDRSH/STRH
86 // (immediate and Rm can be negative, which indicates U=0)
87 static uint32_t immed8_pre(int32_t immed8, int W=0);
88 static uint32_t immed8_post(int32_t immed8);
89 static uint32_t reg_pre(int Rm, int W=0);
90 static uint32_t reg_post(int Rm);
91
92 // -----------------------------------------------------------------------
93 // basic instructions & code generation
94 // -----------------------------------------------------------------------
95
96 // generate the code
97 virtual void reset() = 0;
98 virtual int generate(const char* name) = 0;
99 virtual void disassemble(const char* name) = 0;
100
101 // construct prolog and epilog
102 virtual void prolog() = 0;
103 virtual void epilog(uint32_t touched) = 0;
104 virtual void comment(const char* string) = 0;
105
106 // data processing...
107 enum {
108 opAND, opEOR, opSUB, opRSB, opADD, opADC, opSBC, opRSC,
109 opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN
110 };
111
112 virtual void
113 dataProcessing( int opcode, int cc, int s,
114 int Rd, int Rn,
115 uint32_t Op2) = 0;
116
117 // multiply...
118 virtual void MLA(int cc, int s,
119 int Rd, int Rm, int Rs, int Rn) = 0;
120 virtual void MUL(int cc, int s,
121 int Rd, int Rm, int Rs) = 0;
122 virtual void UMULL(int cc, int s,
123 int RdLo, int RdHi, int Rm, int Rs) = 0;
124 virtual void UMUAL(int cc, int s,
125 int RdLo, int RdHi, int Rm, int Rs) = 0;
126 virtual void SMULL(int cc, int s,
127 int RdLo, int RdHi, int Rm, int Rs) = 0;
128 virtual void SMUAL(int cc, int s,
129 int RdLo, int RdHi, int Rm, int Rs) = 0;
130
131 // branches...
132 virtual void B(int cc, uint32_t* pc) = 0;
133 virtual void BL(int cc, uint32_t* pc) = 0;
134 virtual void BX(int cc, int Rn) = 0;
135
136 virtual void label(const char* theLabel) = 0;
137 virtual void B(int cc, const char* label) = 0;
138 virtual void BL(int cc, const char* label) = 0;
139
140 // valid only after generate() has been called
141 virtual uint32_t* pcForLabel(const char* label) = 0;
142
143 // data transfer...
144 virtual void LDR (int cc, int Rd,
145 int Rn, uint32_t offset = immed12_pre(0)) = 0;
146 virtual void LDRB(int cc, int Rd,
147 int Rn, uint32_t offset = immed12_pre(0)) = 0;
148 virtual void STR (int cc, int Rd,
149 int Rn, uint32_t offset = immed12_pre(0)) = 0;
150 virtual void STRB(int cc, int Rd,
151 int Rn, uint32_t offset = immed12_pre(0)) = 0;
152
153 virtual void LDRH (int cc, int Rd,
154 int Rn, uint32_t offset = immed8_pre(0)) = 0;
155 virtual void LDRSB(int cc, int Rd,
156 int Rn, uint32_t offset = immed8_pre(0)) = 0;
157 virtual void LDRSH(int cc, int Rd,
158 int Rn, uint32_t offset = immed8_pre(0)) = 0;
159 virtual void STRH (int cc, int Rd,
160 int Rn, uint32_t offset = immed8_pre(0)) = 0;
161
162 // block data transfer...
163 virtual void LDM(int cc, int dir,
164 int Rn, int W, uint32_t reg_list) = 0;
165 virtual void STM(int cc, int dir,
166 int Rn, int W, uint32_t reg_list) = 0;
167
168 // special...
169 virtual void SWP(int cc, int Rn, int Rd, int Rm) = 0;
170 virtual void SWPB(int cc, int Rn, int Rd, int Rm) = 0;
171 virtual void SWI(int cc, uint32_t comment) = 0;
172
173 // DSP instructions...
174 enum {
175 // B=0, T=1
176 // yx
177 xyBB = 0, // 0000,
178 xyTB = 2, // 0010,
179 xyBT = 4, // 0100,
180 xyTT = 6, // 0110,
181 yB = 0, // 0000,
182 yT = 4, // 0100
183 };
184
185 virtual void PLD(int Rn, uint32_t offset) = 0;
186
187 virtual void CLZ(int cc, int Rd, int Rm) = 0;
188
189 virtual void QADD(int cc, int Rd, int Rm, int Rn) = 0;
190 virtual void QDADD(int cc, int Rd, int Rm, int Rn) = 0;
191 virtual void QSUB(int cc, int Rd, int Rm, int Rn) = 0;
192 virtual void QDSUB(int cc, int Rd, int Rm, int Rn) = 0;
193
194 virtual void SMUL(int cc, int xy,
195 int Rd, int Rm, int Rs) = 0;
196 virtual void SMULW(int cc, int y,
197 int Rd, int Rm, int Rs) = 0;
198 virtual void SMLA(int cc, int xy,
199 int Rd, int Rm, int Rs, int Rn) = 0;
200 virtual void SMLAL(int cc, int xy,
201 int RdHi, int RdLo, int Rs, int Rm) = 0;
202 virtual void SMLAW(int cc, int y,
203 int Rd, int Rm, int Rs, int Rn) = 0;
204
205 // -----------------------------------------------------------------------
206 // convenience...
207 // -----------------------------------------------------------------------
208 inline void
209 ADC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
210 dataProcessing(opADC, cc, s, Rd, Rn, Op2);
211 }
212 inline void
213 ADD(int cc, int s, int Rd, int Rn, uint32_t Op2) {
214 dataProcessing(opADD, cc, s, Rd, Rn, Op2);
215 }
216 inline void
217 AND(int cc, int s, int Rd, int Rn, uint32_t Op2) {
218 dataProcessing(opAND, cc, s, Rd, Rn, Op2);
219 }
220 inline void
221 BIC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
222 dataProcessing(opBIC, cc, s, Rd, Rn, Op2);
223 }
224 inline void
225 EOR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
226 dataProcessing(opEOR, cc, s, Rd, Rn, Op2);
227 }
228 inline void
229 MOV(int cc, int s, int Rd, uint32_t Op2) {
230 dataProcessing(opMOV, cc, s, Rd, 0, Op2);
231 }
232 inline void
233 MVN(int cc, int s, int Rd, uint32_t Op2) {
234 dataProcessing(opMVN, cc, s, Rd, 0, Op2);
235 }
236 inline void
237 ORR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
238 dataProcessing(opORR, cc, s, Rd, Rn, Op2);
239 }
240 inline void
241 RSB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
242 dataProcessing(opRSB, cc, s, Rd, Rn, Op2);
243 }
244 inline void
245 RSC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
246 dataProcessing(opRSC, cc, s, Rd, Rn, Op2);
247 }
248 inline void
249 SBC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
250 dataProcessing(opSBC, cc, s, Rd, Rn, Op2);
251 }
252 inline void
253 SUB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
254 dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
255 }
256 inline void
257 TEQ(int cc, int Rn, uint32_t Op2) {
258 dataProcessing(opTEQ, cc, 1, 0, Rn, Op2);
259 }
260 inline void
261 TST(int cc, int Rn, uint32_t Op2) {
262 dataProcessing(opTST, cc, 1, 0, Rn, Op2);
263 }
264 inline void
265 CMP(int cc, int Rn, uint32_t Op2) {
266 dataProcessing(opCMP, cc, 1, 0, Rn, Op2);
267 }
268 inline void
269 CMN(int cc, int Rn, uint32_t Op2) {
270 dataProcessing(opCMN, cc, 1, 0, Rn, Op2);
271 }
272
273 inline void SMULBB(int cc, int Rd, int Rm, int Rs) {
274 SMUL(cc, xyBB, Rd, Rm, Rs); }
275 inline void SMULTB(int cc, int Rd, int Rm, int Rs) {
276 SMUL(cc, xyTB, Rd, Rm, Rs); }
277 inline void SMULBT(int cc, int Rd, int Rm, int Rs) {
278 SMUL(cc, xyBT, Rd, Rm, Rs); }
279 inline void SMULTT(int cc, int Rd, int Rm, int Rs) {
280 SMUL(cc, xyTT, Rd, Rm, Rs); }
281
282 inline void SMULWB(int cc, int Rd, int Rm, int Rs) {
283 SMULW(cc, yB, Rd, Rm, Rs); }
284 inline void SMULWT(int cc, int Rd, int Rm, int Rs) {
285 SMULW(cc, yT, Rd, Rm, Rs); }
286
287 inline void
288 SMLABB(int cc, int Rd, int Rm, int Rs, int Rn) {
289 SMLA(cc, xyBB, Rd, Rm, Rs, Rn); }
290 inline void
291 SMLATB(int cc, int Rd, int Rm, int Rs, int Rn) {
292 SMLA(cc, xyTB, Rd, Rm, Rs, Rn); }
293 inline void
294 SMLABT(int cc, int Rd, int Rm, int Rs, int Rn) {
295 SMLA(cc, xyBT, Rd, Rm, Rs, Rn); }
296 inline void
297 SMLATT(int cc, int Rd, int Rm, int Rs, int Rn) {
298 SMLA(cc, xyTT, Rd, Rm, Rs, Rn); }
299
300 inline void
301 SMLALBB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
302 SMLAL(cc, xyBB, RdHi, RdLo, Rs, Rm); }
303 inline void
304 SMLALTB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
305 SMLAL(cc, xyTB, RdHi, RdLo, Rs, Rm); }
306 inline void
307 SMLALBT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
308 SMLAL(cc, xyBT, RdHi, RdLo, Rs, Rm); }
309 inline void
310 SMLALTT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
311 SMLAL(cc, xyTT, RdHi, RdLo, Rs, Rm); }
312
313 inline void
314 SMLAWB(int cc, int Rd, int Rm, int Rs, int Rn) {
315 SMLAW(cc, yB, Rd, Rm, Rs, Rn); }
316 inline void
317 SMLAWT(int cc, int Rd, int Rm, int Rs, int Rn) {
318 SMLAW(cc, yT, Rd, Rm, Rs, Rn); }
319 };
320
321 }; // namespace android
322
323 #endif //ANDROID_ARMASSEMBLER_INTERFACE_H
+0
-200
libpixelflinger/codeflinger/ARMAssemblerProxy.cpp less more
0 /* libs/pixelflinger/codeflinger/ARMAssemblerProxy.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #include <stdint.h>
19 #include <sys/types.h>
20
21 #include "codeflinger/ARMAssemblerProxy.h"
22
23 namespace android {
24
25 // ----------------------------------------------------------------------------
26
27 ARMAssemblerProxy::ARMAssemblerProxy()
28 : mTarget(0)
29 {
30 }
31
32 ARMAssemblerProxy::ARMAssemblerProxy(ARMAssemblerInterface* target)
33 : mTarget(target)
34 {
35 }
36
37 ARMAssemblerProxy::~ARMAssemblerProxy()
38 {
39 delete mTarget;
40 }
41
42 void ARMAssemblerProxy::setTarget(ARMAssemblerInterface* target)
43 {
44 delete mTarget;
45 mTarget = target;
46 }
47
48 void ARMAssemblerProxy::reset() {
49 mTarget->reset();
50 }
51 int ARMAssemblerProxy::generate(const char* name) {
52 return mTarget->generate(name);
53 }
54 void ARMAssemblerProxy::disassemble(const char* name) {
55 return mTarget->disassemble(name);
56 }
57 void ARMAssemblerProxy::prolog() {
58 mTarget->prolog();
59 }
60 void ARMAssemblerProxy::epilog(uint32_t touched) {
61 mTarget->epilog(touched);
62 }
63 void ARMAssemblerProxy::comment(const char* string) {
64 mTarget->comment(string);
65 }
66
67
68 void ARMAssemblerProxy::dataProcessing( int opcode, int cc, int s,
69 int Rd, int Rn, uint32_t Op2)
70 {
71 mTarget->dataProcessing(opcode, cc, s, Rd, Rn, Op2);
72 }
73
74 void ARMAssemblerProxy::MLA(int cc, int s, int Rd, int Rm, int Rs, int Rn) {
75 mTarget->MLA(cc, s, Rd, Rm, Rs, Rn);
76 }
77 void ARMAssemblerProxy::MUL(int cc, int s, int Rd, int Rm, int Rs) {
78 mTarget->MUL(cc, s, Rd, Rm, Rs);
79 }
80 void ARMAssemblerProxy::UMULL(int cc, int s,
81 int RdLo, int RdHi, int Rm, int Rs) {
82 mTarget->UMULL(cc, s, RdLo, RdHi, Rm, Rs);
83 }
84 void ARMAssemblerProxy::UMUAL(int cc, int s,
85 int RdLo, int RdHi, int Rm, int Rs) {
86 mTarget->UMUAL(cc, s, RdLo, RdHi, Rm, Rs);
87 }
88 void ARMAssemblerProxy::SMULL(int cc, int s,
89 int RdLo, int RdHi, int Rm, int Rs) {
90 mTarget->SMULL(cc, s, RdLo, RdHi, Rm, Rs);
91 }
92 void ARMAssemblerProxy::SMUAL(int cc, int s,
93 int RdLo, int RdHi, int Rm, int Rs) {
94 mTarget->SMUAL(cc, s, RdLo, RdHi, Rm, Rs);
95 }
96
97 void ARMAssemblerProxy::B(int cc, uint32_t* pc) {
98 mTarget->B(cc, pc);
99 }
100 void ARMAssemblerProxy::BL(int cc, uint32_t* pc) {
101 mTarget->BL(cc, pc);
102 }
103 void ARMAssemblerProxy::BX(int cc, int Rn) {
104 mTarget->BX(cc, Rn);
105 }
106 void ARMAssemblerProxy::label(const char* theLabel) {
107 mTarget->label(theLabel);
108 }
109 void ARMAssemblerProxy::B(int cc, const char* label) {
110 mTarget->B(cc, label);
111 }
112 void ARMAssemblerProxy::BL(int cc, const char* label) {
113 mTarget->BL(cc, label);
114 }
115
116 uint32_t* ARMAssemblerProxy::pcForLabel(const char* label) {
117 return mTarget->pcForLabel(label);
118 }
119
120 void ARMAssemblerProxy::LDR(int cc, int Rd, int Rn, uint32_t offset) {
121 mTarget->LDR(cc, Rd, Rn, offset);
122 }
123 void ARMAssemblerProxy::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
124 mTarget->LDRB(cc, Rd, Rn, offset);
125 }
126 void ARMAssemblerProxy::STR(int cc, int Rd, int Rn, uint32_t offset) {
127 mTarget->STR(cc, Rd, Rn, offset);
128 }
129 void ARMAssemblerProxy::STRB(int cc, int Rd, int Rn, uint32_t offset) {
130 mTarget->STRB(cc, Rd, Rn, offset);
131 }
132 void ARMAssemblerProxy::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
133 mTarget->LDRH(cc, Rd, Rn, offset);
134 }
135 void ARMAssemblerProxy::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
136 mTarget->LDRSB(cc, Rd, Rn, offset);
137 }
138 void ARMAssemblerProxy::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
139 mTarget->LDRSH(cc, Rd, Rn, offset);
140 }
141 void ARMAssemblerProxy::STRH(int cc, int Rd, int Rn, uint32_t offset) {
142 mTarget->STRH(cc, Rd, Rn, offset);
143 }
144 void ARMAssemblerProxy::LDM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
145 mTarget->LDM(cc, dir, Rn, W, reg_list);
146 }
147 void ARMAssemblerProxy::STM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
148 mTarget->STM(cc, dir, Rn, W, reg_list);
149 }
150
151 void ARMAssemblerProxy::SWP(int cc, int Rn, int Rd, int Rm) {
152 mTarget->SWP(cc, Rn, Rd, Rm);
153 }
154 void ARMAssemblerProxy::SWPB(int cc, int Rn, int Rd, int Rm) {
155 mTarget->SWPB(cc, Rn, Rd, Rm);
156 }
157 void ARMAssemblerProxy::SWI(int cc, uint32_t comment) {
158 mTarget->SWI(cc, comment);
159 }
160
161
162 void ARMAssemblerProxy::PLD(int Rn, uint32_t offset) {
163 mTarget->PLD(Rn, offset);
164 }
165 void ARMAssemblerProxy::CLZ(int cc, int Rd, int Rm) {
166 mTarget->CLZ(cc, Rd, Rm);
167 }
168 void ARMAssemblerProxy::QADD(int cc, int Rd, int Rm, int Rn) {
169 mTarget->QADD(cc, Rd, Rm, Rn);
170 }
171 void ARMAssemblerProxy::QDADD(int cc, int Rd, int Rm, int Rn) {
172 mTarget->QDADD(cc, Rd, Rm, Rn);
173 }
174 void ARMAssemblerProxy::QSUB(int cc, int Rd, int Rm, int Rn) {
175 mTarget->QSUB(cc, Rd, Rm, Rn);
176 }
177 void ARMAssemblerProxy::QDSUB(int cc, int Rd, int Rm, int Rn) {
178 mTarget->QDSUB(cc, Rd, Rm, Rn);
179 }
180 void ARMAssemblerProxy::SMUL(int cc, int xy, int Rd, int Rm, int Rs) {
181 mTarget->SMUL(cc, xy, Rd, Rm, Rs);
182 }
183 void ARMAssemblerProxy::SMULW(int cc, int y, int Rd, int Rm, int Rs) {
184 mTarget->SMULW(cc, y, Rd, Rm, Rs);
185 }
186 void ARMAssemblerProxy::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn) {
187 mTarget->SMLA(cc, xy, Rd, Rm, Rs, Rn);
188 }
189 void ARMAssemblerProxy::SMLAL( int cc, int xy,
190 int RdHi, int RdLo, int Rs, int Rm) {
191 mTarget->SMLAL(cc, xy, RdHi, RdLo, Rs, Rm);
192 }
193 void ARMAssemblerProxy::SMLAW(int cc, int y, int Rd, int Rm, int Rs, int Rn) {
194 mTarget->SMLAW(cc, y, Rd, Rm, Rs, Rn);
195 }
196
197
198 }; // namespace android
199
+0
-123
libpixelflinger/codeflinger/ARMAssemblerProxy.h less more
0 /* libs/pixelflinger/codeflinger/ARMAssemblerProxy.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_ARMASSEMBLER_PROXY_H
19 #define ANDROID_ARMASSEMBLER_PROXY_H
20
21 #include <stdint.h>
22 #include <sys/types.h>
23
24 #include "codeflinger/ARMAssemblerInterface.h"
25
26 namespace android {
27
28 // ----------------------------------------------------------------------------
29
30 class ARMAssemblerProxy : public ARMAssemblerInterface
31 {
32 public:
33 // ARMAssemblerProxy take ownership of the target
34
35 ARMAssemblerProxy();
36 ARMAssemblerProxy(ARMAssemblerInterface* target);
37 virtual ~ARMAssemblerProxy();
38
39 void setTarget(ARMAssemblerInterface* target);
40
41 virtual void reset();
42 virtual int generate(const char* name);
43 virtual void disassemble(const char* name);
44
45 virtual void prolog();
46 virtual void epilog(uint32_t touched);
47 virtual void comment(const char* string);
48
49 virtual void dataProcessing(int opcode, int cc, int s,
50 int Rd, int Rn,
51 uint32_t Op2);
52 virtual void MLA(int cc, int s,
53 int Rd, int Rm, int Rs, int Rn);
54 virtual void MUL(int cc, int s,
55 int Rd, int Rm, int Rs);
56 virtual void UMULL(int cc, int s,
57 int RdLo, int RdHi, int Rm, int Rs);
58 virtual void UMUAL(int cc, int s,
59 int RdLo, int RdHi, int Rm, int Rs);
60 virtual void SMULL(int cc, int s,
61 int RdLo, int RdHi, int Rm, int Rs);
62 virtual void SMUAL(int cc, int s,
63 int RdLo, int RdHi, int Rm, int Rs);
64
65 virtual void B(int cc, uint32_t* pc);
66 virtual void BL(int cc, uint32_t* pc);
67 virtual void BX(int cc, int Rn);
68 virtual void label(const char* theLabel);
69 virtual void B(int cc, const char* label);
70 virtual void BL(int cc, const char* label);
71
72 uint32_t* pcForLabel(const char* label);
73
74 virtual void LDR (int cc, int Rd,
75 int Rn, uint32_t offset = immed12_pre(0));
76 virtual void LDRB(int cc, int Rd,
77 int Rn, uint32_t offset = immed12_pre(0));
78 virtual void STR (int cc, int Rd,
79 int Rn, uint32_t offset = immed12_pre(0));
80 virtual void STRB(int cc, int Rd,
81 int Rn, uint32_t offset = immed12_pre(0));
82 virtual void LDRH (int cc, int Rd,
83 int Rn, uint32_t offset = immed8_pre(0));
84 virtual void LDRSB(int cc, int Rd,
85 int Rn, uint32_t offset = immed8_pre(0));
86 virtual void LDRSH(int cc, int Rd,
87 int Rn, uint32_t offset = immed8_pre(0));
88 virtual void STRH (int cc, int Rd,
89 int Rn, uint32_t offset = immed8_pre(0));
90 virtual void LDM(int cc, int dir,
91 int Rn, int W, uint32_t reg_list);
92 virtual void STM(int cc, int dir,
93 int Rn, int W, uint32_t reg_list);
94
95 virtual void SWP(int cc, int Rn, int Rd, int Rm);
96 virtual void SWPB(int cc, int Rn, int Rd, int Rm);
97 virtual void SWI(int cc, uint32_t comment);
98
99 virtual void PLD(int Rn, uint32_t offset);
100 virtual void CLZ(int cc, int Rd, int Rm);
101 virtual void QADD(int cc, int Rd, int Rm, int Rn);
102 virtual void QDADD(int cc, int Rd, int Rm, int Rn);
103 virtual void QSUB(int cc, int Rd, int Rm, int Rn);
104 virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
105 virtual void SMUL(int cc, int xy,
106 int Rd, int Rm, int Rs);
107 virtual void SMULW(int cc, int y,
108 int Rd, int Rm, int Rs);
109 virtual void SMLA(int cc, int xy,
110 int Rd, int Rm, int Rs, int Rn);
111 virtual void SMLAL(int cc, int xy,
112 int RdHi, int RdLo, int Rs, int Rm);
113 virtual void SMLAW(int cc, int y,
114 int Rd, int Rm, int Rs, int Rn);
115
116 private:
117 ARMAssemblerInterface* mTarget;
118 };
119
120 }; // namespace android
121
122 #endif //ANDROID_ARMASSEMBLER_PROXY_H
+0
-151
libpixelflinger/codeflinger/CodeCache.cpp less more
0 /* libs/pixelflinger/codeflinger/CodeCache.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #include <assert.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #include <cutils/log.h>
23 #include <cutils/atomic.h>
24
25 #include "codeflinger/CodeCache.h"
26
27 namespace android {
28
29 // ----------------------------------------------------------------------------
30
31 #if defined(__arm__)
32 #include <unistd.h>
33 #include <errno.h>
34 #endif
35
36 // ----------------------------------------------------------------------------
37
38 Assembly::Assembly(size_t size)
39 : mCount(1), mSize(0)
40 {
41 mBase = (uint32_t*)malloc(size);
42 if (mBase) {
43 mSize = size;
44 }
45 }
46
47 Assembly::~Assembly()
48 {
49 free(mBase);
50 }
51
52 void Assembly::incStrong(const void*) const
53 {
54 android_atomic_inc(&mCount);
55 }
56
57 void Assembly::decStrong(const void*) const
58 {
59 if (android_atomic_dec(&mCount) == 1) {
60 delete this;
61 }
62 }
63
64 ssize_t Assembly::size() const
65 {
66 if (!mBase) return NO_MEMORY;
67 return mSize;
68 }
69
70 uint32_t* Assembly::base() const
71 {
72 return mBase;
73 }
74
75 ssize_t Assembly::resize(size_t newSize)
76 {
77 mBase = (uint32_t*)realloc(mBase, newSize);
78 mSize = newSize;
79 return size();
80 }
81
82 // ----------------------------------------------------------------------------
83
84 CodeCache::CodeCache(size_t size)
85 : mCacheSize(size), mCacheInUse(0)
86 {
87 pthread_mutex_init(&mLock, 0);
88 }
89
90 CodeCache::~CodeCache()
91 {
92 pthread_mutex_destroy(&mLock);
93 }
94
95 sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
96 {
97 pthread_mutex_lock(&mLock);
98 sp<Assembly> r;
99 ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
100 if (index >= 0) {
101 const cache_entry_t& e = mCacheData.valueAt(index);
102 e.when = mWhen++;
103 r = e.entry;
104 }
105 pthread_mutex_unlock(&mLock);
106 return r;
107 }
108
109 int CodeCache::cache( const AssemblyKeyBase& keyBase,
110 const sp<Assembly>& assembly)
111 {
112 pthread_mutex_lock(&mLock);
113
114 const ssize_t assemblySize = assembly->size();
115 while (mCacheInUse + assemblySize > mCacheSize) {
116 // evict the LRU
117 size_t lru = 0;
118 size_t count = mCacheData.size();
119 for (size_t i=0 ; i<count ; i++) {
120 const cache_entry_t& e = mCacheData.valueAt(i);
121 if (e.when < mCacheData.valueAt(lru).when) {
122 lru = i;
123 }
124 }
125 const cache_entry_t& e = mCacheData.valueAt(lru);
126 mCacheInUse -= e.entry->size();
127 mCacheData.removeItemsAt(lru);
128 }
129
130 ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
131 if (err >= 0) {
132 mCacheInUse += assemblySize;
133 mWhen++;
134 // synchronize caches...
135 #if defined(__arm__)
136 const long base = long(assembly->base());
137 const long curr = base + long(assembly->size());
138 err = cacheflush(base, curr, 0);
139 LOGE_IF(err, "__ARM_NR_cacheflush error %s\n",
140 strerror(errno));
141 #endif
142 }
143
144 pthread_mutex_unlock(&mLock);
145 return err;
146 }
147
148 // ----------------------------------------------------------------------------
149
150 }; // namespace android
+0
-134
libpixelflinger/codeflinger/CodeCache.h less more
0 /* libs/pixelflinger/codeflinger/CodeCache.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_CODECACHE_H
19 #define ANDROID_CODECACHE_H
20
21 #include <stdint.h>
22 #include <pthread.h>
23 #include <sys/types.h>
24
25 #include <utils/KeyedVector.h>
26
27 #include "tinyutils/smartpointer.h"
28
29 namespace android {
30
31 // ----------------------------------------------------------------------------
32
33 class AssemblyKeyBase {
34 public:
35 virtual ~AssemblyKeyBase() { }
36 virtual int compare_type(const AssemblyKeyBase& key) const = 0;
37 };
38
39 template <typename T>
40 class AssemblyKey : public AssemblyKeyBase
41 {
42 public:
43 AssemblyKey(const T& rhs) : mKey(rhs) { }
44 virtual int compare_type(const AssemblyKeyBase& key) const {
45 const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
46 return android::compare_type(mKey, rhs);
47 }
48 private:
49 T mKey;
50 };
51
52 // ----------------------------------------------------------------------------
53
54 class Assembly
55 {
56 public:
57 Assembly(size_t size);
58 virtual ~Assembly();
59
60 ssize_t size() const;
61 uint32_t* base() const;
62 ssize_t resize(size_t size);
63
64 // protocol for sp<>
65 void incStrong(const void* id) const;
66 void decStrong(const void* id) const;
67 typedef void weakref_type;
68
69 private:
70 mutable int32_t mCount;
71 uint32_t* mBase;
72 ssize_t mSize;
73 };
74
75 // ----------------------------------------------------------------------------
76
77 class CodeCache
78 {
79 public:
80 // pretty simple cache API...
81 CodeCache(size_t size);
82 ~CodeCache();
83
84 sp<Assembly> lookup(const AssemblyKeyBase& key) const;
85
86 int cache( const AssemblyKeyBase& key,
87 const sp<Assembly>& assembly);
88
89 private:
90 // nothing to see here...
91 struct cache_entry_t {
92 inline cache_entry_t() { }
93 inline cache_entry_t(const sp<Assembly>& a, int64_t w)
94 : entry(a), when(w) { }
95 sp<Assembly> entry;
96 mutable int64_t when;
97 };
98
99 class key_t {
100 friend int compare_type(
101 const key_value_pair_t<key_t, cache_entry_t>&,
102 const key_value_pair_t<key_t, cache_entry_t>&);
103 const AssemblyKeyBase* mKey;
104 public:
105 key_t() { };
106 key_t(const AssemblyKeyBase& k) : mKey(&k) { }
107 };
108
109 mutable pthread_mutex_t mLock;
110 mutable int64_t mWhen;
111 size_t mCacheSize;
112 size_t mCacheInUse;
113 KeyedVector<key_t, cache_entry_t> mCacheData;
114
115 friend int compare_type(
116 const key_value_pair_t<key_t, cache_entry_t>&,
117 const key_value_pair_t<key_t, cache_entry_t>&);
118 };
119
120 // KeyedVector uses compare_type(), which is more efficient, than
121 // just using operator < ()
122 inline int compare_type(
123 const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& lhs,
124 const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& rhs)
125 {
126 return lhs.key.mKey->compare_type(*(rhs.key.mKey));
127 }
128
129 // ----------------------------------------------------------------------------
130
131 }; // namespace android
132
133 #endif //ANDROID_CODECACHE_H
+0
-1150
libpixelflinger/codeflinger/GGLAssembler.cpp less more
0 /* libs/pixelflinger/codeflinger/GGLAssembler.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #define LOG_TAG "GGLAssembler"
18
19 #include <assert.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <cutils/log.h>
25
26 #include "codeflinger/GGLAssembler.h"
27
28 namespace android {
29
30 // ----------------------------------------------------------------------------
31
32 GGLAssembler::GGLAssembler(ARMAssemblerInterface* target)
33 : ARMAssemblerProxy(target), RegisterAllocator(), mOptLevel(7)
34 {
35 }
36
37 GGLAssembler::~GGLAssembler()
38 {
39 }
40
41 void GGLAssembler::prolog()
42 {
43 ARMAssemblerProxy::prolog();
44 }
45
46 void GGLAssembler::epilog(uint32_t touched)
47 {
48 ARMAssemblerProxy::epilog(touched);
49 }
50
51 void GGLAssembler::reset(int opt_level)
52 {
53 ARMAssemblerProxy::reset();
54 RegisterAllocator::reset();
55 mOptLevel = opt_level;
56 }
57
58 // ---------------------------------------------------------------------------
59
60 int GGLAssembler::scanline(const needs_t& needs, context_t const* c)
61 {
62 int err = 0;
63 int opt_level = mOptLevel;
64 while (opt_level >= 0) {
65 reset(opt_level);
66 err = scanline_core(needs, c);
67 if (err == 0)
68 break;
69 opt_level--;
70 }
71
72 // XXX: in theory, pcForLabel is not valid before generate()
73 uint32_t* fragment_start_pc = pcForLabel("fragment_loop");
74 uint32_t* fragment_end_pc = pcForLabel("epilog");
75 const int per_fragment_ops = int(fragment_end_pc - fragment_start_pc);
76
77 // build a name for our pipeline
78 char name[64];
79 sprintf(name,
80 "scanline__%08X:%08X_%08X_%08X [%3d ipp]",
81 needs.p, needs.n, needs.t[0], needs.t[1], per_fragment_ops);
82
83 if (err) {
84 LOGE("Error while generating ""%s""\n", name);
85 disassemble(name);
86 return -1;
87 }
88
89 return generate(name);
90 }
91
92 int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
93 {
94 int64_t duration = ggl_system_time();
95
96 mBlendFactorCached = 0;
97 mBlending = 0;
98 mMasking = 0;
99 mAA = GGL_READ_NEEDS(P_AA, needs.p);
100 mDithering = GGL_READ_NEEDS(P_DITHER, needs.p);
101 mAlphaTest = GGL_READ_NEEDS(P_ALPHA_TEST, needs.p) + GGL_NEVER;
102 mDepthTest = GGL_READ_NEEDS(P_DEPTH_TEST, needs.p) + GGL_NEVER;
103 mFog = GGL_READ_NEEDS(P_FOG, needs.p) != 0;
104 mSmooth = GGL_READ_NEEDS(SHADE, needs.n) != 0;
105 mBuilderContext.needs = needs;
106 mBuilderContext.c = c;
107 mBuilderContext.Rctx = reserveReg(R0); // context always in R0
108 mCbFormat = c->formats[ GGL_READ_NEEDS(CB_FORMAT, needs.n) ];
109
110 // ------------------------------------------------------------------------
111
112 decodeLogicOpNeeds(needs);
113
114 decodeTMUNeeds(needs, c);
115
116 mBlendSrc = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRC, needs.n));
117 mBlendDst = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DST, needs.n));
118 mBlendSrcA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRCA, needs.n));
119 mBlendDstA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DSTA, needs.n));
120
121 if (!mCbFormat.c[GGLFormat::ALPHA].h) {
122 if ((mBlendSrc == GGL_ONE_MINUS_DST_ALPHA) ||
123 (mBlendSrc == GGL_DST_ALPHA)) {
124 mBlendSrc = GGL_ONE;
125 }
126 if ((mBlendSrcA == GGL_ONE_MINUS_DST_ALPHA) ||
127 (mBlendSrcA == GGL_DST_ALPHA)) {
128 mBlendSrcA = GGL_ONE;
129 }
130 if ((mBlendDst == GGL_ONE_MINUS_DST_ALPHA) ||
131 (mBlendDst == GGL_DST_ALPHA)) {
132 mBlendDst = GGL_ONE;
133 }
134 if ((mBlendDstA == GGL_ONE_MINUS_DST_ALPHA) ||
135 (mBlendDstA == GGL_DST_ALPHA)) {
136 mBlendDstA = GGL_ONE;
137 }
138 }
139
140 // if we need the framebuffer, read it now
141 const int blending = blending_codes(mBlendSrc, mBlendDst) |
142 blending_codes(mBlendSrcA, mBlendDstA);
143
144 // XXX: handle special cases, destination not modified...
145 if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
146 (mBlendDst==GGL_ONE) && (mBlendDstA==GGL_ONE)) {
147 // Destination unmodified (beware of logic ops)
148 } else if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
149 (mBlendDst==GGL_ZERO) && (mBlendDstA==GGL_ZERO)) {
150 // Destination is zero (beware of logic ops)
151 }
152
153 int fbComponents = 0;
154 const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
155 for (int i=0 ; i<4 ; i++) {
156 const int mask = 1<<i;
157 component_info_t& info = mInfo[i];
158 int fs = i==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
159 int fd = i==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
160 if (fs==GGL_SRC_ALPHA_SATURATE && i==GGLFormat::ALPHA)
161 fs = GGL_ONE;
162 info.masked = !!(masking & mask);
163 info.inDest = !info.masked && mCbFormat.c[i].h &&
164 ((mLogicOp & LOGIC_OP_SRC) || (!mLogicOp));
165 if (mCbFormat.components >= GGL_LUMINANCE &&
166 (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
167 info.inDest = false;
168 }
169 info.needed = (i==GGLFormat::ALPHA) &&
170 (isAlphaSourceNeeded() || mAlphaTest != GGL_ALWAYS);
171 info.replaced = !!(mTextureMachine.replaced & mask);
172 info.iterated = (!info.replaced && (info.inDest || info.needed));
173 info.smooth = mSmooth && info.iterated;
174 info.fog = mFog && info.inDest && (i != GGLFormat::ALPHA);
175 info.blend = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
176
177 mBlending |= (info.blend ? mask : 0);
178 mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
179 fbComponents |= mCbFormat.c[i].h ? mask : 0;
180 }
181
182 mAllMasked = (mMasking == fbComponents);
183 if (mAllMasked) {
184 mDithering = 0;
185 }
186
187 fragment_parts_t parts;
188
189 // ------------------------------------------------------------------------
190 prolog();
191 // ------------------------------------------------------------------------
192
193 build_scanline_prolog(parts, needs);
194
195 if (registerFile().status())
196 return registerFile().status();
197
198 // ------------------------------------------------------------------------
199 label("fragment_loop");
200 // ------------------------------------------------------------------------
201 {
202 Scratch regs(registerFile());
203
204 if (mDithering) {
205 // update the dither index.
206 MOV(AL, 0, parts.count.reg,
207 reg_imm(parts.count.reg, ROR, GGL_DITHER_ORDER_SHIFT));
208 ADD(AL, 0, parts.count.reg, parts.count.reg,
209 imm( 1 << (32 - GGL_DITHER_ORDER_SHIFT)));
210 MOV(AL, 0, parts.count.reg,
211 reg_imm(parts.count.reg, ROR, 32 - GGL_DITHER_ORDER_SHIFT));
212 }
213
214 // XXX: could we do an early alpha-test here in some cases?
215 // It would probaly be used only with smooth-alpha and no texture
216 // (or no alpha component in the texture).
217
218 // Early z-test
219 if (mAlphaTest==GGL_ALWAYS) {
220 build_depth_test(parts, Z_TEST|Z_WRITE);
221 } else {
222 // we cannot do the z-write here, because
223 // it might be killed by the alpha-test later
224 build_depth_test(parts, Z_TEST);
225 }
226
227 { // texture coordinates
228 Scratch scratches(registerFile());
229
230 // texel generation
231 build_textures(parts, regs);
232 }
233
234 if ((blending & (FACTOR_DST|BLEND_DST)) ||
235 (mMasking && !mAllMasked) ||
236 (mLogicOp & LOGIC_OP_DST))
237 {
238 // blending / logic_op / masking need the framebuffer
239 mDstPixel.setTo(regs.obtain(), &mCbFormat);
240
241 // load the framebuffer pixel
242 comment("fetch color-buffer");
243 load(parts.cbPtr, mDstPixel);
244 }
245
246 if (registerFile().status())
247 return registerFile().status();
248
249 pixel_t pixel;
250 int directTex = mTextureMachine.directTexture;
251 if (directTex | parts.packed) {
252 // note: we can't have both here
253 // iterated color or direct texture
254 pixel = directTex ? parts.texel[directTex-1] : parts.iterated;
255 pixel.flags &= ~CORRUPTIBLE;
256 } else {
257 if (mDithering) {
258 const int ctxtReg = mBuilderContext.Rctx;
259 const int mask = GGL_DITHER_SIZE-1;
260 parts.dither = reg_t(regs.obtain());
261 AND(AL, 0, parts.dither.reg, parts.count.reg, imm(mask));
262 ADD(AL, 0, parts.dither.reg, parts.dither.reg, ctxtReg);
263 LDRB(AL, parts.dither.reg, parts.dither.reg,
264 immed12_pre(GGL_OFFSETOF(ditherMatrix)));
265 }
266
267 // allocate a register for the resulting pixel
268 pixel.setTo(regs.obtain(), &mCbFormat, FIRST);
269
270 build_component(pixel, parts, GGLFormat::ALPHA, regs);
271
272 if (mAlphaTest!=GGL_ALWAYS) {
273 // only handle the z-write part here. We know z-test
274 // was successful, as well as alpha-test.
275 build_depth_test(parts, Z_WRITE);
276 }
277
278 build_component(pixel, parts, GGLFormat::RED, regs);
279 build_component(pixel, parts, GGLFormat::GREEN, regs);
280 build_component(pixel, parts, GGLFormat::BLUE, regs);
281
282 pixel.flags |= CORRUPTIBLE;
283 }
284
285 if (registerFile().status())
286 return registerFile().status();
287
288 if (pixel.reg == -1) {
289 // be defensive here. if we're here it's probably
290 // that this whole fragment is a no-op.
291 pixel = mDstPixel;
292 }
293
294 if (!mAllMasked) {
295 // logic operation
296 build_logic_op(pixel, regs);
297
298 // masking
299 build_masking(pixel, regs);
300
301 comment("store");
302 store(parts.cbPtr, pixel, WRITE_BACK);
303 }
304 }
305
306 if (registerFile().status())
307 return registerFile().status();
308
309 // update the iterated color...
310 if (parts.reload != 3) {
311 build_smooth_shade(parts);
312 }
313
314 // update iterated z
315 build_iterate_z(parts);
316
317 // update iterated fog
318 build_iterate_f(parts);
319
320 SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
321 B(PL, "fragment_loop");
322 label("epilog");
323 epilog(registerFile().touched());
324
325 if ((mAlphaTest!=GGL_ALWAYS) || (mDepthTest!=GGL_ALWAYS)) {
326 if (mDepthTest!=GGL_ALWAYS) {
327 label("discard_before_textures");
328 build_iterate_texture_coordinates(parts);
329 }
330 label("discard_after_textures");
331 build_smooth_shade(parts);
332 build_iterate_z(parts);
333 build_iterate_f(parts);
334 if (!mAllMasked) {
335 ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
336 }
337 SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
338 B(PL, "fragment_loop");
339 epilog(registerFile().touched());
340 }
341
342 return registerFile().status();
343 }
344
345 // ---------------------------------------------------------------------------
346
347 void GGLAssembler::build_scanline_prolog(
348 fragment_parts_t& parts, const needs_t& needs)
349 {
350 Scratch scratches(registerFile());
351 int Rctx = mBuilderContext.Rctx;
352
353 // compute count
354 comment("compute ct (# of pixels to process)");
355 parts.count.setTo(obtainReg());
356 int Rx = scratches.obtain();
357 int Ry = scratches.obtain();
358 CONTEXT_LOAD(Rx, iterators.xl);
359 CONTEXT_LOAD(parts.count.reg, iterators.xr);
360 CONTEXT_LOAD(Ry, iterators.y);
361
362 // parts.count = iterators.xr - Rx
363 SUB(AL, 0, parts.count.reg, parts.count.reg, Rx);
364 SUB(AL, 0, parts.count.reg, parts.count.reg, imm(1));
365
366 if (mDithering) {
367 // parts.count.reg = 0xNNNNXXDD
368 // NNNN = count-1
369 // DD = dither offset
370 // XX = 0xxxxxxx (x = garbage)
371 Scratch scratches(registerFile());
372 int tx = scratches.obtain();
373 int ty = scratches.obtain();
374 AND(AL, 0, tx, Rx, imm(GGL_DITHER_MASK));
375 AND(AL, 0, ty, Ry, imm(GGL_DITHER_MASK));
376 ADD(AL, 0, tx, tx, reg_imm(ty, LSL, GGL_DITHER_ORDER_SHIFT));
377 ORR(AL, 0, parts.count.reg, tx, reg_imm(parts.count.reg, LSL, 16));
378 } else {
379 // parts.count.reg = 0xNNNN0000
380 // NNNN = count-1
381 MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
382 }
383
384 if (!mAllMasked) {
385 // compute dst ptr
386 comment("compute color-buffer pointer");
387 const int cb_bits = mCbFormat.size*8;
388 int Rs = scratches.obtain();
389 parts.cbPtr.setTo(obtainReg(), cb_bits);
390 CONTEXT_LOAD(Rs, state.buffers.color.stride);
391 CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
392 SMLABB(AL, Rs, Ry, Rs, Rx); // Rs = Rx + Ry*Rs
393 base_offset(parts.cbPtr, parts.cbPtr, Rs);
394 scratches.recycle(Rs);
395 }
396
397 // init fog
398 const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
399 if (need_fog) {
400 comment("compute initial fog coordinate");
401 Scratch scratches(registerFile());
402 int dfdx = scratches.obtain();
403 int ydfdy = scratches.obtain();
404 int f = ydfdy;
405 CONTEXT_LOAD(dfdx, generated_vars.dfdx);
406 CONTEXT_LOAD(ydfdy, iterators.ydfdy);
407 MLA(AL, 0, f, Rx, dfdx, ydfdy);
408 CONTEXT_STORE(f, generated_vars.f);
409 }
410
411 // init Z coordinate
412 if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
413 parts.z = reg_t(obtainReg());
414 comment("compute initial Z coordinate");
415 Scratch scratches(registerFile());
416 int dzdx = scratches.obtain();
417 int ydzdy = parts.z.reg;
418 CONTEXT_LOAD(dzdx, generated_vars.dzdx); // 1.31 fixed-point
419 CONTEXT_LOAD(ydzdy, iterators.ydzdy); // 1.31 fixed-point
420 MLA(AL, 0, parts.z.reg, Rx, dzdx, ydzdy);
421
422 // we're going to index zbase of parts.count
423 // zbase = base + (xl-count + stride*y)*2
424 int Rs = dzdx;
425 int zbase = scratches.obtain();
426 CONTEXT_LOAD(Rs, state.buffers.depth.stride);
427 CONTEXT_LOAD(zbase, state.buffers.depth.data);
428 SMLABB(AL, Rs, Ry, Rs, Rx);
429 ADD(AL, 0, Rs, Rs, reg_imm(parts.count.reg, LSR, 16));
430 ADD(AL, 0, zbase, zbase, reg_imm(Rs, LSL, 1));
431 CONTEXT_STORE(zbase, generated_vars.zbase);
432 }
433
434 // init texture coordinates
435 init_textures(parts.coords, reg_t(Rx), reg_t(Ry));
436 scratches.recycle(Ry);
437
438 // iterated color
439 init_iterated_color(parts, reg_t(Rx));
440
441 // init coverage factor application (anti-aliasing)
442 if (mAA) {
443 parts.covPtr.setTo(obtainReg(), 16);
444 CONTEXT_LOAD(parts.covPtr.reg, state.buffers.coverage);
445 ADD(AL, 0, parts.covPtr.reg, parts.covPtr.reg, reg_imm(Rx, LSL, 1));
446 }
447 }
448
449 // ---------------------------------------------------------------------------
450
451 void GGLAssembler::build_component( pixel_t& pixel,
452 const fragment_parts_t& parts,
453 int component,
454 Scratch& regs)
455 {
456 static char const * comments[] = {"alpha", "red", "green", "blue"};
457 comment(comments[component]);
458
459 // local register file
460 Scratch scratches(registerFile());
461 const int dst_component_size = pixel.component_size(component);
462
463 component_t temp(-1);
464 build_incoming_component( temp, dst_component_size,
465 parts, component, scratches, regs);
466
467 if (mInfo[component].inDest) {
468
469 // blending...
470 build_blending( temp, mDstPixel, component, scratches );
471
472 // downshift component and rebuild pixel...
473 downshift(pixel, component, temp, parts.dither);
474 }
475 }
476
477 void GGLAssembler::build_incoming_component(
478 component_t& temp,
479 int dst_size,
480 const fragment_parts_t& parts,
481 int component,
482 Scratch& scratches,
483 Scratch& global_regs)
484 {
485 const uint32_t component_mask = 1<<component;
486
487 // Figure out what we need for the blending stage...
488 int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
489 int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
490 if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA) {
491 fs = GGL_ONE;
492 }
493
494 // Figure out what we need to extract and for what reason
495 const int blending = blending_codes(fs, fd);
496
497 // Are we actually going to blend?
498 const int need_blending = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
499
500 // expand the source if the destination has more bits
501 int need_expander = false;
502 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT-1 ; i++) {
503 texture_unit_t& tmu = mTextureMachine.tmu[i];
504 if ((tmu.format_idx) &&
505 (parts.texel[i].component_size(component) < dst_size)) {
506 need_expander = true;
507 }
508 }
509
510 // do we need to extract this component?
511 const bool multiTexture = mTextureMachine.activeUnits > 1;
512 const int blend_needs_alpha_source = (component==GGLFormat::ALPHA) &&
513 (isAlphaSourceNeeded());
514 int need_extract = mInfo[component].needed;
515 if (mInfo[component].inDest)
516 {
517 need_extract |= ((need_blending ?
518 (blending & (BLEND_SRC|FACTOR_SRC)) : need_expander));
519 need_extract |= (mTextureMachine.mask != mTextureMachine.replaced);
520 need_extract |= mInfo[component].smooth;
521 need_extract |= mInfo[component].fog;
522 need_extract |= mDithering;
523 need_extract |= multiTexture;
524 }
525
526 if (need_extract) {
527 Scratch& regs = blend_needs_alpha_source ? global_regs : scratches;
528 component_t fragment;
529
530 // iterated color
531 build_iterated_color(fragment, parts, component, regs);
532
533 // texture environement (decal, modulate, replace)
534 build_texture_environment(fragment, parts, component, regs);
535
536 // expand the source if the destination has more bits
537 if (need_expander && (fragment.size() < dst_size)) {
538 // we're here only if we fetched a texel
539 // (so we know for sure fragment is CORRUPTIBLE)
540 expand(fragment, fragment, dst_size);
541 }
542
543 // We have a few specific things to do for the alpha-channel
544 if ((component==GGLFormat::ALPHA) &&
545 (mInfo[component].needed || fragment.size()<dst_size))
546 {
547 // convert to integer_t first and make sure
548 // we don't corrupt a needed register
549 if (fragment.l) {
550 component_t incoming(fragment);
551 modify(fragment, regs);
552 MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSR, incoming.l));
553 fragment.h -= fragment.l;
554 fragment.l = 0;
555 }
556
557 // coverage factor application
558 build_coverage_application(fragment, parts, regs);
559
560 // alpha-test
561 build_alpha_test(fragment, parts);
562
563 if (blend_needs_alpha_source) {
564 // We keep only 8 bits for the blending stage
565 const int shift = fragment.h <= 8 ? 0 : fragment.h-8;
566 if (fragment.flags & CORRUPTIBLE) {
567 fragment.flags &= ~CORRUPTIBLE;
568 mAlphaSource.setTo(fragment.reg,
569 fragment.size(), fragment.flags);
570 if (shift) {
571 MOV(AL, 0, mAlphaSource.reg,
572 reg_imm(mAlphaSource.reg, LSR, shift));
573 }
574 } else {
575 // XXX: it would better to do this in build_blend_factor()
576 // so we can avoid the extra MOV below.
577 mAlphaSource.setTo(regs.obtain(),
578 fragment.size(), CORRUPTIBLE);
579 if (shift) {
580 MOV(AL, 0, mAlphaSource.reg,
581 reg_imm(fragment.reg, LSR, shift));
582 } else {
583 MOV(AL, 0, mAlphaSource.reg, fragment.reg);
584 }
585 }
586 mAlphaSource.s -= shift;
587 }
588 }
589
590 // fog...
591 build_fog( fragment, component, regs );
592
593 temp = fragment;
594 } else {
595 if (mInfo[component].inDest) {
596 // extraction not needed and replace
597 // we just select the right component
598 if ((mTextureMachine.replaced & component_mask) == 0) {
599 // component wasn't replaced, so use it!
600 temp = component_t(parts.iterated, component);
601 }
602 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
603 const texture_unit_t& tmu = mTextureMachine.tmu[i];
604 if ((tmu.mask & component_mask) &&
605 ((tmu.replaced & component_mask) == 0)) {
606 temp = component_t(parts.texel[i], component);
607 }
608 }
609 }
610 }
611 }
612
613 bool GGLAssembler::isAlphaSourceNeeded() const
614 {
615 // XXX: also needed for alpha-test
616 const int bs = mBlendSrc;
617 const int bd = mBlendDst;
618 return bs==GGL_SRC_ALPHA_SATURATE ||
619 bs==GGL_SRC_ALPHA || bs==GGL_ONE_MINUS_SRC_ALPHA ||
620 bd==GGL_SRC_ALPHA || bd==GGL_ONE_MINUS_SRC_ALPHA ;
621 }
622
623 // ---------------------------------------------------------------------------
624
625 void GGLAssembler::build_smooth_shade(const fragment_parts_t& parts)
626 {
627 if (mSmooth && !parts.iterated_packed) {
628 // update the iterated color in a pipelined way...
629 comment("update iterated color");
630 Scratch scratches(registerFile());
631
632 const int reload = parts.reload;
633 for (int i=0 ; i<4 ; i++) {
634 if (!mInfo[i].iterated)
635 continue;
636
637 int c = parts.argb[i].reg;
638 int dx = parts.argb_dx[i].reg;
639
640 if (reload & 1) {
641 c = scratches.obtain();
642 CONTEXT_LOAD(c, generated_vars.argb[i].c);
643 }
644 if (reload & 2) {
645 dx = scratches.obtain();
646 CONTEXT_LOAD(dx, generated_vars.argb[i].dx);
647 }
648
649 if (mSmooth) {
650 ADD(AL, 0, c, c, dx);
651 }
652
653 if (reload & 1) {
654 CONTEXT_STORE(c, generated_vars.argb[i].c);
655 scratches.recycle(c);
656 }
657 if (reload & 2) {
658 scratches.recycle(dx);
659 }
660 }
661 }
662 }
663
664 // ---------------------------------------------------------------------------
665
666 void GGLAssembler::build_coverage_application(component_t& fragment,
667 const fragment_parts_t& parts, Scratch& regs)
668 {
669 // here fragment.l is guarenteed to be 0
670 if (mAA) {
671 // coverages are 1.15 fixed-point numbers
672 comment("coverage application");
673
674 component_t incoming(fragment);
675 modify(fragment, regs);
676
677 Scratch scratches(registerFile());
678 int cf = scratches.obtain();
679 LDRH(AL, cf, parts.covPtr.reg, immed8_post(2));
680 if (fragment.h > 31) {
681 fragment.h--;
682 SMULWB(AL, fragment.reg, incoming.reg, cf);
683 } else {
684 MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSL, 1));
685 SMULWB(AL, fragment.reg, fragment.reg, cf);
686 }
687 }
688 }
689
690 // ---------------------------------------------------------------------------
691
692 void GGLAssembler::build_alpha_test(component_t& fragment,
693 const fragment_parts_t& parts)
694 {
695 if (mAlphaTest != GGL_ALWAYS) {
696 comment("Alpha Test");
697 Scratch scratches(registerFile());
698 int ref = scratches.obtain();
699 const int shift = GGL_COLOR_BITS-fragment.size();
700 CONTEXT_LOAD(ref, state.alpha_test.ref);
701 if (shift) CMP(AL, fragment.reg, reg_imm(ref, LSR, shift));
702 else CMP(AL, fragment.reg, ref);
703 int cc = NV;
704 switch (mAlphaTest) {
705 case GGL_NEVER: cc = NV; break;
706 case GGL_LESS: cc = LT; break;
707 case GGL_EQUAL: cc = EQ; break;
708 case GGL_LEQUAL: cc = LS; break;
709 case GGL_GREATER: cc = HI; break;
710 case GGL_NOTEQUAL: cc = NE; break;
711 case GGL_GEQUAL: cc = HS; break;
712 }
713 B(cc^1, "discard_after_textures");
714 }
715 }
716
717 // ---------------------------------------------------------------------------
718
719 void GGLAssembler::build_depth_test(
720 const fragment_parts_t& parts, uint32_t mask)
721 {
722 mask &= Z_TEST|Z_WRITE;
723 const needs_t& needs = mBuilderContext.needs;
724 const int zmask = GGL_READ_NEEDS(P_MASK_Z, needs.p);
725 Scratch scratches(registerFile());
726
727 if (mDepthTest != GGL_ALWAYS || zmask) {
728 int cc=AL, ic=AL;
729 switch (mDepthTest) {
730 case GGL_LESS: ic = HI; break;
731 case GGL_EQUAL: ic = EQ; break;
732 case GGL_LEQUAL: ic = HS; break;
733 case GGL_GREATER: ic = LT; break;
734 case GGL_NOTEQUAL: ic = NE; break;
735 case GGL_GEQUAL: ic = LS; break;
736 case GGL_NEVER:
737 // this never happens, because it's taken care of when
738 // computing the needs. but we keep it for completness.
739 comment("Depth Test (NEVER)");
740 B(AL, "discard_before_textures");
741 return;
742 case GGL_ALWAYS:
743 // we're here because zmask is enabled
744 mask &= ~Z_TEST; // test always passes.
745 break;
746 }
747
748 // inverse the condition
749 cc = ic^1;
750
751 if ((mask & Z_WRITE) && !zmask) {
752 mask &= ~Z_WRITE;
753 }
754
755 if (!mask)
756 return;
757
758 comment("Depth Test");
759
760 int zbase = scratches.obtain();
761 int depth = scratches.obtain();
762 int z = parts.z.reg;
763
764 CONTEXT_LOAD(zbase, generated_vars.zbase); // stall
765 SUB(AL, 0, zbase, zbase, reg_imm(parts.count.reg, LSR, 15));
766 // above does zbase = zbase + ((count >> 16) << 1)
767
768 if (mask & Z_TEST) {
769 LDRH(AL, depth, zbase); // stall
770 CMP(AL, depth, reg_imm(z, LSR, 16));
771 B(cc, "discard_before_textures");
772 }
773 if (mask & Z_WRITE) {
774 if (mask == Z_WRITE) {
775 // only z-write asked, cc is meaningless
776 ic = AL;
777 }
778 MOV(AL, 0, depth, reg_imm(z, LSR, 16));
779 STRH(ic, depth, zbase);
780 }
781 }
782 }
783
784 void GGLAssembler::build_iterate_z(const fragment_parts_t& parts)
785 {
786 const needs_t& needs = mBuilderContext.needs;
787 if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
788 Scratch scratches(registerFile());
789 int dzdx = scratches.obtain();
790 CONTEXT_LOAD(dzdx, generated_vars.dzdx); // stall
791 ADD(AL, 0, parts.z.reg, parts.z.reg, dzdx);
792 }
793 }
794
795 void GGLAssembler::build_iterate_f(const fragment_parts_t& parts)
796 {
797 const needs_t& needs = mBuilderContext.needs;
798 if (GGL_READ_NEEDS(P_FOG, needs.p)) {
799 Scratch scratches(registerFile());
800 int dfdx = scratches.obtain();
801 int f = scratches.obtain();
802 CONTEXT_LOAD(f, generated_vars.f);
803 CONTEXT_LOAD(dfdx, generated_vars.dfdx); // stall
804 ADD(AL, 0, f, f, dfdx);
805 CONTEXT_STORE(f, generated_vars.f);
806 }
807 }
808
809 // ---------------------------------------------------------------------------
810
811 void GGLAssembler::build_logic_op(pixel_t& pixel, Scratch& regs)
812 {
813 const needs_t& needs = mBuilderContext.needs;
814 const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
815 if (opcode == GGL_COPY)
816 return;
817
818 comment("logic operation");
819
820 pixel_t s(pixel);
821 if (!(pixel.flags & CORRUPTIBLE)) {
822 pixel.reg = regs.obtain();
823 pixel.flags |= CORRUPTIBLE;
824 }
825
826 pixel_t d(mDstPixel);
827 switch(opcode) {
828 case GGL_CLEAR: MOV(AL, 0, pixel.reg, imm(0)); break;
829 case GGL_AND: AND(AL, 0, pixel.reg, s.reg, d.reg); break;
830 case GGL_AND_REVERSE: BIC(AL, 0, pixel.reg, s.reg, d.reg); break;
831 case GGL_COPY: break;
832 case GGL_AND_INVERTED: BIC(AL, 0, pixel.reg, d.reg, s.reg); break;
833 case GGL_NOOP: MOV(AL, 0, pixel.reg, d.reg); break;
834 case GGL_XOR: EOR(AL, 0, pixel.reg, s.reg, d.reg); break;
835 case GGL_OR: ORR(AL, 0, pixel.reg, s.reg, d.reg); break;
836 case GGL_NOR: ORR(AL, 0, pixel.reg, s.reg, d.reg);
837 MVN(AL, 0, pixel.reg, pixel.reg); break;
838 case GGL_EQUIV: EOR(AL, 0, pixel.reg, s.reg, d.reg);
839 MVN(AL, 0, pixel.reg, pixel.reg); break;
840 case GGL_INVERT: MVN(AL, 0, pixel.reg, d.reg); break;
841 case GGL_OR_REVERSE: // s | ~d == ~(~s & d)
842 BIC(AL, 0, pixel.reg, d.reg, s.reg);
843 MVN(AL, 0, pixel.reg, pixel.reg); break;
844 case GGL_COPY_INVERTED: MVN(AL, 0, pixel.reg, s.reg); break;
845 case GGL_OR_INVERTED: // ~s | d == ~(s & ~d)
846 BIC(AL, 0, pixel.reg, s.reg, d.reg);
847 MVN(AL, 0, pixel.reg, pixel.reg); break;
848 case GGL_NAND: AND(AL, 0, pixel.reg, s.reg, d.reg);
849 MVN(AL, 0, pixel.reg, pixel.reg); break;
850 case GGL_SET: MVN(AL, 0, pixel.reg, imm(0)); break;
851 };
852 }
853
854 // ---------------------------------------------------------------------------
855
856 static uint32_t find_bottom(uint32_t val)
857 {
858 uint32_t i = 0;
859 while (!(val & (3<<i)))
860 i+= 2;
861 return i;
862 }
863
864 static void normalize(uint32_t& val, uint32_t& rot)
865 {
866 rot = 0;
867 while (!(val&3) || (val & 0xFC000000)) {
868 uint32_t newval;
869 newval = val >> 2;
870 newval |= (val&3) << 30;
871 val = newval;
872 rot += 2;
873 if (rot == 32) {
874 rot = 0;
875 break;
876 }
877 }
878 }
879
880 void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits)
881 {
882 uint32_t rot;
883 uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
884 mask &= size;
885
886 if (mask == size) {
887 if (d != s)
888 MOV( AL, 0, d, s);
889 return;
890 }
891
892 int negative_logic = !isValidImmediate(mask);
893 if (negative_logic) {
894 mask = ~mask & size;
895 }
896 normalize(mask, rot);
897
898 if (mask) {
899 while (mask) {
900 uint32_t bitpos = find_bottom(mask);
901 int shift = rot + bitpos;
902 uint32_t m = mask & (0xff << bitpos);
903 mask &= ~m;
904 m >>= bitpos;
905 int32_t newMask = (m<<shift) | (m>>(32-shift));
906 if (!negative_logic) {
907 AND( AL, 0, d, s, imm(newMask) );
908 } else {
909 BIC( AL, 0, d, s, imm(newMask) );
910 }
911 s = d;
912 }
913 } else {
914 MOV( AL, 0, d, imm(0));
915 }
916 }
917
918 void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
919 {
920 if (!mMasking || mAllMasked) {
921 return;
922 }
923
924 comment("color mask");
925
926 pixel_t fb(mDstPixel);
927 pixel_t s(pixel);
928 if (!(pixel.flags & CORRUPTIBLE)) {
929 pixel.reg = regs.obtain();
930 pixel.flags |= CORRUPTIBLE;
931 }
932
933 int mask = 0;
934 for (int i=0 ; i<4 ; i++) {
935 const int component_mask = 1<<i;
936 const int h = fb.format.c[i].h;
937 const int l = fb.format.c[i].l;
938 if (h && (!(mMasking & component_mask))) {
939 mask |= ((1<<(h-l))-1) << l;
940 }
941 }
942
943 // There is no need to clear the masked components of the source
944 // (unless we applied a logic op), because they're already zeroed
945 // by construction (masked components are not computed)
946
947 if (mLogicOp) {
948 const needs_t& needs = mBuilderContext.needs;
949 const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
950 if (opcode != GGL_CLEAR) {
951 // clear masked component of source
952 build_and_immediate(pixel.reg, s.reg, mask, fb.size());
953 s = pixel;
954 }
955 }
956
957 // clear non masked components of destination
958 build_and_immediate(fb.reg, fb.reg, ~mask, fb.size());
959
960 // or back the channels that were masked
961 if (s.reg == fb.reg) {
962 // this is in fact a MOV
963 if (s.reg == pixel.reg) {
964 // ugh. this in in fact a nop
965 } else {
966 MOV(AL, 0, pixel.reg, fb.reg);
967 }
968 } else {
969 ORR(AL, 0, pixel.reg, s.reg, fb.reg);
970 }
971 }
972
973 // ---------------------------------------------------------------------------
974
975 void GGLAssembler::base_offset(
976 const pointer_t& d, const pointer_t& b, const reg_t& o)
977 {
978 switch (b.size) {
979 case 32:
980 ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 2));
981 break;
982 case 24:
983 if (d.reg == b.reg) {
984 ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
985 ADD(AL, 0, d.reg, d.reg, o.reg);
986 } else {
987 ADD(AL, 0, d.reg, o.reg, reg_imm(o.reg, LSL, 1));
988 ADD(AL, 0, d.reg, d.reg, b.reg);
989 }
990 break;
991 case 16:
992 ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
993 break;
994 case 8:
995 ADD(AL, 0, d.reg, b.reg, o.reg);
996 break;
997 }
998 }
999
1000 // ----------------------------------------------------------------------------
1001 // cheezy register allocator...
1002 // ----------------------------------------------------------------------------
1003
1004 void RegisterAllocator::reset()
1005 {
1006 mRegs.reset();
1007 }
1008
1009 int RegisterAllocator::reserveReg(int reg)
1010 {
1011 return mRegs.reserve(reg);
1012 }
1013
1014 int RegisterAllocator::obtainReg()
1015 {
1016 return mRegs.obtain();
1017 }
1018
1019 void RegisterAllocator::recycleReg(int reg)
1020 {
1021 mRegs.recycle(reg);
1022 }
1023
1024 RegisterAllocator::RegisterFile& RegisterAllocator::registerFile()
1025 {
1026 return mRegs;
1027 }
1028
1029 // ----------------------------------------------------------------------------
1030
1031 RegisterAllocator::RegisterFile::RegisterFile()
1032 : mRegs(0), mTouched(0), mStatus(0)
1033 {
1034 reserve(ARMAssemblerInterface::SP);
1035 reserve(ARMAssemblerInterface::PC);
1036 }
1037
1038 RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs)
1039 : mRegs(rhs.mRegs), mTouched(rhs.mTouched)
1040 {
1041 }
1042
1043 RegisterAllocator::RegisterFile::~RegisterFile()
1044 {
1045 }
1046
1047 bool RegisterAllocator::RegisterFile::operator == (const RegisterFile& rhs) const
1048 {
1049 return (mRegs == rhs.mRegs);
1050 }
1051
1052 void RegisterAllocator::RegisterFile::reset()
1053 {
1054 mRegs = mTouched = mStatus = 0;
1055 reserve(ARMAssemblerInterface::SP);
1056 reserve(ARMAssemblerInterface::PC);
1057 }
1058
1059 int RegisterAllocator::RegisterFile::reserve(int reg)
1060 {
1061 LOG_ALWAYS_FATAL_IF(isUsed(reg),
1062 "reserving register %d, but already in use",
1063 reg);
1064 mRegs |= (1<<reg);
1065 mTouched |= mRegs;
1066 return reg;
1067 }
1068
1069 void RegisterAllocator::RegisterFile::reserveSeveral(uint32_t regMask)
1070 {
1071 mRegs |= regMask;
1072 mTouched |= regMask;
1073 }
1074
1075 int RegisterAllocator::RegisterFile::isUsed(int reg) const
1076 {
1077 LOG_ALWAYS_FATAL_IF(reg>=16, "invalid register %d", reg);
1078 return mRegs & (1<<reg);
1079 }
1080
1081 int RegisterAllocator::RegisterFile::obtain()
1082 {
1083 const char priorityList[14] = { 0, 1, 2, 3,
1084 12, 14, 4, 5,
1085 6, 7, 8, 9,
1086 10, 11 };
1087 const int nbreg = sizeof(priorityList);
1088 int i, r;
1089 for (i=0 ; i<nbreg ; i++) {
1090 r = priorityList[i];
1091 if (!isUsed(r)) {
1092 break;
1093 }
1094 }
1095 // this is not an error anymore because, we'll try again with
1096 // a lower optimization level.
1097 //LOGE_IF(i >= nbreg, "pixelflinger ran out of registers\n");
1098 if (i >= nbreg) {
1099 mStatus |= OUT_OF_REGISTERS;
1100 // we return SP so we can more easily debug things
1101 // the code will never be run anyway.
1102 return ARMAssemblerInterface::SP;
1103 }
1104 reserve(r);
1105 return r;
1106 }
1107
1108 bool RegisterAllocator::RegisterFile::hasFreeRegs() const
1109 {
1110 return ((mRegs & 0xFFFF) == 0xFFFF) ? false : true;
1111 }
1112
1113 int RegisterAllocator::RegisterFile::countFreeRegs() const
1114 {
1115 int f = ~mRegs & 0xFFFF;
1116 // now count number of 1
1117 f = (f & 0x5555) + ((f>>1) & 0x5555);
1118 f = (f & 0x3333) + ((f>>2) & 0x3333);
1119 f = (f & 0x0F0F) + ((f>>4) & 0x0F0F);
1120 f = (f & 0x00FF) + ((f>>8) & 0x00FF);
1121 return f;
1122 }
1123
1124 void RegisterAllocator::RegisterFile::recycle(int reg)
1125 {
1126 LOG_FATAL_IF(!isUsed(reg),
1127 "recycling unallocated register %d",
1128 reg);
1129 mRegs &= ~(1<<reg);
1130 }
1131
1132 void RegisterAllocator::RegisterFile::recycleSeveral(uint32_t regMask)
1133 {
1134 LOG_FATAL_IF((mRegs & regMask)!=regMask,
1135 "recycling unallocated registers "
1136 "(recycle=%08x, allocated=%08x, unallocated=%08x)",
1137 regMask, mRegs, mRegs&regMask);
1138 mRegs &= ~regMask;
1139 }
1140
1141 uint32_t RegisterAllocator::RegisterFile::touched() const
1142 {
1143 return mTouched;
1144 }
1145
1146 // ----------------------------------------------------------------------------
1147
1148 }; // namespace android
1149
+0
-554
libpixelflinger/codeflinger/GGLAssembler.h less more
0 /* libs/pixelflinger/codeflinger/GGLAssembler.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_GGLASSEMBLER_H
19 #define ANDROID_GGLASSEMBLER_H
20
21 #include <stdint.h>
22 #include <sys/types.h>
23
24 #include <private/pixelflinger/ggl_context.h>
25
26 #include "codeflinger/ARMAssemblerProxy.h"
27
28
29 namespace android {
30
31 // ----------------------------------------------------------------------------
32
33 #define CONTEXT_LOAD(REG, FIELD) \
34 LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
35
36 #define CONTEXT_STORE(REG, FIELD) \
37 STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
38
39
40 class RegisterAllocator
41 {
42 public:
43 class RegisterFile;
44
45 RegisterFile& registerFile();
46 int reserveReg(int reg);
47 int obtainReg();
48 void recycleReg(int reg);
49 void reset();
50
51 class RegisterFile
52 {
53 public:
54 RegisterFile();
55 RegisterFile(const RegisterFile& rhs);
56 ~RegisterFile();
57
58 void reset();
59
60 bool operator == (const RegisterFile& rhs) const;
61 bool operator != (const RegisterFile& rhs) const {
62 return !operator == (rhs);
63 }
64
65 int reserve(int reg);
66 void reserveSeveral(uint32_t regMask);
67
68 void recycle(int reg);
69 void recycleSeveral(uint32_t regMask);
70
71 int obtain();
72 inline int isUsed(int reg) const;
73
74 bool hasFreeRegs() const;
75 int countFreeRegs() const;
76
77 uint32_t touched() const;
78 inline uint32_t status() const { return mStatus; }
79
80 enum {
81 OUT_OF_REGISTERS = 0x1
82 };
83
84 private:
85 uint32_t mRegs;
86 uint32_t mTouched;
87 uint32_t mStatus;
88 };
89
90 class Scratch
91 {
92 public:
93 Scratch(RegisterFile& regFile)
94 : mRegFile(regFile), mScratch(0) {
95 }
96 ~Scratch() {
97 mRegFile.recycleSeveral(mScratch);
98 }
99 int obtain() {
100 int reg = mRegFile.obtain();
101 mScratch |= 1<<reg;
102 return reg;
103 }
104 void recycle(int reg) {
105 mRegFile.recycle(reg);
106 mScratch &= ~(1<<reg);
107 }
108 bool isUsed(int reg) {
109 return (mScratch & (1<<reg));
110 }
111 int countFreeRegs() {
112 return mRegFile.countFreeRegs();
113 }
114 private:
115 RegisterFile& mRegFile;
116 uint32_t mScratch;
117 };
118
119 class Spill
120 {
121 public:
122 Spill(RegisterFile& regFile, ARMAssemblerInterface& gen, uint32_t reglist)
123 : mRegFile(regFile), mGen(gen), mRegList(reglist), mCount(0)
124 {
125 if (reglist) {
126 int count = 0;
127 while (reglist) {
128 count++;
129 reglist &= ~(1 << (31 - __builtin_clz(reglist)));
130 }
131 if (count == 1) {
132 int reg = 31 - __builtin_clz(mRegList);
133 mGen.STR(mGen.AL, reg, mGen.SP, mGen.immed12_pre(-4, 1));
134 } else {
135 mGen.STM(mGen.AL, mGen.DB, mGen.SP, 1, mRegList);
136 }
137 mRegFile.recycleSeveral(mRegList);
138 mCount = count;
139 }
140 }
141 ~Spill() {
142 if (mRegList) {
143 if (mCount == 1) {
144 int reg = 31 - __builtin_clz(mRegList);
145 mGen.LDR(mGen.AL, reg, mGen.SP, mGen.immed12_post(4));
146 } else {
147 mGen.LDM(mGen.AL, mGen.IA, mGen.SP, 1, mRegList);
148 }
149 mRegFile.reserveSeveral(mRegList);
150 }
151 }
152 private:
153 RegisterFile& mRegFile;
154 ARMAssemblerInterface& mGen;
155 uint32_t mRegList;
156 int mCount;
157 };
158
159 private:
160 RegisterFile mRegs;
161 };
162
163 // ----------------------------------------------------------------------------
164
165 class GGLAssembler : public ARMAssemblerProxy, public RegisterAllocator
166 {
167 public:
168
169 GGLAssembler(ARMAssemblerInterface* target);
170 virtual ~GGLAssembler();
171
172 uint32_t* base() const { return 0; } // XXX
173 uint32_t* pc() const { return 0; } // XXX
174
175 void reset(int opt_level);
176
177 virtual void prolog();
178 virtual void epilog(uint32_t touched);
179
180 // generate scanline code for given needs
181 int scanline(const needs_t& needs, context_t const* c);
182 int scanline_core(const needs_t& needs, context_t const* c);
183
184 enum {
185 CLEAR_LO = 0x0001,
186 CLEAR_HI = 0x0002,
187 CORRUPTIBLE = 0x0004,
188 FIRST = 0x0008
189 };
190
191 enum { //load/store flags
192 WRITE_BACK = 0x0001
193 };
194
195 struct reg_t {
196 reg_t() : reg(-1), flags(0) {
197 }
198 reg_t(int r, int f=0)
199 : reg(r), flags(f) {
200 }
201 void setTo(int r, int f=0) {
202 reg=r; flags=f;
203 }
204 int reg;
205 uint16_t flags;
206 };
207
208 struct integer_t : public reg_t {
209 integer_t() : reg_t(), s(0) {
210 }
211 integer_t(int r, int sz=32, int f=0)
212 : reg_t(r, f), s(sz) {
213 }
214 void setTo(int r, int sz=32, int f=0) {
215 reg_t::setTo(r, f); s=sz;
216 }
217 int8_t s;
218 inline int size() const { return s; }
219 };
220
221 struct pixel_t : public reg_t {
222 pixel_t() : reg_t() {
223 memset(&format, 0, sizeof(GGLFormat));
224 }
225 pixel_t(int r, const GGLFormat* fmt, int f=0)
226 : reg_t(r, f), format(*fmt) {
227 }
228 void setTo(int r, const GGLFormat* fmt, int f=0) {
229 reg_t::setTo(r, f); format = *fmt;
230 }
231 GGLFormat format;
232 inline int hi(int c) const { return format.c[c].h; }
233 inline int low(int c) const { return format.c[c].l; }
234 inline int mask(int c) const { return ((1<<size(c))-1) << low(c); }
235 inline int size() const { return format.size*8; }
236 inline int size(int c) const { return component_size(c); }
237 inline int component_size(int c) const { return hi(c) - low(c); }
238 };
239
240 struct component_t : public reg_t {
241 component_t() : reg_t(), h(0), l(0) {
242 }
243 component_t(int r, int f=0)
244 : reg_t(r, f), h(0), l(0) {
245 }
246 component_t(int r, int lo, int hi, int f=0)
247 : reg_t(r, f), h(hi), l(lo) {
248 }
249 explicit component_t(const integer_t& rhs)
250 : reg_t(rhs.reg, rhs.flags), h(rhs.s), l(0) {
251 }
252 explicit component_t(const pixel_t& rhs, int component) {
253 setTo( rhs.reg,
254 rhs.format.c[component].l,
255 rhs.format.c[component].h,
256 rhs.flags|CLEAR_LO|CLEAR_HI);
257 }
258 void setTo(int r, int lo=0, int hi=0, int f=0) {
259 reg_t::setTo(r, f); h=hi; l=lo;
260 }
261 int8_t h;
262 int8_t l;
263 inline int size() const { return h-l; }
264 };
265
266 struct pointer_t : public reg_t {
267 pointer_t() : reg_t(), size(0) {
268 }
269 pointer_t(int r, int s, int f=0)
270 : reg_t(r, f), size(s) {
271 }
272 void setTo(int r, int s, int f=0) {
273 reg_t::setTo(r, f); size=s;
274 }
275 int8_t size;
276 };
277
278
279 private:
280 struct tex_coord_t {
281 reg_t s;
282 reg_t t;
283 pointer_t ptr;
284 };
285
286 struct fragment_parts_t {
287 uint32_t packed : 1;
288 uint32_t reload : 2;
289 uint32_t iterated_packed : 1;
290 pixel_t iterated;
291 pointer_t cbPtr;
292 pointer_t covPtr;
293 reg_t count;
294 reg_t argb[4];
295 reg_t argb_dx[4];
296 reg_t z;
297 reg_t dither;
298 pixel_t texel[GGL_TEXTURE_UNIT_COUNT];
299 tex_coord_t coords[GGL_TEXTURE_UNIT_COUNT];
300 };
301
302 struct texture_unit_t {
303 int format_idx;
304 GGLFormat format;
305 int bits;
306 int swrap;
307 int twrap;
308 int env;
309 int pot;
310 int linear;
311 uint8_t mask;
312 uint8_t replaced;
313 };
314
315 struct texture_machine_t {
316 texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT];
317 uint8_t mask;
318 uint8_t replaced;
319 uint8_t directTexture;
320 uint8_t activeUnits;
321 };
322
323 struct component_info_t {
324 bool masked : 1;
325 bool inDest : 1;
326 bool needed : 1;
327 bool replaced : 1;
328 bool iterated : 1;
329 bool smooth : 1;
330 bool blend : 1;
331 bool fog : 1;
332 };
333
334 struct builder_context_t {
335 context_t const* c;
336 needs_t needs;
337 int Rctx;
338 };
339
340 template <typename T>
341 void modify(T& r, Scratch& regs)
342 {
343 if (!(r.flags & CORRUPTIBLE)) {
344 r.reg = regs.obtain();
345 r.flags |= CORRUPTIBLE;
346 }
347 }
348
349 // helpers
350 void base_offset(const pointer_t& d, const pointer_t& b, const reg_t& o);
351
352 // texture environement
353 void modulate( component_t& dest,
354 const component_t& incoming,
355 const pixel_t& texel, int component);
356
357 void decal( component_t& dest,
358 const component_t& incoming,
359 const pixel_t& texel, int component);
360
361 void blend( component_t& dest,
362 const component_t& incoming,
363 const pixel_t& texel, int component, int tmu);
364
365 void add( component_t& dest,
366 const component_t& incoming,
367 const pixel_t& texel, int component);
368
369 // load/store stuff
370 void store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
371 void load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
372 void extract(integer_t& d, const pixel_t& s, int component);
373 void extract(component_t& d, const pixel_t& s, int component);
374 void extract(integer_t& d, int s, int h, int l, int bits=32);
375 void expand(integer_t& d, const integer_t& s, int dbits);
376 void expand(integer_t& d, const component_t& s, int dbits);
377 void expand(component_t& d, const component_t& s, int dbits);
378 void downshift(pixel_t& d, int component, component_t s, const reg_t& dither);
379
380
381 void mul_factor( component_t& d,
382 const integer_t& v,
383 const integer_t& f);
384
385 void mul_factor_add( component_t& d,
386 const integer_t& v,
387 const integer_t& f,
388 const component_t& a);
389
390 void component_add( component_t& d,
391 const integer_t& dst,
392 const integer_t& src);
393
394 void component_sat( const component_t& v);
395
396
397 void build_scanline_prolog( fragment_parts_t& parts,
398 const needs_t& needs);
399
400 void build_smooth_shade(const fragment_parts_t& parts);
401
402 void build_component( pixel_t& pixel,
403 const fragment_parts_t& parts,
404 int component,
405 Scratch& global_scratches);
406
407 void build_incoming_component(
408 component_t& temp,
409 int dst_size,
410 const fragment_parts_t& parts,
411 int component,
412 Scratch& scratches,
413 Scratch& global_scratches);
414
415 void init_iterated_color(fragment_parts_t& parts, const reg_t& x);
416
417 void build_iterated_color( component_t& fragment,
418 const fragment_parts_t& parts,
419 int component,
420 Scratch& regs);
421
422 void decodeLogicOpNeeds(const needs_t& needs);
423
424 void decodeTMUNeeds(const needs_t& needs, context_t const* c);
425
426 void init_textures( tex_coord_t* coords,
427 const reg_t& x,
428 const reg_t& y);
429
430 void build_textures( fragment_parts_t& parts,
431 Scratch& regs);
432
433 void filter8( const fragment_parts_t& parts,
434 pixel_t& texel, const texture_unit_t& tmu,
435 int U, int V, pointer_t& txPtr,
436 int FRAC_BITS);
437
438 void filter16( const fragment_parts_t& parts,
439 pixel_t& texel, const texture_unit_t& tmu,
440 int U, int V, pointer_t& txPtr,
441 int FRAC_BITS);
442
443 void filter24( const fragment_parts_t& parts,
444 pixel_t& texel, const texture_unit_t& tmu,
445 int U, int V, pointer_t& txPtr,
446 int FRAC_BITS);
447
448 void filter32( const fragment_parts_t& parts,
449 pixel_t& texel, const texture_unit_t& tmu,
450 int U, int V, pointer_t& txPtr,
451 int FRAC_BITS);
452
453 void build_texture_environment( component_t& fragment,
454 const fragment_parts_t& parts,
455 int component,
456 Scratch& regs);
457
458 void wrapping( int d,
459 int coord, int size,
460 int tx_wrap, int tx_linear);
461
462 void build_fog( component_t& temp,
463 int component,
464 Scratch& parent_scratches);
465
466 void build_blending( component_t& in_out,
467 const pixel_t& pixel,
468 int component,
469 Scratch& parent_scratches);
470
471 void build_blend_factor(
472 integer_t& factor, int f, int component,
473 const pixel_t& dst_pixel,
474 integer_t& fragment,
475 integer_t& fb,
476 Scratch& scratches);
477
478 void build_blendFOneMinusF( component_t& temp,
479 const integer_t& factor,
480 const integer_t& fragment,
481 const integer_t& fb);
482
483 void build_blendOneMinusFF( component_t& temp,
484 const integer_t& factor,
485 const integer_t& fragment,
486 const integer_t& fb);
487
488 void build_coverage_application(component_t& fragment,
489 const fragment_parts_t& parts,
490 Scratch& regs);
491
492 void build_alpha_test(component_t& fragment, const fragment_parts_t& parts);
493
494 enum { Z_TEST=1, Z_WRITE=2 };
495 void build_depth_test(const fragment_parts_t& parts, uint32_t mask);
496 void build_iterate_z(const fragment_parts_t& parts);
497 void build_iterate_f(const fragment_parts_t& parts);
498 void build_iterate_texture_coordinates(const fragment_parts_t& parts);
499
500 void build_logic_op(pixel_t& pixel, Scratch& regs);
501
502 void build_masking(pixel_t& pixel, Scratch& regs);
503
504 void build_and_immediate(int d, int s, uint32_t mask, int bits);
505
506 bool isAlphaSourceNeeded() const;
507
508 enum {
509 FACTOR_SRC=1, FACTOR_DST=2, BLEND_SRC=4, BLEND_DST=8
510 };
511
512 enum {
513 LOGIC_OP=1, LOGIC_OP_SRC=2, LOGIC_OP_DST=4
514 };
515
516 static int blending_codes(int fs, int fd);
517
518 builder_context_t mBuilderContext;
519 texture_machine_t mTextureMachine;
520 component_info_t mInfo[4];
521 int mBlending;
522 int mMasking;
523 int mAllMasked;
524 int mLogicOp;
525 int mAlphaTest;
526 int mAA;
527 int mDithering;
528 int mDepthTest;
529
530 int mSmooth;
531 int mFog;
532 pixel_t mDstPixel;
533
534 GGLFormat mCbFormat;
535
536 int mBlendFactorCached;
537 integer_t mAlphaSource;
538
539 int mBaseRegister;
540
541 int mBlendSrc;
542 int mBlendDst;
543 int mBlendSrcA;
544 int mBlendDstA;
545
546 int mOptLevel;
547 };
548
549 // ----------------------------------------------------------------------------
550
551 }; // namespace android
552
553 #endif // ANDROID_GGLASSEMBLER_H
+0
-300
libpixelflinger/codeflinger/armreg.h less more
0 /* $NetBSD: armreg.h,v 1.28 2003/10/31 16:30:15 scw Exp $ */
1
2 /*-
3 * Copyright (c) 1998, 2001 Ben Harris
4 * Copyright (c) 1994-1996 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
6 * All rights reserved.
7 *
8 * This code is derived from software written for Brini by Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Brini.
21 * 4. The name of the company nor the name of the author may be used to
22 * endorse or promote products derived from this software without specific
23 * prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/armreg.h,v 1.3 2005/11/21 19:06:25 cognet Exp $
38 */
39
40 #ifndef MACHINE_ARMREG_H
41 #define MACHINE_ARMREG_H
42 #define INSN_SIZE 4
43 #define INSN_COND_MASK 0xf0000000 /* Condition mask */
44 #define PSR_MODE 0x0000001f /* mode mask */
45 #define PSR_USR26_MODE 0x00000000
46 #define PSR_FIQ26_MODE 0x00000001
47 #define PSR_IRQ26_MODE 0x00000002
48 #define PSR_SVC26_MODE 0x00000003
49 #define PSR_USR32_MODE 0x00000010
50 #define PSR_FIQ32_MODE 0x00000011
51 #define PSR_IRQ32_MODE 0x00000012
52 #define PSR_SVC32_MODE 0x00000013
53 #define PSR_ABT32_MODE 0x00000017
54 #define PSR_UND32_MODE 0x0000001b
55 #define PSR_SYS32_MODE 0x0000001f
56 #define PSR_32_MODE 0x00000010
57 #define PSR_FLAGS 0xf0000000 /* flags */
58
59 #define PSR_C_bit (1 << 29) /* carry */
60
61 /* The high-order byte is always the implementor */
62 #define CPU_ID_IMPLEMENTOR_MASK 0xff000000
63 #define CPU_ID_ARM_LTD 0x41000000 /* 'A' */
64 #define CPU_ID_DEC 0x44000000 /* 'D' */
65 #define CPU_ID_INTEL 0x69000000 /* 'i' */
66 #define CPU_ID_TI 0x54000000 /* 'T' */
67
68 /* How to decide what format the CPUID is in. */
69 #define CPU_ID_ISOLD(x) (((x) & 0x0000f000) == 0x00000000)
70 #define CPU_ID_IS7(x) (((x) & 0x0000f000) == 0x00007000)
71 #define CPU_ID_ISNEW(x) (!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x))
72
73 /* On ARM3 and ARM6, this byte holds the foundry ID. */
74 #define CPU_ID_FOUNDRY_MASK 0x00ff0000
75 #define CPU_ID_FOUNDRY_VLSI 0x00560000
76
77 /* On ARM7 it holds the architecture and variant (sub-model) */
78 #define CPU_ID_7ARCH_MASK 0x00800000
79 #define CPU_ID_7ARCH_V3 0x00000000
80 #define CPU_ID_7ARCH_V4T 0x00800000
81 #define CPU_ID_7VARIANT_MASK 0x007f0000
82
83 /* On more recent ARMs, it does the same, but in a different format */
84 #define CPU_ID_ARCH_MASK 0x000f0000
85 #define CPU_ID_ARCH_V3 0x00000000
86 #define CPU_ID_ARCH_V4 0x00010000
87 #define CPU_ID_ARCH_V4T 0x00020000
88 #define CPU_ID_ARCH_V5 0x00030000
89 #define CPU_ID_ARCH_V5T 0x00040000
90 #define CPU_ID_ARCH_V5TE 0x00050000
91 #define CPU_ID_VARIANT_MASK 0x00f00000
92
93 /* Next three nybbles are part number */
94 #define CPU_ID_PARTNO_MASK 0x0000fff0
95
96 /* Intel XScale has sub fields in part number */
97 #define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */
98 #define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */
99 #define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */
100
101 /* And finally, the revision number. */
102 #define CPU_ID_REVISION_MASK 0x0000000f
103
104 /* Individual CPUs are probably best IDed by everything but the revision. */
105 #define CPU_ID_CPU_MASK 0xfffffff0
106
107 /* Fake CPU IDs for ARMs without CP15 */
108 #define CPU_ID_ARM2 0x41560200
109 #define CPU_ID_ARM250 0x41560250
110
111 /* Pre-ARM7 CPUs -- [15:12] == 0 */
112 #define CPU_ID_ARM3 0x41560300
113 #define CPU_ID_ARM600 0x41560600
114 #define CPU_ID_ARM610 0x41560610
115 #define CPU_ID_ARM620 0x41560620
116
117 /* ARM7 CPUs -- [15:12] == 7 */
118 #define CPU_ID_ARM700 0x41007000 /* XXX This is a guess. */
119 #define CPU_ID_ARM710 0x41007100
120 #define CPU_ID_ARM7500 0x41027100 /* XXX This is a guess. */
121 #define CPU_ID_ARM710A 0x41047100 /* inc ARM7100 */
122 #define CPU_ID_ARM7500FE 0x41077100
123 #define CPU_ID_ARM710T 0x41807100
124 #define CPU_ID_ARM720T 0x41807200
125 #define CPU_ID_ARM740T8K 0x41807400 /* XXX no MMU, 8KB cache */
126 #define CPU_ID_ARM740T4K 0x41817400 /* XXX no MMU, 4KB cache */
127
128 /* Post-ARM7 CPUs */
129 #define CPU_ID_ARM810 0x41018100
130 #define CPU_ID_ARM920T 0x41129200
131 #define CPU_ID_ARM920T_ALT 0x41009200
132 #define CPU_ID_ARM922T 0x41029220
133 #define CPU_ID_ARM940T 0x41029400 /* XXX no MMU */
134 #define CPU_ID_ARM946ES 0x41049460 /* XXX no MMU */
135 #define CPU_ID_ARM966ES 0x41049660 /* XXX no MMU */
136 #define CPU_ID_ARM966ESR1 0x41059660 /* XXX no MMU */
137 #define CPU_ID_ARM1020E 0x4115a200 /* (AKA arm10 rev 1) */
138 #define CPU_ID_ARM1022ES 0x4105a220
139 #define CPU_ID_SA110 0x4401a100
140 #define CPU_ID_SA1100 0x4401a110
141 #define CPU_ID_TI925T 0x54029250
142 #define CPU_ID_SA1110 0x6901b110
143 #define CPU_ID_IXP1200 0x6901c120
144 #define CPU_ID_80200 0x69052000
145 #define CPU_ID_PXA250 0x69052100 /* sans core revision */
146 #define CPU_ID_PXA210 0x69052120
147 #define CPU_ID_PXA250A 0x69052100 /* 1st version Core */
148 #define CPU_ID_PXA210A 0x69052120 /* 1st version Core */
149 #define CPU_ID_PXA250B 0x69052900 /* 3rd version Core */
150 #define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */
151 #define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */
152 #define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */
153 #define CPU_ID_80321_400 0x69052420
154 #define CPU_ID_80321_600 0x69052430
155 #define CPU_ID_80321_400_B0 0x69052c20
156 #define CPU_ID_80321_600_B0 0x69052c30
157 #define CPU_ID_IXP425_533 0x690541c0
158 #define CPU_ID_IXP425_400 0x690541d0
159 #define CPU_ID_IXP425_266 0x690541f0
160
161 /* ARM3-specific coprocessor 15 registers */
162 #define ARM3_CP15_FLUSH 1
163 #define ARM3_CP15_CONTROL 2
164 #define ARM3_CP15_CACHEABLE 3
165 #define ARM3_CP15_UPDATEABLE 4
166 #define ARM3_CP15_DISRUPTIVE 5
167
168 /* ARM3 Control register bits */
169 #define ARM3_CTL_CACHE_ON 0x00000001
170 #define ARM3_CTL_SHARED 0x00000002
171 #define ARM3_CTL_MONITOR 0x00000004
172
173 /*
174 * Post-ARM3 CP15 registers:
175 *
176 * 1 Control register
177 *
178 * 2 Translation Table Base
179 *
180 * 3 Domain Access Control
181 *
182 * 4 Reserved
183 *
184 * 5 Fault Status
185 *
186 * 6 Fault Address
187 *
188 * 7 Cache/write-buffer Control
189 *
190 * 8 TLB Control
191 *
192 * 9 Cache Lockdown
193 *
194 * 10 TLB Lockdown
195 *
196 * 11 Reserved
197 *
198 * 12 Reserved
199 *
200 * 13 Process ID (for FCSE)
201 *
202 * 14 Reserved
203 *
204 * 15 Implementation Dependent
205 */
206
207 /* Some of the definitions below need cleaning up for V3/V4 architectures */
208
209 /* CPU control register (CP15 register 1) */
210 #define CPU_CONTROL_MMU_ENABLE 0x00000001 /* M: MMU/Protection unit enable */
211 #define CPU_CONTROL_AFLT_ENABLE 0x00000002 /* A: Alignment fault enable */
212 #define CPU_CONTROL_DC_ENABLE 0x00000004 /* C: IDC/DC enable */
213 #define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */
214 #define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */
215 #define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */
216 #define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */
217 #define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */
218 #define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */
219 #define CPU_CONTROL_ROM_ENABLE 0x00000200 /* R: ROM protection bit */
220 #define CPU_CONTROL_CPCLK 0x00000400 /* F: Implementation defined */
221 #define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */
222 #define CPU_CONTROL_IC_ENABLE 0x00001000 /* I: IC enable */
223 #define CPU_CONTROL_VECRELOC 0x00002000 /* V: Vector relocation */
224 #define CPU_CONTROL_ROUNDROBIN 0x00004000 /* RR: Predictable replacement */
225 #define CPU_CONTROL_V4COMPAT 0x00008000 /* L4: ARMv4 compat LDR R15 etc */
226
227 #define CPU_CONTROL_IDC_ENABLE CPU_CONTROL_DC_ENABLE
228
229 /* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */
230 #define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */
231 #define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */
232 #define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */
233 #define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */
234 #define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */
235 #define XSCALE_AUXCTL_MD_MASK 0x00000030
236
237 /* Cache type register definitions */
238 #define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */
239 #define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */
240 #define CPU_CT_S (1U << 24) /* split cache */
241 #define CPU_CT_CTYPE(x) (((x) >> 25) & 0xf) /* cache type */
242
243 #define CPU_CT_CTYPE_WT 0 /* write-through */
244 #define CPU_CT_CTYPE_WB1 1 /* write-back, clean w/ read */
245 #define CPU_CT_CTYPE_WB2 2 /* w/b, clean w/ cp15,7 */
246 #define CPU_CT_CTYPE_WB6 6 /* w/b, cp15,7, lockdown fmt A */
247 #define CPU_CT_CTYPE_WB7 7 /* w/b, cp15,7, lockdown fmt B */
248
249 #define CPU_CT_xSIZE_LEN(x) ((x) & 0x3) /* line size */
250 #define CPU_CT_xSIZE_M (1U << 2) /* multiplier */
251 #define CPU_CT_xSIZE_ASSOC(x) (((x) >> 3) & 0x7) /* associativity */
252 #define CPU_CT_xSIZE_SIZE(x) (((x) >> 6) & 0x7) /* size */
253
254 /* Fault status register definitions */
255
256 #define FAULT_TYPE_MASK 0x0f
257 #define FAULT_USER 0x10
258
259 #define FAULT_WRTBUF_0 0x00 /* Vector Exception */
260 #define FAULT_WRTBUF_1 0x02 /* Terminal Exception */
261 #define FAULT_BUSERR_0 0x04 /* External Abort on Linefetch -- Section */
262 #define FAULT_BUSERR_1 0x06 /* External Abort on Linefetch -- Page */
263 #define FAULT_BUSERR_2 0x08 /* External Abort on Non-linefetch -- Section */
264 #define FAULT_BUSERR_3 0x0a /* External Abort on Non-linefetch -- Page */
265 #define FAULT_BUSTRNL1 0x0c /* External abort on Translation -- Level 1 */
266 #define FAULT_BUSTRNL2 0x0e /* External abort on Translation -- Level 2 */
267 #define FAULT_ALIGN_0 0x01 /* Alignment */
268 #define FAULT_ALIGN_1 0x03 /* Alignment */
269 #define FAULT_TRANS_S 0x05 /* Translation -- Section */
270 #define FAULT_TRANS_P 0x07 /* Translation -- Page */
271 #define FAULT_DOMAIN_S 0x09 /* Domain -- Section */
272 #define FAULT_DOMAIN_P 0x0b /* Domain -- Page */
273 #define FAULT_PERM_S 0x0d /* Permission -- Section */
274 #define FAULT_PERM_P 0x0f /* Permission -- Page */
275
276 #define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */
277
278 /*
279 * Address of the vector page, low and high versions.
280 */
281 #define ARM_VECTORS_LOW 0x00000000U
282 #define ARM_VECTORS_HIGH 0xffff0000U
283
284 /*
285 * ARM Instructions
286 *
287 * 3 3 2 2 2
288 * 1 0 9 8 7 0
289 * +-------+-------------------------------------------------------+
290 * | cond | instruction dependant |
291 * |c c c c| |
292 * +-------+-------------------------------------------------------+
293 */
294
295 #define INSN_SIZE 4 /* Always 4 bytes */
296 #define INSN_COND_MASK 0xf0000000 /* Condition mask */
297 #define INSN_COND_AL 0xe0000000 /* Always condition */
298
299 #endif /* !MACHINE_ARMREG_H */
+0
-682
libpixelflinger/codeflinger/blending.cpp less more
0 /* libs/pixelflinger/codeflinger/blending.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22
23 #include <cutils/log.h>
24
25 #include "codeflinger/GGLAssembler.h"
26
27
28 namespace android {
29
30 void GGLAssembler::build_fog(
31 component_t& temp, // incomming fragment / output
32 int component,
33 Scratch& regs)
34 {
35 if (mInfo[component].fog) {
36 Scratch scratches(registerFile());
37 comment("fog");
38
39 integer_t fragment(temp.reg, temp.h, temp.flags);
40 if (!(temp.flags & CORRUPTIBLE)) {
41 temp.reg = regs.obtain();
42 temp.flags |= CORRUPTIBLE;
43 }
44
45 integer_t fogColor(scratches.obtain(), 8, CORRUPTIBLE);
46 LDRB(AL, fogColor.reg, mBuilderContext.Rctx,
47 immed12_pre(GGL_OFFSETOF(state.fog.color[component])));
48
49 integer_t factor(scratches.obtain(), 16, CORRUPTIBLE);
50 CONTEXT_LOAD(factor.reg, generated_vars.f);
51
52 // clamp fog factor (TODO: see if there is a way to guarantee
53 // we won't overflow, when setting the iterators)
54 BIC(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, ASR, 31));
55 CMP(AL, factor.reg, imm( 0x10000 ));
56 MOV(HS, 0, factor.reg, imm( 0x10000 ));
57
58 build_blendFOneMinusF(temp, factor, fragment, fogColor);
59 }
60 }
61
62 void GGLAssembler::build_blending(
63 component_t& temp, // incomming fragment / output
64 const pixel_t& pixel, // framebuffer
65 int component,
66 Scratch& regs)
67 {
68 if (!mInfo[component].blend)
69 return;
70
71 int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
72 int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
73 if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA)
74 fs = GGL_ONE;
75 const int blending = blending_codes(fs, fd);
76 if (!temp.size()) {
77 // here, blending will produce something which doesn't depend on
78 // that component (eg: GL_ZERO:GL_*), so the register has not been
79 // allocated yet. Will never be used as a source.
80 temp = component_t(regs.obtain(), CORRUPTIBLE);
81 }
82
83 // we are doing real blending...
84 // fb: extracted dst
85 // fragment: extracted src
86 // temp: component_t(fragment) and result
87
88 // scoped register allocator
89 Scratch scratches(registerFile());
90 comment("blending");
91
92 // we can optimize these cases a bit...
93 // (1) saturation is not needed
94 // (2) we can use only one multiply instead of 2
95 // (3) we can reduce the register pressure
96 // R = S*f + D*(1-f) = (S-D)*f + D
97 // R = S*(1-f) + D*f = (D-S)*f + S
98
99 const bool same_factor_opt1 =
100 (fs==GGL_DST_COLOR && fd==GGL_ONE_MINUS_DST_COLOR) ||
101 (fs==GGL_SRC_COLOR && fd==GGL_ONE_MINUS_SRC_COLOR) ||
102 (fs==GGL_DST_ALPHA && fd==GGL_ONE_MINUS_DST_ALPHA) ||
103 (fs==GGL_SRC_ALPHA && fd==GGL_ONE_MINUS_SRC_ALPHA);
104
105 const bool same_factor_opt2 =
106 (fs==GGL_ONE_MINUS_DST_COLOR && fd==GGL_DST_COLOR) ||
107 (fs==GGL_ONE_MINUS_SRC_COLOR && fd==GGL_SRC_COLOR) ||
108 (fs==GGL_ONE_MINUS_DST_ALPHA && fd==GGL_DST_ALPHA) ||
109 (fs==GGL_ONE_MINUS_SRC_ALPHA && fd==GGL_SRC_ALPHA);
110
111
112 // XXX: we could also optimize these cases:
113 // R = S*f + D*f = (S+D)*f
114 // R = S*(1-f) + D*(1-f) = (S+D)*(1-f)
115 // R = S*D + D*S = 2*S*D
116
117
118 // see if we need to extract 'component' from the destination (fb)
119 integer_t fb;
120 if (blending & (BLEND_DST|FACTOR_DST)) {
121 fb.setTo(scratches.obtain(), 32);
122 extract(fb, pixel, component);
123 if (mDithering) {
124 // XXX: maybe what we should do instead, is simply
125 // expand fb -or- fragment to the larger of the two
126 if (fb.size() < temp.size()) {
127 // for now we expand 'fb' to min(fragment, 8)
128 int new_size = temp.size() < 8 ? temp.size() : 8;
129 expand(fb, fb, new_size);
130 }
131 }
132 }
133
134
135 // convert input fragment to integer_t
136 if (temp.l && (temp.flags & CORRUPTIBLE)) {
137 MOV(AL, 0, temp.reg, reg_imm(temp.reg, LSR, temp.l));
138 temp.h -= temp.l;
139 temp.l = 0;
140 }
141 integer_t fragment(temp.reg, temp.size(), temp.flags);
142
143 // if not done yet, convert input fragment to integer_t
144 if (temp.l) {
145 // here we know temp is not CORRUPTIBLE
146 fragment.reg = scratches.obtain();
147 MOV(AL, 0, fragment.reg, reg_imm(temp.reg, LSR, temp.l));
148 fragment.flags |= CORRUPTIBLE;
149 }
150
151 if (!(temp.flags & CORRUPTIBLE)) {
152 // temp is not corruptible, but since it's the destination it
153 // will be modified, so we need to allocate a new register.
154 temp.reg = regs.obtain();
155 temp.flags &= ~CORRUPTIBLE;
156 fragment.flags &= ~CORRUPTIBLE;
157 }
158
159 if ((blending & BLEND_SRC) && !same_factor_opt1) {
160 // source (fragment) is needed for the blending stage
161 // so it's not CORRUPTIBLE (unless we're doing same_factor_opt1)
162 fragment.flags &= ~CORRUPTIBLE;
163 }
164
165
166 if (same_factor_opt1) {
167 // R = S*f + D*(1-f) = (S-D)*f + D
168 integer_t factor;
169 build_blend_factor(factor, fs,
170 component, pixel, fragment, fb, scratches);
171 // fb is always corruptible from this point
172 fb.flags |= CORRUPTIBLE;
173 build_blendFOneMinusF(temp, factor, fragment, fb);
174 } else if (same_factor_opt2) {
175 // R = S*(1-f) + D*f = (D-S)*f + S
176 integer_t factor;
177 // fb is always corrruptible here
178 fb.flags |= CORRUPTIBLE;
179 build_blend_factor(factor, fd,
180 component, pixel, fragment, fb, scratches);
181 build_blendOneMinusFF(temp, factor, fragment, fb);
182 } else {
183 integer_t src_factor;
184 integer_t dst_factor;
185
186 // if destination (fb) is not needed for the blending stage,
187 // then it can be marked as CORRUPTIBLE
188 if (!(blending & BLEND_DST)) {
189 fb.flags |= CORRUPTIBLE;
190 }
191
192 // XXX: try to mark some registers as CORRUPTIBLE
193 // in most case we could make those corruptible
194 // when we're processing the last component
195 // but not always, for instance
196 // when fragment is constant and not reloaded
197 // when fb is needed for logic-ops or masking
198 // when a register is aliased (for instance with mAlphaSource)
199
200 // blend away...
201 if (fs==GGL_ZERO) {
202 if (fd==GGL_ZERO) { // R = 0
203 // already taken care of
204 } else if (fd==GGL_ONE) { // R = D
205 // already taken care of
206 } else { // R = D*fd
207 // compute fd
208 build_blend_factor(dst_factor, fd,
209 component, pixel, fragment, fb, scratches);
210 mul_factor(temp, fb, dst_factor);
211 }
212 } else if (fs==GGL_ONE) {
213 if (fd==GGL_ZERO) { // R = S
214 // NOP, taken care of
215 } else if (fd==GGL_ONE) { // R = S + D
216 component_add(temp, fb, fragment); // args order matters
217 component_sat(temp);
218 } else { // R = S + D*fd
219 // compute fd
220 build_blend_factor(dst_factor, fd,
221 component, pixel, fragment, fb, scratches);
222 mul_factor_add(temp, fb, dst_factor, component_t(fragment));
223 if (fd==GGL_ONE_MINUS_SRC_ALPHA) {
224 // XXX: in theory this is not correct, we should
225 // saturate here. However, this mode is often
226 // used for displaying alpha-premultiplied graphics,
227 // in which case, saturation is not necessary.
228 // unfortunatelly, we have no way to know.
229 // This is a case, where we sacrifice correctness for
230 // performance. we should probably have some heuristics.
231 } else {
232 component_sat(temp);
233 }
234 }
235 } else {
236 // compute fs
237 build_blend_factor(src_factor, fs,
238 component, pixel, fragment, fb, scratches);
239 if (fd==GGL_ZERO) { // R = S*fs
240 mul_factor(temp, fragment, src_factor);
241 } else if (fd==GGL_ONE) { // R = S*fs + D
242 mul_factor_add(temp, fragment, src_factor, component_t(fb));
243 component_sat(temp);
244 } else { // R = S*fs + D*fd
245 mul_factor(temp, fragment, src_factor);
246 if (scratches.isUsed(src_factor.reg))
247 scratches.recycle(src_factor.reg);
248 // compute fd
249 build_blend_factor(dst_factor, fd,
250 component, pixel, fragment, fb, scratches);
251 mul_factor_add(temp, fb, dst_factor, temp);
252 if (!same_factor_opt1 && !same_factor_opt2) {
253 component_sat(temp);
254 }
255 }
256 }
257 }
258
259 // now we can be corrupted (it's the dest)
260 temp.flags |= CORRUPTIBLE;
261 }
262
263 void GGLAssembler::build_blend_factor(
264 integer_t& factor, int f, int component,
265 const pixel_t& dst_pixel,
266 integer_t& fragment,
267 integer_t& fb,
268 Scratch& scratches)
269 {
270 integer_t src_alpha(fragment);
271
272 // src_factor/dst_factor won't be used after blending,
273 // so it's fine to mark them as CORRUPTIBLE (if not aliased)
274 factor.flags |= CORRUPTIBLE;
275
276 switch(f) {
277 case GGL_ONE_MINUS_SRC_ALPHA:
278 case GGL_SRC_ALPHA:
279 if (component==GGLFormat::ALPHA && !isAlphaSourceNeeded()) {
280 // we're processing alpha, so we already have
281 // src-alpha in fragment, and we need src-alpha just this time.
282 } else {
283 // alpha-src will be needed for other components
284 if (!mBlendFactorCached || mBlendFactorCached==f) {
285 src_alpha = mAlphaSource;
286 factor = mAlphaSource;
287 factor.flags &= ~CORRUPTIBLE;
288 // we already computed the blend factor before, nothing to do.
289 if (mBlendFactorCached)
290 return;
291 // this is the first time, make sure to compute the blend
292 // factor properly.
293 mBlendFactorCached = f;
294 break;
295 } else {
296 // we have a cached alpha blend factor, but we want another one,
297 // this should really not happen because by construction,
298 // we cannot have BOTH source and destination
299 // blend factors use ALPHA *and* ONE_MINUS_ALPHA (because
300 // the blending stage uses the f/(1-f) optimization
301
302 // for completeness, we handle this case though. Since there
303 // are only 2 choices, this meens we want "the other one"
304 // (1-factor)
305 factor = mAlphaSource;
306 factor.flags &= ~CORRUPTIBLE;
307 RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s)));
308 mBlendFactorCached = f;
309 return;
310 }
311 }
312 // fall-through...
313 case GGL_ONE_MINUS_DST_COLOR:
314 case GGL_DST_COLOR:
315 case GGL_ONE_MINUS_SRC_COLOR:
316 case GGL_SRC_COLOR:
317 case GGL_ONE_MINUS_DST_ALPHA:
318 case GGL_DST_ALPHA:
319 case GGL_SRC_ALPHA_SATURATE:
320 // help us find out what register we can use for the blend-factor
321 // CORRUPTIBLE registers are chosen first, or a new one is allocated.
322 if (fragment.flags & CORRUPTIBLE) {
323 factor.setTo(fragment.reg, 32, CORRUPTIBLE);
324 fragment.flags &= ~CORRUPTIBLE;
325 } else if (fb.flags & CORRUPTIBLE) {
326 factor.setTo(fb.reg, 32, CORRUPTIBLE);
327 fb.flags &= ~CORRUPTIBLE;
328 } else {
329 factor.setTo(scratches.obtain(), 32, CORRUPTIBLE);
330 }
331 break;
332 }
333
334 // XXX: doesn't work if size==1
335
336 switch(f) {
337 case GGL_ONE_MINUS_DST_COLOR:
338 case GGL_DST_COLOR:
339 factor.s = fb.s;
340 ADD(AL, 0, factor.reg, fb.reg, reg_imm(fb.reg, LSR, fb.s-1));
341 break;
342 case GGL_ONE_MINUS_SRC_COLOR:
343 case GGL_SRC_COLOR:
344 factor.s = fragment.s;
345 ADD(AL, 0, factor.reg, fragment.reg,
346 reg_imm(fragment.reg, LSR, fragment.s-1));
347 break;
348 case GGL_ONE_MINUS_SRC_ALPHA:
349 case GGL_SRC_ALPHA:
350 factor.s = src_alpha.s;
351 ADD(AL, 0, factor.reg, src_alpha.reg,
352 reg_imm(src_alpha.reg, LSR, src_alpha.s-1));
353 break;
354 case GGL_ONE_MINUS_DST_ALPHA:
355 case GGL_DST_ALPHA:
356 // XXX: should be precomputed
357 extract(factor, dst_pixel, GGLFormat::ALPHA);
358 ADD(AL, 0, factor.reg, factor.reg,
359 reg_imm(factor.reg, LSR, factor.s-1));
360 break;
361 case GGL_SRC_ALPHA_SATURATE:
362 // XXX: should be precomputed
363 // XXX: f = min(As, 1-Ad)
364 // btw, we're guaranteed that Ad's size is <= 8, because
365 // it's extracted from the framebuffer
366 break;
367 }
368
369 switch(f) {
370 case GGL_ONE_MINUS_DST_COLOR:
371 case GGL_ONE_MINUS_SRC_COLOR:
372 case GGL_ONE_MINUS_DST_ALPHA:
373 case GGL_ONE_MINUS_SRC_ALPHA:
374 RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s)));
375 }
376
377 // don't need more than 8-bits for the blend factor
378 // and this will prevent overflows in the multiplies later
379 if (factor.s > 8) {
380 MOV(AL, 0, factor.reg, reg_imm(factor.reg, LSR, factor.s-8));
381 factor.s = 8;
382 }
383 }
384
385 int GGLAssembler::blending_codes(int fs, int fd)
386 {
387 int blending = 0;
388 switch(fs) {
389 case GGL_ONE:
390 blending |= BLEND_SRC;
391 break;
392
393 case GGL_ONE_MINUS_DST_COLOR:
394 case GGL_DST_COLOR:
395 blending |= FACTOR_DST|BLEND_SRC;
396 break;
397 case GGL_ONE_MINUS_DST_ALPHA:
398 case GGL_DST_ALPHA:
399 // no need to extract 'component' from the destination
400 // for the blend factor, because we need ALPHA only.
401 blending |= BLEND_SRC;
402 break;
403
404 case GGL_ONE_MINUS_SRC_COLOR:
405 case GGL_SRC_COLOR:
406 blending |= FACTOR_SRC|BLEND_SRC;
407 break;
408 case GGL_ONE_MINUS_SRC_ALPHA:
409 case GGL_SRC_ALPHA:
410 case GGL_SRC_ALPHA_SATURATE:
411 blending |= FACTOR_SRC|BLEND_SRC;
412 break;
413 }
414 switch(fd) {
415 case GGL_ONE:
416 blending |= BLEND_DST;
417 break;
418
419 case GGL_ONE_MINUS_DST_COLOR:
420 case GGL_DST_COLOR:
421 blending |= FACTOR_DST|BLEND_DST;
422 break;
423 case GGL_ONE_MINUS_DST_ALPHA:
424 case GGL_DST_ALPHA:
425 blending |= FACTOR_DST|BLEND_DST;
426 break;
427
428 case GGL_ONE_MINUS_SRC_COLOR:
429 case GGL_SRC_COLOR:
430 blending |= FACTOR_SRC|BLEND_DST;
431 break;
432 case GGL_ONE_MINUS_SRC_ALPHA:
433 case GGL_SRC_ALPHA:
434 // no need to extract 'component' from the source
435 // for the blend factor, because we need ALPHA only.
436 blending |= BLEND_DST;
437 break;
438 }
439 return blending;
440 }
441
442 // ---------------------------------------------------------------------------
443
444 void GGLAssembler::build_blendFOneMinusF(
445 component_t& temp,
446 const integer_t& factor,
447 const integer_t& fragment,
448 const integer_t& fb)
449 {
450 // R = S*f + D*(1-f) = (S-D)*f + D
451 Scratch scratches(registerFile());
452 // compute S-D
453 integer_t diff(fragment.flags & CORRUPTIBLE ?
454 fragment.reg : scratches.obtain(), fb.size(), CORRUPTIBLE);
455 const int shift = fragment.size() - fb.size();
456 if (shift>0) RSB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSR, shift));
457 else if (shift<0) RSB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSL,-shift));
458 else RSB(AL, 0, diff.reg, fb.reg, fragment.reg);
459 mul_factor_add(temp, diff, factor, component_t(fb));
460 }
461
462 void GGLAssembler::build_blendOneMinusFF(
463 component_t& temp,
464 const integer_t& factor,
465 const integer_t& fragment,
466 const integer_t& fb)
467 {
468 // R = S*f + D*(1-f) = (S-D)*f + D
469 Scratch scratches(registerFile());
470 // compute D-S
471 integer_t diff(fb.flags & CORRUPTIBLE ?
472 fb.reg : scratches.obtain(), fb.size(), CORRUPTIBLE);
473 const int shift = fragment.size() - fb.size();
474 if (shift>0) SUB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSR, shift));
475 else if (shift<0) SUB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSL,-shift));
476 else SUB(AL, 0, diff.reg, fb.reg, fragment.reg);
477 mul_factor_add(temp, diff, factor, component_t(fragment));
478 }
479
480 // ---------------------------------------------------------------------------
481
482 void GGLAssembler::mul_factor( component_t& d,
483 const integer_t& v,
484 const integer_t& f)
485 {
486 int vs = v.size();
487 int fs = f.size();
488 int ms = vs+fs;
489
490 // XXX: we could have special cases for 1 bit mul
491
492 // all this code below to use the best multiply instruction
493 // wrt the parameters size. We take advantage of the fact
494 // that the 16-bits multiplies allow a 16-bit shift
495 // The trick is that we just make sure that we have at least 8-bits
496 // per component (which is enough for a 8 bits display).
497
498 int xy;
499 int vshift = 0;
500 int fshift = 0;
501 int smulw = 0;
502
503 if (vs<16) {
504 if (fs<16) {
505 xy = xyBB;
506 } else if (GGL_BETWEEN(fs, 24, 31)) {
507 ms -= 16;
508 xy = xyTB;
509 } else {
510 // eg: 15 * 18 -> 15 * 15
511 fshift = fs - 15;
512 ms -= fshift;
513 xy = xyBB;
514 }
515 } else if (GGL_BETWEEN(vs, 24, 31)) {
516 if (fs<16) {
517 ms -= 16;
518 xy = xyTB;
519 } else if (GGL_BETWEEN(fs, 24, 31)) {
520 ms -= 32;
521 xy = xyTT;
522 } else {
523 // eg: 24 * 18 -> 8 * 18
524 fshift = fs - 15;
525 ms -= 16 + fshift;
526 xy = xyTB;
527 }
528 } else {
529 if (fs<16) {
530 // eg: 18 * 15 -> 15 * 15
531 vshift = vs - 15;
532 ms -= vshift;
533 xy = xyBB;
534 } else if (GGL_BETWEEN(fs, 24, 31)) {
535 // eg: 18 * 24 -> 15 * 8
536 vshift = vs - 15;
537 ms -= 16 + vshift;
538 xy = xyBT;
539 } else {
540 // eg: 18 * 18 -> (15 * 18)>>16
541 fshift = fs - 15;
542 ms -= 16 + fshift;
543 xy = yB; //XXX SMULWB
544 smulw = 1;
545 }
546 }
547
548 LOGE_IF(ms>=32, "mul_factor overflow vs=%d, fs=%d", vs, fs);
549
550 int vreg = v.reg;
551 int freg = f.reg;
552 if (vshift) {
553 MOV(AL, 0, d.reg, reg_imm(vreg, LSR, vshift));
554 vreg = d.reg;
555 }
556 if (fshift) {
557 MOV(AL, 0, d.reg, reg_imm(vreg, LSR, fshift));
558 freg = d.reg;
559 }
560 if (smulw) SMULW(AL, xy, d.reg, vreg, freg);
561 else SMUL(AL, xy, d.reg, vreg, freg);
562
563
564 d.h = ms;
565 if (mDithering) {
566 d.l = 0;
567 } else {
568 d.l = fs;
569 d.flags |= CLEAR_LO;
570 }
571 }
572
573 void GGLAssembler::mul_factor_add( component_t& d,
574 const integer_t& v,
575 const integer_t& f,
576 const component_t& a)
577 {
578 // XXX: we could have special cases for 1 bit mul
579 Scratch scratches(registerFile());
580
581 int vs = v.size();
582 int fs = f.size();
583 int as = a.h;
584 int ms = vs+fs;
585
586 LOGE_IF(ms>=32, "mul_factor_add overflow vs=%d, fs=%d, as=%d", vs, fs, as);
587
588 integer_t add(a.reg, a.h, a.flags);
589
590 // 'a' is a component_t but it is guaranteed to have
591 // its high bits set to 0. However in the dithering case,
592 // we can't get away with truncating the potentially bad bits
593 // so extraction is needed.
594
595 if ((mDithering) && (a.size() < ms)) {
596 // we need to expand a
597 if (!(a.flags & CORRUPTIBLE)) {
598 // ... but it's not corruptible, so we need to pick a
599 // temporary register.
600 // Try to uses the destination register first (it's likely
601 // to be usable, unless it aliases an input).
602 if (d.reg!=a.reg && d.reg!=v.reg && d.reg!=f.reg) {
603 add.reg = d.reg;
604 } else {
605 add.reg = scratches.obtain();
606 }
607 }
608 expand(add, a, ms); // extracts and expands
609 as = ms;
610 }
611
612 if (ms == as) {
613 if (vs<16 && fs<16) SMLABB(AL, d.reg, v.reg, f.reg, add.reg);
614 else MLA(AL, 0, d.reg, v.reg, f.reg, add.reg);
615 } else {
616 int temp = d.reg;
617 if (temp == add.reg) {
618 // the mul will modify add.reg, we need an intermediary reg
619 if (v.flags & CORRUPTIBLE) temp = v.reg;
620 else if (f.flags & CORRUPTIBLE) temp = f.reg;
621 else temp = scratches.obtain();
622 }
623
624 if (vs<16 && fs<16) SMULBB(AL, temp, v.reg, f.reg);
625 else MUL(AL, 0, temp, v.reg, f.reg);
626
627 if (ms>as) {
628 ADD(AL, 0, d.reg, temp, reg_imm(add.reg, LSL, ms-as));
629 } else if (ms<as) {
630 // not sure if we should expand the mul instead?
631 ADD(AL, 0, d.reg, temp, reg_imm(add.reg, LSR, as-ms));
632 }
633 }
634
635 d.h = ms;
636 if (mDithering) {
637 d.l = a.l;
638 } else {
639 d.l = fs>a.l ? fs : a.l;
640 d.flags |= CLEAR_LO;
641 }
642 }
643
644 void GGLAssembler::component_add(component_t& d,
645 const integer_t& dst, const integer_t& src)
646 {
647 // here we're guaranteed that fragment.size() >= fb.size()
648 const int shift = src.size() - dst.size();
649 if (!shift) {
650 ADD(AL, 0, d.reg, src.reg, dst.reg);
651 } else {
652 ADD(AL, 0, d.reg, src.reg, reg_imm(dst.reg, LSL, shift));
653 }
654
655 d.h = src.size();
656 if (mDithering) {
657 d.l = 0;
658 } else {
659 d.l = shift;
660 d.flags |= CLEAR_LO;
661 }
662 }
663
664 void GGLAssembler::component_sat(const component_t& v)
665 {
666 const int one = ((1<<v.size())-1)<<v.l;
667 CMP(AL, v.reg, imm( 1<<v.h ));
668 if (isValidImmediate(one)) {
669 MOV(HS, 0, v.reg, imm( one ));
670 } else if (isValidImmediate(~one)) {
671 MVN(HS, 0, v.reg, imm( ~one ));
672 } else {
673 MOV(HS, 0, v.reg, imm( 1<<v.h ));
674 SUB(HS, 0, v.reg, v.reg, imm( 1<<v.l ));
675 }
676 }
677
678 // ----------------------------------------------------------------------------
679
680 }; // namespace android
681
+0
-702
libpixelflinger/codeflinger/disassem.c less more
0 /* $NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $ */
1
2 /*-
3 * Copyright (c) 1996 Mark Brinicombe.
4 * Copyright (c) 1996 Brini.
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Brini.
19 * 4. The name of the company nor the name of the author may be used to
20 * endorse or promote products derived from this software without specific
21 * prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * RiscBSD kernel project
36 *
37 * db_disasm.c
38 *
39 * Kernel disassembler
40 *
41 * Created : 10/02/96
42 *
43 * Structured after the sparc/sparc/db_disasm.c by David S. Miller &
44 * Paul Kranenburg
45 *
46 * This code is not complete. Not all instructions are disassembled.
47 */
48
49 #include <sys/cdefs.h>
50 //__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/arm/arm/disassem.c,v 1.2 2005/01/05 21:58:47 imp Exp $");
51 #include <sys/param.h>
52 #include <stdio.h>
53
54 #include "disassem.h"
55 #include "armreg.h"
56 //#include <ddb/ddb.h>
57
58 /*
59 * General instruction format
60 *
61 * insn[cc][mod] [operands]
62 *
63 * Those fields with an uppercase format code indicate that the field
64 * follows directly after the instruction before the separator i.e.
65 * they modify the instruction rather than just being an operand to
66 * the instruction. The only exception is the writeback flag which
67 * follows a operand.
68 *
69 *
70 * 2 - print Operand 2 of a data processing instruction
71 * d - destination register (bits 12-15)
72 * n - n register (bits 16-19)
73 * s - s register (bits 8-11)
74 * o - indirect register rn (bits 16-19) (used by swap)
75 * m - m register (bits 0-3)
76 * a - address operand of ldr/str instruction
77 * e - address operand of ldrh/strh instruction
78 * l - register list for ldm/stm instruction
79 * f - 1st fp operand (register) (bits 12-14)
80 * g - 2nd fp operand (register) (bits 16-18)
81 * h - 3rd fp operand (register/immediate) (bits 0-4)
82 * b - branch address
83 * t - thumb branch address (bits 24, 0-23)
84 * k - breakpoint comment (bits 0-3, 8-19)
85 * X - block transfer type
86 * Y - block transfer type (r13 base)
87 * c - comment field bits(0-23)
88 * p - saved or current status register
89 * F - PSR transfer fields
90 * D - destination-is-r15 (P) flag on TST, TEQ, CMP, CMN
91 * L - co-processor transfer size
92 * S - set status flag
93 * P - fp precision
94 * Q - fp precision (for ldf/stf)
95 * R - fp rounding
96 * v - co-processor data transfer registers + addressing mode
97 * W - writeback flag
98 * x - instruction in hex
99 * # - co-processor number
100 * y - co-processor data processing registers
101 * z - co-processor register transfer registers
102 */
103
104 struct arm32_insn {
105 u_int mask;
106 u_int pattern;
107 char* name;
108 char* format;
109 };
110
111 static const struct arm32_insn arm32_i[] = {
112 { 0x0fffffff, 0x0ff00000, "imb", "c" }, /* Before swi */
113 { 0x0fffffff, 0x0ff00001, "imbrange", "c" }, /* Before swi */
114 { 0x0f000000, 0x0f000000, "swi", "c" },
115 { 0xfe000000, 0xfa000000, "blx", "t" }, /* Before b and bl */
116 { 0x0f000000, 0x0a000000, "b", "b" },
117 { 0x0f000000, 0x0b000000, "bl", "b" },
118 { 0x0fe000f0, 0x00000090, "mul", "Snms" },
119 { 0x0fe000f0, 0x00200090, "mla", "Snmsd" },
120 { 0x0fe000f0, 0x00800090, "umull", "Sdnms" },
121 { 0x0fe000f0, 0x00c00090, "smull", "Sdnms" },
122 { 0x0fe000f0, 0x00a00090, "umlal", "Sdnms" },
123 { 0x0fe000f0, 0x00e00090, "smlal", "Sdnms" },
124 { 0x0d700000, 0x04200000, "strt", "daW" },
125 { 0x0d700000, 0x04300000, "ldrt", "daW" },
126 { 0x0d700000, 0x04600000, "strbt", "daW" },
127 { 0x0d700000, 0x04700000, "ldrbt", "daW" },
128 { 0x0c500000, 0x04000000, "str", "daW" },
129 { 0x0c500000, 0x04100000, "ldr", "daW" },
130 { 0x0c500000, 0x04400000, "strb", "daW" },
131 { 0x0c500000, 0x04500000, "ldrb", "daW" },
132 { 0x0e1f0000, 0x080d0000, "stm", "YnWl" },/* separate out r13 base */
133 { 0x0e1f0000, 0x081d0000, "ldm", "YnWl" },/* separate out r13 base */
134 { 0x0e100000, 0x08000000, "stm", "XnWl" },
135 { 0x0e100000, 0x08100000, "ldm", "XnWl" },
136 { 0x0e1000f0, 0x00100090, "ldrb", "deW" },
137 { 0x0e1000f0, 0x00000090, "strb", "deW" },
138 { 0x0e1000f0, 0x001000d0, "ldrsb", "deW" },
139 { 0x0e1000f0, 0x001000b0, "ldrh", "deW" },
140 { 0x0e1000f0, 0x000000b0, "strh", "deW" },
141 { 0x0e1000f0, 0x001000f0, "ldrsh", "deW" },
142 { 0x0f200090, 0x00200090, "und", "x" }, /* Before data processing */
143 { 0x0e1000d0, 0x000000d0, "und", "x" }, /* Before data processing */
144 { 0x0ff00ff0, 0x01000090, "swp", "dmo" },
145 { 0x0ff00ff0, 0x01400090, "swpb", "dmo" },
146 { 0x0fbf0fff, 0x010f0000, "mrs", "dp" }, /* Before data processing */
147 { 0x0fb0fff0, 0x0120f000, "msr", "pFm" },/* Before data processing */
148 { 0x0fb0f000, 0x0320f000, "msr", "pF2" },/* Before data processing */
149 { 0x0ffffff0, 0x012fff10, "bx", "m" },
150 { 0x0fff0ff0, 0x016f0f10, "clz", "dm" },
151 { 0x0ffffff0, 0x012fff30, "blx", "m" },
152 { 0xfff000f0, 0xe1200070, "bkpt", "k" },
153 { 0x0de00000, 0x00000000, "and", "Sdn2" },
154 { 0x0de00000, 0x00200000, "eor", "Sdn2" },
155 { 0x0de00000, 0x00400000, "sub", "Sdn2" },
156 { 0x0de00000, 0x00600000, "rsb", "Sdn2" },
157 { 0x0de00000, 0x00800000, "add", "Sdn2" },
158 { 0x0de00000, 0x00a00000, "adc", "Sdn2" },
159 { 0x0de00000, 0x00c00000, "sbc", "Sdn2" },
160 { 0x0de00000, 0x00e00000, "rsc", "Sdn2" },
161 { 0x0df00000, 0x01100000, "tst", "Dn2" },
162 { 0x0df00000, 0x01300000, "teq", "Dn2" },
163 { 0x0df00000, 0x01500000, "cmp", "Dn2" },
164 { 0x0df00000, 0x01700000, "cmn", "Dn2" },
165 { 0x0de00000, 0x01800000, "orr", "Sdn2" },
166 { 0x0de00000, 0x01a00000, "mov", "Sd2" },
167 { 0x0de00000, 0x01c00000, "bic", "Sdn2" },
168 { 0x0de00000, 0x01e00000, "mvn", "Sd2" },
169 { 0x0ff08f10, 0x0e000100, "adf", "PRfgh" },
170 { 0x0ff08f10, 0x0e100100, "muf", "PRfgh" },
171 { 0x0ff08f10, 0x0e200100, "suf", "PRfgh" },
172 { 0x0ff08f10, 0x0e300100, "rsf", "PRfgh" },
173 { 0x0ff08f10, 0x0e400100, "dvf", "PRfgh" },
174 { 0x0ff08f10, 0x0e500100, "rdf", "PRfgh" },
175 { 0x0ff08f10, 0x0e600100, "pow", "PRfgh" },
176 { 0x0ff08f10, 0x0e700100, "rpw", "PRfgh" },
177 { 0x0ff08f10, 0x0e800100, "rmf", "PRfgh" },
178 { 0x0ff08f10, 0x0e900100, "fml", "PRfgh" },
179 { 0x0ff08f10, 0x0ea00100, "fdv", "PRfgh" },
180 { 0x0ff08f10, 0x0eb00100, "frd", "PRfgh" },
181 { 0x0ff08f10, 0x0ec00100, "pol", "PRfgh" },
182 { 0x0f008f10, 0x0e000100, "fpbop", "PRfgh" },
183 { 0x0ff08f10, 0x0e008100, "mvf", "PRfh" },
184 { 0x0ff08f10, 0x0e108100, "mnf", "PRfh" },
185 { 0x0ff08f10, 0x0e208100, "abs", "PRfh" },
186 { 0x0ff08f10, 0x0e308100, "rnd", "PRfh" },
187 { 0x0ff08f10, 0x0e408100, "sqt", "PRfh" },
188 { 0x0ff08f10, 0x0e508100, "log", "PRfh" },
189 { 0x0ff08f10, 0x0e608100, "lgn", "PRfh" },
190 { 0x0ff08f10, 0x0e708100, "exp", "PRfh" },
191 { 0x0ff08f10, 0x0e808100, "sin", "PRfh" },
192 { 0x0ff08f10, 0x0e908100, "cos", "PRfh" },
193 { 0x0ff08f10, 0x0ea08100, "tan", "PRfh" },
194 { 0x0ff08f10, 0x0eb08100, "asn", "PRfh" },
195 { 0x0ff08f10, 0x0ec08100, "acs", "PRfh" },
196 { 0x0ff08f10, 0x0ed08100, "atn", "PRfh" },
197 { 0x0f008f10, 0x0e008100, "fpuop", "PRfh" },
198 { 0x0e100f00, 0x0c000100, "stf", "QLv" },
199 { 0x0e100f00, 0x0c100100, "ldf", "QLv" },
200 { 0x0ff00f10, 0x0e000110, "flt", "PRgd" },
201 { 0x0ff00f10, 0x0e100110, "fix", "PRdh" },
202 { 0x0ff00f10, 0x0e200110, "wfs", "d" },
203 { 0x0ff00f10, 0x0e300110, "rfs", "d" },
204 { 0x0ff00f10, 0x0e400110, "wfc", "d" },
205 { 0x0ff00f10, 0x0e500110, "rfc", "d" },
206 { 0x0ff0ff10, 0x0e90f110, "cmf", "PRgh" },
207 { 0x0ff0ff10, 0x0eb0f110, "cnf", "PRgh" },
208 { 0x0ff0ff10, 0x0ed0f110, "cmfe", "PRgh" },
209 { 0x0ff0ff10, 0x0ef0f110, "cnfe", "PRgh" },
210 { 0xff100010, 0xfe000010, "mcr2", "#z" },
211 { 0x0f100010, 0x0e000010, "mcr", "#z" },
212 { 0xff100010, 0xfe100010, "mrc2", "#z" },
213 { 0x0f100010, 0x0e100010, "mrc", "#z" },
214 { 0xff000010, 0xfe000000, "cdp2", "#y" },
215 { 0x0f000010, 0x0e000000, "cdp", "#y" },
216 { 0xfe100090, 0xfc100000, "ldc2", "L#v" },
217 { 0x0e100090, 0x0c100000, "ldc", "L#v" },
218 { 0xfe100090, 0xfc000000, "stc2", "L#v" },
219 { 0x0e100090, 0x0c000000, "stc", "L#v" },
220 { 0xf550f000, 0xf550f000, "pld", "ne" },
221 { 0x0ff00ff0, 0x01000050, "qaad", "dmn" },
222 { 0x0ff00ff0, 0x01400050, "qdaad", "dmn" },
223 { 0x0ff00ff0, 0x01600050, "qdsub", "dmn" },
224 { 0x0ff00ff0, 0x01200050, "dsub", "dmn" },
225 { 0x0ff000f0, 0x01000080, "smlabb", "nmsd" }, // d & n inverted!!
226 { 0x0ff000f0, 0x010000a0, "smlatb", "nmsd" }, // d & n inverted!!
227 { 0x0ff000f0, 0x010000c0, "smlabt", "nmsd" }, // d & n inverted!!
228 { 0x0ff000f0, 0x010000e0, "smlatt", "nmsd" }, // d & n inverted!!
229 { 0x0ff000f0, 0x01400080, "smlalbb","ndms" }, // d & n inverted!!
230 { 0x0ff000f0, 0x014000a0, "smlaltb","ndms" }, // d & n inverted!!
231 { 0x0ff000f0, 0x014000c0, "smlalbt","ndms" }, // d & n inverted!!
232 { 0x0ff000f0, 0x014000e0, "smlaltt","ndms" }, // d & n inverted!!
233 { 0x0ff000f0, 0x01200080, "smlawb", "nmsd" }, // d & n inverted!!
234 { 0x0ff0f0f0, 0x012000a0, "smulwb","nms" }, // d & n inverted!!
235 { 0x0ff000f0, 0x012000c0, "smlawt", "nmsd" }, // d & n inverted!!
236 { 0x0ff0f0f0, 0x012000e0, "smulwt","nms" }, // d & n inverted!!
237 { 0x0ff0f0f0, 0x01600080, "smulbb","nms" }, // d & n inverted!!
238 { 0x0ff0f0f0, 0x016000a0, "smultb","nms" }, // d & n inverted!!
239 { 0x0ff0f0f0, 0x016000c0, "smulbt","nms" }, // d & n inverted!!
240 { 0x0ff0f0f0, 0x016000e0, "smultt","nms" }, // d & n inverted!!
241 { 0x00000000, 0x00000000, NULL, NULL }
242 };
243
244 static char const arm32_insn_conditions[][4] = {
245 "eq", "ne", "cs", "cc",
246 "mi", "pl", "vs", "vc",
247 "hi", "ls", "ge", "lt",
248 "gt", "le", "", "nv"
249 };
250
251 static char const insn_block_transfers[][4] = {
252 "da", "ia", "db", "ib"
253 };
254
255 static char const insn_stack_block_transfers[][4] = {
256 "ed", "ea", "fd", "fa"
257 };
258
259 static char const op_shifts[][4] = {
260 "lsl", "lsr", "asr", "ror"
261 };
262
263 static char const insn_fpa_rounding[][2] = {
264 "", "p", "m", "z"
265 };
266
267 static char const insn_fpa_precision[][2] = {
268 "s", "d", "e", "p"
269 };
270
271 static char const insn_fpaconstants[][8] = {
272 "0.0", "1.0", "2.0", "3.0",
273 "4.0", "5.0", "0.5", "10.0"
274 };
275
276 #define insn_condition(x) arm32_insn_conditions[(x >> 28) & 0x0f]
277 #define insn_blktrans(x) insn_block_transfers[(x >> 23) & 3]
278 #define insn_stkblktrans(x) insn_stack_block_transfers[(x >> 23) & 3]
279 #define op2_shift(x) op_shifts[(x >> 5) & 3]
280 #define insn_fparnd(x) insn_fpa_rounding[(x >> 5) & 0x03]
281 #define insn_fpaprec(x) insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1]
282 #define insn_fpaprect(x) insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1]
283 #define insn_fpaimm(x) insn_fpaconstants[x & 0x07]
284
285 /* Local prototypes */
286 static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
287 static void disasm_print_reglist(const disasm_interface_t *di, u_int insn);
288 static void disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn,
289 u_int loc);
290 static void disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn,
291 u_int loc);
292 static void disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn,
293 u_int loc);
294 static u_int disassemble_readword(u_int address);
295 static void disassemble_printaddr(u_int address);
296
297 u_int
298 disasm(const disasm_interface_t *di, u_int loc, int altfmt)
299 {
300 const struct arm32_insn *i_ptr = &arm32_i[0];
301
302 u_int insn;
303 int matchp;
304 int branch;
305 char* f_ptr;
306 int fmt;
307
308 fmt = 0;
309 matchp = 0;
310 insn = di->di_readword(loc);
311
312 /* di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
313
314 while (i_ptr->name) {
315 if ((insn & i_ptr->mask) == i_ptr->pattern) {
316 matchp = 1;
317 break;
318 }
319 i_ptr++;
320 }
321
322 if (!matchp) {
323 di->di_printf("und%s\t%08x\n", insn_condition(insn), insn);
324 return(loc + INSN_SIZE);
325 }
326
327 /* If instruction forces condition code, don't print it. */
328 if ((i_ptr->mask & 0xf0000000) == 0xf0000000)
329 di->di_printf("%s", i_ptr->name);
330 else
331 di->di_printf("%s%s", i_ptr->name, insn_condition(insn));
332
333 f_ptr = i_ptr->format;
334
335 /* Insert tab if there are no instruction modifiers */
336
337 if (*(f_ptr) < 'A' || *(f_ptr) > 'Z') {
338 ++fmt;
339 di->di_printf("\t");
340 }
341
342 while (*f_ptr) {
343 switch (*f_ptr) {
344 /* 2 - print Operand 2 of a data processing instruction */
345 case '2':
346 if (insn & 0x02000000) {
347 int rotate= ((insn >> 7) & 0x1e);
348
349 di->di_printf("#0x%08x",
350 (insn & 0xff) << (32 - rotate) |
351 (insn & 0xff) >> rotate);
352 } else {
353 disasm_register_shift(di, insn);
354 }
355 break;
356 /* d - destination register (bits 12-15) */
357 case 'd':
358 di->di_printf("r%d", ((insn >> 12) & 0x0f));
359 break;
360 /* D - insert 'p' if Rd is R15 */
361 case 'D':
362 if (((insn >> 12) & 0x0f) == 15)
363 di->di_printf("p");
364 break;
365 /* n - n register (bits 16-19) */
366 case 'n':
367 di->di_printf("r%d", ((insn >> 16) & 0x0f));
368 break;
369 /* s - s register (bits 8-11) */
370 case 's':
371 di->di_printf("r%d", ((insn >> 8) & 0x0f));
372 break;
373 /* o - indirect register rn (bits 16-19) (used by swap) */
374 case 'o':
375 di->di_printf("[r%d]", ((insn >> 16) & 0x0f));
376 break;
377 /* m - m register (bits 0-4) */
378 case 'm':
379 di->di_printf("r%d", ((insn >> 0) & 0x0f));
380 break;
381 /* a - address operand of ldr/str instruction */
382 case 'a':
383 disasm_insn_ldrstr(di, insn, loc);
384 break;
385 /* e - address operand of ldrh/strh instruction */
386 case 'e':
387 disasm_insn_ldrhstrh(di, insn, loc);
388 break;
389 /* l - register list for ldm/stm instruction */
390 case 'l':
391 disasm_print_reglist(di, insn);
392 break;
393 /* f - 1st fp operand (register) (bits 12-14) */
394 case 'f':
395 di->di_printf("f%d", (insn >> 12) & 7);
396 break;
397 /* g - 2nd fp operand (register) (bits 16-18) */
398 case 'g':
399 di->di_printf("f%d", (insn >> 16) & 7);
400 break;
401 /* h - 3rd fp operand (register/immediate) (bits 0-4) */
402 case 'h':
403 if (insn & (1 << 3))
404 di->di_printf("#%s", insn_fpaimm(insn));
405 else
406 di->di_printf("f%d", insn & 7);
407 break;
408 /* b - branch address */
409 case 'b':
410 branch = ((insn << 2) & 0x03ffffff);
411 if (branch & 0x02000000)
412 branch |= 0xfc000000;
413 di->di_printaddr(loc + 8 + branch);
414 break;
415 /* t - blx address */
416 case 't':
417 branch = ((insn << 2) & 0x03ffffff) |
418 (insn >> 23 & 0x00000002);
419 if (branch & 0x02000000)
420 branch |= 0xfc000000;
421 di->di_printaddr(loc + 8 + branch);
422 break;
423 /* X - block transfer type */
424 case 'X':
425 di->di_printf("%s", insn_blktrans(insn));
426 break;
427 /* Y - block transfer type (r13 base) */
428 case 'Y':
429 di->di_printf("%s", insn_stkblktrans(insn));
430 break;
431 /* c - comment field bits(0-23) */
432 case 'c':
433 di->di_printf("0x%08x", (insn & 0x00ffffff));
434 break;
435 /* k - breakpoint comment (bits 0-3, 8-19) */
436 case 'k':
437 di->di_printf("0x%04x",
438 (insn & 0x000fff00) >> 4 | (insn & 0x0000000f));
439 break;
440 /* p - saved or current status register */
441 case 'p':
442 if (insn & 0x00400000)
443 di->di_printf("spsr");
444 else
445 di->di_printf("cpsr");
446 break;
447 /* F - PSR transfer fields */
448 case 'F':
449 di->di_printf("_");
450 if (insn & (1 << 16))
451 di->di_printf("c");
452 if (insn & (1 << 17))
453 di->di_printf("x");
454 if (insn & (1 << 18))
455 di->di_printf("s");
456 if (insn & (1 << 19))
457 di->di_printf("f");
458 break;
459 /* B - byte transfer flag */
460 case 'B':
461 if (insn & 0x00400000)
462 di->di_printf("b");
463 break;
464 /* L - co-processor transfer size */
465 case 'L':
466 if (insn & (1 << 22))
467 di->di_printf("l");
468 break;
469 /* S - set status flag */
470 case 'S':
471 if (insn & 0x00100000)
472 di->di_printf("s");
473 break;
474 /* P - fp precision */
475 case 'P':
476 di->di_printf("%s", insn_fpaprec(insn));
477 break;
478 /* Q - fp precision (for ldf/stf) */
479 case 'Q':
480 break;
481 /* R - fp rounding */
482 case 'R':
483 di->di_printf("%s", insn_fparnd(insn));
484 break;
485 /* W - writeback flag */
486 case 'W':
487 if (insn & (1 << 21))
488 di->di_printf("!");
489 break;
490 /* # - co-processor number */
491 case '#':
492 di->di_printf("p%d", (insn >> 8) & 0x0f);
493 break;
494 /* v - co-processor data transfer registers+addressing mode */
495 case 'v':
496 disasm_insn_ldcstc(di, insn, loc);
497 break;
498 /* x - instruction in hex */
499 case 'x':
500 di->di_printf("0x%08x", insn);
501 break;
502 /* y - co-processor data processing registers */
503 case 'y':
504 di->di_printf("%d, ", (insn >> 20) & 0x0f);
505
506 di->di_printf("c%d, c%d, c%d", (insn >> 12) & 0x0f,
507 (insn >> 16) & 0x0f, insn & 0x0f);
508
509 di->di_printf(", %d", (insn >> 5) & 0x07);
510 break;
511 /* z - co-processor register transfer registers */
512 case 'z':
513 di->di_printf("%d, ", (insn >> 21) & 0x07);
514 di->di_printf("r%d, c%d, c%d, %d",
515 (insn >> 12) & 0x0f, (insn >> 16) & 0x0f,
516 insn & 0x0f, (insn >> 5) & 0x07);
517
518 /* if (((insn >> 5) & 0x07) != 0)
519 di->di_printf(", %d", (insn >> 5) & 0x07);*/
520 break;
521 default:
522 di->di_printf("[%c - unknown]", *f_ptr);
523 break;
524 }
525 if (*(f_ptr+1) >= 'A' && *(f_ptr+1) <= 'Z')
526 ++f_ptr;
527 else if (*(++f_ptr)) {
528 ++fmt;
529 if (fmt == 1)
530 di->di_printf("\t");
531 else
532 di->di_printf(", ");
533 }
534 };
535
536 di->di_printf("\n");
537
538 return(loc + INSN_SIZE);
539 }
540
541
542 static void
543 disasm_register_shift(const disasm_interface_t *di, u_int insn)
544 {
545 di->di_printf("r%d", (insn & 0x0f));
546 if ((insn & 0x00000ff0) == 0)
547 ;
548 else if ((insn & 0x00000ff0) == 0x00000060)
549 di->di_printf(", rrx");
550 else {
551 if (insn & 0x10)
552 di->di_printf(", %s r%d", op2_shift(insn),
553 (insn >> 8) & 0x0f);
554 else
555 di->di_printf(", %s #%d", op2_shift(insn),
556 (insn >> 7) & 0x1f);
557 }
558 }
559
560
561 static void
562 disasm_print_reglist(const disasm_interface_t *di, u_int insn)
563 {
564 int loop;
565 int start;
566 int comma;
567
568 di->di_printf("{");
569 start = -1;
570 comma = 0;
571
572 for (loop = 0; loop < 17; ++loop) {
573 if (start != -1) {
574 if (loop == 16 || !(insn & (1 << loop))) {
575 if (comma)
576 di->di_printf(", ");
577 else
578 comma = 1;
579 if (start == loop - 1)
580 di->di_printf("r%d", start);
581 else
582 di->di_printf("r%d-r%d", start, loop - 1);
583 start = -1;
584 }
585 } else {
586 if (insn & (1 << loop))
587 start = loop;
588 }
589 }
590 di->di_printf("}");
591
592 if (insn & (1 << 22))
593 di->di_printf("^");
594 }
595
596 static void
597 disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, u_int loc)
598 {
599 int offset;
600
601 offset = insn & 0xfff;
602 if ((insn & 0x032f0000) == 0x010f0000) {
603 /* rA = pc, immediate index */
604 if (insn & 0x00800000)
605 loc += offset;
606 else
607 loc -= offset;
608 di->di_printaddr(loc + 8);
609 } else {
610 di->di_printf("[r%d", (insn >> 16) & 0x0f);
611 if ((insn & 0x03000fff) != 0x01000000) {
612 di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
613 if (!(insn & 0x00800000))
614 di->di_printf("-");
615 if (insn & (1 << 25))
616 disasm_register_shift(di, insn);
617 else
618 di->di_printf("#0x%03x", offset);
619 }
620 if (insn & (1 << 24))
621 di->di_printf("]");
622 }
623 }
624
625 static void
626 disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, u_int loc)
627 {
628 int offset;
629
630 offset = ((insn & 0xf00) >> 4) | (insn & 0xf);
631 if ((insn & 0x004f0000) == 0x004f0000) {
632 /* rA = pc, immediate index */
633 if (insn & 0x00800000)
634 loc += offset;
635 else
636 loc -= offset;
637 di->di_printaddr(loc + 8);
638 } else {
639 di->di_printf("[r%d", (insn >> 16) & 0x0f);
640 if ((insn & 0x01400f0f) != 0x01400000) {
641 di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
642 if (!(insn & 0x00800000))
643 di->di_printf("-");
644 if (insn & (1 << 22))
645 di->di_printf("#0x%02x", offset);
646 else
647 di->di_printf("r%d", (insn & 0x0f));
648 }
649 if (insn & (1 << 24))
650 di->di_printf("]");
651 }
652 }
653
654 static void
655 disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int loc)
656 {
657 if (((insn >> 8) & 0xf) == 1)
658 di->di_printf("f%d, ", (insn >> 12) & 0x07);
659 else
660 di->di_printf("c%d, ", (insn >> 12) & 0x0f);
661
662 di->di_printf("[r%d", (insn >> 16) & 0x0f);
663
664 di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
665
666 if (!(insn & (1 << 23)))
667 di->di_printf("-");
668
669 di->di_printf("#0x%03x", (insn & 0xff) << 2);
670
671 if (insn & (1 << 24))
672 di->di_printf("]");
673
674 if (insn & (1 << 21))
675 di->di_printf("!");
676 }
677
678 static u_int
679 disassemble_readword(u_int address)
680 {
681 return(*((u_int *)address));
682 }
683
684 static void
685 disassemble_printaddr(u_int address)
686 {
687 printf("0x%08x", address);
688 }
689
690 static const disasm_interface_t disassemble_di = {
691 disassemble_readword, disassemble_printaddr, printf
692 };
693
694 void
695 disassemble(u_int address)
696 {
697
698 (void)disasm(&disassemble_di, address, 0);
699 }
700
701 /* End of disassem.c */
+0
-65
libpixelflinger/codeflinger/disassem.h less more
0 /* $NetBSD: disassem.h,v 1.4 2001/03/04 04:15:58 matt Exp $ */
1
2 /*-
3 * Copyright (c) 1997 Mark Brinicombe.
4 * Copyright (c) 1997 Causality Limited.
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Mark Brinicombe.
19 * 4. The name of the company nor the name of the author may be used to
20 * endorse or promote products derived from this software without specific
21 * prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * Define the interface structure required by the disassembler.
36 *
37 * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/disassem.h,v 1.2 2005/01/05 21:58:48 imp Exp $
38 */
39
40 #ifndef ANDROID_MACHINE_DISASSEM_H
41 #define ANDROID_MACHINE_DISASSEM_H
42
43 #include <sys/types.h>
44
45 #if __cplusplus
46 extern "C" {
47 #endif
48
49 typedef struct {
50 u_int (*di_readword)(u_int);
51 void (*di_printaddr)(u_int);
52 void (*di_printf)(const char *, ...);
53 } disasm_interface_t;
54
55 /* Prototypes for callable functions */
56
57 u_int disasm(const disasm_interface_t *, u_int, int);
58 void disassemble(u_int);
59
60 #if __cplusplus
61 }
62 #endif
63
64 #endif /* !ANDROID_MACHINE_DISASSEM_H */
+0
-378
libpixelflinger/codeflinger/load_store.cpp less more
0 /* libs/pixelflinger/codeflinger/load_store.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <stdio.h>
19 #include <cutils/log.h>
20
21 #include "codeflinger/GGLAssembler.h"
22
23 namespace android {
24
25 // ----------------------------------------------------------------------------
26
27 void GGLAssembler::store(const pointer_t& addr, const pixel_t& s, uint32_t flags)
28 {
29 const int bits = addr.size;
30 const int inc = (flags & WRITE_BACK)?1:0;
31 switch (bits) {
32 case 32:
33 if (inc) STR(AL, s.reg, addr.reg, immed12_post(4));
34 else STR(AL, s.reg, addr.reg);
35 break;
36 case 24:
37 // 24 bits formats are a little special and used only for RGB
38 // 0x00BBGGRR is unpacked as R,G,B
39 STRB(AL, s.reg, addr.reg, immed12_pre(0));
40 MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 8));
41 STRB(AL, s.reg, addr.reg, immed12_pre(1));
42 MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 8));
43 STRB(AL, s.reg, addr.reg, immed12_pre(2));
44 if (!(s.flags & CORRUPTIBLE)) {
45 MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 16));
46 }
47 if (inc)
48 ADD(AL, 0, addr.reg, addr.reg, imm(3));
49 break;
50 case 16:
51 if (inc) STRH(AL, s.reg, addr.reg, immed8_post(2));
52 else STRH(AL, s.reg, addr.reg);
53 break;
54 case 8:
55 if (inc) STRB(AL, s.reg, addr.reg, immed12_post(1));
56 else STRB(AL, s.reg, addr.reg);
57 break;
58 }
59 }
60
61 void GGLAssembler::load(const pointer_t& addr, const pixel_t& s, uint32_t flags)
62 {
63 Scratch scratches(registerFile());
64 int s0;
65
66 const int bits = addr.size;
67 const int inc = (flags & WRITE_BACK)?1:0;
68 switch (bits) {
69 case 32:
70 if (inc) LDR(AL, s.reg, addr.reg, immed12_post(4));
71 else LDR(AL, s.reg, addr.reg);
72 break;
73 case 24:
74 // 24 bits formats are a little special and used only for RGB
75 // R,G,B is packed as 0x00BBGGRR
76 s0 = scratches.obtain();
77 if (s.reg != addr.reg) {
78 LDRB(AL, s.reg, addr.reg, immed12_pre(0)); // R
79 LDRB(AL, s0, addr.reg, immed12_pre(1)); // G
80 ORR(AL, 0, s.reg, s.reg, reg_imm(s0, LSL, 8));
81 LDRB(AL, s0, addr.reg, immed12_pre(2)); // B
82 ORR(AL, 0, s.reg, s.reg, reg_imm(s0, LSL, 16));
83 } else {
84 int s1 = scratches.obtain();
85 LDRB(AL, s1, addr.reg, immed12_pre(0)); // R
86 LDRB(AL, s0, addr.reg, immed12_pre(1)); // G
87 ORR(AL, 0, s1, s1, reg_imm(s0, LSL, 8));
88 LDRB(AL, s0, addr.reg, immed12_pre(2)); // B
89 ORR(AL, 0, s.reg, s1, reg_imm(s0, LSL, 16));
90 }
91 if (inc)
92 ADD(AL, 0, addr.reg, addr.reg, imm(3));
93 break;
94 case 16:
95 if (inc) LDRH(AL, s.reg, addr.reg, immed8_post(2));
96 else LDRH(AL, s.reg, addr.reg);
97 break;
98 case 8:
99 if (inc) LDRB(AL, s.reg, addr.reg, immed12_post(1));
100 else LDRB(AL, s.reg, addr.reg);
101 break;
102 }
103 }
104
105 void GGLAssembler::extract(integer_t& d, int s, int h, int l, int bits)
106 {
107 const int maskLen = h-l;
108
109 assert(maskLen<=8);
110 assert(h);
111
112 if (h != bits) {
113 const int mask = ((1<<maskLen)-1) << l;
114 if (isValidImmediate(mask)) {
115 AND(AL, 0, d.reg, s, imm(mask)); // component = packed & mask;
116 } else if (isValidImmediate(~mask)) {
117 BIC(AL, 0, d.reg, s, imm(~mask)); // component = packed & mask;
118 } else {
119 MOV(AL, 0, d.reg, reg_imm(s, LSL, 32-h));
120 l += 32-h;
121 h = 32;
122 }
123 s = d.reg;
124 }
125
126 if (l) {
127 MOV(AL, 0, d.reg, reg_imm(s, LSR, l)); // component = packed >> l;
128 s = d.reg;
129 }
130
131 if (s != d.reg) {
132 MOV(AL, 0, d.reg, s);
133 }
134
135 d.s = maskLen;
136 }
137
138 void GGLAssembler::extract(integer_t& d, const pixel_t& s, int component)
139 {
140 extract(d, s.reg,
141 s.format.c[component].h,
142 s.format.c[component].l,
143 s.size());
144 }
145
146 void GGLAssembler::extract(component_t& d, const pixel_t& s, int component)
147 {
148 integer_t r(d.reg, 32, d.flags);
149 extract(r, s.reg,
150 s.format.c[component].h,
151 s.format.c[component].l,
152 s.size());
153 d = component_t(r);
154 }
155
156
157 void GGLAssembler::expand(integer_t& d, const component_t& s, int dbits)
158 {
159 if (s.l || (s.flags & CLEAR_HI)) {
160 extract(d, s.reg, s.h, s.l, 32);
161 expand(d, d, dbits);
162 } else {
163 expand(d, integer_t(s.reg, s.size(), s.flags), dbits);
164 }
165 }
166
167 void GGLAssembler::expand(component_t& d, const component_t& s, int dbits)
168 {
169 integer_t r(d.reg, 32, d.flags);
170 expand(r, s, dbits);
171 d = component_t(r);
172 }
173
174 void GGLAssembler::expand(integer_t& dst, const integer_t& src, int dbits)
175 {
176 assert(src.size());
177
178 int sbits = src.size();
179 int s = src.reg;
180 int d = dst.reg;
181
182 // be sure to set 'dst' after we read 'src' as they may be identical
183 dst.s = dbits;
184 dst.flags = 0;
185
186 if (dbits<=sbits) {
187 if (s != d) {
188 MOV(AL, 0, d, s);
189 }
190 return;
191 }
192
193 if (sbits == 1) {
194 RSB(AL, 0, d, s, reg_imm(s, LSL, dbits));
195 // d = (s<<dbits) - s;
196 return;
197 }
198
199 if (dbits % sbits) {
200 MOV(AL, 0, d, reg_imm(s, LSL, dbits-sbits));
201 // d = s << (dbits-sbits);
202 dbits -= sbits;
203 do {
204 ORR(AL, 0, d, d, reg_imm(d, LSR, sbits));
205 // d |= d >> sbits;
206 dbits -= sbits;
207 sbits *= 2;
208 } while(dbits>0);
209 return;
210 }
211
212 dbits -= sbits;
213 do {
214 ORR(AL, 0, d, s, reg_imm(s, LSL, sbits));
215 // d |= d<<sbits;
216 s = d;
217 dbits -= sbits;
218 if (sbits*2 < dbits) {
219 sbits *= 2;
220 }
221 } while(dbits>0);
222 }
223
224 void GGLAssembler::downshift(
225 pixel_t& d, int component, component_t s, const reg_t& dither)
226 {
227 const needs_t& needs = mBuilderContext.needs;
228 Scratch scratches(registerFile());
229
230 int sh = s.h;
231 int sl = s.l;
232 int maskHiBits = (sh!=32) ? ((s.flags & CLEAR_HI)?1:0) : 0;
233 int maskLoBits = (sl!=0) ? ((s.flags & CLEAR_LO)?1:0) : 0;
234 int sbits = sh - sl;
235
236 int dh = d.format.c[component].h;
237 int dl = d.format.c[component].l;
238 int dbits = dh - dl;
239 int dithering = 0;
240
241 LOGE_IF(sbits<dbits, "sbits (%d) < dbits (%d) in downshift", sbits, dbits);
242
243 if (sbits>dbits) {
244 // see if we need to dither
245 dithering = mDithering;
246 }
247
248 int ireg = d.reg;
249 if (!(d.flags & FIRST)) {
250 if (s.flags & CORRUPTIBLE) {
251 ireg = s.reg;
252 } else {
253 ireg = scratches.obtain();
254 }
255 }
256 d.flags &= ~FIRST;
257
258 if (maskHiBits) {
259 // we need to mask the high bits (and possibly the lowbits too)
260 // and we might be able to use immediate mask.
261 if (!dithering) {
262 // we don't do this if we only have maskLoBits because we can
263 // do it more efficiently below (in the case where dl=0)
264 const int offset = sh - dbits;
265 if (dbits<=8 && offset >= 0) {
266 const uint32_t mask = ((1<<dbits)-1) << offset;
267 if (isValidImmediate(mask) || isValidImmediate(~mask)) {
268 build_and_immediate(ireg, s.reg, mask, 32);
269 sl = offset;
270 s.reg = ireg;
271 sbits = dbits;
272 maskLoBits = maskHiBits = 0;
273 }
274 }
275 } else {
276 // in the dithering case though, we need to preserve the lower bits
277 const uint32_t mask = ((1<<sbits)-1) << sl;
278 if (isValidImmediate(mask) || isValidImmediate(~mask)) {
279 build_and_immediate(ireg, s.reg, mask, 32);
280 s.reg = ireg;
281 maskLoBits = maskHiBits = 0;
282 }
283 }
284 }
285
286 // XXX: we could special case (maskHiBits & !maskLoBits)
287 // like we do for maskLoBits below, but it happens very rarely
288 // that we have maskHiBits only and the conditions necessary to lead
289 // to better code (like doing d |= s << 24)
290
291 if (maskHiBits) {
292 MOV(AL, 0, ireg, reg_imm(s.reg, LSL, 32-sh));
293 sl += 32-sh;
294 sh = 32;
295 s.reg = ireg;
296 maskHiBits = 0;
297 }
298
299 // Downsampling should be performed as follows:
300 // V * ((1<<dbits)-1) / ((1<<sbits)-1)
301 // V * [(1<<dbits)/((1<<sbits)-1) - 1/((1<<sbits)-1)]
302 // V * [1/((1<<sbits)-1)>>dbits - 1/((1<<sbits)-1)]
303 // V/((1<<(sbits-dbits))-(1>>dbits)) - (V>>sbits)/((1<<sbits)-1)>>sbits
304 // V/((1<<(sbits-dbits))-(1>>dbits)) - (V>>sbits)/(1-(1>>sbits))
305 //
306 // By approximating (1>>dbits) and (1>>sbits) to 0:
307 //
308 // V>>(sbits-dbits) - V>>sbits
309 //
310 // A good approximation is V>>(sbits-dbits),
311 // but better one (needed for dithering) is:
312 //
313 // (V>>(sbits-dbits)<<sbits - V)>>sbits
314 // (V<<dbits - V)>>sbits
315 // (V - V>>dbits)>>(sbits-dbits)
316
317 // Dithering is done here
318 if (dithering) {
319 comment("dithering");
320 if (sl) {
321 MOV(AL, 0, ireg, reg_imm(s.reg, LSR, sl));
322 sh -= sl;
323 sl = 0;
324 s.reg = ireg;
325 }
326 // scaling (V-V>>dbits)
327 SUB(AL, 0, ireg, s.reg, reg_imm(s.reg, LSR, dbits));
328 const int shift = (GGL_DITHER_BITS - (sbits-dbits));
329 if (shift>0) ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSR, shift));
330 else if (shift<0) ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSL,-shift));
331 else ADD(AL, 0, ireg, ireg, dither.reg);
332 s.reg = ireg;
333 }
334
335 if ((maskLoBits|dithering) && (sh > dbits)) {
336 int shift = sh-dbits;
337 if (dl) {
338 MOV(AL, 0, ireg, reg_imm(s.reg, LSR, shift));
339 if (ireg == d.reg) {
340 MOV(AL, 0, d.reg, reg_imm(ireg, LSL, dl));
341 } else {
342 ORR(AL, 0, d.reg, d.reg, reg_imm(ireg, LSL, dl));
343 }
344 } else {
345 if (ireg == d.reg) {
346 MOV(AL, 0, d.reg, reg_imm(s.reg, LSR, shift));
347 } else {
348 ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSR, shift));
349 }
350 }
351 } else {
352 int shift = sh-dh;
353 if (shift>0) {
354 if (ireg == d.reg) {
355 MOV(AL, 0, d.reg, reg_imm(s.reg, LSR, shift));
356 } else {
357 ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSR, shift));
358 }
359 } else if (shift<0) {
360 if (ireg == d.reg) {
361 MOV(AL, 0, d.reg, reg_imm(s.reg, LSL, -shift));
362 } else {
363 ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSL, -shift));
364 }
365 } else {
366 if (ireg == d.reg) {
367 if (s.reg != d.reg) {
368 MOV(AL, 0, d.reg, s.reg);
369 }
370 } else {
371 ORR(AL, 0, d.reg, d.reg, s.reg);
372 }
373 }
374 }
375 }
376
377 }; // namespace android
+0
-1251
libpixelflinger/codeflinger/texturing.cpp less more
0 /* libs/pixelflinger/codeflinger/texturing.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22
23 #include <cutils/log.h>
24
25 #include "codeflinger/GGLAssembler.h"
26
27
28 namespace android {
29
30 // ---------------------------------------------------------------------------
31
32 // iterators are initialized like this:
33 // (intToFixedCenter(x) * dx)>>16 + x0
34 // ((x<<16 + 0x8000) * dx)>>16 + x0
35 // ((x<<16)*dx + (0x8000*dx))>>16 + x0
36 // ( (x*dx) + dx>>1 ) + x0
37 // (x*dx) + (dx>>1 + x0)
38
39 void GGLAssembler::init_iterated_color(fragment_parts_t& parts, const reg_t& x)
40 {
41 context_t const* c = mBuilderContext.c;
42 const needs_t& needs = mBuilderContext.needs;
43
44 if (mSmooth) {
45 // NOTE: we could take this case in the mDithering + !mSmooth case,
46 // but this would use up to 4 more registers for the color components
47 // for only a little added quality.
48 // Currently, this causes the system to run out of registers in
49 // some case (see issue #719496)
50
51 comment("compute initial iterated color (smooth and/or dither case)");
52
53 parts.iterated_packed = 0;
54 parts.packed = 0;
55
56 // 0x1: color component
57 // 0x2: iterators
58 const int optReload = mOptLevel >> 1;
59 if (optReload >= 3) parts.reload = 0; // reload nothing
60 else if (optReload == 2) parts.reload = 2; // reload iterators
61 else if (optReload == 1) parts.reload = 1; // reload colors
62 else if (optReload <= 0) parts.reload = 3; // reload both
63
64 if (!mSmooth) {
65 // we're not smoothing (just dithering), we never have to
66 // reload the iterators
67 parts.reload &= ~2;
68 }
69
70 Scratch scratches(registerFile());
71 const int t0 = (parts.reload & 1) ? scratches.obtain() : 0;
72 const int t1 = (parts.reload & 2) ? scratches.obtain() : 0;
73 for (int i=0 ; i<4 ; i++) {
74 if (!mInfo[i].iterated)
75 continue;
76
77 // this component exists in the destination and is not replaced
78 // by a texture unit.
79 const int c = (parts.reload & 1) ? t0 : obtainReg();
80 if (i==0) CONTEXT_LOAD(c, iterators.ydady);
81 if (i==1) CONTEXT_LOAD(c, iterators.ydrdy);
82 if (i==2) CONTEXT_LOAD(c, iterators.ydgdy);
83 if (i==3) CONTEXT_LOAD(c, iterators.ydbdy);
84 parts.argb[i].reg = c;
85
86 if (mInfo[i].smooth) {
87 parts.argb_dx[i].reg = (parts.reload & 2) ? t1 : obtainReg();
88 const int dvdx = parts.argb_dx[i].reg;
89 CONTEXT_LOAD(dvdx, generated_vars.argb[i].dx);
90 MLA(AL, 0, c, x.reg, dvdx, c);
91
92 // adjust the color iterator to make sure it won't overflow
93 if (!mAA) {
94 // this is not needed when we're using anti-aliasing
95 // because we will (have to) clamp the components
96 // anyway.
97 int end = scratches.obtain();
98 MOV(AL, 0, end, reg_imm(parts.count.reg, LSR, 16));
99 MLA(AL, 1, end, dvdx, end, c);
100 SUB(MI, 0, c, c, end);
101 BIC(AL, 0, c, c, reg_imm(c, ASR, 31));
102 scratches.recycle(end);
103 }
104 }
105
106 if (parts.reload & 1) {
107 CONTEXT_STORE(c, generated_vars.argb[i].c);
108 }
109 }
110 } else {
111 // We're not smoothed, so we can
112 // just use a packed version of the color and extract the
113 // components as needed (or not at all if we don't blend)
114
115 // figure out if we need the iterated color
116 int load = 0;
117 for (int i=0 ; i<4 ; i++) {
118 component_info_t& info = mInfo[i];
119 if ((info.inDest || info.needed) && !info.replaced)
120 load |= 1;
121 }
122
123 parts.iterated_packed = 1;
124 parts.packed = (!mTextureMachine.mask && !mBlending
125 && !mFog && !mDithering);
126 parts.reload = 0;
127 if (load || parts.packed) {
128 if (mBlending || mDithering || mInfo[GGLFormat::ALPHA].needed) {
129 comment("load initial iterated color (8888 packed)");
130 parts.iterated.setTo(obtainReg(),
131 &(c->formats[GGL_PIXEL_FORMAT_RGBA_8888]));
132 CONTEXT_LOAD(parts.iterated.reg, packed8888);
133 } else {
134 comment("load initial iterated color (dest format packed)");
135
136 parts.iterated.setTo(obtainReg(), &mCbFormat);
137
138 // pre-mask the iterated color
139 const int bits = parts.iterated.size();
140 const uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
141 uint32_t mask = 0;
142 if (mMasking) {
143 for (int i=0 ; i<4 ; i++) {
144 const int component_mask = 1<<i;
145 const int h = parts.iterated.format.c[i].h;
146 const int l = parts.iterated.format.c[i].l;
147 if (h && (!(mMasking & component_mask))) {
148 mask |= ((1<<(h-l))-1) << l;
149 }
150 }
151 }
152
153 if (mMasking && ((mask & size)==0)) {
154 // none of the components are present in the mask
155 } else {
156 CONTEXT_LOAD(parts.iterated.reg, packed);
157 if (mCbFormat.size == 1) {
158 AND(AL, 0, parts.iterated.reg,
159 parts.iterated.reg, imm(0xFF));
160 } else if (mCbFormat.size == 2) {
161 MOV(AL, 0, parts.iterated.reg,
162 reg_imm(parts.iterated.reg, LSR, 16));
163 }
164 }
165
166 // pre-mask the iterated color
167 if (mMasking) {
168 build_and_immediate(parts.iterated.reg, parts.iterated.reg,
169 mask, bits);
170 }
171 }
172 }
173 }
174 }
175
176 void GGLAssembler::build_iterated_color(
177 component_t& fragment,
178 const fragment_parts_t& parts,
179 int component,
180 Scratch& regs)
181 {
182 fragment.setTo( regs.obtain(), 0, 32, CORRUPTIBLE);
183
184 if (!mInfo[component].iterated)
185 return;
186
187 if (parts.iterated_packed) {
188 // iterated colors are packed, extract the one we need
189 extract(fragment, parts.iterated, component);
190 } else {
191 fragment.h = GGL_COLOR_BITS;
192 fragment.l = GGL_COLOR_BITS - 8;
193 fragment.flags |= CLEAR_LO;
194 // iterated colors are held in their own register,
195 // (smooth and/or dithering case)
196 if (parts.reload==3) {
197 // this implies mSmooth
198 Scratch scratches(registerFile());
199 int dx = scratches.obtain();
200 CONTEXT_LOAD(fragment.reg, generated_vars.argb[component].c);
201 CONTEXT_LOAD(dx, generated_vars.argb[component].dx);
202 ADD(AL, 0, dx, fragment.reg, dx);
203 CONTEXT_STORE(dx, generated_vars.argb[component].c);
204 } else if (parts.reload & 1) {
205 CONTEXT_LOAD(fragment.reg, generated_vars.argb[component].c);
206 } else {
207 // we don't reload, so simply rename the register and mark as
208 // non CORRUPTIBLE so that the texture env or blending code
209 // won't modify this (renamed) register
210 regs.recycle(fragment.reg);
211 fragment.reg = parts.argb[component].reg;
212 fragment.flags &= ~CORRUPTIBLE;
213 }
214 if (mInfo[component].smooth && mAA) {
215 // when using smooth shading AND anti-aliasing, we need to clamp
216 // the iterators because there is always an extra pixel on the
217 // edges, which most of the time will cause an overflow
218 // (since technically its outside of the domain).
219 BIC(AL, 0, fragment.reg, fragment.reg,
220 reg_imm(fragment.reg, ASR, 31));
221 component_sat(fragment);
222 }
223 }
224 }
225
226 // ---------------------------------------------------------------------------
227
228 void GGLAssembler::decodeLogicOpNeeds(const needs_t& needs)
229 {
230 // gather some informations about the components we need to process...
231 const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
232 switch(opcode) {
233 case GGL_COPY:
234 mLogicOp = 0;
235 break;
236 case GGL_CLEAR:
237 case GGL_SET:
238 mLogicOp = LOGIC_OP;
239 break;
240 case GGL_AND:
241 case GGL_AND_REVERSE:
242 case GGL_AND_INVERTED:
243 case GGL_XOR:
244 case GGL_OR:
245 case GGL_NOR:
246 case GGL_EQUIV:
247 case GGL_OR_REVERSE:
248 case GGL_OR_INVERTED:
249 case GGL_NAND:
250 mLogicOp = LOGIC_OP|LOGIC_OP_SRC|LOGIC_OP_DST;
251 break;
252 case GGL_NOOP:
253 case GGL_INVERT:
254 mLogicOp = LOGIC_OP|LOGIC_OP_DST;
255 break;
256 case GGL_COPY_INVERTED:
257 mLogicOp = LOGIC_OP|LOGIC_OP_SRC;
258 break;
259 };
260 }
261
262 void GGLAssembler::decodeTMUNeeds(const needs_t& needs, context_t const* c)
263 {
264 uint8_t replaced=0;
265 mTextureMachine.mask = 0;
266 mTextureMachine.activeUnits = 0;
267 for (int i=GGL_TEXTURE_UNIT_COUNT-1 ; i>=0 ; i--) {
268 texture_unit_t& tmu = mTextureMachine.tmu[i];
269 if (replaced == 0xF) {
270 // all components are replaced, skip this TMU.
271 tmu.format_idx = 0;
272 tmu.mask = 0;
273 tmu.replaced = replaced;
274 continue;
275 }
276 tmu.format_idx = GGL_READ_NEEDS(T_FORMAT, needs.t[i]);
277 tmu.format = c->formats[tmu.format_idx];
278 tmu.bits = tmu.format.size*8;
279 tmu.swrap = GGL_READ_NEEDS(T_S_WRAP, needs.t[i]);
280 tmu.twrap = GGL_READ_NEEDS(T_T_WRAP, needs.t[i]);
281 tmu.env = ggl_needs_to_env(GGL_READ_NEEDS(T_ENV, needs.t[i]));
282 tmu.pot = GGL_READ_NEEDS(T_POT, needs.t[i]);
283 tmu.linear = GGL_READ_NEEDS(T_LINEAR, needs.t[i])
284 && tmu.format.size!=3; // XXX: only 8, 16 and 32 modes for now
285
286 // 5551 linear filtering is not supported
287 if (tmu.format_idx == GGL_PIXEL_FORMAT_RGBA_5551)
288 tmu.linear = 0;
289
290 tmu.mask = 0;
291 tmu.replaced = replaced;
292
293 if (tmu.format_idx) {
294 mTextureMachine.activeUnits++;
295 if (tmu.format.c[0].h) tmu.mask |= 0x1;
296 if (tmu.format.c[1].h) tmu.mask |= 0x2;
297 if (tmu.format.c[2].h) tmu.mask |= 0x4;
298 if (tmu.format.c[3].h) tmu.mask |= 0x8;
299 if (tmu.env == GGL_REPLACE) {
300 replaced |= tmu.mask;
301 } else if (tmu.env == GGL_DECAL) {
302 if (!tmu.format.c[GGLFormat::ALPHA].h) {
303 // if we don't have alpha, decal does nothing
304 tmu.mask = 0;
305 } else {
306 // decal always ignores At
307 tmu.mask &= ~(1<<GGLFormat::ALPHA);
308 }
309 }
310 }
311 mTextureMachine.mask |= tmu.mask;
312 //printf("%d: mask=%08lx, replaced=%08lx\n",
313 // i, int(tmu.mask), int(tmu.replaced));
314 }
315 mTextureMachine.replaced = replaced;
316 mTextureMachine.directTexture = 0;
317 //printf("replaced=%08lx\n", mTextureMachine.replaced);
318 }
319
320
321 void GGLAssembler::init_textures(
322 tex_coord_t* coords,
323 const reg_t& x, const reg_t& y)
324 {
325 context_t const* c = mBuilderContext.c;
326 const needs_t& needs = mBuilderContext.needs;
327 int Rctx = mBuilderContext.Rctx;
328 int Rx = x.reg;
329 int Ry = y.reg;
330
331 if (mTextureMachine.mask) {
332 comment("compute texture coordinates");
333 }
334
335 // init texture coordinates for each tmu
336 const int cb_format_idx = GGL_READ_NEEDS(CB_FORMAT, needs.n);
337 const bool multiTexture = mTextureMachine.activeUnits > 1;
338 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
339 const texture_unit_t& tmu = mTextureMachine.tmu[i];
340 if (tmu.format_idx == 0)
341 continue;
342 if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
343 (tmu.twrap == GGL_NEEDS_WRAP_11))
344 {
345 // 1:1 texture
346 pointer_t& txPtr = coords[i].ptr;
347 txPtr.setTo(obtainReg(), tmu.bits);
348 CONTEXT_LOAD(txPtr.reg, state.texture[i].iterators.ydsdy);
349 ADD(AL, 0, Rx, Rx, reg_imm(txPtr.reg, ASR, 16)); // x += (s>>16)
350 CONTEXT_LOAD(txPtr.reg, state.texture[i].iterators.ydtdy);
351 ADD(AL, 0, Ry, Ry, reg_imm(txPtr.reg, ASR, 16)); // y += (t>>16)
352 // merge base & offset
353 CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].stride);
354 SMLABB(AL, Rx, Ry, txPtr.reg, Rx); // x+y*stride
355 CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].data);
356 base_offset(txPtr, txPtr, Rx);
357 } else {
358 Scratch scratches(registerFile());
359 reg_t& s = coords[i].s;
360 reg_t& t = coords[i].t;
361 // s = (x * dsdx)>>16 + ydsdy
362 // s = (x * dsdx)>>16 + (y*dsdy)>>16 + s0
363 // t = (x * dtdx)>>16 + ydtdy
364 // t = (x * dtdx)>>16 + (y*dtdy)>>16 + t0
365 s.setTo(obtainReg());
366 t.setTo(obtainReg());
367 const int need_w = GGL_READ_NEEDS(W, needs.n);
368 if (need_w) {
369 CONTEXT_LOAD(s.reg, state.texture[i].iterators.ydsdy);
370 CONTEXT_LOAD(t.reg, state.texture[i].iterators.ydtdy);
371 } else {
372 int ydsdy = scratches.obtain();
373 int ydtdy = scratches.obtain();
374 CONTEXT_LOAD(s.reg, generated_vars.texture[i].dsdx);
375 CONTEXT_LOAD(ydsdy, state.texture[i].iterators.ydsdy);
376 CONTEXT_LOAD(t.reg, generated_vars.texture[i].dtdx);
377 CONTEXT_LOAD(ydtdy, state.texture[i].iterators.ydtdy);
378 MLA(AL, 0, s.reg, Rx, s.reg, ydsdy);
379 MLA(AL, 0, t.reg, Rx, t.reg, ydtdy);
380 }
381
382 if ((mOptLevel&1)==0) {
383 CONTEXT_STORE(s.reg, generated_vars.texture[i].spill[0]);
384 CONTEXT_STORE(t.reg, generated_vars.texture[i].spill[1]);
385 recycleReg(s.reg);
386 recycleReg(t.reg);
387 }
388 }
389
390 // direct texture?
391 if (!multiTexture && !mBlending && !mDithering && !mFog &&
392 cb_format_idx == tmu.format_idx && !tmu.linear &&
393 mTextureMachine.replaced == tmu.mask)
394 {
395 mTextureMachine.directTexture = i + 1;
396 }
397 }
398 }
399
400 void GGLAssembler::build_textures( fragment_parts_t& parts,
401 Scratch& regs)
402 {
403 context_t const* c = mBuilderContext.c;
404 const needs_t& needs = mBuilderContext.needs;
405 int Rctx = mBuilderContext.Rctx;
406
407 // We don't have a way to spill registers automatically
408 // spill depth and AA regs, when we know we may have to.
409 // build the spill list...
410 uint32_t spill_list = 0;
411 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
412 const texture_unit_t& tmu = mTextureMachine.tmu[i];
413 if (tmu.format_idx == 0)
414 continue;
415 if (tmu.linear) {
416 // we may run out of register if we have linear filtering
417 // at 1 or 4 bytes / pixel on any texture unit.
418 if (tmu.format.size == 1) {
419 // if depth and AA enabled, we'll run out of 1 register
420 if (parts.z.reg > 0 && parts.covPtr.reg > 0)
421 spill_list |= 1<<parts.covPtr.reg;
422 }
423 if (tmu.format.size == 4) {
424 // if depth or AA enabled, we'll run out of 1 or 2 registers
425 if (parts.z.reg > 0)
426 spill_list |= 1<<parts.z.reg;
427 if (parts.covPtr.reg > 0)
428 spill_list |= 1<<parts.covPtr.reg;
429 }
430 }
431 }
432
433 Spill spill(registerFile(), *this, spill_list);
434
435 const bool multiTexture = mTextureMachine.activeUnits > 1;
436 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
437 const texture_unit_t& tmu = mTextureMachine.tmu[i];
438 if (tmu.format_idx == 0)
439 continue;
440
441 pointer_t& txPtr = parts.coords[i].ptr;
442 pixel_t& texel = parts.texel[i];
443
444 // repeat...
445 if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
446 (tmu.twrap == GGL_NEEDS_WRAP_11))
447 { // 1:1 textures
448 comment("fetch texel");
449 texel.setTo(regs.obtain(), &tmu.format);
450 load(txPtr, texel, WRITE_BACK);
451 } else {
452 Scratch scratches(registerFile());
453 reg_t& s = parts.coords[i].s;
454 reg_t& t = parts.coords[i].t;
455 if ((mOptLevel&1)==0) {
456 comment("reload s/t (multitexture or linear filtering)");
457 s.reg = scratches.obtain();
458 t.reg = scratches.obtain();
459 CONTEXT_LOAD(s.reg, generated_vars.texture[i].spill[0]);
460 CONTEXT_LOAD(t.reg, generated_vars.texture[i].spill[1]);
461 }
462
463 comment("compute repeat/clamp");
464 int u = scratches.obtain();
465 int v = scratches.obtain();
466 int width = scratches.obtain();
467 int height = scratches.obtain();
468 int U = 0;
469 int V = 0;
470
471 CONTEXT_LOAD(width, generated_vars.texture[i].width);
472 CONTEXT_LOAD(height, generated_vars.texture[i].height);
473
474 int FRAC_BITS = 0;
475 if (tmu.linear) {
476 // linear interpolation
477 if (tmu.format.size == 1) {
478 // for 8-bits textures, we can afford
479 // 7 bits of fractional precision at no
480 // additional cost (we can't do 8 bits
481 // because filter8 uses signed 16 bits muls)
482 FRAC_BITS = 7;
483 } else if (tmu.format.size == 2) {
484 // filter16() is internally limited to 4 bits, so:
485 // FRAC_BITS=2 generates less instructions,
486 // FRAC_BITS=3,4,5 creates unpleasant artifacts,
487 // FRAC_BITS=6+ looks good
488 FRAC_BITS = 6;
489 } else if (tmu.format.size == 4) {
490 // filter32() is internally limited to 8 bits, so:
491 // FRAC_BITS=4 looks good
492 // FRAC_BITS=5+ looks better, but generates 3 extra ipp
493 FRAC_BITS = 6;
494 } else {
495 // for all other cases we use 4 bits.
496 FRAC_BITS = 4;
497 }
498 }
499 wrapping(u, s.reg, width, tmu.swrap, FRAC_BITS);
500 wrapping(v, t.reg, height, tmu.twrap, FRAC_BITS);
501
502 if (tmu.linear) {
503 comment("compute linear filtering offsets");
504 // pixel size scale
505 const int shift = 31 - gglClz(tmu.format.size);
506 U = scratches.obtain();
507 V = scratches.obtain();
508
509 // sample the texel center
510 SUB(AL, 0, u, u, imm(1<<(FRAC_BITS-1)));
511 SUB(AL, 0, v, v, imm(1<<(FRAC_BITS-1)));
512
513 // get the fractionnal part of U,V
514 AND(AL, 0, U, u, imm((1<<FRAC_BITS)-1));
515 AND(AL, 0, V, v, imm((1<<FRAC_BITS)-1));
516
517 // compute width-1 and height-1
518 SUB(AL, 0, width, width, imm(1));
519 SUB(AL, 0, height, height, imm(1));
520
521 // get the integer part of U,V and clamp/wrap
522 // and compute offset to the next texel
523 if (tmu.swrap == GGL_NEEDS_WRAP_REPEAT) {
524 // u has already been REPEATed
525 MOV(AL, 1, u, reg_imm(u, ASR, FRAC_BITS));
526 MOV(MI, 0, u, width);
527 CMP(AL, u, width);
528 MOV(LT, 0, width, imm(1 << shift));
529 if (shift)
530 MOV(GE, 0, width, reg_imm(width, LSL, shift));
531 RSB(GE, 0, width, width, imm(0));
532 } else {
533 // u has not been CLAMPed yet
534 // algorithm:
535 // if ((u>>4) >= width)
536 // u = width<<4
537 // width = 0
538 // else
539 // width = 1<<shift
540 // u = u>>4; // get integer part
541 // if (u<0)
542 // u = 0
543 // width = 0
544 // generated_vars.rt = width
545
546 CMP(AL, width, reg_imm(u, ASR, FRAC_BITS));
547 MOV(LE, 0, u, reg_imm(width, LSL, FRAC_BITS));
548 MOV(LE, 0, width, imm(0));
549 MOV(GT, 0, width, imm(1 << shift));
550 MOV(AL, 1, u, reg_imm(u, ASR, FRAC_BITS));
551 MOV(MI, 0, u, imm(0));
552 MOV(MI, 0, width, imm(0));
553 }
554 CONTEXT_STORE(width, generated_vars.rt);
555
556 const int stride = width;
557 CONTEXT_LOAD(stride, generated_vars.texture[i].stride);
558 if (tmu.twrap == GGL_NEEDS_WRAP_REPEAT) {
559 // v has already been REPEATed
560 MOV(AL, 1, v, reg_imm(v, ASR, FRAC_BITS));
561 MOV(MI, 0, v, height);
562 CMP(AL, v, height);
563 MOV(LT, 0, height, imm(1 << shift));
564 if (shift)
565 MOV(GE, 0, height, reg_imm(height, LSL, shift));
566 RSB(GE, 0, height, height, imm(0));
567 MUL(AL, 0, height, stride, height);
568 } else {
569 // u has not been CLAMPed yet
570 CMP(AL, height, reg_imm(v, ASR, FRAC_BITS));
571 MOV(LE, 0, v, reg_imm(height, LSL, FRAC_BITS));
572 MOV(LE, 0, height, imm(0));
573 if (shift) {
574 MOV(GT, 0, height, reg_imm(stride, LSL, shift));
575 } else {
576 MOV(GT, 0, height, stride);
577 }
578 MOV(AL, 1, v, reg_imm(v, ASR, FRAC_BITS));
579 MOV(MI, 0, v, imm(0));
580 MOV(MI, 0, height, imm(0));
581 }
582 CONTEXT_STORE(height, generated_vars.lb);
583 }
584
585 scratches.recycle(width);
586 scratches.recycle(height);
587
588 // iterate texture coordinates...
589 comment("iterate s,t");
590 int dsdx = scratches.obtain();
591 int dtdx = scratches.obtain();
592 CONTEXT_LOAD(dsdx, generated_vars.texture[i].dsdx);
593 CONTEXT_LOAD(dtdx, generated_vars.texture[i].dtdx);
594 ADD(AL, 0, s.reg, s.reg, dsdx);
595 ADD(AL, 0, t.reg, t.reg, dtdx);
596 if ((mOptLevel&1)==0) {
597 CONTEXT_STORE(s.reg, generated_vars.texture[i].spill[0]);
598 CONTEXT_STORE(t.reg, generated_vars.texture[i].spill[1]);
599 scratches.recycle(s.reg);
600 scratches.recycle(t.reg);
601 }
602 scratches.recycle(dsdx);
603 scratches.recycle(dtdx);
604
605 // merge base & offset...
606 comment("merge base & offset");
607 texel.setTo(regs.obtain(), &tmu.format);
608 txPtr.setTo(texel.reg, tmu.bits);
609 int stride = scratches.obtain();
610 CONTEXT_LOAD(stride, generated_vars.texture[i].stride);
611 CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].data);
612 SMLABB(AL, u, v, stride, u); // u+v*stride
613 base_offset(txPtr, txPtr, u);
614
615 // load texel
616 if (!tmu.linear) {
617 comment("fetch texel");
618 load(txPtr, texel, 0);
619 } else {
620 // recycle registers we don't need anymore
621 scratches.recycle(u);
622 scratches.recycle(v);
623 scratches.recycle(stride);
624
625 comment("fetch texel, bilinear");
626 switch (tmu.format.size) {
627 case 1: filter8(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
628 case 2: filter16(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
629 case 3: filter24(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
630 case 4: filter32(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
631 }
632 }
633 }
634 }
635 }
636
637 void GGLAssembler::build_iterate_texture_coordinates(
638 const fragment_parts_t& parts)
639 {
640 const bool multiTexture = mTextureMachine.activeUnits > 1;
641 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
642 const texture_unit_t& tmu = mTextureMachine.tmu[i];
643 if (tmu.format_idx == 0)
644 continue;
645
646 if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
647 (tmu.twrap == GGL_NEEDS_WRAP_11))
648 { // 1:1 textures
649 const pointer_t& txPtr = parts.coords[i].ptr;
650 ADD(AL, 0, txPtr.reg, txPtr.reg, imm(txPtr.size>>3));
651 } else {
652 Scratch scratches(registerFile());
653 int s = parts.coords[i].s.reg;
654 int t = parts.coords[i].t.reg;
655 if ((mOptLevel&1)==0) {
656 s = scratches.obtain();
657 t = scratches.obtain();
658 CONTEXT_LOAD(s, generated_vars.texture[i].spill[0]);
659 CONTEXT_LOAD(t, generated_vars.texture[i].spill[1]);
660 }
661 int dsdx = scratches.obtain();
662 int dtdx = scratches.obtain();
663 CONTEXT_LOAD(dsdx, generated_vars.texture[i].dsdx);
664 CONTEXT_LOAD(dtdx, generated_vars.texture[i].dtdx);
665 ADD(AL, 0, s, s, dsdx);
666 ADD(AL, 0, t, t, dtdx);
667 if ((mOptLevel&1)==0) {
668 CONTEXT_STORE(s, generated_vars.texture[i].spill[0]);
669 CONTEXT_STORE(t, generated_vars.texture[i].spill[1]);
670 }
671 }
672 }
673 }
674
675 void GGLAssembler::filter8(
676 const fragment_parts_t& parts,
677 pixel_t& texel, const texture_unit_t& tmu,
678 int U, int V, pointer_t& txPtr,
679 int FRAC_BITS)
680 {
681 if (tmu.format.components != GGL_ALPHA &&
682 tmu.format.components != GGL_LUMINANCE)
683 {
684 // this is a packed format, and we don't support
685 // linear filtering (it's probably RGB 332)
686 // Should not happen with OpenGL|ES
687 LDRB(AL, texel.reg, txPtr.reg);
688 return;
689 }
690
691 // ------------------------
692 // about ~22 cycles / pixel
693 Scratch scratches(registerFile());
694
695 int pixel= scratches.obtain();
696 int d = scratches.obtain();
697 int u = scratches.obtain();
698 int k = scratches.obtain();
699 int rt = scratches.obtain();
700 int lb = scratches.obtain();
701
702 // RB -> U * V
703
704 CONTEXT_LOAD(rt, generated_vars.rt);
705 CONTEXT_LOAD(lb, generated_vars.lb);
706
707 int offset = pixel;
708 ADD(AL, 0, offset, lb, rt);
709 LDRB(AL, pixel, txPtr.reg, reg_scale_pre(offset));
710 SMULBB(AL, u, U, V);
711 SMULBB(AL, d, pixel, u);
712 RSB(AL, 0, k, u, imm(1<<(FRAC_BITS*2)));
713
714 // LB -> (1-U) * V
715 RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
716 LDRB(AL, pixel, txPtr.reg, reg_scale_pre(lb));
717 SMULBB(AL, u, U, V);
718 SMLABB(AL, d, pixel, u, d);
719 SUB(AL, 0, k, k, u);
720
721 // LT -> (1-U)*(1-V)
722 RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
723 LDRB(AL, pixel, txPtr.reg);
724 SMULBB(AL, u, U, V);
725 SMLABB(AL, d, pixel, u, d);
726
727 // RT -> U*(1-V)
728 LDRB(AL, pixel, txPtr.reg, reg_scale_pre(rt));
729 SUB(AL, 0, u, k, u);
730 SMLABB(AL, texel.reg, pixel, u, d);
731
732 for (int i=0 ; i<4 ; i++) {
733 if (!texel.format.c[i].h) continue;
734 texel.format.c[i].h = FRAC_BITS*2+8;
735 texel.format.c[i].l = FRAC_BITS*2; // keeping 8 bits in enough
736 }
737 texel.format.size = 4;
738 texel.format.bitsPerPixel = 32;
739 texel.flags |= CLEAR_LO;
740 }
741
742 void GGLAssembler::filter16(
743 const fragment_parts_t& parts,
744 pixel_t& texel, const texture_unit_t& tmu,
745 int U, int V, pointer_t& txPtr,
746 int FRAC_BITS)
747 {
748 // compute the mask
749 // XXX: it would be nice if the mask below could be computed
750 // automatically.
751 uint32_t mask = 0;
752 int shift = 0;
753 int prec = 0;
754 switch (tmu.format_idx) {
755 case GGL_PIXEL_FORMAT_RGB_565:
756 // source: 00000ggg.ggg00000 | rrrrr000.000bbbbb
757 // result: gggggggg.gggrrrrr | rrrrr0bb.bbbbbbbb
758 mask = 0x07E0F81F;
759 shift = 16;
760 prec = 5;
761 break;
762 case GGL_PIXEL_FORMAT_RGBA_4444:
763 // 0000,1111,0000,1111 | 0000,1111,0000,1111
764 mask = 0x0F0F0F0F;
765 shift = 12;
766 prec = 4;
767 break;
768 case GGL_PIXEL_FORMAT_LA_88:
769 // 0000,0000,1111,1111 | 0000,0000,1111,1111
770 // AALL -> 00AA | 00LL
771 mask = 0x00FF00FF;
772 shift = 8;
773 prec = 8;
774 break;
775 default:
776 // unsupported format, do something sensical...
777 LOGE("Unsupported 16-bits texture format (%d)", tmu.format_idx);
778 LDRH(AL, texel.reg, txPtr.reg);
779 return;
780 }
781
782 const int adjust = FRAC_BITS*2 - prec;
783 const int round = 0;
784
785 // update the texel format
786 texel.format.size = 4;
787 texel.format.bitsPerPixel = 32;
788 texel.flags |= CLEAR_HI|CLEAR_LO;
789 for (int i=0 ; i<4 ; i++) {
790 if (!texel.format.c[i].h) continue;
791 const uint32_t offset = (mask & tmu.format.mask(i)) ? 0 : shift;
792 texel.format.c[i].h = tmu.format.c[i].h + offset + prec;
793 texel.format.c[i].l = texel.format.c[i].h - (tmu.format.bits(i) + prec);
794 }
795
796 // ------------------------
797 // about ~40 cycles / pixel
798 Scratch scratches(registerFile());
799
800 int pixel= scratches.obtain();
801 int d = scratches.obtain();
802 int u = scratches.obtain();
803 int k = scratches.obtain();
804
805 // RB -> U * V
806 int offset = pixel;
807 CONTEXT_LOAD(offset, generated_vars.rt);
808 CONTEXT_LOAD(u, generated_vars.lb);
809 ADD(AL, 0, offset, offset, u);
810
811 LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
812 SMULBB(AL, u, U, V);
813 ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
814 build_and_immediate(pixel, pixel, mask, 32);
815 if (adjust) {
816 if (round)
817 ADD(AL, 0, u, u, imm(1<<(adjust-1)));
818 MOV(AL, 0, u, reg_imm(u, LSR, adjust));
819 }
820 MUL(AL, 0, d, pixel, u);
821 RSB(AL, 0, k, u, imm(1<<prec));
822
823 // LB -> (1-U) * V
824 CONTEXT_LOAD(offset, generated_vars.lb);
825 RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
826 LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
827 SMULBB(AL, u, U, V);
828 ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
829 build_and_immediate(pixel, pixel, mask, 32);
830 if (adjust) {
831 if (round)
832 ADD(AL, 0, u, u, imm(1<<(adjust-1)));
833 MOV(AL, 0, u, reg_imm(u, LSR, adjust));
834 }
835 MLA(AL, 0, d, pixel, u, d);
836 SUB(AL, 0, k, k, u);
837
838 // LT -> (1-U)*(1-V)
839 RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
840 LDRH(AL, pixel, txPtr.reg);
841 SMULBB(AL, u, U, V);
842 ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
843 build_and_immediate(pixel, pixel, mask, 32);
844 if (adjust) {
845 if (round)
846 ADD(AL, 0, u, u, imm(1<<(adjust-1)));
847 MOV(AL, 0, u, reg_imm(u, LSR, adjust));
848 }
849 MLA(AL, 0, d, pixel, u, d);
850
851 // RT -> U*(1-V)
852 CONTEXT_LOAD(offset, generated_vars.rt);
853 LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
854 SUB(AL, 0, u, k, u);
855 ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
856 build_and_immediate(pixel, pixel, mask, 32);
857 MLA(AL, 0, texel.reg, pixel, u, d);
858 }
859
860 void GGLAssembler::filter24(
861 const fragment_parts_t& parts,
862 pixel_t& texel, const texture_unit_t& tmu,
863 int U, int V, pointer_t& txPtr,
864 int FRAC_BITS)
865 {
866 // not supported yet (currently disabled)
867 load(txPtr, texel, 0);
868 }
869
870 void GGLAssembler::filter32(
871 const fragment_parts_t& parts,
872 pixel_t& texel, const texture_unit_t& tmu,
873 int U, int V, pointer_t& txPtr,
874 int FRAC_BITS)
875 {
876 const int adjust = FRAC_BITS*2 - 8;
877 const int round = 0;
878
879 // ------------------------
880 // about ~38 cycles / pixel
881 Scratch scratches(registerFile());
882
883 int pixel= scratches.obtain();
884 int dh = scratches.obtain();
885 int u = scratches.obtain();
886 int k = scratches.obtain();
887
888 int temp = scratches.obtain();
889 int dl = scratches.obtain();
890 int mask = scratches.obtain();
891
892 MOV(AL, 0, mask, imm(0xFF));
893 ORR(AL, 0, mask, mask, imm(0xFF0000));
894
895 // RB -> U * V
896 int offset = pixel;
897 CONTEXT_LOAD(offset, generated_vars.rt);
898 CONTEXT_LOAD(u, generated_vars.lb);
899 ADD(AL, 0, offset, offset, u);
900
901 LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
902 SMULBB(AL, u, U, V);
903 AND(AL, 0, temp, mask, pixel);
904 if (adjust) {
905 if (round)
906 ADD(AL, 0, u, u, imm(1<<(adjust-1)));
907 MOV(AL, 0, u, reg_imm(u, LSR, adjust));
908 }
909 MUL(AL, 0, dh, temp, u);
910 AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
911 MUL(AL, 0, dl, temp, u);
912 RSB(AL, 0, k, u, imm(0x100));
913
914 // LB -> (1-U) * V
915 CONTEXT_LOAD(offset, generated_vars.lb);
916 RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
917 LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
918 SMULBB(AL, u, U, V);
919 AND(AL, 0, temp, mask, pixel);
920 if (adjust) {
921 if (round)
922 ADD(AL, 0, u, u, imm(1<<(adjust-1)));
923 MOV(AL, 0, u, reg_imm(u, LSR, adjust));
924 }
925 MLA(AL, 0, dh, temp, u, dh);
926 AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
927 MLA(AL, 0, dl, temp, u, dl);
928 SUB(AL, 0, k, k, u);
929
930 // LT -> (1-U)*(1-V)
931 RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
932 LDR(AL, pixel, txPtr.reg);
933 SMULBB(AL, u, U, V);
934 AND(AL, 0, temp, mask, pixel);
935 if (adjust) {
936 if (round)
937 ADD(AL, 0, u, u, imm(1<<(adjust-1)));
938 MOV(AL, 0, u, reg_imm(u, LSR, adjust));
939 }
940 MLA(AL, 0, dh, temp, u, dh);
941 AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
942 MLA(AL, 0, dl, temp, u, dl);
943
944 // RT -> U*(1-V)
945 CONTEXT_LOAD(offset, generated_vars.rt);
946 LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
947 SUB(AL, 0, u, k, u);
948 AND(AL, 0, temp, mask, pixel);
949 MLA(AL, 0, dh, temp, u, dh);
950 AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
951 MLA(AL, 0, dl, temp, u, dl);
952
953 AND(AL, 0, dh, mask, reg_imm(dh, LSR, 8));
954 AND(AL, 0, dl, dl, reg_imm(mask, LSL, 8));
955 ORR(AL, 0, texel.reg, dh, dl);
956 }
957
958 void GGLAssembler::build_texture_environment(
959 component_t& fragment,
960 const fragment_parts_t& parts,
961 int component,
962 Scratch& regs)
963 {
964 const uint32_t component_mask = 1<<component;
965 const bool multiTexture = mTextureMachine.activeUnits > 1;
966 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
967 texture_unit_t& tmu = mTextureMachine.tmu[i];
968
969 if (tmu.mask & component_mask) {
970 // replace or modulate with this texture
971 if ((tmu.replaced & component_mask) == 0) {
972 // not replaced by a later tmu...
973
974 Scratch scratches(registerFile());
975 pixel_t texel(parts.texel[i]);
976 if (multiTexture &&
977 tmu.swrap == GGL_NEEDS_WRAP_11 &&
978 tmu.twrap == GGL_NEEDS_WRAP_11)
979 {
980 texel.reg = scratches.obtain();
981 texel.flags |= CORRUPTIBLE;
982 comment("fetch texel (multitexture 1:1)");
983 load(parts.coords[i].ptr, texel, WRITE_BACK);
984 }
985
986 component_t incoming(fragment);
987 modify(fragment, regs);
988
989 switch (tmu.env) {
990 case GGL_REPLACE:
991 extract(fragment, texel, component);
992 break;
993 case GGL_MODULATE:
994 modulate(fragment, incoming, texel, component);
995 break;
996 case GGL_DECAL:
997 decal(fragment, incoming, texel, component);
998 break;
999 case GGL_BLEND:
1000 blend(fragment, incoming, texel, component, i);
1001 break;
1002 case GGL_ADD:
1003 add(fragment, incoming, texel, component);
1004 break;
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011 // ---------------------------------------------------------------------------
1012
1013 void GGLAssembler::wrapping(
1014 int d,
1015 int coord, int size,
1016 int tx_wrap, int tx_linear)
1017 {
1018 // notes:
1019 // if tx_linear is set, we need 4 extra bits of precision on the result
1020 // SMULL/UMULL is 3 cycles
1021 Scratch scratches(registerFile());
1022 int c = coord;
1023 if (tx_wrap == GGL_NEEDS_WRAP_REPEAT) {
1024 // UMULL takes 4 cycles (interlocked), and we can get away with
1025 // 2 cycles using SMULWB, but we're loosing 16 bits of precision
1026 // out of 32 (this is not a problem because the iterator keeps
1027 // its full precision)
1028 // UMULL(AL, 0, size, d, c, size);
1029 // note: we can't use SMULTB because it's signed.
1030 MOV(AL, 0, d, reg_imm(c, LSR, 16-tx_linear));
1031 SMULWB(AL, d, d, size);
1032 } else if (tx_wrap == GGL_NEEDS_WRAP_CLAMP_TO_EDGE) {
1033 if (tx_linear) {
1034 // 1 cycle
1035 MOV(AL, 0, d, reg_imm(coord, ASR, 16-tx_linear));
1036 } else {
1037 // 4 cycles (common case)
1038 MOV(AL, 0, d, reg_imm(coord, ASR, 16));
1039 BIC(AL, 0, d, d, reg_imm(d, ASR, 31));
1040 CMP(AL, d, size);
1041 SUB(GE, 0, d, size, imm(1));
1042 }
1043 }
1044 }
1045
1046 // ---------------------------------------------------------------------------
1047
1048 void GGLAssembler::modulate(
1049 component_t& dest,
1050 const component_t& incoming,
1051 const pixel_t& incomingTexel, int component)
1052 {
1053 Scratch locals(registerFile());
1054 integer_t texel(locals.obtain(), 32, CORRUPTIBLE);
1055 extract(texel, incomingTexel, component);
1056
1057 const int Nt = texel.size();
1058 // Nt should always be less than 10 bits because it comes
1059 // from the TMU.
1060
1061 int Ni = incoming.size();
1062 // Ni could be big because it comes from previous MODULATEs
1063
1064 if (Nt == 1) {
1065 // texel acts as a bit-mask
1066 // dest = incoming & ((texel << incoming.h)-texel)
1067 RSB(AL, 0, dest.reg, texel.reg, reg_imm(texel.reg, LSL, incoming.h));
1068 AND(AL, 0, dest.reg, dest.reg, incoming.reg);
1069 dest.l = incoming.l;
1070 dest.h = incoming.h;
1071 dest.flags |= (incoming.flags & CLEAR_LO);
1072 } else if (Ni == 1) {
1073 MOV(AL, 0, dest.reg, reg_imm(incoming.reg, LSL, 31-incoming.h));
1074 AND(AL, 0, dest.reg, texel.reg, reg_imm(dest.reg, ASR, 31));
1075 dest.l = 0;
1076 dest.h = Nt;
1077 } else {
1078 int inReg = incoming.reg;
1079 int shift = incoming.l;
1080 if ((Nt + Ni) > 32) {
1081 // we will overflow, reduce the precision of Ni to 8 bits
1082 // (Note Nt cannot be more than 10 bits which happens with
1083 // 565 textures and GGL_LINEAR)
1084 shift += Ni-8;
1085 Ni = 8;
1086 }
1087
1088 // modulate by the component with the lowest precision
1089 if (Nt >= Ni) {
1090 if (shift) {
1091 // XXX: we should be able to avoid this shift
1092 // when shift==16 && Nt<16 && Ni<16, in which
1093 // we could use SMULBT below.
1094 MOV(AL, 0, dest.reg, reg_imm(inReg, LSR, shift));
1095 inReg = dest.reg;
1096 shift = 0;
1097 }
1098 // operation: (Cf*Ct)/((1<<Ni)-1)
1099 // approximated with: Cf*(Ct + Ct>>(Ni-1))>>Ni
1100 // this operation doesn't change texel's size
1101 ADD(AL, 0, dest.reg, inReg, reg_imm(inReg, LSR, Ni-1));
1102 if (Nt<16 && Ni<16) SMULBB(AL, dest.reg, texel.reg, dest.reg);
1103 else MUL(AL, 0, dest.reg, texel.reg, dest.reg);
1104 dest.l = Ni;
1105 dest.h = Nt + Ni;
1106 } else {
1107 if (shift && (shift != 16)) {
1108 // if shift==16, we can use 16-bits mul instructions later
1109 MOV(AL, 0, dest.reg, reg_imm(inReg, LSR, shift));
1110 inReg = dest.reg;
1111 shift = 0;
1112 }
1113 // operation: (Cf*Ct)/((1<<Nt)-1)
1114 // approximated with: Ct*(Cf + Cf>>(Nt-1))>>Nt
1115 // this operation doesn't change incoming's size
1116 Scratch scratches(registerFile());
1117 int t = (texel.flags & CORRUPTIBLE) ? texel.reg : dest.reg;
1118 if (t == inReg)
1119 t = scratches.obtain();
1120 ADD(AL, 0, t, texel.reg, reg_imm(texel.reg, LSR, Nt-1));
1121 if (Nt<16 && Ni<16) {
1122 if (shift==16) SMULBT(AL, dest.reg, t, inReg);
1123 else SMULBB(AL, dest.reg, t, inReg);
1124 } else MUL(AL, 0, dest.reg, t, inReg);
1125 dest.l = Nt;
1126 dest.h = Nt + Ni;
1127 }
1128
1129 // low bits are not valid
1130 dest.flags |= CLEAR_LO;
1131
1132 // no need to keep more than 8 bits/component
1133 if (dest.size() > 8)
1134 dest.l = dest.h-8;
1135 }
1136 }
1137
1138 void GGLAssembler::decal(
1139 component_t& dest,
1140 const component_t& incoming,
1141 const pixel_t& incomingTexel, int component)
1142 {
1143 // RGBA:
1144 // Cv = Cf*(1 - At) + Ct*At = Cf + (Ct - Cf)*At
1145 // Av = Af
1146 Scratch locals(registerFile());
1147 integer_t texel(locals.obtain(), 32, CORRUPTIBLE);
1148 integer_t factor(locals.obtain(), 32, CORRUPTIBLE);
1149 extract(texel, incomingTexel, component);
1150 extract(factor, incomingTexel, GGLFormat::ALPHA);
1151
1152 // no need to keep more than 8-bits for decal
1153 int Ni = incoming.size();
1154 int shift = incoming.l;
1155 if (Ni > 8) {
1156 shift += Ni-8;
1157 Ni = 8;
1158 }
1159 integer_t incomingNorm(incoming.reg, Ni, incoming.flags);
1160 if (shift) {
1161 MOV(AL, 0, dest.reg, reg_imm(incomingNorm.reg, LSR, shift));
1162 incomingNorm.reg = dest.reg;
1163 incomingNorm.flags |= CORRUPTIBLE;
1164 }
1165 ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1));
1166 build_blendOneMinusFF(dest, factor, incomingNorm, texel);
1167 }
1168
1169 void GGLAssembler::blend(
1170 component_t& dest,
1171 const component_t& incoming,
1172 const pixel_t& incomingTexel, int component, int tmu)
1173 {
1174 // RGBA:
1175 // Cv = (1 - Ct)*Cf + Ct*Cc = Cf + (Cc - Cf)*Ct
1176 // Av = At*Af
1177
1178 if (component == GGLFormat::ALPHA) {
1179 modulate(dest, incoming, incomingTexel, component);
1180 return;
1181 }
1182
1183 Scratch locals(registerFile());
1184 integer_t color(locals.obtain(), 8, CORRUPTIBLE);
1185 integer_t factor(locals.obtain(), 32, CORRUPTIBLE);
1186 LDRB(AL, color.reg, mBuilderContext.Rctx,
1187 immed12_pre(GGL_OFFSETOF(state.texture[tmu].env_color[component])));
1188 extract(factor, incomingTexel, component);
1189
1190 // no need to keep more than 8-bits for blend
1191 int Ni = incoming.size();
1192 int shift = incoming.l;
1193 if (Ni > 8) {
1194 shift += Ni-8;
1195 Ni = 8;
1196 }
1197 integer_t incomingNorm(incoming.reg, Ni, incoming.flags);
1198 if (shift) {
1199 MOV(AL, 0, dest.reg, reg_imm(incomingNorm.reg, LSR, shift));
1200 incomingNorm.reg = dest.reg;
1201 incomingNorm.flags |= CORRUPTIBLE;
1202 }
1203 ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1));
1204 build_blendOneMinusFF(dest, factor, incomingNorm, color);
1205 }
1206
1207 void GGLAssembler::add(
1208 component_t& dest,
1209 const component_t& incoming,
1210 const pixel_t& incomingTexel, int component)
1211 {
1212 // RGBA:
1213 // Cv = Cf + Ct;
1214 Scratch locals(registerFile());
1215
1216 component_t incomingTemp(incoming);
1217
1218 // use "dest" as a temporary for extracting the texel, unless "dest"
1219 // overlaps "incoming".
1220 integer_t texel(dest.reg, 32, CORRUPTIBLE);
1221 if (dest.reg == incomingTemp.reg)
1222 texel.reg = locals.obtain();
1223 extract(texel, incomingTexel, component);
1224
1225 if (texel.s < incomingTemp.size()) {
1226 expand(texel, texel, incomingTemp.size());
1227 } else if (texel.s > incomingTemp.size()) {
1228 if (incomingTemp.flags & CORRUPTIBLE) {
1229 expand(incomingTemp, incomingTemp, texel.s);
1230 } else {
1231 incomingTemp.reg = locals.obtain();
1232 expand(incomingTemp, incoming, texel.s);
1233 }
1234 }
1235
1236 if (incomingTemp.l) {
1237 ADD(AL, 0, dest.reg, texel.reg,
1238 reg_imm(incomingTemp.reg, LSR, incomingTemp.l));
1239 } else {
1240 ADD(AL, 0, dest.reg, texel.reg, incomingTemp.reg);
1241 }
1242 dest.l = 0;
1243 dest.h = texel.size();
1244 component_sat(dest);
1245 }
1246
1247 // ----------------------------------------------------------------------------
1248
1249 }; // namespace android
1250
+0
-339
libpixelflinger/fixed.cpp less more
0 /* libs/pixelflinger/fixed.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdio.h>
18
19 #include <private/pixelflinger/ggl_context.h>
20 #include <private/pixelflinger/ggl_fixed.h>
21
22
23 // ------------------------------------------------------------------------
24
25 int32_t gglRecipQNormalized(int32_t x, int* exponent)
26 {
27 const int32_t s = x>>31;
28 uint32_t a = s ? -x : x;
29
30 // the result will overflow, so just set it to the biggest/inf value
31 if (ggl_unlikely(a <= 2LU)) {
32 *exponent = 0;
33 return s ? FIXED_MIN : FIXED_MAX;
34 }
35
36 // Newton-Raphson iteration:
37 // x = r*(2 - a*r)
38
39 const int32_t lz = gglClz(a);
40 a <<= lz; // 0.32
41 uint32_t r = a;
42 // note: if a == 0x80000000, this means x was a power-of-2, in this
43 // case we don't need to compute anything. We get the reciprocal for
44 // (almost) free.
45 if (a != 0x80000000) {
46 r = (0x2E800 << (30-16)) - (r>>(2-1)); // 2.30, r = 2.90625 - 2*a
47 // 0.32 + 2.30 = 2.62 -> 2.30
48 // 2.30 + 2.30 = 4.60 -> 2.30
49 r = (((2LU<<30) - uint32_t((uint64_t(a)*r) >> 32)) * uint64_t(r)) >> 30;
50 r = (((2LU<<30) - uint32_t((uint64_t(a)*r) >> 32)) * uint64_t(r)) >> 30;
51 }
52
53 // shift right 1-bit to make room for the sign bit
54 *exponent = 30-lz-1;
55 r >>= 1;
56 return s ? -r : r;
57 }
58
59 int32_t gglRecipQ(GGLfixed x, int q)
60 {
61 int shift;
62 x = gglRecipQNormalized(x, &shift);
63 shift += 16-q;
64 x += 1L << (shift-1); // rounding
65 x >>= shift;
66 return x;
67 }
68
69 // ------------------------------------------------------------------------
70
71 GGLfixed gglFastDivx(GGLfixed n, GGLfixed d)
72 {
73 if ((d>>24) && ((d>>24)+1)) {
74 n >>= 8;
75 d >>= 8;
76 }
77 return gglMulx(n, gglRecip(d));
78 }
79
80 // ------------------------------------------------------------------------
81
82 static const GGLfixed ggl_sqrt_reciproc_approx_tab[8] = {
83 // 1/sqrt(x) with x = 1-N/16, N=[8...1]
84 0x16A09, 0x15555, 0x143D1, 0x134BF, 0x1279A, 0x11C01, 0x111AC, 0x10865
85 };
86
87 GGLfixed gglSqrtRecipx(GGLfixed x)
88 {
89 if (x == 0) return FIXED_MAX;
90 if (x == FIXED_ONE) return x;
91 const GGLfixed a = x;
92 const int32_t lz = gglClz(x);
93 x = ggl_sqrt_reciproc_approx_tab[(a>>(28-lz))&0x7];
94 const int32_t exp = lz - 16;
95 if (exp <= 0) x >>= -exp>>1;
96 else x <<= (exp>>1) + (exp & 1);
97 if (exp & 1) {
98 x = gglMulx(x, ggl_sqrt_reciproc_approx_tab[0])>>1;
99 }
100 // 2 Newton-Raphson iterations: x = x/2*(3-(a*x)*x)
101 x = gglMulx((x>>1),(0x30000 - gglMulx(gglMulx(a,x),x)));
102 x = gglMulx((x>>1),(0x30000 - gglMulx(gglMulx(a,x),x)));
103 return x;
104 }
105
106 GGLfixed gglSqrtx(GGLfixed a)
107 {
108 // Compute a full precision square-root (24 bits accuracy)
109 GGLfixed r = 0;
110 GGLfixed bit = 0x800000;
111 int32_t bshift = 15;
112 do {
113 GGLfixed temp = bit + (r<<1);
114 if (bshift >= 8) temp <<= (bshift-8);
115 else temp >>= (8-bshift);
116 if (a >= temp) {
117 r += bit;
118 a -= temp;
119 }
120 bshift--;
121 } while (bit>>=1);
122 return r;
123 }
124
125 // ------------------------------------------------------------------------
126
127 static const GGLfixed ggl_log_approx_tab[] = {
128 // -ln(x)/ln(2) with x = N/16, N=[8...16]
129 0xFFFF, 0xd47f, 0xad96, 0x8a62, 0x6a3f, 0x4caf, 0x3151, 0x17d6, 0x0000
130 };
131
132 static const GGLfixed ggl_alog_approx_tab[] = { // domain [0 - 1.0]
133 0xffff, 0xeac0, 0xd744, 0xc567, 0xb504, 0xa5fe, 0x9837, 0x8b95, 0x8000
134 };
135
136 GGLfixed gglPowx(GGLfixed x, GGLfixed y)
137 {
138 // prerequisite: 0 <= x <= 1, and y >=0
139
140 // pow(x,y) = 2^(y*log2(x))
141 // = 2^(y*log2(x*(2^exp)*(2^-exp))))
142 // = 2^(y*(log2(X)-exp))
143 // = 2^(log2(X)*y - y*exp)
144 // = 2^( - (-log2(X)*y + y*exp) )
145
146 int32_t exp = gglClz(x) - 16;
147 GGLfixed f = x << exp;
148 x = (f & 0x0FFF)<<4;
149 f = (f >> 12) & 0x7;
150 GGLfixed p = gglMulAddx(
151 ggl_log_approx_tab[f+1] - ggl_log_approx_tab[f], x,
152 ggl_log_approx_tab[f]);
153 p = gglMulAddx(p, y, y*exp);
154 exp = gglFixedToIntFloor(p);
155 if (exp < 31) {
156 p = gglFracx(p);
157 x = (p & 0x1FFF)<<3;
158 p >>= 13;
159 p = gglMulAddx(
160 ggl_alog_approx_tab[p+1] - ggl_alog_approx_tab[p], x,
161 ggl_alog_approx_tab[p]);
162 p >>= exp;
163 } else {
164 p = 0;
165 }
166 return p;
167 // ( powf((a*65536.0f), (b*65536.0f)) ) * 65536.0f;
168 }
169
170 // ------------------------------------------------------------------------
171
172 int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i)
173 {
174 //int32_t r =int32_t((int64_t(n)<<i)/d);
175 const int32_t ds = n^d;
176 if (n<0) n = -n;
177 if (d<0) d = -d;
178 int nd = gglClz(d) - gglClz(n);
179 i += nd + 1;
180 if (nd > 0) d <<= nd;
181 else n <<= -nd;
182 uint32_t q = 0;
183
184 int j = i & 7;
185 i >>= 3;
186
187 // gcc deals with the code below pretty well.
188 // we get 3.75 cycles per bit in the main loop
189 // and 8 cycles per bit in the termination loop
190 if (ggl_likely(i)) {
191 n -= d;
192 do {
193 q <<= 8;
194 if (n>=0) q |= 128;
195 else n += d;
196 n = n*2 - d;
197 if (n>=0) q |= 64;
198 else n += d;
199 n = n*2 - d;
200 if (n>=0) q |= 32;
201 else n += d;
202 n = n*2 - d;
203 if (n>=0) q |= 16;
204 else n += d;
205 n = n*2 - d;
206 if (n>=0) q |= 8;
207 else n += d;
208 n = n*2 - d;
209 if (n>=0) q |= 4;
210 else n += d;
211 n = n*2 - d;
212 if (n>=0) q |= 2;
213 else n += d;
214 n = n*2 - d;
215 if (n>=0) q |= 1;
216 else n += d;
217
218 if (--i == 0)
219 goto finish;
220
221 n = n*2 - d;
222 } while(true);
223 do {
224 q <<= 1;
225 n = n*2 - d;
226 if (n>=0) q |= 1;
227 else n += d;
228 finish: ;
229 } while (j--);
230 return (ds<0) ? -q : q;
231 }
232
233 n -= d;
234 if (n>=0) q |= 1;
235 else n += d;
236 j--;
237 goto finish;
238 }
239
240 // ------------------------------------------------------------------------
241
242 // assumes that the int32_t values of a, b, and c are all positive
243 // use when both a and b are larger than c
244
245 template <typename T>
246 static inline void swap(T& a, T& b) {
247 T t(a);
248 a = b;
249 b = t;
250 }
251
252 static __attribute__((noinline))
253 int32_t slow_muldiv(uint32_t a, uint32_t b, uint32_t c)
254 {
255 // first we compute a*b as a 64-bit integer
256 // (GCC generates umull with the code below)
257 uint64_t ab = uint64_t(a)*b;
258 uint32_t hi = ab>>32;
259 uint32_t lo = ab;
260 uint32_t result;
261
262 // now perform the division
263 if (hi >= c) {
264 overflow:
265 result = 0x7fffffff; // basic overflow
266 } else if (hi == 0) {
267 result = lo/c; // note: c can't be 0
268 if ((result >> 31) != 0) // result must fit in 31 bits
269 goto overflow;
270 } else {
271 uint32_t r = hi;
272 int bits = 31;
273 result = 0;
274 do {
275 r = (r << 1) | (lo >> 31);
276 lo <<= 1;
277 result <<= 1;
278 if (r >= c) {
279 r -= c;
280 result |= 1;
281 }
282 } while (bits--);
283 }
284 return int32_t(result);
285 }
286
287 // assumes a >= 0 and c >= b >= 0
288 static inline
289 int32_t quick_muldiv(int32_t a, int32_t b, int32_t c)
290 {
291 int32_t r = 0, q = 0, i;
292 int leading = gglClz(a);
293 i = 32 - leading;
294 a <<= leading;
295 do {
296 r <<= 1;
297 if (a < 0)
298 r += b;
299 a <<= 1;
300 q <<= 1;
301 if (r >= c) {
302 r -= c;
303 q++;
304 }
305 asm(""::); // gcc generates better code this way
306 if (r >= c) {
307 r -= c;
308 q++;
309 }
310 }
311 while (--i);
312 return q;
313 }
314
315 // this function computes a*b/c with 64-bit intermediate accuracy
316 // overflows (e.g. division by 0) are handled and return INT_MAX
317
318 int32_t gglMulDivi(int32_t a, int32_t b, int32_t c)
319 {
320 int32_t result;
321 int32_t sign = a^b^c;
322
323 if (a < 0) a = -a;
324 if (b < 0) b = -b;
325 if (c < 0) c = -c;
326
327 if (a < b) {
328 swap(a, b);
329 }
330
331 if (b <= c) result = quick_muldiv(a, b, c);
332 else result = slow_muldiv((uint32_t)a, (uint32_t)b, (uint32_t)c);
333
334 if (sign < 0)
335 result = -result;
336
337 return result;
338 }
+0
-67
libpixelflinger/format.cpp less more
0 /* libs/pixelflinger/format.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <pixelflinger/format.h>
19
20 namespace android {
21
22 static GGLFormat const gPixelFormatInfos[] =
23 { // Alpha Red Green Blue
24 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
25 { 4, 32, {{32,24, 8, 0, 16, 8, 24,16 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_8888
26 { 4, 24, {{ 0, 0, 8, 0, 16, 8, 24,16 }}, GGL_RGB }, // PIXEL_FORMAT_RGBX_8888
27 { 3, 24, {{ 0, 0, 8, 0, 16, 8, 24,16 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_888
28 { 2, 16, {{ 0, 0, 16,11, 11, 5, 5, 0 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_565
29 { 4, 32, {{32,24, 24,16, 16, 8, 8, 0 }}, GGL_RGBA }, // PIXEL_FORMAT_BGRA_8888
30 { 2, 16, {{ 1, 0, 16,11, 11, 6, 6, 1 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_5551
31 { 2, 16, {{ 4, 0, 16,12, 12, 8, 8, 4 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_4444
32 { 1, 8, {{ 8, 0, 0, 0, 0, 0, 0, 0 }}, GGL_ALPHA}, // PIXEL_FORMAT_A8
33 { 1, 8, {{ 0, 0, 8, 0, 8, 0, 8, 0 }}, GGL_LUMINANCE},//PIXEL_FORMAT_L8
34 { 2, 16, {{16, 8, 8, 0, 8, 0, 8, 0 }}, GGL_LUMINANCE_ALPHA},// PIXEL_FORMAT_LA_88
35 { 1, 8, {{ 0, 0, 8, 5, 5, 2, 2, 0 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_332
36
37 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
38 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
39 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
40 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
41
42 { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_SP },// PIXEL_FORMAT_YCbCr_422_SP
43 { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_SP },// PIXEL_FORMAT_YCbCr_420_SP
44 { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_P }, // PIXEL_FORMAT_YCbCr_422_P
45 { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_P }, // PIXEL_FORMAT_YCbCr_420_P
46 { 1, 16, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_I }, // PIXEL_FORMAT_YCbCr_422_I
47 { 1, 12, {{ 0, 8, 0, 8, 0, 8, 0, 0 }}, GGL_Y_CB_CR_I }, // PIXEL_FORMAT_YCbCr_420_I
48 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
49 { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
50
51 { 2, 16, {{ 0, 0, 16, 0, 0, 0, 0, 0 }}, GGL_DEPTH_COMPONENT},
52 { 1, 8, {{ 8, 0, 0, 0, 0, 0, 0, 0 }}, GGL_STENCIL_INDEX },
53 { 4, 24, {{ 0, 0, 24, 0, 0, 0, 0, 0 }}, GGL_DEPTH_COMPONENT},
54 { 4, 8, {{ 32,24, 0, 0, 0, 0, 0, 0 }}, GGL_STENCIL_INDEX },
55 };
56
57 }; // namespace android
58
59
60 const GGLFormat* gglGetPixelFormatTable(size_t* numEntries)
61 {
62 if (numEntries) {
63 *numEntries = sizeof(android::gPixelFormatInfos)/sizeof(GGLFormat);
64 }
65 return android::gPixelFormatInfos;
66 }
+0
-173
libpixelflinger/picker.cpp less more
0 /* libs/pixelflinger/picker.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #include <stdio.h>
19
20 #include "buffer.h"
21 #include "scanline.h"
22 #include "picker.h"
23
24 namespace android {
25
26 // ----------------------------------------------------------------------------
27
28 void ggl_init_picker(context_t* c)
29 {
30 }
31
32 void ggl_pick(context_t* c)
33 {
34 if (ggl_likely(!c->dirty))
35 return;
36
37 // compute needs, see if they changed...
38 const uint32_t enables = c->state.enables;
39 needs_t new_needs(c->state.needs);
40
41 if (c->dirty & GGL_CB_STATE) {
42 new_needs.n &= ~GGL_NEEDS_CB_FORMAT_MASK;
43 new_needs.n |= GGL_BUILD_NEEDS(c->state.buffers.color.format, CB_FORMAT);
44 if (enables & GGL_ENABLE_BLENDING)
45 c->dirty |= GGL_PIXEL_PIPELINE_STATE;
46 }
47
48 if (c->dirty & GGL_PIXEL_PIPELINE_STATE) {
49 uint32_t n = GGL_BUILD_NEEDS(c->state.buffers.color.format, CB_FORMAT);
50 uint32_t p = 0;
51 if (enables & GGL_ENABLE_BLENDING) {
52 uint32_t src = c->state.blend.src;
53 uint32_t dst = c->state.blend.dst;
54 uint32_t src_alpha = c->state.blend.src_alpha;
55 uint32_t dst_alpha = c->state.blend.dst_alpha;
56 const GGLFormat& cbf = c->formats[ c->state.buffers.color.format ];
57 if (!cbf.c[GGLFormat::ALPHA].h) {
58 if ((src == GGL_ONE_MINUS_DST_ALPHA) ||
59 (src == GGL_DST_ALPHA)) {
60 src = GGL_ONE;
61 }
62 if ((src_alpha == GGL_ONE_MINUS_DST_ALPHA) ||
63 (src_alpha == GGL_DST_ALPHA)) {
64 src_alpha = GGL_ONE;
65 }
66 if ((dst == GGL_ONE_MINUS_DST_ALPHA) ||
67 (dst == GGL_DST_ALPHA)) {
68 dst = GGL_ONE;
69 }
70 if ((dst_alpha == GGL_ONE_MINUS_DST_ALPHA) ||
71 (dst_alpha == GGL_DST_ALPHA)) {
72 dst_alpha = GGL_ONE;
73 }
74 }
75
76 src = ggl_blendfactor_to_needs(src);
77 dst = ggl_blendfactor_to_needs(dst);
78 src_alpha = ggl_blendfactor_to_needs(src_alpha);
79 dst_alpha = ggl_blendfactor_to_needs(dst_alpha);
80
81 n |= GGL_BUILD_NEEDS( src, BLEND_SRC );
82 n |= GGL_BUILD_NEEDS( dst, BLEND_DST );
83 if (c->state.blend.alpha_separate) {
84 n |= GGL_BUILD_NEEDS( src_alpha, BLEND_SRCA );
85 n |= GGL_BUILD_NEEDS( dst_alpha, BLEND_DSTA );
86 } else {
87 n |= GGL_BUILD_NEEDS( src, BLEND_SRCA );
88 n |= GGL_BUILD_NEEDS( dst, BLEND_DSTA );
89 }
90 } else {
91 n |= GGL_BUILD_NEEDS( GGL_ONE, BLEND_SRC );
92 n |= GGL_BUILD_NEEDS( GGL_ZERO, BLEND_DST );
93 n |= GGL_BUILD_NEEDS( GGL_ONE, BLEND_SRCA );
94 n |= GGL_BUILD_NEEDS( GGL_ZERO, BLEND_DSTA );
95 }
96
97
98 n |= GGL_BUILD_NEEDS(c->state.mask.color^0xF, MASK_ARGB);
99 n |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_SMOOTH) ?1:0, SHADE);
100 if (enables & GGL_ENABLE_TMUS) {
101 n |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_W) ?1:0, W);
102 }
103 p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_DITHER) ?1:0, P_DITHER);
104 p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_AA) ?1:0, P_AA);
105 p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_FOG) ?1:0, P_FOG);
106
107 if (enables & GGL_ENABLE_LOGIC_OP) {
108 n |= GGL_BUILD_NEEDS(c->state.logic_op.opcode, LOGIC_OP);
109 } else {
110 n |= GGL_BUILD_NEEDS(GGL_COPY, LOGIC_OP);
111 }
112
113 if (enables & GGL_ENABLE_ALPHA_TEST) {
114 p |= GGL_BUILD_NEEDS(c->state.alpha_test.func, P_ALPHA_TEST);
115 } else {
116 p |= GGL_BUILD_NEEDS(GGL_ALWAYS, P_ALPHA_TEST);
117 }
118
119 if (enables & GGL_ENABLE_DEPTH_TEST) {
120 p |= GGL_BUILD_NEEDS(c->state.depth_test.func, P_DEPTH_TEST);
121 p |= GGL_BUILD_NEEDS(c->state.mask.depth&1, P_MASK_Z);
122 } else {
123 p |= GGL_BUILD_NEEDS(GGL_ALWAYS, P_DEPTH_TEST);
124 // writing to the z-buffer is always disabled if depth-test
125 // is disabled.
126 }
127 new_needs.n = n;
128 new_needs.p = p;
129 }
130
131 if (c->dirty & GGL_TMU_STATE) {
132 int idx = 0;
133 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
134 const texture_t& tx = c->state.texture[i];
135 if (tx.enable) {
136 uint32_t t = 0;
137 t |= GGL_BUILD_NEEDS(tx.surface.format, T_FORMAT);
138 t |= GGL_BUILD_NEEDS(ggl_env_to_needs(tx.env), T_ENV);
139 t |= GGL_BUILD_NEEDS(0, T_POT); // XXX: not used yet
140 if (tx.s_coord==GGL_ONE_TO_ONE && tx.t_coord==GGL_ONE_TO_ONE) {
141 // we encode 1-to-1 into the wrap mode
142 t |= GGL_BUILD_NEEDS(GGL_NEEDS_WRAP_11, T_S_WRAP);
143 t |= GGL_BUILD_NEEDS(GGL_NEEDS_WRAP_11, T_T_WRAP);
144 } else {
145 t |= GGL_BUILD_NEEDS(ggl_wrap_to_needs(tx.s_wrap), T_S_WRAP);
146 t |= GGL_BUILD_NEEDS(ggl_wrap_to_needs(tx.t_wrap), T_T_WRAP);
147 }
148 if (tx.mag_filter == GGL_LINEAR) {
149 t |= GGL_BUILD_NEEDS(1, T_LINEAR);
150 }
151 if (tx.min_filter == GGL_LINEAR) {
152 t |= GGL_BUILD_NEEDS(1, T_LINEAR);
153 }
154 new_needs.t[idx++] = t;
155 } else {
156 new_needs.t[i] = 0;
157 }
158 }
159 }
160
161 if (new_needs != c->state.needs) {
162 c->state.needs = new_needs;
163 ggl_pick_texture(c);
164 ggl_pick_cb(c);
165 ggl_pick_scanline(c);
166 }
167 c->dirty = 0;
168 }
169
170 // ----------------------------------------------------------------------------
171 }; // namespace android
172
+0
-31
libpixelflinger/picker.h less more
0 /* libs/pixelflinger/picker.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_PICKER_H
19 #define ANDROID_PICKER_H
20
21 #include <private/pixelflinger/ggl_context.h>
22
23 namespace android {
24
25 void ggl_init_picker(context_t* c);
26 void ggl_pick(context_t* c);
27
28 }; // namespace android
29
30 #endif
+0
-843
libpixelflinger/pixelflinger.cpp less more
0 /* libs/pixelflinger/pixelflinger.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <assert.h>
21
22 #include <sys/time.h>
23
24 #include <pixelflinger/pixelflinger.h>
25 #include <private/pixelflinger/ggl_context.h>
26
27 #include "buffer.h"
28 #include "clear.h"
29 #include "picker.h"
30 #include "raster.h"
31 #include "scanline.h"
32 #include "trap.h"
33
34 #include "codeflinger/GGLAssembler.h"
35 #include "codeflinger/CodeCache.h"
36
37 #include <stdio.h>
38
39
40 namespace android {
41
42 // ----------------------------------------------------------------------------
43
44 // 8x8 Bayer dither matrix
45 static const uint8_t gDitherMatrix[GGL_DITHER_SIZE] = {
46 0, 32, 8, 40, 2, 34, 10, 42,
47 48, 16, 56, 24, 50, 18, 58, 26,
48 12, 44, 4, 36, 14, 46, 6, 38,
49 60, 28, 52, 20, 62, 30, 54, 22,
50 3, 35, 11, 43, 1, 33, 9, 41,
51 51, 19, 59, 27, 49, 17, 57, 25,
52 15, 47, 7, 39, 13, 45, 5, 37,
53 63, 31, 55, 23, 61, 29, 53, 21
54 };
55
56 static void ggl_init_procs(context_t* c);
57 static void ggl_set_scissor(context_t* c);
58
59 static void ggl_enable_blending(context_t* c, int enable);
60 static void ggl_enable_scissor_test(context_t* c, int enable);
61 static void ggl_enable_alpha_test(context_t* c, int enable);
62 static void ggl_enable_logic_op(context_t* c, int enable);
63 static void ggl_enable_dither(context_t* c, int enable);
64 static void ggl_enable_stencil_test(context_t* c, int enable);
65 static void ggl_enable_depth_test(context_t* c, int enable);
66 static void ggl_enable_aa(context_t* c, int enable);
67 static void ggl_enable_point_aa_nice(context_t* c, int enable);
68 static void ggl_enable_texture2d(context_t* c, int enable);
69 static void ggl_enable_w_lerp(context_t* c, int enable);
70 static void ggl_enable_fog(context_t* c, int enable);
71
72 static inline int min(int a, int b) CONST;
73 static inline int min(int a, int b) {
74 return a < b ? a : b;
75 }
76
77 static inline int max(int a, int b) CONST;
78 static inline int max(int a, int b) {
79 return a < b ? b : a;
80 }
81
82 // ----------------------------------------------------------------------------
83
84 void ggl_error(context_t* c, GGLenum error)
85 {
86 if (c->error == GGL_NO_ERROR)
87 c->error = error;
88 }
89
90 // ----------------------------------------------------------------------------
91
92 static void ggl_bindTexture(void* con, const GGLSurface* surface)
93 {
94 GGL_CONTEXT(c, con);
95 if (surface->format != c->activeTMU->surface.format)
96 ggl_state_changed(c, GGL_TMU_STATE);
97 ggl_set_surface(c, &(c->activeTMU->surface), surface);
98 }
99
100
101 static void ggl_bindTextureLod(void* con, GGLuint tmu,const GGLSurface* surface)
102 {
103 GGL_CONTEXT(c, con);
104 // All LODs must have the same format
105 ggl_set_surface(c, &c->state.texture[tmu].surface, surface);
106 }
107
108 static void ggl_colorBuffer(void* con, const GGLSurface* surface)
109 {
110 GGL_CONTEXT(c, con);
111 if (surface->format != c->state.buffers.color.format)
112 ggl_state_changed(c, GGL_CB_STATE);
113
114 if (surface->width > c->state.buffers.coverageBufferSize) {
115 // allocate the coverage factor buffer
116 free(c->state.buffers.coverage);
117 c->state.buffers.coverage = (int16_t*)malloc(surface->width * 2);
118 c->state.buffers.coverageBufferSize =
119 c->state.buffers.coverage ? surface->width : 0;
120 }
121 ggl_set_surface(c, &(c->state.buffers.color), surface);
122 if (c->state.buffers.read.format == 0) {
123 ggl_set_surface(c, &(c->state.buffers.read), surface);
124 }
125 ggl_set_scissor(c);
126 }
127
128 static void ggl_readBuffer(void* con, const GGLSurface* surface)
129 {
130 GGL_CONTEXT(c, con);
131 ggl_set_surface(c, &(c->state.buffers.read), surface);
132 }
133
134 static void ggl_depthBuffer(void* con, const GGLSurface* surface)
135 {
136 GGL_CONTEXT(c, con);
137 if (surface->format == GGL_PIXEL_FORMAT_Z_16) {
138 ggl_set_surface(c, &(c->state.buffers.depth), surface);
139 } else {
140 c->state.buffers.depth.format = GGL_PIXEL_FORMAT_NONE;
141 ggl_enable_depth_test(c, 0);
142 }
143 }
144
145 static void ggl_scissor(void* con, GGLint x, GGLint y,
146 GGLsizei width, GGLsizei height)
147 {
148 GGL_CONTEXT(c, con);
149 c->state.scissor.user_left = x;
150 c->state.scissor.user_top = y;
151 c->state.scissor.user_right = x + width;
152 c->state.scissor.user_bottom = y + height;
153 ggl_set_scissor(c);
154 }
155
156 // ----------------------------------------------------------------------------
157
158 static void enable_disable(context_t* c, GGLenum name, int en)
159 {
160 switch (name) {
161 case GGL_BLEND: ggl_enable_blending(c, en); break;
162 case GGL_SCISSOR_TEST: ggl_enable_scissor_test(c, en); break;
163 case GGL_ALPHA_TEST: ggl_enable_alpha_test(c, en); break;
164 case GGL_COLOR_LOGIC_OP: ggl_enable_logic_op(c, en); break;
165 case GGL_DITHER: ggl_enable_dither(c, en); break;
166 case GGL_STENCIL_TEST: ggl_enable_stencil_test(c, en); break;
167 case GGL_DEPTH_TEST: ggl_enable_depth_test(c, en); break;
168 case GGL_AA: ggl_enable_aa(c, en); break;
169 case GGL_TEXTURE_2D: ggl_enable_texture2d(c, en); break;
170 case GGL_W_LERP: ggl_enable_w_lerp(c, en); break;
171 case GGL_FOG: ggl_enable_fog(c, en); break;
172 case GGL_POINT_SMOOTH_NICE: ggl_enable_point_aa_nice(c, en); break;
173 }
174 }
175
176 static void ggl_enable(void* con, GGLenum name)
177 {
178 GGL_CONTEXT(c, con);
179 enable_disable(c, name, 1);
180 }
181
182 static void ggl_disable(void* con, GGLenum name)
183 {
184 GGL_CONTEXT(c, con);
185 enable_disable(c, name, 0);
186 }
187
188 static void ggl_enableDisable(void* con, GGLenum name, GGLboolean en)
189 {
190 GGL_CONTEXT(c, con);
191 enable_disable(c, name, en ? 1 : 0);
192 }
193
194 // ----------------------------------------------------------------------------
195
196 static void ggl_shadeModel(void* con, GGLenum mode)
197 {
198 GGL_CONTEXT(c, con);
199 switch (mode) {
200 case GGL_FLAT:
201 if (c->state.enables & GGL_ENABLE_SMOOTH) {
202 c->state.enables &= ~GGL_ENABLE_SMOOTH;
203 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
204 }
205 break;
206 case GGL_SMOOTH:
207 if (!(c->state.enables & GGL_ENABLE_SMOOTH)) {
208 c->state.enables |= GGL_ENABLE_SMOOTH;
209 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
210 }
211 break;
212 default:
213 ggl_error(c, GGL_INVALID_ENUM);
214 }
215 }
216
217 static void ggl_color4xv(void* con, const GGLclampx* color)
218 {
219 GGL_CONTEXT(c, con);
220 c->shade.r0 = gglFixedToIteratedColor(color[0]);
221 c->shade.g0 = gglFixedToIteratedColor(color[1]);
222 c->shade.b0 = gglFixedToIteratedColor(color[2]);
223 c->shade.a0 = gglFixedToIteratedColor(color[3]);
224 }
225
226 static void ggl_colorGrad12xv(void* con, const GGLcolor* grad)
227 {
228 GGL_CONTEXT(c, con);
229 // it is very important to round the iterated value here because
230 // the rasterizer doesn't clamp them, therefore the iterated value
231 //must absolutely be correct.
232 // GGLColor is encoded as 8.16 value
233 const int32_t round = 0x8000;
234 c->shade.r0 = grad[ 0] + round;
235 c->shade.drdx = grad[ 1];
236 c->shade.drdy = grad[ 2];
237 c->shade.g0 = grad[ 3] + round;
238 c->shade.dgdx = grad[ 4];
239 c->shade.dgdy = grad[ 5];
240 c->shade.b0 = grad[ 6] + round;
241 c->shade.dbdx = grad[ 7];
242 c->shade.dbdy = grad[ 8];
243 c->shade.a0 = grad[ 9] + round;
244 c->shade.dadx = grad[10];
245 c->shade.dady = grad[11];
246 }
247
248 static void ggl_zGrad3xv(void* con, const GGLfixed32* grad)
249 {
250 GGL_CONTEXT(c, con);
251 // z iterators are encoded as 0.32 fixed point and the z-buffer
252 // holds 16 bits, the rounding value is 0x8000.
253 const uint32_t round = 0x8000;
254 c->shade.z0 = grad[0] + round;
255 c->shade.dzdx = grad[1];
256 c->shade.dzdy = grad[2];
257 }
258
259 static void ggl_wGrad3xv(void* con, const GGLfixed* grad)
260 {
261 GGL_CONTEXT(c, con);
262 c->shade.w0 = grad[0];
263 c->shade.dwdx = grad[1];
264 c->shade.dwdy = grad[2];
265 }
266
267 // ----------------------------------------------------------------------------
268
269 static void ggl_fogGrad3xv(void* con, const GGLfixed* grad)
270 {
271 GGL_CONTEXT(c, con);
272 c->shade.f0 = grad[0];
273 c->shade.dfdx = grad[1];
274 c->shade.dfdy = grad[2];
275 }
276
277 static void ggl_fogColor3xv(void* con, const GGLclampx* color)
278 {
279 GGL_CONTEXT(c, con);
280 const int32_t r = gglClampx(color[0]);
281 const int32_t g = gglClampx(color[1]);
282 const int32_t b = gglClampx(color[2]);
283 c->state.fog.color[GGLFormat::RED] = (r - (r>>8))>>8;
284 c->state.fog.color[GGLFormat::GREEN]= (g - (g>>8))>>8;
285 c->state.fog.color[GGLFormat::BLUE] = (b - (b>>8))>>8;
286 }
287
288 static void ggl_enable_fog(context_t* c, int enable)
289 {
290 const int e = (c->state.enables & GGL_ENABLE_FOG)?1:0;
291 if (e != enable) {
292 if (enable) c->state.enables |= GGL_ENABLE_FOG;
293 else c->state.enables &= ~GGL_ENABLE_FOG;
294 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
295 }
296 }
297
298 // ----------------------------------------------------------------------------
299
300 static void ggl_blendFunc(void* con, GGLenum src, GGLenum dst)
301 {
302 GGL_CONTEXT(c, con);
303 c->state.blend.src = src;
304 c->state.blend.src_alpha = src;
305 c->state.blend.dst = dst;
306 c->state.blend.dst_alpha = dst;
307 c->state.blend.alpha_separate = 0;
308 if (c->state.enables & GGL_ENABLE_BLENDING) {
309 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
310 }
311 }
312
313 static void ggl_blendFuncSeparate(void* con,
314 GGLenum src, GGLenum dst,
315 GGLenum srcAlpha, GGLenum dstAplha)
316 {
317 GGL_CONTEXT(c, con);
318 c->state.blend.src = src;
319 c->state.blend.src_alpha = srcAlpha;
320 c->state.blend.dst = dst;
321 c->state.blend.dst_alpha = dstAplha;
322 c->state.blend.alpha_separate = 1;
323 if (c->state.enables & GGL_ENABLE_BLENDING) {
324 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
325 }
326 }
327
328 // ----------------------------------------------------------------------------
329
330 static void ggl_texEnvi(void* con, GGLenum target,
331 GGLenum pname,
332 GGLint param)
333 {
334 GGL_CONTEXT(c, con);
335 if (target != GGL_TEXTURE_ENV || pname != GGL_TEXTURE_ENV_MODE) {
336 ggl_error(c, GGL_INVALID_ENUM);
337 return;
338 }
339 switch (param) {
340 case GGL_REPLACE:
341 case GGL_MODULATE:
342 case GGL_DECAL:
343 case GGL_BLEND:
344 case GGL_ADD:
345 if (c->activeTMU->env != param) {
346 c->activeTMU->env = param;
347 ggl_state_changed(c, GGL_TMU_STATE);
348 }
349 break;
350 default:
351 ggl_error(c, GGL_INVALID_ENUM);
352 }
353 }
354
355 static void ggl_texEnvxv(void* con, GGLenum target,
356 GGLenum pname, const GGLfixed* params)
357 {
358 GGL_CONTEXT(c, con);
359 if (target != GGL_TEXTURE_ENV) {
360 ggl_error(c, GGL_INVALID_ENUM);
361 return;
362 }
363 switch (pname) {
364 case GGL_TEXTURE_ENV_MODE:
365 ggl_texEnvi(con, target, pname, params[0]);
366 break;
367 case GGL_TEXTURE_ENV_COLOR: {
368 uint8_t* const color = c->activeTMU->env_color;
369 const GGLclampx r = gglClampx(params[0]);
370 const GGLclampx g = gglClampx(params[1]);
371 const GGLclampx b = gglClampx(params[2]);
372 const GGLclampx a = gglClampx(params[3]);
373 color[0] = (a-(a>>8))>>8;
374 color[1] = (r-(r>>8))>>8;
375 color[2] = (g-(g>>8))>>8;
376 color[3] = (b-(b>>8))>>8;
377 break;
378 }
379 default:
380 ggl_error(c, GGL_INVALID_ENUM);
381 return;
382 }
383 }
384
385
386 static void ggl_texParameteri(void* con,
387 GGLenum target,
388 GGLenum pname,
389 GGLint param)
390 {
391 GGL_CONTEXT(c, con);
392 if (target != GGL_TEXTURE_2D) {
393 ggl_error(c, GGL_INVALID_ENUM);
394 return;
395 }
396
397 if (param == GGL_CLAMP_TO_EDGE)
398 param = GGL_CLAMP;
399
400 uint16_t* what = 0;
401 switch (pname) {
402 case GGL_TEXTURE_WRAP_S:
403 if ((param == GGL_CLAMP) ||
404 (param == GGL_REPEAT)) {
405 what = &c->activeTMU->s_wrap;
406 }
407 break;
408 case GGL_TEXTURE_WRAP_T:
409 if ((param == GGL_CLAMP) ||
410 (param == GGL_REPEAT)) {
411 what = &c->activeTMU->t_wrap;
412 }
413 break;
414 case GGL_TEXTURE_MIN_FILTER:
415 if ((param == GGL_NEAREST) ||
416 (param == GGL_NEAREST_MIPMAP_NEAREST) ||
417 (param == GGL_NEAREST_MIPMAP_LINEAR)) {
418 what = &c->activeTMU->min_filter;
419 param = GGL_NEAREST;
420 }
421 if ((param == GGL_LINEAR) ||
422 (param == GGL_LINEAR_MIPMAP_NEAREST) ||
423 (param == GGL_LINEAR_MIPMAP_LINEAR)) {
424 what = &c->activeTMU->min_filter;
425 param = GGL_LINEAR;
426 }
427 break;
428 case GGL_TEXTURE_MAG_FILTER:
429 if ((param == GGL_NEAREST) ||
430 (param == GGL_LINEAR)) {
431 what = &c->activeTMU->mag_filter;
432 }
433 break;
434 }
435
436 if (!what) {
437 ggl_error(c, GGL_INVALID_ENUM);
438 return;
439 }
440
441 if (*what != param) {
442 *what = param;
443 ggl_state_changed(c, GGL_TMU_STATE);
444 }
445 }
446
447 static void ggl_texCoordGradScale8xv(void* con, GGLint tmu, const int32_t* grad)
448 {
449 GGL_CONTEXT(c, con);
450 texture_t& u = c->state.texture[tmu];
451 u.shade.is0 = grad[0];
452 u.shade.idsdx = grad[1];
453 u.shade.idsdy = grad[2];
454 u.shade.it0 = grad[3];
455 u.shade.idtdx = grad[4];
456 u.shade.idtdy = grad[5];
457 u.shade.sscale= grad[6];
458 u.shade.tscale= grad[7];
459 }
460
461 static void ggl_texCoord2x(void* con, GGLfixed s, GGLfixed t)
462 {
463 GGL_CONTEXT(c, con);
464 c->activeTMU->shade.is0 = s;
465 c->activeTMU->shade.it0 = t;
466 c->activeTMU->shade.sscale= 0;
467 c->activeTMU->shade.tscale= 0;
468 }
469
470 static void ggl_texCoord2i(void* con, GGLint s, GGLint t)
471 {
472 ggl_texCoord2x(con, s<<16, t<<16);
473 }
474
475 static void ggl_texGeni(void* con, GGLenum coord, GGLenum pname, GGLint param)
476 {
477 GGL_CONTEXT(c, con);
478 if (pname != GGL_TEXTURE_GEN_MODE) {
479 ggl_error(c, GGL_INVALID_ENUM);
480 return;
481 }
482
483 uint32_t* coord_ptr = 0;
484 if (coord == GGL_S) coord_ptr = &(c->activeTMU->s_coord);
485 else if (coord == GGL_T) coord_ptr = &(c->activeTMU->t_coord);
486
487 if (coord_ptr) {
488 if (*coord_ptr != uint32_t(param)) {
489 *coord_ptr = uint32_t(param);
490 ggl_state_changed(c, GGL_TMU_STATE);
491 }
492 } else {
493 ggl_error(c, GGL_INVALID_ENUM);
494 }
495 }
496
497 static void ggl_activeTexture(void* con, GGLuint tmu)
498 {
499 GGL_CONTEXT(c, con);
500 if (tmu >= GGLuint(GGL_TEXTURE_UNIT_COUNT)) {
501 ggl_error(c, GGL_INVALID_ENUM);
502 return;
503 }
504 c->activeTMUIndex = tmu;
505 c->activeTMU = &(c->state.texture[tmu]);
506 }
507
508 // ----------------------------------------------------------------------------
509
510 static void ggl_colorMask(void* con, GGLboolean r,
511 GGLboolean g,
512 GGLboolean b,
513 GGLboolean a)
514 {
515 GGL_CONTEXT(c, con);
516 int mask = 0;
517 if (a) mask |= 1 << GGLFormat::ALPHA;
518 if (r) mask |= 1 << GGLFormat::RED;
519 if (g) mask |= 1 << GGLFormat::GREEN;
520 if (b) mask |= 1 << GGLFormat::BLUE;
521 if (c->state.mask.color != mask) {
522 c->state.mask.color = mask;
523 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
524 }
525 }
526
527 static void ggl_depthMask(void* con, GGLboolean flag)
528 {
529 GGL_CONTEXT(c, con);
530 if (c->state.mask.depth != flag?1:0) {
531 c->state.mask.depth = flag?1:0;
532 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
533 }
534 }
535
536 static void ggl_stencilMask(void* con, GGLuint mask)
537 {
538 GGL_CONTEXT(c, con);
539 if (c->state.mask.stencil != mask) {
540 c->state.mask.stencil = mask;
541 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
542 }
543 }
544
545 // ----------------------------------------------------------------------------
546
547 static void ggl_alphaFuncx(void* con, GGLenum func, GGLclampx ref)
548 {
549 GGL_CONTEXT(c, con);
550 if ((func < GGL_NEVER) || (func > GGL_ALWAYS)) {
551 ggl_error(c, GGL_INVALID_ENUM);
552 return;
553 }
554 c->state.alpha_test.ref = gglFixedToIteratedColor(gglClampx(ref));
555 if (c->state.alpha_test.func != func) {
556 c->state.alpha_test.func = func;
557 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
558 }
559 }
560
561 // ----------------------------------------------------------------------------
562
563 static void ggl_depthFunc(void* con, GGLenum func)
564 {
565 GGL_CONTEXT(c, con);
566 if ((func < GGL_NEVER) || (func > GGL_ALWAYS)) {
567 ggl_error(c, GGL_INVALID_ENUM);
568 return;
569 }
570 if (c->state.depth_test.func != func) {
571 c->state.depth_test.func = func;
572 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
573 }
574 }
575
576 // ----------------------------------------------------------------------------
577
578 static void ggl_logicOp(void* con, GGLenum opcode)
579 {
580 GGL_CONTEXT(c, con);
581 if ((opcode < GGL_CLEAR) || (opcode > GGL_SET)) {
582 ggl_error(c, GGL_INVALID_ENUM);
583 return;
584 }
585 if (c->state.logic_op.opcode != opcode) {
586 c->state.logic_op.opcode = opcode;
587 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
588 }
589 }
590
591
592 // ----------------------------------------------------------------------------
593
594 void ggl_set_scissor(context_t* c)
595 {
596 if (c->state.enables & GGL_ENABLE_SCISSOR_TEST) {
597 const int32_t l = c->state.scissor.user_left;
598 const int32_t t = c->state.scissor.user_top;
599 const int32_t r = c->state.scissor.user_right;
600 const int32_t b = c->state.scissor.user_bottom;
601 c->state.scissor.left = max(0, l);
602 c->state.scissor.right = min(c->state.buffers.color.width, r);
603 c->state.scissor.top = max(0, t);
604 c->state.scissor.bottom = min(c->state.buffers.color.height, b);
605 } else {
606 c->state.scissor.left = 0;
607 c->state.scissor.top = 0;
608 c->state.scissor.right = c->state.buffers.color.width;
609 c->state.scissor.bottom = c->state.buffers.color.height;
610 }
611 }
612
613 void ggl_enable_blending(context_t* c, int enable)
614 {
615 const int e = (c->state.enables & GGL_ENABLE_BLENDING)?1:0;
616 if (e != enable) {
617 if (enable) c->state.enables |= GGL_ENABLE_BLENDING;
618 else c->state.enables &= ~GGL_ENABLE_BLENDING;
619 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
620 }
621 }
622
623 void ggl_enable_scissor_test(context_t* c, int enable)
624 {
625 const int e = (c->state.enables & GGL_ENABLE_SCISSOR_TEST)?1:0;
626 if (e != enable) {
627 if (enable) c->state.enables |= GGL_ENABLE_SCISSOR_TEST;
628 else c->state.enables &= ~GGL_ENABLE_SCISSOR_TEST;
629 ggl_set_scissor(c);
630 }
631 }
632
633 void ggl_enable_alpha_test(context_t* c, int enable)
634 {
635 const int e = (c->state.enables & GGL_ENABLE_ALPHA_TEST)?1:0;
636 if (e != enable) {
637 if (enable) c->state.enables |= GGL_ENABLE_ALPHA_TEST;
638 else c->state.enables &= ~GGL_ENABLE_ALPHA_TEST;
639 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
640 }
641 }
642
643 void ggl_enable_logic_op(context_t* c, int enable)
644 {
645 const int e = (c->state.enables & GGL_ENABLE_LOGIC_OP)?1:0;
646 if (e != enable) {
647 if (enable) c->state.enables |= GGL_ENABLE_LOGIC_OP;
648 else c->state.enables &= ~GGL_ENABLE_LOGIC_OP;
649 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
650 }
651 }
652
653 void ggl_enable_dither(context_t* c, int enable)
654 {
655 const int e = (c->state.enables & GGL_ENABLE_DITHER)?1:0;
656 if (e != enable) {
657 if (enable) c->state.enables |= GGL_ENABLE_DITHER;
658 else c->state.enables &= ~GGL_ENABLE_DITHER;
659 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
660 }
661 }
662
663 void ggl_enable_stencil_test(context_t* c, int enable)
664 {
665 }
666
667 void ggl_enable_depth_test(context_t* c, int enable)
668 {
669 if (c->state.buffers.depth.format == 0)
670 enable = 0;
671 const int e = (c->state.enables & GGL_ENABLE_DEPTH_TEST)?1:0;
672 if (e != enable) {
673 if (enable) c->state.enables |= GGL_ENABLE_DEPTH_TEST;
674 else c->state.enables &= ~GGL_ENABLE_DEPTH_TEST;
675 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
676 }
677 }
678
679 void ggl_enable_aa(context_t* c, int enable)
680 {
681 const int e = (c->state.enables & GGL_ENABLE_AA)?1:0;
682 if (e != enable) {
683 if (enable) c->state.enables |= GGL_ENABLE_AA;
684 else c->state.enables &= ~GGL_ENABLE_AA;
685 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
686 }
687 }
688
689 void ggl_enable_point_aa_nice(context_t* c, int enable)
690 {
691 const int e = (c->state.enables & GGL_ENABLE_POINT_AA_NICE)?1:0;
692 if (e != enable) {
693 if (enable) c->state.enables |= GGL_ENABLE_POINT_AA_NICE;
694 else c->state.enables &= ~GGL_ENABLE_POINT_AA_NICE;
695 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
696 }
697 }
698
699 void ggl_enable_w_lerp(context_t* c, int enable)
700 {
701 const int e = (c->state.enables & GGL_ENABLE_W)?1:0;
702 if (e != enable) {
703 if (enable) c->state.enables |= GGL_ENABLE_W;
704 else c->state.enables &= ~GGL_ENABLE_W;
705 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
706 }
707 }
708
709 void ggl_enable_texture2d(context_t* c, int enable)
710 {
711 if (c->activeTMU->enable != enable) {
712 const uint32_t tmu = c->activeTMUIndex;
713 c->activeTMU->enable = enable;
714 const uint32_t mask = 1UL << tmu;
715 if (enable) c->state.enabled_tmu |= mask;
716 else c->state.enabled_tmu &= ~mask;
717 if (c->state.enabled_tmu) c->state.enables |= GGL_ENABLE_TMUS;
718 else c->state.enables &= ~GGL_ENABLE_TMUS;
719 ggl_state_changed(c, GGL_TMU_STATE);
720 }
721 }
722
723
724 // ----------------------------------------------------------------------------
725
726 int64_t ggl_system_time()
727 {
728 #if defined(HAVE_POSIX_CLOCKS)
729 struct timespec t;
730 t.tv_sec = t.tv_nsec = 0;
731 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
732 return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
733 #else
734 // we don't support the clocks here.
735 struct timeval t;
736 t.tv_sec = t.tv_usec = 0;
737 gettimeofday(&t, NULL);
738 return int64_t(t.tv_sec)*1000000000LL + int64_t(t.tv_usec)*1000LL;
739 #endif
740 }
741
742 // ----------------------------------------------------------------------------
743
744 void ggl_init_procs(context_t* c)
745 {
746 GGLContext& procs = *(GGLContext*)c;
747 GGL_INIT_PROC(procs, scissor);
748 GGL_INIT_PROC(procs, activeTexture);
749 GGL_INIT_PROC(procs, bindTexture);
750 GGL_INIT_PROC(procs, bindTextureLod);
751 GGL_INIT_PROC(procs, colorBuffer);
752 GGL_INIT_PROC(procs, readBuffer);
753 GGL_INIT_PROC(procs, depthBuffer);
754 GGL_INIT_PROC(procs, enable);
755 GGL_INIT_PROC(procs, disable);
756 GGL_INIT_PROC(procs, enableDisable);
757 GGL_INIT_PROC(procs, shadeModel);
758 GGL_INIT_PROC(procs, color4xv);
759 GGL_INIT_PROC(procs, colorGrad12xv);
760 GGL_INIT_PROC(procs, zGrad3xv);
761 GGL_INIT_PROC(procs, wGrad3xv);
762 GGL_INIT_PROC(procs, fogGrad3xv);
763 GGL_INIT_PROC(procs, fogColor3xv);
764 GGL_INIT_PROC(procs, blendFunc);
765 GGL_INIT_PROC(procs, blendFuncSeparate);
766 GGL_INIT_PROC(procs, texEnvi);
767 GGL_INIT_PROC(procs, texEnvxv);
768 GGL_INIT_PROC(procs, texParameteri);
769 GGL_INIT_PROC(procs, texCoord2i);
770 GGL_INIT_PROC(procs, texCoord2x);
771 GGL_INIT_PROC(procs, texCoordGradScale8xv);
772 GGL_INIT_PROC(procs, texGeni);
773 GGL_INIT_PROC(procs, colorMask);
774 GGL_INIT_PROC(procs, depthMask);
775 GGL_INIT_PROC(procs, stencilMask);
776 GGL_INIT_PROC(procs, alphaFuncx);
777 GGL_INIT_PROC(procs, depthFunc);
778 GGL_INIT_PROC(procs, logicOp);
779 ggl_init_clear(c);
780 }
781
782 void ggl_init_context(context_t* c)
783 {
784 memset(c, 0, sizeof(context_t));
785 ggl_init_procs(c);
786 ggl_init_trap(c);
787 ggl_init_scanline(c);
788 ggl_init_texture(c);
789 ggl_init_picker(c);
790 ggl_init_raster(c);
791 c->formats = gglGetPixelFormatTable();
792 c->state.blend.src = GGL_ONE;
793 c->state.blend.dst = GGL_ZERO;
794 c->state.blend.src_alpha = GGL_ONE;
795 c->state.blend.dst_alpha = GGL_ZERO;
796 c->state.mask.color = 0xF;
797 c->state.mask.depth = 0;
798 c->state.mask.stencil = 0xFFFFFFFF;
799 c->state.logic_op.opcode = GGL_COPY;
800 c->state.alpha_test.func = GGL_ALWAYS;
801 c->state.depth_test.func = GGL_LESS;
802 c->state.depth_test.clearValue = FIXED_ONE;
803 c->shade.w0 = FIXED_ONE;
804 memcpy(c->ditherMatrix, gDitherMatrix, sizeof(gDitherMatrix));
805 }
806
807 void ggl_uninit_context(context_t* c)
808 {
809 ggl_uninit_scanline(c);
810 }
811
812 // ----------------------------------------------------------------------------
813 }; // namespace android
814 // ----------------------------------------------------------------------------
815
816
817
818 using namespace android;
819
820 ssize_t gglInit(GGLContext** context)
821 {
822 void* const base = malloc(sizeof(context_t) + 32);
823 if (base) {
824 // always align the context on cache lines
825 context_t *c = (context_t *)((ptrdiff_t(base)+31) & ~0x1FL);
826 ggl_init_context(c);
827 c->base = base;
828 *context = (GGLContext*)c;
829 } else {
830 return -1;
831 }
832 return 0;
833 }
834
835 ssize_t gglUninit(GGLContext* con)
836 {
837 GGL_CONTEXT(c, (void*)con);
838 ggl_uninit_context(c);
839 free(c->base);
840 return 0;
841 }
842
+0
-217
libpixelflinger/raster.cpp less more
0 /* libs/pixelflinger/raster.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18
19 #include <string.h>
20
21 #include "raster.h"
22 #include "trap.h"
23
24 namespace android {
25
26 static void ggl_rasterPos2x(void* con, GGLfixed x, GGLfixed y);
27 static void ggl_rasterPos2i(void* con, GGLint x, GGLint y);
28 static void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
29 GGLsizei width, GGLsizei height, GGLenum type);
30
31 void ggl_init_raster(context_t* c)
32 {
33 GGLContext& procs = *(GGLContext*)c;
34 GGL_INIT_PROC(procs, copyPixels);
35 GGL_INIT_PROC(procs, rasterPos2x);
36 GGL_INIT_PROC(procs, rasterPos2i);
37 }
38
39 void ggl_rasterPos2x(void* con, GGLfixed x, GGLfixed y)
40 {
41 GGL_CONTEXT(c, con);
42 // raster pos should be processed just like glVertex
43 c->state.raster.x = x;
44 c->state.raster.y = y;
45 }
46
47 void ggl_rasterPos2i(void* con, GGLint x, GGLint y)
48 {
49 ggl_rasterPos2x(con, gglIntToFixed(x), gglIntToFixed(y));
50 }
51
52 void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
53 GGLsizei width, GGLsizei height, GGLenum type)
54 {
55 GGL_CONTEXT(c, con);
56
57 // color-buffer
58 surface_t* cb = &(c->state.buffers.color);
59
60 // undefined behaviour if we try to copy from outside the surface
61 if (uint32_t(xs) > cb->width)
62 return;
63 if (uint32_t(ys) > cb->height)
64 return;
65 if (uint32_t(xs + width) > cb->width)
66 return;
67 if (uint32_t(ys + height) > cb->height)
68 return;
69
70 // copy to current raster position
71 GGLint xd = gglFixedToIntRound(c->state.raster.x);
72 GGLint yd = gglFixedToIntRound(c->state.raster.y);
73
74 // clip to scissor
75 if (xd < GGLint(c->state.scissor.left)) {
76 GGLint offset = GGLint(c->state.scissor.left) - xd;
77 xd = GGLint(c->state.scissor.left);
78 xs += offset;
79 width -= offset;
80 }
81 if (yd < GGLint(c->state.scissor.top)) {
82 GGLint offset = GGLint(c->state.scissor.top) - yd;
83 yd = GGLint(c->state.scissor.top);
84 ys += offset;
85 height -= offset;
86 }
87 if ((xd + width) > GGLint(c->state.scissor.right)) {
88 width = GGLint(c->state.scissor.right) - xd;
89 }
90 if ((yd + height) > GGLint(c->state.scissor.bottom)) {
91 height = GGLint(c->state.scissor.bottom) - yd;
92 }
93
94 if (width<=0 || height<=0) {
95 return; // nothing to copy
96 }
97
98 if (xs==xd && ys==yd) {
99 // nothing to do, but be careful, this might not be true when we support
100 // gglPixelTransfer, gglPixelMap and gglPixelZoom
101 return;
102 }
103
104 const GGLFormat* fp = &(c->formats[cb->format]);
105 uint8_t* src = reinterpret_cast<uint8_t*>(cb->data)
106 + (xs + (cb->stride * ys)) * fp->size;
107 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data)
108 + (xd + (cb->stride * yd)) * fp->size;
109 const size_t bpr = cb->stride * fp->size;
110 const size_t rowsize = width * fp->size;
111 size_t yc = height;
112
113 if (ys < yd) {
114 // bottom to top
115 src += height * bpr;
116 dst += height * bpr;
117 do {
118 dst -= bpr;
119 src -= bpr;
120 memcpy(dst, src, rowsize);
121 } while (--yc);
122 } else {
123 if (ys == yd) {
124 // might be right to left
125 do {
126 memmove(dst, src, rowsize);
127 dst += bpr;
128 src += bpr;
129 } while (--yc);
130 } else {
131 // top to bottom
132 do {
133 memcpy(dst, src, rowsize);
134 dst += bpr;
135 src += bpr;
136 } while (--yc);
137 }
138 }
139 }
140
141 }; // namespace android
142
143 using namespace android;
144
145 GGLint gglBitBlti(GGLContext* con, int tmu, GGLint crop[4], GGLint where[4])
146 {
147 GGL_CONTEXT(c, (void*)con);
148
149 GGLint x = where[0];
150 GGLint y = where[1];
151 GGLint w = where[2];
152 GGLint h = where[3];
153
154 // exclsively enable this tmu
155 const GGLSurface& cbSurface = c->state.buffers.color.s;
156 c->procs.activeTexture(c, tmu);
157 c->procs.disable(c, GGL_W_LERP);
158
159 uint32_t tmus = 1UL<<tmu;
160 if (c->state.enabled_tmu != tmus) {
161 c->activeTMU->enable = 1;
162 c->state.enabled_tmu = tmus;
163 c->state.enables |= GGL_ENABLE_TMUS;
164 ggl_state_changed(c, GGL_TMU_STATE);
165 }
166
167 const GGLint Wcr = crop[2];
168 const GGLint Hcr = crop[3];
169 if ((w == Wcr) && (h == Hcr)) {
170 c->procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
171 c->procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
172 const GGLint Ucr = crop[0];
173 const GGLint Vcr = crop[1];
174 const GGLint s0 = Ucr - x;
175 const GGLint t0 = Vcr - y;
176 c->procs.texCoord2i(c, s0, t0);
177 c->procs.recti(c, x, y, x+w, y+h);
178 } else {
179 int32_t texcoords[8];
180 x = gglIntToFixed(x);
181 y = gglIntToFixed(y);
182
183 // we CLAMP here, which works with premultiplied (s,t)
184 c->procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
185 c->procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
186 c->procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
187 c->procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
188
189 const GGLint Ucr = crop[0] << 16;
190 const GGLint Vcr = crop[1] << 16;
191 const GGLint Wcr = crop[2] << 16;
192 const GGLint Hcr = crop[3] << 16;
193
194 // computes texture coordinates (pre-multiplied)
195 int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
196 int32_t dtdy = Hcr / h; // dtdy = ((Hcr/h)/Ht)*Ht
197 int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
198 int32_t t0 = Vcr - gglMulx(dtdy, y); // t0 = Vcr - y * dtdy
199 texcoords[0] = s0;
200 texcoords[1] = dsdx;
201 texcoords[2] = 0;
202 texcoords[3] = t0;
203 texcoords[4] = 0;
204 texcoords[5] = dtdy;
205 texcoords[6] = 0;
206 texcoords[7] = 0;
207 c->procs.texCoordGradScale8xv(c, tmu, texcoords);
208 c->procs.recti(c,
209 gglFixedToIntRound(x),
210 gglFixedToIntRound(y),
211 gglFixedToIntRound(x)+w,
212 gglFixedToIntRound(y)+h);
213 }
214 return 0;
215 }
216
+0
-33
libpixelflinger/raster.h less more
0 /* libs/pixelflinger/raster.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_GGL_RASTER_H
19 #define ANDROID_GGL_RASTER_H
20
21 #include <private/pixelflinger/ggl_context.h>
22
23 namespace android {
24
25 void ggl_init_raster(context_t* c);
26
27 void gglCopyPixels(void* c, GGLint x, GGLint y, GGLsizei width, GGLsizei height, GGLenum type);
28 void gglRasterPos2d(void* c, GGLint x, GGLint y);
29
30 }; // namespace android
31
32 #endif // ANDROID_GGL_RASTER_H
+0
-62
libpixelflinger/rotate90CW_4x4_16v6.S less more
0 /*
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 .text
19 .align
20
21 .global rotate90CW_4x4_16v6
22
23 // Rotates 90deg CW a 4x4 block of 16bpp pixels using ARMv6
24 // src and dst must be 4 pixels-aligned (2-pixels aligned might
25 // actually work)
26 //
27 // The code below is complicated by ARM's little endianness.
28
29 rotate90CW_4x4_16v6:
30 // r0 = dst
31 // r1 = src
32 // r2 = dst stride in pixels
33 // r3 = src stride in pixels
34
35 stmfd sp!, {r4,r5, r6,r7, r8,r9, r10,r11, lr}
36 add r14, r3, r3
37 add r12, r2, r2
38
39 ldrd r2, r3, [r1], r14
40 ldrd r4, r5, [r1], r14
41 ldrd r6, r7, [r1], r14
42 ldrd r8, r9, [r1]
43
44 pkhbt r10, r8, r6, lsl #16
45 pkhbt r11, r4, r2, lsl #16
46 strd r10, r11, [r0], r12
47
48 pkhtb r10, r6, r8, asr #16
49 pkhtb r11, r2, r4, asr #16
50
51 strd r10, r11, [r0], r12
52 pkhbt r10, r9, r7, lsl #16
53 pkhbt r11, r5, r3, lsl #16
54
55 strd r10, r11, [r0], r12
56
57 pkhtb r10, r7, r9, asr #16
58 pkhtb r11, r3, r5, asr #16
59 strd r10, r11, [r0]
60
61 ldmfd sp!, {r4,r5, r6,r7, r8,r9, r10,r11, pc}
+0
-1496
libpixelflinger/scanline.cpp less more
0 /* libs/pixelflinger/scanline.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #define LOG_TAG "pixelflinger"
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <cutils/memory.h>
26 #include <cutils/log.h>
27
28 #include "buffer.h"
29 #include "scanline.h"
30
31 #include "codeflinger/CodeCache.h"
32 #include "codeflinger/GGLAssembler.h"
33 #include "codeflinger/ARMAssembler.h"
34 //#include "codeflinger/ARMAssemblerOptimizer.h"
35
36 // ----------------------------------------------------------------------------
37
38 #define ANDROID_CODEGEN_GENERIC 0 // force generic pixel pipeline
39 #define ANDROID_CODEGEN_C 1 // hand-written C, fallback generic
40 #define ANDROID_CODEGEN_ASM 2 // hand-written asm, fallback generic
41 #define ANDROID_CODEGEN_GENERATED 3 // hand-written asm, fallback codegen
42
43 #ifdef NDEBUG
44 # define ANDROID_RELEASE
45 # define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED
46 #else
47 # define ANDROID_DEBUG
48 # define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED
49 #endif
50
51 #if defined(__arm__)
52 # define ANDROID_ARM_CODEGEN 1
53 #else
54 # define ANDROID_ARM_CODEGEN 0
55 #endif
56
57 #define DEBUG__CODEGEN_ONLY 0
58
59
60 #define ASSEMBLY_SCRATCH_SIZE 2048
61
62 // ----------------------------------------------------------------------------
63 namespace android {
64 // ----------------------------------------------------------------------------
65
66 static void init_y(context_t*, int32_t);
67 static void init_y_noop(context_t*, int32_t);
68 static void init_y_packed(context_t*, int32_t);
69 static void init_y_error(context_t*, int32_t);
70
71 static void step_y__generic(context_t* c);
72 static void step_y__nop(context_t*);
73 static void step_y__smooth(context_t* c);
74 static void step_y__tmu(context_t* c);
75 static void step_y__w(context_t* c);
76
77 static void scanline(context_t* c);
78 static void scanline_perspective(context_t* c);
79 static void scanline_perspective_single(context_t* c);
80 static void scanline_t32cb16blend(context_t* c);
81 static void scanline_t32cb16(context_t* c);
82 static void scanline_memcpy(context_t* c);
83 static void scanline_memset8(context_t* c);
84 static void scanline_memset16(context_t* c);
85 static void scanline_memset32(context_t* c);
86 static void scanline_noop(context_t* c);
87 static void scanline_set(context_t* c);
88 static void scanline_clear(context_t* c);
89
90 static void rect_generic(context_t* c, size_t yc);
91 static void rect_memcpy(context_t* c, size_t yc);
92
93 extern "C" void scanline_t32cb16blend_arm(uint16_t*, uint32_t*, size_t);
94 extern "C" void scanline_t32cb16_arm(uint16_t *dst, uint32_t *src, size_t ct);
95
96 // ----------------------------------------------------------------------------
97
98 struct shortcut_t {
99 needs_filter_t filter;
100 const char* desc;
101 void (*scanline)(context_t*);
102 void (*init_y)(context_t*, int32_t);
103 };
104
105 // Keep in sync with needs
106 static shortcut_t shortcuts[] = {
107 { { { 0x03515104, 0x00000077, { 0x00000A01, 0x00000000 } },
108 { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
109 "565 fb, 8888 tx, blend", scanline_t32cb16blend, init_y_noop },
110 { { { 0x03010104, 0x00000077, { 0x00000A01, 0x00000000 } },
111 { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
112 "565 fb, 8888 tx", scanline_t32cb16, init_y_noop },
113 { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
114 { 0x00000000, 0x00000007, { 0x00000000, 0x00000000 } } },
115 "(nop) alpha test", scanline_noop, init_y_noop },
116 { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
117 { 0x00000000, 0x00000070, { 0x00000000, 0x00000000 } } },
118 "(nop) depth test", scanline_noop, init_y_noop },
119 { { { 0x05000000, 0x00000000, { 0x00000000, 0x00000000 } },
120 { 0x0F000000, 0x00000080, { 0x00000000, 0x00000000 } } },
121 "(nop) logic_op", scanline_noop, init_y_noop },
122 { { { 0xF0000000, 0x00000000, { 0x00000000, 0x00000000 } },
123 { 0xF0000000, 0x00000080, { 0x00000000, 0x00000000 } } },
124 "(nop) color mask", scanline_noop, init_y_noop },
125 { { { 0x0F000000, 0x00000077, { 0x00000000, 0x00000000 } },
126 { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } },
127 "(set) logic_op", scanline_set, init_y_noop },
128 { { { 0x00000000, 0x00000077, { 0x00000000, 0x00000000 } },
129 { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } },
130 "(clear) logic_op", scanline_clear, init_y_noop },
131 { { { 0x03000000, 0x00000077, { 0x00000000, 0x00000000 } },
132 { 0xFFFFFF00, 0x000000F7, { 0x00000000, 0x00000000 } } },
133 "(clear) blending 0/0", scanline_clear, init_y_noop },
134 { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
135 { 0x0000003F, 0x00000000, { 0x00000000, 0x00000000 } } },
136 "(error) invalid color-buffer format", scanline_noop, init_y_error },
137 };
138 static const needs_filter_t noblend1to1 = {
139 // (disregard dithering, see below)
140 { 0x03010100, 0x00000077, { 0x00000A00, 0x00000000 } },
141 { 0xFFFFFFC0, 0xFFFFFEFF, { 0xFFFFFFC0, 0x0000003F } }
142 };
143 static const needs_filter_t fill16noblend = {
144 { 0x03010100, 0x00000077, { 0x00000000, 0x00000000 } },
145 { 0xFFFFFFC0, 0xFFFFFFFF, { 0x0000003F, 0x0000003F } }
146 };
147
148 // ----------------------------------------------------------------------------
149
150 #if ANDROID_ARM_CODEGEN
151 static CodeCache gCodeCache(12 * 1024);
152
153 class ScanlineAssembly : public Assembly {
154 AssemblyKey<needs_t> mKey;
155 public:
156 ScanlineAssembly(needs_t needs, size_t size)
157 : Assembly(size), mKey(needs) { }
158 const AssemblyKey<needs_t>& key() const { return mKey; }
159 };
160 #endif
161
162 // ----------------------------------------------------------------------------
163
164 void ggl_init_scanline(context_t* c)
165 {
166 c->init_y = init_y;
167 c->step_y = step_y__generic;
168 c->scanline = scanline;
169 }
170
171 void ggl_uninit_scanline(context_t* c)
172 {
173 if (c->state.buffers.coverage)
174 free(c->state.buffers.coverage);
175 #if ANDROID_ARM_CODEGEN
176 if (c->scanline_as)
177 c->scanline_as->decStrong(c);
178 #endif
179 }
180
181 // ----------------------------------------------------------------------------
182
183 static void pick_scanline(context_t* c)
184 {
185 #if (!defined(DEBUG__CODEGEN_ONLY) || (DEBUG__CODEGEN_ONLY == 0))
186
187 #if ANDROID_CODEGEN == ANDROID_CODEGEN_GENERIC
188 c->init_y = init_y;
189 c->step_y = step_y__generic;
190 c->scanline = scanline;
191 return;
192 #endif
193
194 //printf("*** needs [%08lx:%08lx:%08lx:%08lx]\n",
195 // c->state.needs.n, c->state.needs.p,
196 // c->state.needs.t[0], c->state.needs.t[1]);
197
198 // first handle the special case that we cannot test with a filter
199 const uint32_t cb_format = GGL_READ_NEEDS(CB_FORMAT, c->state.needs.n);
200 if (GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0]) == cb_format) {
201 if (c->state.needs.match(noblend1to1)) {
202 // this will match regardless of dithering state, since both
203 // src and dest have the same format anyway, there is no dithering
204 // to be done.
205 const GGLFormat* f =
206 &(c->formats[GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0])]);
207 if ((f->components == GGL_RGB) ||
208 (f->components == GGL_RGBA) ||
209 (f->components == GGL_LUMINANCE) ||
210 (f->components == GGL_LUMINANCE_ALPHA))
211 {
212 // format must have all of RGB components
213 // (so the current color doesn't show through)
214 c->scanline = scanline_memcpy;
215 c->init_y = init_y_noop;
216 return;
217 }
218 }
219 }
220
221 if (c->state.needs.match(fill16noblend)) {
222 c->init_y = init_y_packed;
223 switch (c->formats[cb_format].size) {
224 case 1: c->scanline = scanline_memset8; return;
225 case 2: c->scanline = scanline_memset16; return;
226 case 4: c->scanline = scanline_memset32; return;
227 }
228 }
229
230 const int numFilters = sizeof(shortcuts)/sizeof(shortcut_t);
231 for (int i=0 ; i<numFilters ; i++) {
232 if (c->state.needs.match(shortcuts[i].filter)) {
233 c->scanline = shortcuts[i].scanline;
234 c->init_y = shortcuts[i].init_y;
235 return;
236 }
237 }
238
239 #endif // DEBUG__CODEGEN_ONLY
240
241 c->init_y = init_y;
242 c->step_y = step_y__generic;
243
244 #if ANDROID_ARM_CODEGEN
245 // we're going to have to generate some code...
246 // here, generate code for our pixel pipeline
247 const AssemblyKey<needs_t> key(c->state.needs);
248 sp<Assembly> assembly = gCodeCache.lookup(key);
249 if (assembly == 0) {
250 // create a new assembly region
251 sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs,
252 ASSEMBLY_SCRATCH_SIZE);
253 // initialize our assembler
254 GGLAssembler assembler( new ARMAssembler(a) );
255 //GGLAssembler assembler(
256 // new ARMAssemblerOptimizer(new ARMAssembler(a)) );
257 // generate the scanline code for the given needs
258 int err = assembler.scanline(c->state.needs, c);
259 if (ggl_likely(!err)) {
260 // finally, cache this assembly
261 err = gCodeCache.cache(a->key(), a);
262 }
263 if (ggl_unlikely(err)) {
264 LOGE("error generating or caching assembly. Reverting to NOP.");
265 c->scanline = scanline_noop;
266 c->init_y = init_y_noop;
267 c->step_y = step_y__nop;
268 return;
269 }
270 assembly = a;
271 }
272
273 // release the previous assembly
274 if (c->scanline_as) {
275 c->scanline_as->decStrong(c);
276 }
277
278 //LOGI("using generated pixel-pipeline");
279 c->scanline_as = assembly.get();
280 c->scanline_as->incStrong(c); // hold on to assembly
281 c->scanline = (void(*)(context_t* c))assembly->base();
282 #else
283 // LOGW("using generic (slow) pixel-pipeline");
284 c->scanline = scanline;
285 #endif
286 }
287
288 void ggl_pick_scanline(context_t* c)
289 {
290 pick_scanline(c);
291 if ((c->state.enables & GGL_ENABLE_W) &&
292 (c->state.enables & GGL_ENABLE_TMUS))
293 {
294 c->span = c->scanline;
295 c->scanline = scanline_perspective;
296 if (!(c->state.enabled_tmu & (c->state.enabled_tmu - 1))) {
297 // only one TMU enabled
298 c->scanline = scanline_perspective_single;
299 }
300 }
301 }
302
303 // ----------------------------------------------------------------------------
304
305 static void blending(context_t* c, pixel_t* fragment, pixel_t* fb);
306 static void blend_factor(context_t* c, pixel_t* r, uint32_t factor,
307 const pixel_t* src, const pixel_t* dst);
308 static void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv);
309
310 #if ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)
311
312 // no need to compile the generic-pipeline, it can't be reached
313 void scanline(context_t*)
314 {
315 }
316
317 #else
318
319 void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv)
320 {
321 if (su && sv) {
322 if (su > sv) {
323 v = ggl_expand(v, sv, su);
324 sv = su;
325 } else if (su < sv) {
326 u = ggl_expand(u, su, sv);
327 su = sv;
328 }
329 }
330 }
331
332 void blending(context_t* c, pixel_t* fragment, pixel_t* fb)
333 {
334 rescale(fragment->c[0], fragment->s[0], fb->c[0], fb->s[0]);
335 rescale(fragment->c[1], fragment->s[1], fb->c[1], fb->s[1]);
336 rescale(fragment->c[2], fragment->s[2], fb->c[2], fb->s[2]);
337 rescale(fragment->c[3], fragment->s[3], fb->c[3], fb->s[3]);
338
339 pixel_t sf, df;
340 blend_factor(c, &sf, c->state.blend.src, fragment, fb);
341 blend_factor(c, &df, c->state.blend.dst, fragment, fb);
342
343 fragment->c[1] =
344 gglMulAddx(fragment->c[1], sf.c[1], gglMulx(fb->c[1], df.c[1]));
345 fragment->c[2] =
346 gglMulAddx(fragment->c[2], sf.c[2], gglMulx(fb->c[2], df.c[2]));
347 fragment->c[3] =
348 gglMulAddx(fragment->c[3], sf.c[3], gglMulx(fb->c[3], df.c[3]));
349
350 if (c->state.blend.alpha_separate) {
351 blend_factor(c, &sf, c->state.blend.src_alpha, fragment, fb);
352 blend_factor(c, &df, c->state.blend.dst_alpha, fragment, fb);
353 }
354
355 fragment->c[0] =
356 gglMulAddx(fragment->c[0], sf.c[0], gglMulx(fb->c[0], df.c[0]));
357
358 // clamp to 1.0
359 if (fragment->c[0] >= (1LU<<fragment->s[0]))
360 fragment->c[0] = (1<<fragment->s[0])-1;
361 if (fragment->c[1] >= (1LU<<fragment->s[1]))
362 fragment->c[1] = (1<<fragment->s[1])-1;
363 if (fragment->c[2] >= (1LU<<fragment->s[2]))
364 fragment->c[2] = (1<<fragment->s[2])-1;
365 if (fragment->c[3] >= (1LU<<fragment->s[3]))
366 fragment->c[3] = (1<<fragment->s[3])-1;
367 }
368
369 static inline int blendfactor(uint32_t x, uint32_t size, uint32_t def = 0)
370 {
371 if (!size)
372 return def;
373
374 // scale to 16 bits
375 if (size > 16) {
376 x >>= (size - 16);
377 } else if (size < 16) {
378 x = ggl_expand(x, size, 16);
379 }
380 x += x >> 15;
381 return x;
382 }
383
384 void blend_factor(context_t* c, pixel_t* r,
385 uint32_t factor, const pixel_t* src, const pixel_t* dst)
386 {
387 switch (factor) {
388 case GGL_ZERO:
389 r->c[1] =
390 r->c[2] =
391 r->c[3] =
392 r->c[0] = 0;
393 break;
394 case GGL_ONE:
395 r->c[1] =
396 r->c[2] =
397 r->c[3] =
398 r->c[0] = FIXED_ONE;
399 break;
400 case GGL_DST_COLOR:
401 r->c[1] = blendfactor(dst->c[1], dst->s[1]);
402 r->c[2] = blendfactor(dst->c[2], dst->s[2]);
403 r->c[3] = blendfactor(dst->c[3], dst->s[3]);
404 r->c[0] = blendfactor(dst->c[0], dst->s[0]);
405 break;
406 case GGL_SRC_COLOR:
407 r->c[1] = blendfactor(src->c[1], src->s[1]);
408 r->c[2] = blendfactor(src->c[2], src->s[2]);
409 r->c[3] = blendfactor(src->c[3], src->s[3]);
410 r->c[0] = blendfactor(src->c[0], src->s[0]);
411 break;
412 case GGL_ONE_MINUS_DST_COLOR:
413 r->c[1] = FIXED_ONE - blendfactor(dst->c[1], dst->s[1]);
414 r->c[2] = FIXED_ONE - blendfactor(dst->c[2], dst->s[2]);
415 r->c[3] = FIXED_ONE - blendfactor(dst->c[3], dst->s[3]);
416 r->c[0] = FIXED_ONE - blendfactor(dst->c[0], dst->s[0]);
417 break;
418 case GGL_ONE_MINUS_SRC_COLOR:
419 r->c[1] = FIXED_ONE - blendfactor(src->c[1], src->s[1]);
420 r->c[2] = FIXED_ONE - blendfactor(src->c[2], src->s[2]);
421 r->c[3] = FIXED_ONE - blendfactor(src->c[3], src->s[3]);
422 r->c[0] = FIXED_ONE - blendfactor(src->c[0], src->s[0]);
423 break;
424 case GGL_SRC_ALPHA:
425 r->c[1] =
426 r->c[2] =
427 r->c[3] =
428 r->c[0] = blendfactor(src->c[0], src->s[0], FIXED_ONE);
429 break;
430 case GGL_ONE_MINUS_SRC_ALPHA:
431 r->c[1] =
432 r->c[2] =
433 r->c[3] =
434 r->c[0] = FIXED_ONE - blendfactor(src->c[0], src->s[0], FIXED_ONE);
435 break;
436 case GGL_DST_ALPHA:
437 r->c[1] =
438 r->c[2] =
439 r->c[3] =
440 r->c[0] = blendfactor(dst->c[0], dst->s[0], FIXED_ONE);
441 break;
442 case GGL_ONE_MINUS_DST_ALPHA:
443 r->c[1] =
444 r->c[2] =
445 r->c[3] =
446 r->c[0] = FIXED_ONE - blendfactor(dst->c[0], dst->s[0], FIXED_ONE);
447 break;
448 case GGL_SRC_ALPHA_SATURATE:
449 // XXX: GGL_SRC_ALPHA_SATURATE
450 break;
451 }
452 }
453
454 static GGLfixed wrapping(int32_t coord, uint32_t size, int tx_wrap)
455 {
456 GGLfixed d;
457 if (tx_wrap == GGL_REPEAT) {
458 d = (uint32_t(coord)>>16) * size;
459 } else if (tx_wrap == GGL_CLAMP) { // CLAMP_TO_EDGE semantics
460 const GGLfixed clamp_min = FIXED_HALF;
461 const GGLfixed clamp_max = (size << 16) - FIXED_HALF;
462 if (coord < clamp_min) coord = clamp_min;
463 if (coord > clamp_max) coord = clamp_max;
464 d = coord;
465 } else { // 1:1
466 const GGLfixed clamp_min = 0;
467 const GGLfixed clamp_max = (size << 16);
468 if (coord < clamp_min) coord = clamp_min;
469 if (coord > clamp_max) coord = clamp_max;
470 d = coord;
471 }
472 return d;
473 }
474
475 static inline
476 GGLcolor ADJUST_COLOR_ITERATOR(GGLcolor v, GGLcolor dvdx, int len)
477 {
478 const int32_t end = dvdx * (len-1) + v;
479 if (end < 0)
480 v -= end;
481 v &= ~(v>>31);
482 return v;
483 }
484
485 void scanline(context_t* c)
486 {
487 const uint32_t enables = c->state.enables;
488 const int xs = c->iterators.xl;
489 const int x1 = c->iterators.xr;
490 int xc = x1 - xs;
491 const int16_t* covPtr = c->state.buffers.coverage + xs;
492
493 // All iterated values are sampled at the pixel center
494
495 // reset iterators for that scanline...
496 GGLcolor r, g, b, a;
497 iterators_t& ci = c->iterators;
498 if (enables & GGL_ENABLE_SMOOTH) {
499 r = (xs * c->shade.drdx) + ci.ydrdy;
500 g = (xs * c->shade.dgdx) + ci.ydgdy;
501 b = (xs * c->shade.dbdx) + ci.ydbdy;
502 a = (xs * c->shade.dadx) + ci.ydady;
503 r = ADJUST_COLOR_ITERATOR(r, c->shade.drdx, xc);
504 g = ADJUST_COLOR_ITERATOR(g, c->shade.dgdx, xc);
505 b = ADJUST_COLOR_ITERATOR(b, c->shade.dbdx, xc);
506 a = ADJUST_COLOR_ITERATOR(a, c->shade.dadx, xc);
507 } else {
508 r = ci.ydrdy;
509 g = ci.ydgdy;
510 b = ci.ydbdy;
511 a = ci.ydady;
512 }
513
514 // z iterators are 1.31
515 GGLfixed z = (xs * c->shade.dzdx) + ci.ydzdy;
516 GGLfixed f = (xs * c->shade.dfdx) + ci.ydfdy;
517
518 struct {
519 GGLfixed s, t;
520 } tc[GGL_TEXTURE_UNIT_COUNT];
521 if (enables & GGL_ENABLE_TMUS) {
522 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
523 if (c->state.texture[i].enable) {
524 texture_iterators_t& ti = c->state.texture[i].iterators;
525 if (enables & GGL_ENABLE_W) {
526 tc[i].s = ti.ydsdy;
527 tc[i].t = ti.ydtdy;
528 } else {
529 tc[i].s = (xs * ti.dsdx) + ti.ydsdy;
530 tc[i].t = (xs * ti.dtdx) + ti.ydtdy;
531 }
532 }
533 }
534 }
535
536 pixel_t fragment;
537 pixel_t texel;
538 pixel_t fb;
539
540 uint32_t x = xs;
541 uint32_t y = c->iterators.y;
542
543 while (xc--) {
544
545 { // just a scope
546
547 // read color (convert to 8 bits by keeping only the integer part)
548 fragment.s[1] = fragment.s[2] =
549 fragment.s[3] = fragment.s[0] = 8;
550 fragment.c[1] = r >> (GGL_COLOR_BITS-8);
551 fragment.c[2] = g >> (GGL_COLOR_BITS-8);
552 fragment.c[3] = b >> (GGL_COLOR_BITS-8);
553 fragment.c[0] = a >> (GGL_COLOR_BITS-8);
554
555 // texturing
556 if (enables & GGL_ENABLE_TMUS) {
557 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
558 texture_t& tx = c->state.texture[i];
559 if (!tx.enable)
560 continue;
561 texture_iterators_t& ti = tx.iterators;
562 int32_t u, v;
563
564 // s-coordinate
565 if (tx.s_coord != GGL_ONE_TO_ONE) {
566 const int w = tx.surface.width;
567 u = wrapping(tc[i].s, w, tx.s_wrap);
568 tc[i].s += ti.dsdx;
569 } else {
570 u = (((tx.shade.is0>>16) + x)<<16) + FIXED_HALF;
571 }
572
573 // t-coordinate
574 if (tx.t_coord != GGL_ONE_TO_ONE) {
575 const int h = tx.surface.height;
576 v = wrapping(tc[i].t, h, tx.t_wrap);
577 tc[i].t += ti.dtdx;
578 } else {
579 v = (((tx.shade.it0>>16) + y)<<16) + FIXED_HALF;
580 }
581
582 // read texture
583 if (tx.mag_filter == GGL_NEAREST &&
584 tx.min_filter == GGL_NEAREST)
585 {
586 u >>= 16;
587 v >>= 16;
588 tx.surface.read(&tx.surface, c, u, v, &texel);
589 } else {
590 const int w = tx.surface.width;
591 const int h = tx.surface.height;
592 u -= FIXED_HALF;
593 v -= FIXED_HALF;
594 int u0 = u >> 16;
595 int v0 = v >> 16;
596 int u1 = u0 + 1;
597 int v1 = v0 + 1;
598 if (tx.s_wrap == GGL_REPEAT) {
599 if (u0<0) u0 += w;
600 if (u1<0) u1 += w;
601 if (u0>=w) u0 -= w;
602 if (u1>=w) u1 -= w;
603 } else {
604 if (u0<0) u0 = 0;
605 if (u1<0) u1 = 0;
606 if (u0>=w) u0 = w-1;
607 if (u1>=w) u1 = w-1;
608 }
609 if (tx.t_wrap == GGL_REPEAT) {
610 if (v0<0) v0 += h;
611 if (v1<0) v1 += h;
612 if (v0>=h) v0 -= h;
613 if (v1>=h) v1 -= h;
614 } else {
615 if (v0<0) v0 = 0;
616 if (v1<0) v1 = 0;
617 if (v0>=h) v0 = h-1;
618 if (v1>=h) v1 = h-1;
619 }
620 pixel_t texels[4];
621 uint32_t mm[4];
622 tx.surface.read(&tx.surface, c, u0, v0, &texels[0]);
623 tx.surface.read(&tx.surface, c, u0, v1, &texels[1]);
624 tx.surface.read(&tx.surface, c, u1, v0, &texels[2]);
625 tx.surface.read(&tx.surface, c, u1, v1, &texels[3]);
626 u = (u >> 12) & 0xF;
627 v = (v >> 12) & 0xF;
628 u += u>>3;
629 v += v>>3;
630 mm[0] = (0x10 - u) * (0x10 - v);
631 mm[1] = (0x10 - u) * v;
632 mm[2] = u * (0x10 - v);
633 mm[3] = 0x100 - (mm[0] + mm[1] + mm[2]);
634 for (int j=0 ; j<4 ; j++) {
635 texel.s[j] = texels[0].s[j];
636 if (!texel.s[j]) continue;
637 texel.s[j] += 8;
638 texel.c[j] = texels[0].c[j]*mm[0] +
639 texels[1].c[j]*mm[1] +
640 texels[2].c[j]*mm[2] +
641 texels[3].c[j]*mm[3] ;
642 }
643 }
644
645 // Texture environnement...
646 for (int j=0 ; j<4 ; j++) {
647 uint32_t& Cf = fragment.c[j];
648 uint32_t& Ct = texel.c[j];
649 uint8_t& sf = fragment.s[j];
650 uint8_t& st = texel.s[j];
651 uint32_t At = texel.c[0];
652 uint8_t sat = texel.s[0];
653 switch (tx.env) {
654 case GGL_REPLACE:
655 if (st) {
656 Cf = Ct;
657 sf = st;
658 }
659 break;
660 case GGL_MODULATE:
661 if (st) {
662 uint32_t factor = Ct + (Ct>>(st-1));
663 Cf = (Cf * factor) >> st;
664 }
665 break;
666 case GGL_DECAL:
667 if (sat) {
668 rescale(Cf, sf, Ct, st);
669 Cf += ((Ct - Cf) * (At + (At>>(sat-1)))) >> sat;
670 }
671 break;
672 case GGL_BLEND:
673 if (st) {
674 uint32_t Cc = tx.env_color[i];
675 if (sf>8) Cc = (Cc * ((1<<sf)-1))>>8;
676 else if (sf<8) Cc = (Cc - (Cc>>(8-sf)))>>(8-sf);
677 uint32_t factor = Ct + (Ct>>(st-1));
678 Cf = ((((1<<st) - factor) * Cf) + Ct*Cc)>>st;
679 }
680 break;
681 case GGL_ADD:
682 if (st) {
683 rescale(Cf, sf, Ct, st);
684 Cf += Ct;
685 }
686 break;
687 }
688 }
689 }
690 }
691
692 // coverage application
693 if (enables & GGL_ENABLE_AA) {
694 int16_t cf = *covPtr++;
695 fragment.c[0] = (int64_t(fragment.c[0]) * cf) >> 15;
696 }
697
698 // alpha-test
699 if (enables & GGL_ENABLE_ALPHA_TEST) {
700 GGLcolor ref = c->state.alpha_test.ref;
701 GGLcolor alpha = (uint64_t(fragment.c[0]) *
702 ((1<<GGL_COLOR_BITS)-1)) / ((1<<fragment.s[0])-1);
703 switch (c->state.alpha_test.func) {
704 case GGL_NEVER: goto discard;
705 case GGL_LESS: if (alpha<ref) break; goto discard;
706 case GGL_EQUAL: if (alpha==ref) break; goto discard;
707 case GGL_LEQUAL: if (alpha<=ref) break; goto discard;
708 case GGL_GREATER: if (alpha>ref) break; goto discard;
709 case GGL_NOTEQUAL: if (alpha!=ref) break; goto discard;
710 case GGL_GEQUAL: if (alpha>=ref) break; goto discard;
711 }
712 }
713
714 // depth test
715 if (c->state.buffers.depth.format) {
716 if (enables & GGL_ENABLE_DEPTH_TEST) {
717 surface_t* cb = &(c->state.buffers.depth);
718 uint16_t* p = (uint16_t*)(cb->data)+(x+(cb->stride*y));
719 uint16_t zz = uint32_t(z)>>(16);
720 uint16_t depth = *p;
721 switch (c->state.depth_test.func) {
722 case GGL_NEVER: goto discard;
723 case GGL_LESS: if (zz<depth) break; goto discard;
724 case GGL_EQUAL: if (zz==depth) break; goto discard;
725 case GGL_LEQUAL: if (zz<=depth) break; goto discard;
726 case GGL_GREATER: if (zz>depth) break; goto discard;
727 case GGL_NOTEQUAL: if (zz!=depth) break; goto discard;
728 case GGL_GEQUAL: if (zz>=depth) break; goto discard;
729 }
730 // depth buffer is not enabled, if depth-test is not enabled
731 /*
732 fragment.s[1] = fragment.s[2] =
733 fragment.s[3] = fragment.s[0] = 8;
734 fragment.c[1] =
735 fragment.c[2] =
736 fragment.c[3] =
737 fragment.c[0] = 255 - (zz>>8);
738 */
739 if (c->state.mask.depth) {
740 *p = zz;
741 }
742 }
743 }
744
745 // fog
746 if (enables & GGL_ENABLE_FOG) {
747 for (int i=1 ; i<=3 ; i++) {
748 GGLfixed fc = (c->state.fog.color[i] * 0x10000) / 0xFF;
749 uint32_t& c = fragment.c[i];
750 uint8_t& s = fragment.s[i];
751 c = (c * 0x10000) / ((1<<s)-1);
752 c = gglMulAddx(c, f, gglMulx(fc, 0x10000 - f));
753 s = 16;
754 }
755 }
756
757 // blending
758 if (enables & GGL_ENABLE_BLENDING) {
759 fb.c[1] = fb.c[2] = fb.c[3] = fb.c[0] = 0; // placate valgrind
760 fb.s[1] = fb.s[2] = fb.s[3] = fb.s[0] = 0;
761 c->state.buffers.color.read(
762 &(c->state.buffers.color), c, x, y, &fb);
763 blending( c, &fragment, &fb );
764 }
765
766 // write
767 c->state.buffers.color.write(
768 &(c->state.buffers.color), c, x, y, &fragment);
769 }
770
771 discard:
772 // iterate...
773 x += 1;
774 if (enables & GGL_ENABLE_SMOOTH) {
775 r += c->shade.drdx;
776 g += c->shade.dgdx;
777 b += c->shade.dbdx;
778 a += c->shade.dadx;
779 }
780 z += c->shade.dzdx;
781 f += c->shade.dfdx;
782 }
783 }
784
785 #endif // ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)
786
787 // ----------------------------------------------------------------------------
788 #if 0
789 #pragma mark -
790 #pragma mark Scanline
791 #endif
792
793 template <typename T, typename U>
794 static inline __attribute__((const))
795 T interpolate(int y, T v0, U dvdx, U dvdy) {
796 // interpolates in pixel's centers
797 // v = v0 + (y + 0.5) * dvdy + (0.5 * dvdx)
798 return (y * dvdy) + (v0 + ((dvdy + dvdx) >> 1));
799 }
800
801 // ----------------------------------------------------------------------------
802 #if 0
803 #pragma mark -
804 #endif
805
806 void init_y(context_t* c, int32_t ys)
807 {
808 const uint32_t enables = c->state.enables;
809
810 // compute iterators...
811 iterators_t& ci = c->iterators;
812
813 // sample in the center
814 ci.y = ys;
815
816 if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_W|GGL_ENABLE_FOG)) {
817 ci.ydzdy = interpolate(ys, c->shade.z0, c->shade.dzdx, c->shade.dzdy);
818 ci.ydwdy = interpolate(ys, c->shade.w0, c->shade.dwdx, c->shade.dwdy);
819 ci.ydfdy = interpolate(ys, c->shade.f0, c->shade.dfdx, c->shade.dfdy);
820 }
821
822 if (ggl_unlikely(enables & GGL_ENABLE_SMOOTH)) {
823 ci.ydrdy = interpolate(ys, c->shade.r0, c->shade.drdx, c->shade.drdy);
824 ci.ydgdy = interpolate(ys, c->shade.g0, c->shade.dgdx, c->shade.dgdy);
825 ci.ydbdy = interpolate(ys, c->shade.b0, c->shade.dbdx, c->shade.dbdy);
826 ci.ydady = interpolate(ys, c->shade.a0, c->shade.dadx, c->shade.dady);
827 c->step_y = step_y__smooth;
828 } else {
829 ci.ydrdy = c->shade.r0;
830 ci.ydgdy = c->shade.g0;
831 ci.ydbdy = c->shade.b0;
832 ci.ydady = c->shade.a0;
833 // XXX: do only if needed, or make sure this is fast
834 c->packed = ggl_pack_color(c, c->state.buffers.color.format,
835 ci.ydrdy, ci.ydgdy, ci.ydbdy, ci.ydady);
836 c->packed8888 = ggl_pack_color(c, GGL_PIXEL_FORMAT_RGBA_8888,
837 ci.ydrdy, ci.ydgdy, ci.ydbdy, ci.ydady);
838 }
839
840 // initialize the variables we need in the shader
841 generated_vars_t& gen = c->generated_vars;
842 gen.argb[GGLFormat::ALPHA].c = ci.ydady;
843 gen.argb[GGLFormat::ALPHA].dx = c->shade.dadx;
844 gen.argb[GGLFormat::RED ].c = ci.ydrdy;
845 gen.argb[GGLFormat::RED ].dx = c->shade.drdx;
846 gen.argb[GGLFormat::GREEN].c = ci.ydgdy;
847 gen.argb[GGLFormat::GREEN].dx = c->shade.dgdx;
848 gen.argb[GGLFormat::BLUE ].c = ci.ydbdy;
849 gen.argb[GGLFormat::BLUE ].dx = c->shade.dbdx;
850 gen.dzdx = c->shade.dzdx;
851 gen.f = ci.ydfdy;
852 gen.dfdx = c->shade.dfdx;
853
854 if (enables & GGL_ENABLE_TMUS) {
855 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
856 texture_t& t = c->state.texture[i];
857 if (!t.enable) continue;
858
859 texture_iterators_t& ti = t.iterators;
860 if (t.s_coord == GGL_ONE_TO_ONE && t.t_coord == GGL_ONE_TO_ONE) {
861 // we need to set all of these to 0 because in some cases
862 // step_y__generic() or step_y__tmu() will be used and
863 // therefore will update dtdy, however, in 1:1 mode
864 // this is always done by the scanline rasterizer.
865 ti.dsdx = ti.dsdy = ti.dtdx = ti.dtdy = 0;
866 ti.ydsdy = t.shade.is0;
867 ti.ydtdy = t.shade.it0;
868 } else {
869 const int adjustSWrap = ((t.s_wrap==GGL_CLAMP)?0:16);
870 const int adjustTWrap = ((t.t_wrap==GGL_CLAMP)?0:16);
871 ti.sscale = t.shade.sscale + adjustSWrap;
872 ti.tscale = t.shade.tscale + adjustTWrap;
873 if (!(enables & GGL_ENABLE_W)) {
874 // S coordinate
875 const int32_t sscale = ti.sscale;
876 const int32_t sy = interpolate(ys,
877 t.shade.is0, t.shade.idsdx, t.shade.idsdy);
878 if (sscale>=0) {
879 ti.ydsdy= sy << sscale;
880 ti.dsdx = t.shade.idsdx << sscale;
881 ti.dsdy = t.shade.idsdy << sscale;
882 } else {
883 ti.ydsdy= sy >> -sscale;
884 ti.dsdx = t.shade.idsdx >> -sscale;
885 ti.dsdy = t.shade.idsdy >> -sscale;
886 }
887 // T coordinate
888 const int32_t tscale = ti.tscale;
889 const int32_t ty = interpolate(ys,
890 t.shade.it0, t.shade.idtdx, t.shade.idtdy);
891 if (tscale>=0) {
892 ti.ydtdy= ty << tscale;
893 ti.dtdx = t.shade.idtdx << tscale;
894 ti.dtdy = t.shade.idtdy << tscale;
895 } else {
896 ti.ydtdy= ty >> -tscale;
897 ti.dtdx = t.shade.idtdx >> -tscale;
898 ti.dtdy = t.shade.idtdy >> -tscale;
899 }
900 }
901 }
902 // mirror for generated code...
903 generated_tex_vars_t& gen = c->generated_vars.texture[i];
904 gen.width = t.surface.width;
905 gen.height = t.surface.height;
906 gen.stride = t.surface.stride;
907 gen.data = int32_t(t.surface.data);
908 gen.dsdx = ti.dsdx;
909 gen.dtdx = ti.dtdx;
910 }
911 }
912
913 // choose the y-stepper
914 c->step_y = step_y__nop;
915 if (enables & GGL_ENABLE_FOG) {
916 c->step_y = step_y__generic;
917 } else if (enables & GGL_ENABLE_TMUS) {
918 if (enables & GGL_ENABLE_SMOOTH) {
919 c->step_y = step_y__generic;
920 } else if (enables & GGL_ENABLE_W) {
921 c->step_y = step_y__w;
922 } else {
923 c->step_y = step_y__tmu;
924 }
925 } else {
926 if (enables & GGL_ENABLE_SMOOTH) {
927 c->step_y = step_y__smooth;
928 }
929 }
930
931 // choose the rectangle blitter
932 c->rect = rect_generic;
933 if ((c->step_y == step_y__nop) &&
934 (c->scanline == scanline_memcpy))
935 {
936 c->rect = rect_memcpy;
937 }
938 }
939
940 void init_y_packed(context_t* c, int32_t y0)
941 {
942 uint8_t f = c->state.buffers.color.format;
943 c->packed = ggl_pack_color(c, f,
944 c->shade.r0, c->shade.g0, c->shade.b0, c->shade.a0);
945 c->iterators.y = y0;
946 c->step_y = step_y__nop;
947 // choose the rectangle blitter
948 c->rect = rect_generic;
949 if (c->scanline == scanline_memcpy) {
950 c->rect = rect_memcpy;
951 }
952 }
953
954 void init_y_noop(context_t* c, int32_t y0)
955 {
956 c->iterators.y = y0;
957 c->step_y = step_y__nop;
958 // choose the rectangle blitter
959 c->rect = rect_generic;
960 if (c->scanline == scanline_memcpy) {
961 c->rect = rect_memcpy;
962 }
963 }
964
965 void init_y_error(context_t* c, int32_t y0)
966 {
967 // woooops, shoud never happen,
968 // fail gracefully (don't display anything)
969 init_y_noop(c, y0);
970 LOGE("color-buffer has an invalid format!");
971 }
972
973 // ----------------------------------------------------------------------------
974 #if 0
975 #pragma mark -
976 #endif
977
978 void step_y__generic(context_t* c)
979 {
980 const uint32_t enables = c->state.enables;
981
982 // iterate...
983 iterators_t& ci = c->iterators;
984 ci.y += 1;
985
986 if (enables & GGL_ENABLE_SMOOTH) {
987 ci.ydrdy += c->shade.drdy;
988 ci.ydgdy += c->shade.dgdy;
989 ci.ydbdy += c->shade.dbdy;
990 ci.ydady += c->shade.dady;
991 }
992
993 const uint32_t mask =
994 GGL_ENABLE_DEPTH_TEST |
995 GGL_ENABLE_W |
996 GGL_ENABLE_FOG;
997 if (enables & mask) {
998 ci.ydzdy += c->shade.dzdy;
999 ci.ydwdy += c->shade.dwdy;
1000 ci.ydfdy += c->shade.dfdy;
1001 }
1002
1003 if ((enables & GGL_ENABLE_TMUS) && (!(enables & GGL_ENABLE_W))) {
1004 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
1005 if (c->state.texture[i].enable) {
1006 texture_iterators_t& ti = c->state.texture[i].iterators;
1007 ti.ydsdy += ti.dsdy;
1008 ti.ydtdy += ti.dtdy;
1009 }
1010 }
1011 }
1012 }
1013
1014 void step_y__nop(context_t* c)
1015 {
1016 c->iterators.y += 1;
1017 c->iterators.ydzdy += c->shade.dzdy;
1018 }
1019
1020 void step_y__smooth(context_t* c)
1021 {
1022 iterators_t& ci = c->iterators;
1023 ci.y += 1;
1024 ci.ydrdy += c->shade.drdy;
1025 ci.ydgdy += c->shade.dgdy;
1026 ci.ydbdy += c->shade.dbdy;
1027 ci.ydady += c->shade.dady;
1028 ci.ydzdy += c->shade.dzdy;
1029 }
1030
1031 void step_y__w(context_t* c)
1032 {
1033 iterators_t& ci = c->iterators;
1034 ci.y += 1;
1035 ci.ydzdy += c->shade.dzdy;
1036 ci.ydwdy += c->shade.dwdy;
1037 }
1038
1039 void step_y__tmu(context_t* c)
1040 {
1041 iterators_t& ci = c->iterators;
1042 ci.y += 1;
1043 ci.ydzdy += c->shade.dzdy;
1044 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
1045 if (c->state.texture[i].enable) {
1046 texture_iterators_t& ti = c->state.texture[i].iterators;
1047 ti.ydsdy += ti.dsdy;
1048 ti.ydtdy += ti.dtdy;
1049 }
1050 }
1051 }
1052
1053 // ----------------------------------------------------------------------------
1054 #if 0
1055 #pragma mark -
1056 #endif
1057
1058 void scanline_perspective(context_t* c)
1059 {
1060 struct {
1061 union {
1062 struct {
1063 int32_t s, sq;
1064 int32_t t, tq;
1065 };
1066 struct {
1067 int32_t v, q;
1068 } st[2];
1069 };
1070 } tc[GGL_TEXTURE_UNIT_COUNT] __attribute__((aligned(16)));
1071
1072 // XXX: we should have a special case when dwdx = 0
1073
1074 // 32 pixels spans works okay. 16 is a lot better,
1075 // but hey, it's a software renderer...
1076 const uint32_t SPAN_BITS = 5;
1077 const uint32_t ys = c->iterators.y;
1078 const uint32_t xs = c->iterators.xl;
1079 const uint32_t x1 = c->iterators.xr;
1080 const uint32_t xc = x1 - xs;
1081 uint32_t remainder = xc & ((1<<SPAN_BITS)-1);
1082 uint32_t numSpans = xc >> SPAN_BITS;
1083
1084 const iterators_t& ci = c->iterators;
1085 int32_t w0 = (xs * c->shade.dwdx) + ci.ydwdy;
1086 int32_t q0 = gglRecipQ(w0, 30);
1087 const int iwscale = 32 - gglClz(q0);
1088
1089 const int32_t dwdx = c->shade.dwdx << SPAN_BITS;
1090 int32_t xl = c->iterators.xl;
1091
1092 // We process s & t with a loop to reduce the code size
1093 // (and i-cache pressure).
1094
1095 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
1096 const texture_t& tmu = c->state.texture[i];
1097 if (!tmu.enable) continue;
1098 int32_t s = tmu.shade.is0 +
1099 (tmu.shade.idsdy * ys) + (tmu.shade.idsdx * xs) +
1100 ((tmu.shade.idsdx + tmu.shade.idsdy)>>1);
1101 int32_t t = tmu.shade.it0 +
1102 (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
1103 ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
1104 tc[i].s = s;
1105 tc[i].t = t;
1106 tc[i].sq = gglMulx(s, q0, iwscale);
1107 tc[i].tq = gglMulx(t, q0, iwscale);
1108 }
1109
1110 int32_t span = 0;
1111 do {
1112 int32_t w1;
1113 if (ggl_likely(numSpans)) {
1114 w1 = w0 + dwdx;
1115 } else {
1116 if (remainder) {
1117 // finish off the scanline...
1118 span = remainder;
1119 w1 = (c->shade.dwdx * span) + w0;
1120 } else {
1121 break;
1122 }
1123 }
1124 int32_t q1 = gglRecipQ(w1, 30);
1125 for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
1126 texture_t& tmu = c->state.texture[i];
1127 if (!tmu.enable) continue;
1128 texture_iterators_t& ti = tmu.iterators;
1129
1130 for (int j=0 ; j<2 ; j++) {
1131 int32_t v = tc[i].st[j].v;
1132 if (span) v += (tmu.shade.st[j].dx)*span;
1133 else v += (tmu.shade.st[j].dx)<<SPAN_BITS;
1134 const int32_t v0 = tc[i].st[j].q;
1135 const int32_t v1 = gglMulx(v, q1, iwscale);
1136 int32_t dvdx = v1 - v0;
1137 if (span) dvdx /= span;
1138 else dvdx >>= SPAN_BITS;
1139 tc[i].st[j].v = v;
1140 tc[i].st[j].q = v1;
1141
1142 const int scale = ti.st[j].scale + (iwscale - 30);
1143 if (scale >= 0) {
1144 ti.st[j].ydvdy = v0 << scale;
1145 ti.st[j].dvdx = dvdx << scale;
1146 } else {
1147 ti.st[j].ydvdy = v0 >> -scale;
1148 ti.st[j].dvdx = dvdx >> -scale;
1149 }
1150 }
1151 generated_tex_vars_t& gen = c->generated_vars.texture[i];
1152 gen.dsdx = ti.st[0].dvdx;
1153 gen.dtdx = ti.st[1].dvdx;
1154 }
1155 c->iterators.xl = xl;
1156 c->iterators.xr = xl = xl + (span ? span : (1<<SPAN_BITS));
1157 w0 = w1;
1158 q0 = q1;
1159 c->span(c);
1160 } while(numSpans--);
1161 }
1162
1163 void scanline_perspective_single(context_t* c)
1164 {
1165 // 32 pixels spans works okay. 16 is a lot better,
1166 // but hey, it's a software renderer...
1167 const uint32_t SPAN_BITS = 5;
1168 const uint32_t ys = c->iterators.y;
1169 const uint32_t xs = c->iterators.xl;
1170 const uint32_t x1 = c->iterators.xr;
1171 const uint32_t xc = x1 - xs;
1172
1173 const iterators_t& ci = c->iterators;
1174 int32_t w = (xs * c->shade.dwdx) + ci.ydwdy;
1175 int32_t iw = gglRecipQ(w, 30);
1176 const int iwscale = 32 - gglClz(iw);
1177
1178 const int i = 31 - gglClz(c->state.enabled_tmu);
1179 generated_tex_vars_t& gen = c->generated_vars.texture[i];
1180 texture_t& tmu = c->state.texture[i];
1181 texture_iterators_t& ti = tmu.iterators;
1182 const int sscale = ti.sscale + (iwscale - 30);
1183 const int tscale = ti.tscale + (iwscale - 30);
1184 int32_t s = tmu.shade.is0 +
1185 (tmu.shade.idsdy * ys) + (tmu.shade.idsdx * xs) +
1186 ((tmu.shade.idsdx + tmu.shade.idsdy)>>1);
1187 int32_t t = tmu.shade.it0 +
1188 (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
1189 ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
1190 int32_t s0 = gglMulx(s, iw, iwscale);
1191 int32_t t0 = gglMulx(t, iw, iwscale);
1192 int32_t xl = c->iterators.xl;
1193
1194 int32_t sq, tq, dsdx, dtdx;
1195 int32_t premainder = xc & ((1<<SPAN_BITS)-1);
1196 uint32_t numSpans = xc >> SPAN_BITS;
1197 if (c->shade.dwdx == 0) {
1198 // XXX: we could choose to do this if the error is small enough
1199 numSpans = 0;
1200 premainder = xc;
1201 goto no_perspective;
1202 }
1203
1204 if (premainder) {
1205 w += c->shade.dwdx * premainder;
1206 iw = gglRecipQ(w, 30);
1207 no_perspective:
1208 s += tmu.shade.idsdx * premainder;
1209 t += tmu.shade.idtdx * premainder;
1210 sq = gglMulx(s, iw, iwscale);
1211 tq = gglMulx(t, iw, iwscale);
1212 dsdx = (sq - s0) / premainder;
1213 dtdx = (tq - t0) / premainder;
1214 c->iterators.xl = xl;
1215 c->iterators.xr = xl = xl + premainder;
1216 goto finish;
1217 }
1218
1219 while (numSpans--) {
1220 w += c->shade.dwdx << SPAN_BITS;
1221 s += tmu.shade.idsdx << SPAN_BITS;
1222 t += tmu.shade.idtdx << SPAN_BITS;
1223 iw = gglRecipQ(w, 30);
1224 sq = gglMulx(s, iw, iwscale);
1225 tq = gglMulx(t, iw, iwscale);
1226 dsdx = (sq - s0) >> SPAN_BITS;
1227 dtdx = (tq - t0) >> SPAN_BITS;
1228 c->iterators.xl = xl;
1229 c->iterators.xr = xl = xl + (1<<SPAN_BITS);
1230 finish:
1231 if (sscale >= 0) {
1232 ti.ydsdy = s0 << sscale;
1233 ti.dsdx = dsdx << sscale;
1234 } else {
1235 ti.ydsdy = s0 >>-sscale;
1236 ti.dsdx = dsdx >>-sscale;
1237 }
1238 if (tscale >= 0) {
1239 ti.ydtdy = t0 << tscale;
1240 ti.dtdx = dtdx << tscale;
1241 } else {
1242 ti.ydtdy = t0 >>-tscale;
1243 ti.dtdx = dtdx >>-tscale;
1244 }
1245 s0 = sq;
1246 t0 = tq;
1247 gen.dsdx = ti.dsdx;
1248 gen.dtdx = ti.dtdx;
1249 c->span(c);
1250 }
1251 }
1252
1253 // ----------------------------------------------------------------------------
1254
1255 void scanline_t32cb16(context_t* c)
1256 {
1257 int32_t x = c->iterators.xl;
1258 size_t ct = c->iterators.xr - x;
1259 int32_t y = c->iterators.y;
1260 surface_t* cb = &(c->state.buffers.color);
1261 union {
1262 uint16_t* dst;
1263 uint32_t* dst32;
1264 };
1265 dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
1266
1267 surface_t* tex = &(c->state.texture[0].surface);
1268 const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
1269 const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
1270 uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
1271 int sR, sG, sB;
1272 uint32_t s, d;
1273
1274 if (ct==1 || uint32_t(dst)&2) {
1275 last_one:
1276 s = GGL_RGBA_TO_HOST( *src++ );
1277 sR = (s >> ( 3))&0x1F;
1278 sG = (s >> ( 8+2))&0x3F;
1279 sB = (s >> (16+3))&0x1F;
1280 *dst++ = uint16_t((sR<<11)|(sG<<5)|sB);
1281 ct--;
1282 }
1283
1284 while (ct >= 2) {
1285 s = GGL_RGBA_TO_HOST( *src++ );
1286 sR = (s >> ( 3))&0x1F;
1287 sG = (s >> ( 8+2))&0x3F;
1288 sB = (s >> (16+3))&0x1F;
1289 d = (sR<<11)|(sG<<5)|sB;
1290
1291 s = GGL_RGBA_TO_HOST( *src++ );
1292 sR = (s >> ( 3))&0x1F;
1293 sG = (s >> ( 8+2))&0x3F;
1294 sB = (s >> (16+3))&0x1F;
1295 d |= ((sR<<11)|(sG<<5)|sB)<<16;
1296
1297 #if BYTE_ORDER == BIG_ENDIAN
1298 d = (d>>16) | (d<<16);
1299 #endif
1300
1301 *dst32++ = d;
1302 ct -= 2;
1303 }
1304
1305 if (ct > 0) {
1306 goto last_one;
1307 }
1308 }
1309
1310 void scanline_t32cb16blend(context_t* c)
1311 {
1312 int32_t x = c->iterators.xl;
1313 size_t ct = c->iterators.xr - x;
1314 int32_t y = c->iterators.y;
1315 surface_t* cb = &(c->state.buffers.color);
1316 uint16_t* dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
1317
1318 surface_t* tex = &(c->state.texture[0].surface);
1319 const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
1320 const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
1321 uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
1322
1323 #if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__arm__))
1324 scanline_t32cb16blend_arm(dst, src, ct);
1325 #else
1326 while (ct--) {
1327 uint32_t s = *src++;
1328 if (!s) {
1329 dst++;
1330 continue;
1331 }
1332 uint16_t d = *dst;
1333 s = GGL_RGBA_TO_HOST(s);
1334 int sR = (s >> ( 3))&0x1F;
1335 int sG = (s >> ( 8+2))&0x3F;
1336 int sB = (s >> (16+3))&0x1F;
1337 int sA = (s>>24);
1338 int f = 0x100 - (sA + (sA>>7));
1339 int dR = (d>>11)&0x1f;
1340 int dG = (d>>5)&0x3f;
1341 int dB = (d)&0x1f;
1342 sR += (f*dR)>>8;
1343 sG += (f*dG)>>8;
1344 sB += (f*dB)>>8;
1345 *dst++ = uint16_t((sR<<11)|(sG<<5)|sB);
1346 }
1347 #endif
1348 }
1349
1350 void scanline_memcpy(context_t* c)
1351 {
1352 int32_t x = c->iterators.xl;
1353 size_t ct = c->iterators.xr - x;
1354 int32_t y = c->iterators.y;
1355 surface_t* cb = &(c->state.buffers.color);
1356 const GGLFormat* fp = &(c->formats[cb->format]);
1357 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
1358 (x + (cb->stride * y)) * fp->size;
1359
1360 surface_t* tex = &(c->state.texture[0].surface);
1361 const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
1362 const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
1363 uint8_t *src = reinterpret_cast<uint8_t*>(tex->data) +
1364 (u + (tex->stride * v)) * fp->size;
1365
1366 const size_t size = ct * fp->size;
1367 memcpy(dst, src, size);
1368 }
1369
1370 void scanline_memset8(context_t* c)
1371 {
1372 int32_t x = c->iterators.xl;
1373 size_t ct = c->iterators.xr - x;
1374 int32_t y = c->iterators.y;
1375 surface_t* cb = &(c->state.buffers.color);
1376 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) + (x+(cb->stride*y));
1377 uint32_t packed = c->packed;
1378 memset(dst, packed, ct);
1379 }
1380
1381 void scanline_memset16(context_t* c)
1382 {
1383 int32_t x = c->iterators.xl;
1384 size_t ct = c->iterators.xr - x;
1385 int32_t y = c->iterators.y;
1386 surface_t* cb = &(c->state.buffers.color);
1387 uint16_t* dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
1388 uint32_t packed = c->packed;
1389 android_memset16(dst, packed, ct*2);
1390 }
1391
1392 void scanline_memset32(context_t* c)
1393 {
1394 int32_t x = c->iterators.xl;
1395 size_t ct = c->iterators.xr - x;
1396 int32_t y = c->iterators.y;
1397 surface_t* cb = &(c->state.buffers.color);
1398 uint32_t* dst = reinterpret_cast<uint32_t*>(cb->data) + (x+(cb->stride*y));
1399 uint32_t packed = GGL_HOST_TO_RGBA(c->packed);
1400 android_memset32(dst, packed, ct*4);
1401 }
1402
1403 void scanline_clear(context_t* c)
1404 {
1405 int32_t x = c->iterators.xl;
1406 size_t ct = c->iterators.xr - x;
1407 int32_t y = c->iterators.y;
1408 surface_t* cb = &(c->state.buffers.color);
1409 const GGLFormat* fp = &(c->formats[cb->format]);
1410 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
1411 (x + (cb->stride * y)) * fp->size;
1412 const size_t size = ct * fp->size;
1413 memset(dst, 0, size);
1414 }
1415
1416 void scanline_set(context_t* c)
1417 {
1418 int32_t x = c->iterators.xl;
1419 size_t ct = c->iterators.xr - x;
1420 int32_t y = c->iterators.y;
1421 surface_t* cb = &(c->state.buffers.color);
1422 const GGLFormat* fp = &(c->formats[cb->format]);
1423 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
1424 (x + (cb->stride * y)) * fp->size;
1425 const size_t size = ct * fp->size;
1426 memset(dst, 0xFF, size);
1427 }
1428
1429 void scanline_noop(context_t* c)
1430 {
1431 }
1432
1433 void rect_generic(context_t* c, size_t yc)
1434 {
1435 do {
1436 c->scanline(c);
1437 c->step_y(c);
1438 } while (--yc);
1439 }
1440
1441 void rect_memcpy(context_t* c, size_t yc)
1442 {
1443 int32_t x = c->iterators.xl;
1444 size_t ct = c->iterators.xr - x;
1445 int32_t y = c->iterators.y;
1446 surface_t* cb = &(c->state.buffers.color);
1447 const GGLFormat* fp = &(c->formats[cb->format]);
1448 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
1449 (x + (cb->stride * y)) * fp->size;
1450
1451 surface_t* tex = &(c->state.texture[0].surface);
1452 const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
1453 const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
1454 uint8_t *src = reinterpret_cast<uint8_t*>(tex->data) +
1455 (u + (tex->stride * v)) * fp->size;
1456
1457 if (cb->stride == tex->stride && ct == size_t(cb->stride)) {
1458 memcpy(dst, src, ct * fp->size * yc);
1459 } else {
1460 const size_t size = ct * fp->size;
1461 const size_t dbpr = cb->stride * fp->size;
1462 const size_t sbpr = tex->stride * fp->size;
1463 do {
1464 memcpy(dst, src, size);
1465 dst += dbpr;
1466 src += sbpr;
1467 } while (--yc);
1468 }
1469 }
1470 // ----------------------------------------------------------------------------
1471 }; // namespace android
1472
1473 using namespace android;
1474 extern "C" void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t1)
1475 {
1476 #if ANDROID_ARM_CODEGEN
1477 GGLContext* c;
1478 gglInit(&c);
1479 needs_t needs;
1480 needs.n = n;
1481 needs.p = p;
1482 needs.t[0] = t0;
1483 needs.t[1] = t1;
1484 sp<ScanlineAssembly> a(new ScanlineAssembly(needs, ASSEMBLY_SCRATCH_SIZE));
1485 GGLAssembler assembler( new ARMAssembler(a) );
1486 int err = assembler.scanline(needs, (context_t*)c);
1487 if (err != 0) {
1488 printf("error %08x (%s)\n", err, strerror(-err));
1489 }
1490 gglUninit(c);
1491 #else
1492 printf("This test runs only on ARM\n");
1493 #endif
1494 }
1495
+0
-32
libpixelflinger/scanline.h less more
0 /* libs/pixelflinger/scanline.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_SCANLINE_H
19 #define ANDROID_SCANLINE_H
20
21 #include <private/pixelflinger/ggl_context.h>
22
23 namespace android {
24
25 void ggl_init_scanline(context_t* c);
26 void ggl_uninit_scanline(context_t* c);
27 void ggl_pick_scanline(context_t* c);
28
29 }; // namespace android
30
31 #endif
+0
-171
libpixelflinger/t32cb16blend.S less more
0 /* libs/pixelflinger/t32cb16blend.S
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 .text
19 .align
20
21 .global scanline_t32cb16blend_arm
22
23 // uses r6, r7, lr
24
25 .macro pixel, DREG, SRC, FB, OFFSET
26
27 // SRC = AARRGGBB
28 mov r7, \SRC, lsr #24 // sA
29 add r7, r7, r7, lsr #7 // sA + (sA >> 7)
30 rsb r7, r7, #0x100 // sA = 0x100 - (sA+(sA>>7))
31
32 1:
33
34 .if \OFFSET
35
36 // red
37 mov lr, \DREG, lsr #(\OFFSET + 6 + 5)
38 smulbb lr, r7, lr
39 mov r6, \SRC, lsr #3
40 and r6, r6, #0x1F
41 add lr, r6, lr, lsr #8
42 orr \FB, lr, lsl #(\OFFSET + 11)
43
44 // green
45 and r6, \DREG, #(0x3F<<(\OFFSET + 5))
46 smulbt r6, r7, r6
47 mov lr, \SRC, lsr #(8+2)
48 and lr, lr, #0x3F
49 add r6, lr, r6, lsr #(5+8)
50 orr \FB, \FB, r6, lsl #(\OFFSET + 5)
51
52 // blue
53 and lr, \DREG, #(0x1F << \OFFSET)
54 smulbt lr, r7, lr
55 mov r6, \SRC, lsr #(8+8+3)
56 and r6, r6, #0x1F
57 add lr, r6, lr, lsr #8
58 orr \FB, \FB, lr, lsl #\OFFSET
59
60 .else
61
62 // red
63 mov lr, \DREG, lsr #(6+5)
64 and lr, lr, #0x1F
65 smulbb lr, r7, lr
66 mov r6, \SRC, lsr #3
67 and r6, r6, #0x1F
68 add lr, r6, lr, lsr #8
69 mov \FB, lr, lsl #11
70
71 // green
72 and r6, \DREG, #(0x3F<<5)
73 smulbb r6, r7, r6
74 mov lr, \SRC, lsr #(8+2)
75 and lr, lr, #0x3F
76 add r6, lr, r6, lsr #(5+8)
77 orr \FB, \FB, r6, lsl #5
78
79 // blue
80 and lr, \DREG, #0x1F
81 smulbb lr, r7, lr
82 mov r6, \SRC, lsr #(8+8+3)
83 and r6, r6, #0x1F
84 add lr, r6, lr, lsr #8
85 orr \FB, \FB, lr
86
87 .endif
88
89 .endm
90
91
92 // r0: dst ptr
93 // r1: src ptr
94 // r2: count
95 // r3: d
96 // r4: s0
97 // r5: s1
98 // r6: pixel
99 // r7: pixel
100 // r8: free
101 // r9: free
102 // r10: free
103 // r11: free
104 // r12: scratch
105 // r14: pixel
106
107 scanline_t32cb16blend_arm:
108 stmfd sp!, {r4-r7, lr}
109
110 pld [r0]
111 pld [r1]
112
113 // align DST to 32 bits
114 tst r0, #0x3
115 beq aligned
116 subs r2, r2, #1
117 ldmlofd sp!, {r4-r7, lr} // return
118 bxlo lr
119
120 last:
121 ldr r4, [r1], #4
122 ldrh r3, [r0]
123 pixel r3, r4, r12, 0
124 strh r12, [r0], #2
125
126 aligned:
127 subs r2, r2, #2
128 blo 9f
129
130 // The main loop is unrolled twice and process 4 pixels
131 8: ldmia r1!, {r4, r5}
132 // stream the source
133 pld [r1, #32]
134 add r0, r0, #4
135 // it's all zero, skip this pixel
136 orrs r3, r4, r5
137 beq 7f
138
139 // load the destination
140 ldr r3, [r0, #-4]
141 // stream the destination
142 pld [r0, #32]
143 pixel r3, r4, r12, 0
144 pixel r3, r5, r12, 16
145 // effectively, we're getting write-combining by virtue of the
146 // cpu's write-back cache.
147 str r12, [r0, #-4]
148
149 // 2nd iterration of the loop, don't stream anything
150 subs r2, r2, #2
151 movlt r4, r5
152 blt 9f
153 ldmia r1!, {r4, r5}
154 add r0, r0, #4
155 orrs r3, r4, r5
156 beq 7f
157 ldr r3, [r0, #-4]
158 pixel r3, r4, r12, 0
159 pixel r3, r5, r12, 16
160 str r12, [r0, #-4]
161
162
163 7: subs r2, r2, #2
164 bhs 8b
165 mov r4, r5
166
167 9: adds r2, r2, #1
168 ldmlofd sp!, {r4-r7, lr} // return
169 bxlo lr
170 b last
+0
-1
libpixelflinger/tests/Android.mk less more
0 include $(all-subdir-makefiles)
+0
-15
libpixelflinger/tests/codegen/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 LOCAL_SRC_FILES:= \
4 codegen.cpp
5
6 LOCAL_SHARED_LIBRARIES := \
7 libcutils \
8 libpixelflinger
9
10 LOCAL_MODULE:= test-opengl-codegen
11
12 LOCAL_MODULE_TAGS := tests
13
14 include $(BUILD_EXECUTABLE)
+0
-21
libpixelflinger/tests/codegen/codegen.cpp less more
0 #include <stdio.h>
1 #include <stdint.h>
2
3 extern "C" void ggl_test_codegen(
4 uint32_t n, uint32_t p, uint32_t t0, uint32_t t1);
5
6
7 int main(int argc, char** argv)
8 {
9 if (argc != 2) {
10 printf("usage: %s 00000117:03454504_00001501_00000000\n", argv[0]);
11 return 0;
12 }
13 uint32_t n;
14 uint32_t p;
15 uint32_t t0;
16 uint32_t t1;
17 sscanf(argv[1], "%08x:%08x_%08x_%08x", &p, &n, &t0, &t1);
18 ggl_test_codegen(n, p, t0, t1);
19 return 0;
20 }
+0
-193
libpixelflinger/tinyutils/KeyedVector.h less more
0 /*
1 * keyed_vector.h
2 * Android
3 *
4 * Created on 11/18/05.
5 * Copyright 2005 The Android Open Source Project
6 *
7 */
8
9 #ifndef ANDROID_KEYED_VECTOR_H
10 #define ANDROID_KEYED_VECTOR_H
11
12 #include <assert.h>
13 #include <stdint.h>
14 #include <sys/types.h>
15
16 #include "tinyutils/SortedVector.h"
17 #include "tinyutils/TypeHelpers.h"
18
19 // ---------------------------------------------------------------------------
20
21 namespace android {
22
23 template <typename KEY, typename VALUE>
24 class KeyedVector
25 {
26 public:
27 typedef KEY key_type;
28 typedef VALUE value_type;
29
30 inline KeyedVector();
31
32 /*
33 * empty the vector
34 */
35
36 inline void clear() { mVector.clear(); }
37
38 /*!
39 * vector stats
40 */
41
42 //! returns number of items in the vector
43 inline size_t size() const { return mVector.size(); }
44 //! returns wether or not the vector is empty
45 inline bool isEmpty() const { return mVector.isEmpty(); }
46 //! returns how many items can be stored without reallocating the backing store
47 inline size_t capacity() const { return mVector.capacity(); }
48 //! setst the capacity. capacity can never be reduced less than size()
49 inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); }
50
51 /*!
52 * accessors
53 */
54 const VALUE& valueFor(const KEY& key) const;
55 const VALUE& valueAt(size_t index) const;
56 const KEY& keyAt(size_t index) const;
57 ssize_t indexOfKey(const KEY& key) const;
58
59 /*!
60 * modifing the array
61 */
62
63 VALUE& editValueFor(const KEY& key);
64 VALUE& editValueAt(size_t index);
65
66 /*!
67 * add/insert/replace items
68 */
69
70 ssize_t add(const KEY& key, const VALUE& item);
71 ssize_t replaceValueFor(const KEY& key, const VALUE& item);
72 ssize_t replaceValueAt(size_t index, const VALUE& item);
73
74 /*!
75 * remove items
76 */
77
78 ssize_t removeItem(const KEY& key);
79 ssize_t removeItemsAt(size_t index, size_t count = 1);
80
81 private:
82 SortedVector< key_value_pair_t<KEY, VALUE> > mVector;
83 };
84
85 // ---------------------------------------------------------------------------
86
87 /**
88 * Variation of KeyedVector that holds a default value to return when
89 * valueFor() is called with a key that doesn't exist.
90 */
91 template <typename KEY, typename VALUE>
92 class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
93 {
94 public:
95 inline DefaultKeyedVector(const VALUE& defValue = VALUE());
96 const VALUE& valueFor(const KEY& key) const;
97
98 private:
99 VALUE mDefault;
100 };
101
102 // ---------------------------------------------------------------------------
103
104 template<typename KEY, typename VALUE> inline
105 KeyedVector<KEY,VALUE>::KeyedVector()
106 {
107 }
108
109 template<typename KEY, typename VALUE> inline
110 ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
111 return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
112 }
113
114 template<typename KEY, typename VALUE> inline
115 const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
116 ssize_t i = indexOfKey(key);
117 assert(i>=0);
118 return mVector.itemAt(i).value;
119 }
120
121 template<typename KEY, typename VALUE> inline
122 const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const {
123 return mVector.itemAt(index).value;
124 }
125
126 template<typename KEY, typename VALUE> inline
127 const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
128 return mVector.itemAt(index).key;
129 }
130
131 template<typename KEY, typename VALUE> inline
132 VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
133 ssize_t i = indexOfKey(key);
134 assert(i>=0);
135 return mVector.editItemAt(i).value;
136 }
137
138 template<typename KEY, typename VALUE> inline
139 VALUE& KeyedVector<KEY,VALUE>::editValueAt(size_t index) {
140 return mVector.editItemAt(index).value;
141 }
142
143 template<typename KEY, typename VALUE> inline
144 ssize_t KeyedVector<KEY,VALUE>::add(const KEY& key, const VALUE& value) {
145 return mVector.add( key_value_pair_t<KEY,VALUE>(key, value) );
146 }
147
148 template<typename KEY, typename VALUE> inline
149 ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& value) {
150 key_value_pair_t<KEY,VALUE> pair(key, value);
151 mVector.remove(pair);
152 return mVector.add(pair);
153 }
154
155 template<typename KEY, typename VALUE> inline
156 ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
157 if (index<size()) {
158 mVector.editValueAt(index).value = item;
159 return index;
160 }
161 return BAD_INDEX;
162 }
163
164 template<typename KEY, typename VALUE> inline
165 ssize_t KeyedVector<KEY,VALUE>::removeItem(const KEY& key) {
166 return mVector.remove(key_value_pair_t<KEY,VALUE>(key));
167 }
168
169 template<typename KEY, typename VALUE> inline
170 ssize_t KeyedVector<KEY, VALUE>::removeItemsAt(size_t index, size_t count) {
171 return mVector.removeItemsAt(index, count);
172 }
173
174 // ---------------------------------------------------------------------------
175
176 template<typename KEY, typename VALUE> inline
177 DefaultKeyedVector<KEY,VALUE>::DefaultKeyedVector(const VALUE& defValue)
178 : mDefault(defValue)
179 {
180 }
181
182 template<typename KEY, typename VALUE> inline
183 const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
184 ssize_t i = indexOfKey(key);
185 return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
186 }
187
188 }; // namespace android
189
190 // ---------------------------------------------------------------------------
191
192 #endif // ANDROID_KEYED_VECTOR_H
+0
-106
libpixelflinger/tinyutils/SharedBuffer.cpp less more
0 /*
1 * SharedBuffer.cpp
2 * Android
3 *
4 * Copyright 2005 The Android Open Source Project
5 *
6 */
7
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <cutils/atomic.h>
12
13 #include "tinyutils/SharedBuffer.h"
14
15 // ---------------------------------------------------------------------------
16
17 namespace android {
18
19 SharedBuffer* SharedBuffer::alloc(size_t size)
20 {
21 SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
22 if (sb) {
23 sb->mRefs = 1;
24 sb->mSize = size;
25 }
26 return sb;
27 }
28
29
30 ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
31 {
32 if (released->mRefs != 0) return -1; // XXX: invalid operation
33 free(const_cast<SharedBuffer*>(released));
34 return 0;
35 }
36
37 SharedBuffer* SharedBuffer::edit() const
38 {
39 if (onlyOwner()) {
40 return const_cast<SharedBuffer*>(this);
41 }
42 SharedBuffer* sb = alloc(mSize);
43 if (sb) {
44 memcpy(sb->data(), data(), size());
45 release();
46 }
47 return sb;
48 }
49
50 SharedBuffer* SharedBuffer::editResize(size_t newSize) const
51 {
52 if (onlyOwner()) {
53 SharedBuffer* buf = const_cast<SharedBuffer*>(this);
54 if (buf->mSize == newSize) return buf;
55 buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
56 if (buf != NULL) {
57 buf->mSize = newSize;
58 return buf;
59 }
60 }
61 SharedBuffer* sb = alloc(newSize);
62 if (sb) {
63 const size_t mySize = mSize;
64 memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
65 release();
66 }
67 return sb;
68 }
69
70 SharedBuffer* SharedBuffer::attemptEdit() const
71 {
72 if (onlyOwner()) {
73 return const_cast<SharedBuffer*>(this);
74 }
75 return 0;
76 }
77
78 SharedBuffer* SharedBuffer::reset(size_t new_size) const
79 {
80 // cheap-o-reset.
81 SharedBuffer* sb = alloc(new_size);
82 if (sb) {
83 release();
84 }
85 return sb;
86 }
87
88 void SharedBuffer::acquire() const {
89 android_atomic_inc(&mRefs);
90 }
91
92 int32_t SharedBuffer::release(uint32_t flags) const
93 {
94 int32_t prev = 1;
95 if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
96 mRefs = 0;
97 if ((flags & eKeepStorage) == 0) {
98 free(const_cast<SharedBuffer*>(this));
99 }
100 }
101 return prev;
102 }
103
104
105 }; // namespace android
+0
-138
libpixelflinger/tinyutils/SharedBuffer.h less more
0 /*
1 * SharedBuffer.h
2 * Android
3 *
4 * Copyright 2005 The Android Open Source Project
5 *
6 */
7
8 #ifndef ANDROID_SHARED_BUFFER_H
9 #define ANDROID_SHARED_BUFFER_H
10
11 #include <stdint.h>
12 #include <sys/types.h>
13
14 // ---------------------------------------------------------------------------
15
16 namespace android {
17
18 class SharedBuffer
19 {
20 public:
21
22 /* flags to use with release() */
23 enum {
24 eKeepStorage = 0x00000001
25 };
26
27 /*! allocate a buffer of size 'size' and acquire() it.
28 * call release() to free it.
29 */
30 static SharedBuffer* alloc(size_t size);
31
32 /*! free the memory associated with the SharedBuffer.
33 * Fails if there are any users associated with this SharedBuffer.
34 * In other words, the buffer must have been release by all its
35 * users.
36 */
37 static ssize_t dealloc(const SharedBuffer* released);
38
39 //! get the SharedBuffer from the data pointer
40 static inline const SharedBuffer* sharedBuffer(const void* data);
41
42 //! access the data for read
43 inline const void* data() const;
44
45 //! access the data for read/write
46 inline void* data();
47
48 //! get size of the buffer
49 inline size_t size() const;
50
51 //! get back a SharedBuffer object from its data
52 static inline SharedBuffer* bufferFromData(void* data);
53
54 //! get back a SharedBuffer object from its data
55 static inline const SharedBuffer* bufferFromData(const void* data);
56
57 //! get the size of a SharedBuffer object from its data
58 static inline size_t sizeFromData(const void* data);
59
60 //! edit the buffer (get a writtable, or non-const, version of it)
61 SharedBuffer* edit() const;
62
63 //! edit the buffer, resizing if needed
64 SharedBuffer* editResize(size_t size) const;
65
66 //! like edit() but fails if a copy is required
67 SharedBuffer* attemptEdit() const;
68
69 //! resize and edit the buffer, loose it's content.
70 SharedBuffer* reset(size_t size) const;
71
72 //! acquire/release a reference on this buffer
73 void acquire() const;
74
75 /*! release a reference on this buffer, with the option of not
76 * freeing the memory associated with it if it was the last reference
77 * returns the previous reference count
78 */
79 int32_t release(uint32_t flags = 0) const;
80
81 //! returns wether or not we're the only owner
82 inline bool onlyOwner() const;
83
84
85 private:
86 inline SharedBuffer() { }
87 inline ~SharedBuffer() { }
88 inline SharedBuffer(const SharedBuffer&);
89
90 // 16 bytes. must be sized to preserve correct alingment.
91 mutable int32_t mRefs;
92 size_t mSize;
93 uint32_t mReserved[2];
94 };
95
96 // ---------------------------------------------------------------------------
97
98 const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
99 return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
100 }
101
102 const void* SharedBuffer::data() const {
103 return this + 1;
104 }
105
106 void* SharedBuffer::data() {
107 return this + 1;
108 }
109
110 size_t SharedBuffer::size() const {
111 return mSize;
112 }
113
114 SharedBuffer* SharedBuffer::bufferFromData(void* data)
115 {
116 return ((SharedBuffer*)data)-1;
117 }
118
119 const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
120 {
121 return ((const SharedBuffer*)data)-1;
122 }
123
124 size_t SharedBuffer::sizeFromData(const void* data)
125 {
126 return (((const SharedBuffer*)data)-1)->mSize;
127 }
128
129 bool SharedBuffer::onlyOwner() const {
130 return (mRefs == 1);
131 }
132
133 }; // namespace android
134
135 // ---------------------------------------------------------------------------
136
137 #endif // ANDROID_VECTOR_H
+0
-245
libpixelflinger/tinyutils/TypeHelpers.h less more
0 /*
1 * TypeHelpers.h
2 *
3 * Copyright 2005 The Android Open Source Project
4 *
5 */
6
7 #ifndef ANDROID_TYPE_HELPERS_H
8 #define ANDROID_TYPE_HELPERS_H
9
10 #include <new>
11 #include <stdint.h>
12 #include <string.h>
13 #include <sys/types.h>
14
15 // ---------------------------------------------------------------------------
16
17 namespace android {
18
19 /*
20 * Types traits
21 */
22
23 template <typename T> struct trait_trivial_ctor { enum { value = false }; };
24 template <typename T> struct trait_trivial_dtor { enum { value = false }; };
25 template <typename T> struct trait_trivial_copy { enum { value = false }; };
26 template <typename T> struct trait_trivial_assign{ enum { value = false }; };
27
28 template <typename T> struct trait_pointer { enum { value = false }; };
29 template <typename T> struct trait_pointer<T*> { enum { value = true }; };
30
31 #define ANDROID_BASIC_TYPES_TRAITS( T ) \
32 template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
33 template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
34 template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
35 template<> struct trait_trivial_assign< T >{ enum { value = true }; };
36
37 #define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
38 template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
39 template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
40 template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
41 template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
42
43 template <typename TYPE>
44 struct traits {
45 enum {
46 is_pointer = trait_pointer<TYPE>::value,
47 has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
48 has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
49 has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
50 has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
51 };
52 };
53
54 template <typename T, typename U>
55 struct aggregate_traits {
56 enum {
57 is_pointer = false,
58 has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
59 has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
60 has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
61 has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
62 };
63 };
64
65 // ---------------------------------------------------------------------------
66
67 /*
68 * basic types traits
69 */
70
71 ANDROID_BASIC_TYPES_TRAITS( void );
72 ANDROID_BASIC_TYPES_TRAITS( bool );
73 ANDROID_BASIC_TYPES_TRAITS( char );
74 ANDROID_BASIC_TYPES_TRAITS( unsigned char );
75 ANDROID_BASIC_TYPES_TRAITS( short );
76 ANDROID_BASIC_TYPES_TRAITS( unsigned short );
77 ANDROID_BASIC_TYPES_TRAITS( int );
78 ANDROID_BASIC_TYPES_TRAITS( unsigned int );
79 ANDROID_BASIC_TYPES_TRAITS( long );
80 ANDROID_BASIC_TYPES_TRAITS( unsigned long );
81 ANDROID_BASIC_TYPES_TRAITS( long long );
82 ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
83 ANDROID_BASIC_TYPES_TRAITS( float );
84 ANDROID_BASIC_TYPES_TRAITS( double );
85
86 // ---------------------------------------------------------------------------
87
88
89 /*
90 * compare and order types
91 */
92
93 template<typename TYPE> inline
94 int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
95 return (lhs < rhs) ? 1 : 0;
96 }
97
98 template<typename TYPE> inline
99 int compare_type(const TYPE& lhs, const TYPE& rhs) {
100 return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
101 }
102
103 /*
104 * create, destroy, copy and assign types...
105 */
106
107 template<typename TYPE> inline
108 void construct_type(TYPE* p, size_t n) {
109 if (!traits<TYPE>::has_trivial_ctor) {
110 while (n--) {
111 new(p++) TYPE;
112 }
113 }
114 }
115
116 template<typename TYPE> inline
117 void destroy_type(TYPE* p, size_t n) {
118 if (!traits<TYPE>::has_trivial_dtor) {
119 while (n--) {
120 p->~TYPE();
121 p++;
122 }
123 }
124 }
125
126 template<typename TYPE> inline
127 void copy_type(TYPE* d, const TYPE* s, size_t n) {
128 if (!traits<TYPE>::has_trivial_copy) {
129 while (n--) {
130 new(d) TYPE(*s);
131 d++, s++;
132 }
133 } else {
134 memcpy(d,s,n*sizeof(TYPE));
135 }
136 }
137
138 template<typename TYPE> inline
139 void assign_type(TYPE* d, const TYPE* s, size_t n) {
140 if (!traits<TYPE>::has_trivial_assign) {
141 while (n--) {
142 *d++ = *s++;
143 }
144 } else {
145 memcpy(d,s,n*sizeof(TYPE));
146 }
147 }
148
149 template<typename TYPE> inline
150 void splat_type(TYPE* where, const TYPE* what, size_t n) {
151 if (!traits<TYPE>::has_trivial_copy) {
152 while (n--) {
153 new(where) TYPE(*what);
154 where++;
155 }
156 } else {
157 while (n--) {
158 *where++ = *what;
159 }
160 }
161 }
162
163 template<typename TYPE> inline
164 void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
165 if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
166 d += n;
167 s += n;
168 while (n--) {
169 --d, --s;
170 if (!traits<TYPE>::has_trivial_copy) {
171 new(d) TYPE(*s);
172 } else {
173 *d = *s;
174 }
175 if (!traits<TYPE>::has_trivial_dtor) {
176 s->~TYPE();
177 }
178 }
179 } else {
180 memmove(d,s,n*sizeof(TYPE));
181 }
182 }
183
184 template<typename TYPE> inline
185 void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
186 if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
187 while (n--) {
188 if (!traits<TYPE>::has_trivial_copy) {
189 new(d) TYPE(*s);
190 } else {
191 *d = *s;
192 }
193 if (!traits<TYPE>::has_trivial_dtor) {
194 s->~TYPE();
195 }
196 d++, s++;
197 }
198 } else {
199 memmove(d,s,n*sizeof(TYPE));
200 }
201 }
202 // ---------------------------------------------------------------------------
203
204 /*
205 * a key/value pair
206 */
207
208 template <typename KEY, typename VALUE>
209 struct key_value_pair_t {
210 KEY key;
211 VALUE value;
212 key_value_pair_t() { }
213 key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
214 key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { }
215 key_value_pair_t(const KEY& k) : key(k) { }
216 inline bool operator < (const key_value_pair_t& o) const {
217 return strictly_order_type(key, o.key);
218 }
219 };
220
221 template<>
222 template <typename K, typename V>
223 struct trait_trivial_ctor< key_value_pair_t<K, V> >
224 { enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
225 template<>
226 template <typename K, typename V>
227 struct trait_trivial_dtor< key_value_pair_t<K, V> >
228 { enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
229 template<>
230 template <typename K, typename V>
231 struct trait_trivial_copy< key_value_pair_t<K, V> >
232 { enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
233 template<>
234 template <typename K, typename V>
235 struct trait_trivial_assign< key_value_pair_t<K, V> >
236 { enum { value = aggregate_traits<K,V>::has_trivial_assign};};
237
238 // ---------------------------------------------------------------------------
239
240 }; // namespace android
241
242 // ---------------------------------------------------------------------------
243
244 #endif // ANDROID_TYPE_HELPERS_H
+0
-352
libpixelflinger/tinyutils/Vector.h less more
0 /*
1 * vector.h
2 * Android
3 *
4 * Copyright 2005 The Android Open Source Project
5 *
6 */
7
8 #ifndef ANDROID_VECTOR_H
9 #define ANDROID_VECTOR_H
10
11 #include <new>
12 #include <stdint.h>
13 #include <sys/types.h>
14
15 #include <cutils/log.h>
16
17 #include "tinyutils/VectorImpl.h"
18 #include "tinyutils/TypeHelpers.h"
19
20 // ---------------------------------------------------------------------------
21
22 namespace android {
23
24 /*!
25 * The main templated vector class ensuring type safety
26 * while making use of VectorImpl.
27 * This is the class users want to use.
28 */
29
30 template <class TYPE>
31 class Vector : private VectorImpl
32 {
33 public:
34 typedef TYPE value_type;
35
36 /*!
37 * Constructors and destructors
38 */
39
40 Vector();
41 Vector(const Vector<TYPE>& rhs);
42 virtual ~Vector();
43
44 /*! copy operator */
45 const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const;
46 Vector<TYPE>& operator = (const Vector<TYPE>& rhs);
47
48 /*
49 * empty the vector
50 */
51
52 inline void clear() { VectorImpl::clear(); }
53
54 /*!
55 * vector stats
56 */
57
58 //! returns number of items in the vector
59 inline size_t size() const { return VectorImpl::size(); }
60 //! returns wether or not the vector is empty
61 inline bool isEmpty() const { return VectorImpl::isEmpty(); }
62 //! returns how many items can be stored without reallocating the backing store
63 inline size_t capacity() const { return VectorImpl::capacity(); }
64 //! setst the capacity. capacity can never be reduced less than size()
65 inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
66
67 /*!
68 * C-style array access
69 */
70
71 //! read-only C-style access
72 inline const TYPE* array() const;
73 //! read-write C-style access
74 TYPE* editArray();
75
76 /*!
77 * accessors
78 */
79
80 //! read-only access to an item at a given index
81 inline const TYPE& operator [] (size_t index) const;
82 //! alternate name for operator []
83 inline const TYPE& itemAt(size_t index) const;
84 //! stack-usage of the vector. returns the top of the stack (last element)
85 const TYPE& top() const;
86 //! same as operator [], but allows to access the vector backward (from the end) with a negative index
87 const TYPE& mirrorItemAt(ssize_t index) const;
88
89 /*!
90 * modifing the array
91 */
92
93 //! copy-on write support, grants write access to an item
94 TYPE& editItemAt(size_t index);
95 //! grants right acces to the top of the stack (last element)
96 TYPE& editTop();
97
98 /*!
99 * append/insert another vector
100 */
101
102 //! insert another vector at a given index
103 ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index);
104
105 //! append another vector at the end of this one
106 ssize_t appendVector(const Vector<TYPE>& vector);
107
108
109 /*!
110 * add/insert/replace items
111 */
112
113 //! insert one or several items initialized with their default constructor
114 inline ssize_t insertAt(size_t index, size_t numItems = 1);
115 //! insert on onr several items initialized from a prototype item
116 ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
117 //! pop the top of the stack (removes the last element). No-op if the stack's empty
118 inline void pop();
119 //! pushes an item initialized with its default constructor
120 inline void push();
121 //! pushes an item on the top of the stack
122 void push(const TYPE& item);
123 //! same as push() but returns the index the item was added at (or an error)
124 inline ssize_t add();
125 //! same as push() but returns the index the item was added at (or an error)
126 ssize_t add(const TYPE& item);
127 //! replace an item with a new one initialized with its default constructor
128 inline ssize_t replaceAt(size_t index);
129 //! replace an item with a new one
130 ssize_t replaceAt(const TYPE& item, size_t index);
131
132 /*!
133 * remove items
134 */
135
136 //! remove several items
137 inline ssize_t removeItemsAt(size_t index, size_t count = 1);
138 //! remove one item
139 inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
140
141 /*!
142 * sort (stable) the array
143 */
144
145 typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
146 typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
147
148 inline status_t sort(compar_t cmp);
149 inline status_t sort(compar_r_t cmp, void* state);
150
151 protected:
152 virtual void do_construct(void* storage, size_t num) const;
153 virtual void do_destroy(void* storage, size_t num) const;
154 virtual void do_copy(void* dest, const void* from, size_t num) const;
155 virtual void do_splat(void* dest, const void* item, size_t num) const;
156 virtual void do_move_forward(void* dest, const void* from, size_t num) const;
157 virtual void do_move_backward(void* dest, const void* from, size_t num) const;
158 };
159
160
161 // ---------------------------------------------------------------------------
162 // No user serviceable parts from here...
163 // ---------------------------------------------------------------------------
164
165 template<class TYPE> inline
166 Vector<TYPE>::Vector()
167 : VectorImpl(sizeof(TYPE),
168 ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
169 |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
170 |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
171 |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
172 )
173 {
174 }
175
176 template<class TYPE> inline
177 Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
178 : VectorImpl(rhs) {
179 }
180
181 template<class TYPE> inline
182 Vector<TYPE>::~Vector() {
183 finish_vector();
184 }
185
186 template<class TYPE> inline
187 Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
188 VectorImpl::operator = (rhs);
189 return *this;
190 }
191
192 template<class TYPE> inline
193 const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
194 VectorImpl::operator = (rhs);
195 return *this;
196 }
197
198 template<class TYPE> inline
199 const TYPE* Vector<TYPE>::array() const {
200 return static_cast<const TYPE *>(arrayImpl());
201 }
202
203 template<class TYPE> inline
204 TYPE* Vector<TYPE>::editArray() {
205 return static_cast<TYPE *>(editArrayImpl());
206 }
207
208
209 template<class TYPE> inline
210 const TYPE& Vector<TYPE>::operator[](size_t index) const {
211 LOG_FATAL_IF( index>=size(),
212 "itemAt: index %d is past size %d", (int)index, (int)size() );
213 return *(array() + index);
214 }
215
216 template<class TYPE> inline
217 const TYPE& Vector<TYPE>::itemAt(size_t index) const {
218 return operator[](index);
219 }
220
221 template<class TYPE> inline
222 const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const {
223 LOG_FATAL_IF( (index>0 ? index : -index)>=size(),
224 "mirrorItemAt: index %d is past size %d",
225 (int)index, (int)size() );
226 return *(array() + ((index<0) ? (size()-index) : index));
227 }
228
229 template<class TYPE> inline
230 const TYPE& Vector<TYPE>::top() const {
231 return *(array() + size() - 1);
232 }
233
234 template<class TYPE> inline
235 TYPE& Vector<TYPE>::editItemAt(size_t index) {
236 return *( static_cast<TYPE *>(editItemLocation(index)) );
237 }
238
239 template<class TYPE> inline
240 TYPE& Vector<TYPE>::editTop() {
241 return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
242 }
243
244 template<class TYPE> inline
245 ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
246 return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
247 }
248
249 template<class TYPE> inline
250 ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
251 return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
252 }
253
254 template<class TYPE> inline
255 ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
256 return VectorImpl::insertAt(&item, index, numItems);
257 }
258
259 template<class TYPE> inline
260 void Vector<TYPE>::push(const TYPE& item) {
261 return VectorImpl::push(&item);
262 }
263
264 template<class TYPE> inline
265 ssize_t Vector<TYPE>::add(const TYPE& item) {
266 return VectorImpl::add(&item);
267 }
268
269 template<class TYPE> inline
270 ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
271 return VectorImpl::replaceAt(&item, index);
272 }
273
274 template<class TYPE> inline
275 ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
276 return VectorImpl::insertAt(index, numItems);
277 }
278
279 template<class TYPE> inline
280 void Vector<TYPE>::pop() {
281 VectorImpl::pop();
282 }
283
284 template<class TYPE> inline
285 void Vector<TYPE>::push() {
286 VectorImpl::push();
287 }
288
289 template<class TYPE> inline
290 ssize_t Vector<TYPE>::add() {
291 return VectorImpl::add();
292 }
293
294 template<class TYPE> inline
295 ssize_t Vector<TYPE>::replaceAt(size_t index) {
296 return VectorImpl::replaceAt(index);
297 }
298
299 template<class TYPE> inline
300 ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
301 return VectorImpl::removeItemsAt(index, count);
302 }
303
304 template<class TYPE> inline
305 status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
306 return VectorImpl::sort((VectorImpl::compar_t)cmp);
307 }
308
309 template<class TYPE> inline
310 status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
311 return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
312 }
313
314 // ---------------------------------------------------------------------------
315
316 template<class TYPE>
317 void Vector<TYPE>::do_construct(void* storage, size_t num) const {
318 construct_type( reinterpret_cast<TYPE*>(storage), num );
319 }
320
321 template<class TYPE>
322 void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
323 destroy_type( reinterpret_cast<TYPE*>(storage), num );
324 }
325
326 template<class TYPE>
327 void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
328 copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
329 }
330
331 template<class TYPE>
332 void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
333 splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
334 }
335
336 template<class TYPE>
337 void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
338 move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
339 }
340
341 template<class TYPE>
342 void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
343 move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
344 }
345
346 }; // namespace android
347
348
349 // ---------------------------------------------------------------------------
350
351 #endif // ANDROID_VECTOR_H
+0
-552
libpixelflinger/tinyutils/VectorImpl.cpp less more
0 /*
1 * vector_impl.cpp
2 * Android
3 *
4 * Copyright 2005 The Android Open Source Project
5 *
6 */
7
8 #define LOG_TAG "Vector"
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <errno.h>
14
15 #include <cutils/log.h>
16
17 #include "tinyutils/SharedBuffer.h"
18 #include "tinyutils/VectorImpl.h"
19
20 /*****************************************************************************/
21
22
23 namespace android {
24
25 enum {
26 NO_ERROR = 0, // No errors.
27 NO_MEMORY = -ENOMEM,
28 BAD_VALUE = -EINVAL,
29 BAD_INDEX = -EOVERFLOW,
30 NAME_NOT_FOUND = -ENOENT,
31 };
32
33 // ----------------------------------------------------------------------------
34
35 const size_t kMinVectorCapacity = 4;
36
37 static inline size_t max(size_t a, size_t b) {
38 return a>b ? a : b;
39 }
40
41 // ----------------------------------------------------------------------------
42
43 VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
44 : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
45 {
46 }
47
48 VectorImpl::VectorImpl(const VectorImpl& rhs)
49 : mStorage(rhs.mStorage), mCount(rhs.mCount),
50 mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
51 {
52 if (mStorage) {
53 SharedBuffer::sharedBuffer(mStorage)->acquire();
54 }
55 }
56
57 VectorImpl::~VectorImpl()
58 {
59 LOG_ASSERT(!mCount,
60 "[%p] "
61 "subclasses of VectorImpl must call finish_vector()"
62 " in their destructor. Leaking %d bytes.",
63 this, (int)(mCount*mItemSize));
64 // We can't call _do_destroy() here because the vtable is already gone.
65 }
66
67 VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
68 {
69 LOG_ASSERT(mItemSize == rhs.mItemSize,
70 "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
71 if (this != &rhs) {
72 release_storage();
73 if (rhs.mCount) {
74 mStorage = rhs.mStorage;
75 mCount = rhs.mCount;
76 SharedBuffer::sharedBuffer(mStorage)->acquire();
77 } else {
78 mStorage = 0;
79 mCount = 0;
80 }
81 }
82 return *this;
83 }
84
85 void* VectorImpl::editArrayImpl()
86 {
87 if (mStorage) {
88 SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
89 if (sb == 0) {
90 sb = SharedBuffer::alloc(capacity() * mItemSize);
91 if (sb) {
92 _do_copy(sb->data(), mStorage, mCount);
93 release_storage();
94 mStorage = sb->data();
95 }
96 }
97 }
98 return mStorage;
99 }
100
101 size_t VectorImpl::capacity() const
102 {
103 if (mStorage) {
104 return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
105 }
106 return 0;
107 }
108
109 ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
110 {
111 if (index > size())
112 return BAD_INDEX;
113 void* where = _grow(index, vector.size());
114 if (where) {
115 _do_copy(where, vector.arrayImpl(), vector.size());
116 }
117 return where ? index : (ssize_t)NO_MEMORY;
118 }
119
120 ssize_t VectorImpl::appendVector(const VectorImpl& vector)
121 {
122 return insertVectorAt(vector, size());
123 }
124
125 ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
126 {
127 return insertAt(0, index, numItems);
128 }
129
130 ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
131 {
132 if (index > size())
133 return BAD_INDEX;
134 void* where = _grow(index, numItems);
135 if (where) {
136 if (item) {
137 _do_splat(where, item, numItems);
138 } else {
139 _do_construct(where, numItems);
140 }
141 }
142 return where ? index : (ssize_t)NO_MEMORY;
143 }
144
145 void VectorImpl::pop()
146 {
147 if (size())
148 removeItemsAt(size()-1, 1);
149 }
150
151 void VectorImpl::push()
152 {
153 push(0);
154 }
155
156 void VectorImpl::push(const void* item)
157 {
158 insertAt(item, size());
159 }
160
161 ssize_t VectorImpl::add()
162 {
163 return add(0);
164 }
165
166 ssize_t VectorImpl::add(const void* item)
167 {
168 return insertAt(item, size());
169 }
170
171 ssize_t VectorImpl::replaceAt(size_t index)
172 {
173 return replaceAt(0, index);
174 }
175
176 ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
177 {
178 LOG_ASSERT(index<size(),
179 "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
180
181 void* item = editItemLocation(index);
182 if (item == 0)
183 return NO_MEMORY;
184 _do_destroy(item, 1);
185 if (prototype == 0) {
186 _do_construct(item, 1);
187 } else {
188 _do_copy(item, prototype, 1);
189 }
190 return ssize_t(index);
191 }
192
193 ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
194 {
195 LOG_ASSERT((index+count)<=size(),
196 "[%p] remove: index=%d, count=%d, size=%d",
197 this, (int)index, (int)count, (int)size());
198
199 if ((index+count) > size())
200 return BAD_VALUE;
201 _shrink(index, count);
202 return index;
203 }
204
205 void VectorImpl::finish_vector()
206 {
207 release_storage();
208 mStorage = 0;
209 mCount = 0;
210 }
211
212 void VectorImpl::clear()
213 {
214 _shrink(0, mCount);
215 }
216
217 void* VectorImpl::editItemLocation(size_t index)
218 {
219 LOG_ASSERT(index<capacity(),
220 "[%p] itemLocation: index=%d, capacity=%d, count=%d",
221 this, (int)index, (int)capacity(), (int)mCount);
222
223 void* buffer = editArrayImpl();
224 if (buffer)
225 return reinterpret_cast<char*>(buffer) + index*mItemSize;
226 return 0;
227 }
228
229 const void* VectorImpl::itemLocation(size_t index) const
230 {
231 LOG_ASSERT(index<capacity(),
232 "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
233 this, (int)index, (int)capacity(), (int)mCount);
234
235 const void* buffer = arrayImpl();
236 if (buffer)
237 return reinterpret_cast<const char*>(buffer) + index*mItemSize;
238 return 0;
239 }
240
241 ssize_t VectorImpl::setCapacity(size_t new_capacity)
242 {
243 size_t current_capacity = capacity();
244 ssize_t amount = new_capacity - size();
245 if (amount <= 0) {
246 // we can't reduce the capacity
247 return current_capacity;
248 }
249 SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
250 if (sb) {
251 void* array = sb->data();
252 _do_copy(array, mStorage, size());
253 release_storage();
254 mStorage = const_cast<void*>(array);
255 } else {
256 return NO_MEMORY;
257 }
258 return new_capacity;
259 }
260
261 void VectorImpl::release_storage()
262 {
263 if (mStorage) {
264 const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
265 if (sb->release(SharedBuffer::eKeepStorage) == 1) {
266 _do_destroy(mStorage, mCount);
267 SharedBuffer::dealloc(sb);
268 }
269 }
270 }
271
272 void* VectorImpl::_grow(size_t where, size_t amount)
273 {
274 // LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
275 // this, (int)where, (int)amount, (int)mCount, (int)capacity());
276
277 if (where > mCount)
278 where = mCount;
279
280 const size_t new_size = mCount + amount;
281 if (capacity() < new_size) {
282 const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
283 // LOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
284 if ((mStorage) &&
285 (mCount==where) &&
286 (mFlags & HAS_TRIVIAL_COPY) &&
287 (mFlags & HAS_TRIVIAL_DTOR))
288 {
289 const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
290 SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
291 mStorage = sb->data();
292 } else {
293 SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
294 if (sb) {
295 void* array = sb->data();
296 if (where>0) {
297 _do_copy(array, mStorage, where);
298 }
299 if (mCount>where) {
300 const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
301 void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
302 _do_copy(dest, from, mCount-where);
303 }
304 release_storage();
305 mStorage = const_cast<void*>(array);
306 }
307 }
308 } else {
309 ssize_t s = mCount-where;
310 if (s>0) {
311 void* array = editArrayImpl();
312 void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
313 const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
314 _do_move_forward(to, from, s);
315 }
316 }
317 mCount += amount;
318 void* free_space = const_cast<void*>(itemLocation(where));
319 return free_space;
320 }
321
322 void VectorImpl::_shrink(size_t where, size_t amount)
323 {
324 if (!mStorage)
325 return;
326
327 // LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
328 // this, (int)where, (int)amount, (int)mCount, (int)capacity());
329
330 if (where >= mCount)
331 where = mCount - amount;
332
333 const size_t new_size = mCount - amount;
334 if (new_size*3 < capacity()) {
335 const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
336 // LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
337 if ((where == mCount-amount) &&
338 (mFlags & HAS_TRIVIAL_COPY) &&
339 (mFlags & HAS_TRIVIAL_DTOR))
340 {
341 const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
342 SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
343 mStorage = sb->data();
344 } else {
345 SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
346 if (sb) {
347 void* array = sb->data();
348 if (where>0) {
349 _do_copy(array, mStorage, where);
350 }
351 if (mCount > where+amount) {
352 const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
353 void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
354 _do_copy(dest, from, mCount-(where+amount));
355 }
356 release_storage();
357 mStorage = const_cast<void*>(array);
358 }
359 }
360 } else {
361 void* array = editArrayImpl();
362 void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
363 _do_destroy(to, amount);
364 ssize_t s = mCount-(where+amount);
365 if (s>0) {
366 const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
367 _do_move_backward(to, from, s);
368 }
369 }
370
371 // adjust the number of items...
372 mCount -= amount;
373 }
374
375 size_t VectorImpl::itemSize() const {
376 return mItemSize;
377 }
378
379 void VectorImpl::_do_construct(void* storage, size_t num) const
380 {
381 if (!(mFlags & HAS_TRIVIAL_CTOR)) {
382 do_construct(storage, num);
383 }
384 }
385
386 void VectorImpl::_do_destroy(void* storage, size_t num) const
387 {
388 if (!(mFlags & HAS_TRIVIAL_DTOR)) {
389 do_destroy(storage, num);
390 }
391 }
392
393 void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
394 {
395 if (!(mFlags & HAS_TRIVIAL_COPY)) {
396 do_copy(dest, from, num);
397 } else {
398 memcpy(dest, from, num*itemSize());
399 }
400 }
401
402 void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
403 do_splat(dest, item, num);
404 }
405
406 void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
407 do_move_forward(dest, from, num);
408 }
409
410 void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
411 do_move_backward(dest, from, num);
412 }
413
414 void VectorImpl::reservedVectorImpl1() { }
415 void VectorImpl::reservedVectorImpl2() { }
416 void VectorImpl::reservedVectorImpl3() { }
417 void VectorImpl::reservedVectorImpl4() { }
418 void VectorImpl::reservedVectorImpl5() { }
419 void VectorImpl::reservedVectorImpl6() { }
420 void VectorImpl::reservedVectorImpl7() { }
421 void VectorImpl::reservedVectorImpl8() { }
422
423 /*****************************************************************************/
424
425 SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
426 : VectorImpl(itemSize, flags)
427 {
428 }
429
430 SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
431 : VectorImpl(rhs)
432 {
433 }
434
435 SortedVectorImpl::~SortedVectorImpl()
436 {
437 }
438
439 SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
440 {
441 return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
442 }
443
444 ssize_t SortedVectorImpl::indexOf(const void* item) const
445 {
446 return _indexOrderOf(item);
447 }
448
449 size_t SortedVectorImpl::orderOf(const void* item) const
450 {
451 size_t o;
452 _indexOrderOf(item, &o);
453 return o;
454 }
455
456 ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
457 {
458 // binary search
459 ssize_t err = NAME_NOT_FOUND;
460 ssize_t l = 0;
461 ssize_t h = size()-1;
462 ssize_t mid;
463 const void* a = arrayImpl();
464 const size_t s = itemSize();
465 while (l <= h) {
466 mid = l + (h - l)/2;
467 const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
468 const int c = do_compare(curr, item);
469 if (c == 0) {
470 err = l = mid;
471 break;
472 } else if (c < 0) {
473 l = mid + 1;
474 } else {
475 h = mid - 1;
476 }
477 }
478 if (order) *order = l;
479 return err;
480 }
481
482 ssize_t SortedVectorImpl::add(const void* item)
483 {
484 size_t order;
485 ssize_t index = _indexOrderOf(item, &order);
486 if (index < 0) {
487 index = VectorImpl::insertAt(item, order, 1);
488 } else {
489 index = VectorImpl::replaceAt(item, index);
490 }
491 return index;
492 }
493
494 ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
495 {
496 // naive merge...
497 if (!vector.isEmpty()) {
498 const void* buffer = vector.arrayImpl();
499 const size_t is = itemSize();
500 size_t s = vector.size();
501 for (size_t i=0 ; i<s ; i++) {
502 ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
503 if (err<0) {
504 return err;
505 }
506 }
507 }
508 return NO_ERROR;
509 }
510
511 ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
512 {
513 // we've merging a sorted vector... nice!
514 ssize_t err = NO_ERROR;
515 if (!vector.isEmpty()) {
516 // first take care of the case where the vectors are sorted together
517 if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
518 err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
519 } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
520 err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
521 } else {
522 // this could be made a little better
523 err = merge(static_cast<const VectorImpl&>(vector));
524 }
525 }
526 return err;
527 }
528
529 ssize_t SortedVectorImpl::remove(const void* item)
530 {
531 ssize_t i = indexOf(item);
532 if (i>=0) {
533 VectorImpl::removeItemsAt(i, 1);
534 }
535 return i;
536 }
537
538 void SortedVectorImpl::reservedSortedVectorImpl1() { };
539 void SortedVectorImpl::reservedSortedVectorImpl2() { };
540 void SortedVectorImpl::reservedSortedVectorImpl3() { };
541 void SortedVectorImpl::reservedSortedVectorImpl4() { };
542 void SortedVectorImpl::reservedSortedVectorImpl5() { };
543 void SortedVectorImpl::reservedSortedVectorImpl6() { };
544 void SortedVectorImpl::reservedSortedVectorImpl7() { };
545 void SortedVectorImpl::reservedSortedVectorImpl8() { };
546
547
548 /*****************************************************************************/
549
550 }; // namespace android
551
+0
-185
libpixelflinger/tinyutils/VectorImpl.h less more
0 /*
1 * vector_impl.h
2 * Android
3 *
4 * Copyright 2005 The Android Open Source Project
5 *
6 */
7
8 #ifndef ANDROID_VECTOR_IMPL_H
9 #define ANDROID_VECTOR_IMPL_H
10
11 #include <assert.h>
12 #include <stdint.h>
13 #include <sys/types.h>
14
15 // ---------------------------------------------------------------------------
16 // No user serviceable parts in here...
17 // ---------------------------------------------------------------------------
18
19 namespace android {
20
21 /*!
22 * Implementation of the guts of the vector<> class
23 * this ensures backward binary compatibility and
24 * reduces code size.
25 * For performance reasons, we expose mStorage and mCount
26 * so these fields are set in stone.
27 *
28 */
29
30 class VectorImpl
31 {
32 public:
33 enum { // flags passed to the ctor
34 HAS_TRIVIAL_CTOR = 0x00000001,
35 HAS_TRIVIAL_DTOR = 0x00000002,
36 HAS_TRIVIAL_COPY = 0x00000004,
37 HAS_TRIVIAL_ASSIGN = 0x00000008
38 };
39
40 VectorImpl(size_t itemSize, uint32_t flags);
41 VectorImpl(const VectorImpl& rhs);
42 virtual ~VectorImpl();
43
44 /*! must be called from subclasses destructor */
45 void finish_vector();
46
47 VectorImpl& operator = (const VectorImpl& rhs);
48
49 /*! C-style array access */
50 inline const void* arrayImpl() const { return mStorage; }
51 void* editArrayImpl();
52
53 /*! vector stats */
54 inline size_t size() const { return mCount; }
55 inline bool isEmpty() const { return mCount == 0; }
56 size_t capacity() const;
57 ssize_t setCapacity(size_t size);
58
59 /*! append/insert another vector */
60 ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
61 ssize_t appendVector(const VectorImpl& vector);
62
63 /*! add/insert/replace items */
64 ssize_t insertAt(size_t where, size_t numItems = 1);
65 ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
66 void pop();
67 void push();
68 void push(const void* item);
69 ssize_t add();
70 ssize_t add(const void* item);
71 ssize_t replaceAt(size_t index);
72 ssize_t replaceAt(const void* item, size_t index);
73
74 /*! remove items */
75 ssize_t removeItemsAt(size_t index, size_t count = 1);
76 void clear();
77
78 const void* itemLocation(size_t index) const;
79 void* editItemLocation(size_t index);
80
81 protected:
82 size_t itemSize() const;
83 void release_storage();
84
85 virtual void do_construct(void* storage, size_t num) const = 0;
86 virtual void do_destroy(void* storage, size_t num) const = 0;
87 virtual void do_copy(void* dest, const void* from, size_t num) const = 0;
88 virtual void do_splat(void* dest, const void* item, size_t num) const = 0;
89 virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0;
90 virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0;
91
92 // take care of FBC...
93 virtual void reservedVectorImpl1();
94 virtual void reservedVectorImpl2();
95 virtual void reservedVectorImpl3();
96 virtual void reservedVectorImpl4();
97 virtual void reservedVectorImpl5();
98 virtual void reservedVectorImpl6();
99 virtual void reservedVectorImpl7();
100 virtual void reservedVectorImpl8();
101
102 private:
103 void* _grow(size_t where, size_t amount);
104 void _shrink(size_t where, size_t amount);
105
106 inline void _do_construct(void* storage, size_t num) const;
107 inline void _do_destroy(void* storage, size_t num) const;
108 inline void _do_copy(void* dest, const void* from, size_t num) const;
109 inline void _do_splat(void* dest, const void* item, size_t num) const;
110 inline void _do_move_forward(void* dest, const void* from, size_t num) const;
111 inline void _do_move_backward(void* dest, const void* from, size_t num) const;
112
113 // These 2 fields are exposed in the inlines below,
114 // so they're set in stone.
115 void * mStorage; // base address of the vector
116 size_t mCount; // number of items
117
118 const uint32_t mFlags;
119 const size_t mItemSize;
120 };
121
122
123
124 class SortedVectorImpl : public VectorImpl
125 {
126 public:
127 SortedVectorImpl(size_t itemSize, uint32_t flags);
128 SortedVectorImpl(const VectorImpl& rhs);
129 virtual ~SortedVectorImpl();
130
131 SortedVectorImpl& operator = (const SortedVectorImpl& rhs);
132
133 //! finds the index of an item
134 ssize_t indexOf(const void* item) const;
135
136 //! finds where this item should be inserted
137 size_t orderOf(const void* item) const;
138
139 //! add an item in the right place (or replaces it if there is one)
140 ssize_t add(const void* item);
141
142 //! merges a vector into this one
143 ssize_t merge(const VectorImpl& vector);
144 ssize_t merge(const SortedVectorImpl& vector);
145
146 //! removes an item
147 ssize_t remove(const void* item);
148
149 protected:
150 virtual int do_compare(const void* lhs, const void* rhs) const = 0;
151
152 // take care of FBC...
153 virtual void reservedSortedVectorImpl1();
154 virtual void reservedSortedVectorImpl2();
155 virtual void reservedSortedVectorImpl3();
156 virtual void reservedSortedVectorImpl4();
157 virtual void reservedSortedVectorImpl5();
158 virtual void reservedSortedVectorImpl6();
159 virtual void reservedSortedVectorImpl7();
160 virtual void reservedSortedVectorImpl8();
161
162 private:
163 ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
164
165 // these are made private, because they can't be used on a SortedVector
166 // (they don't have an implementation either)
167 ssize_t add();
168 void pop();
169 void push();
170 void push(const void* item);
171 ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
172 ssize_t appendVector(const VectorImpl& vector);
173 ssize_t insertAt(size_t where, size_t numItems = 1);
174 ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
175 ssize_t replaceAt(size_t index);
176 ssize_t replaceAt(const void* item, size_t index);
177 };
178
179 }; // namespace android
180
181
182 // ---------------------------------------------------------------------------
183
184 #endif // ANDROID_VECTOR_IMPL_H
+0
-170
libpixelflinger/tinyutils/smartpointer.h less more
0 /*
1 * smartpointer.h
2 * Android
3 *
4 * Copyright 2005 The Android Open Source Project
5 *
6 */
7
8 #ifndef ANDROID_SMART_POINTER_H
9 #define ANDROID_SMART_POINTER_H
10
11 #include <stdint.h>
12 #include <sys/types.h>
13 #include <stdlib.h>
14
15 // ---------------------------------------------------------------------------
16 namespace android {
17
18 // ---------------------------------------------------------------------------
19
20 #define COMPARE(_op_) \
21 inline bool operator _op_ (const sp<T>& o) const { \
22 return m_ptr _op_ o.m_ptr; \
23 } \
24 inline bool operator _op_ (const T* o) const { \
25 return m_ptr _op_ o; \
26 } \
27 template<typename U> \
28 inline bool operator _op_ (const sp<U>& o) const { \
29 return m_ptr _op_ o.m_ptr; \
30 } \
31 template<typename U> \
32 inline bool operator _op_ (const U* o) const { \
33 return m_ptr _op_ o; \
34 }
35
36 // ---------------------------------------------------------------------------
37
38 template <typename T>
39 class sp
40 {
41 public:
42 inline sp() : m_ptr(0) { }
43
44 sp(T* other);
45 sp(const sp<T>& other);
46 template<typename U> sp(U* other);
47 template<typename U> sp(const sp<U>& other);
48
49 ~sp();
50
51 // Assignment
52
53 sp& operator = (T* other);
54 sp& operator = (const sp<T>& other);
55
56 template<typename U> sp& operator = (const sp<U>& other);
57 template<typename U> sp& operator = (U* other);
58
59 // Reset
60 void clear();
61
62 // Accessors
63
64 inline T& operator* () const { return *m_ptr; }
65 inline T* operator-> () const { return m_ptr; }
66 inline T* get() const { return m_ptr; }
67
68 // Operators
69
70 COMPARE(==)
71 COMPARE(!=)
72 COMPARE(>)
73 COMPARE(<)
74 COMPARE(<=)
75 COMPARE(>=)
76
77 private:
78 template<typename Y> friend class sp;
79
80 T* m_ptr;
81 };
82
83 // ---------------------------------------------------------------------------
84 // No user serviceable parts below here.
85
86 template<typename T>
87 sp<T>::sp(T* other)
88 : m_ptr(other)
89 {
90 if (other) other->incStrong(this);
91 }
92
93 template<typename T>
94 sp<T>::sp(const sp<T>& other)
95 : m_ptr(other.m_ptr)
96 {
97 if (m_ptr) m_ptr->incStrong(this);
98 }
99
100 template<typename T> template<typename U>
101 sp<T>::sp(U* other) : m_ptr(other)
102 {
103 if (other) other->incStrong(this);
104 }
105
106 template<typename T> template<typename U>
107 sp<T>::sp(const sp<U>& other)
108 : m_ptr(other.m_ptr)
109 {
110 if (m_ptr) m_ptr->incStrong(this);
111 }
112
113 template<typename T>
114 sp<T>::~sp()
115 {
116 if (m_ptr) m_ptr->decStrong(this);
117 }
118
119 template<typename T>
120 sp<T>& sp<T>::operator = (const sp<T>& other) {
121 if (other.m_ptr) other.m_ptr->incStrong(this);
122 if (m_ptr) m_ptr->decStrong(this);
123 m_ptr = other.m_ptr;
124 return *this;
125 }
126
127 template<typename T>
128 sp<T>& sp<T>::operator = (T* other)
129 {
130 if (other) other->incStrong(this);
131 if (m_ptr) m_ptr->decStrong(this);
132 m_ptr = other;
133 return *this;
134 }
135
136 template<typename T> template<typename U>
137 sp<T>& sp<T>::operator = (const sp<U>& other)
138 {
139 if (other.m_ptr) other.m_ptr->incStrong(this);
140 if (m_ptr) m_ptr->decStrong(this);
141 m_ptr = other.m_ptr;
142 return *this;
143 }
144
145 template<typename T> template<typename U>
146 sp<T>& sp<T>::operator = (U* other)
147 {
148 if (other) other->incStrong(this);
149 if (m_ptr) m_ptr->decStrong(this);
150 m_ptr = other;
151 return *this;
152 }
153
154 template<typename T>
155 void sp<T>::clear()
156 {
157 if (m_ptr) {
158 m_ptr->decStrong(this);
159 m_ptr = 0;
160 }
161 }
162
163 // ---------------------------------------------------------------------------
164
165 }; // namespace android
166
167 // ---------------------------------------------------------------------------
168
169 #endif // ANDROID_SMART_POINTER_H
+0
-1173
libpixelflinger/trap.cpp less more
0 /* libs/pixelflinger/trap.cpp
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20
21 #include "trap.h"
22 #include "picker.h"
23
24 #include <cutils/log.h>
25 #include <cutils/memory.h>
26
27 namespace android {
28
29 // ----------------------------------------------------------------------------
30
31 // enable to see triangles edges
32 #define DEBUG_TRANGLES 0
33
34 // ----------------------------------------------------------------------------
35
36 static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r);
37 static void pointx(void *con, const GGLcoord* c, GGLcoord r);
38 static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r);
39 static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r);
40
41 static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
42 static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
43 static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
44
45 static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
46 static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
47
48 static void trianglex_validate(void*,
49 const GGLcoord*, const GGLcoord*, const GGLcoord*);
50 static void trianglex_small(void*,
51 const GGLcoord*, const GGLcoord*, const GGLcoord*);
52 static void trianglex_big(void*,
53 const GGLcoord*, const GGLcoord*, const GGLcoord*);
54 static void aa_trianglex(void*,
55 const GGLcoord*, const GGLcoord*, const GGLcoord*);
56 static void trianglex_debug(void* con,
57 const GGLcoord*, const GGLcoord*, const GGLcoord*);
58
59 static void aapolyx(void* con,
60 const GGLcoord* pts, int count);
61
62 static inline int min(int a, int b) CONST;
63 static inline int max(int a, int b) CONST;
64 static inline int min(int a, int b, int c) CONST;
65 static inline int max(int a, int b, int c) CONST;
66
67 // ----------------------------------------------------------------------------
68 #if 0
69 #pragma mark -
70 #pragma mark Tools
71 #endif
72
73 inline int min(int a, int b) {
74 return a<b ? a : b;
75 }
76 inline int max(int a, int b) {
77 return a<b ? b : a;
78 }
79 inline int min(int a, int b, int c) {
80 return min(a,min(b,c));
81 }
82 inline int max(int a, int b, int c) {
83 return max(a,max(b,c));
84 }
85
86 template <typename T>
87 static inline void swap(T& a, T& b) {
88 T t(a);
89 a = b;
90 b = t;
91 }
92
93 static void
94 triangle_dump_points( const GGLcoord* v0,
95 const GGLcoord* v1,
96 const GGLcoord* v2 )
97 {
98 float tri = 1.0f / TRI_ONE;
99 LOGD( " P0=(%.3f, %.3f) [%08x, %08x]\n"
100 " P1=(%.3f, %.3f) [%08x, %08x]\n"
101 " P2=(%.3f, %.3f) [%08x, %08x]\n",
102 v0[0]*tri, v0[1]*tri, v0[0], v0[1],
103 v1[0]*tri, v1[1]*tri, v1[0], v1[1],
104 v2[0]*tri, v2[1]*tri, v2[0], v2[1] );
105 }
106
107 // ----------------------------------------------------------------------------
108 #if 0
109 #pragma mark -
110 #pragma mark Misc
111 #endif
112
113 void ggl_init_trap(context_t* c)
114 {
115 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE);
116 }
117
118 void ggl_state_changed(context_t* c, int flags)
119 {
120 if (ggl_likely(!c->dirty)) {
121 c->procs.pointx = pointx_validate;
122 c->procs.linex = linex_validate;
123 c->procs.recti = recti_validate;
124 c->procs.trianglex = trianglex_validate;
125 }
126 c->dirty |= uint32_t(flags);
127 }
128
129 // ----------------------------------------------------------------------------
130 #if 0
131 #pragma mark -
132 #pragma mark Point
133 #endif
134
135 void pointx_validate(void *con, const GGLcoord* v, GGLcoord rad)
136 {
137 GGL_CONTEXT(c, con);
138 ggl_pick(c);
139 if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
140 if (c->state.enables & GGL_ENABLE_POINT_AA_NICE) {
141 c->procs.pointx = aa_nice_pointx;
142 } else {
143 c->procs.pointx = aa_pointx;
144 }
145 } else {
146 c->procs.pointx = pointx;
147 }
148 c->procs.pointx(con, v, rad);
149 }
150
151 void pointx(void *con, const GGLcoord* v, GGLcoord rad)
152 {
153 GGL_CONTEXT(c, con);
154 GGLcoord halfSize = TRI_ROUND(rad) >> 1;
155 if (halfSize == 0)
156 halfSize = TRI_HALF;
157 GGLcoord xc = v[0];
158 GGLcoord yc = v[1];
159 if (halfSize & TRI_HALF) { // size odd
160 xc = TRI_FLOOR(xc) + TRI_HALF;
161 yc = TRI_FLOOR(yc) + TRI_HALF;
162 } else { // size even
163 xc = TRI_ROUND(xc);
164 yc = TRI_ROUND(yc);
165 }
166 GGLint l = (xc - halfSize) >> TRI_FRACTION_BITS;
167 GGLint t = (yc - halfSize) >> TRI_FRACTION_BITS;
168 GGLint r = (xc + halfSize) >> TRI_FRACTION_BITS;
169 GGLint b = (yc + halfSize) >> TRI_FRACTION_BITS;
170 recti(c, l, t, r, b);
171 }
172
173 // This way of computing the coverage factor, is more accurate and gives
174 // better results for small circles, but it is also a lot slower.
175 // Here we use super-sampling.
176 static int32_t coverageNice(GGLcoord x, GGLcoord y,
177 GGLcoord rmin, GGLcoord rmax, GGLcoord rr)
178 {
179 const GGLcoord d2 = x*x + y*y;
180 if (d2 >= rmax) return 0;
181 if (d2 < rmin) return 0x7FFF;
182
183 const int kSamples = 4;
184 const int kInc = 4; // 1/4 = 0.25
185 const int kCoverageUnit = 1; // 1/(4^2) = 0.0625
186 const GGLcoord kCoordOffset = -6; // -0.375
187
188 int hits = 0;
189 int x_sample = x + kCoordOffset;
190 for (int i=0 ; i<kSamples ; i++, x_sample += kInc) {
191 const int xval = rr - (x_sample * x_sample);
192 int y_sample = y + kCoordOffset;
193 for (int j=0 ; j<kSamples ; j++, y_sample += kInc) {
194 if (xval - (y_sample * y_sample) > 0)
195 hits += kCoverageUnit;
196 }
197 }
198 return min(0x7FFF, hits << (15 - kSamples));
199 }
200
201
202 void aa_nice_pointx(void *con, const GGLcoord* v, GGLcoord size)
203 {
204 GGL_CONTEXT(c, con);
205
206 GGLcoord rad = ((size + 1)>>1);
207 GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
208 GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
209 GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
210 GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
211 GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
212 GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
213
214 // scissor...
215 if (l < GGLint(c->state.scissor.left)) {
216 xstart += TRI_FROM_INT(c->state.scissor.left-l);
217 l = GGLint(c->state.scissor.left);
218 }
219 if (t < GGLint(c->state.scissor.top)) {
220 ystart += TRI_FROM_INT(c->state.scissor.top-t);
221 t = GGLint(c->state.scissor.top);
222 }
223 if (r > GGLint(c->state.scissor.right)) {
224 r = GGLint(c->state.scissor.right);
225 }
226 if (b > GGLint(c->state.scissor.bottom)) {
227 b = GGLint(c->state.scissor.bottom);
228 }
229
230 int xc = r - l;
231 int yc = b - t;
232 if (xc>0 && yc>0) {
233 int16_t* covPtr = c->state.buffers.coverage;
234 const int32_t sqr2Over2 = 0xC; // rounded up
235 GGLcoord rr = rad*rad;
236 GGLcoord rmin = (rad - sqr2Over2)*(rad - sqr2Over2);
237 GGLcoord rmax = (rad + sqr2Over2)*(rad + sqr2Over2);
238 GGLcoord y = ystart;
239 c->iterators.xl = l;
240 c->iterators.xr = r;
241 c->init_y(c, t);
242 do {
243 // compute coverage factors for each pixel
244 GGLcoord x = xstart;
245 for (int i=l ; i<r ; i++) {
246 covPtr[i] = coverageNice(x, y, rmin, rmax, rr);
247 x += TRI_ONE;
248 }
249 y += TRI_ONE;
250 c->scanline(c);
251 c->step_y(c);
252 } while (--yc);
253 }
254 }
255
256 // This is a cheap way of computing the coverage factor for a circle.
257 // We just lerp between the circles of radii r-sqrt(2)/2 and r+sqrt(2)/2
258 static inline int32_t coverageFast(GGLcoord x, GGLcoord y,
259 GGLcoord rmin, GGLcoord rmax, GGLcoord scale)
260 {
261 const GGLcoord d2 = x*x + y*y;
262 if (d2 >= rmax) return 0;
263 if (d2 < rmin) return 0x7FFF;
264 return 0x7FFF - (d2-rmin)*scale;
265 }
266
267 void aa_pointx(void *con, const GGLcoord* v, GGLcoord size)
268 {
269 GGL_CONTEXT(c, con);
270
271 GGLcoord rad = ((size + 1)>>1);
272 GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
273 GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
274 GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
275 GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
276 GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
277 GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
278
279 // scissor...
280 if (l < GGLint(c->state.scissor.left)) {
281 xstart += TRI_FROM_INT(c->state.scissor.left-l);
282 l = GGLint(c->state.scissor.left);
283 }
284 if (t < GGLint(c->state.scissor.top)) {
285 ystart += TRI_FROM_INT(c->state.scissor.top-t);
286 t = GGLint(c->state.scissor.top);
287 }
288 if (r > GGLint(c->state.scissor.right)) {
289 r = GGLint(c->state.scissor.right);
290 }
291 if (b > GGLint(c->state.scissor.bottom)) {
292 b = GGLint(c->state.scissor.bottom);
293 }
294
295 int xc = r - l;
296 int yc = b - t;
297 if (xc>0 && yc>0) {
298 int16_t* covPtr = c->state.buffers.coverage;
299 rad <<= 4;
300 const int32_t sqr2Over2 = 0xB5; // fixed-point 24.8
301 GGLcoord rmin = rad - sqr2Over2;
302 GGLcoord rmax = rad + sqr2Over2;
303 GGLcoord scale;
304 rmin *= rmin;
305 rmax *= rmax;
306 scale = 0x800000 / (rmax - rmin);
307 rmin >>= 8;
308 rmax >>= 8;
309
310 GGLcoord y = ystart;
311 c->iterators.xl = l;
312 c->iterators.xr = r;
313 c->init_y(c, t);
314
315 do {
316 // compute coverage factors for each pixel
317 GGLcoord x = xstart;
318 for (int i=l ; i<r ; i++) {
319 covPtr[i] = coverageFast(x, y, rmin, rmax, scale);
320 x += TRI_ONE;
321 }
322 y += TRI_ONE;
323 c->scanline(c);
324 c->step_y(c);
325 } while (--yc);
326 }
327 }
328
329 // ----------------------------------------------------------------------------
330 #if 0
331 #pragma mark -
332 #pragma mark Line
333 #endif
334
335 void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w)
336 {
337 GGL_CONTEXT(c, con);
338 ggl_pick(c);
339 if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
340 c->procs.linex = aa_linex;
341 } else {
342 c->procs.linex = linex;
343 }
344 c->procs.linex(con, v0, v1, w);
345 }
346
347 static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
348 {
349 GGL_CONTEXT(c, con);
350 GGLcoord v[4][2];
351 v[0][0] = v0[0]; v[0][1] = v0[1];
352 v[1][0] = v1[0]; v[1][1] = v1[1];
353 v0 = v[0];
354 v1 = v[1];
355 const GGLcoord dx = abs(v0[0] - v1[0]);
356 const GGLcoord dy = abs(v0[1] - v1[1]);
357 GGLcoord nx, ny;
358 nx = ny = 0;
359
360 GGLcoord halfWidth = TRI_ROUND(width) >> 1;
361 if (halfWidth == 0)
362 halfWidth = TRI_HALF;
363
364 ((dx > dy) ? ny : nx) = halfWidth;
365 v[2][0] = v1[0]; v[2][1] = v1[1];
366 v[3][0] = v0[0]; v[3][1] = v0[1];
367 v[0][0] += nx; v[0][1] += ny;
368 v[1][0] += nx; v[1][1] += ny;
369 v[2][0] -= nx; v[2][1] -= ny;
370 v[3][0] -= nx; v[3][1] -= ny;
371 trianglex_big(con, v[0], v[1], v[2]);
372 trianglex_big(con, v[0], v[2], v[3]);
373 }
374
375 static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
376 {
377 GGL_CONTEXT(c, con);
378 GGLcoord v[4][2];
379 v[0][0] = v0[0]; v[0][1] = v0[1];
380 v[1][0] = v1[0]; v[1][1] = v1[1];
381 v0 = v[0];
382 v1 = v[1];
383
384 const GGLcoord dx = v0[0] - v1[0];
385 const GGLcoord dy = v0[1] - v1[1];
386 GGLcoord nx = -dy;
387 GGLcoord ny = dx;
388
389 // generally, this will be well below 1.0
390 const GGLfixed norm = gglMulx(width, gglSqrtRecipx(nx*nx+ny*ny), 4);
391 nx = gglMulx(nx, norm, 21);
392 ny = gglMulx(ny, norm, 21);
393
394 v[2][0] = v1[0]; v[2][1] = v1[1];
395 v[3][0] = v0[0]; v[3][1] = v0[1];
396 v[0][0] += nx; v[0][1] += ny;
397 v[1][0] += nx; v[1][1] += ny;
398 v[2][0] -= nx; v[2][1] -= ny;
399 v[3][0] -= nx; v[3][1] -= ny;
400 aapolyx(con, v[0], 4);
401 }
402
403
404 // ----------------------------------------------------------------------------
405 #if 0
406 #pragma mark -
407 #pragma mark Rect
408 #endif
409
410 void recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b)
411 {
412 GGL_CONTEXT(c, con);
413 ggl_pick(c);
414 c->procs.recti = recti;
415 c->procs.recti(con, l, t, r, b);
416 }
417
418 void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b)
419 {
420 GGL_CONTEXT(c, con);
421
422 // scissor...
423 if (l < GGLint(c->state.scissor.left))
424 l = GGLint(c->state.scissor.left);
425 if (t < GGLint(c->state.scissor.top))
426 t = GGLint(c->state.scissor.top);
427 if (r > GGLint(c->state.scissor.right))
428 r = GGLint(c->state.scissor.right);
429 if (b > GGLint(c->state.scissor.bottom))
430 b = GGLint(c->state.scissor.bottom);
431
432 int xc = r - l;
433 int yc = b - t;
434 if (xc>0 && yc>0) {
435 c->iterators.xl = l;
436 c->iterators.xr = r;
437 c->init_y(c, t);
438 c->rect(c, yc);
439 }
440 }
441
442 // ----------------------------------------------------------------------------
443 #if 0
444 #pragma mark -
445 #pragma mark Triangle / Debugging
446 #endif
447
448 static void scanline_set(context_t* c)
449 {
450 int32_t x = c->iterators.xl;
451 size_t ct = c->iterators.xr - x;
452 int32_t y = c->iterators.y;
453 surface_t* cb = &(c->state.buffers.color);
454 const GGLFormat* fp = &(c->formats[cb->format]);
455 uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
456 (x + (cb->stride * y)) * fp->size;
457 const size_t size = ct * fp->size;
458 memset(dst, 0xFF, size);
459 }
460
461 static void trianglex_debug(void* con,
462 const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
463 {
464 GGL_CONTEXT(c, con);
465 if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
466 aa_trianglex(con,v0,v1,v2);
467 } else {
468 trianglex_big(con,v0,v1,v2);
469 }
470 void (*save_scanline)(context_t*) = c->scanline;
471 c->scanline = scanline_set;
472 linex(con, v0, v1, TRI_ONE);
473 linex(con, v1, v2, TRI_ONE);
474 linex(con, v2, v0, TRI_ONE);
475 c->scanline = save_scanline;
476 }
477
478 static void trianglex_xor(void* con,
479 const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
480 {
481 trianglex_big(con,v0,v1,v2);
482 trianglex_small(con,v0,v1,v2);
483 }
484
485 // ----------------------------------------------------------------------------
486 #if 0
487 #pragma mark -
488 #pragma mark Triangle
489 #endif
490
491 void trianglex_validate(void *con,
492 const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
493 {
494 GGL_CONTEXT(c, con);
495 ggl_pick(c);
496 if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
497 c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex;
498 } else {
499 c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big;
500 }
501 c->procs.trianglex(con, v0, v1, v2);
502 }
503
504 // ----------------------------------------------------------------------------
505
506 void trianglex_small(void* con,
507 const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
508 {
509 GGL_CONTEXT(c, con);
510
511 // vertices are in 28.4 fixed point, which allows
512 // us to use 32 bits multiplies below.
513 int32_t x0 = v0[0];
514 int32_t y0 = v0[1];
515 int32_t x1 = v1[0];
516 int32_t y1 = v1[1];
517 int32_t x2 = v2[0];
518 int32_t y2 = v2[1];
519
520 int32_t dx01 = x0 - x1;
521 int32_t dy20 = y2 - y0;
522 int32_t dy01 = y0 - y1;
523 int32_t dx20 = x2 - x0;
524
525 // The code below works only with CCW triangles
526 // so if we get a CW triangle, we need to swap two of its vertices
527 if (dx01*dy20 < dy01*dx20) {
528 swap(x0, x1);
529 swap(y0, y1);
530 dx01 = x0 - x1;
531 dy01 = y0 - y1;
532 dx20 = x2 - x0;
533 dy20 = y2 - y0;
534 }
535 int32_t dx12 = x1 - x2;
536 int32_t dy12 = y1 - y2;
537
538 // bounding box & scissor
539 const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS;
540 const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS;
541 const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS;
542 const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS;
543 const int32_t minx = max(bminx, c->state.scissor.left);
544 const int32_t miny = max(bminy, c->state.scissor.top);
545 const int32_t maxx = min(bmaxx, c->state.scissor.right);
546 const int32_t maxy = min(bmaxy, c->state.scissor.bottom);
547 if ((minx >= maxx) || (miny >= maxy))
548 return; // too small or clipped out...
549
550 // step equations to the bounding box and snap to pixel center
551 const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF;
552 const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF;
553 int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my);
554 int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my);
555 int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my);
556
557 // right-exclusive fill rule, to avoid rare cases
558 // of over drawing
559 if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++;
560 if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++;
561 if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++;
562
563 c->init_y(c, miny);
564 for (int32_t y = miny; y < maxy; y++) {
565 register int32_t ex0 = ey0;
566 register int32_t ex1 = ey1;
567 register int32_t ex2 = ey2;
568 register int32_t xl, xr;
569 for (xl=minx ; xl<maxx ; xl++) {
570 if (ex0>0 && ex1>0 && ex2>0)
571 break; // all strictly positive
572 ex0 -= dy01 << TRI_FRACTION_BITS;
573 ex1 -= dy12 << TRI_FRACTION_BITS;
574 ex2 -= dy20 << TRI_FRACTION_BITS;
575 }
576 xr = xl;
577 for ( ; xr<maxx ; xr++) {
578 if (!(ex0>0 && ex1>0 && ex2>0))
579 break; // not all strictly positive
580 ex0 -= dy01 << TRI_FRACTION_BITS;
581 ex1 -= dy12 << TRI_FRACTION_BITS;
582 ex2 -= dy20 << TRI_FRACTION_BITS;
583 }
584
585 if (xl < xr) {
586 c->iterators.xl = xl;
587 c->iterators.xr = xr;
588 c->scanline(c);
589 }
590 c->step_y(c);
591
592 ey0 += dx01 << TRI_FRACTION_BITS;
593 ey1 += dx12 << TRI_FRACTION_BITS;
594 ey2 += dx20 << TRI_FRACTION_BITS;
595 }
596 }
597
598 // ----------------------------------------------------------------------------
599 #if 0
600 #pragma mark -
601 #endif
602
603 // the following routine fills a triangle via edge stepping, which
604 // unfortunately requires divisions in the setup phase to get right,
605 // it should probably only be used for relatively large trianges
606
607
608 // x = y*DX/DY (ou DX and DY are constants, DY > 0, et y >= 0)
609 //
610 // for an equation of the type:
611 // x' = y*K/2^p (with K and p constants "carefully chosen")
612 //
613 // We can now do a DDA without precision loss. We define 'e' by:
614 // x' - x = y*(DX/DY - K/2^p) = y*e
615 //
616 // If we choose K = round(DX*2^p/DY) then,
617 // abs(e) <= 1/2^(p+1) by construction
618 //
619 // therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1)
620 //
621 // which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including
622 // at the last line. In fact, it's even a strict inequality except in one
623 // extrem case (DY == DMAX et e = +/- 1/2)
624 //
625 // Applying that to our coordinates, we need 2^p >= 4096*16 = 65536
626 // so p = 16 is enough, we're so lucky!
627
628 const int TRI_ITERATORS_BITS = 16;
629
630 struct Edge
631 {
632 int32_t x; // edge position in 16.16 coordinates
633 int32_t x_incr; // on each step, increment x by that amount
634 int32_t y_top; // starting scanline, 16.4 format
635 int32_t y_bot;
636 };
637
638 static void
639 edge_dump( Edge* edge )
640 {
641 LOGI( " top=%d (%.3f) bot=%d (%.3f) x=%d (%.3f) ix=%d (%.3f)",
642 edge->y_top, edge->y_top/float(TRI_ONE),
643 edge->y_bot, edge->y_bot/float(TRI_ONE),
644 edge->x, edge->x/float(FIXED_ONE),
645 edge->x_incr, edge->x_incr/float(FIXED_ONE) );
646 }
647
648 static void
649 triangle_dump_edges( Edge* edges,
650 int count )
651 {
652 LOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" );
653 for ( ; count > 0; count--, edges++ )
654 edge_dump( edges );
655 }
656
657 // the following function sets up an edge, it assumes
658 // that ymin and ymax are in already in the 'reduced'
659 // format
660 static __attribute__((noinline))
661 void edge_setup(
662 Edge* edges,
663 int* pcount,
664 const GGLcoord* p1,
665 const GGLcoord* p2,
666 int32_t ymin,
667 int32_t ymax )
668 {
669 const GGLfixed* top = p1;
670 const GGLfixed* bot = p2;
671 Edge* edge = edges + *pcount;
672
673 if (top[1] > bot[1]) {
674 swap(top, bot);
675 }
676
677 int y1 = top[1] | 1;
678 int y2 = bot[1] | 1;
679 int dy = y2 - y1;
680
681 if ( dy == 0 || y1 > ymax || y2 < ymin )
682 return;
683
684 if ( y1 > ymin )
685 ymin = TRI_SNAP_NEXT_HALF(y1);
686
687 if ( y2 < ymax )
688 ymax = TRI_SNAP_PREV_HALF(y2);
689
690 if ( ymin > ymax ) // when the edge doesn't cross any scanline
691 return;
692
693 const int x1 = top[0];
694 const int dx = bot[0] - x1;
695 const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS;
696
697 // setup edge fields
698 // We add 0.5 to edge->x here because it simplifies the rounding
699 // in triangle_sweep_edges() -- this doesn't change the ordering of 'x'
700 edge->x = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1));
701 edge->x_incr = 0;
702 edge->y_top = ymin;
703 edge->y_bot = ymax;
704
705 if (ggl_likely(ymin <= ymax && dx)) {
706 edge->x_incr = gglDivQ16(dx, dy);
707 }
708 if (ggl_likely(y1 < ymin)) {
709 int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS;
710 edge->x += xadjust;
711 }
712
713 ++*pcount;
714 }
715
716
717 static void
718 triangle_sweep_edges( Edge* left,
719 Edge* right,
720 int ytop,
721 int ybot,
722 context_t* c )
723 {
724 int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1;
725 if (count<=0) return;
726
727 // sort the edges horizontally
728 if ((left->x > right->x) ||
729 ((left->x == right->x) && (left->x_incr > right->x_incr))) {
730 swap(left, right);
731 }
732
733 int left_x = left->x;
734 int right_x = right->x;
735 const int left_xi = left->x_incr;
736 const int right_xi = right->x_incr;
737 left->x += left_xi * count;
738 right->x += right_xi * count;
739
740 const int xmin = c->state.scissor.left;
741 const int xmax = c->state.scissor.right;
742 do {
743 // horizontal scissoring
744 const int32_t xl = max(left_x >> TRI_ITERATORS_BITS, xmin);
745 const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax);
746 left_x += left_xi;
747 right_x += right_xi;
748 // invoke the scanline rasterizer
749 if (ggl_likely(xl < xr)) {
750 c->iterators.xl = xl;
751 c->iterators.xr = xr;
752 c->scanline(c);
753 }
754 c->step_y(c);
755 } while (--count);
756 }
757
758
759 void trianglex_big(void* con,
760 const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
761 {
762 GGL_CONTEXT(c, con);
763
764 Edge edges[3];
765 int num_edges = 0;
766 int32_t ymin = TRI_FROM_INT(c->state.scissor.top) + TRI_HALF;
767 int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF;
768
769 edge_setup( edges, &num_edges, v0, v1, ymin, ymax );
770 edge_setup( edges, &num_edges, v0, v2, ymin, ymax );
771 edge_setup( edges, &num_edges, v1, v2, ymin, ymax );
772
773 if (ggl_unlikely(num_edges<2)) // for really tiny triangles that don't
774 return; // cross any scanline centers
775
776 Edge* left = &edges[0];
777 Edge* right = &edges[1];
778 Edge* other = &edges[2];
779 int32_t y_top = min(left->y_top, right->y_top);
780 int32_t y_bot = max(left->y_bot, right->y_bot);
781
782 if (ggl_likely(num_edges==3)) {
783 y_top = min(y_top, edges[2].y_top);
784 y_bot = max(y_bot, edges[2].y_bot);
785 if (edges[0].y_top > y_top) {
786 other = &edges[0];
787 left = &edges[2];
788 } else if (edges[1].y_top > y_top) {
789 other = &edges[1];
790 right = &edges[2];
791 }
792 }
793
794 c->init_y(c, y_top >> TRI_FRACTION_BITS);
795
796 int32_t y_mid = min(left->y_bot, right->y_bot);
797 triangle_sweep_edges( left, right, y_top, y_mid, c );
798
799 // second scanline sweep loop, if necessary
800 y_mid += TRI_ONE;
801 if (y_mid <= y_bot) {
802 ((left->y_bot == y_bot) ? right : left) = other;
803 if (other->y_top < y_mid) {
804 other->x += other->x_incr;
805 }
806 triangle_sweep_edges( left, right, y_mid, y_bot, c );
807 }
808 }
809
810 void aa_trianglex(void* con,
811 const GGLcoord* a, const GGLcoord* b, const GGLcoord* c)
812 {
813 GGLcoord pts[6] = { a[0], a[1], b[0], b[1], c[0], c[1] };
814 aapolyx(con, pts, 3);
815 }
816
817 // ----------------------------------------------------------------------------
818 #if 0
819 #pragma mark -
820 #endif
821
822 struct AAEdge
823 {
824 GGLfixed x; // edge position in 12.16 coordinates
825 GGLfixed x_incr; // on each y step, increment x by that amount
826 GGLfixed y_incr; // on each x step, increment y by that amount
827 int16_t y_top; // starting scanline, 12.4 format
828 int16_t y_bot; // starting scanline, 12.4 format
829 void dump();
830 };
831
832 void AAEdge::dump()
833 {
834 float tri = 1.0f / TRI_ONE;
835 float iter = 1.0f / (1<<TRI_ITERATORS_BITS);
836 float fix = 1.0f / FIXED_ONE;
837 LOGD( "x=%08x (%.3f), "
838 "x_incr=%08x (%.3f), y_incr=%08x (%.3f), "
839 "y_top=%08x (%.3f), y_bot=%08x (%.3f) ",
840 x, x*fix,
841 x_incr, x_incr*iter,
842 y_incr, y_incr*iter,
843 y_top, y_top*tri,
844 y_bot, y_bot*tri );
845 }
846
847 // the following function sets up an edge, it assumes
848 // that ymin and ymax are in already in the 'reduced'
849 // format
850 static __attribute__((noinline))
851 void aa_edge_setup(
852 AAEdge* edges,
853 int* pcount,
854 const GGLcoord* p1,
855 const GGLcoord* p2,
856 int32_t ymin,
857 int32_t ymax )
858 {
859 const GGLfixed* top = p1;
860 const GGLfixed* bot = p2;
861 AAEdge* edge = edges + *pcount;
862
863 if (top[1] > bot[1])
864 swap(top, bot);
865
866 int y1 = top[1];
867 int y2 = bot[1];
868 int dy = y2 - y1;
869
870 if (dy==0 || y1>ymax || y2<ymin)
871 return;
872
873 if (y1 > ymin)
874 ymin = y1;
875
876 if (y2 < ymax)
877 ymax = y2;
878
879 const int x1 = top[0];
880 const int dx = bot[0] - x1;
881 const int shift = FIXED_BITS - TRI_FRACTION_BITS;
882
883 // setup edge fields
884 edge->x = x1 << shift;
885 edge->x_incr = 0;
886 edge->y_top = ymin;
887 edge->y_bot = ymax;
888 edge->y_incr = 0x7FFFFFFF;
889
890 if (ggl_likely(ymin <= ymax && dx)) {
891 edge->x_incr = gglDivQ16(dx, dy);
892 if (dx != 0) {
893 edge->y_incr = abs(gglDivQ16(dy, dx));
894 }
895 }
896 if (ggl_likely(y1 < ymin)) {
897 int32_t xadjust = (edge->x_incr * (ymin-y1))
898 >> (TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS);
899 edge->x += xadjust;
900 }
901
902 ++*pcount;
903 }
904
905
906 typedef int (*compar_t)(const void*, const void*);
907 static int compare_edges(const AAEdge *e0, const AAEdge *e1) {
908 if (e0->y_top > e1->y_top) return 1;
909 if (e0->y_top < e1->y_top) return -1;
910 if (e0->x > e1->x) return 1;
911 if (e0->x < e1->x) return -1;
912 if (e0->x_incr > e1->x_incr) return 1;
913 if (e0->x_incr < e1->x_incr) return -1;
914 return 0; // same edges, should never happen
915 }
916
917 static inline
918 void SET_COVERAGE(int16_t*& p, int32_t value, ssize_t n)
919 {
920 android_memset16((uint16_t*)p, value, n*2);
921 p += n;
922 }
923
924 static inline
925 void ADD_COVERAGE(int16_t*& p, int32_t value)
926 {
927 value = *p + value;
928 if (value >= 0x8000)
929 value = 0x7FFF;
930 *p++ = value;
931 }
932
933 static inline
934 void SUB_COVERAGE(int16_t*& p, int32_t value)
935 {
936 value = *p - value;
937 value &= ~(value>>31);
938 *p++ = value;
939 }
940
941 void aapolyx(void* con,
942 const GGLcoord* pts, int count)
943 {
944 /*
945 * NOTE: This routine assumes that the polygon has been clipped to the
946 * viewport already, that is, no vertex lies outside of the framebuffer.
947 * If this happens, the code below won't corrupt memory but the
948 * coverage values may not be correct.
949 */
950
951 GGL_CONTEXT(c, con);
952
953 // we do only quads for now (it's used for thick lines)
954 if ((count>4) || (count<2)) return;
955
956 // take scissor into account
957 const int xmin = c->state.scissor.left;
958 const int xmax = c->state.scissor.right;
959 if (xmin >= xmax) return;
960
961 // generate edges from the vertices
962 int32_t ymin = TRI_FROM_INT(c->state.scissor.top);
963 int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom);
964 if (ymin >= ymax) return;
965
966 AAEdge edges[4];
967 int num_edges = 0;
968 GGLcoord const * p = pts;
969 for (int i=0 ; i<count-1 ; i++, p+=2) {
970 aa_edge_setup(edges, &num_edges, p, p+2, ymin, ymax);
971 }
972 aa_edge_setup(edges, &num_edges, p, pts, ymin, ymax );
973 if (ggl_unlikely(num_edges<2))
974 return;
975
976 // sort the edge list top to bottom, left to right.
977 qsort(edges, num_edges, sizeof(AAEdge), (compar_t)compare_edges);
978
979 int16_t* const covPtr = c->state.buffers.coverage;
980 memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
981
982 // now, sweep all edges in order
983 // start with the 2 first edges. We know that they share their top
984 // vertex, by construction.
985 int i = 2;
986 AAEdge* left = &edges[0];
987 AAEdge* right = &edges[1];
988 int32_t yt = left->y_top;
989 GGLfixed l = left->x;
990 GGLfixed r = right->x;
991 int retire = 0;
992 int16_t* coverage;
993
994 // at this point we can initialize the rasterizer
995 c->init_y(c, yt>>TRI_FRACTION_BITS);
996 c->iterators.xl = xmax;
997 c->iterators.xr = xmin;
998
999 do {
1000 int32_t y = min(min(left->y_bot, right->y_bot), TRI_FLOOR(yt + TRI_ONE));
1001 const int32_t shift = TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS;
1002 const int cf_shift = (1 + TRI_FRACTION_BITS*2 + TRI_ITERATORS_BITS - 15);
1003
1004 // compute xmin and xmax for the left edge
1005 GGLfixed l_min = gglMulAddx(left->x_incr, y - left->y_top, left->x, shift);
1006 GGLfixed l_max = l;
1007 l = l_min;
1008 if (l_min > l_max)
1009 swap(l_min, l_max);
1010
1011 // compute xmin and xmax for the right edge
1012 GGLfixed r_min = gglMulAddx(right->x_incr, y - right->y_top, right->x, shift);
1013 GGLfixed r_max = r;
1014 r = r_min;
1015 if (r_min > r_max)
1016 swap(r_min, r_max);
1017
1018 // make sure we're not touching coverage values outside of the
1019 // framebuffer
1020 l_min &= ~(l_min>>31);
1021 r_min &= ~(r_min>>31);
1022 l_max &= ~(l_max>>31);
1023 r_max &= ~(r_max>>31);
1024 if (gglFixedToIntFloor(l_min) >= xmax) l_min = gglIntToFixed(xmax)-1;
1025 if (gglFixedToIntFloor(r_min) >= xmax) r_min = gglIntToFixed(xmax)-1;
1026 if (gglFixedToIntCeil(l_max) >= xmax) l_max = gglIntToFixed(xmax)-1;
1027 if (gglFixedToIntCeil(r_max) >= xmax) r_max = gglIntToFixed(xmax)-1;
1028
1029 // compute the integer versions of the above
1030 const GGLfixed l_min_i = gglFloorx(l_min);
1031 const GGLfixed l_max_i = gglCeilx (l_max);
1032 const GGLfixed r_min_i = gglFloorx(r_min);
1033 const GGLfixed r_max_i = gglCeilx (r_max);
1034
1035 // clip horizontally using the scissor
1036 const int xml = max(xmin, gglFixedToIntFloor(l_min_i));
1037 const int xmr = min(xmax, gglFixedToIntFloor(r_max_i));
1038
1039 // if we just stepped to a new scanline, render the previous one.
1040 // and clear the coverage buffer
1041 if (retire) {
1042 if (c->iterators.xl < c->iterators.xr)
1043 c->scanline(c);
1044 c->step_y(c);
1045 memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
1046 c->iterators.xl = xml;
1047 c->iterators.xr = xmr;
1048 } else {
1049 // update the horizontal range of this scanline
1050 c->iterators.xl = min(c->iterators.xl, xml);
1051 c->iterators.xr = max(c->iterators.xr, xmr);
1052 }
1053
1054 coverage = covPtr + gglFixedToIntFloor(l_min_i);
1055 if (l_min_i == gglFloorx(l_max)) {
1056
1057 /*
1058 * fully traverse this pixel vertically
1059 * l_max
1060 * +-----/--+ yt
1061 * | / |
1062 * | / |
1063 * | / |
1064 * +-/------+ y
1065 * l_min (l_min_i + TRI_ONE)
1066 */
1067
1068 GGLfixed dx = l_max - l_min;
1069 int32_t dy = y - yt;
1070 int cf = gglMulx((dx >> 1) + (l_min_i + FIXED_ONE - l_max), dy,
1071 FIXED_BITS + TRI_FRACTION_BITS - 15);
1072 ADD_COVERAGE(coverage, cf);
1073 // all pixels on the right have cf = 1.0
1074 } else {
1075 /*
1076 * spans several pixels in one scanline
1077 * l_max
1078 * +--------+--/-----+ yt
1079 * | |/ |
1080 * | /| |
1081 * | / | |
1082 * +---/----+--------+ y
1083 * l_min (l_min_i + TRI_ONE)
1084 */
1085
1086 // handle the first pixel separately...
1087 const int32_t y_incr = left->y_incr;
1088 int32_t dx = TRI_FROM_FIXED(l_min_i - l_min) + TRI_ONE;
1089 int32_t cf = (dx * dx * y_incr) >> cf_shift;
1090 ADD_COVERAGE(coverage, cf);
1091
1092 // following pixels get covered by y_incr, but we need
1093 // to fix-up the cf to account for previous partial pixel
1094 dx = TRI_FROM_FIXED(l_min - l_min_i);
1095 cf -= (dx * dx * y_incr) >> cf_shift;
1096 for (int x = l_min_i+FIXED_ONE ; x < l_max_i-FIXED_ONE ; x += FIXED_ONE) {
1097 cf += y_incr >> (TRI_ITERATORS_BITS-15);
1098 ADD_COVERAGE(coverage, cf);
1099 }
1100
1101 // and the last pixel
1102 dx = TRI_FROM_FIXED(l_max - l_max_i) - TRI_ONE;
1103 cf += (dx * dx * y_incr) >> cf_shift;
1104 ADD_COVERAGE(coverage, cf);
1105 }
1106
1107 // now, fill up all fully covered pixels
1108 coverage = covPtr + gglFixedToIntFloor(l_max_i);
1109 int cf = ((y - yt) << (15 - TRI_FRACTION_BITS));
1110 if (ggl_likely(cf >= 0x8000)) {
1111 SET_COVERAGE(coverage, 0x7FFF, ((r_max - l_max_i)>>FIXED_BITS)+1);
1112 } else {
1113 for (int x=l_max_i ; x<r_max ; x+=FIXED_ONE) {
1114 ADD_COVERAGE(coverage, cf);
1115 }
1116 }
1117
1118 // subtract the coverage of the right edge
1119 coverage = covPtr + gglFixedToIntFloor(r_min_i);
1120 if (r_min_i == gglFloorx(r_max)) {
1121 GGLfixed dx = r_max - r_min;
1122 int32_t dy = y - yt;
1123 int cf = gglMulx((dx >> 1) + (r_min_i + FIXED_ONE - r_max), dy,
1124 FIXED_BITS + TRI_FRACTION_BITS - 15);
1125 SUB_COVERAGE(coverage, cf);
1126 // all pixels on the right have cf = 1.0
1127 } else {
1128 // handle the first pixel separately...
1129 const int32_t y_incr = right->y_incr;
1130 int32_t dx = TRI_FROM_FIXED(r_min_i - r_min) + TRI_ONE;
1131 int32_t cf = (dx * dx * y_incr) >> cf_shift;
1132 SUB_COVERAGE(coverage, cf);
1133
1134 // following pixels get covered by y_incr, but we need
1135 // to fix-up the cf to account for previous partial pixel
1136 dx = TRI_FROM_FIXED(r_min - r_min_i);
1137 cf -= (dx * dx * y_incr) >> cf_shift;
1138 for (int x = r_min_i+FIXED_ONE ; x < r_max_i-FIXED_ONE ; x += FIXED_ONE) {
1139 cf += y_incr >> (TRI_ITERATORS_BITS-15);
1140 SUB_COVERAGE(coverage, cf);
1141 }
1142
1143 // and the last pixel
1144 dx = TRI_FROM_FIXED(r_max - r_max_i) - TRI_ONE;
1145 cf += (dx * dx * y_incr) >> cf_shift;
1146 SUB_COVERAGE(coverage, cf);
1147 }
1148
1149 // did we reach the end of an edge? if so, get a new one.
1150 if (y == left->y_bot || y == right->y_bot) {
1151 // bail out if we're done
1152 if (i>=num_edges)
1153 break;
1154 if (y == left->y_bot)
1155 left = &edges[i++];
1156 if (y == right->y_bot)
1157 right = &edges[i++];
1158 }
1159
1160 // next scanline
1161 yt = y;
1162
1163 // did we just finish a scanline?
1164 retire = (y << (32-TRI_FRACTION_BITS)) == 0;
1165 } while (true);
1166
1167 // render the last scanline
1168 if (c->iterators.xl < c->iterators.xr)
1169 c->scanline(c);
1170 }
1171
1172 }; // namespace android
+0
-31
libpixelflinger/trap.h less more
0 /* libs/pixelflinger/trap.h
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17
18 #ifndef ANDROID_TRAP_H
19 #define ANDROID_TRAP_H
20
21 #include <private/pixelflinger/ggl_context.h>
22
23 namespace android {
24
25 void ggl_init_trap(context_t* c);
26 void ggl_state_changed(context_t* c, int flags);
27
28 }; // namespace android
29
30 #endif
+0
-48
libzipfile/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1
2 # build host static library
3 include $(CLEAR_VARS)
4
5 LOCAL_SRC_FILES:= \
6 centraldir.c \
7 zipfile.c
8
9 LOCAL_STATIC_LIBRARIES := \
10 libunz
11
12 LOCAL_MODULE:= libzipfile
13
14 LOCAL_C_INCLUDES += external/zlib
15
16 include $(BUILD_HOST_STATIC_LIBRARY)
17
18 # build device static library
19 include $(CLEAR_VARS)
20
21 LOCAL_SRC_FILES:= \
22 centraldir.c \
23 zipfile.c
24
25 LOCAL_STATIC_LIBRARIES := \
26 libunz
27
28 LOCAL_MODULE:= libzipfile
29
30 LOCAL_C_INCLUDES += external/zlib
31
32 include $(BUILD_STATIC_LIBRARY)
33
34
35 # build test_zipfile
36 include $(CLEAR_VARS)
37
38 LOCAL_SRC_FILES:= \
39 test_zipfile.c
40
41 LOCAL_STATIC_LIBRARIES := libzipfile libunz
42
43 LOCAL_MODULE := test_zipfile
44
45 LOCAL_C_INCLUDES += external/zlib
46
47 include $(BUILD_HOST_EXECUTABLE)
+0
-0
libzipfile/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
libzipfile/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-256
libzipfile/centraldir.c less more
0 #include "private.h"
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 enum {
6 // finding the directory
7 CD_SIGNATURE = 0x06054b50,
8 EOCD_LEN = 22, // EndOfCentralDir len, excl. comment
9 MAX_COMMENT_LEN = 65535,
10 MAX_EOCD_SEARCH = MAX_COMMENT_LEN + EOCD_LEN,
11
12 // central directory entries
13 ENTRY_SIGNATURE = 0x02014b50,
14 ENTRY_LEN = 46, // CentralDirEnt len, excl. var fields
15
16 // local file header
17 LFH_SIZE = 30,
18 };
19
20 unsigned int
21 read_le_int(const unsigned char* buf)
22 {
23 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
24 }
25
26 unsigned int
27 read_le_short(const unsigned char* buf)
28 {
29 return buf[0] | (buf[1] << 8);
30 }
31
32 static int
33 read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)
34 {
35 if (len < EOCD_LEN) {
36 // looks like ZIP file got truncated
37 fprintf(stderr, " Zip EOCD: expected >= %d bytes, found %d\n",
38 EOCD_LEN, len);
39 return -1;
40 }
41
42 file->disknum = read_le_short(&buf[0x04]);
43 file->diskWithCentralDir = read_le_short(&buf[0x06]);
44 file->entryCount = read_le_short(&buf[0x08]);
45 file->totalEntryCount = read_le_short(&buf[0x0a]);
46 file->centralDirSize = read_le_int(&buf[0x0c]);
47 file->centralDirOffest = read_le_int(&buf[0x10]);
48 file->commentLen = read_le_short(&buf[0x14]);
49
50 if (file->commentLen > 0) {
51 if (EOCD_LEN + file->commentLen > len) {
52 fprintf(stderr, "EOCD(%d) + comment(%d) exceeds len (%d)\n",
53 EOCD_LEN, file->commentLen, len);
54 return -1;
55 }
56 file->comment = buf + EOCD_LEN;
57 }
58
59 return 0;
60 }
61
62 static int
63 read_central_directory_entry(Zipfile* file, Zipentry* entry,
64 const unsigned char** buf, ssize_t* len)
65 {
66 const unsigned char* p;
67
68 unsigned short versionMadeBy;
69 unsigned short versionToExtract;
70 unsigned short gpBitFlag;
71 unsigned short compressionMethod;
72 unsigned short lastModFileTime;
73 unsigned short lastModFileDate;
74 unsigned long crc32;
75 unsigned long compressedSize;
76 unsigned long uncompressedSize;
77 unsigned short extraFieldLength;
78 unsigned short fileCommentLength;
79 unsigned short diskNumberStart;
80 unsigned short internalAttrs;
81 unsigned long externalAttrs;
82 unsigned long localHeaderRelOffset;
83 const unsigned char* extraField;
84 const unsigned char* fileComment;
85 unsigned int dataOffset;
86 unsigned short lfhExtraFieldSize;
87
88
89 p = *buf;
90
91 if (*len < ENTRY_LEN) {
92 fprintf(stderr, "cde entry not large enough\n");
93 return -1;
94 }
95
96 if (read_le_int(&p[0x00]) != ENTRY_SIGNATURE) {
97 fprintf(stderr, "Whoops: didn't find expected signature\n");
98 return -1;
99 }
100
101 versionMadeBy = read_le_short(&p[0x04]);
102 versionToExtract = read_le_short(&p[0x06]);
103 gpBitFlag = read_le_short(&p[0x08]);
104 entry->compressionMethod = read_le_short(&p[0x0a]);
105 lastModFileTime = read_le_short(&p[0x0c]);
106 lastModFileDate = read_le_short(&p[0x0e]);
107 crc32 = read_le_int(&p[0x10]);
108 compressedSize = read_le_int(&p[0x14]);
109 entry->uncompressedSize = read_le_int(&p[0x18]);
110 entry->fileNameLength = read_le_short(&p[0x1c]);
111 extraFieldLength = read_le_short(&p[0x1e]);
112 fileCommentLength = read_le_short(&p[0x20]);
113 diskNumberStart = read_le_short(&p[0x22]);
114 internalAttrs = read_le_short(&p[0x24]);
115 externalAttrs = read_le_int(&p[0x26]);
116 localHeaderRelOffset = read_le_int(&p[0x2a]);
117
118 p += ENTRY_LEN;
119
120 // filename
121 if (entry->fileNameLength != 0) {
122 entry->fileName = p;
123 } else {
124 entry->fileName = NULL;
125 }
126 p += entry->fileNameLength;
127
128 // extra field
129 if (extraFieldLength != 0) {
130 extraField = p;
131 } else {
132 extraField = NULL;
133 }
134 p += extraFieldLength;
135
136 // comment, if any
137 if (fileCommentLength != 0) {
138 fileComment = p;
139 } else {
140 fileComment = NULL;
141 }
142 p += fileCommentLength;
143
144 *buf = p;
145
146 // the size of the extraField in the central dir is how much data there is,
147 // but the one in the local file header also contains some padding.
148 p = file->buf + localHeaderRelOffset;
149 extraFieldLength = read_le_short(&p[0x1c]);
150
151 dataOffset = localHeaderRelOffset + LFH_SIZE
152 + entry->fileNameLength + extraFieldLength;
153 entry->data = file->buf + dataOffset;
154 #if 0
155 printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "
156 "entry->fileNameLength=%d extraFieldLength=%d\n",
157 file->buf, entry->data, dataOffset, localHeaderRelOffset,
158 entry->fileNameLength, extraFieldLength);
159 #endif
160 return 0;
161 }
162
163 /*
164 * Find the central directory and read the contents.
165 *
166 * The fun thing about ZIP archives is that they may or may not be
167 * readable from start to end. In some cases, notably for archives
168 * that were written to stdout, the only length information is in the
169 * central directory at the end of the file.
170 *
171 * Of course, the central directory can be followed by a variable-length
172 * comment field, so we have to scan through it backwards. The comment
173 * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
174 * itself, plus apparently sometimes people throw random junk on the end
175 * just for the fun of it.
176 *
177 * This is all a little wobbly. If the wrong value ends up in the EOCD
178 * area, we're hosed. This appears to be the way that everbody handles
179 * it though, so we're in pretty good company if this fails.
180 */
181 int
182 read_central_dir(Zipfile *file)
183 {
184 int err;
185
186 const unsigned char* buf = file->buf;
187 ssize_t bufsize = file->bufsize;
188 const unsigned char* eocd;
189 const unsigned char* p;
190 const unsigned char* start;
191 ssize_t len;
192 int i;
193
194 // too small to be a ZIP archive?
195 if (bufsize < EOCD_LEN) {
196 fprintf(stderr, "Length is %d -- too small\n", bufsize);
197 goto bail;
198 }
199
200 // find the end-of-central-dir magic
201 if (bufsize > MAX_EOCD_SEARCH) {
202 start = buf + bufsize - MAX_EOCD_SEARCH;
203 } else {
204 start = buf;
205 }
206 p = buf + bufsize - 4;
207 while (p >= start) {
208 if (*p == 0x50 && read_le_int(p) == CD_SIGNATURE) {
209 eocd = p;
210 break;
211 }
212 p--;
213 }
214 if (p < start) {
215 fprintf(stderr, "EOCD not found, not Zip\n");
216 goto bail;
217 }
218
219 // extract eocd values
220 err = read_central_dir_values(file, eocd, (buf+bufsize)-eocd);
221 if (err != 0) {
222 goto bail;
223 }
224
225 if (file->disknum != 0
226 || file->diskWithCentralDir != 0
227 || file->entryCount != file->totalEntryCount) {
228 fprintf(stderr, "Archive spanning not supported\n");
229 goto bail;
230 }
231
232 // Loop through and read the central dir entries.
233 p = buf + file->centralDirOffest;
234 len = (buf+bufsize)-p;
235 for (i=0; i < file->totalEntryCount; i++) {
236 Zipentry* entry = malloc(sizeof(Zipentry));
237 memset(entry, sizeof(Zipentry), 0);
238
239 err = read_central_directory_entry(file, entry, &p, &len);
240 if (err != 0) {
241 fprintf(stderr, "read_central_directory_entry failed\n");
242 free(entry);
243 goto bail;
244 }
245
246 // add it to our list
247 entry->next = file->entries;
248 file->entries = entry;
249 }
250
251 return 0;
252 bail:
253 return -1;
254 }
255
+0
-45
libzipfile/private.h less more
0 #ifndef PRIVATE_H
1 #define PRIVATE_H
2
3 #include <stddef.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8
9 typedef struct Zipentry {
10 unsigned long fileNameLength;
11 const unsigned char* fileName;
12 unsigned short compressionMethod;
13 unsigned int uncompressedSize;
14 unsigned int compressedSize;
15 const unsigned char* data;
16
17 struct Zipentry* next;
18 } Zipentry;
19
20 typedef struct Zipfile
21 {
22 const unsigned char *buf;
23 ssize_t bufsize;
24
25 // Central directory
26 unsigned short disknum; //mDiskNumber;
27 unsigned short diskWithCentralDir; //mDiskWithCentralDir;
28 unsigned short entryCount; //mNumEntries;
29 unsigned short totalEntryCount; //mTotalNumEntries;
30 unsigned int centralDirSize; //mCentralDirSize;
31 unsigned int centralDirOffest; // offset from first disk //mCentralDirOffset;
32 unsigned short commentLen; //mCommentLen;
33 const unsigned char* comment; //mComment;
34
35 Zipentry* entries;
36 } Zipfile;
37
38 int read_central_dir(Zipfile* file);
39
40 unsigned int read_le_int(const unsigned char* buf);
41 unsigned int read_le_short(const unsigned char* buf);
42
43 #endif // PRIVATE_H
44
+0
-92
libzipfile/test_zipfile.c less more
0 #include <zipfile/zipfile.h>
1
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 void dump_zipfile(FILE* to, zipfile_t file);
6
7 int
8 main(int argc, char** argv)
9 {
10 FILE* f;
11 size_t size, unsize;
12 void* buf;
13 void* scratch;
14 zipfile_t zip;
15 zipentry_t entry;
16 int err;
17 enum { HUH, LIST, UNZIP } what = HUH;
18
19 if (strcmp(argv[2], "-l") == 0 && argc == 3) {
20 what = LIST;
21 }
22 else if (strcmp(argv[2], "-u") == 0 && argc == 5) {
23 what = UNZIP;
24 }
25 else {
26 fprintf(stderr, "usage: test_zipfile ZIPFILE -l\n"
27 " lists the files in the zipfile\n"
28 " test_zipfile ZIPFILE -u FILENAME SAVETO\n"
29 " saves FILENAME from the zip file into SAVETO\n");
30 return 1;
31 }
32
33 f = fopen(argv[1], "r");
34 if (f == NULL) {
35 fprintf(stderr, "couldn't open %s\n", argv[1]);
36 return 1;
37 }
38
39 fseek(f, 0, SEEK_END);
40 size = ftell(f);
41 rewind(f);
42
43 buf = malloc(size);
44 fread(buf, 1, size, f);
45
46 zip = init_zipfile(buf, size);
47 if (zip == NULL) {
48 fprintf(stderr, "inti_zipfile failed\n");
49 return 1;
50 }
51
52 fclose(f);
53
54
55 switch (what)
56 {
57 case LIST:
58 dump_zipfile(stdout, zip);
59 break;
60 case UNZIP:
61 entry = lookup_zipentry(zip, argv[3]);
62 if (entry == NULL) {
63 fprintf(stderr, "zip file '%s' does not contain file '%s'\n",
64 argv[1], argv[1]);
65 return 1;
66 }
67 f = fopen(argv[4], "w");
68 if (f == NULL) {
69 fprintf(stderr, "can't open file for writing '%s'\n", argv[4]);
70 return 1;
71 }
72 unsize = get_zipentry_size(entry);
73 size = unsize * 1.001;
74 scratch = malloc(size);
75 printf("scratch=%p\n", scratch);
76 err = decompress_zipentry(entry, scratch, size);
77 if (err != 0) {
78 fprintf(stderr, "error decompressing file\n");
79 return 1;
80 }
81 fwrite(scratch, unsize, 1, f);
82 free(scratch);
83 fclose(f);
84 break;
85 }
86
87 free(buf);
88
89 return 0;
90 }
91
+0
-160
libzipfile/zipfile.c less more
0 #include <zipfile/zipfile.h>
1
2 #include "private.h"
3 #include <stdlib.h>
4 #include <string.h>
5 #include <zlib.h>
6 #define DEF_MEM_LEVEL 8 // normally in zutil.h?
7
8 zipfile_t
9 init_zipfile(const void* data, size_t size)
10 {
11 int err;
12
13 Zipfile *file = malloc(sizeof(Zipfile));
14 if (file == NULL) return NULL;
15 memset(file, 0, sizeof(Zipfile));
16 file->buf = data;
17 file->bufsize = size;
18
19 err = read_central_dir(file);
20 if (err != 0) goto fail;
21
22 return file;
23 fail:
24 free(file);
25 return NULL;
26 }
27
28 void
29 release_zipfile(zipfile_t f)
30 {
31 Zipfile* file = (Zipfile*)f;
32 Zipentry* entry = file->entries;
33 while (entry) {
34 Zipentry* next = entry->next;
35 free(entry);
36 entry = next;
37 }
38 free(file);
39 }
40
41 zipentry_t
42 lookup_zipentry(zipfile_t f, const char* entryName)
43 {
44 Zipfile* file = (Zipfile*)f;
45 Zipentry* entry = file->entries;
46 while (entry) {
47 if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) {
48 return entry;
49 }
50 entry = entry->next;
51 }
52 return NULL;
53 }
54
55 size_t
56 get_zipentry_size(zipentry_t entry)
57 {
58 return ((Zipentry*)entry)->uncompressedSize;
59 }
60
61 char*
62 get_zipentry_name(zipentry_t entry)
63 {
64 Zipentry* e = (Zipentry*)entry;
65 int l = e->fileNameLength;
66 char* s = malloc(l+1);
67 memcpy(s, e->fileName, l);
68 s[l] = '\0';
69 return s;
70 }
71
72 enum {
73 STORED = 0,
74 DEFLATED = 8
75 };
76
77 static int
78 uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
79 {
80 z_stream zstream;
81 unsigned long crc;
82 int err = 0;
83 int zerr;
84
85 memset(&zstream, 0, sizeof(zstream));
86 zstream.zalloc = Z_NULL;
87 zstream.zfree = Z_NULL;
88 zstream.opaque = Z_NULL;
89 zstream.next_in = (void*)in;
90 zstream.avail_in = unlen;
91 zstream.next_out = (Bytef*) out;
92 zstream.avail_out = unlen;
93 zstream.data_type = Z_UNKNOWN;
94
95 // Use the undocumented "negative window bits" feature to tell zlib
96 // that there's no zlib header waiting for it.
97 zerr = inflateInit2(&zstream, -MAX_WBITS);
98 if (zerr != Z_OK) {
99 return -1;
100 }
101
102 // uncompress the data
103 zerr = inflate(&zstream, Z_FINISH);
104 if (zerr != Z_STREAM_END) {
105 fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END,
106 zstream.total_out);
107 err = -1;
108 }
109
110 inflateEnd(&zstream);
111 return err;
112 }
113
114 int
115 decompress_zipentry(zipentry_t e, void* buf, int bufsize)
116 {
117 Zipentry* entry = (Zipentry*)e;
118 switch (entry->compressionMethod)
119 {
120 case STORED:
121 memcpy(buf, entry->data, entry->uncompressedSize);
122 return 0;
123 case DEFLATED:
124 return uninflate(buf, bufsize, entry->data, entry->compressedSize);
125 default:
126 return -1;
127 }
128 }
129
130 void
131 dump_zipfile(FILE* to, zipfile_t file)
132 {
133 Zipfile* zip = (Zipfile*)file;
134 Zipentry* entry = zip->entries;
135 int i;
136
137 fprintf(to, "entryCount=%d\n", zip->entryCount);
138 for (i=0; i<zip->entryCount; i++) {
139 fprintf(to, " file \"");
140 fwrite(entry->fileName, entry->fileNameLength, 1, to);
141 fprintf(to, "\"\n");
142 entry = entry->next;
143 }
144 }
145
146 zipentry_t
147 iterate_zipfile(zipfile_t file, void** cookie)
148 {
149 Zipentry* entry = (Zipentry*)*cookie;
150 if (entry == NULL) {
151 Zipfile* zip = (Zipfile*)file;
152 *cookie = zip->entries;
153 return *cookie;
154 } else {
155 entry = entry->next;
156 *cookie = entry;
157 return entry;
158 }
159 }
+0
-27
logcat/Android.mk less more
0 # Copyright 2006 The Android Open Source Project
1
2 LOCAL_PATH:= $(call my-dir)
3 include $(CLEAR_VARS)
4
5 LOCAL_SRC_FILES:= logcat.cpp
6
7 LOCAL_SHARED_LIBRARIES := liblog
8
9 LOCAL_MODULE:= logcat
10
11 include $(BUILD_EXECUTABLE)
12
13 ########################
14 include $(CLEAR_VARS)
15
16 LOCAL_MODULE := event-log-tags
17
18 #LOCAL_MODULE_TAGS := user development
19
20 # This will install the file in /system/etc
21 #
22 LOCAL_MODULE_CLASS := ETC
23
24 LOCAL_SRC_FILES := $(LOCAL_MODULE)
25
26 include $(BUILD_PREBUILT)
+0
-0
logcat/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
logcat/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-346
logcat/event-log-tags less more
0 # The entries in this file map a sparse set of log tag numbers to tag names.
1 # This is installed on the device, in /system/etc, and parsed by logcat.
2 #
3 # Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
4 # negative values alone for now.)
5 #
6 # Tag names are one or more ASCII letters and numbers or underscores, i.e.
7 # "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
8 # impacts log readability, the latter makes regex searches more annoying).
9 #
10 # Tag numbers and names are separated by whitespace. Blank lines and lines
11 # starting with '#' are ignored.
12 #
13 # Optionally, after the tag names can be put a description for the value(s)
14 # of the tag. Description are in the format
15 # (<name>|data type[|data unit])
16 # Multiple values are separated by commas.
17 #
18 # The data type is a number from the following values:
19 # 1: int
20 # 2: long
21 # 3: string
22 # 4: list
23 #
24 # The data unit is a number taken from the following list:
25 # 1: Number of objects
26 # 2: Number of bytes
27 # 3: Number of milliseconds
28 # 4: Number of allocations
29 # 5: Id
30 # 6: Percent
31 # Default value for data of type int/long is 2 (bytes).
32 #
33 # TODO: generate ".java" and ".h" files with integer constants from this file.
34
35 # These are used for testing, do not modify without updating
36 # tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
37 42 answer (to life the universe etc|3)
38 314 pi
39 2718 e
40
41 2719 configuration_changed (config mask|1|5)
42 2720 sync (id|3),(event|1|5),(source|1|5)
43 2721 cpu (total|1|6),(user|1|6),(system|1|6),(iowait|1|6),(irq|1|6),(softirq|1|6)
44 2722 battery_level (level|1|6),(voltage|1|1),(temperature|1|1)
45 2723 battery_status (status|1|5),(health|1|5),(present|1|5),(plugged|1|5),(technology|3)
46 # This is logged when the device is being forced to sleep (typically by
47 # the user pressing the power button).
48 2724 power_sleep_requested (wakeLocksCleared|1|1)
49 # This is logged when the screen on broadcast has completed
50 2725 power_screen_broadcast_send (wakelockCount|1|1)
51 # This is logged when the screen broadcast has completed
52 2726 power_screen_broadcast_done (on|1|5),(broadcastDuration|2|3),(wakelockCount|1|1)
53 # This is logged when the screen on broadcast has completed
54 2727 power_screen_broadcast_stop (which|1|5),(wakelockCount|1|1)
55 # This is logged when the screen is turned on or off.
56 2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
57 # This is logged when the partial wake lock (keeping the device awake
58 # regardless of whether the screen is off) is acquired or released.
59 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3)
60 # This is logged when battery goes from discharging to charging.
61 # It lets us count the total amount of time between charges and the discharge level
62 2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6)
63 #
64 # Leave IDs through 2739 for more power logs
65 #
66
67 # This event is logged when the location service uploads location data.
68 2740 location_controller
69 # This event is logged when someone is deciding to force a garbage collection
70 2741 force_gc (reason|3)
71 # This event is logged on each tickle
72 2742 tickle (authority|3)
73 # What happens in a sync operation (bytes sent and received, and
74 # operation details)
75 2743 sync_details (authority|3),(send|1|2),(recv|1|2),(details|3)
76
77 # The disk space free on the /data partition, in bytes
78 2744 free_storage_changed (data|2|2)
79 # Device low memory notification and disk space free on the /data partition, in bytes at that time
80 2745 low_storage (data|2|2)
81 # disk space free on the /data partition in bytes
82 2746 free_storage_left (data|2|2)
83
84 # when a NotificationManager.notify is called
85 2750 notification_enqueue (pkg|3),(id|1|5),(notification|3)
86 # when someone tries to cancel a notification, the notification manager sometimes
87 # calls this with flags too
88 2751 notification_cancel (pkg|3),(id|1|5),(required_flags|1)
89 # when someone tries to cancel all of the notifications for a particular package
90 2752 notification_cancel_all (pkg|3),(required_flags|1)
91
92 # This event is logged when GTalkService encounters important events
93 2800 gtalkservice (eventType|1)
94 # This event is logged for GTalk connection state changes. The status field is an int, but
95 # it really contains 4 separate values, each taking up a byte
96 # (eventType, connection state, connection error, network state)
97 2801 gtalk_connection (status|1)
98
99 2802 watchdog (Service|3)
100 2803 watchdog_proc_pss (Process|3),(Pid|1|5),(Pss|1|2)
101 2804 watchdog_soft_reset (Process|3),(Pid|1|5),(MaxPss|1|2),(Pss|1|2),(Skip|3)
102 2805 watchdog_hard_reset (Process|3),(Pid|1|5),(MaxPss|1|2),(Pss|1|2)
103 2806 watchdog_pss_stats (EmptyPss|1|2),(EmptyCount|1|1),(BackgroundPss|1|2),(BackgroundCount|1|1),(ServicePss|1|2),(ServiceCount|1|1),(VisiblePss|1|2),(VisibleCount|1|1),(ForegroundPss|1|2),(ForegroundCount|1|1),(NoPssCount|1|1)
104 2807 watchdog_proc_stats (DeathsInOne|1|1),(DeathsInTwo|1|1),(DeathsInThree|1|1),(DeathsInFour|1|1),(DeathsInFive|1|1)
105 2808 watchdog_scheduled_reboot (Now|2|1),(Interval|1|3),(StartTime|1|3),(Window|1|3),(Skip|3)
106 2809 watchdog_meminfo (MemFree|1|2),(Buffers|1|2),(Cached|1|2),(Active|1|2),(Inactive|1|2),(AnonPages|1|2),(Mapped|1|2),(Slab|1|2),(SReclaimable|1|2),(SUnreclaim|1|2),(PageTables|1|2)
107 2810 watchdog_vmstat (runtime|2|3),(pgfree|1|1),(pgactivate|1|1),(pgdeactivate|1|1),(pgfault|1|1),(pgmajfault|1|1)
108 2811 watchdog_requested_reboot (NoWait|1|1),(ScheduleInterval|1|3),(RecheckInterval|1|3),(StartTime|1|3),(Window|1|3),(MinScreenOff|1|3),(MinNextAlarm|1|3)
109
110 # Device boot timings. We include monotonic clock values because the
111 # intrinsic event log times are wall-clock.
112 #
113 # Runtime starts:
114 3000 boot_progress_start (time|2|3)
115 # SystemServer.run() starts:
116 3010 boot_progress_system_run (time|2|3)
117 # ZygoteInit class preloading starts:
118 3020 boot_progress_preload_start (time|2|3)
119 # ZygoteInit class preloading ends:
120 3030 boot_progress_preload_end (time|2|3)
121 # ActivityManagerService.systemReady() starts:
122 3040 boot_progress_ams_ready (time|2|3)
123 # ActivityManagerService calls enableScreenAfterBoot():
124 3050 boot_progress_enable_screen (time|2|3)
125 # Package Manager starts:
126 3060 boot_progress_pms_start (time|2|3)
127 # Package Manager .apk scan starts:
128 3070 boot_progress_pms_system_scan_start (time|2|3)
129 # Package Manager .apk scan starts:
130 3080 boot_progress_pms_data_scan_start (time|2|3)
131 # Package Manager .apk scan ends:
132 3090 boot_progress_pms_scan_end (time|2|3)
133 # Package Manager ready:
134 3100 boot_progress_pms_ready (time|2|3)
135 # + check activity_launch_time for Home app
136
137 # Do not change these names without updating the checkin_events setting in
138 # google3/googledata/wireless/android/provisioning/gservices.config !!
139 #
140 # An activity is being finished:
141 30001 am_finish_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
142 # A task is being brought to the front of the screen:
143 30002 am_task_to_front (Task|1|5)
144 # An existing activity is being given a new intent:
145 30003 am_new_intent (Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
146 # A new task is being created:
147 30004 am_create_task (Task ID|1|5)
148 # A new activity is being created in an existing task:
149 30005 am_create_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
150 # An activity has been resumed into the foreground but was not already running:
151 30006 am_restart_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
152 # An activity has been resumed and is now in the foreground:
153 30007 am_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
154 # Application Not Responding
155 30008 anr (pid|1|5),(Package Name|3),(reason|3)
156 # Activity launch time
157 30009 activity_launch_time (Token|1|5),(Component Name|3),(time|2|3)
158 # Application process bound to work
159 30010 am_proc_bound (PID|1|5),(Process Name|3)
160 # Application process died
161 30011 am_proc_died (PID|1|5),(Process Name|3)
162 # The Activity Manager failed to pause the given activity.
163 30012 am_failed_to_pause (Token|1|5),(Wanting to pause|3),(Currently pausing|3)
164 # Attempting to pause the current activity
165 30013 am_pause_activity (Token|1|5),(Component Name|3)
166 # Application process has been started
167 30014 am_proc_start (PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
168 # An application process has been marked as bad
169 30015 am_proc_bad (UID|1|5),(Process Name|3)
170 # An application process that was bad is now marked as good
171 30016 am_proc_good (UID|1|5),(Process Name|3)
172 # Reporting to applications that memory is low
173 30017 am_low_memory (Num Processes|1|1)
174 # An activity is being destroyed:
175 30018 am_destroy_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
176 # An activity has been relaunched, resumed, and is now in the foreground:
177 30019 am_relaunch_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
178 # An activity has been relaunched:
179 30020 am_relaunch_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
180 # The activity's onPause has been called.
181 30021 am_on_paused_called (Component Name|3)
182 # The activity's onResume has been called.
183 30022 am_on_resume_called (Component Name|3)
184 # Kill a process to reclaim memory.
185 30023 am_kill_for_memory (PID|1|5),(Process Name|3),(OomAdj|1|5)
186 # Discard an undelivered serialized broadcast (timeout/ANR/crash)
187 30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
188 30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
189 # A service is being created
190 30030 am_create_service (Service Record|1|5),(Name|3),(Intent|3),(PID|1|5)
191 # A service is being destroyed
192 30031 am_destroy_service (Service Record|1|5),(Name|3),(PID|1|5)
193 # A process has crashed too many times, it is being cleared
194 30032 am_process_crashed_too_much (Name|3),(PID|1|5)
195 # An unknown process is trying to attach to the activity manager
196 30033 am_drop_process (PID|1|5)
197 # A service has crashed too many times, it is being stopped
198 30034 am_service_crashed_too_much (Crash Count|1|1),(Component Name|3),(PID|1|5)
199 # A service is going to be restarted after its process went away
200 30035 am_schedule_service_restart (Component Name|3),(Time|2|3)
201 # A client was waiting for a content provider, but its process was lost
202 30036 am_provider_lost_process (Package Name|3),(UID|1|5),(Name|3)
203
204 # Out of memory for surfaces.
205 31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
206
207 # Re-connecting to input method service because we haven't received its interface
208 32000 imf_force_reconnect_ime (IME|4),(Time Since Connect|2|3),(Showing|1|1)
209
210 # dvm_gc_info: LIST (LONG, LONG, LONG)
211 #
212 # First LONG:
213 #
214 # [63] 1
215 # [62-24] ASCII process identifier
216 # [23-12] GC time in ms
217 # [11- 0] Bytes freed
218 #
219 # Second LONG (aggregated heap info):
220 #
221 # [63-62] 10
222 # [61-60] Reserved; must be zero
223 # [59-48] Objects freed
224 # [47-36] Actual size (current footprint)
225 # [35-24] Allowed size (current hard max)
226 # [23-12] Objects allocated
227 # [11- 0] Bytes allocated
228 #
229 # Third LONG (zygote heap info):
230 #
231 # [63-62] 11
232 # [61-60] Reserved; must be zero
233 # [59-48] Soft limit
234 # [47-36] Actual size (current footprint)
235 # [35-24] Allowed size (current hard max)
236 # [23-12] Objects allocated
237 # [11- 0] Bytes allocated
238 #
239 # Fourth LONG:
240 #
241 # [63-48] Reserved; must be zero
242 # [47-36] dlmallocFootprint
243 # [35-24] mallinfo: total allocated space
244 # [23-12] External byte limit
245 # [11- 0] External bytes allocated
246 #
247 # See HeapDebug.c
248 #
249 20001 dvm_gc_info (custom|2),(custom|2),(custom|2),(custom|2)
250 20002 dvm_gc_madvise_info (total|1|2),(zygote|1|2)
251
252 75000 sqlite_mem_alarm_current (current|1|2)
253 75001 sqlite_mem_alarm_max (max|1|2)
254 75002 sqlite_mem_alarm_alloc_attempt (attempts|1|4)
255 75003 sqlite_mem_released (Memory released|1|2)
256
257 40000 checkin (Check in time|2|3)
258
259 50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3)
260 50001 menu_opened (Menu type where 0 is options and 1 is context|1|5)
261 # Connectivity state changed:
262 # [31-13] Reserved for future use
263 # [12- 9] Network subtype (for mobile network, as defined by TelephonyManager)
264 # [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
265 # [ 2- 0] Network type (as defined by ConnectivityManager)
266 50020 connectivity_state_changed (custom|1|5)
267
268 # Wi-Fi network state changed:
269 # [31- 6] Reserved for future use
270 # [ 5- 0] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
271 50021 wifi_network_state_changed (network_state|1|5)
272
273 # Wi-Fi supplicant state changed:
274 # [31- 6] Reserved for future use
275 # [ 5- 0] Supplicant state ordinal (as defined by SupplicantState)
276 50022 wifi_supplicant_state_changed (supplicant_state|1|5)
277
278 # Wi-Fi driver state changed:
279 # [31- 1] Reserved for future use
280 # [ 0- 0] Driver start (1) or stopped (0)
281 50023 wifi_driver_state_changed (driver_state|1|5)
282
283 # Wi-Fi interface configuration state changed:
284 # [31- 1] Reserved for future use
285 # [ 0- 0] Interface configuration succeeded (1) or failed (0)
286 50024 wifi_interface_configuration_state_changed (IP_configuration|1|5)
287
288 # Wi-Fi supplicant connection state changed:
289 # [31- 2] Reserved for future use
290 # [ 1- 0] Connected to supplicant (1) or disconnected from supplicant (0),
291 # or supplicant died (2)
292 50025 wifi_supplicant_connection_state_changed (connected|1|5)
293
294 # PDP Context has a bad DNS address
295 50100 pdp_bad_dns_address (dns_address|3)
296
297 # For data connection on PDP context, reached the data-out-without-data-in
298 # packet count that triggers a countdown to radio restart
299 50101 pdp_radio_reset_countdown_triggered (out_packet_count|1|1)
300
301 # Radio restart - timed out with no incoming packets.
302 50102 pdp_radio_reset (out_packet_count|1|1)
303
304 # PDP context reset - timed out with no incoming packets.
305 50103 pdp_context_reset (out_packet_count|1|1)
306
307 # Reregister to data network - timed out with no incoming packets.
308 50104 pdp_reregister_network (out_packet_count|1|1)
309
310 # PDP Setup failures
311 50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5)
312
313 # Call drops
314 50106 call_drop (cause|1|5), (cid|1|5), (network_type|1|5)
315
316 # Data network registration failed after successful voice registration
317 50107 data_network_registration_fail (op_numeric|1|5), (cid|1|5)
318
319 # Suspicious status of data connection while radio poweroff
320 50108 data_network_status_on_radio_off (dc_state|3), (enable|1|5)
321
322 # PDP drop caused by network
323 50109 pdp_network_drop (cid|1|5), (network_type|1|5)
324
325 # Do not change these names without updating tag in:
326 #//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c
327 51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5)
328
329 # db stats. 0 is query, 1 is write (may become more fine grained in the
330 # future)
331 52000 db_operation (name|3),(op_type|1|5),(time|2|3)
332
333 # http request/response stats
334 52001 http_stats (useragent|3),(response|2|3),(processing|2|3),(tx|1|2),(rx|1|2)
335 60000 viewroot_draw (Draw time|1|3)
336 60001 viewroot_layout (Layout time|1|3)
337 60002 view_build_drawing_cache (View created drawing cache|1|5)
338 60003 view_use_drawing_cache (View drawn using bitmap cache|1|5)
339
340 # 0 for screen off, 1 for screen on, 2 for key-guard done
341 70000 screen_toggled (screen_state|1|5)
342
343 # browser stats for diary study
344 70101 browser_zoom_level_change (start level|1|5),(end level|1|5),(time|2|3)
345 70102 browser_double_tap_duration (duration|1|3),(time|2|3)
+0
-568
logcat/logcat.cpp less more
0 // Copyright 2006 The Android Open Source Project
1
2 #include <cutils/logger.h>
3 #include <cutils/logd.h>
4 #include <cutils/sockets.h>
5 #include <cutils/logprint.h>
6 #include <cutils/event_tag_map.h>
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <time.h>
15 #include <errno.h>
16 #include <assert.h>
17 #include <ctype.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <arpa/inet.h>
21
22 #define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
23 #define DEFAULT_MAX_ROTATED_LOGS 4
24
25 static AndroidLogFormat * g_logformat;
26
27 /* logd prefixes records with a length field */
28 #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
29
30 #define LOG_FILE_DIR "/dev/log/"
31
32
33 namespace android {
34
35 /* Global Variables */
36
37 static const char * g_outputFileName = NULL;
38 static int g_logRotateSizeKBytes = 0; // 0 means "no log rotation"
39 static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
40 static int g_outFD = -1;
41 static off_t g_outByteCount = 0;
42 static int g_isBinary = 0;
43 static int g_printBinary = 0;
44
45 static EventTagMap* g_eventTagMap = NULL;
46
47 static int openLogFile (const char *pathname)
48 {
49 return open(g_outputFileName, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
50 }
51
52 static void rotateLogs()
53 {
54 int err;
55
56 // Can't rotate logs if we're not outputting to a file
57 if (g_outputFileName == NULL) {
58 return;
59 }
60
61 close(g_outFD);
62
63 for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
64 char *file0, *file1;
65
66 asprintf(&file1, "%s.%d", g_outputFileName, i);
67
68 if (i - 1 == 0) {
69 asprintf(&file0, "%s", g_outputFileName);
70 } else {
71 asprintf(&file0, "%s.%d", g_outputFileName, i - 1);
72 }
73
74 err = rename (file0, file1);
75
76 if (err < 0 && errno != ENOENT) {
77 perror("while rotating log files");
78 }
79
80 free(file1);
81 free(file0);
82 }
83
84 g_outFD = openLogFile (g_outputFileName);
85
86 if (g_outFD < 0) {
87 perror ("couldn't open output file");
88 exit(-1);
89 }
90
91 g_outByteCount = 0;
92
93 }
94
95 void printBinary(struct logger_entry *buf)
96 {
97 size_t size = sizeof(logger_entry) + buf->len;
98 int ret;
99
100 do {
101 ret = write(g_outFD, buf, size);
102 } while (ret < 0 && errno == EINTR);
103 }
104
105 static void processBuffer(struct logger_entry *buf)
106 {
107 int bytesWritten;
108 int err;
109 AndroidLogEntry entry;
110 char binaryMsgBuf[1024];
111
112 if (g_isBinary) {
113 err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
114 binaryMsgBuf, sizeof(binaryMsgBuf));
115 //printf(">>> pri=%d len=%d msg='%s'\n",
116 // entry.priority, entry.messageLen, entry.message);
117 } else {
118 err = android_log_processLogBuffer(buf, &entry);
119 }
120 if (err < 0)
121 goto error;
122
123 bytesWritten = android_log_filterAndPrintLogLine(
124 g_logformat, g_outFD, &entry);
125
126 if (bytesWritten < 0) {
127 perror("output error");
128 exit(-1);
129 }
130
131 g_outByteCount += bytesWritten;
132
133 if (g_logRotateSizeKBytes > 0
134 && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
135 ) {
136 rotateLogs();
137 }
138
139 error:
140 //fprintf (stderr, "Error processing record\n");
141 return;
142 }
143
144 static void readLogLines(int logfd)
145 {
146 while (1) {
147 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
148 struct logger_entry *entry = (struct logger_entry *) buf;
149 int ret;
150
151 ret = read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
152 if (ret < 0) {
153 if (errno == EINTR)
154 continue;
155 if (errno == EAGAIN)
156 break;
157 perror("logcat read");
158 exit(EXIT_FAILURE);
159 }
160 else if (!ret) {
161 fprintf(stderr, "read: Unexpected EOF!\n");
162 exit(EXIT_FAILURE);
163 }
164
165 /* NOTE: driver guarantees we read exactly one full entry */
166
167 entry->msg[entry->len] = '\0';
168
169 if (g_printBinary) {
170 printBinary(entry);
171 } else {
172 (void) processBuffer(entry);
173 }
174 }
175 }
176
177 static int clearLog(int logfd)
178 {
179 return ioctl(logfd, LOGGER_FLUSH_LOG);
180 }
181
182 /* returns the total size of the log's ring buffer */
183 static int getLogSize(int logfd)
184 {
185 return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE);
186 }
187
188 /* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */
189 static int getLogReadableSize(int logfd)
190 {
191 return ioctl(logfd, LOGGER_GET_LOG_LEN);
192 }
193
194 static void setupOutput()
195 {
196
197 if (g_outputFileName == NULL) {
198 g_outFD = STDOUT_FILENO;
199
200 } else {
201 struct stat statbuf;
202
203 g_outFD = openLogFile (g_outputFileName);
204
205 if (g_outFD < 0) {
206 perror ("couldn't open output file");
207 exit(-1);
208 }
209
210 fstat(g_outFD, &statbuf);
211
212 g_outByteCount = statbuf.st_size;
213 }
214 }
215
216 static void show_help(const char *cmd)
217 {
218 fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
219
220 fprintf(stderr, "options include:\n"
221 " -s Set default filter to silent.\n"
222 " Like specifying filterspec '*:s'\n"
223 " -f <filename> Log to file. Default to stdout\n"
224 " -r [<kbytes>] Rotate log every kbytes. (16 if unspecified). Requires -f\n"
225 " -n <count> Sets max number of rotated logs to <count>, default 4\n"
226 " -v <format> Sets the log print format, where <format> is one of:\n\n"
227 " brief process tag thread raw time threadtime long\n\n"
228 " -c clear (flush) the entire log and exit\n"
229 " -d dump the log and then exit (don't block)\n"
230 " -g get the size of the log's ring buffer and exit\n"
231 " -b <buffer> request alternate ring buffer\n"
232 " ('main' (default), 'radio', 'events')\n"
233 " -B output the log in binary");
234
235
236 fprintf(stderr,"\nfilterspecs are a series of \n"
237 " <tag>[:priority]\n\n"
238 "where <tag> is a log component tag (or * for all) and priority is:\n"
239 " V Verbose\n"
240 " D Debug\n"
241 " I Info\n"
242 " W Warn\n"
243 " E Error\n"
244 " F Fatal\n"
245 " S Silent (supress all output)\n"
246 "\n'*' means '*:d' and <tag> by itself means <tag>:v\n"
247 "\nIf not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.\n"
248 "If no filterspec is found, filter defaults to '*:I'\n"
249 "\nIf not specified with -v, format is set from ANDROID_PRINTF_LOG\n"
250 "or defaults to \"brief\"\n\n");
251
252
253
254 }
255
256
257 } /* namespace android */
258
259 static int setLogFormat(const char * formatString)
260 {
261 static AndroidLogPrintFormat format;
262
263 format = android_log_formatFromString(formatString);
264
265 if (format == FORMAT_OFF) {
266 // FORMAT_OFF means invalid string
267 return -1;
268 }
269
270 android_log_setPrintFormat(g_logformat, format);
271
272 return 0;
273 }
274
275 extern "C" void logprint_run_tests(void);
276
277 int main (int argc, char **argv)
278 {
279 int logfd;
280 int err;
281 int hasSetLogFormat = 0;
282 int clearLog = 0;
283 int getLogSize = 0;
284 int mode = O_RDONLY;
285 char *log_device = strdup("/dev/"LOGGER_LOG_MAIN);
286 const char *forceFilters = NULL;
287
288 g_logformat = android_log_format_new();
289
290 if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
291 logprint_run_tests();
292 exit(0);
293 }
294
295 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
296 android::show_help(argv[0]);
297 exit(0);
298 }
299
300 for (;;) {
301 int ret;
302
303 ret = getopt(argc, argv, "cdgsQf:r::n:v:b:B");
304
305 if (ret < 0) {
306 break;
307 }
308
309 switch(ret) {
310 case 's':
311 // default to all silent
312 android_log_addFilterRule(g_logformat, "*:s");
313 break;
314
315 case 'c':
316 clearLog = 1;
317 mode = O_WRONLY;
318 break;
319
320 case 'd':
321 mode |= O_NONBLOCK;
322 break;
323
324 case 'g':
325 getLogSize = 1;
326 break;
327
328 case 'b':
329 free(log_device);
330 log_device =
331 (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
332 strcpy(log_device, LOG_FILE_DIR);
333 strcat(log_device, optarg);
334
335 android::g_isBinary = (strcmp(optarg, "events") == 0);
336 break;
337
338 case 'B':
339 android::g_printBinary = 1;
340 break;
341
342 case 'f':
343 // redirect output to a file
344
345 android::g_outputFileName = optarg;
346
347 break;
348
349 case 'r':
350 if (optarg == NULL) {
351 android::g_logRotateSizeKBytes
352 = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
353 } else {
354 long logRotateSize;
355 char *lastDigit;
356
357 if (!isdigit(optarg[0])) {
358 fprintf(stderr,"Invalid parameter to -r\n");
359 android::show_help(argv[0]);
360 exit(-1);
361 }
362 android::g_logRotateSizeKBytes = atoi(optarg);
363 }
364 break;
365
366 case 'n':
367 if (!isdigit(optarg[0])) {
368 fprintf(stderr,"Invalid parameter to -r\n");
369 android::show_help(argv[0]);
370 exit(-1);
371 }
372
373 android::g_maxRotatedLogs = atoi(optarg);
374 break;
375
376 case 'v':
377 err = setLogFormat (optarg);
378 if (err < 0) {
379 fprintf(stderr,"Invalid parameter to -v\n");
380 android::show_help(argv[0]);
381 exit(-1);
382 }
383
384 hasSetLogFormat = 1;
385 break;
386
387 case 'Q':
388 /* this is a *hidden* option used to start a version of logcat */
389 /* in an emulated device only. it basically looks for androidboot.logcat= */
390 /* on the kernel command line. If something is found, it extracts a log filter */
391 /* and uses it to run the program. If nothing is found, the program should */
392 /* quit immediately */
393 #define KERNEL_OPTION "androidboot.logcat="
394 #define CONSOLE_OPTION "androidboot.console="
395 {
396 int fd;
397 char* logcat;
398 char* console;
399 int force_exit = 1;
400 static char cmdline[1024];
401
402 fd = open("/proc/cmdline", O_RDONLY);
403 if (fd >= 0) {
404 int n = read(fd, cmdline, sizeof(cmdline)-1 );
405 if (n < 0) n = 0;
406 cmdline[n] = 0;
407 close(fd);
408 } else {
409 cmdline[0] = 0;
410 }
411
412 logcat = strstr( cmdline, KERNEL_OPTION );
413 console = strstr( cmdline, CONSOLE_OPTION );
414 if (logcat != NULL) {
415 char* p = logcat + sizeof(KERNEL_OPTION)-1;;
416 char* q = strpbrk( p, " \t\n\r" );;
417
418 if (q != NULL)
419 *q = 0;
420
421 forceFilters = p;
422 force_exit = 0;
423 }
424 /* if nothing found or invalid filters, exit quietly */
425 if (force_exit)
426 exit(0);
427
428 /* redirect our output to the emulator console */
429 if (console) {
430 char* p = console + sizeof(CONSOLE_OPTION)-1;
431 char* q = strpbrk( p, " \t\n\r" );
432 char devname[64];
433 int len;
434
435 if (q != NULL) {
436 len = q - p;
437 } else
438 len = strlen(p);
439
440 len = snprintf( devname, sizeof(devname), "/dev/%.*s", len, p );
441 fprintf(stderr, "logcat using %s (%d)\n", devname, len);
442 if (len < (int)sizeof(devname)) {
443 fd = open( devname, O_WRONLY );
444 if (fd >= 0) {
445 dup2(fd, 1);
446 dup2(fd, 2);
447 close(fd);
448 }
449 }
450 }
451 }
452 break;
453
454 default:
455 fprintf(stderr,"Unrecognized Option\n");
456 android::show_help(argv[0]);
457 exit(-1);
458 break;
459 }
460 }
461
462 if (android::g_logRotateSizeKBytes != 0
463 && android::g_outputFileName == NULL
464 ) {
465 fprintf(stderr,"-r requires -f as well\n");
466 android::show_help(argv[0]);
467 exit(-1);
468 }
469
470 android::setupOutput();
471
472 if (hasSetLogFormat == 0) {
473 const char* logFormat = getenv("ANDROID_PRINTF_LOG");
474
475 if (logFormat != NULL) {
476 err = setLogFormat(logFormat);
477
478 if (err < 0) {
479 fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
480 logFormat);
481 }
482 }
483 }
484
485 if (forceFilters) {
486 err = android_log_addFilterString(g_logformat, forceFilters);
487 if (err < 0) {
488 fprintf (stderr, "Invalid filter expression in -logcat option\n");
489 exit(0);
490 }
491 } else if (argc == optind) {
492 // Add from environment variable
493 char *env_tags_orig = getenv("ANDROID_LOG_TAGS");
494
495 if (env_tags_orig != NULL) {
496 err = android_log_addFilterString(g_logformat, env_tags_orig);
497
498 if (err < 0) {
499 fprintf(stderr, "Invalid filter expression in"
500 " ANDROID_LOG_TAGS\n");
501 android::show_help(argv[0]);
502 exit(-1);
503 }
504 }
505 } else {
506 // Add from commandline
507 for (int i = optind ; i < argc ; i++) {
508 err = android_log_addFilterString(g_logformat, argv[i]);
509
510 if (err < 0) {
511 fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
512 android::show_help(argv[0]);
513 exit(-1);
514 }
515 }
516 }
517
518 logfd = open(log_device, mode);
519 if (logfd < 0) {
520 fprintf(stderr, "Unable to open log device '%s': %s\n",
521 log_device, strerror(errno));
522 exit(EXIT_FAILURE);
523 }
524
525 if (clearLog) {
526 int ret;
527 ret = android::clearLog(logfd);
528 if (ret) {
529 perror("ioctl");
530 exit(EXIT_FAILURE);
531 }
532 return 0;
533 }
534
535 if (getLogSize) {
536 int size, readable;
537
538 size = android::getLogSize(logfd);
539 if (size < 0) {
540 perror("ioctl");
541 exit(EXIT_FAILURE);
542 }
543
544 readable = android::getLogReadableSize(logfd);
545 if (readable < 0) {
546 perror("ioctl");
547 exit(EXIT_FAILURE);
548 }
549
550 printf("ring buffer is %dKb (%dKb consumed), "
551 "max entry is %db, max payload is %db\n",
552 size / 1024, readable / 1024,
553 (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
554 return 0;
555 }
556
557 //LOG_EVENT_INT(10, 12345);
558 //LOG_EVENT_LONG(11, 0x1122334455667788LL);
559 //LOG_EVENT_STRING(0, "whassup, doc?");
560
561 if (android::g_isBinary)
562 android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
563
564 android::readLogLines(logfd);
565
566 return 0;
567 }
+0
-7
logwrapper/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1
2 include $(CLEAR_VARS)
3 LOCAL_SRC_FILES:= logwrapper.c
4 LOCAL_MODULE := logwrapper
5 LOCAL_STATIC_LIBRARIES := liblog
6 include $(BUILD_EXECUTABLE)
+0
-181
logwrapper/logwrapper.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <fcntl.h>
24
25 #include "private/android_filesystem_config.h"
26 #include "cutils/log.h"
27
28 void fatal(const char *msg) {
29 fprintf(stderr, msg);
30 LOG(LOG_ERROR, "logwrapper", msg);
31 exit(-1);
32 }
33
34 void usage() {
35 fatal(
36 "Usage: logwrapper [-x] BINARY [ARGS ...]\n"
37 "\n"
38 "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
39 "the Android logging system. Tag is set to BINARY, priority is\n"
40 "always LOG_INFO.\n"
41 "\n"
42 "-x: Causes logwrapper to SIGSEGV when BINARY terminates\n"
43 " fault address is set to the status of wait()\n");
44 }
45
46 void parent(const char *tag, int seg_fault_on_exit, int parent_read) {
47 int status;
48 char buffer[4096];
49
50 int a = 0; // start index of unprocessed data
51 int b = 0; // end index of unprocessed data
52 int sz;
53 while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
54
55 sz += b;
56 // Log one line at a time
57 for (b = 0; b < sz; b++) {
58 if (buffer[b] == '\r') {
59 buffer[b] = '\0';
60 } else if (buffer[b] == '\n') {
61 buffer[b] = '\0';
62 LOG(LOG_INFO, tag, &buffer[a]);
63 a = b + 1;
64 }
65 }
66
67 if (a == 0 && b == sizeof(buffer) - 1) {
68 // buffer is full, flush
69 buffer[b] = '\0';
70 LOG(LOG_INFO, tag, &buffer[a]);
71 b = 0;
72 } else if (a != b) {
73 // Keep left-overs
74 b -= a;
75 memmove(buffer, &buffer[a], b);
76 a = 0;
77 } else {
78 a = 0;
79 b = 0;
80 }
81
82 }
83 // Flush remaining data
84 if (a != b) {
85 buffer[b] = '\0';
86 LOG(LOG_INFO, tag, &buffer[a]);
87 }
88 status = 0xAAAA;
89 if (wait(&status) != -1) { // Wait for child
90 if (WIFEXITED(status))
91 LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
92 WEXITSTATUS(status));
93 else if (WIFSIGNALED(status))
94 LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
95 WTERMSIG(status));
96 else if (WIFSTOPPED(status))
97 LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
98 WSTOPSIG(status));
99 } else
100 LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
101 strerror(errno), errno);
102 if (seg_fault_on_exit)
103 *(int *)status = 0; // causes SIGSEGV with fault_address = status
104 }
105
106 void child(int argc, char* argv[]) {
107 // create null terminated argv_child array
108 char* argv_child[argc + 1];
109 memcpy(argv_child, argv, argc * sizeof(char *));
110 argv_child[argc] = NULL;
111
112 if (execvp(argv_child[0], argv_child)) {
113 LOG(LOG_ERROR, "logwrapper",
114 "executing %s failed: %s\n", argv_child[0], strerror(errno));
115 exit(-1);
116 }
117 }
118
119 int main(int argc, char* argv[]) {
120 pid_t pid;
121 int seg_fault_on_exit = 0;
122
123 int parent_ptty;
124 int child_ptty;
125 char *child_devname = NULL;
126
127 if (argc < 2) {
128 usage();
129 }
130
131 if (strncmp(argv[1], "-d", 2) == 0) {
132 seg_fault_on_exit = 1;
133 argc--;
134 argv++;
135 }
136
137 if (argc < 2) {
138 usage();
139 }
140
141 /* Use ptty instead of socketpair so that STDOUT is not buffered */
142 parent_ptty = open("/dev/ptmx", O_RDWR);
143 if (parent_ptty < 0) {
144 fatal("Cannot create parent ptty\n");
145 }
146
147 if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
148 ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
149 fatal("Problem with /dev/ptmx\n");
150 }
151
152 pid = fork();
153 if (pid < 0) {
154 fatal("Failed to fork\n");
155 } else if (pid == 0) {
156 child_ptty = open(child_devname, O_RDWR);
157 if (child_ptty < 0) {
158 fatal("Problem with child ptty\n");
159 }
160
161 // redirect stdout and stderr
162 close(parent_ptty);
163 dup2(child_ptty, 1);
164 dup2(child_ptty, 2);
165 close(child_ptty);
166
167 child(argc - 1, &argv[1]);
168
169 } else {
170 // switch user and group to "log"
171 // this may fail if we are not root,
172 // but in that case switching user/group is unnecessary
173 setgid(AID_LOG);
174 setuid(AID_LOG);
175
176 parent(argv[1], seg_fault_on_exit, parent_ptty);
177 }
178
179 return 0;
180 }
+0
-12
mkbootimg/Android.mk less more
0
1 LOCAL_PATH:= $(call my-dir)
2 include $(CLEAR_VARS)
3
4 LOCAL_SRC_FILES := mkbootimg.c
5 LOCAL_STATIC_LIBRARIES := libmincrypt
6
7 LOCAL_MODULE := mkbootimg
8
9 include $(BUILD_HOST_EXECUTABLE)
10
11 $(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+0
-97
mkbootimg/bootimg.h less more
0 /* tools/mkbootimg/bootimg.h
1 **
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #ifndef _BOOT_IMAGE_H_
18 #define _BOOT_IMAGE_H_
19
20 typedef struct boot_img_hdr boot_img_hdr;
21
22 #define BOOT_MAGIC "ANDROID!"
23 #define BOOT_MAGIC_SIZE 8
24 #define BOOT_NAME_SIZE 16
25 #define BOOT_ARGS_SIZE 512
26
27 struct boot_img_hdr
28 {
29 unsigned char magic[BOOT_MAGIC_SIZE];
30
31 unsigned kernel_size; /* size in bytes */
32 unsigned kernel_addr; /* physical load addr */
33
34 unsigned ramdisk_size; /* size in bytes */
35 unsigned ramdisk_addr; /* physical load addr */
36
37 unsigned second_size; /* size in bytes */
38 unsigned second_addr; /* physical load addr */
39
40 unsigned tags_addr; /* physical addr for kernel tags */
41 unsigned page_size; /* flash page size we assume */
42 unsigned unused[2]; /* future expansion: should be 0 */
43
44 unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
45
46 unsigned char cmdline[BOOT_ARGS_SIZE];
47
48 unsigned id[8]; /* timestamp / checksum / sha1 / etc */
49 };
50
51 /*
52 ** +-----------------+
53 ** | boot header | 1 page
54 ** +-----------------+
55 ** | kernel | n pages
56 ** +-----------------+
57 ** | ramdisk | m pages
58 ** +-----------------+
59 ** | second stage | o pages
60 ** +-----------------+
61 **
62 ** n = (kernel_size + page_size - 1) / page_size
63 ** m = (ramdisk_size + page_size - 1) / page_size
64 ** o = (second_size + page_size - 1) / page_size
65 **
66 ** 0. all entities are page_size aligned in flash
67 ** 1. kernel and ramdisk are required (size != 0)
68 ** 2. second is optional (second_size == 0 -> no second)
69 ** 3. load each element (kernel, ramdisk, second) at
70 ** the specified physical address (kernel_addr, etc)
71 ** 4. prepare tags at tag_addr. kernel_args[] is
72 ** appended to the kernel commandline in the tags.
73 ** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
74 ** 6. if second_size != 0: jump to second_addr
75 ** else: jump to kernel_addr
76 */
77
78 #if 0
79 typedef struct ptentry ptentry;
80
81 struct ptentry {
82 char name[16]; /* asciiz partition name */
83 unsigned start; /* starting block number */
84 unsigned length; /* length in blocks */
85 unsigned flags; /* set to zero */
86 };
87
88 /* MSM Partition Table ATAG
89 **
90 ** length: 2 + 7 * n
91 ** atag: 0x4d534d70
92 ** <ptentry> x n
93 */
94 #endif
95
96 #endif
+0
-251
mkbootimg/mkbootimg.c less more
0 /* tools/mkbootimg/mkbootimg.c
1 **
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23
24 #include "mincrypt/sha.h"
25 #include "bootimg.h"
26
27 static void *load_file(const char *fn, unsigned *_sz)
28 {
29 char *data;
30 int sz;
31 int fd;
32
33 data = 0;
34 fd = open(fn, O_RDONLY);
35 if(fd < 0) return 0;
36
37 sz = lseek(fd, 0, SEEK_END);
38 if(sz < 0) goto oops;
39
40 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
41
42 data = (char*) malloc(sz);
43 if(data == 0) goto oops;
44
45 if(read(fd, data, sz) != sz) goto oops;
46 close(fd);
47
48 if(_sz) *_sz = sz;
49 return data;
50
51 oops:
52 close(fd);
53 if(data != 0) free(data);
54 return 0;
55 }
56
57 int usage(void)
58 {
59 fprintf(stderr,"usage: mkbootimg\n"
60 " --kernel <filename>\n"
61 " --ramdisk <filename>\n"
62 " [ --second <2ndbootloader-filename> ]\n"
63 " [ --cmdline <kernel-commandline> ]\n"
64 " [ --board <boardname> ]\n"
65 " -o|--output <filename>\n"
66 );
67 return 1;
68 }
69
70
71
72 static unsigned char padding[2048] = { 0, };
73
74 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
75 {
76 unsigned pagemask = pagesize - 1;
77 unsigned count;
78
79 if((itemsize & pagemask) == 0) {
80 return 0;
81 }
82
83 count = pagesize - (itemsize & pagemask);
84
85 if(write(fd, padding, count) != count) {
86 return -1;
87 } else {
88 return 0;
89 }
90 }
91
92 int main(int argc, char **argv)
93 {
94 boot_img_hdr hdr;
95
96 char *kernel_fn = 0;
97 void *kernel_data = 0;
98 char *ramdisk_fn = 0;
99 void *ramdisk_data = 0;
100 char *second_fn = 0;
101 void *second_data = 0;
102 char *cmdline = "";
103 char *bootimg = 0;
104 char *board = "";
105 unsigned pagesize = 2048;
106 unsigned saddr = 0;
107 int fd;
108 SHA_CTX ctx;
109 uint8_t* sha;
110
111 argc--;
112 argv++;
113
114 memset(&hdr, 0, sizeof(hdr));
115
116 while(argc > 0){
117 char *arg = argv[0];
118 char *val = argv[1];
119 if(argc < 2) {
120 return usage();
121 }
122 argc -= 2;
123 argv += 2;
124 if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
125 bootimg = val;
126 } else if(!strcmp(arg, "--kernel")) {
127 kernel_fn = val;
128 } else if(!strcmp(arg, "--ramdisk")) {
129 ramdisk_fn = val;
130 } else if(!strcmp(arg, "--second")) {
131 second_fn = val;
132 } else if(!strcmp(arg, "--cmdline")) {
133 cmdline = val;
134 } else if(!strcmp(arg, "--saddr")) {
135 saddr = strtoul(val, 0, 16);
136 } else if(!strcmp(arg, "--board")) {
137 board = val;
138 } else {
139 return usage();
140 }
141 }
142
143 if(bootimg == 0) {
144 fprintf(stderr,"error: no output filename specified\n");
145 return usage();
146 }
147
148 if(kernel_fn == 0) {
149 fprintf(stderr,"error: no kernel image specified\n");
150 return usage();
151 }
152
153 if(ramdisk_fn == 0) {
154 fprintf(stderr,"error: no ramdisk image specified\n");
155 return usage();
156 }
157
158 if(strlen(board) >= BOOT_NAME_SIZE) {
159 fprintf(stderr,"error: board name too large\n");
160 return usage();
161 }
162
163 strcpy(hdr.name, board);
164
165 hdr.kernel_addr = 0x10008000;
166 hdr.ramdisk_addr = 0x11000000;
167 if(saddr) {
168 hdr.second_addr = 0x00300000;
169 } else {
170 hdr.second_addr = 0x10F00000;
171 }
172 hdr.tags_addr = 0x10000100;
173 hdr.page_size = pagesize;
174
175 memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
176
177 if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
178 fprintf(stderr,"error: kernel commandline too large\n");
179 return 1;
180 }
181 strcpy((char*)hdr.cmdline, cmdline);
182
183 kernel_data = load_file(kernel_fn, &hdr.kernel_size);
184 if(kernel_data == 0) {
185 fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
186 return 1;
187 }
188
189 if(!strcmp(ramdisk_fn,"NONE")) {
190 ramdisk_data = 0;
191 hdr.ramdisk_size = 0;
192 } else {
193 ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
194 if(ramdisk_data == 0) {
195 fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
196 return 1;
197 }
198 }
199
200 if(second_fn) {
201 second_data = load_file(second_fn, &hdr.second_size);
202 if(second_data == 0) {
203 fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
204 return 1;
205 }
206 }
207
208 /* put a hash of the contents in the header so boot images can be
209 * differentiated based on their first 2k.
210 */
211 SHA_init(&ctx);
212 SHA_update(&ctx, kernel_data, hdr.kernel_size);
213 SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
214 SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
215 SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
216 SHA_update(&ctx, second_data, hdr.second_size);
217 SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
218 sha = SHA_final(&ctx);
219 memcpy(hdr.id, sha,
220 SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
221
222 fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
223 if(fd < 0) {
224 fprintf(stderr,"error: could not create '%s'\n", bootimg);
225 return 1;
226 }
227
228 if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
229 if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
230
231 if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
232 if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
233
234 if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
235 if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
236
237 if(second_data) {
238 if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
239 if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
240 }
241
242 return 0;
243
244 fail:
245 unlink(bootimg);
246 close(fd);
247 fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
248 strerror(errno));
249 return 1;
250 }
+0
-774
mountd/ASEC.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 ** Android Secure External Cache
18 */
19
20 #include "mountd.h"
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <ctype.h>
28 #include <pwd.h>
29 #include <stdlib.h>
30 #include <poll.h>
31 #include <errno.h>
32
33 #include <sys/ioctl.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
36
37 #include <linux/dm-ioctl.h>
38 #include <linux/loop.h>
39
40 #include <cutils/properties.h>
41 #include <cutils/misc.h>
42
43 #include "ASEC.h"
44
45 //#define MODULE_FAILURE_IS_FATAL
46
47 extern int init_module(void *, unsigned long, const char *);
48 extern int delete_module(const char *, unsigned int);
49
50 struct asec_context
51 {
52 char *name; // Device mapper volume name
53 char *srcPath; // Path to the source (original) mount
54 char *backingFile; // Name of the image file
55 unsigned int sectors; // Number of sectors
56 char *dstPath; // Destination mount point
57 char *crypt; // Crypt options
58
59 boolean needs_format;
60 boolean started;
61 int cacheFd;
62 int lo_num;
63 int dm_num;
64 unsigned char key[16];
65 };
66
67 static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher",
68 "cryptomgr", "dm_crypt", "jbd",
69 "twofish_common", "twofish", "cbc",
70 "mbcache", "ext3",
71 NULL };
72 static const char KEY_PATH[] = "/data/system/asec.key";
73 static const char MODULE_PATH[] = "/system/lib/modules";
74 static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
75 static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
76
77 boolean AsecIsStarted(void *Handle)
78 {
79 struct asec_context *ctx = (struct asec_context *) Handle;
80
81 return ctx->started;
82 }
83
84 const char *AsecMountPoint(void *Handle)
85 {
86 struct asec_context *ctx = (struct asec_context *) Handle;
87
88 return ctx->dstPath;
89 }
90
91 static boolean AsecIsEnabled()
92 {
93 char value[PROPERTY_VALUE_MAX];
94 int enabled;
95
96 property_get(ASEC_ENABLED, value, "0");
97
98 if (atoi(value) == 1)
99 return true;
100 return false;
101 }
102
103 void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
104 const char *Size, const char *DstPath, const char *Crypt)
105 {
106 struct asec_context *ctx;
107
108 if (!AsecIsEnabled())
109 return NULL;
110
111 LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
112 Name, SrcPath, BackingFile, Size, DstPath, Crypt);
113
114 if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
115 LOG_ERROR("AsecInit(): Invalid arguments\n");
116 return NULL;
117 }
118
119 if (!(ctx = malloc(sizeof(struct asec_context)))) {
120 LOG_ERROR("AsecInit(): Out of memory\n");
121 return NULL;
122 }
123
124 memset(ctx, 0, sizeof(struct asec_context));
125 ctx->name = strdup(Name);
126 ctx->srcPath = strdup(SrcPath);
127 ctx->backingFile = strdup(BackingFile);
128 ctx->sectors = atoi(Size);
129 ctx->dstPath = strdup(DstPath);
130 ctx->crypt = strdup(Crypt);
131 return ctx;
132 }
133
134 void AsecDeinit(void *Handle)
135 {
136 struct asec_context *ctx = (struct asec_context *) Handle;
137
138 free(ctx->name);
139 free(ctx->srcPath);
140 free(ctx->backingFile);
141 free(ctx->dstPath);
142 free(ctx->crypt);
143
144 free(ctx);
145 }
146
147 static int AsecLoadModules()
148 {
149 int i;
150
151 for (i = 0; MODULES[i] != NULL; i++) {
152 const char *moduleName = MODULES[i];
153 char moduleFile[255];
154 int rc = 0;
155 void *module;
156 unsigned int size;
157
158 sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
159 module = load_file(moduleFile, &size);
160 if (!module) {
161 LOG_ERROR("Failed to load module %s (%d)\n", moduleFile, errno);
162 return -1;
163 }
164
165 rc = init_module(module, size, "");
166 free(module);
167 if (rc && errno != EEXIST) {
168 LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
169 return -errno;
170 }
171 }
172 return 0;
173 }
174
175 static int AsecUnloadModules()
176 {
177 int i, j, rc;
178
179 for (i = 0; MODULES[i] != NULL; i++);
180
181 for (j = (i - 1); j >= 0; j--) {
182 const char *moduleName = MODULES[j];
183 int maxretry = 10;
184 while(maxretry-- > 0) {
185 rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
186 if (rc < 0 && errno == EAGAIN)
187 usleep(500000);
188 else
189 break;
190 }
191 if (rc != 0) {
192 LOG_ERROR("Failed to unload module %s\n", moduleName);
193 return -errno;
194 }
195 }
196 return 0;
197 }
198
199 static int AsecGenerateKey(struct asec_context *ctx)
200 {
201 LOG_ASEC("AsecGenerateKey():\n");
202
203 memset((void *) ctx->key, 0x69, sizeof(ctx->key));
204 return 0;
205 }
206
207 static int AsecLoadGenerateKey(struct asec_context *ctx)
208 {
209 int fd;
210 int rc = 0;
211
212 if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
213 LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
214 return -errno;
215 }
216
217 if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
218 LOG_ASEC("Generating key\n");
219 if ((rc = AsecGenerateKey(ctx)) < 0) {
220 LOG_ERROR("Error generating key (%d)\n", rc);
221 goto out;
222 }
223 if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
224 LOG_ERROR("Error writing keyfile (%d)\n", errno);
225 rc = -1;
226 goto out;
227 }
228 }
229
230 out:
231 close (fd);
232 return rc;
233 }
234
235 static int AsecFormatFilesystem(struct asec_context *ctx)
236 {
237 char cmdline[255];
238 int rc;
239
240 sprintf(cmdline,
241 "%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
242 MKE2FS_PATH, ctx->name, ctx->dm_num);
243
244 LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
245 // XXX: PROTECT FROM VIKING KILLER
246 if ((rc = system(cmdline)) < 0) {
247 LOG_ERROR("Error executing format command (%d)\n", errno);
248 return -errno;
249 }
250
251 rc = WEXITSTATUS(rc);
252
253 if (!rc) {
254 LOG_ASEC("Format completed\n");
255 } else {
256 LOG_ASEC("Format failed (%d)\n", rc);
257 }
258
259 return rc;
260 }
261
262 static int AsecCheckFilesystem(struct asec_context *ctx)
263 {
264 char cmdline[255];
265 int rc;
266
267 sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
268
269 LOG_ASEC("Checking filesystem (%s)\n", cmdline);
270 // XXX: PROTECT FROM VIKING KILLER
271 if ((rc = system(cmdline)) < 0) {
272 LOG_ERROR("Error executing check command (%d)\n", errno);
273 return -errno;
274 }
275
276 rc = WEXITSTATUS(rc);
277
278 if (rc == 0) {
279 LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
280 } else if (rc == 1) {
281 LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
282 rc = 0;
283 } else if (rc == 2) {
284 LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
285 } else if (rc == 4) {
286 LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
287 } else if (rc == 8) {
288 LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
289 } else {
290 LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
291 }
292 return rc;
293 }
294
295 static int AsecOpenCreateCache(struct asec_context *ctx)
296 {
297 char filepath[255];
298
299 sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
300
301 if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
302 if (errno == ENOENT) {
303 int rc = 0;
304
305 LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
306 if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
307 LOG_ERROR("Error creating cache (%d)\n", errno);
308 return -errno;
309 }
310 if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
311 LOG_ERROR("Error truncating cache (%d)\n", errno);
312 close(ctx->cacheFd);
313 unlink(filepath);
314 return -errno;
315 }
316 LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
317 close(ctx->cacheFd); // creat() is WRONLY
318
319 if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
320 LOG_ERROR("Error opening cache file (%d)\n", errno);
321 close(ctx->cacheFd);
322 unlink(filepath);
323 return -errno;
324 }
325
326 ctx->needs_format = 1;
327 } else
328 return -errno;
329 } else {
330 struct stat stat_buf;
331
332 if (fstat(ctx->cacheFd, &stat_buf) < 0) {
333 LOG_ERROR("Failed to fstat cache (%d)\n", errno);
334 close(ctx->cacheFd);
335 return -errno;
336 }
337 if (stat_buf.st_size != ctx->sectors * 512) {
338 LOG_ERROR("Cache size %lld != configured size %u\n",
339 stat_buf.st_size, ctx->sectors * 512);
340 }
341
342 // XXX: Verify volume label matches ctx->name
343 }
344
345 return 0;
346 }
347
348 static void AsecCloseCache(struct asec_context *ctx)
349 {
350 close(ctx->cacheFd);
351 }
352
353 static void *_align(void *ptr, unsigned int a)
354 {
355 register unsigned long agn = --a;
356
357 return (void *) (((unsigned long) ptr + agn) & ~agn);
358 }
359
360 static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
361 {
362 void *buffer;
363 void *p;
364 const size_t min_size = 16 * 1024;
365 size_t len = sizeof(struct dm_ioctl);
366 struct dm_ioctl *io;
367 struct dm_target_spec *tgt;
368 int i;
369 char params[1024];
370 char key[80];
371
372 key[0] = '\0';
373
374 for (i = 0; i < (int) sizeof(ctx->key); i++) {
375 char tmp[8];
376
377 sprintf(tmp, "%02x", ctx->key[i]);
378 strcat(key, tmp);
379 }
380
381 // XXX: Handle ctx->crypt
382 sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
383
384 if (len < min_size)
385 len = min_size;
386
387 if (!(buffer = malloc(len))) {
388 LOG_ERROR("Unable to allocate memory\n");
389 return NULL;
390 }
391
392 memset(buffer, 0, len);
393 io = buffer;
394 tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
395
396 io->version[0] = 4;
397 io->version[1] = 0;
398 io->version[2] = 0;
399
400 io->data_size = len;
401 io->data_start = sizeof(struct dm_ioctl);
402
403 io->flags = flags;
404 io->dev = 0;
405
406 io->target_count = 1;
407 io->event_nr = 1;
408 strncpy(io->name, ctx->name, sizeof(io->name));
409
410 tgt->status = 0;
411 tgt->sector_start = 0;
412 tgt->length = ctx->sectors;
413 strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
414
415 p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
416 strcpy((char *) p, params);
417 p+= strlen(params) + 1;
418
419 p = _align(p, 8);
420 tgt->next = p - buffer;
421
422 return io;
423 }
424
425 static int FindNextAvailableDm()
426 {
427 int i;
428
429 for (i = 0; i < 8; i++) {
430 char path[255];
431 sprintf(path, "/dev/block/dm-%d", i);
432 if ((access(path, F_OK) < 0) && (errno == ENOENT))
433 return i;
434 }
435
436 LOG_ERROR("Out of device mapper numbers\n");
437 return -1;
438 }
439
440 static int AsecCreateDeviceMapping(struct asec_context *ctx)
441 {
442 struct dm_ioctl *io;
443 int dmFd;
444 int rc = 0;
445
446 ctx->dm_num = FindNextAvailableDm();
447
448 if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
449 LOG_ERROR("Error opening device mapper (%d)\n", errno);
450 return -errno;
451 }
452
453 if (!(io = _dm_ioctl_setup(ctx, 0))) {
454 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
455 close(dmFd);
456 return -ENOMEM;
457 }
458
459 if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
460 LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
461 rc = -errno;
462 goto out_free;
463 }
464
465 free(io);
466
467 if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
468 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
469 rc = -ENOMEM;
470 goto out_nofree;
471 }
472
473 if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
474 LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
475 rc = -errno;
476 goto out_free;
477 }
478
479 free(io);
480
481 if (!(io = _dm_ioctl_setup(ctx, 0))) {
482 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
483 rc = -ENOMEM;
484 goto out_nofree;
485 }
486
487 if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
488 LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
489 rc = -errno;
490 goto out_free;
491 }
492
493 out_free:
494 free (io);
495 out_nofree:
496 close (dmFd);
497 return rc;
498 }
499
500 static int AsecDestroyDeviceMapping(struct asec_context *ctx)
501 {
502 struct dm_ioctl *io;
503 int dmFd;
504 int rc = 0;
505
506 if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
507 LOG_ERROR("Error opening device mapper (%d)\n", errno);
508 return -errno;
509 }
510
511 if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
512 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
513 rc = -ENOMEM;
514 goto out_nofree;
515 }
516
517 if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
518 LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
519 rc = -errno;
520 goto out_free;
521 }
522
523 out_free:
524 free (io);
525 out_nofree:
526 close (dmFd);
527 return rc;
528 }
529
530 static int AsecMountCache(struct asec_context *ctx)
531 {
532 int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
533 char devname[255];
534
535 if (access(ctx->dstPath, R_OK)) {
536 LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
537 return -errno;
538 }
539
540 sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
541
542 if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
543 LOG_ERROR("ASEC mount failed (%d)\n", errno);
544 return -errno;
545 }
546
547 return 0;
548 }
549
550 static int AsecUnmountCache(struct asec_context *ctx)
551 {
552 if (umount(ctx->dstPath)) {
553 if (errno == EBUSY) {
554 LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
555 } else {
556 LOG_ERROR("ASEC umount failed (%d)\n", errno);
557 }
558 return -errno;
559 }
560 LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
561 return 0;
562 }
563
564 static int FindNextAvailableLoop()
565 {
566 int i;
567
568 for (i = 0; i < MAX_LOOP; i++) {
569 struct loop_info info;
570 char devname[255];
571 int fd;
572
573 sprintf(devname, "/dev/block/loop%d", i);
574
575 if ((fd = open(devname, O_RDONLY)) < 0) {
576 LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
577 return -errno;
578 }
579
580 if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
581 close(fd);
582
583 if (errno == ENXIO)
584 return i;
585
586 LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
587 return -errno;
588 }
589 close(fd);
590 }
591 return -ENXIO;
592 }
593
594 static int AsecCreateLoop(struct asec_context *ctx)
595 {
596 char devname[255];
597 int device_fd;
598 int rc = 0;
599
600 ctx->lo_num = FindNextAvailableLoop();
601 if (ctx->lo_num < 0) {
602 LOG_ERROR("No loop devices available\n");
603 return -ENXIO;
604 }
605
606 sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
607 device_fd = open(devname, O_RDWR);
608 if (device_fd < 0) {
609 LOG_ERROR("failed to open loop device (%d)\n", errno);
610 return -errno;
611 }
612
613 if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
614 LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
615 rc = -errno;
616 }
617 close(device_fd);
618 return rc;
619 }
620
621 static int AsecDestroyLoop(struct asec_context *ctx)
622 {
623 char devname[255];
624 int device_fd;
625 int rc = 0;
626
627 sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
628 device_fd = open(devname, O_RDONLY);
629 if (device_fd < 0) {
630 LOG_ERROR("Failed to open loop (%d)\n", errno);
631 return -errno;
632 }
633
634 if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
635 LOG_ERROR("Failed to destroy loop (%d)\n", errno);
636 rc = -errno;
637 }
638
639 close(device_fd);
640 return rc;
641 }
642
643 int AsecStart(void *Handle)
644 {
645 struct asec_context *ctx = (struct asec_context *) Handle;
646 char value[PROPERTY_VALUE_MAX];
647 int rc = 0;
648
649 if (!ctx)
650 return -EINVAL;
651
652 if (ctx->started)
653 return -EBUSY;
654
655 LOG_ASEC("AsecStart(%s):\n", ctx->name);
656
657 NotifyAsecState(ASEC_BUSY, ctx->dstPath);
658
659 if ((rc = AsecLoadModules()) < 0) {
660 LOG_ERROR("AsecStart: Failed to load kernel modules\n");
661 #ifdef MODULE_FAILURE_IS_FATAL
662 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
663 return rc;
664 #endif
665 }
666
667 if ((rc = AsecLoadGenerateKey(ctx))) {
668 LOG_ERROR("AsecStart: Failed to load / generate key\n");
669 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
670 return rc;
671 }
672
673 if ((rc = AsecOpenCreateCache(ctx)) < 0) {
674 LOG_ERROR("AsecStart: Failed to open / create cache\n");
675 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
676 return rc;
677 }
678
679 if ((rc = AsecCreateLoop(ctx)) < 0) {
680 LOG_ERROR("AsecStart: Failed to create loop\n");
681 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
682 goto fail_closecache;
683 }
684
685 if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
686 LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
687 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
688 goto fail_destroyloop;
689 }
690
691 if (ctx->needs_format) {
692 if ((rc = AsecFormatFilesystem(ctx))) {
693 LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
694 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
695 goto fail_destroydm;
696 }
697 ctx->needs_format = 0;
698 } else {
699 if ((rc = AsecCheckFilesystem(ctx))) {
700 LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
701 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
702 goto fail_destroydm;
703 }
704 }
705
706 if ((rc = AsecMountCache(ctx)) < 0) {
707 LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
708 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
709 goto fail_destroydm;
710 }
711
712 NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
713 ctx->started = true;
714
715 return rc;
716
717 fail_destroydm:
718 AsecDestroyDeviceMapping(ctx);
719 fail_destroyloop:
720 AsecDestroyLoop(ctx);
721 fail_closecache:
722 AsecCloseCache(ctx);
723 return rc;
724 }
725
726 int AsecStop(void *Handle)
727 {
728 struct asec_context *ctx = (struct asec_context *) Handle;
729 int rc = 0;
730
731 if (!ctx->started)
732 return -EINVAL;
733
734 LOG_ASEC("AsecStop(%s):\n", ctx->name);
735
736 NotifyAsecState(ASEC_BUSY, ctx->dstPath);
737
738 if ((rc = AsecUnmountCache(ctx)) < 0) {
739 LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
740 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
741 return rc;
742 }
743
744 if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
745 LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
746 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
747 return rc;
748 }
749
750 if ((rc = AsecDestroyLoop(ctx)) < 0) {
751 LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
752 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
753 return rc;
754 }
755
756 AsecCloseCache(ctx);
757
758 if ((rc = AsecUnloadModules()) < 0) {
759 if (rc == -EAGAIN) {
760 LOG_ASEC("AsecStop: Kernel modules still in use\n");
761 } else {
762 LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
763 #ifdef MODULE_FAILURE_IS_FATAL
764 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
765 return rc;
766 #endif
767 }
768 }
769
770 ctx->started = false;
771 NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
772 return rc;
773 }
+0
-66
mountd/ASEC.h less more
0 #ifndef _ASEC_H
1 #define _ASEC_H
2
3 #define ASEC_STORES_MAX 4
4 #define MAX_LOOP 8
5
6 typedef enum AsecState {
7 // Feature disabled
8 ASEC_DISABLED,
9
10 // Feature enabled and operational
11 ASEC_AVAILABLE,
12
13 // Busy
14 ASEC_BUSY,
15
16 // Internal Error
17 ASEC_FAILED_INTERR,
18
19 // No media available
20 ASEC_FAILED_NOMEDIA,
21
22 // Media is corrupt
23 ASEC_FAILED_BADMEDIA,
24
25 // Key mismatch
26 ASEC_FAILED_BADKEY,
27 } AsecState;
28
29 /*
30 * ASEC commands
31 */
32 #define ASEC_CMD_SEND_STATUS "asec_send_status"
33 #define ASEC_CMD_ENABLE "asec_enable"
34 #define ASEC_CMD_DISABLE "asec_disable"
35
36 /*
37 * ASEC events
38 */
39
40 // These events correspond to the states in the AsecState enum.
41 // A path to the ASEC mount point follows the colon
42 #define ASEC_EVENT_DISABLED "asec_disabled:"
43 #define ASEC_EVENT_AVAILABLE "asec_available:"
44 #define ASEC_EVENT_BUSY "asec_busy:"
45 #define ASEC_EVENT_FAILED_INTERR "asec_failed_interror:"
46 #define ASEC_EVENT_FAILED_NOMEDIA "asec_failed_nomedia"
47 #define ASEC_EVENT_FAILED_BADMEDIA "asec_failed_badmedia:"
48 #define ASEC_EVENT_FAILED_BADKEY "asec_failed_badkey:"
49
50 /*
51 * System Properties
52 */
53
54 #define ASEC_ENABLED "asec.enabled"
55
56 #define ASEC_STATUS "ro.asec.status"
57 #define ASEC_STATUS_DISABLED "disabled"
58 #define ASEC_STATUS_AVAILABLE "available"
59 #define ASEC_STATUS_BUSY "busy"
60 #define ASEC_STATUS_FAILED_INTERR "internal_error"
61 #define ASEC_STATUS_FAILED_NOMEDIA "no_media"
62 #define ASEC_STATUS_FAILED_BADMEDIA "bad_media"
63 #define ASEC_STATUS_FAILED_BADKEY "bad_key"
64
65 #endif
+0
-22
mountd/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1
2 include $(CLEAR_VARS)
3
4 LOCAL_SRC_FILES:= \
5 AutoMount.c \
6 ProcessKiller.c \
7 Server.c \
8 mountd.c \
9 ASEC.c \
10 logwrapper.c
11
12 LOCAL_MODULE:= mountd
13
14 LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
15
16 LOCAL_CFLAGS := -DCREATE_MOUNT_POINTS=0
17
18 LOCAL_SHARED_LIBRARIES := libcutils
19
20 # disabled - we are using vold now instead
21 # include $(BUILD_EXECUTABLE)
+0
-1062
mountd/AutoMount.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 ** mountd automount support
18 */
19
20 #include "mountd.h"
21
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <ctype.h>
29 #include <pwd.h>
30 #include <stdlib.h>
31 #include <poll.h>
32
33 #include <sys/mount.h>
34 #include <sys/stat.h>
35 #include <linux/loop.h>
36 #include <sys/inotify.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include <linux/netlink.h>
40
41 #define DEVPATH "/dev/block/"
42 #define DEVPATHLENGTH 11 // strlen(DEVPATH)
43
44 // FIXME - only one loop mount is supported at a time
45 #define LOOP_DEVICE "/dev/block/loop0"
46
47 // timeout value for poll() when retries are pending
48 #define POLL_TIMEOUT 1000
49
50 #define MAX_MOUNT_RETRIES 3
51 #define MAX_UNMOUNT_RETRIES 5
52
53 typedef enum {
54 // device is unmounted
55 kUnmounted,
56
57 // attempting to mount device
58 kMounting,
59
60 // device is unmounted
61 kMounted,
62
63 // attempting to unmount device
64 // so the media can be removed
65 kUnmountingForEject,
66
67 // attempting to mount device
68 // so it can be shared via USB mass storage
69 kUnmountingForUms,
70 } MountState;
71
72 typedef struct MountPoint {
73 // block device to mount
74 const char* device;
75
76 // mount point for device
77 const char* mountPoint;
78
79 // path to the UMS driver file for specifying the block device path
80 const char* driverStorePath;
81
82 // true if device can be shared via
83 // USB mass storage
84 boolean enableUms;
85
86 // Array of ASEC handles
87 void *asecHandles[ASEC_STORES_MAX];
88
89 // true if the device is being shared via USB mass storage
90 boolean umsActive;
91
92 // current state of the mount point
93 MountState state;
94
95 // number of mount or unmount retries so far,
96 // when attempting to mount or unmount the device
97 int retryCount;
98
99 // next in sMountPointList linked list
100 struct MountPoint* next;
101 } MountPoint;
102
103 // list of our mount points (does not change after initialization)
104 static MountPoint* sMountPointList = NULL;
105 boolean gMassStorageEnabled = false;
106 boolean gMassStorageConnected = false;
107
108 static pthread_t sAutoMountThread = 0;
109 static pid_t gExcludedPids[2] = {-1, -1};
110
111 static const char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
112
113 // number of mount points that have timeouts pending
114 static int sRetriesPending = 0;
115
116 // for synchronization between sAutoMountThread and the server thread
117 static pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
118
119 // requests the USB mass_storage driver to begin or end sharing a block device
120 // via USB mass storage.
121 static void SetBackingStore(MountPoint* mp, boolean enable)
122 {
123 int fd;
124
125 if (!mp->driverStorePath) {
126 LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
127 return;
128 }
129
130 LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
131 fd = open(mp->driverStorePath, O_WRONLY);
132 if (fd < 0)
133 {
134 LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
135 }
136 else
137 {
138 if (enable)
139 {
140 write(fd, mp->device, strlen(mp->device));
141 mp->umsActive = true;
142 }
143 else
144 {
145 char ch = 0;
146 write(fd, &ch, 1);
147 mp->umsActive = false;
148 }
149 close(fd);
150 }
151 }
152
153 static boolean ReadMassStorageState()
154 {
155 FILE* file = fopen("/sys/class/switch/usb_mass_storage/state", "r");
156 if (file)
157 {
158 char buffer[20];
159 fgets(buffer, sizeof(buffer), file);
160 fclose(file);
161 return (strncmp(buffer, "online", strlen("online")) == 0);
162 }
163 else
164 {
165 LOG_ERROR("could not read initial mass storage state\n");
166 return false;
167 }
168 }
169
170 static boolean IsLoopMounted(const char* path)
171 {
172 FILE* f;
173 int count;
174 char device[256];
175 char mount_path[256];
176 char rest[256];
177 int result = 0;
178 int path_length = strlen(path);
179
180 f = fopen("/proc/mounts", "r");
181 if (!f) {
182 LOG_ERROR("could not open /proc/mounts\n");
183 return -1;
184 }
185
186 do {
187 count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
188 if (count == 3) {
189 if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0)
190 {
191 result = 1;
192 break;
193 }
194 }
195 } while (count == 3);
196
197 fclose(f);
198 LOG_MOUNT("IsLoopMounted: %s returning %d\n", path, result);
199 return result;
200 }
201
202 static int CheckFilesystem(const char *device)
203 {
204 char cmdline[255];
205 int rc;
206
207 // XXX: SAN: Check for FAT signature
208
209 int result = access(FSCK_MSDOS_PATH, X_OK);
210 if (result != 0) {
211 LOG_MOUNT("CheckFilesystem(%s): %s not found (skipping checks)\n", FSCK_MSDOS_PATH, device);
212 return 0;
213 }
214
215 char *args[7];
216 args[0] = FSCK_MSDOS_PATH;
217 args[1] = "-v";
218 args[2] = "-V";
219 args[3] = "-w";
220 args[4] = "-p";
221 args[5] = device;
222 args[6] = NULL;
223
224 LOG_MOUNT("Checking filesystem on %s\n", device);
225 rc = logwrap(6, args);
226
227 // XXX: We need to be able to distinguish between a FS with an error
228 // and a block device which does not have a FAT fs at all on it
229 if (rc == 0) {
230 LOG_MOUNT("Filesystem check completed OK\n");
231 return 0;
232 } else if (rc == 1) {
233 LOG_MOUNT("Filesystem check failed (general failure)\n");
234 return -EINVAL;
235 } else if (rc == 2) {
236 LOG_MOUNT("Filesystem check failed (invalid usage)\n");
237 return -EIO;
238 } else {
239 LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
240 return -EIO;
241 }
242 }
243
244 static int DoMountDevice(const char* device, const char* mountPoint)
245 {
246 LOG_MOUNT("Attempting mount of %s on %s\n", device, mountPoint);
247
248 #if CREATE_MOUNT_POINTS
249 // make sure mount point exists
250 mkdir(mountPoint, 0000);
251 #endif
252
253 int flags = 0;
254
255 if (device && strncmp(device, "/dev/", 5))
256 {
257 // mount with the loop driver if device does not start with "/dev/"
258 int file_fd, device_fd;
259
260 // FIXME - only one loop mount supported at a time
261 file_fd = open(device, O_RDWR);
262 if (file_fd < -1) {
263 LOG_ERROR("open backing file %s failed\n", device);
264 return 1;
265 }
266 device_fd = open(LOOP_DEVICE, O_RDWR);
267 if (device_fd < -1) {
268 LOG_ERROR("open %s failed", LOOP_DEVICE);
269 close(file_fd);
270 return 1;
271 }
272 if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0)
273 {
274 LOG_ERROR("ioctl LOOP_SET_FD failed\n");
275 close(file_fd);
276 close(device_fd);
277 return 1;
278 }
279
280 close(file_fd);
281 close(device_fd);
282 device = "/dev/block/loop0";
283 }
284
285 int result = access(device, R_OK);
286 if (result) {
287 LOG_ERROR("Unable to access '%s' (%d)\n", device, errno);
288 return -errno;
289 }
290
291 #if 0
292 if ((result = CheckFilesystem(device))) {
293 LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
294 // XXX: Notify framework - need a new SDCARD state for the following:
295 // - SD cards which are not present
296 // - SD cards with no partition table
297 // - SD cards with no filesystem
298 // - SD cards with bad filesystem
299 return result;
300 }
301 #endif
302
303 // Extra safety measures:
304 flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
305 // Also, set fmask = 711 so that files cannot be marked executable,
306 // and cannot by opened by uid 1000 (system). Similar, dmask = 700
307 // so that directories cannot be accessed by uid 1000.
308 result = mount(device, mountPoint, "vfat", flags,
309 "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
310 if (result && errno == EROFS) {
311 LOG_ERROR("mount failed EROFS, try again read-only\n");
312 flags |= MS_RDONLY;
313 result = mount(device, mountPoint, "vfat", flags,
314 "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
315 }
316
317 if (result == 0) {
318 LOG_MOUNT("Partition %s mounted on %s\n", device, mountPoint);
319 NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
320
321 MountPoint* mp = sMountPointList;
322 while (mp) {
323 if (!strcmp(mountPoint, mp->mountPoint)) {
324 int i;
325
326 for (i = 0; i < ASEC_STORES_MAX; i++) {
327 if (mp->asecHandles[i] != NULL) {
328 int a_result;
329 if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
330 LOG_ERROR("ASEC start failure (%d)\n", a_result);
331 }
332 }
333 }
334 break;
335 }
336 mp = mp -> next;
337 }
338 } else if (errno == EBUSY) {
339 LOG_MOUNT("Mount failed (already mounted)\n");
340 result = 0;
341 } else {
342 #if CREATE_MOUNT_POINTS
343 rmdir(mountPoint);
344 #endif
345 LOG_MOUNT("Unable to mount %s on %s\n", device, mountPoint);
346 }
347
348 return result;
349 }
350
351 static int DoUnmountDevice(MountPoint *mp)
352 {
353 boolean loop = IsLoopMounted(mp->mountPoint);
354 int i;
355
356 for (i = 0; i < ASEC_STORES_MAX; i++) {
357 if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
358 AsecStop(mp->asecHandles[i]);
359 }
360
361 int result = umount(mp->mountPoint);
362 LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
363
364 if (result == 0)
365 {
366 #if CREATE_MOUNT_POINTS
367 rmdir(mountPoint);
368 #endif
369 NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
370 }
371
372 if (loop)
373 {
374 // free the loop device
375 int loop_fd = open(LOOP_DEVICE, O_RDONLY);
376 if (loop_fd < -1) {
377 LOG_ERROR("open loop device failed\n");
378 }
379 if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
380 LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
381 }
382
383 close(loop_fd);
384 }
385
386 // ignore EINVAL and ENOENT, since it usually means the device is already unmounted
387 if (result && (errno == EINVAL || errno == ENOENT))
388 result = 0;
389
390 return result;
391 }
392
393 static int MountPartition(const char* device, const char* mountPoint)
394 {
395 char buf[100];
396 int i;
397
398 // attempt to mount subpartitions of the device
399 for (i = 1; i < 10; i++)
400 {
401 int rc;
402 snprintf(buf, sizeof(buf), "%sp%d", device, i);
403 rc = DoMountDevice(buf, mountPoint);
404 LOG_MOUNT("DoMountDevice(%s, %s) = %d\n", buf, mountPoint, rc);
405 if (rc == 0)
406 return 0;
407 }
408
409 return -1;
410 }
411
412 /*****************************************************
413 *
414 * AUTO-MOUNTER STATE ENGINE IMPLEMENTATION
415 *
416 *****************************************************/
417
418 static void SetState(MountPoint* mp, MountState state)
419 {
420 mp->state = state;
421 }
422
423 // Enter a state that requires retries and timeouts.
424 static void SetRetries(MountPoint* mp, MountState state)
425 {
426 SetState(mp, state);
427 mp->retryCount = 0;
428
429 sRetriesPending++;
430 // wake up the automounter thread if we are being called
431 // from somewhere else with no retries pending
432 if (sRetriesPending == 1 && sAutoMountThread != 0 &&
433 pthread_self() != sAutoMountThread)
434 pthread_kill(sAutoMountThread, SIGUSR1);
435 }
436
437 // Exit a state that requires retries and timeouts.
438 static void ClearRetries(MountPoint* mp, MountState state)
439 {
440 SetState(mp, state);
441 sRetriesPending--;
442 }
443
444 // attempt to mount the specified mount point.
445 // set up retry/timeout if it does not succeed at first.
446 static void RequestMount(MountPoint* mp)
447 {
448 LOG_MOUNT("RequestMount %s\n", mp->mountPoint);
449
450 if (mp->state != kMounted && mp->state != kMounting &&
451 access(mp->device, R_OK) == 0) {
452 // try raw device first
453 if (DoMountDevice(mp->device, mp->mountPoint) == 0 ||
454 MountPartition(mp->device, mp->mountPoint) == 0)
455 {
456 SetState(mp, kMounted);
457 }
458 else
459 {
460 SetState(mp, kMounting);
461 mp->retryCount = 0;
462 SetRetries(mp, kMounting);
463 }
464 }
465 }
466
467 // Force the kernel to drop all caches.
468 static void DropSystemCaches(void)
469 {
470 int fd;
471
472 LOG_MOUNT("Dropping system caches\n");
473 fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
474
475 if (fd > 0) {
476 char ch = 3;
477 int rc;
478
479 rc = write(fd, &ch, 1);
480 if (rc <= 0)
481 LOG_MOUNT("Error dropping caches (%d)\n", rc);
482 close(fd);
483 }
484 }
485
486 // attempt to unmount the specified mount point.
487 // set up retry/timeout if it does not succeed at first.
488 static void RequestUnmount(MountPoint* mp, MountState retryState)
489 {
490 int result;
491
492 LOG_MOUNT("RequestUnmount %s retryState: %d\n", mp->mountPoint, retryState);
493
494 if (mp->state == kMounted)
495 {
496 SendUnmountRequest(mp->mountPoint);
497
498 // do this in case the user pulls the SD card before we can successfully unmount
499 sync();
500 DropSystemCaches();
501
502 if (DoUnmountDevice(mp) == 0)
503 {
504 SetState(mp, kUnmounted);
505 if (retryState == kUnmountingForUms)
506 {
507 SetBackingStore(mp, true);
508 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
509 }
510 }
511 else
512 {
513 LOG_MOUNT("unmount failed, set retry\n");
514 SetRetries(mp, retryState);
515 }
516 }
517 else if (mp->state == kMounting)
518 {
519 SetState(mp, kUnmounted);
520 }
521 }
522
523 // returns true if the mount point should be shared via USB mass storage
524 static boolean MassStorageEnabledForMountPoint(const MountPoint* mp)
525 {
526 return (gMassStorageEnabled && gMassStorageConnected && mp->enableUms);
527 }
528
529 // handles changes in gMassStorageEnabled and gMassStorageConnected
530 static void MassStorageStateChanged()
531 {
532 MountPoint* mp = sMountPointList;
533
534 boolean enable = (gMassStorageEnabled && gMassStorageConnected);
535 LOG_MOUNT("MassStorageStateChanged enable: %s\n", (enable ? "true" : "false"));
536
537 while (mp)
538 {
539 if (mp->enableUms)
540 {
541 if (enable)
542 {
543 if (mp->state == kMounting)
544 SetState(mp, kUnmounted);
545 if (mp->state == kUnmounted)
546 {
547 SetBackingStore(mp, true);
548 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
549 }
550 else
551 {
552 LOG_MOUNT("MassStorageStateChanged requesting unmount\n");
553 // need to successfully unmount first
554 RequestUnmount(mp, kUnmountingForUms);
555 }
556 } else if (mp->umsActive) {
557 SetBackingStore(mp, false);
558 if (mp->state == kUnmountingForUms)
559 {
560 ClearRetries(mp, kMounted);
561 NotifyMediaState(mp->mountPoint, MEDIA_MOUNTED, false);
562 }
563 else if (mp->state == kUnmounted)
564 {
565 NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
566 RequestMount(mp);
567 }
568 }
569 }
570
571 mp = mp->next;
572 }
573 }
574
575 // called when USB mass storage connected state changes
576 static void HandleMassStorageOnline(boolean connected)
577 {
578 if (connected != gMassStorageConnected)
579 {
580 gMassStorageConnected = connected;
581 SendMassStorageConnected(connected);
582
583 // we automatically reset to mass storage off after USB is connected
584 if (!connected)
585 gMassStorageEnabled = false;
586
587 MassStorageStateChanged();
588 }
589 }
590
591 // called when a new block device has been created
592 static void HandleMediaInserted(const char* device)
593 {
594 MountPoint* mp = sMountPointList;
595
596 LOG_MOUNT("HandleMediaInserted(%s):\n", device);
597
598 while (mp)
599 {
600 // see if the device matches mount point's block device
601 if (mp->state == kUnmounted &&
602 strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
603 {
604 if (MassStorageEnabledForMountPoint(mp))
605 {
606 SetBackingStore(mp, true);
607 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
608 }
609 else
610 RequestMount(mp);
611 }
612 mp = mp->next;
613 }
614 }
615
616 // called when a new block device has been deleted
617 static void HandleMediaRemoved(const char* device)
618 {
619 MountPoint* mp = sMountPointList;
620 while (mp)
621 {
622 if (strncmp(device, mp->device + DEVPATHLENGTH, strlen(mp->device) - DEVPATHLENGTH) == 0)
623 {
624 if (mp->enableUms)
625 SetBackingStore(mp, false);
626
627 if (mp->state == kMounted)
628 {
629 RequestUnmount(mp, kUnmountingForEject);
630 NotifyMediaState(mp->mountPoint, MEDIA_BAD_REMOVAL, false);
631 }
632
633 NotifyMediaState(mp->mountPoint, MEDIA_REMOVED, false);
634 break;
635 }
636 mp = mp->next;
637 }
638 }
639
640 // Handle retrying to mount or unmount devices,
641 // and handle timeout condition if we have tried too many times
642 static void HandleRetries()
643 {
644 MountPoint* mp = sMountPointList;
645
646 while (mp)
647 {
648 if (mp->state == kMounting)
649 {
650 if (MountPartition(mp->device, mp->mountPoint) == 0)
651 {
652 // mount succeeded - clear the retry for this mount point
653 ClearRetries(mp, kMounted);
654 }
655 else
656 {
657 mp->retryCount++;
658 if (mp->retryCount == MAX_MOUNT_RETRIES)
659 {
660 // we failed to mount the device too many times
661 ClearRetries(mp, kUnmounted);
662 // notify that we failed to mount
663 NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTABLE, false);
664 }
665 }
666 }
667 else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
668 {
669 if (DoUnmountDevice(mp) == 0)
670 {
671 // unmounting succeeded
672 // start mass storage, if state is kUnmountingForUms
673 if (mp->state == kUnmountingForUms)
674 {
675 SetBackingStore(mp, true);
676 NotifyMediaState(mp->mountPoint, MEDIA_SHARED, false);
677 }
678 // clear the retry for this mount point
679 ClearRetries(mp, kUnmounted);
680 }
681 else
682 {
683 mp->retryCount++;
684 if (mp->retryCount >= MAX_UNMOUNT_RETRIES)
685 {
686 // kill any processes that are preventing the device from unmounting
687 // send SIGKILL instead of SIGTERM if the first attempt did not succeed
688 boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
689
690 int i;
691
692 for (i = 0; i < ASEC_STORES_MAX; i++) {
693 if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
694 LOG_MOUNT("Killing processes for ASEC path '%s'\n",
695 AsecMountPoint(mp->asecHandles[i]));
696 KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
697 sigkill,
698 gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
699
700 // Now that we've killed the processes, try to stop the volume again
701 AsecStop(mp->asecHandles[i]);
702 }
703 }
704
705 // unmounting the device is failing, so start killing processes
706 KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids,
707 sizeof(gExcludedPids) / sizeof(pid_t));
708
709 }
710 }
711 }
712
713 mp = mp->next;
714 }
715 }
716
717 /*****************************************************
718 *
719 * AUTO-MOUNTER THREAD
720 *
721 *****************************************************/
722
723 static void sigusr1_handler(int signo)
724 {
725 // don't need to do anything here
726 }
727
728 // create a socket for listening to inotify events
729 int CreateINotifySocket()
730 {
731 // initialize inotify
732 int fd = inotify_init();
733
734 if (fd < 0) {
735 LOG_ERROR("inotify_init failed, %s\n", strerror(errno));
736 return -1;
737 }
738
739 fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
740
741 return fd;
742 }
743
744
745 // create a socket for listening to uevents
746 int CreateUEventSocket()
747 {
748 struct sockaddr_nl addr;
749 int sz = 64*1024;
750 int fd;
751
752 memset(&addr, 0, sizeof(addr));
753 addr.nl_family = AF_NETLINK;
754 addr.nl_pid = getpid();
755 addr.nl_groups = 0xffffffff;
756
757 fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
758 if(fd < 0)
759 {
760 LOG_ERROR("could not create NETLINK_KOBJECT_UEVENT socket\n");
761 return -1;
762 }
763
764 setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
765
766 if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
767 LOG_ERROR("could not bind NETLINK_KOBJECT_UEVENT socket\n");
768 close(fd);
769 return -1;
770 }
771
772 return fd;
773 }
774
775 /*
776 * Automounter main event thread.
777 * This thread listens for block devices being created and deleted via inotify,
778 * and listens for changes in the USB mass storage connected/disconnected via uevents from the
779 * power supply driver.
780 * This thread also handles retries and timeouts for requests to mount or unmount a device.
781 */
782 static void* AutoMountThread(void* arg)
783 {
784 int inotify_fd;
785 int uevent_fd;
786 int id;
787 struct sigaction actions;
788
789 gExcludedPids[1] = getpid();
790
791 memset(&actions, 0, sizeof(actions));
792 sigemptyset(&actions.sa_mask);
793 actions.sa_flags = 0;
794 actions.sa_handler = sigusr1_handler;
795 sigaction(SIGUSR1, &actions, NULL);
796
797 // initialize inotify
798 inotify_fd = CreateINotifySocket();
799 // watch for files created and deleted in "/dev"
800 inotify_add_watch(inotify_fd, DEVPATH, IN_CREATE|IN_DELETE);
801
802 // initialize uevent watcher
803 uevent_fd = CreateUEventSocket();
804 if (uevent_fd < 0)
805 {
806 LOG_ERROR("CreateUEventSocket failed, %s\n", strerror(errno));
807 return NULL;
808 }
809
810 while (1)
811 {
812 struct pollfd fds[2];
813 int timeout, result;
814
815 #define INOTIFY_IDX 0
816 #define UEVENT_IDX 1
817
818 fds[INOTIFY_IDX].fd = inotify_fd;
819 fds[INOTIFY_IDX].events = POLLIN;
820 fds[INOTIFY_IDX].revents = 0;
821 fds[UEVENT_IDX].fd = uevent_fd;
822 fds[UEVENT_IDX].events = POLLIN;
823 fds[UEVENT_IDX].revents = 0;
824
825 // wait for an event or a timeout to occur.
826 // poll() can also return in response to a SIGUSR1 signal
827 timeout = (sRetriesPending ? POLL_TIMEOUT : -1);
828 result = poll(fds, 2, timeout);
829
830 // lock the mutex while we are handling events
831 pthread_mutex_lock(&sMutex);
832
833 // handle inotify notifications for block device creation and deletion
834 if (fds[INOTIFY_IDX].revents == POLLIN)
835 {
836 struct inotify_event event;
837 char buffer[512];
838 int length = read(inotify_fd, buffer, sizeof(buffer));
839 int offset = 0;
840
841 while (length >= (int)sizeof(struct inotify_event))
842 {
843 struct inotify_event* event = (struct inotify_event *)&buffer[offset];
844
845 if (event->mask == IN_CREATE)
846 {
847 LOG_MOUNT("/dev/block/%s created\n", event->name);
848 HandleMediaInserted(event->name);
849 }
850 else if (event->mask == IN_DELETE)
851 {
852 LOG_MOUNT("/dev/block/%s deleted\n", event->name);
853 HandleMediaRemoved(event->name);
854 }
855
856 int size = sizeof(struct inotify_event) + event->len;
857 length -= size;
858 offset += size;
859 }
860 }
861
862 // handle uevent notifications for USB state changes
863 if (fds[UEVENT_IDX].revents == POLLIN)
864 {
865 char buffer[64*1024];
866 int count;
867
868 count = recv(uevent_fd, buffer, sizeof(buffer), 0);
869 if (count > 0) {
870 char* s = buffer;
871 char* end = s + count;
872 char* type = NULL;
873 char* online = NULL;
874 char* switchName = NULL;
875 char* switchState = NULL;
876
877 while (s < end) {
878 if (!strncmp("POWER_SUPPLY_TYPE=", s, strlen("POWER_SUPPLY_TYPE=")))
879 type = s + strlen("POWER_SUPPLY_TYPE=");
880 else if (!strncmp("POWER_SUPPLY_ONLINE=", s, strlen("POWER_SUPPLY_ONLINE=")))
881 online = s + strlen("POWER_SUPPLY_ONLINE=");
882 else if (!strncmp("SWITCH_NAME=", s, strlen("SWITCH_NAME=")))
883 switchName = s + strlen("SWITCH_NAME=");
884 else if (!strncmp("SWITCH_STATE=", s, strlen("SWITCH_STATE=")))
885 switchState = s + strlen("SWITCH_STATE=");
886 s += (strlen(s) + 1);
887 }
888
889 // we use the usb_mass_storage switch state to tell us when USB is online
890 if (switchName && switchState &&
891 !strcmp(switchName, "usb_mass_storage") && !strcmp(switchState, "online"))
892 {
893 LOG_MOUNT("USB online\n");
894 HandleMassStorageOnline(true);
895 }
896
897 // and we use the power supply state to tell us when USB is offline
898 // we can't rely on the switch for offline detection because we get false positives
899 // when USB is reenumerated by the host.
900 if (type && online && !strcmp(type, "USB") && !strcmp(online, "0"))
901 {
902 LOG_MOUNT("USB offline\n");
903 HandleMassStorageOnline(false);
904 }
905 }
906 }
907
908 // handle retries
909 if (sRetriesPending)
910 HandleRetries();
911
912 // done handling events, so unlock the mutex
913 pthread_mutex_unlock(&sMutex);
914 }
915
916 inotify_rm_watch(inotify_fd, id);
917 close(inotify_fd);
918 close(uevent_fd);
919
920 return NULL;
921 }
922
923 /*****************************************************
924 *
925 * THESE FUNCTIONS ARE CALLED FROM THE SERVER THREAD
926 *
927 *****************************************************/
928
929 // Called to enable or disable USB mass storage support
930 void EnableMassStorage(boolean enable)
931 {
932 pthread_mutex_lock(&sMutex);
933
934 LOG_MOUNT("EnableMassStorage %s\n", (enable ? "true" : "false"));
935 gMassStorageEnabled = enable;
936 MassStorageStateChanged();
937 pthread_mutex_unlock(&sMutex);
938 }
939
940 // Called to request that the specified mount point be mounted
941 void MountMedia(const char* mountPoint)
942 {
943 MountPoint* mp = sMountPointList;
944
945 LOG_MOUNT("MountMedia(%s)\n", mountPoint);
946
947 pthread_mutex_lock(&sMutex);
948 while (mp)
949 {
950 if (strcmp(mp->mountPoint, mountPoint) == 0)
951 {
952 if (mp->state == kUnmountingForEject)
953 {
954 // handle the case where we try to remount before we actually unmounted
955 ClearRetries(mp, kMounted);
956 }
957
958 // don't attempt to mount if mass storage is active
959 if (!MassStorageEnabledForMountPoint(mp))
960 RequestMount(mp);
961 }
962
963 mp = mp->next;
964 }
965 pthread_mutex_unlock(&sMutex);
966 }
967
968 // Called to request that the specified mount point be unmounted
969 void UnmountMedia(const char* mountPoint)
970 {
971 MountPoint* mp = sMountPointList;
972
973 pthread_mutex_lock(&sMutex);
974 while (mp)
975 {
976 if (strcmp(mp->mountPoint, mountPoint) == 0)
977 RequestUnmount(mp, kUnmountingForEject);
978
979 mp = mp->next;
980 }
981 pthread_mutex_unlock(&sMutex);
982 }
983
984 boolean IsMassStorageEnabled()
985 {
986 return gMassStorageEnabled;
987 }
988
989 boolean IsMassStorageConnected()
990 {
991 return gMassStorageConnected;
992 }
993
994 /***********************************************
995 *
996 * THESE FUNCTIONS ARE CALLED ONLY AT STARTUP
997 *
998 ***********************************************/
999
1000 void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
1001 {
1002 MountPoint* newMountPoint;
1003
1004 LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
1005 // add a new MountPoint to the head of our linked list
1006 newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
1007 newMountPoint->device = device;
1008 newMountPoint->mountPoint = mountPoint;
1009 newMountPoint->driverStorePath = driverStorePath;
1010 newMountPoint->enableUms = enableUms;
1011 newMountPoint->umsActive = false;
1012 newMountPoint->state = kUnmounted;
1013 newMountPoint->retryCount = 0;
1014
1015 // add to linked list
1016 newMountPoint->next = sMountPointList;
1017 sMountPointList = newMountPoint;
1018 return newMountPoint;
1019 }
1020
1021 int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
1022 const char *mount_point, const char *crypt)
1023 {
1024 MountPoint *mp = (MountPoint *) Mp;
1025 int i;
1026
1027 for (i = 0; i < ASEC_STORES_MAX; i++) {
1028 if (!mp->asecHandles[i])
1029 break;
1030 }
1031
1032 if (i == ASEC_STORES_MAX) {
1033 LOG_ERROR("Maximum # of ASEC stores exceeded\n");
1034 return -EINVAL;
1035 }
1036
1037 if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
1038 return -1;
1039
1040 return 0;
1041 }
1042 static void MountDevices()
1043 {
1044 MountPoint* mp = sMountPointList;
1045 while (mp)
1046 {
1047 RequestMount(mp);
1048 mp = mp->next;
1049 }
1050 }
1051
1052 void StartAutoMounter()
1053 {
1054 gExcludedPids[0] = getpid();
1055
1056 gMassStorageConnected = ReadMassStorageState();
1057 LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
1058
1059 MountDevices();
1060 pthread_create(&sAutoMountThread, NULL, AutoMountThread, NULL);
1061 }
+0
-0
mountd/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
mountd/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-222
mountd/ProcessKiller.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 ** mountd process killer
18 */
19
20 #include "mountd.h"
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <ctype.h>
28 #include <pwd.h>
29 #include <stdlib.h>
30 #include <poll.h>
31 #include <sys/stat.h>
32
33
34 static boolean ReadSymLink(const char* path, char* link)
35 {
36 struct stat s;
37 int length;
38
39 if (lstat(path, &s) < 0)
40 return false;
41 if ((s.st_mode & S_IFMT) != S_IFLNK)
42 return false;
43
44 // we have a symlink
45 length = readlink(path, link, PATH_MAX - 1);
46 if (length <= 0)
47 return false;
48 link[length] = 0;
49 return true;
50 }
51
52 static boolean PathMatchesMountPoint(const char* path, const char* mountPoint)
53 {
54 int length = strlen(mountPoint);
55 if (length > 1 && strncmp(path, mountPoint, length) == 0)
56 {
57 // we need to do extra checking if mountPoint does not end in a '/'
58 if (mountPoint[length - 1] == '/')
59 return true;
60 // if mountPoint does not have a trailing slash, we need to make sure
61 // there is one in the path to avoid partial matches.
62 return (path[length] == 0 || path[length] == '/');
63 }
64
65 return false;
66 }
67
68 static void GetProcessName(int pid, char buffer[PATH_MAX])
69 {
70 int fd;
71 sprintf(buffer, "/proc/%d/cmdline", pid);
72 fd = open(buffer, O_RDONLY);
73 if (fd < 0) {
74 strcpy(buffer, "???");
75 } else {
76 int length = read(fd, buffer, PATH_MAX - 1);
77 buffer[length] = 0;
78 close(fd);
79 }
80 }
81
82 static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
83 {
84 DIR* dir;
85 struct dirent* de;
86 boolean fileOpen = false;
87 char path[PATH_MAX];
88 char link[PATH_MAX];
89 int parent_length;
90
91 // compute path to process's directory of open files
92 sprintf(path, "/proc/%d/fd", pid);
93 dir = opendir(path);
94 if (!dir)
95 return false;
96
97 // remember length of the path
98 parent_length = strlen(path);
99 // append a trailing '/'
100 path[parent_length++] = '/';
101
102 while ((de = readdir(dir)) != 0 && !fileOpen) {
103 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
104 continue;
105
106 // append the file name, after truncating to parent directory
107 path[parent_length] = 0;
108 strcat(path, de->d_name);
109
110 if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
111 {
112 char name[PATH_MAX];
113 GetProcessName(pid, name);
114 LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link);
115 fileOpen = true;
116 }
117 }
118
119 closedir(dir);
120 return fileOpen;
121 }
122
123 static boolean CheckFileMaps(int pid, const char* mountPoint)
124 {
125 FILE* file;
126 char buffer[PATH_MAX + 100];
127 boolean mapOpen = false;
128
129 sprintf(buffer, "/proc/%d/maps", pid);
130 file = fopen(buffer, "r");
131 if (!file)
132 return false;
133
134 while (!mapOpen && fgets(buffer, sizeof(buffer), file))
135 {
136 // skip to the path
137 const char* path = strchr(buffer, '/');
138 if (path && PathMatchesMountPoint(path, mountPoint))
139 {
140 char name[PATH_MAX];
141 GetProcessName(pid, name);
142 LOG_ERROR("process %s (%d) has open file map for %s\n", name, pid, path);
143 mapOpen = true;
144 }
145 }
146
147 fclose(file);
148 return mapOpen;
149 }
150
151 static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
152 {
153 char path[PATH_MAX];
154 char link[PATH_MAX];
155
156 sprintf(path, "/proc/%d/%s", pid, name);
157 if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
158 {
159 char name[PATH_MAX];
160 GetProcessName(pid, name);
161 LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint);
162 return true;
163 }
164 else
165 return false;
166 }
167
168 static int get_pid(const char* s)
169 {
170 int result = 0;
171 while (*s) {
172 if (!isdigit(*s)) return -1;
173 result = 10 * result + (*s++ - '0');
174 }
175 return result;
176 }
177
178 // hunt down and kill processes that have files open on the given mount point
179 void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
180 {
181 DIR* dir;
182 struct dirent* de;
183
184 LOG_ERROR("KillProcessesWithOpenFiles %s\n", mountPoint);
185 dir = opendir("/proc");
186 if (!dir) return;
187
188 while ((de = readdir(dir)) != 0)
189 {
190 boolean killed = false;
191 // does the name look like a process ID?
192 int pid = get_pid(de->d_name);
193 if (pid == -1) continue;
194
195 if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files
196 || CheckFileMaps(pid, mountPoint) // check for mmap()
197 || CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory
198 || CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot()
199 || CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
200 )
201 {
202 int i;
203 boolean hit = false;
204
205 for (i = 0; i < num_excluded; i++) {
206 if (pid == excluded[i]) {
207 LOG_ERROR("I just need a little more TIME captain!\n");
208 hit = true;
209 break;
210 }
211 }
212
213 if (!hit) {
214 LOG_ERROR("Killing process %d\n", pid);
215 kill(pid, (sigkill ? SIGKILL : SIGTERM));
216 }
217 }
218 }
219
220 closedir(dir);
221 }
+0
-313
mountd/Server.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 ** mountd server support
18 */
19
20 #include "mountd.h"
21 #include "ASEC.h"
22
23 #include <cutils/properties.h>
24 #include <cutils/sockets.h>
25
26 #include <pthread.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <sys/socket.h>
33
34 #include <private/android_filesystem_config.h>
35
36
37 // current client file descriptor
38 static int sFD = -1;
39
40 // to synchronize writing to client
41 static pthread_mutex_t sWriteMutex = PTHREAD_MUTEX_INITIALIZER;
42
43 // path for media that failed to mount before the runtime is connected
44 static char* sDeferredUnmountableMediaPath = NULL;
45
46 // last asec msg before the runtime was connected
47 static char* sAsecDeferredMessage = NULL;
48 static char* sAsecDeferredArgument = NULL;
49
50 static int Write(const char* message)
51 {
52 int result = -1;
53
54 pthread_mutex_lock(&sWriteMutex);
55
56 LOG_SERVER("Write: %s\n", message);
57 if (sFD >= 0)
58 result = write(sFD, message, strlen(message) + 1);
59
60 pthread_mutex_unlock(&sWriteMutex);
61
62 return result;
63 }
64
65 static int Write2(const char* message, const char* data)
66 {
67 int result = -1;
68
69 char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
70 if (!buffer)
71 {
72 LOG_ERROR("alloca failed in Write2\n");
73 return -1;
74 }
75
76 strcpy(buffer, message);
77 strcat(buffer, data);
78 return Write(buffer);
79 }
80
81 static void SendStatus()
82 {
83 Write(IsMassStorageConnected() ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
84 Write(IsMassStorageEnabled() ? MOUNTD_UMS_ENABLED : MOUNTD_UMS_DISABLED);
85 }
86
87 static void DoCommand(const char* command)
88 {
89 LOG_SERVER("DoCommand %s\n", command);
90
91 if (strcmp(command, MOUNTD_ENABLE_UMS) == 0)
92 {
93 EnableMassStorage(true);
94 Write(MOUNTD_UMS_ENABLED);
95 }
96 else if (strcmp(command, MOUNTD_DISABLE_UMS) == 0)
97 {
98 EnableMassStorage(false);
99 Write(MOUNTD_UMS_DISABLED);
100 }
101 else if (strcmp(command, MOUNTD_SEND_STATUS) == 0)
102 {
103 SendStatus();
104 }
105 else if (strncmp(command, MOUNTD_MOUNT_MEDIA, strlen(MOUNTD_MOUNT_MEDIA)) == 0)
106 {
107 const char* path = command + strlen(MOUNTD_MOUNT_MEDIA);
108 MountMedia(path);
109 }
110 else if (strncmp(command, MOUNTD_EJECT_MEDIA, strlen(MOUNTD_EJECT_MEDIA)) == 0)
111 {
112 const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
113 UnmountMedia(path);
114 }
115 else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
116 LOG_ASEC("Got ASEC_CMD_ENABLE\n");
117 // XXX: SAN: Impliment
118 }
119 else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
120 LOG_ASEC("Got ASEC_CMD_DISABLE\n");
121 // XXX: SAN: Impliment
122 }
123 else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
124 LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
125 // XXX: SAN: Impliment
126 }
127 else
128 LOGE("unknown command %s\n", command);
129 }
130
131 int RunServer()
132 {
133 int socket = android_get_control_socket(MOUNTD_SOCKET);
134 if (socket < 0) {
135 LOGE("Obtaining file descriptor for socket '%s' failed: %s",
136 MOUNTD_SOCKET, strerror(errno));
137 return -1;
138 }
139
140 if (listen(socket, 4) < 0) {
141 LOGE("Unable to listen on file descriptor '%d' for socket '%s': %s",
142 socket, MOUNTD_SOCKET, strerror(errno));
143 return -1;
144 }
145
146 while (1)
147 {
148 struct sockaddr addr;
149 socklen_t alen;
150 struct ucred cred;
151 socklen_t size;
152
153 alen = sizeof(addr);
154 sFD = accept(socket, &addr, &alen);
155 if (sFD < 0)
156 continue;
157
158 if (sDeferredUnmountableMediaPath) {
159 NotifyMediaState(sDeferredUnmountableMediaPath, MEDIA_UNMOUNTABLE, false);
160 free(sDeferredUnmountableMediaPath);
161 sDeferredUnmountableMediaPath = NULL;
162 }
163
164 if (sAsecDeferredMessage) {
165
166 if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
167 LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
168 free(sAsecDeferredMessage);
169 free(sAsecDeferredArgument);
170 sAsecDeferredMessage = sAsecDeferredArgument = NULL;
171 }
172
173 while (1)
174 {
175 char buffer[101];
176 int result = read(sFD, buffer, sizeof(buffer) - 1);
177 if (result > 0)
178 {
179 int start = 0;
180 int i;
181 // command should be zero terminated, but just in case
182 buffer[result] = 0;
183 for (i = 0; i < result; i++)
184 {
185 if (buffer[i] == 0)
186 {
187 DoCommand(buffer + start);
188 start = i + 1;
189 }
190 }
191 }
192 else
193 {
194 close(sFD);
195 sFD = -1;
196 break;
197 }
198 }
199 }
200
201 // should never get here
202 return 0;
203 }
204
205 void SendMassStorageConnected(boolean connected)
206 {
207 Write(connected ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
208 }
209
210 void SendUnmountRequest(const char* path)
211 {
212 Write2(MOUNTD_REQUEST_EJECT, path);
213 }
214
215 void NotifyAsecState(AsecState state, const char *argument)
216 {
217 const char *event = NULL;
218 const char *status = NULL;
219 boolean deferr = true;;
220
221 switch (state) {
222 case ASEC_DISABLED:
223 event = ASEC_EVENT_DISABLED;
224 status = ASEC_STATUS_DISABLED;
225 break;
226 case ASEC_AVAILABLE:
227 event = ASEC_EVENT_AVAILABLE;
228 status = ASEC_STATUS_AVAILABLE;
229 break;
230 case ASEC_BUSY:
231 event = ASEC_EVENT_BUSY;
232 status = ASEC_STATUS_BUSY;
233 deferr = false;
234 break;
235 case ASEC_FAILED_INTERR:
236 event = ASEC_EVENT_FAILED_INTERR;
237 status = ASEC_STATUS_FAILED_INTERR;
238 break;
239 case ASEC_FAILED_NOMEDIA:
240 event = ASEC_EVENT_FAILED_NOMEDIA;
241 status = ASEC_STATUS_FAILED_NOMEDIA;
242 break;
243 case ASEC_FAILED_BADMEDIA:
244 event = ASEC_EVENT_FAILED_BADMEDIA;
245 status = ASEC_STATUS_FAILED_BADMEDIA;
246 break;
247 case ASEC_FAILED_BADKEY:
248 event = ASEC_EVENT_FAILED_BADKEY;
249 status = ASEC_STATUS_FAILED_BADKEY;
250 break;
251 default:
252 LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
253 return;
254 }
255
256 property_set(ASEC_STATUS, status);
257
258 int result = Write2(event, argument);
259 if ((result < 0) && deferr) {
260 if (sAsecDeferredMessage)
261 free(sAsecDeferredMessage);
262 sAsecDeferredMessage = strdup(event);
263 if (sAsecDeferredArgument)
264 free(sAsecDeferredArgument);
265 sAsecDeferredArgument = strdup(argument);
266 LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
267 }
268 }
269
270 void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
271 {
272 const char* event = NULL;
273 const char* propertyValue = NULL;
274
275 switch (state) {
276 case MEDIA_REMOVED:
277 event = MOUNTD_MEDIA_REMOVED;
278 propertyValue = EXTERNAL_STORAGE_REMOVED;
279 break;
280 case MEDIA_UNMOUNTED:
281 event = MOUNTD_MEDIA_UNMOUNTED;
282 propertyValue = EXTERNAL_STORAGE_UNMOUNTED;
283 break;
284 case MEDIA_MOUNTED:
285 event = (readOnly ? MOUNTD_MEDIA_MOUNTED_READ_ONLY : MOUNTD_MEDIA_MOUNTED);
286 propertyValue = (readOnly ? EXTERNAL_STORAGE_MOUNTED_READ_ONLY : EXTERNAL_STORAGE_MOUNTED);
287 break;
288 case MEDIA_SHARED:
289 event = MOUNTD_MEDIA_SHARED;
290 propertyValue = EXTERNAL_STORAGE_SHARED;
291 break;
292 case MEDIA_BAD_REMOVAL:
293 event = MOUNTD_MEDIA_BAD_REMOVAL;
294 propertyValue = EXTERNAL_STORAGE_BAD_REMOVAL;
295 break;
296 case MEDIA_UNMOUNTABLE:
297 event = MOUNTD_MEDIA_UNMOUNTABLE;
298 propertyValue = EXTERNAL_STORAGE_UNMOUNTABLE;
299 break;
300 default:
301 LOG_ERROR("unknown MediaState %d in NotifyMediaState\n", state);
302 return;
303 }
304
305 property_set(EXTERNAL_STORAGE_STATE, propertyValue);
306 int result = Write2(event, path);
307 if (result < 0 && state == MEDIA_UNMOUNTABLE) {
308
309 // if we cannot communicate with the runtime, defer this message until the runtime is available
310 sDeferredUnmountableMediaPath = strdup(path);
311 }
312 }
+0
-154
mountd/logwrapper.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <fcntl.h>
24
25 #include "private/android_filesystem_config.h"
26 #include "cutils/log.h"
27
28 int parent(const char *tag, int parent_read) {
29 int status;
30 char buffer[4096];
31
32 int a = 0; // start index of unprocessed data
33 int b = 0; // end index of unprocessed data
34 int sz;
35 while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
36
37 sz += b;
38 // Log one line at a time
39 for (b = 0; b < sz; b++) {
40 if (buffer[b] == '\r') {
41 buffer[b] = '\0';
42 } else if (buffer[b] == '\n') {
43 buffer[b] = '\0';
44 LOG(LOG_INFO, tag, &buffer[a]);
45 a = b + 1;
46 }
47 }
48
49 if (a == 0 && b == sizeof(buffer) - 1) {
50 // buffer is full, flush
51 buffer[b] = '\0';
52 LOG(LOG_INFO, tag, &buffer[a]);
53 b = 0;
54 } else if (a != b) {
55 // Keep left-overs
56 b -= a;
57 memmove(buffer, &buffer[a], b);
58 a = 0;
59 } else {
60 a = 0;
61 b = 0;
62 }
63
64 }
65 // Flush remaining data
66 if (a != b) {
67 buffer[b] = '\0';
68 LOG(LOG_INFO, tag, &buffer[a]);
69 }
70 status = 0xAAAA;
71 if (wait(&status) != -1) { // Wait for child
72 if (WIFEXITED(status)) {
73 LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
74 WEXITSTATUS(status));
75 return WEXITSTATUS(status);
76 } else if (WIFSIGNALED(status))
77 LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
78 WTERMSIG(status));
79 else if (WIFSTOPPED(status))
80 LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
81 WSTOPSIG(status));
82 } else
83 LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
84 strerror(errno), errno);
85 return -EAGAIN;
86 }
87
88 void child(int argc, char* argv[]) {
89 // create null terminated argv_child array
90 char* argv_child[argc + 1];
91 memcpy(argv_child, argv, argc * sizeof(char *));
92 argv_child[argc] = NULL;
93
94 // XXX: PROTECT FROM VIKING KILLER
95 if (execvp(argv_child[0], argv_child)) {
96 LOG(LOG_ERROR, "logwrapper",
97 "executing %s failed: %s\n", argv_child[0], strerror(errno));
98 exit(-1);
99 }
100 }
101
102 int logwrap(int argc, char* argv[])
103 {
104 pid_t pid;
105
106 int parent_ptty;
107 int child_ptty;
108 char *child_devname = NULL;
109
110 /* Use ptty instead of socketpair so that STDOUT is not buffered */
111 parent_ptty = open("/dev/ptmx", O_RDWR);
112 if (parent_ptty < 0) {
113 LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty\n");
114 return -errno;
115 }
116
117 if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
118 ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
119 LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx\n");
120 return -1;
121 }
122
123 pid = fork();
124 if (pid < 0) {
125 LOG(LOG_ERROR, "logwrapper", "Failed to fork\n");
126 return -errno;
127 } else if (pid == 0) {
128 child_ptty = open(child_devname, O_RDWR);
129 if (child_ptty < 0) {
130 LOG(LOG_ERROR, "logwrapper", "Problem with child ptty\n");
131 return -errno;
132 }
133
134 // redirect stdout and stderr
135 close(parent_ptty);
136 dup2(child_ptty, 1);
137 dup2(child_ptty, 2);
138 close(child_ptty);
139
140 child(argc, argv);
141 } else {
142 // switch user and group to "log"
143 // this may fail if we are not root,
144 // but in that case switching user/group is unnecessary
145
146 // setgid(AID_LOG);
147 // setuid(AID_LOG);
148
149 return parent(argv[0], parent_ptty);
150 }
151
152 return 0;
153 }
+0
-174
mountd/mountd.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 ** mountd main program
18 */
19
20 #include "mountd.h"
21
22 #include <cutils/config_utils.h>
23 #include <cutils/cpu_info.h>
24 #include <cutils/properties.h>
25
26 #include <sys/mount.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <linux/capability.h>
33 #include <linux/prctl.h>
34
35 #include <private/android_filesystem_config.h>
36
37 #ifdef MOUNTD_LOG
38 FILE* logFile;
39 #endif
40
41 struct asec_cfg {
42 const char *name;
43 const char *backing_file;
44 const char *size;
45 const char *mount_point;
46 const char *crypt;
47 };
48
49 static int ProcessAsecData(cnode *node, struct asec_cfg *stores, int idx)
50 {
51 cnode *child = node->first_child;
52 const char *name = NULL;
53 const char *file = NULL;
54 const char *size = NULL;
55 const char *mp = NULL;
56 const char *crypt = NULL;
57
58 LOG_ASEC("ProcessAsecData(%s, %p, %d)\n", node->name, stores, idx);
59
60 while (child) {
61 if (!strcmp(child->name, "name"))
62 name = child->value;
63 else if (!strcmp(child->name, "backing_file"))
64 file = child->value;
65 else if (!strcmp(child->name, "size"))
66 size = child->value;
67 else if (!strcmp(child->name, "mount_point"))
68 mp = child->value;
69 else if (!strcmp(child->name, "crypt"))
70 crypt = child->value;
71 child = child->next;
72 }
73
74 if (!name || !file || !size || !mp || !crypt) {
75 LOG_ERROR("Missing required token from config. Skipping ASEC volume\n");
76 return -1;
77 } else if (idx == ASEC_STORES_MAX) {
78 LOG_ERROR("Maximum # of ASEC stores already defined\n");
79 return -1;
80 }
81
82 stores[idx].name = name;
83 stores[idx].backing_file = file;
84 stores[idx].size = size;
85 stores[idx].mount_point = mp;
86 stores[idx].crypt = crypt;
87 return ++idx;
88 }
89
90 static void ReadConfigFile(const char* path)
91 {
92 cnode* root = config_node("", "");
93 cnode* node;
94
95 config_load_file(root, path);
96 node = root->first_child;
97
98 while (node)
99 {
100 if (strcmp(node->name, "mount") == 0)
101 {
102 const char* block_device = NULL;
103 const char* mount_point = NULL;
104 const char* driver_store_path = NULL;
105 boolean enable_ums = false;
106 cnode* child = node->first_child;
107 struct asec_cfg asec_stores[ASEC_STORES_MAX];
108 int asec_idx = 0;
109
110 memset(asec_stores, 0, sizeof(asec_stores));
111
112 while (child)
113 {
114 const char* name = child->name;
115 const char* value = child->value;
116
117 if (!strncmp(name, "asec_", 5)) {
118 int rc = ProcessAsecData(child, asec_stores, asec_idx);
119 if (rc < 0) {
120 LOG_ERROR("Error processing ASEC cfg data\n");
121 } else
122 asec_idx = rc;
123 } else if (strcmp(name, "block_device") == 0)
124 block_device = value;
125 else if (strcmp(name, "mount_point") == 0)
126 mount_point = value;
127 else if (strcmp(name, "driver_store_path") == 0)
128 driver_store_path = value;
129 else if (strcmp(name, "enable_ums") == 0 &&
130 strcmp(value, "true") == 0)
131 enable_ums = true;
132
133 child = child->next;
134 }
135
136 // mount point and removable fields are optional
137 if (block_device && mount_point)
138 {
139 void *mp = AddMountPoint(block_device, mount_point, driver_store_path, enable_ums);
140 int i;
141
142 for (i = 0; i < asec_idx; i++) {
143 AddAsecToMountPoint(mp, asec_stores[i].name, asec_stores[i].backing_file,
144 asec_stores[i].size, asec_stores[i].mount_point,
145 asec_stores[i].crypt);
146 }
147 }
148 }
149
150 node = node->next;
151 }
152 }
153
154 int main(int argc, char* argv[])
155 {
156 const char* configPath = "/system/etc/mountd.conf";
157 int i;
158
159 for (i = 1; i < argc; i++)
160 {
161 const char* arg = argv[i];
162
163 if (strcmp(arg, "-f") == 0)
164 {
165 if (i < argc - 1)
166 configPath = argv[++i];
167 }
168 }
169
170 ReadConfigFile(configPath);
171 StartAutoMounter();
172 return RunServer();
173 }
+0
-190
mountd/mountd.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef MOUNTD_H__
17 #define MOUNTD_H__
18
19 #define LOG_TAG "mountd"
20 #include "cutils/log.h"
21
22 #include "ASEC.h"
23
24 typedef int boolean;
25 enum {
26 false = 0,
27 true = 1
28 };
29
30 #define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
31
32 // Set this for logging error messages
33 #define ENABLE_LOG_ERROR
34
35 // set this to log automounter events
36 #define ENABLE_LOG_MOUNT
37
38 // set this to log server events
39 //#define ENABLE_LOG_SERVER
40
41 // set this to log ASEC events
42 #define ENABLE_LOG_ASEC
43
44 #ifdef ENABLE_LOG_ERROR
45 #define LOG_ERROR(fmt, args...) \
46 { LOGE(fmt , ## args); }
47 #else
48 #define LOG_ERROR(fmt, args...) \
49 do { } while (0)
50 #endif /* ENABLE_LOG_ERROR */
51
52 #ifdef ENABLE_LOG_MOUNT
53 #define LOG_MOUNT(fmt, args...) \
54 { LOGD(fmt , ## args); }
55 #else
56 #define LOG_MOUNT(fmt, args...) \
57 do { } while (0)
58 #endif /* ENABLE_LOG_MOUNT */
59
60 #ifdef ENABLE_LOG_SERVER
61 #define LOG_SERVER(fmt, args...) \
62 { LOGD(fmt , ## args); }
63 #else
64 #define LOG_SERVER(fmt, args...) \
65 do { } while (0)
66 #endif /* ENABLE_LOG_SERVER */
67
68 #ifdef ENABLE_LOG_ASEC
69 #define LOG_ASEC(fmt, args...) \
70 { LOGD(fmt , ## args); }
71 #else
72 #define LOG_ASEC(fmt, args...) \
73 do { } while (0)
74 #endif /* ENABLE_LOG_ASEC */
75
76
77 typedef enum MediaState {
78 // no media in SD card slot
79 MEDIA_REMOVED,
80
81 // media in SD card slot, but not mounted
82 MEDIA_UNMOUNTED,
83
84 // media in SD card slot and mounted at its mount point
85 MEDIA_MOUNTED,
86
87 // media in SD card slot, unmounted, and shared as a mass storage device
88 MEDIA_SHARED,
89
90 // media was removed from SD card slot, but mount point was not unmounted
91 // this state is cleared after the mount point is unmounted
92 MEDIA_BAD_REMOVAL,
93
94 // media in SD card slot could not be mounted (corrupt file system?)
95 MEDIA_UNMOUNTABLE,
96 } MediaState;
97
98 // socket name for connecting to mountd
99 #define MOUNTD_SOCKET "mountd"
100
101 // mountd commands
102 // these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
103 #define MOUNTD_ENABLE_UMS "enable_ums"
104 #define MOUNTD_DISABLE_UMS "disable_ums"
105 #define MOUNTD_SEND_STATUS "send_status"
106
107 // these commands should contain a mount point following the colon
108 #define MOUNTD_MOUNT_MEDIA "mount_media:"
109 #define MOUNTD_EJECT_MEDIA "eject_media:"
110
111 // mountd events
112 // these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
113 #define MOUNTD_UMS_ENABLED "ums_enabled"
114 #define MOUNTD_UMS_DISABLED "ums_disabled"
115 #define MOUNTD_UMS_CONNECTED "ums_connected"
116 #define MOUNTD_UMS_DISCONNECTED "ums_disconnected"
117
118 // these events correspond to the states in the MediaState enum.
119 // a path to the mount point follows the colon.
120 #define MOUNTD_MEDIA_REMOVED "media_removed:"
121 #define MOUNTD_MEDIA_UNMOUNTED "media_unmounted:"
122 #define MOUNTD_MEDIA_MOUNTED "media_mounted:"
123 #define MOUNTD_MEDIA_MOUNTED_READ_ONLY "media_mounted_ro:"
124 #define MOUNTD_MEDIA_SHARED "media_shared:"
125 #define MOUNTD_MEDIA_BAD_REMOVAL "media_bad_removal:"
126 #define MOUNTD_MEDIA_UNMOUNTABLE "media_unmountable:"
127
128 // this event sent to request unmount for media mount point
129 #define MOUNTD_REQUEST_EJECT "request_eject:"
130
131 // system properties
132 // these must match the corresponding strings in //device/java/android/android/os/Environment.java
133 #define EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
134 #define EXTERNAL_STORAGE_REMOVED "removed"
135 #define EXTERNAL_STORAGE_UNMOUNTED "unmounted"
136 #define EXTERNAL_STORAGE_MOUNTED "mounted"
137 #define EXTERNAL_STORAGE_MOUNTED_READ_ONLY "mounted_ro"
138 #define EXTERNAL_STORAGE_SHARED "shared"
139 #define EXTERNAL_STORAGE_BAD_REMOVAL "bad_removal"
140 #define EXTERNAL_STORAGE_UNMOUNTABLE "unmountable"
141
142 // AutoMount.c
143
144 boolean IsMassStorageEnabled();
145 boolean IsMassStorageConnected();
146
147 void MountMedia(const char* mountPoint);
148 void UnmountMedia(const char* mountPoint);
149 void EnableMassStorage(boolean enable);
150
151 // call this before StartAutoMounter() to add a mount point to monitor
152 void *AddMountPoint(const char* device, const char* mountPoint, const char* driverStorePath,
153 boolean enableUms);
154
155 int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file,
156 const char *size, const char *mount_point, const char *crypt);
157
158 // start automounter thread
159 void StartAutoMounter();
160
161 // check /proc/mounts for mounted file systems, and notify mount or unmount for any that are in our automount list
162 void NotifyExistingMounts();
163
164
165 // ASEC.c
166
167 void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
168 const char *Size, const char *DstPath, const char *Crypt);
169 int AsecStart(void *Handle);
170 int AsecStop(void *Handle);
171 void AsecDeinit(void *Handle);
172 boolean AsecIsStarted(void *Handle);
173 const char *AsecMountPoint(void *Handle);
174
175 // ProcessKiller.c
176
177 void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
178
179 // logwrapper.c
180 int logwrap(int argc, char* argv[]);
181
182 // Server.c
183
184 int RunServer();
185 void SendMassStorageConnected(boolean connected);
186 void SendUnmountRequest(const char* path);
187 void NotifyMediaState(const char* path, MediaState state, boolean readOnly);
188 void NotifyAsecState(AsecState state, const char *argument);
189 #endif // MOUNTD_H__
+0
-16
netcfg/Android.mk less more
0 ifneq ($(BUILD_TINY_ANDROID),true)
1 LOCAL_PATH:= $(call my-dir)
2
3 include $(CLEAR_VARS)
4 LOCAL_SRC_FILES:= netcfg.c
5 LOCAL_MODULE:= netcfg
6
7 #LOCAL_FORCE_STATIC_EXECUTABLE := true
8 #LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
9 #LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
10 #LOCAL_STATIC_LIBRARIES := libcutils libc
11
12 LOCAL_SHARED_LIBRARIES := libc libnetutils
13
14 include $(BUILD_EXECUTABLE)
15 endif
+0
-0
netcfg/MODULE_LICENSE_APACHE2 less more
(Empty file)
+0
-190
netcfg/NOTICE less more
0
1 Copyright (c) 2005-2008, The Android Open Source Project
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5
6 Unless required by applicable law or agreed to in writing, software
7 distributed under the License is distributed on an "AS IS" BASIS,
8 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 See the License for the specific language governing permissions and
10 limitations under the License.
11
12
13 Apache License
14 Version 2.0, January 2004
15 http://www.apache.org/licenses/
16
17 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
18
19 1. Definitions.
20
21 "License" shall mean the terms and conditions for use, reproduction,
22 and distribution as defined by Sections 1 through 9 of this document.
23
24 "Licensor" shall mean the copyright owner or entity authorized by
25 the copyright owner that is granting the License.
26
27 "Legal Entity" shall mean the union of the acting entity and all
28 other entities that control, are controlled by, or are under common
29 control with that entity. For the purposes of this definition,
30 "control" means (i) the power, direct or indirect, to cause the
31 direction or management of such entity, whether by contract or
32 otherwise, or (ii) ownership of fifty percent (50%) or more of the
33 outstanding shares, or (iii) beneficial ownership of such entity.
34
35 "You" (or "Your") shall mean an individual or Legal Entity
36 exercising permissions granted by this License.
37
38 "Source" form shall mean the preferred form for making modifications,
39 including but not limited to software source code, documentation
40 source, and configuration files.
41
42 "Object" form shall mean any form resulting from mechanical
43 transformation or translation of a Source form, including but
44 not limited to compiled object code, generated documentation,
45 and conversions to other media types.
46
47 "Work" shall mean the work of authorship, whether in Source or
48 Object form, made available under the License, as indicated by a
49 copyright notice that is included in or attached to the work
50 (an example is provided in the Appendix below).
51
52 "Derivative Works" shall mean any work, whether in Source or Object
53 form, that is based on (or derived from) the Work and for which the
54 editorial revisions, annotations, elaborations, or other modifications
55 represent, as a whole, an original work of authorship. For the purposes
56 of this License, Derivative Works shall not include works that remain
57 separable from, or merely link (or bind by name) to the interfaces of,
58 the Work and Derivative Works thereof.
59
60 "Contribution" shall mean any work of authorship, including
61 the original version of the Work and any modifications or additions
62 to that Work or Derivative Works thereof, that is intentionally
63 submitted to Licensor for inclusion in the Work by the copyright owner
64 or by an individual or Legal Entity authorized to submit on behalf of
65 the copyright owner. For the purposes of this definition, "submitted"
66 means any form of electronic, verbal, or written communication sent
67 to the Licensor or its representatives, including but not limited to
68 communication on electronic mailing lists, source code control systems,
69 and issue tracking systems that are managed by, or on behalf of, the
70 Licensor for the purpose of discussing and improving the Work, but
71 excluding communication that is conspicuously marked or otherwise
72 designated in writing by the copyright owner as "Not a Contribution."
73
74 "Contributor" shall mean Licensor and any individual or Legal Entity
75 on behalf of whom a Contribution has been received by Licensor and
76 subsequently incorporated within the Work.
77
78 2. Grant of Copyright License. Subject to the terms and conditions of
79 this License, each Contributor hereby grants to You a perpetual,
80 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81 copyright license to reproduce, prepare Derivative Works of,
82 publicly display, publicly perform, sublicense, and distribute the
83 Work and such Derivative Works in Source or Object form.
84
85 3. Grant of Patent License. Subject to the terms and conditions of
86 this License, each Contributor hereby grants to You a perpetual,
87 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
88 (except as stated in this section) patent license to make, have made,
89 use, offer to sell, sell, import, and otherwise transfer the Work,
90 where such license applies only to those patent claims licensable
91 by such Contributor that are necessarily infringed by their
92 Contribution(s) alone or by combination of their Contribution(s)
93 with the Work to which such Contribution(s) was submitted. If You
94 institute patent litigation against any entity (including a
95 cross-claim or counterclaim in a lawsuit) alleging that the Work
96 or a Contribution incorporated within the Work constitutes direct
97 or contributory patent infringement, then any patent licenses
98 granted to You under this License for that Work shall terminate
99 as of the date such litigation is filed.
100
101 4. Redistribution. You may reproduce and distribute copies of the
102 Work or Derivative Works thereof in any medium, with or without
103 modifications, and in Source or Object form, provided that You
104 meet the following conditions:
105
106 (a) You must give any other recipients of the Work or
107 Derivative Works a copy of this License; and
108
109 (b) You must cause any modified files to carry prominent notices
110 stating that You changed the files; and
111
112 (c) You must retain, in the Source form of any Derivative Works
113 that You distribute, all copyright, patent, trademark, and
114 attribution notices from the Source form of the Work,
115 excluding those notices that do not pertain to any part of
116 the Derivative Works; and
117
118 (d) If the Work includes a "NOTICE" text file as part of its
119 distribution, then any Derivative Works that You distribute must
120 include a readable copy of the attribution notices contained
121 within such NOTICE file, excluding those notices that do not
122 pertain to any part of the Derivative Works, in at least one
123 of the following places: within a NOTICE text file distributed
124 as part of the Derivative Works; within the Source form or
125 documentation, if provided along with the Derivative Works; or,
126 within a display generated by the Derivative Works, if and
127 wherever such third-party notices normally appear. The contents
128 of the NOTICE file are for informational purposes only and
129 do not modify the License. You may add Your own attribution
130 notices within Derivative Works that You distribute, alongside
131 or as an addendum to the NOTICE text from the Work, provided
132 that such additional attribution notices cannot be construed
133 as modifying the License.
134
135 You may add Your own copyright statement to Your modifications and
136 may provide additional or different license terms and conditions
137 for use, reproduction, or distribution of Your modifications, or
138 for any such Derivative Works as a whole, provided Your use,
139 reproduction, and distribution of the Work otherwise complies with
140 the conditions stated in this License.
141
142 5. Submission of Contributions. Unless You explicitly state otherwise,
143 any Contribution intentionally submitted for inclusion in the Work
144 by You to the Licensor shall be under the terms and conditions of
145 this License, without any additional terms or conditions.
146 Notwithstanding the above, nothing herein shall supersede or modify
147 the terms of any separate license agreement you may have executed
148 with Licensor regarding such Contributions.
149
150 6. Trademarks. This License does not grant permission to use the trade
151 names, trademarks, service marks, or product names of the Licensor,
152 except as required for reasonable and customary use in describing the
153 origin of the Work and reproducing the content of the NOTICE file.
154
155 7. Disclaimer of Warranty. Unless required by applicable law or
156 agreed to in writing, Licensor provides the Work (and each
157 Contributor provides its Contributions) on an "AS IS" BASIS,
158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
159 implied, including, without limitation, any warranties or conditions
160 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
161 PARTICULAR PURPOSE. You are solely responsible for determining the
162 appropriateness of using or redistributing the Work and assume any
163 risks associated with Your exercise of permissions under this License.
164
165 8. Limitation of Liability. In no event and under no legal theory,
166 whether in tort (including negligence), contract, or otherwise,
167 unless required by applicable law (such as deliberate and grossly
168 negligent acts) or agreed to in writing, shall any Contributor be
169 liable to You for damages, including any direct, indirect, special,
170 incidental, or consequential damages of any character arising as a
171 result of this License or out of the use or inability to use the
172 Work (including but not limited to damages for loss of goodwill,
173 work stoppage, computer failure or malfunction, or any and all
174 other commercial damages or losses), even if such Contributor
175 has been advised of the possibility of such damages.
176
177 9. Accepting Warranty or Additional Liability. While redistributing
178 the Work or Derivative Works thereof, You may choose to offer,
179 and charge a fee for, acceptance of support, warranty, indemnity,
180 or other liability obligations and/or rights consistent with this
181 License. However, in accepting such obligations, You may act only
182 on Your own behalf and on Your sole responsibility, not on behalf
183 of any other Contributor, and only if You agree to indemnify,
184 defend, and hold each Contributor harmless for any liability
185 incurred by, or claims asserted against, such Contributor by reason
186 of your accepting any such warranty or additional liability.
187
188 END OF TERMS AND CONDITIONS
189
+0
-175
netcfg/netcfg.c less more
0 /* system/bin/netcfg/netcfg.c
1 **
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <dirent.h>
21
22 static int verbose = 0;
23
24 int ifc_init();
25 void ifc_close();
26 int ifc_up(char *iname);
27 int ifc_down(char *iname);
28 int ifc_remove_host_routes(char *iname);
29 int ifc_remove_default_route(char *iname);
30 int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
31 int do_dhcp(char *iname);
32
33 void die(const char *reason)
34 {
35 perror(reason);
36 exit(1);
37 }
38
39 const char *ipaddr(unsigned addr)
40 {
41 static char buf[32];
42
43 sprintf(buf,"%d.%d.%d.%d",
44 addr & 255,
45 ((addr >> 8) & 255),
46 ((addr >> 16) & 255),
47 (addr >> 24));
48 return buf;
49 }
50
51 void usage(void)
52 {
53 fprintf(stderr,"usage: netcfg [<interface> {dhcp|up|down}]\n");
54 exit(1);
55 }
56
57 int dump_interface(const char *name)
58 {
59 unsigned addr, mask, flags;
60
61 if(ifc_get_info(name, &addr, &mask, &flags)) {
62 return 0;
63 }
64
65 printf("%-8s %s ", name, flags & 1 ? "UP " : "DOWN");
66 printf("%-16s", ipaddr(addr));
67 printf("%-16s", ipaddr(mask));
68 printf("0x%08x\n", flags);
69 return 0;
70 }
71
72 int dump_interfaces(void)
73 {
74 DIR *d;
75 struct dirent *de;
76
77 d = opendir("/sys/class/net");
78 if(d == 0) return -1;
79
80 while((de = readdir(d))) {
81 if(de->d_name[0] == '.') continue;
82 dump_interface(de->d_name);
83 }
84 closedir(d);
85 return 0;
86 }
87
88 struct
89 {
90 const char *name;
91 int nargs;
92 void *func;
93 } CMDS[] = {
94 { "dhcp", 1, do_dhcp },
95 { "up", 1, ifc_up },
96 { "down", 1, ifc_down },
97 { "flhosts", 1, ifc_remove_host_routes },
98 { "deldefault", 1, ifc_remove_default_route },
99 { 0, 0, 0 },
100 };
101
102 static int call_func(void *_func, unsigned nargs, char **args)
103 {
104 switch(nargs){
105 case 1: {
106 int (*func)(char *a0) = _func;
107 return func(args[0]);
108 }
109 case 2: {
110 int (*func)(char *a0, char *a1) = _func;
111 return func(args[0], args[1]);
112 }
113 case 3: {
114 int (*func)(char *a0, char *a1, char *a2) = _func;
115 return func(args[0], args[1], args[2]);
116 }
117 default:
118 return -1;
119 }
120 }
121
122 int main(int argc, char **argv)
123 {
124 char *iname;
125 int n;
126
127 if(ifc_init()) {
128 die("Cannot perform requested operation");
129 }
130
131 if(argc == 1) {
132 int result = dump_interfaces();
133 ifc_close();
134 return result;
135 }
136
137 if(argc < 3) usage();
138
139 iname = argv[1];
140 if(strlen(iname) > 16) usage();
141
142 argc -= 2;
143 argv += 2;
144 while(argc > 0) {
145 for(n = 0; CMDS[n].name; n++){
146 if(!strcmp(argv[0], CMDS[n].name)) {
147 char *cmdname = argv[0];
148 int nargs = CMDS[n].nargs;
149
150 argv[0] = iname;
151 if(argc < nargs) {
152 fprintf(stderr, "not enough arguments for '%s'\n", cmdname);
153 ifc_close();
154 exit(1);
155 }
156 if(call_func(CMDS[n].func, nargs, argv)) {
157 fprintf(stderr, "action '%s' failed (%s)\n", cmdname, strerror(errno));
158 ifc_close();
159 exit(1);
160 }
161 argc -= nargs;
162 argv += nargs;
163 goto done;
164 }
165 }
166 fprintf(stderr,"no such action '%s'\n", argv[0]);
167 usage();
168 done:
169 ;
170 }
171 ifc_close();
172
173 return 0;
174 }
+0
-58
rootdir/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 # files that live under /system/etc/...
4
5 copy_from := \
6 etc/dbus.conf \
7 etc/init.goldfish.sh \
8 etc/hosts
9
10 dont_copy := \
11 etc/init.gprs-pppd \
12 etc/ppp/chap-secrets \
13 etc/ppp/ip-down \
14 etc/ppp/ip-up
15
16 copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from))
17 copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from))
18
19 $(copy_to) : PRIVATE_MODULE := system_etcdir
20 $(copy_to) : $(TARGET_OUT)/% : $(LOCAL_PATH)/% | $(ACP)
21 $(transform-prebuilt-to-target)
22
23 ALL_PREBUILT += $(copy_to)
24
25
26 # files that live under /...
27
28 # Only copy init.rc if the target doesn't have its own.
29 ifneq ($(TARGET_PROVIDES_INIT_RC),true)
30 file := $(TARGET_ROOT_OUT)/init.rc
31 $(file) : $(LOCAL_PATH)/init.rc | $(ACP)
32 $(transform-prebuilt-to-target)
33 ALL_PREBUILT += $(file)
34 endif
35
36 file := $(TARGET_ROOT_OUT)/init.goldfish.rc
37 $(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP)
38 $(transform-prebuilt-to-target)
39 ALL_PREBUILT += $(file)
40
41
42 # create some directories (some are mount points)
43 DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \
44 sbin \
45 dev \
46 proc \
47 sys \
48 system \
49 data \
50 ) \
51 $(TARGET_OUT_DATA)
52
53 $(DIRS):
54 @echo Directory: $@
55 @mkdir -p $@
56
57 ALL_PREBUILT += $(DIRS)
+0
-27
rootdir/etc/dbus.conf less more
0 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
1 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
2 <busconfig>
3
4 <!-- Our well-known bus type, do not change this -->
5 <type>system</type>
6
7 <!-- Only allow socket-credentials-based authentication -->
8 <auth>EXTERNAL</auth>
9
10 <!-- Only listen on a local socket. (abstract=/path/to/socket
11 means use abstract namespace, don't really create filesystem
12 file; only Linux supports this. Use path=/whatever on other
13 systems.) -->
14 <listen>unix:path=/dev/socket/dbus</listen>
15
16 <!-- Allow everything, D-Bus socket is protected by unix filesystem
17 permissions -->
18 <policy context="default">
19 <allow send_interface="*"/>
20 <allow receive_interface="*"/>
21 <allow own="*"/>
22 <allow user="*"/>
23 <allow send_requested_reply="true"/>
24 <allow receive_requested_reply="true"/>
25 </policy>
26 </busconfig>
+0
-1
rootdir/etc/hosts less more
0 127.0.0.1 localhost
+0
-54
rootdir/etc/init.goldfish.rc less more
0 on boot
1 setprop ARGH ARGH
2 setprop net.eth0.dns1 10.0.2.3
3 setprop net.gprs.local-ip 10.0.2.15
4 setprop ro.radio.use-ppp no
5 setprop ro.build.product generic
6 setprop ro.product.device generic
7
8 # fake some battery state
9 setprop status.battery.state Slow
10 setprop status.battery.level 5
11 setprop status.battery.level_raw 50
12 setprop status.battery.level_scale 9
13
14 # disable some daemons the emulator doesn't want
15 stop dund
16 stop akmd
17
18 setprop ro.setupwizard.mode EMULATOR
19
20 # enable Google-specific location features,
21 # like NetworkLocationProvider and LocationCollector
22 setprop ro.com.google.locationfeatures 1
23
24 # For the emulator, which bypasses Setup Wizard, you can specify
25 # account info for the device via these two properties. Google
26 # Login Service will insert these accounts into the database when
27 # it is created (ie, after a data wipe).
28 #
29 # setprop ro.config.hosted_account username@hosteddomain.org:password
30 # setprop ro.config.google_account username@gmail.com:password
31 #
32 # You MUST have a Google account on the device, and you MAY
33 # additionally have a hosted account. No other configuration is
34 # supported, and arbitrary breakage may result if you specify
35 # something else.
36
37 service goldfish-setup /system/etc/init.goldfish.sh
38 oneshot
39
40 service qemud /system/bin/qemud
41 socket qemud_gsm stream 666
42 socket qemud_gps stream 666
43 socket qemud_control stream 666
44 oneshot
45
46 # -Q is a special logcat option that forces the
47 # program to check wether it runs on the emulator
48 # if it does, it redirects its output to the device
49 # named by the androidboot.console kernel option
50 # if not, is simply exit immediately
51
52 service goldfish-logcat /system/bin/logcat -Q
53 oneshot
+0
-39
rootdir/etc/init.goldfish.sh less more
0 #!/system/bin/sh
1
2 ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
3 route add default gw 10.0.2.2 dev eth0
4
5 qemud=`getprop.ro.kernel.android.qemud`
6 if test -z "$qemud"; then
7 radio_ril=`getprop ro.kernel.android.ril`
8 if test -z "$radio_ril"; then
9 # no need for the radio interface daemon
10 # telephony is entirely emulated in Java
11 setprop ro.radio.noril yes
12 stop ril-daemon
13 fi
14 fi
15
16 num_dns=`getprop ro.kernel.android.ndns`
17 case "$num_dns" in
18 2) setprop net.eth0.dns2 10.0.2.4
19 ;;
20 3) setprop net.eth0.dns2 10.0.2.4
21 setprop net.eth0.dns3 10.0.2.5
22 ;;
23 4) setprop net.eth0.dns2 10.0.2.4
24 setprop net.eth0.dns3 10.0.2.5
25 setprop net.eth0.dns4 10.0.2.6
26 ;;
27 esac
28
29 # disable boot animation for a faster boot sequence when needed
30 boot_anim=`getprop ro.kernel.android.bootanim`
31 case "$boot_anim" in
32 0) setprop debug.sf.nobootanimation 1
33 ;;
34 esac
35
36 # this line doesn't really do anything useful. however without it the
37 # previous setprop doesn't seem to apply for some really odd reason
38 setprop ro.qemu.init.completed 1
+0
-23
rootdir/etc/init.gprs-pppd less more
0 #!/system/bin/sh
1 # An unforunate wrapper script
2 # so that the exit code of pppd may be retrieved
3
4
5 # this is a workaround for issue #651747
6 #trap "/system/bin/sleep 1;exit 0" TERM
7
8
9 PPPD_PID=
10
11 /system/bin/setprop "net.gprs.ppp-exit" ""
12
13 /system/bin/log -t pppd "Starting pppd"
14
15 /system/bin/pppd $*
16
17 PPPD_EXIT=$?
18 PPPD_PID=$!
19
20 /system/bin/log -t pppd "pppd exited with $PPPD_EXIT"
21
22 /system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"
+0
-322
rootdir/etc/init.testmenu less more
0 #!/system/bin/sh
1
2 atdev=/dev/omap_csmi_tty0
3 pppdev=/dev/omap_csmi_tty1
4
5 n1=`cat /data/phoneentry1 2>/dev/null`
6 n2=`cat /data/phoneentry2 2>/dev/null`
7 n3=`cat /data/phoneentry3 2>/dev/null`
8 n1=${n1:-"*#06#"}
9 n2=${n2:-"*#06#"}
10 n3=${n3:-"*#06#"}
11 phoneoutputpid=
12 eventoutputpid=
13 notifypid=
14 notifytoggle=false
15 pppdpid=
16 powerdidletime=120
17
18 # map phone specific keys
19 setkey -k 0xe4 -v 0x23 # map #
20 setkey -k 0xe3 -v 0x2a # map *
21 setkey -k 231 -v 513 # map send to newline
22 #setkey -k 0x67 -v 0x20b # map up to scroll back
23 #setkey -k 0x6c -v 0x20a # map down to scroll forward
24 setkey -k 0x73 -v 0x20b # map volume up to scroll back
25 setkey -k 0x72 -v 0x20a # map volume down to scroll forward
26 setkey -k 0x60 -v 0x211 # map PoC to next console
27
28 # tuttle keys
29 setkey -k 0x38 -v 0x703 # map leftalt to alt
30 setkey -k 0x9b -v 0x703 # map mail to alt
31 setkey -t 8 -k 0x9b -v 0x703 # map alt-mail to alt
32 setkey -t 8 -k 0x10 -v 0x21 # map alt-q to !
33 setkey -t 8 -k 0x11 -v 0x31 # map alt-w to 1
34 setkey -t 8 -k 0x12 -v 0x32 # map alt-e to 2
35 setkey -t 8 -k 0x13 -v 0x33 # map alt-r to 3
36 setkey -t 8 -k 0x14 -v 0x2b # map alt-t to +
37 setkey -t 8 -k 0x15 -v 0x28 # map alt-y to (
38 setkey -t 8 -k 0x16 -v 0x29 # map alt-u to )
39 setkey -t 8 -k 0x17 -v 0x2d # map alt-i to -
40 setkey -t 8 -k 0x18 -v 0x5f # map alt-o to _
41 setkey -t 8 -k 0x19 -v 0x22 # map alt-p to "
42 setkey -t 8 -k 0x1e -v 0x23 # map alt-a to #
43 setkey -t 8 -k 0x1f -v 0x34 # map alt-s to 4
44 setkey -t 8 -k 0x20 -v 0x35 # map alt-d to 5
45 setkey -t 8 -k 0x21 -v 0x36 # map alt-f to 6
46 setkey -t 8 -k 0x22 -v 0x2f # map alt-g to /
47 setkey -t 8 -k 0x23 -v 0x3f # map alt-h to ?
48 setkey -t 8 -k 0x24 -v 0xa3 # map alt-j to pound
49 setkey -t 8 -k 0x25 -v 0x24 # map alt-k to $
50 setkey -t 8 -k 0x2c -v 0x2a # map alt-z to *
51 setkey -t 8 -k 0x2d -v 0x37 # map alt-x to 7
52 setkey -t 8 -k 0x2e -v 0x38 # map alt-c to 8
53 setkey -t 8 -k 0x2f -v 0x39 # map alt-v to 9
54 setkey -t 8 -k 0x30 -v 0x7c # map alt-b to |
55 setkey -t 8 -k 0x31 -v 0x40 # map alt-n to @
56 setkey -t 8 -k 0x32 -v 0x3d # map alt-m to =
57 setkey -t 8 -k 0x33 -v 0x3b # map alt-, to ;
58 setkey -t 8 -k 0x34 -v 0x3a # map alt-. to :
59 setkey -t 8 -k 0x0f -v 0x30 # map alt-tab to 0
60 setkey -t 8 -k 0x67 -v 0x20b # map alt-up to scroll back
61 setkey -t 8 -k 0x6c -v 0x20a # map alt-down to scroll forward
62
63 while true
64 do
65 echo
66 echo "------------------------------"
67 echo " 1: init commands"
68 echo " 2: call commands"
69 echo " 3: misc phone"
70 echo " 4: phone debug output"
71 echo " 5: test data connection"
72 echo " 6: start runtime"
73 echo " 7: start runtime w/output"
74 echo " 8: stop runtime"
75 echo " 9: misc"
76 echo -n ": "
77 while true
78 do
79 c=`readtty -t 50 -f -a 1234567890#`
80 case "$c" in
81 "" ) ;;
82 * ) break;
83 esac
84 done
85 echo Got key -$c-
86 case $c in
87 "1" )
88 while true; do
89 echo
90 echo "------------------------------"
91 echo " 1: Print phone output"
92 echo " 2: ATQ0V1E1+CMEE=2;+CREG=0"
93 echo " 3: AT+CFUN=1"
94 echo " 4: AT+COPS=0"
95 echo " 5: AT+CREG?"
96 echo " 6: Stop phone output"
97 echo " 0: back"
98 echo -n ": "
99 c=`readtty -f -a 1234560#`
100 echo Got key -$c-
101 case "$c" in
102 "1" ) kill $phoneoutputpid; cat $atdev & phoneoutputpid=$! ;;
103 "2" ) echo -e "ATQ0V1E1+CMEE=2;+CREG=0\r" >$atdev;;
104 "3" ) echo -e "AT+CFUN=1\r" >$atdev;;
105 "4" ) echo -e "AT+COPS=0\r" >$atdev;;
106 "5" ) echo -e "AT+CREG?\r" >$atdev;;
107 "6" ) kill $phoneoutputpid; phoneoutputpid= ;;
108 "0" ) break;;
109 esac
110 done
111 ;;
112 "2" )
113 while true; do
114 echo
115 echo "------------------------------"
116 echo " 1: Dial: ATD $n1;"
117 echo " 2: Dial: ATD $n2;"
118 echo " 3: Dial: ATD $n3;"
119 echo " 4: Set number for 1"
120 echo " 5: Set number for 2"
121 echo " 6: Set number for 3"
122 echo " 7: Dial: ATD ...;"
123 echo " 8: Hang up: ATH"
124 echo " 9: Answer: ATA"
125 echo " 0: back"
126 echo -n ": "
127 c=`readtty -f -a 1234567890#`
128 echo Got key -$c-
129 case "$c" in
130 "1" ) echo "Dialing $n1"; echo -e "ATD $n1;\r" >$atdev;;
131 "2" ) echo "Dialing $n2"; echo -e "ATD $n2;\r" >$atdev;;
132 "3" ) echo "Dialing $n3"; echo -e "ATD $n3;\r" >$atdev;;
133 "4" ) echo -n "Number: "; read n1; echo $n1 >/data/phoneentry1;;
134 "5" ) echo -n "Number: "; read n2; echo $n2 >/data/phoneentry2;;
135 "6" ) echo -n "Number: "; read n3; echo $n3 >/data/phoneentry3;;
136 "7" ) echo -n "Number: "; read n; echo "Dialing $n"; echo -e "ATD $n;\r" >$atdev;;
137 "8" ) echo -e "ATH\r" >$atdev;;
138 "9" ) echo -e "ATA\r" >$atdev;;
139 "0" ) break;;
140 esac
141 done
142 ;;
143 "3" )
144 while true; do
145 echo
146 echo "------------------------------"
147 echo " 1: Save FFS data"
148 echo " 2: Load user FFS data"
149 echo " 3: Load system FFS data"
150 echo " 4: Reset FFS data"
151 echo " 5: Set uplink gain"
152 echo " 6: Set echo"
153 echo " 7: cat /dev/omap_csmi_battery_t"
154 echo " 8: cat /dev/omap_csmi_htc"
155 echo " 0: back"
156 echo -n ": "
157 c=`readtty -f -a 123456780#`
158 echo Got key -$c-
159 case "$c" in
160 "1" ) cat /dev/omap_csmi_ffs >/data/ffsdata;;
161 "2" ) cat /data/ffsdata >/dev/omap_csmi_ffs;;
162 "3" ) cat /system/ffsdata >/dev/omap_csmi_ffs;;
163 "4" ) echo - >/dev/omap_csmi_ffs;;
164 "5" )
165 echo -n "Gain: "; read g;
166 echo gu$g >/tmp/gain;
167 cat /tmp/gain 2>/dev/null >/dev/omap_csmi_audio_tes
168 ;;
169 "6" )
170 echo -n "Echo param (hex): "; read e;
171 echo "e0x$e" >/tmp/echo;
172 cat /tmp/echo 2>/dev/null >/dev/omap_csmi_audio_tes
173 ;;
174 "7" ) cat /dev/omap_csmi_battery_t;;
175 "8" ) cat /dev/omap_csmi_htc;;
176 "0" ) break;;
177 esac
178 done
179 ;;
180 "4" )
181 while true; do
182 echo
183 echo "------------------------------"
184 echo " 1: Toggle debug I/O"
185 echo " 2: Toggle debug Flow"
186 echo " 3: Toggle debug Interrupt"
187 echo " 4: Toggle debug Info"
188 echo " 5: Toggle GSM run state"
189 echo " 6: Clear GSM data area"
190 echo " 0: back"
191 echo -n ": "
192 c=`readtty -f -a 1234560#`
193 echo Got key -$c-
194 case "$c" in
195 "1" ) echo -n "i" >/sys/devices/system/omap_csmi/debug;;
196 "2" ) echo -n "f" >/sys/devices/system/omap_csmi/debug;;
197 "3" ) echo -n "I" >/sys/devices/system/omap_csmi/debug;;
198 "4" ) echo -n "F" >/sys/devices/system/omap_csmi/debug;;
199 "5" ) echo -n "s" >/sys/devices/system/omap_csmi/debug;;
200 "6" ) echo -n "c" >/sys/devices/system/omap_csmi/debug;;
201 "0" ) break;;
202 esac
203 done
204 ;;
205 "5" )
206 while true; do
207 echo
208 echo "------------------------------"
209 echo " 1: Start pppd - userspace"
210 echo " 2: Start pppd - kernel"
211 echo " 3: Start pppd - kernel <at1"
212 echo " 4: Configure ppp data to at2"
213 echo " 5: Test with HTTP GET"
214 echo " 6: Kill pppd"
215 echo " 0: back"
216 echo -n ": "
217 c=`readtty -f -a 1234560#`
218 echo Got key -$c-
219 case "$c" in
220 "1" ) kill $pppdpid; pppd notty < $pppdev > $pppdev & pppdpid=$!;;
221 "2" ) kill $pppdpid; pppd nodetach $pppdev & pppdpid=$!;;
222 "3" ) kill &pppdpid; pppd nodetach $pppdev connect "sh -c \"chat -v -f /etc/ppp/connect-data <$atdev >$atdev\"" & pppdpid=$!;;
223 "4" ) echo -e 'AT%DATA=2,"UART",1,,"SER","UART",0\r' >$atdev;;
224 "5" ) test-data-connection;;
225 "6" ) kill $pppdpid; pppdpid=;;
226 "0" ) break;;
227 esac
228 done
229 ;;
230 "6" )
231 echo
232 echo ------------------------
233 echo Starting android runtime
234 echo ------------------------
235 start
236 ;;
237 "7" )
238 echo
239 echo ------------------------
240 echo Starting android runtime
241 echo ------------------------
242 if exists /data/singleproc
243 then
244 single_process="-s"
245 else
246 single_process=""
247 fi
248 start runtime $single_process
249 ;;
250 "8" )
251 stop
252 ;;
253 "9" )
254 while true; do
255 echo
256 echo "------------------------------"
257 echo " 1: Print events"
258 echo " 2: Stop event output"
259 if $notifytoggle
260 then
261 echo " 3: stop notify"
262 else
263 echo " 3: notify /sys/android_power"
264 fi
265 echo " 4: start powerd"
266 echo " 5: start powerd verbose"
267 echo " 6: stop powerd"
268 echo " 7: set powerd idletime ($powerdidletime)"
269 echo " 8: start multitap shell"
270 if exists /data/singleproc
271 then
272 echo " 9: enable multiprocess"
273 else
274 echo " 9: disable multiprocess"
275 fi
276 echo " c: start shell"
277 echo " 0: back"
278 echo -n ": "
279 c=`readtty -f -a 1234567890c#`
280 echo Got key -$c-
281 case "$c" in
282 "1" ) kill $eventoutputpid; getevent & eventoutputpid=$! ;;
283 "2" ) kill $eventoutputpid; eventoutputpid= ;;
284 "3" )
285 if $notifytoggle
286 then
287 kill $notifypid
288 notifypid=
289 notifytoggle=false
290 else
291 kill $notifypid
292 notify -m 0x00000002 -c 0 -p -v 0 -w 30 /sys/android_power &
293 notifypid=$!
294 notifytoggle=true
295 fi
296 ;;
297 "4" ) start powerd -i $powerdidletime ;;
298 "5" ) start powerd -i $powerdidletime -v ;;
299 "6" ) stop powerd ;;
300 "7" ) echo -n "Idle time (seconds): "; read powerdidletime ;;
301 "8" )
302 readtty -f -p -t 10 -e "[ ~" | sh -i
303 ;;
304 "9" )
305 if exists /data/singleproc
306 then
307 echo "Enabling multiprocess environment."
308 rm /data/singleproc
309 else
310 echo "Disabling multiprocess environment."
311 echo >/data/singleproc "true"
312 fi
313 ;;
314 "c" ) sh -i <>/dev/tty0 1>&0 2>&1 ;;
315 "0" ) break;;
316 esac
317 done
318 ;;
319 esac
320 done
321
+0
-19
rootdir/etc/mountd.conf less more
0 ## mountd configuration file
1
2 ## add a mount entry for each mount point to be managed by mountd
3 mount {
4 ## root block device with partition map or raw FAT file system
5 block_device /dev/block/mmcblk0
6
7 ## mount point for block device
8 mount_point /sdcard
9
10 ## true if this mount point can be shared via USB mass storage
11 enable_ums true
12
13 ## path to the UMS driver file for specifying the block device path
14 ## use this for the mass_storage function driver
15 driver_store_path /sys/devices/platform/usb_mass_storage/lun0/file
16 ## use this for android_usb composite gadget driver
17 ##driver_store_path /sys/devices/platform/msm_hsusb/gadget/lun0/file
18 }
+0
-2
rootdir/etc/ppp/chap-secrets less more
0 * * bogus
1
+0
-14
rootdir/etc/ppp/ip-down less more
0 #!/system/bin/sh
1 case $1 in
2 ppp1)
3 echo 0 > /proc/sys/net/ipv4/ip_forward;
4 ;;
5 esac
6
7 # Use interface name if linkname is not available
8 NAME=${LINKNAME:-"$1"}
9
10 /system/bin/setprop "net.$NAME.dns1" "$DNS1"
11 /system/bin/setprop "net.$NAME.dns2" "$DNS2"
12 /system/bin/setprop "net.$NAME.local-ip" "$IPLOCAL"
13 /system/bin/setprop "net.$NAME.remote-ip" "$IPREMOTE"
+0
-24
rootdir/etc/ppp/ip-up less more
0 #!/system/bin/sh
1 case $1 in
2 ppp1)
3 /android/bin/iptables --flush;
4 /android/bin/iptables --table nat --flush;
5 /android/bin/iptables --delete-chain;
6 /android/bin/iptables --table nat --append POSTROUTING --out-interface ppp0 -j MASQUERADE;
7 /android/bin/iptables --append FORWARD --in-interface ppp1 -j ACCEPT;
8 echo 0 > /proc/sys/net/ipv4/ip_forward;
9 echo 1 > /proc/sys/net/ipv4/ip_forward;
10 ;;
11 ppp0)
12 /system/bin/setprop "net.interfaces.defaultroute" "gprs"
13 ;;
14 esac
15
16 # Use interface name if linkname is not available
17 NAME=${LINKNAME:-"$1"}
18
19 /system/bin/setprop "net.$NAME.dns1" "$DNS1"
20 /system/bin/setprop "net.$NAME.dns2" "$DNS2"
21 /system/bin/setprop "net.$NAME.local-ip" "$IPLOCAL"
22 /system/bin/setprop "net.$NAME.remote-ip" "$IPREMOTE"
23
+0
-245
rootdir/init.rc less more
0
1 on init
2
3 sysclktz 0
4
5 loglevel 3
6
7 # setup the global environment
8 export PATH /sbin:/system/sbin:/system/bin:/system/xbin
9 export LD_LIBRARY_PATH /system/lib
10 export ANDROID_BOOTLOGO 1
11 export ANDROID_ROOT /system
12 export ANDROID_ASSETS /system/app
13 export ANDROID_DATA /data
14 export EXTERNAL_STORAGE /sdcard
15 export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar
16
17 # Backward compatibility
18 symlink /system/etc /etc
19
20 # create mountpoints and mount tmpfs on sqlite_stmt_journals
21 mkdir /sdcard 0000 system system
22 mkdir /system
23 mkdir /data 0771 system system
24 mkdir /cache 0770 system cache
25 mkdir /sqlite_stmt_journals 01777 root root
26 mount tmpfs tmpfs /sqlite_stmt_journals size=4m
27
28 mount rootfs rootfs / ro remount
29
30 write /proc/sys/kernel/panic_on_oops 1
31 write /proc/sys/kernel/hung_task_timeout_secs 0
32 write /proc/cpu/alignment 4
33 write /proc/sys/kernel/sched_latency_ns 10000000
34 write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
35
36 # mount mtd partitions
37 # Mount /system rw first to give the filesystem a chance to save a checkpoint
38 mount yaffs2 mtd@system /system
39 mount yaffs2 mtd@system /system ro remount
40
41 # We chown/chmod /data again so because mount is run as root + defaults
42 mount yaffs2 mtd@userdata /data nosuid nodev
43 chown system system /data
44 chmod 0771 /data
45
46 # Same reason as /data above
47 mount yaffs2 mtd@cache /cache nosuid nodev
48 chown system cache /cache
49 chmod 0770 /cache
50
51 # This may have been created by the recovery system with odd permissions
52 chown system system /cache/recovery
53 chmod 0770 /cache/recovery
54
55 # create basic filesystem structure
56 mkdir /data/misc 01771 system misc
57 mkdir /data/misc/hcid 0770 bluetooth bluetooth
58 mkdir /data/local 0771 shell shell
59 mkdir /data/local/tmp 0771 shell shell
60 mkdir /data/data 0771 system system
61 mkdir /data/app-private 0771 system system
62 mkdir /data/app 0771 system system
63 mkdir /data/property 0700 root root
64
65 # create dalvik-cache and double-check the perms
66 mkdir /data/dalvik-cache 0771 system system
67 chown system system /data/dalvik-cache
68 chmod 0771 /data/dalvik-cache
69
70 # create the lost+found directories, so as to enforce our permissions
71 mkdir /data/lost+found 0770
72 mkdir /cache/lost+found 0770
73
74 # double check the perms, in case lost+found already exists, and set owner
75 chown root root /data/lost+found
76 chmod 0770 /data/lost+found
77 chown root root /cache/lost+found
78 chmod 0770 /cache/lost+found
79
80 on boot
81 # basic network init
82 ifup lo
83 hostname localhost
84 domainname localdomain
85
86 # set RLIMIT_NICE to allow priorities from 19 to -20
87 setrlimit 13 40 40
88
89 # Define the oom_adj values for the classes of processes that can be
90 # killed by the kernel. These are used in ActivityManagerService.
91 setprop ro.FOREGROUND_APP_ADJ 0
92 setprop ro.VISIBLE_APP_ADJ 1
93 setprop ro.SECONDARY_SERVER_ADJ 2
94 setprop ro.HIDDEN_APP_MIN_ADJ 7
95 setprop ro.CONTENT_PROVIDER_ADJ 14
96 setprop ro.EMPTY_APP_ADJ 15
97
98 # Define the memory thresholds at which the above process classes will
99 # be killed. These numbers are in pages (4k).
100 setprop ro.FOREGROUND_APP_MEM 1536
101 setprop ro.VISIBLE_APP_MEM 2048
102 setprop ro.SECONDARY_SERVER_MEM 4096
103 setprop ro.HIDDEN_APP_MEM 5120
104 setprop ro.CONTENT_PROVIDER_MEM 5632
105 setprop ro.EMPTY_APP_MEM 6144
106
107 # Write value must be consistent with the above properties.
108 write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
109
110 write /proc/sys/vm/overcommit_memory 1
111 write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144
112
113 # Set init its forked children's oom_adj.
114 write /proc/1/oom_adj -16
115
116 # Permissions for System Server and daemons.
117 chown radio system /sys/android_power/state
118 chown radio system /sys/android_power/request_state
119 chown radio system /sys/android_power/acquire_full_wake_lock
120 chown radio system /sys/android_power/acquire_partial_wake_lock
121 chown radio system /sys/android_power/release_wake_lock
122 chown radio system /sys/power/state
123 chown radio system /sys/power/wake_lock
124 chown radio system /sys/power/wake_unlock
125 chmod 0660 /sys/power/state
126 chmod 0660 /sys/power/wake_lock
127 chmod 0660 /sys/power/wake_unlock
128 chown system system /sys/class/timed_output/vibrator/enable
129 chown system system /sys/class/leds/keyboard-backlight/brightness
130 chown system system /sys/class/leds/lcd-backlight/brightness
131 chown system system /sys/class/leds/button-backlight/brightness
132 chown system system /sys/class/leds/red/brightness
133 chown system system /sys/class/leds/green/brightness
134 chown system system /sys/class/leds/blue/brightness
135 chown system system /sys/class/leds/red/device/grpfreq
136 chown system system /sys/class/leds/red/device/grppwm
137 chown system system /sys/class/leds/red/device/blink
138 chown system system /sys/class/leds/red/brightness
139 chown system system /sys/class/leds/green/brightness
140 chown system system /sys/class/leds/blue/brightness
141 chown system system /sys/class/leds/red/device/grpfreq
142 chown system system /sys/class/leds/red/device/grppwm
143 chown system system /sys/class/leds/red/device/blink
144 chown system system /sys/class/timed_output/vibrator/enable
145 chown system system /sys/module/sco/parameters/disable_esco
146 chown system system /sys/kernel/ipv4/tcp_wmem_min
147 chown system system /sys/kernel/ipv4/tcp_wmem_def
148 chown system system /sys/kernel/ipv4/tcp_wmem_max
149 chown system system /sys/kernel/ipv4/tcp_rmem_min
150 chown system system /sys/kernel/ipv4/tcp_rmem_def
151 chown system system /sys/kernel/ipv4/tcp_rmem_max
152 chown root radio /proc/cmdline
153
154 # Define TCP buffer sizes for various networks
155 # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
156 setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
157 setprop net.tcp.buffersize.wifi 4095,87380,110208,4096,16384,110208
158 setprop net.tcp.buffersize.umts 4094,87380,110208,4096,16384,110208
159 setprop net.tcp.buffersize.edge 4093,26280,35040,4096,16384,35040
160 setprop net.tcp.buffersize.gprs 4092,8760,11680,4096,8760,11680
161
162 class_start default
163
164 ## Daemon processes to be run by init.
165 ##
166 service console /system/bin/sh
167 console
168
169 # adbd is controlled by the persist.service.adb.enable system property
170 service adbd /sbin/adbd
171 disabled
172
173 # adbd on at boot in emulator
174 on property:ro.kernel.qemu=1
175 start adbd
176
177 on property:persist.service.adb.enable=1
178 start adbd
179
180 on property:persist.service.adb.enable=0
181 stop adbd
182
183 service servicemanager /system/bin/servicemanager
184 user system
185 critical
186 onrestart restart zygote
187 onrestart restart media
188
189 service mountd /system/bin/mountd
190 socket mountd stream 0660 root mount
191
192 service debuggerd /system/bin/debuggerd
193
194 service ril-daemon /system/bin/rild
195 socket rild stream 660 root radio
196 socket rild-debug stream 660 radio system
197 user root
198 group radio cache inet misc
199
200 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
201 socket zygote stream 666
202 onrestart write /sys/android_power/request_state wake
203 onrestart write /sys/power/state on
204
205 service media /system/bin/mediaserver
206 user media
207 group system audio camera graphics inet net_bt net_bt_admin
208
209 service bootsound /system/bin/playmp3
210 user media
211 group audio
212 oneshot
213
214 service dbus /system/bin/dbus-daemon --system --nofork
215 socket dbus stream 660 bluetooth bluetooth
216 user bluetooth
217 group bluetooth net_bt_admin
218
219 #STOPSHIP: disable the verbose logging
220 service hcid /system/bin/logwrapper /system/bin/hcid -d -s -n -f /etc/bluez/hcid.conf
221 socket bluetooth stream 660 bluetooth bluetooth
222 socket dbus_bluetooth stream 660 bluetooth bluetooth
223 # init.rc does not yet support applying capabilities, so run as root and
224 # let hcid drop uid to bluetooth with the right linux capabilities
225 group bluetooth net_bt_admin misc
226 disabled
227
228 service hfag /system/bin/sdptool add --channel=10 HFAG
229 user bluetooth
230 group bluetooth net_bt_admin
231 disabled
232 oneshot
233
234 service hsag /system/bin/sdptool add --channel=11 HSAG
235 user bluetooth
236 group bluetooth net_bt_admin
237 disabled
238 oneshot
239
240 service installd /system/bin/installd
241 socket installd stream 600 system system
242
243 service flash_recovery /system/bin/flash_image recovery /system/recovery.img
244 oneshot
+0
-49
sh/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 LOCAL_SRC_FILES:= \
4 alias.c \
5 arith.c \
6 arith_lex.c \
7 builtins.c \
8 cd.c \
9 error.c \
10 eval.c \
11 exec.c \
12 expand.c \
13 input.c \
14 jobs.c \
15 main.c \
16 memalloc.c \
17 miscbltin.c \
18 mystring.c \
19 nodes.c \
20 options.c \
21 parser.c \
22 redir.c \
23 show.c \
24 syntax.c \
25 trap.c \
26 output.c \
27 var.c \
28 bltin/echo.c \
29 init.c
30
31 LOCAL_MODULE:= sh
32
33 LOCAL_CFLAGS += -DSHELL
34
35 make_ash_files: PRIVATE_SRC_FILES := $(SRC_FILES)
36 make_ash_files: PRIVATE_CFLAGS := $(LOCAL_CFLAGS)
37 make_ash_files:
38 p4 edit arith.c arith_lex.c arith.h builtins.h builtins.c
39 p4 edit init.c nodes.c nodes.h token.h
40 sh ./mktokens
41 bison -o arith.c arith.y
42 flex -o arith_lex.c arith_lex.l
43 perl -ne 'print if ( /^\#\s*define\s+ARITH/ );' < arith.c > arith.h
44 sh ./mkbuiltins shell.h builtins.def . -Wall -O2
45 sh ./mknodes.sh nodetypes nodes.c.pat .
46 sh ./mkinit.sh $(PRIVATE_SRC_FILES)
47
48 include $(BUILD_EXECUTABLE)
+0
-0
sh/MODULE_LICENSE_BSD less more
(Empty file)
+0
-31
sh/NOTICE less more
0 Copyright (c) 1991, 1993
1 The Regents of the University of California. All rights reserved.
2
3 This code is derived from software contributed to Berkeley by
4 Kenneth Almquist.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. Neither the name of the University nor the names of its contributors
15 may be used to endorse or promote products derived from this software
16 without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 SUCH DAMAGE.
29
30
+0
-357
sh/TOUR less more
0 # $NetBSD: TOUR,v 1.8 1996/10/16 14:24:56 christos Exp $
1 # @(#)TOUR 8.1 (Berkeley) 5/31/93
2
3 NOTE -- This is the original TOUR paper distributed with ash and
4 does not represent the current state of the shell. It is provided anyway
5 since it provides helpful information for how the shell is structured,
6 but be warned that things have changed -- the current shell is
7 still under development.
8
9 ================================================================
10
11 A Tour through Ash
12
13 Copyright 1989 by Kenneth Almquist.
14
15
16 DIRECTORIES: The subdirectory bltin contains commands which can
17 be compiled stand-alone. The rest of the source is in the main
18 ash directory.
19
20 SOURCE CODE GENERATORS: Files whose names begin with "mk" are
21 programs that generate source code. A complete list of these
22 programs is:
23
24 program intput files generates
25 ------- ------------ ---------
26 mkbuiltins builtins builtins.h builtins.c
27 mkinit *.c init.c
28 mknodes nodetypes nodes.h nodes.c
29 mksignames - signames.h signames.c
30 mksyntax - syntax.h syntax.c
31 mktokens - token.h
32 bltin/mkexpr unary_op binary_op operators.h operators.c
33
34 There are undoubtedly too many of these. Mkinit searches all the
35 C source files for entries looking like:
36
37 INIT {
38 x = 1; /* executed during initialization */
39 }
40
41 RESET {
42 x = 2; /* executed when the shell does a longjmp
43 back to the main command loop */
44 }
45
46 SHELLPROC {
47 x = 3; /* executed when the shell runs a shell procedure */
48 }
49
50 It pulls this code out into routines which are when particular
51 events occur. The intent is to improve modularity by isolating
52 the information about which modules need to be explicitly
53 initialized/reset within the modules themselves.
54
55 Mkinit recognizes several constructs for placing declarations in
56 the init.c file.
57 INCLUDE "file.h"
58 includes a file. The storage class MKINIT makes a declaration
59 available in the init.c file, for example:
60 MKINIT int funcnest; /* depth of function calls */
61 MKINIT alone on a line introduces a structure or union declara-
62 tion:
63 MKINIT
64 struct redirtab {
65 short renamed[10];
66 };
67 Preprocessor #define statements are copied to init.c without any
68 special action to request this.
69
70 INDENTATION: The ash source is indented in multiples of six
71 spaces. The only study that I have heard of on the subject con-
72 cluded that the optimal amount to indent is in the range of four
73 to six spaces. I use six spaces since it is not too big a jump
74 from the widely used eight spaces. If you really hate six space
75 indentation, use the adjind (source included) program to change
76 it to something else.
77
78 EXCEPTIONS: Code for dealing with exceptions appears in
79 exceptions.c. The C language doesn't include exception handling,
80 so I implement it using setjmp and longjmp. The global variable
81 exception contains the type of exception. EXERROR is raised by
82 calling error. EXINT is an interrupt. EXSHELLPROC is an excep-
83 tion which is raised when a shell procedure is invoked. The pur-
84 pose of EXSHELLPROC is to perform the cleanup actions associated
85 with other exceptions. After these cleanup actions, the shell
86 can interpret a shell procedure itself without exec'ing a new
87 copy of the shell.
88
89 INTERRUPTS: In an interactive shell, an interrupt will cause an
90 EXINT exception to return to the main command loop. (Exception:
91 EXINT is not raised if the user traps interrupts using the trap
92 command.) The INTOFF and INTON macros (defined in exception.h)
93 provide uninterruptable critical sections. Between the execution
94 of INTOFF and the execution of INTON, interrupt signals will be
95 held for later delivery. INTOFF and INTON can be nested.
96
97 MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
98 which call error when there is no memory left. It also defines a
99 stack oriented memory allocation scheme. Allocating off a stack
100 is probably more efficient than allocation using malloc, but the
101 big advantage is that when an exception occurs all we have to do
102 to free up the memory in use at the time of the exception is to
103 restore the stack pointer. The stack is implemented using a
104 linked list of blocks.
105
106 STPUTC: If the stack were contiguous, it would be easy to store
107 strings on the stack without knowing in advance how long the
108 string was going to be:
109 p = stackptr;
110 *p++ = c; /* repeated as many times as needed */
111 stackptr = p;
112 The folloing three macros (defined in memalloc.h) perform these
113 operations, but grow the stack if you run off the end:
114 STARTSTACKSTR(p);
115 STPUTC(c, p); /* repeated as many times as needed */
116 grabstackstr(p);
117
118 We now start a top-down look at the code:
119
120 MAIN.C: The main routine performs some initialization, executes
121 the user's profile if necessary, and calls cmdloop. Cmdloop is
122 repeatedly parses and executes commands.
123
124 OPTIONS.C: This file contains the option processing code. It is
125 called from main to parse the shell arguments when the shell is
126 invoked, and it also contains the set builtin. The -i and -j op-
127 tions (the latter turns on job control) require changes in signal
128 handling. The routines setjobctl (in jobs.c) and setinteractive
129 (in trap.c) are called to handle changes to these options.
130
131 PARSING: The parser code is all in parser.c. A recursive des-
132 cent parser is used. Syntax tables (generated by mksyntax) are
133 used to classify characters during lexical analysis. There are
134 three tables: one for normal use, one for use when inside single
135 quotes, and one for use when inside double quotes. The tables
136 are machine dependent because they are indexed by character vari-
137 ables and the range of a char varies from machine to machine.
138
139 PARSE OUTPUT: The output of the parser consists of a tree of
140 nodes. The various types of nodes are defined in the file node-
141 types.
142
143 Nodes of type NARG are used to represent both words and the con-
144 tents of here documents. An early version of ash kept the con-
145 tents of here documents in temporary files, but keeping here do-
146 cuments in memory typically results in significantly better per-
147 formance. It would have been nice to make it an option to use
148 temporary files for here documents, for the benefit of small
149 machines, but the code to keep track of when to delete the tem-
150 porary files was complex and I never fixed all the bugs in it.
151 (AT&T has been maintaining the Bourne shell for more than ten
152 years, and to the best of my knowledge they still haven't gotten
153 it to handle temporary files correctly in obscure cases.)
154
155 The text field of a NARG structure points to the text of the
156 word. The text consists of ordinary characters and a number of
157 special codes defined in parser.h. The special codes are:
158
159 CTLVAR Variable substitution
160 CTLENDVAR End of variable substitution
161 CTLBACKQ Command substitution
162 CTLBACKQ|CTLQUOTE Command substitution inside double quotes
163 CTLESC Escape next character
164
165 A variable substitution contains the following elements:
166
167 CTLVAR type name '=' [ alternative-text CTLENDVAR ]
168
169 The type field is a single character specifying the type of sub-
170 stitution. The possible types are:
171
172 VSNORMAL $var
173 VSMINUS ${var-text}
174 VSMINUS|VSNUL ${var:-text}
175 VSPLUS ${var+text}
176 VSPLUS|VSNUL ${var:+text}
177 VSQUESTION ${var?text}
178 VSQUESTION|VSNUL ${var:?text}
179 VSASSIGN ${var=text}
180 VSASSIGN|VSNUL ${var=text}
181
182 In addition, the type field will have the VSQUOTE flag set if the
183 variable is enclosed in double quotes. The name of the variable
184 comes next, terminated by an equals sign. If the type is not
185 VSNORMAL, then the text field in the substitution follows, ter-
186 minated by a CTLENDVAR byte.
187
188 Commands in back quotes are parsed and stored in a linked list.
189 The locations of these commands in the string are indicated by
190 CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
191 the back quotes were enclosed in double quotes.
192
193 The character CTLESC escapes the next character, so that in case
194 any of the CTL characters mentioned above appear in the input,
195 they can be passed through transparently. CTLESC is also used to
196 escape '*', '?', '[', and '!' characters which were quoted by the
197 user and thus should not be used for file name generation.
198
199 CTLESC characters have proved to be particularly tricky to get
200 right. In the case of here documents which are not subject to
201 variable and command substitution, the parser doesn't insert any
202 CTLESC characters to begin with (so the contents of the text
203 field can be written without any processing). Other here docu-
204 ments, and words which are not subject to splitting and file name
205 generation, have the CTLESC characters removed during the vari-
206 able and command substitution phase. Words which are subject
207 splitting and file name generation have the CTLESC characters re-
208 moved as part of the file name phase.
209
210 EXECUTION: Command execution is handled by the following files:
211 eval.c The top level routines.
212 redir.c Code to handle redirection of input and output.
213 jobs.c Code to handle forking, waiting, and job control.
214 exec.c Code to to path searches and the actual exec sys call.
215 expand.c Code to evaluate arguments.
216 var.c Maintains the variable symbol table. Called from expand.c.
217
218 EVAL.C: Evaltree recursively executes a parse tree. The exit
219 status is returned in the global variable exitstatus. The alter-
220 native entry evalbackcmd is called to evaluate commands in back
221 quotes. It saves the result in memory if the command is a buil-
222 tin; otherwise it forks off a child to execute the command and
223 connects the standard output of the child to a pipe.
224
225 JOBS.C: To create a process, you call makejob to return a job
226 structure, and then call forkshell (passing the job structure as
227 an argument) to create the process. Waitforjob waits for a job
228 to complete. These routines take care of process groups if job
229 control is defined.
230
231 REDIR.C: Ash allows file descriptors to be redirected and then
232 restored without forking off a child process. This is accom-
233 plished by duplicating the original file descriptors. The redir-
234 tab structure records where the file descriptors have be dupli-
235 cated to.
236
237 EXEC.C: The routine find_command locates a command, and enters
238 the command in the hash table if it is not already there. The
239 third argument specifies whether it is to print an error message
240 if the command is not found. (When a pipeline is set up,
241 find_command is called for all the commands in the pipeline be-
242 fore any forking is done, so to get the commands into the hash
243 table of the parent process. But to make command hashing as
244 transparent as possible, we silently ignore errors at that point
245 and only print error messages if the command cannot be found
246 later.)
247
248 The routine shellexec is the interface to the exec system call.
249
250 EXPAND.C: Arguments are processed in three passes. The first
251 (performed by the routine argstr) performs variable and command
252 substitution. The second (ifsbreakup) performs word splitting
253 and the third (expandmeta) performs file name generation. If the
254 "/u" directory is simulated, then when "/u/username" is replaced
255 by the user's home directory, the flag "didudir" is set. This
256 tells the cd command that it should print out the directory name,
257 just as it would if the "/u" directory were implemented using
258 symbolic links.
259
260 VAR.C: Variables are stored in a hash table. Probably we should
261 switch to extensible hashing. The variable name is stored in the
262 same string as the value (using the format "name=value") so that
263 no string copying is needed to create the environment of a com-
264 mand. Variables which the shell references internally are preal-
265 located so that the shell can reference the values of these vari-
266 ables without doing a lookup.
267
268 When a program is run, the code in eval.c sticks any environment
269 variables which precede the command (as in "PATH=xxx command") in
270 the variable table as the simplest way to strip duplicates, and
271 then calls "environment" to get the value of the environment.
272 There are two consequences of this. First, if an assignment to
273 PATH precedes the command, the value of PATH before the assign-
274 ment must be remembered and passed to shellexec. Second, if the
275 program turns out to be a shell procedure, the strings from the
276 environment variables which preceded the command must be pulled
277 out of the table and replaced with strings obtained from malloc,
278 since the former will automatically be freed when the stack (see
279 the entry on memalloc.c) is emptied.
280
281 BUILTIN COMMANDS: The procedures for handling these are scat-
282 tered throughout the code, depending on which location appears
283 most appropriate. They can be recognized because their names al-
284 ways end in "cmd". The mapping from names to procedures is
285 specified in the file builtins, which is processed by the mkbuil-
286 tins command.
287
288 A builtin command is invoked with argc and argv set up like a
289 normal program. A builtin command is allowed to overwrite its
290 arguments. Builtin routines can call nextopt to do option pars-
291 ing. This is kind of like getopt, but you don't pass argc and
292 argv to it. Builtin routines can also call error. This routine
293 normally terminates the shell (or returns to the main command
294 loop if the shell is interactive), but when called from a builtin
295 command it causes the builtin command to terminate with an exit
296 status of 2.
297
298 The directory bltins contains commands which can be compiled in-
299 dependently but can also be built into the shell for efficiency
300 reasons. The makefile in this directory compiles these programs
301 in the normal fashion (so that they can be run regardless of
302 whether the invoker is ash), but also creates a library named
303 bltinlib.a which can be linked with ash. The header file bltin.h
304 takes care of most of the differences between the ash and the
305 stand-alone environment. The user should call the main routine
306 "main", and #define main to be the name of the routine to use
307 when the program is linked into ash. This #define should appear
308 before bltin.h is included; bltin.h will #undef main if the pro-
309 gram is to be compiled stand-alone.
310
311 CD.C: This file defines the cd and pwd builtins. The pwd com-
312 mand runs /bin/pwd the first time it is invoked (unless the user
313 has already done a cd to an absolute pathname), but then
314 remembers the current directory and updates it when the cd com-
315 mand is run, so subsequent pwd commands run very fast. The main
316 complication in the cd command is in the docd command, which
317 resolves symbolic links into actual names and informs the user
318 where the user ended up if he crossed a symbolic link.
319
320 SIGNALS: Trap.c implements the trap command. The routine set-
321 signal figures out what action should be taken when a signal is
322 received and invokes the signal system call to set the signal ac-
323 tion appropriately. When a signal that a user has set a trap for
324 is caught, the routine "onsig" sets a flag. The routine dotrap
325 is called at appropriate points to actually handle the signal.
326 When an interrupt is caught and no trap has been set for that
327 signal, the routine "onint" in error.c is called.
328
329 OUTPUT: Ash uses it's own output routines. There are three out-
330 put structures allocated. "Output" represents the standard out-
331 put, "errout" the standard error, and "memout" contains output
332 which is to be stored in memory. This last is used when a buil-
333 tin command appears in backquotes, to allow its output to be col-
334 lected without doing any I/O through the UNIX operating system.
335 The variables out1 and out2 normally point to output and errout,
336 respectively, but they are set to point to memout when appropri-
337 ate inside backquotes.
338
339 INPUT: The basic input routine is pgetc, which reads from the
340 current input file. There is a stack of input files; the current
341 input file is the top file on this stack. The code allows the
342 input to come from a string rather than a file. (This is for the
343 -c option and the "." and eval builtin commands.) The global
344 variable plinno is saved and restored when files are pushed and
345 popped from the stack. The parser routines store the number of
346 the current line in this variable.
347
348 DEBUGGING: If DEBUG is defined in shell.h, then the shell will
349 write debugging information to the file $HOME/trace. Most of
350 this is done using the TRACE macro, which takes a set of printf
351 arguments inside two sets of parenthesis. Example:
352 "TRACE(("n=%d0, n))". The double parenthesis are necessary be-
353 cause the preprocessor can't handle functions with a variable
354 number of arguments. Defining DEBUG also causes the shell to
355 generate a core dump if it is sent a quit signal. The tracing
356 code is in show.c.
+0
-273
sh/alias.c less more
0 /* $NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <stdlib.h>
44 #include "shell.h"
45 #include "input.h"
46 #include "output.h"
47 #include "error.h"
48 #include "memalloc.h"
49 #include "mystring.h"
50 #include "alias.h"
51 #include "options.h" /* XXX for argptr (should remove?) */
52 #include "var.h"
53
54 #define ATABSIZE 39
55
56 struct alias *atab[ATABSIZE];
57
58 STATIC void setalias(char *, char *);
59 STATIC int unalias(char *);
60 STATIC struct alias **hashalias(char *);
61
62 STATIC
63 void
64 setalias(char *name, char *val)
65 {
66 struct alias *ap, **app;
67
68 app = hashalias(name);
69 for (ap = *app; ap; ap = ap->next) {
70 if (equal(name, ap->name)) {
71 INTOFF;
72 ckfree(ap->val);
73 ap->val = savestr(val);
74 INTON;
75 return;
76 }
77 }
78 /* not found */
79 INTOFF;
80 ap = ckmalloc(sizeof (struct alias));
81 ap->name = savestr(name);
82 /*
83 * XXX - HACK: in order that the parser will not finish reading the
84 * alias value off the input before processing the next alias, we
85 * dummy up an extra space at the end of the alias. This is a crock
86 * and should be re-thought. The idea (if you feel inclined to help)
87 * is to avoid alias recursions. The mechanism used is: when
88 * expanding an alias, the value of the alias is pushed back on the
89 * input as a string and a pointer to the alias is stored with the
90 * string. The alias is marked as being in use. When the input
91 * routine finishes reading the string, it markes the alias not
92 * in use. The problem is synchronization with the parser. Since
93 * it reads ahead, the alias is marked not in use before the
94 * resulting token(s) is next checked for further alias sub. The
95 * H A C K is that we add a little fluff after the alias value
96 * so that the string will not be exhausted. This is a good
97 * idea ------- ***NOT***
98 */
99 #ifdef notyet
100 ap->val = savestr(val);
101 #else /* hack */
102 {
103 int len = strlen(val);
104 ap->val = ckmalloc(len + 2);
105 memcpy(ap->val, val, len);
106 ap->val[len] = ' '; /* fluff */
107 ap->val[len+1] = '\0';
108 }
109 #endif
110 ap->next = *app;
111 *app = ap;
112 INTON;
113 }
114
115 STATIC int
116 unalias(char *name)
117 {
118 struct alias *ap, **app;
119
120 app = hashalias(name);
121
122 for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
123 if (equal(name, ap->name)) {
124 /*
125 * if the alias is currently in use (i.e. its
126 * buffer is being used by the input routine) we
127 * just null out the name instead of freeing it.
128 * We could clear it out later, but this situation
129 * is so rare that it hardly seems worth it.
130 */
131 if (ap->flag & ALIASINUSE)
132 *ap->name = '\0';
133 else {
134 INTOFF;
135 *app = ap->next;
136 ckfree(ap->name);
137 ckfree(ap->val);
138 ckfree(ap);
139 INTON;
140 }
141 return (0);
142 }
143 }
144
145 return (1);
146 }
147
148 #ifdef mkinit
149 MKINIT void rmaliases(void);
150
151 SHELLPROC {
152 rmaliases();
153 }
154 #endif
155
156 void
157 rmaliases(void)
158 {
159 struct alias *ap, *tmp;
160 int i;
161
162 INTOFF;
163 for (i = 0; i < ATABSIZE; i++) {
164 ap = atab[i];
165 atab[i] = NULL;
166 while (ap) {
167 ckfree(ap->name);
168 ckfree(ap->val);
169 tmp = ap;
170 ap = ap->next;
171 ckfree(tmp);
172 }
173 }
174 INTON;
175 }
176
177 struct alias *
178 lookupalias(char *name, int check)
179 {
180 struct alias *ap = *hashalias(name);
181
182 for (; ap; ap = ap->next) {
183 if (equal(name, ap->name)) {
184 if (check && (ap->flag & ALIASINUSE))
185 return (NULL);
186 return (ap);
187 }
188 }
189
190 return (NULL);
191 }
192
193 char *
194 get_alias_text(char *name)
195 {
196 struct alias *ap;
197
198 ap = lookupalias(name, 0);
199 if (ap == NULL)
200 return NULL;
201 return ap->val;
202 }
203
204 /*
205 * TODO - sort output
206 */
207 int
208 aliascmd(int argc, char **argv)
209 {
210 char *n, *v;
211 int ret = 0;
212 struct alias *ap;
213
214 if (argc == 1) {
215 int i;
216
217 for (i = 0; i < ATABSIZE; i++)
218 for (ap = atab[i]; ap; ap = ap->next) {
219 if (*ap->name != '\0') {
220 out1fmt("alias %s=", ap->name);
221 print_quoted(ap->val);
222 out1c('\n');
223 }
224 }
225 return (0);
226 }
227 while ((n = *++argv) != NULL) {
228 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
229 if ((ap = lookupalias(n, 0)) == NULL) {
230 outfmt(out2, "alias: %s not found\n", n);
231 ret = 1;
232 } else {
233 out1fmt("alias %s=", n);
234 print_quoted(ap->val);
235 out1c('\n');
236 }
237 } else {
238 *v++ = '\0';
239 setalias(n, v);
240 }
241 }
242
243 return (ret);
244 }
245
246 int
247 unaliascmd(int argc, char **argv)
248 {
249 int i;
250
251 while ((i = nextopt("a")) != '\0') {
252 if (i == 'a') {
253 rmaliases();
254 return (0);
255 }
256 }
257 for (i = 0; *argptr; argptr++)
258 i = unalias(*argptr);
259
260 return (i);
261 }
262
263 STATIC struct alias **
264 hashalias(char *p)
265 {
266 unsigned int hashval;
267
268 hashval = *p << 4;
269 while (*p)
270 hashval+= *p++;
271 return &atab[hashval % ATABSIZE];
272 }
+0
-50
sh/alias.h less more
0 /* $NetBSD: alias.h,v 1.6 2003/08/07 09:05:29 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)alias.h 8.2 (Berkeley) 5/4/95
34 */
35
36 #define ALIASINUSE 1
37
38 struct alias {
39 struct alias *next;
40 char *name;
41 char *val;
42 int flag;
43 };
44
45 struct alias *lookupalias(char *, int);
46 char *get_alias_text(char *);
47 int aliascmd(int, char **);
48 int unaliascmd(int, char **);
49 void rmaliases(void);
+0
-1587
sh/arith.c less more
0 /* A Bison parser, made by GNU Bison 1.875d. */
1
2 /* Skeleton parser for Yacc-like parsing with Bison,
3 Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 /* As a special exception, when this file is copied by Bison into a
21 Bison output file, you may use that output file without restriction.
22 This special exception was added by the Free Software Foundation
23 in version 1.24 of Bison. */
24
25 /* Written by Richard Stallman by simplifying the original so called
26 ``semantic'' parser. */
27
28 /* All symbols defined below should begin with yy or YY, to avoid
29 infringing on user name space. This should be done even for local
30 variables, as they might otherwise be expanded by user macros.
31 There are some unavoidable exceptions within include files to
32 define necessary library symbols; they are noted "INFRINGES ON
33 USER NAME SPACE" below. */
34
35 /* Identify Bison output. */
36 #define YYBISON 1
37
38 /* Skeleton name. */
39 #define YYSKELETON_NAME "yacc.c"
40
41 /* Pure parsers. */
42 #define YYPURE 0
43
44 /* Using locations. */
45 #define YYLSP_NEEDED 0
46
47
48
49 /* Tokens. */
50 #ifndef YYTOKENTYPE
51 # define YYTOKENTYPE
52 /* Put the tokens into the symbol table, so that GDB and other debuggers
53 know about them. */
54 enum yytokentype {
55 ARITH_NUM = 258,
56 ARITH_LPAREN = 259,
57 ARITH_RPAREN = 260,
58 ARITH_OR = 261,
59 ARITH_AND = 262,
60 ARITH_BOR = 263,
61 ARITH_BXOR = 264,
62 ARITH_BAND = 265,
63 ARITH_NE = 266,
64 ARITH_EQ = 267,
65 ARITH_LE = 268,
66 ARITH_GE = 269,
67 ARITH_GT = 270,
68 ARITH_LT = 271,
69 ARITH_RSHIFT = 272,
70 ARITH_LSHIFT = 273,
71 ARITH_SUB = 274,
72 ARITH_ADD = 275,
73 ARITH_REM = 276,
74 ARITH_DIV = 277,
75 ARITH_MUL = 278,
76 ARITH_BNOT = 279,
77 ARITH_NOT = 280,
78 ARITH_UNARYPLUS = 281,
79 ARITH_UNARYMINUS = 282
80 };
81 #endif
82 #define ARITH_NUM 258
83 #define ARITH_LPAREN 259
84 #define ARITH_RPAREN 260
85 #define ARITH_OR 261
86 #define ARITH_AND 262
87 #define ARITH_BOR 263
88 #define ARITH_BXOR 264
89 #define ARITH_BAND 265
90 #define ARITH_NE 266
91 #define ARITH_EQ 267
92 #define ARITH_LE 268
93 #define ARITH_GE 269
94 #define ARITH_GT 270
95 #define ARITH_LT 271
96 #define ARITH_RSHIFT 272
97 #define ARITH_LSHIFT 273
98 #define ARITH_SUB 274
99 #define ARITH_ADD 275
100 #define ARITH_REM 276
101 #define ARITH_DIV 277
102 #define ARITH_MUL 278
103 #define ARITH_BNOT 279
104 #define ARITH_NOT 280
105 #define ARITH_UNARYPLUS 281
106 #define ARITH_UNARYMINUS 282
107
108
109
110
111 /* Copy the first part of user declarations. */
112 #line 1 "arith.y"
113
114 /* $NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $ */
115
116 /*-
117 * Copyright (c) 1993
118 * The Regents of the University of California. All rights reserved.
119 *
120 * This code is derived from software contributed to Berkeley by
121 * Kenneth Almquist.
122 *
123 * Redistribution and use in source and binary forms, with or without
124 * modification, are permitted provided that the following conditions
125 * are met:
126 * 1. Redistributions of source code must retain the above copyright
127 * notice, this list of conditions and the following disclaimer.
128 * 2. Redistributions in binary form must reproduce the above copyright
129 * notice, this list of conditions and the following disclaimer in the
130 * documentation and/or other materials provided with the distribution.
131 * 3. Neither the name of the University nor the names of its contributors
132 * may be used to endorse or promote products derived from this software
133 * without specific prior written permission.
134 *
135 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
136 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
137 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
138 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
139 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
140 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
141 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
142 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
143 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
144 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
145 * SUCH DAMAGE.
146 */
147
148 #include <sys/cdefs.h>
149 #ifndef lint
150 #if 0
151 static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95";
152 #else
153 __RCSID("$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $");
154 #endif
155 #endif /* not lint */
156
157 #include <stdlib.h>
158 #include "expand.h"
159 #include "shell.h"
160 #include "error.h"
161 #include "output.h"
162 #include "memalloc.h"
163
164 const char *arith_buf, *arith_startbuf;
165
166 void yyerror(const char *);
167 #ifdef TESTARITH
168 int main(int , char *[]);
169 int error(char *);
170 #endif
171
172
173
174 /* Enabling traces. */
175 #ifndef YYDEBUG
176 # define YYDEBUG 0
177 #endif
178
179 /* Enabling verbose error messages. */
180 #ifdef YYERROR_VERBOSE
181 # undef YYERROR_VERBOSE
182 # define YYERROR_VERBOSE 1
183 #else
184 # define YYERROR_VERBOSE 0
185 #endif
186
187 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
188 typedef int YYSTYPE;
189 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
190 # define YYSTYPE_IS_DECLARED 1
191 # define YYSTYPE_IS_TRIVIAL 1
192 #endif
193
194
195
196 /* Copy the second part of user declarations. */
197
198
199 /* Line 214 of yacc.c. */
200 #line 202 "arith.c"
201
202 #if ! defined (yyoverflow) || YYERROR_VERBOSE
203
204 # ifndef YYFREE
205 # define YYFREE free
206 # endif
207 # ifndef YYMALLOC
208 # define YYMALLOC malloc
209 # endif
210
211 /* The parser invokes alloca or malloc; define the necessary symbols. */
212
213 # ifdef YYSTACK_USE_ALLOCA
214 # if YYSTACK_USE_ALLOCA
215 # define YYSTACK_ALLOC alloca
216 # endif
217 # else
218 # if defined (alloca) || defined (_ALLOCA_H)
219 # define YYSTACK_ALLOC alloca
220 # else
221 # ifdef __GNUC__
222 # define YYSTACK_ALLOC __builtin_alloca
223 # endif
224 # endif
225 # endif
226
227 # ifdef YYSTACK_ALLOC
228 /* Pacify GCC's `empty if-body' warning. */
229 # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
230 # else
231 # if defined (__STDC__) || defined (__cplusplus)
232 # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
233 # define YYSIZE_T size_t
234 # endif
235 # define YYSTACK_ALLOC YYMALLOC
236 # define YYSTACK_FREE YYFREE
237 # endif
238 #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
239
240
241 #if (! defined (yyoverflow) \
242 && (! defined (__cplusplus) \
243 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
244
245 /* A type that is properly aligned for any stack member. */
246 union yyalloc
247 {
248 short int yyss;
249 YYSTYPE yyvs;
250 };
251
252 /* The size of the maximum gap between one aligned stack and the next. */
253 # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
254
255 /* The size of an array large to enough to hold all stacks, each with
256 N elements. */
257 # define YYSTACK_BYTES(N) \
258 ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
259 + YYSTACK_GAP_MAXIMUM)
260
261 /* Copy COUNT objects from FROM to TO. The source and destination do
262 not overlap. */
263 # ifndef YYCOPY
264 # if defined (__GNUC__) && 1 < __GNUC__
265 # define YYCOPY(To, From, Count) \
266 __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
267 # else
268 # define YYCOPY(To, From, Count) \
269 do \
270 { \
271 register YYSIZE_T yyi; \
272 for (yyi = 0; yyi < (Count); yyi++) \
273 (To)[yyi] = (From)[yyi]; \
274 } \
275 while (0)
276 # endif
277 # endif
278
279 /* Relocate STACK from its old location to the new one. The
280 local variables YYSIZE and YYSTACKSIZE give the old and new number of
281 elements in the stack, and YYPTR gives the new location of the
282 stack. Advance YYPTR to a properly aligned location for the next
283 stack. */
284 # define YYSTACK_RELOCATE(Stack) \
285 do \
286 { \
287 YYSIZE_T yynewbytes; \
288 YYCOPY (&yyptr->Stack, Stack, yysize); \
289 Stack = &yyptr->Stack; \
290 yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
291 yyptr += yynewbytes / sizeof (*yyptr); \
292 } \
293 while (0)
294
295 #endif
296
297 #if defined (__STDC__) || defined (__cplusplus)
298 typedef signed char yysigned_char;
299 #else
300 typedef short int yysigned_char;
301 #endif
302
303 /* YYFINAL -- State number of the termination state. */
304 #define YYFINAL 14
305 /* YYLAST -- Last index in YYTABLE. */
306 #define YYLAST 170
307
308 /* YYNTOKENS -- Number of terminals. */
309 #define YYNTOKENS 28
310 /* YYNNTS -- Number of nonterminals. */
311 #define YYNNTS 3
312 /* YYNRULES -- Number of rules. */
313 #define YYNRULES 26
314 /* YYNRULES -- Number of states. */
315 #define YYNSTATES 52
316
317 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
318 #define YYUNDEFTOK 2
319 #define YYMAXUTOK 282
320
321 #define YYTRANSLATE(YYX) \
322 ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
323
324 /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
325 static const unsigned char yytranslate[] =
326 {
327 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
328 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
329 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
330 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
331 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
332 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
333 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
334 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
335 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
336 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
337 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
338 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
339 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
340 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
341 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
342 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
343 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
344 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
345 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
346 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
347 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
348 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
349 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
350 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
351 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
352 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
353 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
354 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
355 25, 26, 27
356 };
357
358 #if YYDEBUG
359 /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
360 YYRHS. */
361 static const unsigned char yyprhs[] =
362 {
363 0, 0, 3, 5, 9, 13, 17, 21, 25, 29,
364 33, 37, 41, 45, 49, 53, 57, 61, 65, 69,
365 73, 77, 81, 84, 87, 90, 93
366 };
367
368 /* YYRHS -- A `-1'-separated list of the rules' RHS. */
369 static const yysigned_char yyrhs[] =
370 {
371 29, 0, -1, 30, -1, 4, 30, 5, -1, 30,
372 6, 30, -1, 30, 7, 30, -1, 30, 8, 30,
373 -1, 30, 9, 30, -1, 30, 10, 30, -1, 30,
374 12, 30, -1, 30, 15, 30, -1, 30, 14, 30,
375 -1, 30, 16, 30, -1, 30, 13, 30, -1, 30,
376 11, 30, -1, 30, 18, 30, -1, 30, 17, 30,
377 -1, 30, 20, 30, -1, 30, 19, 30, -1, 30,
378 23, 30, -1, 30, 22, 30, -1, 30, 21, 30,
379 -1, 25, 30, -1, 24, 30, -1, 19, 30, -1,
380 20, 30, -1, 3, -1
381 };
382
383 /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
384 static const unsigned char yyrline[] =
385 {
386 0, 76, 76, 82, 83, 84, 85, 86, 87, 88,
387 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
388 99, 104, 109, 110, 111, 112, 113
389 };
390 #endif
391
392 #if YYDEBUG || YYERROR_VERBOSE
393 /* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
394 First, the terminals, then, starting at YYNTOKENS, nonterminals. */
395 static const char *const yytname[] =
396 {
397 "$end", "error", "$undefined", "ARITH_NUM", "ARITH_LPAREN",
398 "ARITH_RPAREN", "ARITH_OR", "ARITH_AND", "ARITH_BOR", "ARITH_BXOR",
399 "ARITH_BAND", "ARITH_NE", "ARITH_EQ", "ARITH_LE", "ARITH_GE", "ARITH_GT",
400 "ARITH_LT", "ARITH_RSHIFT", "ARITH_LSHIFT", "ARITH_SUB", "ARITH_ADD",
401 "ARITH_REM", "ARITH_DIV", "ARITH_MUL", "ARITH_BNOT", "ARITH_NOT",
402 "ARITH_UNARYPLUS", "ARITH_UNARYMINUS", "$accept", "exp", "expr", 0
403 };
404 #endif
405
406 # ifdef YYPRINT
407 /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
408 token YYLEX-NUM. */
409 static const unsigned short int yytoknum[] =
410 {
411 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
412 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
413 275, 276, 277, 278, 279, 280, 281, 282
414 };
415 # endif
416
417 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
418 static const unsigned char yyr1[] =
419 {
420 0, 28, 29, 30, 30, 30, 30, 30, 30, 30,
421 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
422 30, 30, 30, 30, 30, 30, 30
423 };
424
425 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
426 static const unsigned char yyr2[] =
427 {
428 0, 2, 1, 3, 3, 3, 3, 3, 3, 3,
429 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
430 3, 3, 2, 2, 2, 2, 1
431 };
432
433 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
434 STATE-NUM when YYTABLE doesn't specify something else to do. Zero
435 means the default is an error. */
436 static const unsigned char yydefact[] =
437 {
438 0, 26, 0, 0, 0, 0, 0, 0, 2, 0,
439 24, 25, 23, 22, 1, 0, 0, 0, 0, 0,
440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
441 0, 0, 0, 3, 4, 5, 6, 7, 8, 14,
442 9, 13, 11, 10, 12, 16, 15, 18, 17, 21,
443 20, 19
444 };
445
446 /* YYDEFGOTO[NTERM-NUM]. */
447 static const yysigned_char yydefgoto[] =
448 {
449 -1, 7, 8
450 };
451
452 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
453 STATE-NUM. */
454 #define YYPACT_NINF -13
455 static const short int yypact[] =
456 {
457 28, -13, 28, 28, 28, 28, 28, 12, 67, 49,
458 -13, -13, -13, -13, -13, 28, 28, 28, 28, 28,
459 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
460 28, 28, 28, -13, 84, 100, 115, 23, 128, 139,
461 139, -12, -12, -12, -12, 144, 144, 147, 147, -13,
462 -13, -13
463 };
464
465 /* YYPGOTO[NTERM-NUM]. */
466 static const yysigned_char yypgoto[] =
467 {
468 -13, -13, -2
469 };
470
471 /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
472 positive, shift that token. If negative, reduce the rule which
473 number is the opposite. If zero, do what YYDEFACT says.
474 If YYTABLE_NINF, syntax error. */
475 #define YYTABLE_NINF -1
476 static const unsigned char yytable[] =
477 {
478 9, 10, 11, 12, 13, 26, 27, 28, 29, 30,
479 31, 32, 14, 34, 35, 36, 37, 38, 39, 40,
480 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
481 51, 1, 2, 19, 20, 21, 22, 23, 24, 25,
482 26, 27, 28, 29, 30, 31, 32, 3, 4, 0,
483 0, 0, 5, 6, 33, 15, 16, 17, 18, 19,
484 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
485 30, 31, 32, 15, 16, 17, 18, 19, 20, 21,
486 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
487 32, 16, 17, 18, 19, 20, 21, 22, 23, 24,
488 25, 26, 27, 28, 29, 30, 31, 32, 17, 18,
489 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
490 29, 30, 31, 32, 18, 19, 20, 21, 22, 23,
491 24, 25, 26, 27, 28, 29, 30, 31, 32, 20,
492 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
493 31, 32, 22, 23, 24, 25, 26, 27, 28, 29,
494 30, 31, 32, 28, 29, 30, 31, 32, 30, 31,
495 32
496 };
497
498 static const yysigned_char yycheck[] =
499 {
500 2, 3, 4, 5, 6, 17, 18, 19, 20, 21,
501 22, 23, 0, 15, 16, 17, 18, 19, 20, 21,
502 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
503 32, 3, 4, 10, 11, 12, 13, 14, 15, 16,
504 17, 18, 19, 20, 21, 22, 23, 19, 20, -1,
505 -1, -1, 24, 25, 5, 6, 7, 8, 9, 10,
506 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
507 21, 22, 23, 6, 7, 8, 9, 10, 11, 12,
508 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
509 23, 7, 8, 9, 10, 11, 12, 13, 14, 15,
510 16, 17, 18, 19, 20, 21, 22, 23, 8, 9,
511 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
512 20, 21, 22, 23, 9, 10, 11, 12, 13, 14,
513 15, 16, 17, 18, 19, 20, 21, 22, 23, 11,
514 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
515 22, 23, 13, 14, 15, 16, 17, 18, 19, 20,
516 21, 22, 23, 19, 20, 21, 22, 23, 21, 22,
517 23
518 };
519
520 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
521 symbol of state STATE-NUM. */
522 static const unsigned char yystos[] =
523 {
524 0, 3, 4, 19, 20, 24, 25, 29, 30, 30,
525 30, 30, 30, 30, 0, 6, 7, 8, 9, 10,
526 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
527 21, 22, 23, 5, 30, 30, 30, 30, 30, 30,
528 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
529 30, 30
530 };
531
532 #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
533 # define YYSIZE_T __SIZE_TYPE__
534 #endif
535 #if ! defined (YYSIZE_T) && defined (size_t)
536 # define YYSIZE_T size_t
537 #endif
538 #if ! defined (YYSIZE_T)
539 # if defined (__STDC__) || defined (__cplusplus)
540 # include <stddef.h> /* INFRINGES ON USER NAME SPACE */
541 # define YYSIZE_T size_t
542 # endif
543 #endif
544 #if ! defined (YYSIZE_T)
545 # define YYSIZE_T unsigned int
546 #endif
547
548 #define yyerrok (yyerrstatus = 0)
549 #define yyclearin (yychar = YYEMPTY)
550 #define YYEMPTY (-2)
551 #define YYEOF 0
552
553 #define YYACCEPT goto yyacceptlab
554 #define YYABORT goto yyabortlab
555 #define YYERROR goto yyerrorlab
556
557
558 /* Like YYERROR except do call yyerror. This remains here temporarily
559 to ease the transition to the new meaning of YYERROR, for GCC.
560 Once GCC version 2 has supplanted version 1, this can go. */
561
562 #define YYFAIL goto yyerrlab
563
564 #define YYRECOVERING() (!!yyerrstatus)
565
566 #define YYBACKUP(Token, Value) \
567 do \
568 if (yychar == YYEMPTY && yylen == 1) \
569 { \
570 yychar = (Token); \
571 yylval = (Value); \
572 yytoken = YYTRANSLATE (yychar); \
573 YYPOPSTACK; \
574 goto yybackup; \
575 } \
576 else \
577 { \
578 yyerror ("syntax error: cannot back up");\
579 YYERROR; \
580 } \
581 while (0)
582
583 #define YYTERROR 1
584 #define YYERRCODE 256
585
586 /* YYLLOC_DEFAULT -- Compute the default location (before the actions
587 are run). */
588
589 #ifndef YYLLOC_DEFAULT
590 # define YYLLOC_DEFAULT(Current, Rhs, N) \
591 ((Current).first_line = (Rhs)[1].first_line, \
592 (Current).first_column = (Rhs)[1].first_column, \
593 (Current).last_line = (Rhs)[N].last_line, \
594 (Current).last_column = (Rhs)[N].last_column)
595 #endif
596
597 /* YYLEX -- calling `yylex' with the right arguments. */
598
599 #ifdef YYLEX_PARAM
600 # define YYLEX yylex (YYLEX_PARAM)
601 #else
602 # define YYLEX yylex ()
603 #endif
604
605 /* Enable debugging if requested. */
606 #if YYDEBUG
607
608 # ifndef YYFPRINTF
609 # include <stdio.h> /* INFRINGES ON USER NAME SPACE */
610 # define YYFPRINTF fprintf
611 # endif
612
613 # define YYDPRINTF(Args) \
614 do { \
615 if (yydebug) \
616 YYFPRINTF Args; \
617 } while (0)
618
619 # define YYDSYMPRINT(Args) \
620 do { \
621 if (yydebug) \
622 yysymprint Args; \
623 } while (0)
624
625 # define YYDSYMPRINTF(Title, Token, Value, Location) \
626 do { \
627 if (yydebug) \
628 { \
629 YYFPRINTF (stderr, "%s ", Title); \
630 yysymprint (stderr, \
631 Token, Value); \
632 YYFPRINTF (stderr, "\n"); \
633 } \
634 } while (0)
635
636 /*------------------------------------------------------------------.
637 | yy_stack_print -- Print the state stack from its BOTTOM up to its |
638 | TOP (included). |
639 `------------------------------------------------------------------*/
640
641 #if defined (__STDC__) || defined (__cplusplus)
642 static void
643 yy_stack_print (short int *bottom, short int *top)
644 #else
645 static void
646 yy_stack_print (bottom, top)
647 short int *bottom;
648 short int *top;
649 #endif
650 {
651 YYFPRINTF (stderr, "Stack now");
652 for (/* Nothing. */; bottom <= top; ++bottom)
653 YYFPRINTF (stderr, " %d", *bottom);
654 YYFPRINTF (stderr, "\n");
655 }
656
657 # define YY_STACK_PRINT(Bottom, Top) \
658 do { \
659 if (yydebug) \
660 yy_stack_print ((Bottom), (Top)); \
661 } while (0)
662
663
664 /*------------------------------------------------.
665 | Report that the YYRULE is going to be reduced. |
666 `------------------------------------------------*/
667
668 #if defined (__STDC__) || defined (__cplusplus)
669 static void
670 yy_reduce_print (int yyrule)
671 #else
672 static void
673 yy_reduce_print (yyrule)
674 int yyrule;
675 #endif
676 {
677 int yyi;
678 unsigned int yylno = yyrline[yyrule];
679 YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
680 yyrule - 1, yylno);
681 /* Print the symbols being reduced, and their result. */
682 for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
683 YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
684 YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
685 }
686
687 # define YY_REDUCE_PRINT(Rule) \
688 do { \
689 if (yydebug) \
690 yy_reduce_print (Rule); \
691 } while (0)
692
693 /* Nonzero means print parse trace. It is left uninitialized so that
694 multiple parsers can coexist. */
695 int yydebug;
696 #else /* !YYDEBUG */
697 # define YYDPRINTF(Args)
698 # define YYDSYMPRINT(Args)
699 # define YYDSYMPRINTF(Title, Token, Value, Location)
700 # define YY_STACK_PRINT(Bottom, Top)
701 # define YY_REDUCE_PRINT(Rule)
702 #endif /* !YYDEBUG */
703
704
705 /* YYINITDEPTH -- initial size of the parser's stacks. */
706 #ifndef YYINITDEPTH
707 # define YYINITDEPTH 200
708 #endif
709
710 /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
711 if the built-in stack extension method is used).
712
713 Do not make this value too large; the results are undefined if
714 SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
715 evaluated with infinite-precision integer arithmetic. */
716
717 #if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
718 # undef YYMAXDEPTH
719 #endif
720
721 #ifndef YYMAXDEPTH
722 # define YYMAXDEPTH 10000
723 #endif
724
725
726
727 #if YYERROR_VERBOSE
728
729 # ifndef yystrlen
730 # if defined (__GLIBC__) && defined (_STRING_H)
731 # define yystrlen strlen
732 # else
733 /* Return the length of YYSTR. */
734 static YYSIZE_T
735 # if defined (__STDC__) || defined (__cplusplus)
736 yystrlen (const char *yystr)
737 # else
738 yystrlen (yystr)
739 const char *yystr;
740 # endif
741 {
742 register const char *yys = yystr;
743
744 while (*yys++ != '\0')
745 continue;
746
747 return yys - yystr - 1;
748 }
749 # endif
750 # endif
751
752 # ifndef yystpcpy
753 # if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
754 # define yystpcpy stpcpy
755 # else
756 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
757 YYDEST. */
758 static char *
759 # if defined (__STDC__) || defined (__cplusplus)
760 yystpcpy (char *yydest, const char *yysrc)
761 # else
762 yystpcpy (yydest, yysrc)
763 char *yydest;
764 const char *yysrc;
765 # endif
766 {
767 register char *yyd = yydest;
768 register const char *yys = yysrc;
769
770 while ((*yyd++ = *yys++) != '\0')
771 continue;
772
773 return yyd - 1;
774 }
775 # endif
776 # endif
777
778 #endif /* !YYERROR_VERBOSE */
779
780
781
782 #if YYDEBUG
783 /*--------------------------------.
784 | Print this symbol on YYOUTPUT. |
785 `--------------------------------*/
786
787 #if defined (__STDC__) || defined (__cplusplus)
788 static void
789 yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
790 #else
791 static void
792 yysymprint (yyoutput, yytype, yyvaluep)
793 FILE *yyoutput;
794 int yytype;
795 YYSTYPE *yyvaluep;
796 #endif
797 {
798 /* Pacify ``unused variable'' warnings. */
799 (void) yyvaluep;
800
801 if (yytype < YYNTOKENS)
802 {
803 YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
804 # ifdef YYPRINT
805 YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
806 # endif
807 }
808 else
809 YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
810
811 switch (yytype)
812 {
813 default:
814 break;
815 }
816 YYFPRINTF (yyoutput, ")");
817 }
818
819 #endif /* ! YYDEBUG */
820 /*-----------------------------------------------.
821 | Release the memory associated to this symbol. |
822 `-----------------------------------------------*/
823
824 #if defined (__STDC__) || defined (__cplusplus)
825 static void
826 yydestruct (int yytype, YYSTYPE *yyvaluep)
827 #else
828 static void
829 yydestruct (yytype, yyvaluep)
830 int yytype;
831 YYSTYPE *yyvaluep;
832 #endif
833 {
834 /* Pacify ``unused variable'' warnings. */
835 (void) yyvaluep;
836
837 switch (yytype)
838 {
839
840 default:
841 break;
842 }
843 }
844
845
846 /* Prevent warnings from -Wmissing-prototypes. */
847
848 #ifdef YYPARSE_PARAM
849 # if defined (__STDC__) || defined (__cplusplus)
850 int yyparse (void *YYPARSE_PARAM);
851 # else
852 int yyparse ();
853 # endif
854 #else /* ! YYPARSE_PARAM */
855 #if defined (__STDC__) || defined (__cplusplus)
856 int yyparse (void);
857 #else
858 int yyparse ();
859 #endif
860 #endif /* ! YYPARSE_PARAM */
861
862
863
864 /* The lookahead symbol. */
865 int yychar;
866
867 /* The semantic value of the lookahead symbol. */
868 YYSTYPE yylval;
869
870 /* Number of syntax errors so far. */
871 int yynerrs;
872
873
874
875 /*----------.
876 | yyparse. |
877 `----------*/
878
879 #ifdef YYPARSE_PARAM
880 # if defined (__STDC__) || defined (__cplusplus)
881 int yyparse (void *YYPARSE_PARAM)
882 # else
883 int yyparse (YYPARSE_PARAM)
884 void *YYPARSE_PARAM;
885 # endif
886 #else /* ! YYPARSE_PARAM */
887 #if defined (__STDC__) || defined (__cplusplus)
888 int
889 yyparse (void)
890 #else
891 int
892 yyparse ()
893
894 #endif
895 #endif
896 {
897
898 register int yystate;
899 register int yyn;
900 int yyresult;
901 /* Number of tokens to shift before error messages enabled. */
902 int yyerrstatus;
903 /* Lookahead token as an internal (translated) token number. */
904 int yytoken = 0;
905
906 /* Three stacks and their tools:
907 `yyss': related to states,
908 `yyvs': related to semantic values,
909 `yyls': related to locations.
910
911 Refer to the stacks thru separate pointers, to allow yyoverflow
912 to reallocate them elsewhere. */
913
914 /* The state stack. */
915 short int yyssa[YYINITDEPTH];
916 short int *yyss = yyssa;
917 register short int *yyssp;
918
919 /* The semantic value stack. */
920 YYSTYPE yyvsa[YYINITDEPTH];
921 YYSTYPE *yyvs = yyvsa;
922 register YYSTYPE *yyvsp;
923
924
925
926 #define YYPOPSTACK (yyvsp--, yyssp--)
927
928 YYSIZE_T yystacksize = YYINITDEPTH;
929
930 /* The variables used to return semantic value and location from the
931 action routines. */
932 YYSTYPE yyval;
933
934
935 /* When reducing, the number of symbols on the RHS of the reduced
936 rule. */
937 int yylen;
938
939 YYDPRINTF ((stderr, "Starting parse\n"));
940
941 yystate = 0;
942 yyerrstatus = 0;
943 yynerrs = 0;
944 yychar = YYEMPTY; /* Cause a token to be read. */
945
946 /* Initialize stack pointers.
947 Waste one element of value and location stack
948 so that they stay on the same level as the state stack.
949 The wasted elements are never initialized. */
950
951 yyssp = yyss;
952 yyvsp = yyvs;
953
954
955 goto yysetstate;
956
957 /*------------------------------------------------------------.
958 | yynewstate -- Push a new state, which is found in yystate. |
959 `------------------------------------------------------------*/
960 yynewstate:
961 /* In all cases, when you get here, the value and location stacks
962 have just been pushed. so pushing a state here evens the stacks.
963 */
964 yyssp++;
965
966 yysetstate:
967 *yyssp = yystate;
968
969 if (yyss + yystacksize - 1 <= yyssp)
970 {
971 /* Get the current used size of the three stacks, in elements. */
972 YYSIZE_T yysize = yyssp - yyss + 1;
973
974 #ifdef yyoverflow
975 {
976 /* Give user a chance to reallocate the stack. Use copies of
977 these so that the &'s don't force the real ones into
978 memory. */
979 YYSTYPE *yyvs1 = yyvs;
980 short int *yyss1 = yyss;
981
982
983 /* Each stack pointer address is followed by the size of the
984 data in use in that stack, in bytes. This used to be a
985 conditional around just the two extra args, but that might
986 be undefined if yyoverflow is a macro. */
987 yyoverflow ("parser stack overflow",
988 &yyss1, yysize * sizeof (*yyssp),
989 &yyvs1, yysize * sizeof (*yyvsp),
990
991 &yystacksize);
992
993 yyss = yyss1;
994 yyvs = yyvs1;
995 }
996 #else /* no yyoverflow */
997 # ifndef YYSTACK_RELOCATE
998 goto yyoverflowlab;
999 # else
1000 /* Extend the stack our own way. */
1001 if (YYMAXDEPTH <= yystacksize)
1002 goto yyoverflowlab;
1003 yystacksize *= 2;
1004 if (YYMAXDEPTH < yystacksize)
1005 yystacksize = YYMAXDEPTH;
1006
1007 {
1008 short int *yyss1 = yyss;
1009 union yyalloc *yyptr =
1010 (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
1011 if (! yyptr)
1012 goto yyoverflowlab;
1013 YYSTACK_RELOCATE (yyss);
1014 YYSTACK_RELOCATE (yyvs);
1015
1016 # undef YYSTACK_RELOCATE
1017 if (yyss1 != yyssa)
1018 YYSTACK_FREE (yyss1);
1019 }
1020 # endif
1021 #endif /* no yyoverflow */
1022
1023 yyssp = yyss + yysize - 1;
1024 yyvsp = yyvs + yysize - 1;
1025
1026
1027 YYDPRINTF ((stderr, "Stack size increased to %lu\n",
1028 (unsigned long int) yystacksize));
1029
1030 if (yyss + yystacksize - 1 <= yyssp)
1031 YYABORT;
1032 }
1033
1034 YYDPRINTF ((stderr, "Entering state %d\n", yystate));
1035
1036 goto yybackup;
1037
1038 /*-----------.
1039 | yybackup. |
1040 `-----------*/
1041 yybackup:
1042
1043 /* Do appropriate processing given the current state. */
1044 /* Read a lookahead token if we need one and don't already have one. */
1045 /* yyresume: */
1046
1047 /* First try to decide what to do without reference to lookahead token. */
1048
1049 yyn = yypact[yystate];
1050 if (yyn == YYPACT_NINF)
1051 goto yydefault;
1052
1053 /* Not known => get a lookahead token if don't already have one. */
1054
1055 /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
1056 if (yychar == YYEMPTY)
1057 {
1058 YYDPRINTF ((stderr, "Reading a token: "));
1059 yychar = YYLEX;
1060 }
1061
1062 if (yychar <= YYEOF)
1063 {
1064 yychar = yytoken = YYEOF;
1065 YYDPRINTF ((stderr, "Now at end of input.\n"));
1066 }
1067 else
1068 {
1069 yytoken = YYTRANSLATE (yychar);
1070 YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
1071 }
1072
1073 /* If the proper action on seeing token YYTOKEN is to reduce or to
1074 detect an error, take that action. */
1075 yyn += yytoken;
1076 if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
1077 goto yydefault;
1078 yyn = yytable[yyn];
1079 if (yyn <= 0)
1080 {
1081 if (yyn == 0 || yyn == YYTABLE_NINF)
1082 goto yyerrlab;
1083 yyn = -yyn;
1084 goto yyreduce;
1085 }
1086
1087 if (yyn == YYFINAL)
1088 YYACCEPT;
1089
1090 /* Shift the lookahead token. */
1091 YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
1092
1093 /* Discard the token being shifted unless it is eof. */
1094 if (yychar != YYEOF)
1095 yychar = YYEMPTY;
1096
1097 *++yyvsp = yylval;
1098
1099
1100 /* Count tokens shifted since error; after three, turn off error
1101 status. */
1102 if (yyerrstatus)
1103 yyerrstatus--;
1104
1105 yystate = yyn;
1106 goto yynewstate;
1107
1108
1109 /*-----------------------------------------------------------.
1110 | yydefault -- do the default action for the current state. |
1111 `-----------------------------------------------------------*/
1112 yydefault:
1113 yyn = yydefact[yystate];
1114 if (yyn == 0)
1115 goto yyerrlab;
1116 goto yyreduce;
1117
1118
1119 /*-----------------------------.
1120 | yyreduce -- Do a reduction. |
1121 `-----------------------------*/
1122 yyreduce:
1123 /* yyn is the number of a rule to reduce with. */
1124 yylen = yyr2[yyn];
1125
1126 /* If YYLEN is nonzero, implement the default value of the action:
1127 `$$ = $1'.
1128
1129 Otherwise, the following line sets YYVAL to garbage.
1130 This behavior is undocumented and Bison
1131 users should not rely upon it. Assigning to YYVAL
1132 unconditionally makes the parser a bit smaller, and it avoids a
1133 GCC warning that YYVAL may be used uninitialized. */
1134 yyval = yyvsp[1-yylen];
1135
1136
1137 YY_REDUCE_PRINT (yyn);
1138 switch (yyn)
1139 {
1140 case 2:
1141 #line 76 "arith.y"
1142 {
1143 return (yyvsp[0]);
1144 ;}
1145 break;
1146
1147 case 3:
1148 #line 82 "arith.y"
1149 { yyval = yyvsp[-1]; ;}
1150 break;
1151
1152 case 4:
1153 #line 83 "arith.y"
1154 { yyval = yyvsp[-2] ? yyvsp[-2] : yyvsp[0] ? yyvsp[0] : 0; ;}
1155 break;
1156
1157 case 5:
1158 #line 84 "arith.y"
1159 { yyval = yyvsp[-2] ? ( yyvsp[0] ? yyvsp[0] : 0 ) : 0; ;}
1160 break;
1161
1162 case 6:
1163 #line 85 "arith.y"
1164 { yyval = yyvsp[-2] | yyvsp[0]; ;}
1165 break;
1166
1167 case 7:
1168 #line 86 "arith.y"
1169 { yyval = yyvsp[-2] ^ yyvsp[0]; ;}
1170 break;
1171
1172 case 8:
1173 #line 87 "arith.y"
1174 { yyval = yyvsp[-2] & yyvsp[0]; ;}
1175 break;
1176
1177 case 9:
1178 #line 88 "arith.y"
1179 { yyval = yyvsp[-2] == yyvsp[0]; ;}
1180 break;
1181
1182 case 10:
1183 #line 89 "arith.y"
1184 { yyval = yyvsp[-2] > yyvsp[0]; ;}
1185 break;
1186
1187 case 11:
1188 #line 90 "arith.y"
1189 { yyval = yyvsp[-2] >= yyvsp[0]; ;}
1190 break;
1191
1192 case 12:
1193 #line 91 "arith.y"
1194 { yyval = yyvsp[-2] < yyvsp[0]; ;}
1195 break;
1196
1197 case 13:
1198 #line 92 "arith.y"
1199 { yyval = yyvsp[-2] <= yyvsp[0]; ;}
1200 break;
1201
1202 case 14:
1203 #line 93 "arith.y"
1204 { yyval = yyvsp[-2] != yyvsp[0]; ;}
1205 break;
1206
1207 case 15:
1208 #line 94 "arith.y"
1209 { yyval = yyvsp[-2] << yyvsp[0]; ;}
1210 break;
1211
1212 case 16:
1213 #line 95 "arith.y"
1214 { yyval = yyvsp[-2] >> yyvsp[0]; ;}
1215 break;
1216
1217 case 17:
1218 #line 96 "arith.y"
1219 { yyval = yyvsp[-2] + yyvsp[0]; ;}
1220 break;
1221
1222 case 18:
1223 #line 97 "arith.y"
1224 { yyval = yyvsp[-2] - yyvsp[0]; ;}
1225 break;
1226
1227 case 19:
1228 #line 98 "arith.y"
1229 { yyval = yyvsp[-2] * yyvsp[0]; ;}
1230 break;
1231
1232 case 20:
1233 #line 99 "arith.y"
1234 {
1235 if (yyvsp[0] == 0)
1236 yyerror("division by zero");
1237 yyval = yyvsp[-2] / yyvsp[0];
1238 ;}
1239 break;
1240
1241 case 21:
1242 #line 104 "arith.y"
1243 {
1244 if (yyvsp[0] == 0)
1245 yyerror("division by zero");
1246 yyval = yyvsp[-2] % yyvsp[0];
1247 ;}
1248 break;
1249
1250 case 22:
1251 #line 109 "arith.y"
1252 { yyval = !(yyvsp[0]); ;}
1253 break;
1254
1255 case 23:
1256 #line 110 "arith.y"
1257 { yyval = ~(yyvsp[0]); ;}
1258 break;
1259
1260 case 24:
1261 #line 111 "arith.y"
1262 { yyval = -(yyvsp[0]); ;}
1263 break;
1264
1265 case 25:
1266 #line 112 "arith.y"
1267 { yyval = yyvsp[0]; ;}
1268 break;
1269
1270
1271 }
1272
1273 /* Line 1010 of yacc.c. */
1274 #line 1276 "arith.c"
1275
1276 yyvsp -= yylen;
1277 yyssp -= yylen;
1278
1279
1280 YY_STACK_PRINT (yyss, yyssp);
1281
1282 *++yyvsp = yyval;
1283
1284
1285 /* Now `shift' the result of the reduction. Determine what state
1286 that goes to, based on the state we popped back to and the rule
1287 number reduced by. */
1288
1289 yyn = yyr1[yyn];
1290
1291 yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
1292 if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1293 yystate = yytable[yystate];
1294 else
1295 yystate = yydefgoto[yyn - YYNTOKENS];
1296
1297 goto yynewstate;
1298
1299
1300 /*------------------------------------.
1301 | yyerrlab -- here on detecting error |
1302 `------------------------------------*/
1303 yyerrlab:
1304 /* If not already recovering from an error, report this error. */
1305 if (!yyerrstatus)
1306 {
1307 ++yynerrs;
1308 #if YYERROR_VERBOSE
1309 yyn = yypact[yystate];
1310
1311 if (YYPACT_NINF < yyn && yyn < YYLAST)
1312 {
1313 YYSIZE_T yysize = 0;
1314 int yytype = YYTRANSLATE (yychar);
1315 const char* yyprefix;
1316 char *yymsg;
1317 int yyx;
1318
1319 /* Start YYX at -YYN if negative to avoid negative indexes in
1320 YYCHECK. */
1321 int yyxbegin = yyn < 0 ? -yyn : 0;
1322
1323 /* Stay within bounds of both yycheck and yytname. */
1324 int yychecklim = YYLAST - yyn;
1325 int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
1326 int yycount = 0;
1327
1328 yyprefix = ", expecting ";
1329 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1330 if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
1331 {
1332 yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
1333 yycount += 1;
1334 if (yycount == 5)
1335 {
1336 yysize = 0;
1337 break;
1338 }
1339 }
1340 yysize += (sizeof ("syntax error, unexpected ")
1341 + yystrlen (yytname[yytype]));
1342 yymsg = (char *) YYSTACK_ALLOC (yysize);
1343 if (yymsg != 0)
1344 {
1345 char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
1346 yyp = yystpcpy (yyp, yytname[yytype]);
1347
1348 if (yycount < 5)
1349 {
1350 yyprefix = ", expecting ";
1351 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1352 if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
1353 {
1354 yyp = yystpcpy (yyp, yyprefix);
1355 yyp = yystpcpy (yyp, yytname[yyx]);
1356 yyprefix = " or ";
1357 }
1358 }
1359 yyerror (yymsg);
1360 YYSTACK_FREE (yymsg);
1361 }
1362 else
1363 yyerror ("syntax error; also virtual memory exhausted");
1364 }
1365 else
1366 #endif /* YYERROR_VERBOSE */
1367 yyerror ("syntax error");
1368 }
1369
1370
1371
1372 if (yyerrstatus == 3)
1373 {
1374 /* If just tried and failed to reuse lookahead token after an
1375 error, discard it. */
1376
1377 if (yychar <= YYEOF)
1378 {
1379 /* If at end of input, pop the error token,
1380 then the rest of the stack, then return failure. */
1381 if (yychar == YYEOF)
1382 for (;;)
1383 {
1384 YYPOPSTACK;
1385 if (yyssp == yyss)
1386 YYABORT;
1387 YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
1388 yydestruct (yystos[*yyssp], yyvsp);
1389 }
1390 }
1391 else
1392 {
1393 YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
1394 yydestruct (yytoken, &yylval);
1395 yychar = YYEMPTY;
1396
1397 }
1398 }
1399
1400 /* Else will try to reuse lookahead token after shifting the error
1401 token. */
1402 goto yyerrlab1;
1403
1404
1405 /*---------------------------------------------------.
1406 | yyerrorlab -- error raised explicitly by YYERROR. |
1407 `---------------------------------------------------*/
1408 yyerrorlab:
1409
1410 #ifdef __GNUC__
1411 /* Pacify GCC when the user code never invokes YYERROR and the label
1412 yyerrorlab therefore never appears in user code. */
1413 if (0)
1414 goto yyerrorlab;
1415 #endif
1416
1417 yyvsp -= yylen;
1418 yyssp -= yylen;
1419 yystate = *yyssp;
1420 goto yyerrlab1;
1421
1422
1423 /*-------------------------------------------------------------.
1424 | yyerrlab1 -- common code for both syntax error and YYERROR. |
1425 `-------------------------------------------------------------*/
1426 yyerrlab1:
1427 yyerrstatus = 3; /* Each real token shifted decrements this. */
1428
1429 for (;;)
1430 {
1431 yyn = yypact[yystate];
1432 if (yyn != YYPACT_NINF)
1433 {
1434 yyn += YYTERROR;
1435 if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
1436 {
1437 yyn = yytable[yyn];
1438 if (0 < yyn)
1439 break;
1440 }
1441 }
1442
1443 /* Pop the current state because it cannot handle the error token. */
1444 if (yyssp == yyss)
1445 YYABORT;
1446
1447 YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
1448 yydestruct (yystos[yystate], yyvsp);
1449 YYPOPSTACK;
1450 yystate = *yyssp;
1451 YY_STACK_PRINT (yyss, yyssp);
1452 }
1453
1454 if (yyn == YYFINAL)
1455 YYACCEPT;
1456
1457 YYDPRINTF ((stderr, "Shifting error token, "));
1458
1459 *++yyvsp = yylval;
1460
1461
1462 yystate = yyn;
1463 goto yynewstate;
1464
1465
1466 /*-------------------------------------.
1467 | yyacceptlab -- YYACCEPT comes here. |
1468 `-------------------------------------*/
1469 yyacceptlab:
1470 yyresult = 0;
1471 goto yyreturn;
1472
1473 /*-----------------------------------.
1474 | yyabortlab -- YYABORT comes here. |
1475 `-----------------------------------*/
1476 yyabortlab:
1477 yyresult = 1;
1478 goto yyreturn;
1479
1480 #ifndef yyoverflow
1481 /*----------------------------------------------.
1482 | yyoverflowlab -- parser overflow comes here. |
1483 `----------------------------------------------*/
1484 yyoverflowlab:
1485 yyerror ("parser stack overflow");
1486 yyresult = 2;
1487 /* Fall through. */
1488 #endif
1489
1490 yyreturn:
1491 #ifndef yyoverflow
1492 if (yyss != yyssa)
1493 YYSTACK_FREE (yyss);
1494 #endif
1495 return yyresult;
1496 }
1497
1498
1499 #line 115 "arith.y"
1500
1501 int
1502 arith(s)
1503 const char *s;
1504 {
1505 long result;
1506
1507 arith_buf = arith_startbuf = s;
1508
1509 INTOFF;
1510 result = yyparse();
1511 arith_lex_reset(); /* reprime lex */
1512 INTON;
1513
1514 return (result);
1515 }
1516
1517
1518 /*
1519 * The exp(1) builtin.
1520 */
1521 int
1522 expcmd(argc, argv)
1523 int argc;
1524 char **argv;
1525 {
1526 const char *p;
1527 char *concat;
1528 char **ap;
1529 long i;
1530
1531 if (argc > 1) {
1532 p = argv[1];
1533 if (argc > 2) {
1534 /*
1535 * concatenate arguments
1536 */
1537 STARTSTACKSTR(concat);
1538 ap = argv + 2;
1539 for (;;) {
1540 while (*p)
1541 STPUTC(*p++, concat);
1542 if ((p = *ap++) == NULL)
1543 break;
1544 STPUTC(' ', concat);
1545 }
1546 STPUTC('\0', concat);
1547 p = grabstackstr(concat);
1548 }
1549 } else
1550 p = "";
1551
1552 i = arith(p);
1553
1554 out1fmt("%ld\n", i);
1555 return (! i);
1556 }
1557
1558 /*************************/
1559 #ifdef TEST_ARITH
1560 #include <stdio.h>
1561 main(argc, argv)
1562 char *argv[];
1563 {
1564 printf("%d\n", exp(argv[1]));
1565 }
1566 error(s)
1567 char *s;
1568 {
1569 fprintf(stderr, "exp: %s\n", s);
1570 exit(1);
1571 }
1572 #endif
1573
1574 void
1575 yyerror(s)
1576 const char *s;
1577 {
1578
1579 // yyerrok;
1580 yyclearin;
1581 arith_lex_reset(); /* reprime lex */
1582 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
1583 /* NOTREACHED */
1584 }
1585
1586
+0
-25
sh/arith.h less more
0 #define ARITH_NUM 258
1 #define ARITH_LPAREN 259
2 #define ARITH_RPAREN 260
3 #define ARITH_OR 261
4 #define ARITH_AND 262
5 #define ARITH_BOR 263
6 #define ARITH_BXOR 264
7 #define ARITH_BAND 265
8 #define ARITH_NE 266
9 #define ARITH_EQ 267
10 #define ARITH_LE 268
11 #define ARITH_GE 269
12 #define ARITH_GT 270
13 #define ARITH_LT 271
14 #define ARITH_RSHIFT 272
15 #define ARITH_LSHIFT 273
16 #define ARITH_SUB 274
17 #define ARITH_ADD 275
18 #define ARITH_REM 276
19 #define ARITH_DIV 277
20 #define ARITH_MUL 278
21 #define ARITH_BNOT 279
22 #define ARITH_NOT 280
23 #define ARITH_UNARYPLUS 281
24 #define ARITH_UNARYMINUS 282
+0
-199
sh/arith.y less more
0 %{
1 /* $NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $ */
2
3 /*-
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <stdlib.h>
45 #include "expand.h"
46 #include "shell.h"
47 #include "error.h"
48 #include "output.h"
49 #include "memalloc.h"
50
51 const char *arith_buf, *arith_startbuf;
52
53 void yyerror(const char *);
54 #ifdef TESTARITH
55 int main(int , char *[]);
56 int error(char *);
57 #endif
58
59 %}
60 %token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
61
62 %left ARITH_OR
63 %left ARITH_AND
64 %left ARITH_BOR
65 %left ARITH_BXOR
66 %left ARITH_BAND
67 %left ARITH_EQ ARITH_NE
68 %left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
69 %left ARITH_LSHIFT ARITH_RSHIFT
70 %left ARITH_ADD ARITH_SUB
71 %left ARITH_MUL ARITH_DIV ARITH_REM
72 %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
73 %%
74
75 exp: expr {
76 return ($1);
77 }
78 ;
79
80
81 expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }
82 | expr ARITH_OR expr { $$ = $1 ? $1 : $3 ? $3 : 0; }
83 | expr ARITH_AND expr { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; }
84 | expr ARITH_BOR expr { $$ = $1 | $3; }
85 | expr ARITH_BXOR expr { $$ = $1 ^ $3; }
86 | expr ARITH_BAND expr { $$ = $1 & $3; }
87 | expr ARITH_EQ expr { $$ = $1 == $3; }
88 | expr ARITH_GT expr { $$ = $1 > $3; }
89 | expr ARITH_GE expr { $$ = $1 >= $3; }
90 | expr ARITH_LT expr { $$ = $1 < $3; }
91 | expr ARITH_LE expr { $$ = $1 <= $3; }
92 | expr ARITH_NE expr { $$ = $1 != $3; }
93 | expr ARITH_LSHIFT expr { $$ = $1 << $3; }
94 | expr ARITH_RSHIFT expr { $$ = $1 >> $3; }
95 | expr ARITH_ADD expr { $$ = $1 + $3; }
96 | expr ARITH_SUB expr { $$ = $1 - $3; }
97 | expr ARITH_MUL expr { $$ = $1 * $3; }
98 | expr ARITH_DIV expr {
99 if ($3 == 0)
100 yyerror("division by zero");
101 $$ = $1 / $3;
102 }
103 | expr ARITH_REM expr {
104 if ($3 == 0)
105 yyerror("division by zero");
106 $$ = $1 % $3;
107 }
108 | ARITH_NOT expr { $$ = !($2); }
109 | ARITH_BNOT expr { $$ = ~($2); }
110 | ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); }
111 | ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; }
112 | ARITH_NUM
113 ;
114 %%
115 int
116 arith(s)
117 const char *s;
118 {
119 long result;
120
121 arith_buf = arith_startbuf = s;
122
123 INTOFF;
124 result = yyparse();
125 arith_lex_reset(); /* reprime lex */
126 INTON;
127
128 return (result);
129 }
130
131
132 /*
133 * The exp(1) builtin.
134 */
135 int
136 expcmd(argc, argv)
137 int argc;
138 char **argv;
139 {
140 const char *p;
141 char *concat;
142 char **ap;
143 long i;
144
145 if (argc > 1) {
146 p = argv[1];
147 if (argc > 2) {
148 /*
149 * concatenate arguments
150 */
151 STARTSTACKSTR(concat);
152 ap = argv + 2;
153 for (;;) {
154 while (*p)
155 STPUTC(*p++, concat);
156 if ((p = *ap++) == NULL)
157 break;
158 STPUTC(' ', concat);
159 }
160 STPUTC('\0', concat);
161 p = grabstackstr(concat);
162 }
163 } else
164 p = "";
165
166 i = arith(p);
167
168 out1fmt("%ld\n", i);
169 return (! i);
170 }
171
172 /*************************/
173 #ifdef TEST_ARITH
174 #include <stdio.h>
175 main(argc, argv)
176 char *argv[];
177 {
178 printf("%d\n", exp(argv[1]));
179 }
180 error(s)
181 char *s;
182 {
183 fprintf(stderr, "exp: %s\n", s);
184 exit(1);
185 }
186 #endif
187
188 void
189 yyerror(s)
190 const char *s;
191 {
192
193 // yyerrok;
194 yyclearin;
195 arith_lex_reset(); /* reprime lex */
196 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
197 /* NOTREACHED */
198 }
+0
-1890
sh/arith_lex.c less more
0 #line 2 "arith_lex.c"
1
2 #line 4 "arith_lex.c"
3
4 #define YY_INT_ALIGNED short int
5
6 /* A lexical scanner generated by flex */
7
8 #define FLEX_SCANNER
9 #define YY_FLEX_MAJOR_VERSION 2
10 #define YY_FLEX_MINOR_VERSION 5
11 #define YY_FLEX_SUBMINOR_VERSION 31
12 #if YY_FLEX_SUBMINOR_VERSION > 0
13 #define FLEX_BETA
14 #endif
15
16 /* First, we deal with platform-specific or compiler-specific issues. */
17
18 /* begin standard C headers. */
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdlib.h>
23
24 /* end standard C headers. */
25
26 /* flex integer type definitions */
27
28 #ifndef FLEXINT_H
29 #define FLEXINT_H
30
31 /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
32
33 #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
34 #include <inttypes.h>
35 typedef int8_t flex_int8_t;
36 typedef uint8_t flex_uint8_t;
37 typedef int16_t flex_int16_t;
38 typedef uint16_t flex_uint16_t;
39 typedef int32_t flex_int32_t;
40 typedef uint32_t flex_uint32_t;
41 #else
42 typedef signed char flex_int8_t;
43 typedef short int flex_int16_t;
44 typedef int flex_int32_t;
45 typedef unsigned char flex_uint8_t;
46 typedef unsigned short int flex_uint16_t;
47 typedef unsigned int flex_uint32_t;
48 #endif /* ! C99 */
49
50 /* Limits of integral types. */
51 #ifndef INT8_MIN
52 #define INT8_MIN (-128)
53 #endif
54 #ifndef INT16_MIN
55 #define INT16_MIN (-32767-1)
56 #endif
57 #ifndef INT32_MIN
58 #define INT32_MIN (-2147483647-1)
59 #endif
60 #ifndef INT8_MAX
61 #define INT8_MAX (127)
62 #endif
63 #ifndef INT16_MAX
64 #define INT16_MAX (32767)
65 #endif
66 #ifndef INT32_MAX
67 #define INT32_MAX (2147483647)
68 #endif
69 #ifndef UINT8_MAX
70 #define UINT8_MAX (255U)
71 #endif
72 #ifndef UINT16_MAX
73 #define UINT16_MAX (65535U)
74 #endif
75 #ifndef UINT32_MAX
76 #define UINT32_MAX (4294967295U)
77 #endif
78
79 #endif /* ! FLEXINT_H */
80
81 #ifdef __cplusplus
82
83 /* The "const" storage-class-modifier is valid. */
84 #define YY_USE_CONST
85
86 #else /* ! __cplusplus */
87
88 #if __STDC__
89
90 #define YY_USE_CONST
91
92 #endif /* __STDC__ */
93 #endif /* ! __cplusplus */
94
95 #ifdef YY_USE_CONST
96 #define yyconst const
97 #else
98 #define yyconst
99 #endif
100
101 /* Returned upon end-of-file. */
102 #define YY_NULL 0
103
104 /* Promotes a possibly negative, possibly signed char to an unsigned
105 * integer for use as an array index. If the signed char is negative,
106 * we want to instead treat it as an 8-bit unsigned char, hence the
107 * double cast.
108 */
109 #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
110
111 /* Enter a start condition. This macro really ought to take a parameter,
112 * but we do it the disgusting crufty way forced on us by the ()-less
113 * definition of BEGIN.
114 */
115 #define BEGIN (yy_start) = 1 + 2 *
116
117 /* Translate the current start state into a value that can be later handed
118 * to BEGIN to return to the state. The YYSTATE alias is for lex
119 * compatibility.
120 */
121 #define YY_START (((yy_start) - 1) / 2)
122 #define YYSTATE YY_START
123
124 /* Action number for EOF rule of a given start state. */
125 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
126
127 /* Special action meaning "start processing a new file". */
128 #define YY_NEW_FILE yyrestart(yyin )
129
130 #define YY_END_OF_BUFFER_CHAR 0
131
132 /* Size of default input buffer. */
133 #ifndef YY_BUF_SIZE
134 #define YY_BUF_SIZE 16384
135 #endif
136
137 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
138 #define YY_TYPEDEF_YY_BUFFER_STATE
139 typedef struct yy_buffer_state *YY_BUFFER_STATE;
140 #endif
141
142 extern int yyleng;
143
144 extern FILE *yyin, *yyout;
145
146 #define EOB_ACT_CONTINUE_SCAN 0
147 #define EOB_ACT_END_OF_FILE 1
148 #define EOB_ACT_LAST_MATCH 2
149
150 #define YY_LESS_LINENO(n)
151
152 /* Return all but the first "n" matched characters back to the input stream. */
153 #define yyless(n) \
154 do \
155 { \
156 /* Undo effects of setting up yytext. */ \
157 int yyless_macro_arg = (n); \
158 YY_LESS_LINENO(yyless_macro_arg);\
159 *yy_cp = (yy_hold_char); \
160 YY_RESTORE_YY_MORE_OFFSET \
161 (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
162 YY_DO_BEFORE_ACTION; /* set up yytext again */ \
163 } \
164 while ( 0 )
165
166 #define unput(c) yyunput( c, (yytext_ptr) )
167
168 /* The following is because we cannot portably get our hands on size_t
169 * (without autoconf's help, which isn't available because we want
170 * flex-generated scanners to compile on their own).
171 */
172
173 #ifndef YY_TYPEDEF_YY_SIZE_T
174 #define YY_TYPEDEF_YY_SIZE_T
175 typedef unsigned int yy_size_t;
176 #endif
177
178 #ifndef YY_STRUCT_YY_BUFFER_STATE
179 #define YY_STRUCT_YY_BUFFER_STATE
180 struct yy_buffer_state
181 {
182 FILE *yy_input_file;
183
184 char *yy_ch_buf; /* input buffer */
185 char *yy_buf_pos; /* current position in input buffer */
186
187 /* Size of input buffer in bytes, not including room for EOB
188 * characters.
189 */
190 yy_size_t yy_buf_size;
191
192 /* Number of characters read into yy_ch_buf, not including EOB
193 * characters.
194 */
195 int yy_n_chars;
196
197 /* Whether we "own" the buffer - i.e., we know we created it,
198 * and can realloc() it to grow it, and should free() it to
199 * delete it.
200 */
201 int yy_is_our_buffer;
202
203 /* Whether this is an "interactive" input source; if so, and
204 * if we're using stdio for input, then we want to use getc()
205 * instead of fread(), to make sure we stop fetching input after
206 * each newline.
207 */
208 int yy_is_interactive;
209
210 /* Whether we're considered to be at the beginning of a line.
211 * If so, '^' rules will be active on the next match, otherwise
212 * not.
213 */
214 int yy_at_bol;
215
216 int yy_bs_lineno; /**< The line count. */
217 int yy_bs_column; /**< The column count. */
218
219 /* Whether to try to fill the input buffer when we reach the
220 * end of it.
221 */
222 int yy_fill_buffer;
223
224 int yy_buffer_status;
225
226 #define YY_BUFFER_NEW 0
227 #define YY_BUFFER_NORMAL 1
228 /* When an EOF's been seen but there's still some text to process
229 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
230 * shouldn't try reading from the input source any more. We might
231 * still have a bunch of tokens to match, though, because of
232 * possible backing-up.
233 *
234 * When we actually see the EOF, we change the status to "new"
235 * (via yyrestart()), so that the user can continue scanning by
236 * just pointing yyin at a new input file.
237 */
238 #define YY_BUFFER_EOF_PENDING 2
239
240 };
241 #endif /* !YY_STRUCT_YY_BUFFER_STATE */
242
243 /* Stack of input buffers. */
244 static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
245 static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
246 static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
247
248 /* We provide macros for accessing buffer states in case in the
249 * future we want to put the buffer states in a more general
250 * "scanner state".
251 *
252 * Returns the top of the stack, or NULL.
253 */
254 #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
255 ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
256 : NULL)
257
258 /* Same as previous macro, but useful when we know that the buffer stack is not
259 * NULL or when we need an lvalue. For internal use only.
260 */
261 #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
262
263 /* yy_hold_char holds the character lost when yytext is formed. */
264 static char yy_hold_char;
265 static int yy_n_chars; /* number of characters read into yy_ch_buf */
266 int yyleng;
267
268 /* Points to current character in buffer. */
269 static char *yy_c_buf_p = (char *) 0;
270 static int yy_init = 1; /* whether we need to initialize */
271 static int yy_start = 0; /* start state number */
272
273 /* Flag which is used to allow yywrap()'s to do buffer switches
274 * instead of setting up a fresh yyin. A bit of a hack ...
275 */
276 static int yy_did_buffer_switch_on_eof;
277
278 void yyrestart (FILE *input_file );
279 void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
280 YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
281 void yy_delete_buffer (YY_BUFFER_STATE b );
282 void yy_flush_buffer (YY_BUFFER_STATE b );
283 void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
284 void yypop_buffer_state (void );
285
286 static void yyensure_buffer_stack (void );
287 static void yy_load_buffer_state (void );
288 static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
289
290 #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
291
292 YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
293 YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
294 YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
295
296 void *yyalloc (yy_size_t );
297 void *yyrealloc (void *,yy_size_t );
298 void yyfree (void * );
299
300 #define yy_new_buffer yy_create_buffer
301
302 #define yy_set_interactive(is_interactive) \
303 { \
304 if ( ! YY_CURRENT_BUFFER ){ \
305 yyensure_buffer_stack (); \
306 YY_CURRENT_BUFFER_LVALUE = \
307 yy_create_buffer(yyin,YY_BUF_SIZE ); \
308 } \
309 YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
310 }
311
312 #define yy_set_bol(at_bol) \
313 { \
314 if ( ! YY_CURRENT_BUFFER ){\
315 yyensure_buffer_stack (); \
316 YY_CURRENT_BUFFER_LVALUE = \
317 yy_create_buffer(yyin,YY_BUF_SIZE ); \
318 } \
319 YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
320 }
321
322 #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
323
324 /* Begin user sect3 */
325
326 #define yywrap(n) 1
327 #define YY_SKIP_YYWRAP
328
329 typedef unsigned char YY_CHAR;
330
331 FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
332
333 typedef int yy_state_type;
334
335 extern int yylineno;
336
337 int yylineno = 1;
338
339 extern char *yytext;
340 #define yytext_ptr yytext
341
342 static yy_state_type yy_get_previous_state (void );
343 static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
344 static int yy_get_next_buffer (void );
345 static void yy_fatal_error (yyconst char msg[] );
346
347 /* Done after the current pattern has been matched and before the
348 * corresponding action - sets up yytext.
349 */
350 #define YY_DO_BEFORE_ACTION \
351 (yytext_ptr) = yy_bp; \
352 yyleng = (size_t) (yy_cp - yy_bp); \
353 (yy_hold_char) = *yy_cp; \
354 *yy_cp = '\0'; \
355 (yy_c_buf_p) = yy_cp;
356
357 #define YY_NUM_RULES 29
358 #define YY_END_OF_BUFFER 30
359 /* This struct is not used in this scanner,
360 but its presence is necessary. */
361 struct yy_trans_info
362 {
363 flex_int32_t yy_verify;
364 flex_int32_t yy_nxt;
365 };
366 static yyconst flex_int16_t yy_accept[39] =
367 { 0,
368 0, 0, 30, 28, 1, 1, 27, 23, 12, 6,
369 7, 21, 24, 25, 22, 3, 4, 17, 28, 15,
370 5, 11, 10, 26, 14, 9, 3, 0, 4, 19,
371 18, 13, 16, 20, 5, 8, 2, 0
372 } ;
373
374 static yyconst flex_int32_t yy_ec[256] =
375 { 0,
376 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
379 1, 2, 4, 1, 1, 1, 5, 6, 1, 7,
380 8, 9, 10, 1, 11, 1, 12, 13, 14, 14,
381 14, 14, 14, 14, 14, 15, 15, 1, 1, 16,
382 17, 18, 1, 1, 19, 19, 19, 19, 19, 19,
383 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
384 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
385 1, 1, 1, 21, 20, 1, 19, 19, 19, 19,
386
387 19, 19, 20, 20, 20, 20, 20, 20, 20, 20,
388 20, 20, 20, 20, 20, 20, 20, 20, 20, 22,
389 20, 20, 1, 23, 1, 24, 1, 1, 1, 1,
390 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
391 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
392 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
393 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
394 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
395 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
396 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
397
398 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
399 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
400 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
401 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
402 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
403 1, 1, 1, 1, 1
404 } ;
405
406 static yyconst flex_int32_t yy_meta[25] =
407 { 0,
408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
409 1, 1, 2, 2, 2, 1, 1, 1, 2, 3,
410 1, 3, 1, 1
411 } ;
412
413 static yyconst flex_int16_t yy_base[41] =
414 { 0,
415 0, 0, 47, 48, 48, 48, 29, 48, 39, 48,
416 48, 48, 48, 48, 48, 12, 14, 14, 27, 15,
417 0, 48, 20, 48, 48, 48, 22, 0, 24, 48,
418 48, 48, 48, 48, 0, 48, 0, 48, 38, 40
419 } ;
420
421 static yyconst flex_int16_t yy_def[41] =
422 { 0,
423 38, 1, 38, 38, 38, 38, 38, 38, 38, 38,
424 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
425 39, 38, 38, 38, 38, 38, 38, 40, 38, 38,
426 38, 38, 38, 38, 39, 38, 40, 0, 38, 38
427 } ;
428
429 static yyconst flex_int16_t yy_nxt[73] =
430 { 0,
431 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
432 14, 15, 16, 17, 17, 18, 19, 20, 21, 21,
433 22, 21, 23, 24, 27, 27, 29, 29, 29, 30,
434 31, 33, 34, 28, 27, 27, 29, 29, 29, 35,
435 35, 37, 36, 32, 26, 25, 38, 3, 38, 38,
436 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
437 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
438 38, 38
439 } ;
440
441 static yyconst flex_int16_t yy_chk[73] =
442 { 0,
443 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
444 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
445 1, 1, 1, 1, 16, 16, 17, 17, 17, 18,
446 18, 20, 20, 16, 27, 27, 29, 29, 29, 39,
447 39, 40, 23, 19, 9, 7, 3, 38, 38, 38,
448 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
449 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
450 38, 38
451 } ;
452
453 static yy_state_type yy_last_accepting_state;
454 static char *yy_last_accepting_cpos;
455
456 extern int yy_flex_debug;
457 int yy_flex_debug = 0;
458
459 /* The intent behind this definition is that it'll catch
460 * any uses of REJECT which flex missed.
461 */
462 #define REJECT reject_used_but_not_detected
463 #define yymore() yymore_used_but_not_detected
464 #define YY_MORE_ADJ 0
465 #define YY_RESTORE_YY_MORE_OFFSET
466 char *yytext;
467 #line 1 "arith_lex.l"
468 #line 2 "arith_lex.l"
469 /* $NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $ */
470
471 /*-
472 * Copyright (c) 1993
473 * The Regents of the University of California. All rights reserved.
474 *
475 * This code is derived from software contributed to Berkeley by
476 * Kenneth Almquist.
477 *
478 * Redistribution and use in source and binary forms, with or without
479 * modification, are permitted provided that the following conditions
480 * are met:
481 * 1. Redistributions of source code must retain the above copyright
482 * notice, this list of conditions and the following disclaimer.
483 * 2. Redistributions in binary form must reproduce the above copyright
484 * notice, this list of conditions and the following disclaimer in the
485 * documentation and/or other materials provided with the distribution.
486 * 3. Neither the name of the University nor the names of its contributors
487 * may be used to endorse or promote products derived from this software
488 * without specific prior written permission.
489 *
490 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
491 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
492 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
493 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
494 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
495 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
496 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
497 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
498 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
499 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
500 * SUCH DAMAGE.
501 */
502
503 #include <sys/cdefs.h>
504 #ifndef lint
505 #if 0
506 static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95";
507 #else
508 __RCSID("$NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $");
509 #endif
510 #endif /* not lint */
511
512 #include <unistd.h>
513 #include "arith.h"
514 #include "error.h"
515 #include "expand.h"
516 #include "var.h"
517
518 extern int yylval;
519 extern char *arith_buf, *arith_startbuf;
520 #undef YY_INPUT
521 #define YY_INPUT(buf,result,max) \
522 result = (*buf = *arith_buf++) ? 1 : YY_NULL;
523 #define YY_NO_UNPUT
524 #line 526 "arith_lex.c"
525
526 #define INITIAL 0
527
528 #ifndef YY_NO_UNISTD_H
529 /* Special case for "unistd.h", since it is non-ANSI. We include it way
530 * down here because we want the user's section 1 to have been scanned first.
531 * The user has a chance to override it with an option.
532 */
533 #include <unistd.h>
534 #endif
535
536 #ifndef YY_EXTRA_TYPE
537 #define YY_EXTRA_TYPE void *
538 #endif
539
540 /* Macros after this point can all be overridden by user definitions in
541 * section 1.
542 */
543
544 #ifndef YY_SKIP_YYWRAP
545 #ifdef __cplusplus
546 extern "C" int yywrap (void );
547 #else
548 extern int yywrap (void );
549 #endif
550 #endif
551
552 static void yyunput (int c,char *buf_ptr );
553
554 #ifndef yytext_ptr
555 static void yy_flex_strncpy (char *,yyconst char *,int );
556 #endif
557
558 #ifdef YY_NEED_STRLEN
559 static int yy_flex_strlen (yyconst char * );
560 #endif
561
562 #ifndef YY_NO_INPUT
563
564 #ifdef __cplusplus
565 static int yyinput (void );
566 #else
567 static int input (void );
568 #endif
569
570 #endif
571
572 /* Amount of stuff to slurp up with each read. */
573 #ifndef YY_READ_BUF_SIZE
574 #define YY_READ_BUF_SIZE 8192
575 #endif
576
577 /* Copy whatever the last rule matched to the standard output. */
578 #ifndef ECHO
579 /* This used to be an fputs(), but since the string might contain NUL's,
580 * we now use fwrite().
581 */
582 #define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
583 #endif
584
585 /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
586 * is returned in "result".
587 */
588 #ifndef YY_INPUT
589 #define YY_INPUT(buf,result,max_size) \
590 if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
591 { \
592 int c = '*'; \
593 size_t n; \
594 for ( n = 0; n < max_size && \
595 (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
596 buf[n] = (char) c; \
597 if ( c == '\n' ) \
598 buf[n++] = (char) c; \
599 if ( c == EOF && ferror( yyin ) ) \
600 YY_FATAL_ERROR( "input in flex scanner failed" ); \
601 result = n; \
602 } \
603 else \
604 { \
605 errno=0; \
606 while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
607 { \
608 if( errno != EINTR) \
609 { \
610 YY_FATAL_ERROR( "input in flex scanner failed" ); \
611 break; \
612 } \
613 errno=0; \
614 clearerr(yyin); \
615 } \
616 }\
617 \
618
619 #endif
620
621 /* No semi-colon after return; correct usage is to write "yyterminate();" -
622 * we don't want an extra ';' after the "return" because that will cause
623 * some compilers to complain about unreachable statements.
624 */
625 #ifndef yyterminate
626 #define yyterminate() return YY_NULL
627 #endif
628
629 /* Number of entries by which start-condition stack grows. */
630 #ifndef YY_START_STACK_INCR
631 #define YY_START_STACK_INCR 25
632 #endif
633
634 /* Report a fatal error. */
635 #ifndef YY_FATAL_ERROR
636 #define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
637 #endif
638
639 /* end tables serialization structures and prototypes */
640
641 /* Default declaration of generated scanner - a define so the user can
642 * easily add parameters.
643 */
644 #ifndef YY_DECL
645 #define YY_DECL_IS_OURS 1
646
647 extern int yylex (void);
648
649 #define YY_DECL int yylex (void)
650 #endif /* !YY_DECL */
651
652 /* Code executed at the beginning of each rule, after yytext and yyleng
653 * have been set up.
654 */
655 #ifndef YY_USER_ACTION
656 #define YY_USER_ACTION
657 #endif
658
659 /* Code executed at the end of each rule. */
660 #ifndef YY_BREAK
661 #define YY_BREAK break;
662 #endif
663
664 #define YY_RULE_SETUP \
665 YY_USER_ACTION
666
667 /** The main scanner function which does all the work.
668 */
669 YY_DECL
670 {
671 register yy_state_type yy_current_state;
672 register char *yy_cp, *yy_bp;
673 register int yy_act;
674
675 #line 60 "arith_lex.l"
676
677 #line 679 "arith_lex.c"
678
679 if ( (yy_init) )
680 {
681 (yy_init) = 0;
682
683 #ifdef YY_USER_INIT
684 YY_USER_INIT;
685 #endif
686
687 if ( ! (yy_start) )
688 (yy_start) = 1; /* first start state */
689
690 if ( ! yyin )
691 yyin = stdin;
692
693 if ( ! yyout )
694 yyout = stdout;
695
696 if ( ! YY_CURRENT_BUFFER ) {
697 yyensure_buffer_stack ();
698 YY_CURRENT_BUFFER_LVALUE =
699 yy_create_buffer(yyin,YY_BUF_SIZE );
700 }
701
702 yy_load_buffer_state( );
703 }
704
705 while ( 1 ) /* loops until end-of-file is reached */
706 {
707 yy_cp = (yy_c_buf_p);
708
709 /* Support of yytext. */
710 *yy_cp = (yy_hold_char);
711
712 /* yy_bp points to the position in yy_ch_buf of the start of
713 * the current run.
714 */
715 yy_bp = yy_cp;
716
717 yy_current_state = (yy_start);
718 yy_match:
719 do
720 {
721 register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
722 if ( yy_accept[yy_current_state] )
723 {
724 (yy_last_accepting_state) = yy_current_state;
725 (yy_last_accepting_cpos) = yy_cp;
726 }
727 while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
728 {
729 yy_current_state = (int) yy_def[yy_current_state];
730 if ( yy_current_state >= 39 )
731 yy_c = yy_meta[(unsigned int) yy_c];
732 }
733 yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
734 ++yy_cp;
735 }
736 while ( yy_base[yy_current_state] != 48 );
737
738 yy_find_action:
739 yy_act = yy_accept[yy_current_state];
740 if ( yy_act == 0 )
741 { /* have to back up */
742 yy_cp = (yy_last_accepting_cpos);
743 yy_current_state = (yy_last_accepting_state);
744 yy_act = yy_accept[yy_current_state];
745 }
746
747 YY_DO_BEFORE_ACTION;
748
749 do_action: /* This label is used only to access EOF actions. */
750
751 switch ( yy_act )
752 { /* beginning of action switch */
753 case 0: /* must back up */
754 /* undo the effects of YY_DO_BEFORE_ACTION */
755 *yy_cp = (yy_hold_char);
756 yy_cp = (yy_last_accepting_cpos);
757 yy_current_state = (yy_last_accepting_state);
758 goto yy_find_action;
759
760 case 1:
761 /* rule 1 can match eol */
762 YY_RULE_SETUP
763 #line 61 "arith_lex.l"
764 { ; }
765 YY_BREAK
766 case 2:
767 YY_RULE_SETUP
768 #line 62 "arith_lex.l"
769 { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); }
770 YY_BREAK
771 case 3:
772 YY_RULE_SETUP
773 #line 63 "arith_lex.l"
774 { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); }
775 YY_BREAK
776 case 4:
777 YY_RULE_SETUP
778 #line 64 "arith_lex.l"
779 { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); }
780 YY_BREAK
781 case 5:
782 YY_RULE_SETUP
783 #line 65 "arith_lex.l"
784 { char *v = lookupvar(yytext);
785 if (v) {
786 yylval = strtol(v, &v, 0);
787 if (*v == 0)
788 return ARITH_NUM;
789 }
790 error("arith: syntax error: \"%s\"", arith_startbuf);
791 }
792 YY_BREAK
793 case 6:
794 YY_RULE_SETUP
795 #line 73 "arith_lex.l"
796 { return(ARITH_LPAREN); }
797 YY_BREAK
798 case 7:
799 YY_RULE_SETUP
800 #line 74 "arith_lex.l"
801 { return(ARITH_RPAREN); }
802 YY_BREAK
803 case 8:
804 YY_RULE_SETUP
805 #line 75 "arith_lex.l"
806 { return(ARITH_OR); }
807 YY_BREAK
808 case 9:
809 YY_RULE_SETUP
810 #line 76 "arith_lex.l"
811 { return(ARITH_AND); }
812 YY_BREAK
813 case 10:
814 YY_RULE_SETUP
815 #line 77 "arith_lex.l"
816 { return(ARITH_BOR); }
817 YY_BREAK
818 case 11:
819 YY_RULE_SETUP
820 #line 78 "arith_lex.l"
821 { return(ARITH_BXOR); }
822 YY_BREAK
823 case 12:
824 YY_RULE_SETUP
825 #line 79 "arith_lex.l"
826 { return(ARITH_BAND); }
827 YY_BREAK
828 case 13:
829 YY_RULE_SETUP
830 #line 80 "arith_lex.l"
831 { return(ARITH_EQ); }
832 YY_BREAK
833 case 14:
834 YY_RULE_SETUP
835 #line 81 "arith_lex.l"
836 { return(ARITH_NE); }
837 YY_BREAK
838 case 15:
839 YY_RULE_SETUP
840 #line 82 "arith_lex.l"
841 { return(ARITH_GT); }
842 YY_BREAK
843 case 16:
844 YY_RULE_SETUP
845 #line 83 "arith_lex.l"
846 { return(ARITH_GE); }
847 YY_BREAK
848 case 17:
849 YY_RULE_SETUP
850 #line 84 "arith_lex.l"
851 { return(ARITH_LT); }
852 YY_BREAK
853 case 18:
854 YY_RULE_SETUP
855 #line 85 "arith_lex.l"
856 { return(ARITH_LE); }
857 YY_BREAK
858 case 19:
859 YY_RULE_SETUP
860 #line 86 "arith_lex.l"
861 { return(ARITH_LSHIFT); }
862 YY_BREAK
863 case 20:
864 YY_RULE_SETUP
865 #line 87 "arith_lex.l"
866 { return(ARITH_RSHIFT); }
867 YY_BREAK
868 case 21:
869 YY_RULE_SETUP
870 #line 88 "arith_lex.l"
871 { return(ARITH_MUL); }
872 YY_BREAK
873 case 22:
874 YY_RULE_SETUP
875 #line 89 "arith_lex.l"
876 { return(ARITH_DIV); }
877 YY_BREAK
878 case 23:
879 YY_RULE_SETUP
880 #line 90 "arith_lex.l"
881 { return(ARITH_REM); }
882 YY_BREAK
883 case 24:
884 YY_RULE_SETUP
885 #line 91 "arith_lex.l"
886 { return(ARITH_ADD); }
887 YY_BREAK
888 case 25:
889 YY_RULE_SETUP
890 #line 92 "arith_lex.l"
891 { return(ARITH_SUB); }
892 YY_BREAK
893 case 26:
894 YY_RULE_SETUP
895 #line 93 "arith_lex.l"
896 { return(ARITH_BNOT); }
897 YY_BREAK
898 case 27:
899 YY_RULE_SETUP
900 #line 94 "arith_lex.l"
901 { return(ARITH_NOT); }
902 YY_BREAK
903 case 28:
904 YY_RULE_SETUP
905 #line 95 "arith_lex.l"
906 { error("arith: syntax error: \"%s\"", arith_startbuf); }
907 YY_BREAK
908 case 29:
909 YY_RULE_SETUP
910 #line 96 "arith_lex.l"
911 ECHO;
912 YY_BREAK
913 #line 915 "arith_lex.c"
914 case YY_STATE_EOF(INITIAL):
915 yyterminate();
916
917 case YY_END_OF_BUFFER:
918 {
919 /* Amount of text matched not including the EOB char. */
920 int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
921
922 /* Undo the effects of YY_DO_BEFORE_ACTION. */
923 *yy_cp = (yy_hold_char);
924 YY_RESTORE_YY_MORE_OFFSET
925
926 if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
927 {
928 /* We're scanning a new file or input source. It's
929 * possible that this happened because the user
930 * just pointed yyin at a new source and called
931 * yylex(). If so, then we have to assure
932 * consistency between YY_CURRENT_BUFFER and our
933 * globals. Here is the right place to do so, because
934 * this is the first action (other than possibly a
935 * back-up) that will match for the new input source.
936 */
937 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
938 YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
939 YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
940 }
941
942 /* Note that here we test for yy_c_buf_p "<=" to the position
943 * of the first EOB in the buffer, since yy_c_buf_p will
944 * already have been incremented past the NUL character
945 * (since all states make transitions on EOB to the
946 * end-of-buffer state). Contrast this with the test
947 * in input().
948 */
949 if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
950 { /* This was really a NUL. */
951 yy_state_type yy_next_state;
952
953 (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
954
955 yy_current_state = yy_get_previous_state( );
956
957 /* Okay, we're now positioned to make the NUL
958 * transition. We couldn't have
959 * yy_get_previous_state() go ahead and do it
960 * for us because it doesn't know how to deal
961 * with the possibility of jamming (and we don't
962 * want to build jamming into it because then it
963 * will run more slowly).
964 */
965
966 yy_next_state = yy_try_NUL_trans( yy_current_state );
967
968 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
969
970 if ( yy_next_state )
971 {
972 /* Consume the NUL. */
973 yy_cp = ++(yy_c_buf_p);
974 yy_current_state = yy_next_state;
975 goto yy_match;
976 }
977
978 else
979 {
980 yy_cp = (yy_c_buf_p);
981 goto yy_find_action;
982 }
983 }
984
985 else switch ( yy_get_next_buffer( ) )
986 {
987 case EOB_ACT_END_OF_FILE:
988 {
989 (yy_did_buffer_switch_on_eof) = 0;
990
991 if ( yywrap( ) )
992 {
993 /* Note: because we've taken care in
994 * yy_get_next_buffer() to have set up
995 * yytext, we can now set up
996 * yy_c_buf_p so that if some total
997 * hoser (like flex itself) wants to
998 * call the scanner after we return the
999 * YY_NULL, it'll still work - another
1000 * YY_NULL will get returned.
1001 */
1002 (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
1003
1004 yy_act = YY_STATE_EOF(YY_START);
1005 goto do_action;
1006 }
1007
1008 else
1009 {
1010 if ( ! (yy_did_buffer_switch_on_eof) )
1011 YY_NEW_FILE;
1012 }
1013 break;
1014 }
1015
1016 case EOB_ACT_CONTINUE_SCAN:
1017 (yy_c_buf_p) =
1018 (yytext_ptr) + yy_amount_of_matched_text;
1019
1020 yy_current_state = yy_get_previous_state( );
1021
1022 yy_cp = (yy_c_buf_p);
1023 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
1024 goto yy_match;
1025
1026 case EOB_ACT_LAST_MATCH:
1027 (yy_c_buf_p) =
1028 &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
1029
1030 yy_current_state = yy_get_previous_state( );
1031
1032 yy_cp = (yy_c_buf_p);
1033 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
1034 goto yy_find_action;
1035 }
1036 break;
1037 }
1038
1039 default:
1040 YY_FATAL_ERROR(
1041 "fatal flex scanner internal error--no action found" );
1042 } /* end of action switch */
1043 } /* end of scanning one token */
1044 } /* end of yylex */
1045
1046 /* yy_get_next_buffer - try to read in a new buffer
1047 *
1048 * Returns a code representing an action:
1049 * EOB_ACT_LAST_MATCH -
1050 * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
1051 * EOB_ACT_END_OF_FILE - end of file
1052 */
1053 static int yy_get_next_buffer (void)
1054 {
1055 register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
1056 register char *source = (yytext_ptr);
1057 register int number_to_move, i;
1058 int ret_val;
1059
1060 if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
1061 YY_FATAL_ERROR(
1062 "fatal flex scanner internal error--end of buffer missed" );
1063
1064 if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
1065 { /* Don't try to fill the buffer, so this is an EOF. */
1066 if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
1067 {
1068 /* We matched a single character, the EOB, so
1069 * treat this as a final EOF.
1070 */
1071 return EOB_ACT_END_OF_FILE;
1072 }
1073
1074 else
1075 {
1076 /* We matched some text prior to the EOB, first
1077 * process it.
1078 */
1079 return EOB_ACT_LAST_MATCH;
1080 }
1081 }
1082
1083 /* Try to read more data. */
1084
1085 /* First move last chars to start of buffer. */
1086 number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
1087
1088 for ( i = 0; i < number_to_move; ++i )
1089 *(dest++) = *(source++);
1090
1091 if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
1092 /* don't do the read, it's not guaranteed to return an EOF,
1093 * just force an EOF
1094 */
1095 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
1096
1097 else
1098 {
1099 size_t num_to_read =
1100 YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
1101
1102 while ( num_to_read <= 0 )
1103 { /* Not enough room in the buffer - grow it. */
1104
1105 /* just a shorter name for the current buffer */
1106 YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
1107
1108 int yy_c_buf_p_offset =
1109 (int) ((yy_c_buf_p) - b->yy_ch_buf);
1110
1111 if ( b->yy_is_our_buffer )
1112 {
1113 int new_size = b->yy_buf_size * 2;
1114
1115 if ( new_size <= 0 )
1116 b->yy_buf_size += b->yy_buf_size / 8;
1117 else
1118 b->yy_buf_size *= 2;
1119
1120 b->yy_ch_buf = (char *)
1121 /* Include room in for 2 EOB chars. */
1122 yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
1123 }
1124 else
1125 /* Can't grow it, we don't own it. */
1126 b->yy_ch_buf = 0;
1127
1128 if ( ! b->yy_ch_buf )
1129 YY_FATAL_ERROR(
1130 "fatal error - scanner input buffer overflow" );
1131
1132 (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
1133
1134 num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
1135 number_to_move - 1;
1136
1137 }
1138
1139 if ( num_to_read > YY_READ_BUF_SIZE )
1140 num_to_read = YY_READ_BUF_SIZE;
1141
1142 /* Read in more data. */
1143 YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
1144 (yy_n_chars), num_to_read );
1145
1146 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
1147 }
1148
1149 if ( (yy_n_chars) == 0 )
1150 {
1151 if ( number_to_move == YY_MORE_ADJ )
1152 {
1153 ret_val = EOB_ACT_END_OF_FILE;
1154 yyrestart(yyin );
1155 }
1156
1157 else
1158 {
1159 ret_val = EOB_ACT_LAST_MATCH;
1160 YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
1161 YY_BUFFER_EOF_PENDING;
1162 }
1163 }
1164
1165 else
1166 ret_val = EOB_ACT_CONTINUE_SCAN;
1167
1168 (yy_n_chars) += number_to_move;
1169 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
1170 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
1171
1172 (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
1173
1174 return ret_val;
1175 }
1176
1177 /* yy_get_previous_state - get the state just before the EOB char was reached */
1178
1179 static yy_state_type yy_get_previous_state (void)
1180 {
1181 register yy_state_type yy_current_state;
1182 register char *yy_cp;
1183
1184 yy_current_state = (yy_start);
1185
1186 for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
1187 {
1188 register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
1189 if ( yy_accept[yy_current_state] )
1190 {
1191 (yy_last_accepting_state) = yy_current_state;
1192 (yy_last_accepting_cpos) = yy_cp;
1193 }
1194 while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
1195 {
1196 yy_current_state = (int) yy_def[yy_current_state];
1197 if ( yy_current_state >= 39 )
1198 yy_c = yy_meta[(unsigned int) yy_c];
1199 }
1200 yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
1201 }
1202
1203 return yy_current_state;
1204 }
1205
1206 /* yy_try_NUL_trans - try to make a transition on the NUL character
1207 *
1208 * synopsis
1209 * next_state = yy_try_NUL_trans( current_state );
1210 */
1211 static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
1212 {
1213 register int yy_is_jam;
1214 register char *yy_cp = (yy_c_buf_p);
1215
1216 register YY_CHAR yy_c = 1;
1217 if ( yy_accept[yy_current_state] )
1218 {
1219 (yy_last_accepting_state) = yy_current_state;
1220 (yy_last_accepting_cpos) = yy_cp;
1221 }
1222 while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
1223 {
1224 yy_current_state = (int) yy_def[yy_current_state];
1225 if ( yy_current_state >= 39 )
1226 yy_c = yy_meta[(unsigned int) yy_c];
1227 }
1228 yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
1229 yy_is_jam = (yy_current_state == 38);
1230
1231 return yy_is_jam ? 0 : yy_current_state;
1232 }
1233
1234 static void yyunput (int c, register char * yy_bp )
1235 {
1236 register char *yy_cp;
1237
1238 yy_cp = (yy_c_buf_p);
1239
1240 /* undo effects of setting up yytext */
1241 *yy_cp = (yy_hold_char);
1242
1243 if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
1244 { /* need to shift things up to make room */
1245 /* +2 for EOB chars. */
1246 register int number_to_move = (yy_n_chars) + 2;
1247 register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
1248 YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
1249 register char *source =
1250 &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
1251
1252 while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
1253 *--dest = *--source;
1254
1255 yy_cp += (int) (dest - source);
1256 yy_bp += (int) (dest - source);
1257 YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
1258 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
1259
1260 if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
1261 YY_FATAL_ERROR( "flex scanner push-back overflow" );
1262 }
1263
1264 *--yy_cp = (char) c;
1265
1266 (yytext_ptr) = yy_bp;
1267 (yy_hold_char) = *yy_cp;
1268 (yy_c_buf_p) = yy_cp;
1269 }
1270
1271 #ifndef YY_NO_INPUT
1272 #ifdef __cplusplus
1273 static int yyinput (void)
1274 #else
1275 static int input (void)
1276 #endif
1277
1278 {
1279 int c;
1280
1281 *(yy_c_buf_p) = (yy_hold_char);
1282
1283 if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
1284 {
1285 /* yy_c_buf_p now points to the character we want to return.
1286 * If this occurs *before* the EOB characters, then it's a
1287 * valid NUL; if not, then we've hit the end of the buffer.
1288 */
1289 if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
1290 /* This was really a NUL. */
1291 *(yy_c_buf_p) = '\0';
1292
1293 else
1294 { /* need more input */
1295 int offset = (yy_c_buf_p) - (yytext_ptr);
1296 ++(yy_c_buf_p);
1297
1298 switch ( yy_get_next_buffer( ) )
1299 {
1300 case EOB_ACT_LAST_MATCH:
1301 /* This happens because yy_g_n_b()
1302 * sees that we've accumulated a
1303 * token and flags that we need to
1304 * try matching the token before
1305 * proceeding. But for input(),
1306 * there's no matching to consider.
1307 * So convert the EOB_ACT_LAST_MATCH
1308 * to EOB_ACT_END_OF_FILE.
1309 */
1310
1311 /* Reset buffer status. */
1312 yyrestart(yyin );
1313
1314 /*FALLTHROUGH*/
1315
1316 case EOB_ACT_END_OF_FILE:
1317 {
1318 if ( yywrap( ) )
1319 return EOF;
1320
1321 if ( ! (yy_did_buffer_switch_on_eof) )
1322 YY_NEW_FILE;
1323 #ifdef __cplusplus
1324 return yyinput();
1325 #else
1326 return input();
1327 #endif
1328 }
1329
1330 case EOB_ACT_CONTINUE_SCAN:
1331 (yy_c_buf_p) = (yytext_ptr) + offset;
1332 break;
1333 }
1334 }
1335 }
1336
1337 c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
1338 *(yy_c_buf_p) = '\0'; /* preserve yytext */
1339 (yy_hold_char) = *++(yy_c_buf_p);
1340
1341 return c;
1342 }
1343 #endif /* ifndef YY_NO_INPUT */
1344
1345 /** Immediately switch to a different input stream.
1346 * @param input_file A readable stream.
1347 *
1348 * @note This function does not reset the start condition to @c INITIAL .
1349 */
1350 void yyrestart (FILE * input_file )
1351 {
1352
1353 if ( ! YY_CURRENT_BUFFER ){
1354 yyensure_buffer_stack ();
1355 YY_CURRENT_BUFFER_LVALUE =
1356 yy_create_buffer(yyin,YY_BUF_SIZE );
1357 }
1358
1359 yy_init_buffer(YY_CURRENT_BUFFER,input_file );
1360 yy_load_buffer_state( );
1361 }
1362
1363 /** Switch to a different input buffer.
1364 * @param new_buffer The new input buffer.
1365 *
1366 */
1367 void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
1368 {
1369
1370 /* TODO. We should be able to replace this entire function body
1371 * with
1372 * yypop_buffer_state();
1373 * yypush_buffer_state(new_buffer);
1374 */
1375 yyensure_buffer_stack ();
1376 if ( YY_CURRENT_BUFFER == new_buffer )
1377 return;
1378
1379 if ( YY_CURRENT_BUFFER )
1380 {
1381 /* Flush out information for old buffer. */
1382 *(yy_c_buf_p) = (yy_hold_char);
1383 YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
1384 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
1385 }
1386
1387 YY_CURRENT_BUFFER_LVALUE = new_buffer;
1388 yy_load_buffer_state( );
1389
1390 /* We don't actually know whether we did this switch during
1391 * EOF (yywrap()) processing, but the only time this flag
1392 * is looked at is after yywrap() is called, so it's safe
1393 * to go ahead and always set it.
1394 */
1395 (yy_did_buffer_switch_on_eof) = 1;
1396 }
1397
1398 static void yy_load_buffer_state (void)
1399 {
1400 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
1401 (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
1402 yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
1403 (yy_hold_char) = *(yy_c_buf_p);
1404 }
1405
1406 /** Allocate and initialize an input buffer state.
1407 * @param file A readable stream.
1408 * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
1409 *
1410 * @return the allocated buffer state.
1411 */
1412 YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
1413 {
1414 YY_BUFFER_STATE b;
1415
1416 b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
1417 if ( ! b )
1418 YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
1419
1420 b->yy_buf_size = size;
1421
1422 /* yy_ch_buf has to be 2 characters longer than the size given because
1423 * we need to put in 2 end-of-buffer characters.
1424 */
1425 b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
1426 if ( ! b->yy_ch_buf )
1427 YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
1428
1429 b->yy_is_our_buffer = 1;
1430
1431 yy_init_buffer(b,file );
1432
1433 return b;
1434 }
1435
1436 /** Destroy the buffer.
1437 * @param b a buffer created with yy_create_buffer()
1438 *
1439 */
1440 void yy_delete_buffer (YY_BUFFER_STATE b )
1441 {
1442
1443 if ( ! b )
1444 return;
1445
1446 if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
1447 YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
1448
1449 if ( b->yy_is_our_buffer )
1450 yyfree((void *) b->yy_ch_buf );
1451
1452 yyfree((void *) b );
1453 }
1454
1455 #ifndef __cplusplus
1456 extern int isatty (int );
1457 #endif /* __cplusplus */
1458
1459 /* Initializes or reinitializes a buffer.
1460 * This function is sometimes called more than once on the same buffer,
1461 * such as during a yyrestart() or at EOF.
1462 */
1463 static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
1464
1465 {
1466 int oerrno = errno;
1467
1468 yy_flush_buffer(b );
1469
1470 b->yy_input_file = file;
1471 b->yy_fill_buffer = 1;
1472
1473 /* If b is the current buffer, then yy_init_buffer was _probably_
1474 * called from yyrestart() or through yy_get_next_buffer.
1475 * In that case, we don't want to reset the lineno or column.
1476 */
1477 if (b != YY_CURRENT_BUFFER){
1478 b->yy_bs_lineno = 1;
1479 b->yy_bs_column = 0;
1480 }
1481
1482 b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
1483
1484 errno = oerrno;
1485 }
1486
1487 /** Discard all buffered characters. On the next scan, YY_INPUT will be called.
1488 * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
1489 *
1490 */
1491 void yy_flush_buffer (YY_BUFFER_STATE b )
1492 {
1493 if ( ! b )
1494 return;
1495
1496 b->yy_n_chars = 0;
1497
1498 /* We always need two end-of-buffer characters. The first causes
1499 * a transition to the end-of-buffer state. The second causes
1500 * a jam in that state.
1501 */
1502 b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
1503 b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
1504
1505 b->yy_buf_pos = &b->yy_ch_buf[0];
1506
1507 b->yy_at_bol = 1;
1508 b->yy_buffer_status = YY_BUFFER_NEW;
1509
1510 if ( b == YY_CURRENT_BUFFER )
1511 yy_load_buffer_state( );
1512 }
1513
1514 /** Pushes the new state onto the stack. The new state becomes
1515 * the current state. This function will allocate the stack
1516 * if necessary.
1517 * @param new_buffer The new state.
1518 *
1519 */
1520 void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
1521 {
1522 if (new_buffer == NULL)
1523 return;
1524
1525 yyensure_buffer_stack();
1526
1527 /* This block is copied from yy_switch_to_buffer. */
1528 if ( YY_CURRENT_BUFFER )
1529 {
1530 /* Flush out information for old buffer. */
1531 *(yy_c_buf_p) = (yy_hold_char);
1532 YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
1533 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
1534 }
1535
1536 /* Only push if top exists. Otherwise, replace top. */
1537 if (YY_CURRENT_BUFFER)
1538 (yy_buffer_stack_top)++;
1539 YY_CURRENT_BUFFER_LVALUE = new_buffer;
1540
1541 /* copied from yy_switch_to_buffer. */
1542 yy_load_buffer_state( );
1543 (yy_did_buffer_switch_on_eof) = 1;
1544 }
1545
1546 /** Removes and deletes the top of the stack, if present.
1547 * The next element becomes the new top.
1548 *
1549 */
1550 void yypop_buffer_state (void)
1551 {
1552 if (!YY_CURRENT_BUFFER)
1553 return;
1554
1555 yy_delete_buffer(YY_CURRENT_BUFFER );
1556 YY_CURRENT_BUFFER_LVALUE = NULL;
1557 if ((yy_buffer_stack_top) > 0)
1558 --(yy_buffer_stack_top);
1559
1560 if (YY_CURRENT_BUFFER) {
1561 yy_load_buffer_state( );
1562 (yy_did_buffer_switch_on_eof) = 1;
1563 }
1564 }
1565
1566 /* Allocates the stack if it does not exist.
1567 * Guarantees space for at least one push.
1568 */
1569 static void yyensure_buffer_stack (void)
1570 {
1571 int num_to_alloc;
1572
1573 if (!(yy_buffer_stack)) {
1574
1575 /* First allocation is just for 2 elements, since we don't know if this
1576 * scanner will even need a stack. We use 2 instead of 1 to avoid an
1577 * immediate realloc on the next call.
1578 */
1579 num_to_alloc = 1;
1580 (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
1581 (num_to_alloc * sizeof(struct yy_buffer_state*)
1582 );
1583
1584 memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
1585
1586 (yy_buffer_stack_max) = num_to_alloc;
1587 (yy_buffer_stack_top) = 0;
1588 return;
1589 }
1590
1591 if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
1592
1593 /* Increase the buffer to prepare for a possible push. */
1594 int grow_size = 8 /* arbitrary grow size */;
1595
1596 num_to_alloc = (yy_buffer_stack_max) + grow_size;
1597 (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
1598 ((yy_buffer_stack),
1599 num_to_alloc * sizeof(struct yy_buffer_state*)
1600 );
1601
1602 /* zero only the new slots.*/
1603 memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
1604 (yy_buffer_stack_max) = num_to_alloc;
1605 }
1606 }
1607
1608 /** Setup the input buffer state to scan directly from a user-specified character buffer.
1609 * @param base the character buffer
1610 * @param size the size in bytes of the character buffer
1611 *
1612 * @return the newly allocated buffer state object.
1613 */
1614 YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
1615 {
1616 YY_BUFFER_STATE b;
1617
1618 if ( size < 2 ||
1619 base[size-2] != YY_END_OF_BUFFER_CHAR ||
1620 base[size-1] != YY_END_OF_BUFFER_CHAR )
1621 /* They forgot to leave room for the EOB's. */
1622 return 0;
1623
1624 b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
1625 if ( ! b )
1626 YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
1627
1628 b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
1629 b->yy_buf_pos = b->yy_ch_buf = base;
1630 b->yy_is_our_buffer = 0;
1631 b->yy_input_file = 0;
1632 b->yy_n_chars = b->yy_buf_size;
1633 b->yy_is_interactive = 0;
1634 b->yy_at_bol = 1;
1635 b->yy_fill_buffer = 0;
1636 b->yy_buffer_status = YY_BUFFER_NEW;
1637
1638 yy_switch_to_buffer(b );
1639
1640 return b;
1641 }
1642
1643 /** Setup the input buffer state to scan a string. The next call to yylex() will
1644 * scan from a @e copy of @a str.
1645 * @param str a NUL-terminated string to scan
1646 *
1647 * @return the newly allocated buffer state object.
1648 * @note If you want to scan bytes that may contain NUL values, then use
1649 * yy_scan_bytes() instead.
1650 */
1651 YY_BUFFER_STATE yy_scan_string (yyconst char * yy_str )
1652 {
1653
1654 return yy_scan_bytes(yy_str,strlen(yy_str) );
1655 }
1656
1657 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
1658 * scan from a @e copy of @a bytes.
1659 * @param bytes the byte buffer to scan
1660 * @param len the number of bytes in the buffer pointed to by @a bytes.
1661 *
1662 * @return the newly allocated buffer state object.
1663 */
1664 YY_BUFFER_STATE yy_scan_bytes (yyconst char * bytes, int len )
1665 {
1666 YY_BUFFER_STATE b;
1667 char *buf;
1668 yy_size_t n;
1669 int i;
1670
1671 /* Get memory for full buffer, including space for trailing EOB's. */
1672 n = len + 2;
1673 buf = (char *) yyalloc(n );
1674 if ( ! buf )
1675 YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
1676
1677 for ( i = 0; i < len; ++i )
1678 buf[i] = bytes[i];
1679
1680 buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
1681
1682 b = yy_scan_buffer(buf,n );
1683 if ( ! b )
1684 YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
1685
1686 /* It's okay to grow etc. this buffer, and we should throw it
1687 * away when we're done.
1688 */
1689 b->yy_is_our_buffer = 1;
1690
1691 return b;
1692 }
1693
1694 #ifndef YY_EXIT_FAILURE
1695 #define YY_EXIT_FAILURE 2
1696 #endif
1697
1698 static void yy_fatal_error (yyconst char* msg )
1699 {
1700 (void) fprintf( stderr, "%s\n", msg );
1701 exit( YY_EXIT_FAILURE );
1702 }
1703
1704 /* Redefine yyless() so it works in section 3 code. */
1705
1706 #undef yyless
1707 #define yyless(n) \
1708 do \
1709 { \
1710 /* Undo effects of setting up yytext. */ \
1711 int yyless_macro_arg = (n); \
1712 YY_LESS_LINENO(yyless_macro_arg);\
1713 yytext[yyleng] = (yy_hold_char); \
1714 (yy_c_buf_p) = yytext + yyless_macro_arg; \
1715 (yy_hold_char) = *(yy_c_buf_p); \
1716 *(yy_c_buf_p) = '\0'; \
1717 yyleng = yyless_macro_arg; \
1718 } \
1719 while ( 0 )
1720
1721 /* Accessor methods (get/set functions) to struct members. */
1722
1723 /** Get the current line number.
1724 *
1725 */
1726 int yyget_lineno (void)
1727 {
1728
1729 return yylineno;
1730 }
1731
1732 /** Get the input stream.
1733 *
1734 */
1735 FILE *yyget_in (void)
1736 {
1737 return yyin;
1738 }
1739
1740 /** Get the output stream.
1741 *
1742 */
1743 FILE *yyget_out (void)
1744 {
1745 return yyout;
1746 }
1747
1748 /** Get the length of the current token.
1749 *
1750 */
1751 int yyget_leng (void)
1752 {
1753 return yyleng;
1754 }
1755
1756 /** Get the current token.
1757 *
1758 */
1759
1760 char *yyget_text (void)
1761 {
1762 return yytext;
1763 }
1764
1765 /** Set the current line number.
1766 * @param line_number
1767 *
1768 */
1769 void yyset_lineno (int line_number )
1770 {
1771
1772 yylineno = line_number;
1773 }
1774
1775 /** Set the input stream. This does not discard the current
1776 * input buffer.
1777 * @param in_str A readable stream.
1778 *
1779 * @see yy_switch_to_buffer
1780 */
1781 void yyset_in (FILE * in_str )
1782 {
1783 yyin = in_str ;
1784 }
1785
1786 void yyset_out (FILE * out_str )
1787 {
1788 yyout = out_str ;
1789 }
1790
1791 int yyget_debug (void)
1792 {
1793 return yy_flex_debug;
1794 }
1795
1796 void yyset_debug (int bdebug )
1797 {
1798 yy_flex_debug = bdebug ;
1799 }
1800
1801 /* yylex_destroy is for both reentrant and non-reentrant scanners. */
1802 int yylex_destroy (void)
1803 {
1804
1805 /* Pop the buffer stack, destroying each element. */
1806 while(YY_CURRENT_BUFFER){
1807 yy_delete_buffer(YY_CURRENT_BUFFER );
1808 YY_CURRENT_BUFFER_LVALUE = NULL;
1809 yypop_buffer_state();
1810 }
1811
1812 /* Destroy the stack itself. */
1813 yyfree((yy_buffer_stack) );
1814 (yy_buffer_stack) = NULL;
1815
1816 return 0;
1817 }
1818
1819 /*
1820 * Internal utility routines.
1821 */
1822
1823 #ifndef yytext_ptr
1824 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
1825 {
1826 register int i;
1827 for ( i = 0; i < n; ++i )
1828 s1[i] = s2[i];
1829 }
1830 #endif
1831
1832 #ifdef YY_NEED_STRLEN
1833 static int yy_flex_strlen (yyconst char * s )
1834 {
1835 register int n;
1836 for ( n = 0; s[n]; ++n )
1837 ;
1838
1839 return n;
1840 }
1841 #endif
1842
1843 void *yyalloc (yy_size_t size )
1844 {
1845 return (void *) malloc( size );
1846 }
1847
1848 void *yyrealloc (void * ptr, yy_size_t size )
1849 {
1850 /* The cast to (char *) in the following accommodates both
1851 * implementations that use char* generic pointers, and those
1852 * that use void* generic pointers. It works with the latter
1853 * because both ANSI C and C++ allow castless assignment from
1854 * any pointer type to void*, and deal with argument conversions
1855 * as though doing an assignment.
1856 */
1857 return (void *) realloc( (char *) ptr, size );
1858 }
1859
1860 void yyfree (void * ptr )
1861 {
1862 free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
1863 }
1864
1865 #define YYTABLES_NAME "yytables"
1866
1867 #undef YY_NEW_FILE
1868 #undef YY_FLUSH_BUFFER
1869 #undef yy_set_bol
1870 #undef yy_new_buffer
1871 #undef yy_set_interactive
1872 #undef yytext_ptr
1873 #undef YY_DO_BEFORE_ACTION
1874
1875 #ifdef YY_DECL_IS_OURS
1876 #undef YY_DECL_IS_OURS
1877 #undef YY_DECL
1878 #endif
1879 #line 96 "arith_lex.l"
1880
1881
1882
1883 void
1884 arith_lex_reset() {
1885 #ifdef YY_NEW_FILE
1886 YY_NEW_FILE;
1887 #endif
1888 }
1889
+0
-103
sh/arith_lex.l less more
0 %{
1 /* $NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $ */
2
3 /*-
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <unistd.h>
45 #include "arith.h"
46 #include "error.h"
47 #include "expand.h"
48 #include "var.h"
49
50 extern int yylval;
51 extern char *arith_buf, *arith_startbuf;
52 #undef YY_INPUT
53 #define YY_INPUT(buf,result,max) \
54 result = (*buf = *arith_buf++) ? 1 : YY_NULL;
55 #define YY_NO_UNPUT
56 %}
57 %option noyywrap
58
59 %%
60 [ \t\n] { ; }
61 0x[0-9a-fA-F]+ { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); }
62 0[0-7]* { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); }
63 [1-9][0-9]* { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); }
64 [A-Za-z_][A-Za-z_0-9]* { char *v = lookupvar(yytext);
65 if (v) {
66 yylval = strtol(v, &v, 0);
67 if (*v == 0)
68 return ARITH_NUM;
69 }
70 error("arith: syntax error: \"%s\"", arith_startbuf);
71 }
72 "(" { return(ARITH_LPAREN); }
73 ")" { return(ARITH_RPAREN); }
74 "||" { return(ARITH_OR); }
75 "&&" { return(ARITH_AND); }
76 "|" { return(ARITH_BOR); }
77 "^" { return(ARITH_BXOR); }
78 "&" { return(ARITH_BAND); }
79 "==" { return(ARITH_EQ); }
80 "!=" { return(ARITH_NE); }
81 ">" { return(ARITH_GT); }
82 ">=" { return(ARITH_GE); }
83 "<" { return(ARITH_LT); }
84 "<=" { return(ARITH_LE); }
85 "<<" { return(ARITH_LSHIFT); }
86 ">>" { return(ARITH_RSHIFT); }
87 "*" { return(ARITH_MUL); }
88 "/" { return(ARITH_DIV); }
89 "%" { return(ARITH_REM); }
90 "+" { return(ARITH_ADD); }
91 "-" { return(ARITH_SUB); }
92 "~" { return(ARITH_BNOT); }
93 "!" { return(ARITH_NOT); }
94 . { error("arith: syntax error: \"%s\"", arith_startbuf); }
95 %%
96
97 void
98 arith_lex_reset() {
99 #ifdef YY_NEW_FILE
100 YY_NEW_FILE;
101 #endif
102 }
+0
-94
sh/bltin/bltin.h less more
0 /* $NetBSD: bltin.h,v 1.11 2003/08/07 09:05:40 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)bltin.h 8.1 (Berkeley) 5/31/93
34 */
35
36 /*
37 * This file is included by programs which are optionally built into the
38 * shell. If SHELL is defined, we try to map the standard UNIX library
39 * routines to ash routines using defines.
40 */
41
42 #include "../shell.h"
43 #include "../mystring.h"
44 #ifdef SHELL
45 #include "../output.h"
46 #include "../error.h"
47 #undef stdout
48 #undef stderr
49 #undef putc
50 #undef putchar
51 #undef fileno
52 #define stdout out1
53 #define stderr out2
54 #define printf out1fmt
55 #define putc(c, file) outc(c, file)
56 #define putchar(c) out1c(c)
57 #define FILE struct output
58 #define fprintf outfmt
59 #define fputs outstr
60 #define fflush flushout
61 #define fileno(f) ((f)->fd)
62 #define INITARGS(argv)
63 #define err sh_err
64 #define verr sh_verr
65 #define errx sh_errx
66 #define verrx sh_verrx
67 #define warn sh_warn
68 #define vwarn sh_vwarn
69 #define warnx sh_warnx
70 #define vwarnx sh_vwarnx
71 #define exit sh_exit
72 #define setprogname(s)
73 #define getprogname() commandname
74 #define setlocate(l,s) 0
75
76 #define getenv(p) bltinlookup((p),0)
77
78 #else
79 #undef NULL
80 #include <stdio.h>
81 #undef main
82 #define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
83 #endif
84
85 pointer stalloc(int);
86 void error(const char *, ...);
87 void sh_warnx(const char *, ...);
88 void sh_exit(int) __attribute__((__noreturn__));
89
90 int echocmd(int, char **);
91
92
93 extern const char *commandname;
+0
-109
sh/bltin/echo.1 less more
0 .\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:40 agc Exp $
1 .\"
2 .\" Copyright (c) 1991, 1993
3 .\" The Regents of the University of California. All rights reserved.
4 .\"
5 .\" This code is derived from software contributed to Berkeley by
6 .\" Kenneth Almquist.
7 .\" Copyright 1989 by Kenneth Almquist
8 .\"
9 .\" Redistribution and use in source and binary forms, with or without
10 .\" modification, are permitted provided that the following conditions
11 .\" are met:
12 .\" 1. Redistributions of source code must retain the above copyright
13 .\" notice, this list of conditions and the following disclaimer.
14 .\" 2. Redistributions in binary form must reproduce the above copyright
15 .\" notice, this list of conditions and the following disclaimer in the
16 .\" documentation and/or other materials provided with the distribution.
17 .\" 3. Neither the name of the University nor the names of its contributors
18 .\" may be used to endorse or promote products derived from this software
19 .\" without specific prior written permission.
20 .\"
21 .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 .\" SUCH DAMAGE.
32 .\"
33 .\" @(#)echo.1 8.1 (Berkeley) 5/31/93
34 .\"
35 .Dd May 31, 1993
36 .Dt ECHO 1
37 .Os
38 .Sh NAME
39 .Nm echo
40 .Nd produce message in a shell script
41 .Sh SYNOPSIS
42 .Nm
43 .Op Fl n | Fl e
44 .Ar args ...
45 .Sh DESCRIPTION
46 .Nm
47 prints its arguments on the standard output, separated by spaces.
48 Unless the
49 .Fl n
50 option is present, a newline is output following the arguments.
51 The
52 .Fl e
53 option causes
54 .Nm
55 to treat the escape sequences specially, as described in the following
56 paragraph.
57 The
58 .Fl e
59 option is the default, and is provided solely for compatibility with
60 other systems.
61 Only one of the options
62 .Fl n
63 and
64 .Fl e
65 may be given.
66 .Pp
67 If any of the following sequences of characters is encountered during
68 output, the sequence is not output. Instead, the specified action is
69 performed:
70 .Bl -tag -width indent
71 .It Li \eb
72 A backspace character is output.
73 .It Li \ec
74 Subsequent output is suppressed. This is normally used at the end of the
75 last argument to suppress the trailing newline that
76 .Nm
77 would otherwise output.
78 .It Li \ef
79 Output a form feed.
80 .It Li \en
81 Output a newline character.
82 .It Li \er
83 Output a carriage return.
84 .It Li \et
85 Output a (horizontal) tab character.
86 .It Li \ev
87 Output a vertical tab.
88 .It Li \e0 Ns Ar digits
89 Output the character whose value is given by zero to three digits.
90 If there are zero digits, a nul character is output.
91 .It Li \e\e
92 Output a backslash.
93 .El
94 .Sh HINTS
95 Remember that backslash is special to the shell and needs to be escaped.
96 To output a message to standard error, say
97 .Pp
98 .D1 echo message \*[Gt]\*[Am]2
99 .Sh BUGS
100 The octal character escape mechanism
101 .Pq Li \e0 Ns Ar digits
102 differs from the
103 C language mechanism.
104 .Pp
105 There is no way to force
106 .Nm
107 to treat its arguments literally, rather than interpreting them as
108 options and escape sequences.
+0
-116
sh/bltin/echo.c less more
0 /* $NetBSD: echo.c,v 1.12 2005/02/06 04:43:43 perry Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)echo.c 8.1 (Berkeley) 5/31/93
34 */
35
36 /*
37 * Echo command.
38 *
39 * echo is steeped in tradition - several of them!
40 * netbsd has supported 'echo [-n | -e] args' in spite of -e not being
41 * documented anywhere.
42 * Posix requires that -n be supported, output from strings containing
43 * \ is implementation defined
44 * The Single Unix Spec requires that \ escapes be treated as if -e
45 * were set, but that -n not be treated as an option.
46 * (ksh supports 'echo [-eEn] args', but not -- so that it is actually
47 * impossible to actually output '-n')
48 *
49 * It is suggested that 'printf "%b" "string"' be used to get \ sequences
50 * expanded. printf is now a builtin of netbsd's sh and csh.
51 */
52
53 //#define main echocmd
54
55 #include "bltin.h"
56
57 int
58 echocmd(int argc, char **argv)
59 {
60 char **ap;
61 char *p;
62 char c;
63 int count;
64 int nflag = 0;
65 int eflag = 0;
66
67 ap = argv;
68 if (argc)
69 ap++;
70
71 if ((p = *ap) != NULL) {
72 if (equal(p, "-n")) {
73 nflag = 1;
74 ap++;
75 } else if (equal(p, "-e")) {
76 eflag = 1;
77 ap++;
78 }
79 }
80
81 while ((p = *ap++) != NULL) {
82 while ((c = *p++) != '\0') {
83 if (c == '\\' && eflag) {
84 switch (*p++) {
85 case 'a': c = '\a'; break; /* bell */
86 case 'b': c = '\b'; break;
87 case 'c': return 0; /* exit */
88 case 'e': c = 033; break; /* escape */
89 case 'f': c = '\f'; break;
90 case 'n': c = '\n'; break;
91 case 'r': c = '\r'; break;
92 case 't': c = '\t'; break;
93 case 'v': c = '\v'; break;
94 case '\\': break; /* c = '\\' */
95 case '0':
96 c = 0;
97 count = 3;
98 while (--count >= 0 && (unsigned)(*p - '0') < 8)
99 c = (c << 3) + (*p++ - '0');
100 break;
101 default:
102 /* Output the '/' and char following */
103 p--;
104 break;
105 }
106 }
107 putchar(c);
108 }
109 if (*ap)
110 putchar(' ');
111 }
112 if (! nflag)
113 putchar('\n');
114 return 0;
115 }
+0
-61
sh/builtins.c less more
0 /*
1 * This file was generated by the mkbuiltins program.
2 */
3
4 #include "shell.h"
5 #include "builtins.h"
6
7 const struct builtincmd builtincmd[] = {
8
9 { "command", bltincmd },
10 { "bg", bgcmd },
11 { "cd", cdcmd },
12 { "chdir", cdcmd },
13 { "echo", echocmd },
14 { "exp", expcmd },
15 { "let", expcmd },
16 { "false", falsecmd },
17 #if WITH_HISTORY
18 { "fc", histcmd },
19 { "inputrc", inputrc },
20 #endif
21 { "fg", fgcmd },
22 { "getopts", getoptscmd },
23 { "hash", hashcmd },
24 { "jobid", jobidcmd },
25 { "jobs", jobscmd },
26 { "local", localcmd },
27 #ifndef SMALL
28 #endif
29 { "pwd", pwdcmd },
30 { "read", readcmd },
31 { "setvar", setvarcmd },
32 { "true", truecmd },
33 { "type", typecmd },
34 { "umask", umaskcmd },
35 { "unalias", unaliascmd },
36 { "wait", waitcmd },
37 { "alias", aliascmd },
38 { "ulimit", ulimitcmd },
39 { "wordexp", wordexpcmd },
40 { 0, 0 },
41 };
42
43 const struct builtincmd splbltincmd[] = {
44 { "break", breakcmd },
45 { "continue", breakcmd },
46 { ".", dotcmd },
47 { "eval", evalcmd },
48 { "exec", execcmd },
49 { "exit", exitcmd },
50 { "export", exportcmd },
51 { "readonly", exportcmd },
52 { "return", returncmd },
53 { "set", setcmd },
54 { "shift", shiftcmd },
55 { "times", timescmd },
56 { "trap", trapcmd },
57 { ":", truecmd },
58 { "unset", unsetcmd },
59 { 0, 0 },
60 };
+0
-94
sh/builtins.def less more
0 #!/bin/sh -
1 # $NetBSD: builtins.def,v 1.21 2004/07/13 15:05:59 seb Exp $
2 #
3 # Copyright (c) 1991, 1993
4 # The Regents of the University of California. All rights reserved.
5 #
6 # This code is derived from software contributed to Berkeley by
7 # Kenneth Almquist.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 # 3. Neither the name of the University nor the names of its contributors
18 # may be used to endorse or promote products derived from this software
19 # without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # SUCH DAMAGE.
32 #
33 # @(#)builtins.def 8.4 (Berkeley) 5/4/95
34
35 #
36 # This file lists all the builtin commands. The first column is the name
37 # of a C routine.
38 # The -j flag specifies that this command is to be excluded from systems
39 # without job control.
40 # The -h flag specifies that this command is to be excluded from systems
41 # based on the SMALL compile-time symbol.
42 # The -s flag specifies that this is a posix 'special builtin' command.
43 # The -u flag specifies that this is a posix 'standard utility'.
44 # The rest of the line specifies the command name or names used to run
45 # the command.
46
47 bltincmd -u command
48 bgcmd -j -u bg
49 breakcmd -s break -s continue
50 cdcmd -u cd chdir
51 dotcmd -s .
52 echocmd echo
53 evalcmd -s eval
54 execcmd -s exec
55 exitcmd -s exit
56 expcmd exp let
57 exportcmd -s export -s readonly
58 falsecmd -u false
59 #if WITH_HISTORY
60 histcmd -h -u fc
61 inputrc inputrc
62 #endif
63 fgcmd -j -u fg
64 getoptscmd -u getopts
65 hashcmd hash
66 jobidcmd jobid
67 jobscmd -u jobs
68 localcmd local
69 #ifndef SMALL
70 ##printfcmd printf
71 #endif
72 pwdcmd -u pwd
73 readcmd -u read
74 returncmd -s return
75 setcmd -s set
76 setvarcmd setvar
77 shiftcmd -s shift
78 timescmd -s times
79 trapcmd -s trap
80 truecmd -s : -u true
81 typecmd type
82 umaskcmd -u umask
83 unaliascmd -u unalias
84 unsetcmd -s unset
85 waitcmd -u wait
86 aliascmd -u alias
87 ulimitcmd ulimit
88 ##testcmd test [
89 ##killcmd -u kill # mandated by posix for 'kill %job'
90 wordexpcmd wordexp
91 #newgrp -u newgrp # optional command in posix
92
93 #exprcmd expr
+0
-56
sh/builtins.h less more
0 /*
1 * This file was generated by the mkbuiltins program.
2 */
3
4 #include <sys/cdefs.h>
5
6 struct builtincmd {
7 const char *name;
8 int (*builtin)(int, char **);
9 };
10
11 extern const struct builtincmd builtincmd[];
12 extern const struct builtincmd splbltincmd[];
13
14
15 int bltincmd(int, char **);
16 int bgcmd(int, char **);
17 int breakcmd(int, char **);
18 int cdcmd(int, char **);
19 int dotcmd(int, char **);
20 int echocmd(int, char **);
21 int evalcmd(int, char **);
22 int execcmd(int, char **);
23 int exitcmd(int, char **);
24 int expcmd(int, char **);
25 int exportcmd(int, char **);
26 int falsecmd(int, char **);
27 #if WITH_HISTORY
28 int histcmd(int, char **);
29 int inputrc(int, char **);
30 #endif
31 int fgcmd(int, char **);
32 int getoptscmd(int, char **);
33 int hashcmd(int, char **);
34 int jobidcmd(int, char **);
35 int jobscmd(int, char **);
36 int localcmd(int, char **);
37 #ifndef SMALL
38 #endif
39 int pwdcmd(int, char **);
40 int readcmd(int, char **);
41 int returncmd(int, char **);
42 int setcmd(int, char **);
43 int setvarcmd(int, char **);
44 int shiftcmd(int, char **);
45 int timescmd(int, char **);
46 int trapcmd(int, char **);
47 int truecmd(int, char **);
48 int typecmd(int, char **);
49 int umaskcmd(int, char **);
50 int unaliascmd(int, char **);
51 int unsetcmd(int, char **);
52 int waitcmd(int, char **);
53 int aliascmd(int, char **);
54 int ulimitcmd(int, char **);
55 int wordexpcmd(int, char **);
+0
-446
sh/cd.c less more
0 /* $NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49
50 /*
51 * The cd and pwd commands.
52 */
53
54 #include "shell.h"
55 #include "var.h"
56 #include "nodes.h" /* for jobs.h */
57 #include "jobs.h"
58 #include "options.h"
59 #include "output.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "exec.h"
63 #include "redir.h"
64 #include "mystring.h"
65 #include "show.h"
66 #include "cd.h"
67
68 STATIC int docd(char *, int);
69 STATIC char *getcomponent(void);
70 STATIC void updatepwd(char *);
71 STATIC void find_curdir(int noerror);
72
73 char *curdir = NULL; /* current working directory */
74 char *prevdir; /* previous working directory */
75 STATIC char *cdcomppath;
76
77 int
78 cdcmd(int argc, char **argv)
79 {
80 const char *dest;
81 const char *path;
82 char *p, *d;
83 struct stat statb;
84 int print = cdprint; /* set -cdprint to enable */
85
86 nextopt(nullstr);
87
88 /*
89 * Try (quite hard) to have 'curdir' defined, nothing has set
90 * it on entry to the shell, but we want 'cd fred; cd -' to work.
91 */
92 getpwd(1);
93 dest = *argptr;
94 if (dest == NULL) {
95 dest = bltinlookup("HOME", 1);
96 if (dest == NULL)
97 error("HOME not set");
98 } else {
99 if (argptr[1]) {
100 /* Do 'ksh' style substitution */
101 if (!curdir)
102 error("PWD not set");
103 p = strstr(curdir, dest);
104 if (!p)
105 error("bad substitution");
106 d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
107 memcpy(d, curdir, p - curdir);
108 strcpy(d + (p - curdir), argptr[1]);
109 strcat(d, p + strlen(dest));
110 dest = d;
111 print = 1;
112 }
113 }
114
115 if (dest[0] == '-' && dest[1] == '\0') {
116 dest = prevdir ? prevdir : curdir;
117 print = 1;
118 }
119 if (*dest == '\0')
120 dest = ".";
121 if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
122 path = nullstr;
123 while ((p = padvance(&path, dest)) != NULL) {
124 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
125 if (!print) {
126 /*
127 * XXX - rethink
128 */
129 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
130 p += 2;
131 print = strcmp(p, dest);
132 }
133 if (docd(p, print) >= 0)
134 return 0;
135
136 }
137 }
138 error("can't cd to %s", dest);
139 /* NOTREACHED */
140 }
141
142
143 /*
144 * Actually do the chdir. In an interactive shell, print the
145 * directory name if "print" is nonzero.
146 */
147
148 STATIC int
149 docd(char *dest, int print)
150 {
151 char *p;
152 char *q;
153 char *component;
154 struct stat statb;
155 int first;
156 int badstat;
157
158 TRACE(("docd(\"%s\", %d) called\n", dest, print));
159
160 /*
161 * Check each component of the path. If we find a symlink or
162 * something we can't stat, clear curdir to force a getcwd()
163 * next time we get the value of the current directory.
164 */
165 badstat = 0;
166 cdcomppath = stalloc(strlen(dest) + 1);
167 scopy(dest, cdcomppath);
168 STARTSTACKSTR(p);
169 if (*dest == '/') {
170 STPUTC('/', p);
171 cdcomppath++;
172 }
173 first = 1;
174 while ((q = getcomponent()) != NULL) {
175 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
176 continue;
177 if (! first)
178 STPUTC('/', p);
179 first = 0;
180 component = q;
181 while (*q)
182 STPUTC(*q++, p);
183 if (equal(component, ".."))
184 continue;
185 STACKSTRNUL(p);
186 if ((lstat(stackblock(), &statb) < 0)
187 || (S_ISLNK(statb.st_mode))) {
188 /* print = 1; */
189 badstat = 1;
190 break;
191 }
192 }
193
194 INTOFF;
195 if (chdir(dest) < 0) {
196 INTON;
197 return -1;
198 }
199 updatepwd(badstat ? NULL : dest);
200 INTON;
201 if (print && iflag && curdir)
202 out1fmt("%s\n", curdir);
203 return 0;
204 }
205
206
207 /*
208 * Get the next component of the path name pointed to by cdcomppath.
209 * This routine overwrites the string pointed to by cdcomppath.
210 */
211
212 STATIC char *
213 getcomponent()
214 {
215 char *p;
216 char *start;
217
218 if ((p = cdcomppath) == NULL)
219 return NULL;
220 start = cdcomppath;
221 while (*p != '/' && *p != '\0')
222 p++;
223 if (*p == '\0') {
224 cdcomppath = NULL;
225 } else {
226 *p++ = '\0';
227 cdcomppath = p;
228 }
229 return start;
230 }
231
232
233
234 /*
235 * Update curdir (the name of the current directory) in response to a
236 * cd command. We also call hashcd to let the routines in exec.c know
237 * that the current directory has changed.
238 */
239
240 STATIC void
241 updatepwd(char *dir)
242 {
243 char *new;
244 char *p;
245
246 hashcd(); /* update command hash table */
247
248 /*
249 * If our argument is NULL, we don't know the current directory
250 * any more because we traversed a symbolic link or something
251 * we couldn't stat().
252 */
253 if (dir == NULL || curdir == NULL) {
254 if (prevdir)
255 ckfree(prevdir);
256 INTOFF;
257 prevdir = curdir;
258 curdir = NULL;
259 getpwd(1);
260 INTON;
261 if (curdir)
262 setvar("PWD", curdir, VEXPORT);
263 else
264 unsetvar("PWD", 0);
265 return;
266 }
267 cdcomppath = stalloc(strlen(dir) + 1);
268 scopy(dir, cdcomppath);
269 STARTSTACKSTR(new);
270 if (*dir != '/') {
271 p = curdir;
272 while (*p)
273 STPUTC(*p++, new);
274 if (p[-1] == '/')
275 STUNPUTC(new);
276 }
277 while ((p = getcomponent()) != NULL) {
278 if (equal(p, "..")) {
279 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
280 } else if (*p != '\0' && ! equal(p, ".")) {
281 STPUTC('/', new);
282 while (*p)
283 STPUTC(*p++, new);
284 }
285 }
286 if (new == stackblock())
287 STPUTC('/', new);
288 STACKSTRNUL(new);
289 INTOFF;
290 if (prevdir)
291 ckfree(prevdir);
292 prevdir = curdir;
293 curdir = savestr(stackblock());
294 setvar("PWD", curdir, VEXPORT);
295 INTON;
296 }
297
298 /*
299 * Posix says the default should be 'pwd -L' (as below), however
300 * the 'cd' command (above) does something much nearer to the
301 * posix 'cd -P' (not the posix default of 'cd -L').
302 * If 'cd' is changed to support -P/L then the default here
303 * needs to be revisited if the historic behaviour is to be kept.
304 */
305
306 int
307 pwdcmd(int argc, char **argv)
308 {
309 int i;
310 char opt = 'L';
311
312 while ((i = nextopt("LP")) != '\0')
313 opt = i;
314 if (*argptr)
315 error("unexpected argument");
316
317 if (opt == 'L')
318 getpwd(0);
319 else
320 find_curdir(0);
321
322 setvar("PWD", curdir, VEXPORT);
323 out1str(curdir);
324 out1c('\n');
325 return 0;
326 }
327
328
329
330
331 #define MAXPWD 256
332
333 /*
334 * Find out what the current directory is. If we already know the current
335 * directory, this routine returns immediately.
336 */
337 void
338 getpwd(int noerror)
339 {
340 char *pwd;
341 struct stat stdot, stpwd;
342 static int first = 1;
343
344 if (curdir)
345 return;
346
347 if (first) {
348 first = 0;
349 pwd = getenv("PWD");
350 if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
351 stat(pwd, &stpwd) != -1 &&
352 stdot.st_dev == stpwd.st_dev &&
353 stdot.st_ino == stpwd.st_ino) {
354 curdir = savestr(pwd);
355 return;
356 }
357 }
358
359 find_curdir(noerror);
360
361 return;
362 }
363
364 STATIC void
365 find_curdir(int noerror)
366 {
367 int i;
368 char *pwd;
369
370 /*
371 * Things are a bit complicated here; we could have just used
372 * getcwd, but traditionally getcwd is implemented using popen
373 * to /bin/pwd. This creates a problem for us, since we cannot
374 * keep track of the job if it is being ran behind our backs.
375 * So we re-implement getcwd(), and we suppress interrupts
376 * throughout the process. This is not completely safe, since
377 * the user can still break out of it by killing the pwd program.
378 * We still try to use getcwd for systems that we know have a
379 * c implementation of getcwd, that does not open a pipe to
380 * /bin/pwd.
381 */
382 #if defined(__NetBSD__) || defined(__SVR4) || defined(__linux__)
383 for (i = MAXPWD;; i *= 2) {
384 pwd = stalloc(i);
385 if (getcwd(pwd, i) != NULL) {
386 curdir = savestr(pwd);
387 return;
388 }
389 stunalloc(pwd);
390 if (errno == ERANGE)
391 continue;
392 if (!noerror)
393 error("getcwd() failed: %s", strerror(errno));
394 return;
395 }
396 #else
397 {
398 char *p;
399 int status;
400 struct job *jp;
401 int pip[2];
402
403 pwd = stalloc(MAXPWD);
404 INTOFF;
405 if (pipe(pip) < 0)
406 error("Pipe call failed");
407 jp = makejob((union node *)NULL, 1);
408 if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
409 (void) close(pip[0]);
410 if (pip[1] != 1) {
411 close(1);
412 copyfd(pip[1], 1);
413 close(pip[1]);
414 }
415 (void) execl("/bin/pwd", "pwd", (char *)0);
416 sh_warn("Cannot exec /bin/pwd");
417 exit(1);
418 }
419 (void) close(pip[1]);
420 pip[1] = -1;
421 p = pwd;
422 while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
423 || (i == -1 && errno == EINTR)) {
424 if (i > 0)
425 p += i;
426 }
427 (void) close(pip[0]);
428 pip[0] = -1;
429 status = waitforjob(jp);
430 if (status != 0)
431 error((char *)0);
432 if (i < 0 || p == pwd || p[-1] != '\n') {
433 if (noerror) {
434 INTON;
435 return;
436 }
437 error("pwd command failed");
438 }
439 p[-1] = '\0';
440 INTON;
441 curdir = savestr(pwd);
442 return;
443 }
444 #endif
445 }
+0
-35
sh/cd.h less more
0 /* $NetBSD: cd.h,v 1.4 2003/08/07 09:05:30 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1995
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 */
31
32 void getpwd(int);
33 int cdcmd(int, char **);
34 int pwdcmd(int, char **);
+0
-366
sh/error.c less more
0 /* $NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 /*
44 * Errors and exceptions.
45 */
46
47 #include <signal.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <string.h>
53
54 #include "shell.h"
55 #include "main.h"
56 #include "options.h"
57 #include "output.h"
58 #include "error.h"
59 #include "show.h"
60
61 #define signal bsd_signal
62 /*
63 * Code to handle exceptions in C.
64 */
65
66 struct jmploc *handler;
67 int exception;
68 volatile int suppressint;
69 volatile int intpending;
70 char *commandname;
71
72
73 static void exverror(int, const char *, va_list)
74 __attribute__((__noreturn__));
75
76 /*
77 * Called to raise an exception. Since C doesn't include exceptions, we
78 * just do a longjmp to the exception handler. The type of exception is
79 * stored in the global variable "exception".
80 */
81
82 void
83 exraise(int e)
84 {
85 if (handler == NULL)
86 abort();
87 exception = e;
88 longjmp(handler->loc, 1);
89 }
90
91
92 /*
93 * Called from trap.c when a SIGINT is received. (If the user specifies
94 * that SIGINT is to be trapped or ignored using the trap builtin, then
95 * this routine is not called.) Suppressint is nonzero when interrupts
96 * are held using the INTOFF macro. The call to _exit is necessary because
97 * there is a short period after a fork before the signal handlers are
98 * set to the appropriate value for the child. (The test for iflag is
99 * just defensive programming.)
100 */
101
102 void
103 onint(void)
104 {
105 sigset_t nsigset;
106
107 if (suppressint) {
108 intpending = 1;
109 return;
110 }
111 intpending = 0;
112 sigemptyset(&nsigset);
113 sigprocmask(SIG_SETMASK, &nsigset, NULL);
114 if (rootshell && iflag)
115 exraise(EXINT);
116 else {
117 signal(SIGINT, SIG_DFL);
118 raise(SIGINT);
119 }
120 /* NOTREACHED */
121 }
122
123 static void
124 exvwarning(int sv_errno, const char *msg, va_list ap)
125 {
126 /* Partially emulate line buffered output so that:
127 * printf '%d\n' 1 a 2
128 * and
129 * printf '%d %d %d\n' 1 a 2
130 * both generate sensible text when stdout and stderr are merged.
131 */
132 if (output.nextc != output.buf && output.nextc[-1] == '\n')
133 flushout(&output);
134 if (commandname)
135 outfmt(&errout, "%s: ", commandname);
136 if (msg != NULL) {
137 doformat(&errout, msg, ap);
138 if (sv_errno >= 0)
139 outfmt(&errout, ": ");
140 }
141 if (sv_errno >= 0)
142 outfmt(&errout, "%s", strerror(sv_errno));
143 out2c('\n');
144 flushout(&errout);
145 }
146
147 /*
148 * Exverror is called to raise the error exception. If the second argument
149 * is not NULL then error prints an error message using printf style
150 * formatting. It then raises the error exception.
151 */
152 static void
153 exverror(int cond, const char *msg, va_list ap)
154 {
155 CLEAR_PENDING_INT;
156 INTOFF;
157
158 #ifdef DEBUG
159 if (msg) {
160 TRACE(("exverror(%d, \"", cond));
161 TRACEV((msg, ap));
162 TRACE(("\") pid=%d\n", getpid()));
163 } else
164 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
165 #endif
166 if (msg)
167 exvwarning(-1, msg, ap);
168
169 flushall();
170 exraise(cond);
171 /* NOTREACHED */
172 }
173
174
175 void
176 error(const char *msg, ...)
177 {
178 va_list ap;
179
180 va_start(ap, msg);
181 exverror(EXERROR, msg, ap);
182 /* NOTREACHED */
183 va_end(ap);
184 }
185
186
187 void
188 exerror(int cond, const char *msg, ...)
189 {
190 va_list ap;
191
192 va_start(ap, msg);
193 exverror(cond, msg, ap);
194 /* NOTREACHED */
195 va_end(ap);
196 }
197
198 /*
199 * error/warning routines for external builtins
200 */
201
202 void
203 sh_exit(int rval)
204 {
205 exerrno = rval & 255;
206 exraise(EXEXEC);
207 }
208
209 void
210 sh_err(int status, const char *fmt, ...)
211 {
212 va_list ap;
213
214 va_start(ap, fmt);
215 exvwarning(errno, fmt, ap);
216 va_end(ap);
217 sh_exit(status);
218 }
219
220 void
221 sh_verr(int status, const char *fmt, va_list ap)
222 {
223 exvwarning(errno, fmt, ap);
224 sh_exit(status);
225 }
226
227 void
228 sh_errx(int status, const char *fmt, ...)
229 {
230 va_list ap;
231
232 va_start(ap, fmt);
233 exvwarning(-1, fmt, ap);
234 va_end(ap);
235 sh_exit(status);
236 }
237
238 void
239 sh_verrx(int status, const char *fmt, va_list ap)
240 {
241 exvwarning(-1, fmt, ap);
242 sh_exit(status);
243 }
244
245 void
246 sh_warn(const char *fmt, ...)
247 {
248 va_list ap;
249
250 va_start(ap, fmt);
251 exvwarning(errno, fmt, ap);
252 va_end(ap);
253 }
254
255 void
256 sh_vwarn(const char *fmt, va_list ap)
257 {
258 exvwarning(errno, fmt, ap);
259 }
260
261 void
262 sh_warnx(const char *fmt, ...)
263 {
264 va_list ap;
265
266 va_start(ap, fmt);
267 exvwarning(-1, fmt, ap);
268 va_end(ap);
269 }
270
271 void
272 sh_vwarnx(const char *fmt, va_list ap)
273 {
274 exvwarning(-1, fmt, ap);
275 }
276
277
278 /*
279 * Table of error messages.
280 */
281
282 struct errname {
283 short errcode; /* error number */
284 short action; /* operation which encountered the error */
285 const char *msg; /* text describing the error */
286 };
287
288
289 #define ALL (E_OPEN|E_CREAT|E_EXEC)
290
291 STATIC const struct errname errormsg[] = {
292 { EINTR, ALL, "interrupted" },
293 { EACCES, ALL, "permission denied" },
294 { EIO, ALL, "I/O error" },
295 { EEXIST, ALL, "file exists" },
296 { ENOENT, E_OPEN, "no such file" },
297 { ENOENT, E_CREAT,"directory nonexistent" },
298 { ENOENT, E_EXEC, "not found" },
299 { ENOTDIR, E_OPEN, "no such file" },
300 { ENOTDIR, E_CREAT,"directory nonexistent" },
301 { ENOTDIR, E_EXEC, "not found" },
302 { EISDIR, ALL, "is a directory" },
303 #ifdef EMFILE
304 { EMFILE, ALL, "too many open files" },
305 #endif
306 { ENFILE, ALL, "file table overflow" },
307 { ENOSPC, ALL, "file system full" },
308 #ifdef EDQUOT
309 { EDQUOT, ALL, "disk quota exceeded" },
310 #endif
311 #ifdef ENOSR
312 { ENOSR, ALL, "no streams resources" },
313 #endif
314 { ENXIO, ALL, "no such device or address" },
315 { EROFS, ALL, "read-only file system" },
316 { ETXTBSY, ALL, "text busy" },
317 #ifdef EAGAIN
318 { EAGAIN, E_EXEC, "not enough memory" },
319 #endif
320 { ENOMEM, ALL, "not enough memory" },
321 #ifdef ENOLINK
322 { ENOLINK, ALL, "remote access failed" },
323 #endif
324 #ifdef EMULTIHOP
325 { EMULTIHOP, ALL, "remote access failed" },
326 #endif
327 #ifdef ECOMM
328 { ECOMM, ALL, "remote access failed" },
329 #endif
330 #ifdef ESTALE
331 { ESTALE, ALL, "remote access failed" },
332 #endif
333 #ifdef ETIMEDOUT
334 { ETIMEDOUT, ALL, "remote access failed" },
335 #endif
336 #ifdef ELOOP
337 { ELOOP, ALL, "symbolic link loop" },
338 #endif
339 { E2BIG, E_EXEC, "argument list too long" },
340 #ifdef ELIBACC
341 { ELIBACC, E_EXEC, "shared library missing" },
342 #endif
343 { 0, 0, NULL },
344 };
345
346
347 /*
348 * Return a string describing an error. The returned string may be a
349 * pointer to a static buffer that will be overwritten on the next call.
350 * Action describes the operation that got the error.
351 */
352
353 const char *
354 errmsg(int e, int action)
355 {
356 struct errname const *ep;
357 static char buf[12];
358
359 for (ep = errormsg ; ep->errcode ; ep++) {
360 if (ep->errcode == e && (ep->action & action) != 0)
361 return ep->msg;
362 }
363 fmtstr(buf, sizeof buf, "error %d", e);
364 return buf;
365 }
+0
-117
sh/error.h less more
0 /* $NetBSD: error.h,v 1.16 2003/08/07 09:05:30 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)error.h 8.2 (Berkeley) 5/4/95
34 */
35
36 #include <stdarg.h>
37
38 /*
39 * Types of operations (passed to the errmsg routine).
40 */
41
42 #define E_OPEN 01 /* opening a file */
43 #define E_CREAT 02 /* creating a file */
44 #define E_EXEC 04 /* executing a program */
45
46
47 /*
48 * We enclose jmp_buf in a structure so that we can declare pointers to
49 * jump locations. The global variable handler contains the location to
50 * jump to when an exception occurs, and the global variable exception
51 * contains a code identifying the exeception. To implement nested
52 * exception handlers, the user should save the value of handler on entry
53 * to an inner scope, set handler to point to a jmploc structure for the
54 * inner scope, and restore handler on exit from the scope.
55 */
56
57 #include <setjmp.h>
58
59 struct jmploc {
60 jmp_buf loc;
61 };
62
63 extern struct jmploc *handler;
64 extern int exception;
65 extern int exerrno; /* error for EXEXEC */
66
67 /* exceptions */
68 #define EXINT 0 /* SIGINT received */
69 #define EXERROR 1 /* a generic error */
70 #define EXSHELLPROC 2 /* execute a shell procedure */
71 #define EXEXEC 3 /* command execution failed */
72
73
74 /*
75 * These macros allow the user to suspend the handling of interrupt signals
76 * over a period of time. This is similar to SIGHOLD to or sigblock, but
77 * much more efficient and portable. (But hacking the kernel is so much
78 * more fun than worrying about efficiency and portability. :-))
79 */
80
81 extern volatile int suppressint;
82 extern volatile int intpending;
83
84 #define INTOFF suppressint++
85 #define INTON { if (--suppressint == 0 && intpending) onint(); }
86 #define FORCEINTON {suppressint = 0; if (intpending) onint();}
87 #define CLEAR_PENDING_INT intpending = 0
88 #define int_pending() intpending
89
90 void exraise(int) __attribute__((__noreturn__));
91 void onint(void);
92 void error(const char *, ...) __attribute__((__noreturn__));
93 void exerror(int, const char *, ...) __attribute__((__noreturn__));
94 const char *errmsg(int, int);
95
96 void sh_err(int, const char *, ...) __attribute__((__noreturn__));
97 void sh_verr(int, const char *, va_list) __attribute__((__noreturn__));
98 void sh_errx(int, const char *, ...) __attribute__((__noreturn__));
99 void sh_verrx(int, const char *, va_list) __attribute__((__noreturn__));
100 void sh_warn(const char *, ...);
101 void sh_vwarn(const char *, va_list);
102 void sh_warnx(const char *, ...);
103 void sh_vwarnx(const char *, va_list);
104
105 void sh_exit(int) __attribute__((__noreturn__));
106
107
108 /*
109 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
110 * so we use _setjmp instead.
111 */
112
113 #if defined(BSD) && !defined(__SVR4) && !defined(__linux__)
114 #define setjmp(jmploc) _setjmp(jmploc)
115 #define longjmp(jmploc, val) _longjmp(jmploc, val)
116 #endif
+0
-1257
sh/eval.c less more
0 /* $NetBSD: eval.c,v 1.81.2.1 2005/06/13 22:03:51 tron Exp $ */
1
2 /*-
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
38 #else
39 __RCSID("$NetBSD: eval.c,v 1.81.2.1 2005/06/13 22:03:51 tron Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <stdlib.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #ifdef __linux__
48 #include <fcntl.h>
49 #else
50 #include <sys/fcntl.h>
51 #endif
52 #include <sys/times.h>
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/wait.h>
56
57 /*
58 * Evaluate a command.
59 */
60
61 #include "shell.h"
62 #include "nodes.h"
63 #include "syntax.h"
64 #include "expand.h"
65 #include "parser.h"
66 #include "jobs.h"
67 #include "eval.h"
68 #include "builtins.h"
69 #include "options.h"
70 #include "exec.h"
71 #include "redir.h"
72 #include "input.h"
73 #include "output.h"
74 #include "trap.h"
75 #include "var.h"
76 #include "memalloc.h"
77 #include "error.h"
78 #include "show.h"
79 #include "mystring.h"
80 #include "main.h"
81 #ifndef SMALL
82 #include "myhistedit.h"
83 #endif
84
85
86 /* flags in argument to evaltree */
87 #define EV_EXIT 01 /* exit after evaluating tree */
88 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
89 #define EV_BACKCMD 04 /* command executing within back quotes */
90
91 int evalskip; /* set if we are skipping commands */
92 STATIC int skipcount; /* number of levels to skip */
93 MKINIT int loopnest; /* current loop nesting level */
94 int funcnest; /* depth of function calls */
95
96
97 char *commandname;
98 struct strlist *cmdenviron;
99 int exitstatus; /* exit status of last command */
100 int back_exitstatus; /* exit status of backquoted command */
101
102
103 STATIC void evalloop(union node *, int);
104 STATIC void evalfor(union node *, int);
105 STATIC void evalcase(union node *, int);
106 STATIC void evalsubshell(union node *, int);
107 STATIC void expredir(union node *);
108 STATIC void evalpipe(union node *);
109 STATIC void evalcommand(union node *, int, struct backcmd *);
110 STATIC void prehash(union node *);
111
112
113 /*
114 * Called to reset things after an exception.
115 */
116
117 #ifdef mkinit
118 INCLUDE "eval.h"
119
120 RESET {
121 evalskip = 0;
122 loopnest = 0;
123 funcnest = 0;
124 }
125
126 SHELLPROC {
127 exitstatus = 0;
128 }
129 #endif
130
131 static int
132 sh_pipe(int fds[2])
133 {
134 int nfd;
135
136 if (pipe(fds))
137 return -1;
138
139 if (fds[0] < 3) {
140 nfd = fcntl(fds[0], F_DUPFD, 3);
141 if (nfd != -1) {
142 close(fds[0]);
143 fds[0] = nfd;
144 }
145 }
146
147 if (fds[1] < 3) {
148 nfd = fcntl(fds[1], F_DUPFD, 3);
149 if (nfd != -1) {
150 close(fds[1]);
151 fds[1] = nfd;
152 }
153 }
154 return 0;
155 }
156
157
158 /*
159 * The eval commmand.
160 */
161
162 int
163 evalcmd(int argc, char **argv)
164 {
165 char *p;
166 char *concat;
167 char **ap;
168
169 if (argc > 1) {
170 p = argv[1];
171 if (argc > 2) {
172 STARTSTACKSTR(concat);
173 ap = argv + 2;
174 for (;;) {
175 while (*p)
176 STPUTC(*p++, concat);
177 if ((p = *ap++) == NULL)
178 break;
179 STPUTC(' ', concat);
180 }
181 STPUTC('\0', concat);
182 p = grabstackstr(concat);
183 }
184 evalstring(p, EV_TESTED);
185 }
186 return exitstatus;
187 }
188
189
190 /*
191 * Execute a command or commands contained in a string.
192 */
193
194 void
195 evalstring(char *s, int flag)
196 {
197 union node *n;
198 struct stackmark smark;
199
200 setstackmark(&smark);
201 setinputstring(s, 1);
202
203 while ((n = parsecmd(0)) != NEOF) {
204 evaltree(n, flag);
205 popstackmark(&smark);
206 }
207 popfile();
208 popstackmark(&smark);
209 }
210
211
212
213 /*
214 * Evaluate a parse tree. The value is left in the global variable
215 * exitstatus.
216 */
217
218 void
219 evaltree(union node *n, int flags)
220 {
221 if (n == NULL) {
222 TRACE(("evaltree(NULL) called\n"));
223 exitstatus = 0;
224 goto out;
225 }
226 #ifdef WITH_HISTORY
227 displayhist = 1; /* show history substitutions done with fc */
228 #endif
229 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
230 getpid(), n, n->type, flags));
231 switch (n->type) {
232 case NSEMI:
233 evaltree(n->nbinary.ch1, flags & EV_TESTED);
234 if (evalskip)
235 goto out;
236 evaltree(n->nbinary.ch2, flags);
237 break;
238 case NAND:
239 evaltree(n->nbinary.ch1, EV_TESTED);
240 if (evalskip || exitstatus != 0)
241 goto out;
242 evaltree(n->nbinary.ch2, flags);
243 break;
244 case NOR:
245 evaltree(n->nbinary.ch1, EV_TESTED);
246 if (evalskip || exitstatus == 0)
247 goto out;
248 evaltree(n->nbinary.ch2, flags);
249 break;
250 case NREDIR:
251 expredir(n->nredir.redirect);
252 redirect(n->nredir.redirect, REDIR_PUSH);
253 evaltree(n->nredir.n, flags);
254 popredir();
255 break;
256 case NSUBSHELL:
257 evalsubshell(n, flags);
258 break;
259 case NBACKGND:
260 evalsubshell(n, flags);
261 break;
262 case NIF: {
263 evaltree(n->nif.test, EV_TESTED);
264 if (evalskip)
265 goto out;
266 if (exitstatus == 0)
267 evaltree(n->nif.ifpart, flags);
268 else if (n->nif.elsepart)
269 evaltree(n->nif.elsepart, flags);
270 else
271 exitstatus = 0;
272 break;
273 }
274 case NWHILE:
275 case NUNTIL:
276 evalloop(n, flags);
277 break;
278 case NFOR:
279 evalfor(n, flags);
280 break;
281 case NCASE:
282 evalcase(n, flags);
283 break;
284 case NDEFUN:
285 defun(n->narg.text, n->narg.next);
286 exitstatus = 0;
287 break;
288 case NNOT:
289 evaltree(n->nnot.com, EV_TESTED);
290 exitstatus = !exitstatus;
291 break;
292 case NPIPE:
293 evalpipe(n);
294 break;
295 case NCMD:
296 evalcommand(n, flags, (struct backcmd *)NULL);
297 break;
298 default:
299 out1fmt("Node type = %d\n", n->type);
300 flushout(&output);
301 break;
302 }
303 out:
304 if (pendingsigs)
305 dotrap();
306 if ((flags & EV_EXIT) != 0)
307 exitshell(exitstatus);
308 }
309
310
311 STATIC void
312 evalloop(union node *n, int flags)
313 {
314 int status;
315
316 loopnest++;
317 status = 0;
318 for (;;) {
319 evaltree(n->nbinary.ch1, EV_TESTED);
320 if (evalskip) {
321 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
322 evalskip = 0;
323 continue;
324 }
325 if (evalskip == SKIPBREAK && --skipcount <= 0)
326 evalskip = 0;
327 break;
328 }
329 if (n->type == NWHILE) {
330 if (exitstatus != 0)
331 break;
332 } else {
333 if (exitstatus == 0)
334 break;
335 }
336 evaltree(n->nbinary.ch2, flags & EV_TESTED);
337 status = exitstatus;
338 if (evalskip)
339 goto skipping;
340 }
341 loopnest--;
342 exitstatus = status;
343 }
344
345
346
347 STATIC void
348 evalfor(union node *n, int flags)
349 {
350 struct arglist arglist;
351 union node *argp;
352 struct strlist *sp;
353 struct stackmark smark;
354 int status = 0;
355
356 setstackmark(&smark);
357 arglist.lastp = &arglist.list;
358 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
359 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
360 if (evalskip)
361 goto out;
362 }
363 *arglist.lastp = NULL;
364
365 loopnest++;
366 for (sp = arglist.list ; sp ; sp = sp->next) {
367 setvar(n->nfor.var, sp->text, 0);
368 evaltree(n->nfor.body, flags & EV_TESTED);
369 status = exitstatus;
370 if (evalskip) {
371 if (evalskip == SKIPCONT && --skipcount <= 0) {
372 evalskip = 0;
373 continue;
374 }
375 if (evalskip == SKIPBREAK && --skipcount <= 0)
376 evalskip = 0;
377 break;
378 }
379 }
380 loopnest--;
381 exitstatus = status;
382 out:
383 popstackmark(&smark);
384 }
385
386
387
388 STATIC void
389 evalcase(union node *n, int flags)
390 {
391 union node *cp;
392 union node *patp;
393 struct arglist arglist;
394 struct stackmark smark;
395 int status = 0;
396
397 setstackmark(&smark);
398 arglist.lastp = &arglist.list;
399 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
400 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
401 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
402 if (casematch(patp, arglist.list->text)) {
403 if (evalskip == 0) {
404 evaltree(cp->nclist.body, flags);
405 status = exitstatus;
406 }
407 goto out;
408 }
409 }
410 }
411 out:
412 exitstatus = status;
413 popstackmark(&smark);
414 }
415
416
417
418 /*
419 * Kick off a subshell to evaluate a tree.
420 */
421
422 STATIC void
423 evalsubshell(union node *n, int flags)
424 {
425 struct job *jp;
426 int backgnd = (n->type == NBACKGND);
427
428 expredir(n->nredir.redirect);
429 INTOFF;
430 jp = makejob(n, 1);
431 if (forkshell(jp, n, backgnd) == 0) {
432 INTON;
433 if (backgnd)
434 flags &=~ EV_TESTED;
435 redirect(n->nredir.redirect, 0);
436 /* never returns */
437 evaltree(n->nredir.n, flags | EV_EXIT);
438 }
439 if (! backgnd)
440 exitstatus = waitforjob(jp);
441 INTON;
442 }
443
444
445
446 /*
447 * Compute the names of the files in a redirection list.
448 */
449
450 STATIC void
451 expredir(union node *n)
452 {
453 union node *redir;
454
455 for (redir = n ; redir ; redir = redir->nfile.next) {
456 struct arglist fn;
457 fn.lastp = &fn.list;
458 switch (redir->type) {
459 case NFROMTO:
460 case NFROM:
461 case NTO:
462 case NCLOBBER:
463 case NAPPEND:
464 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
465 redir->nfile.expfname = fn.list->text;
466 break;
467 case NFROMFD:
468 case NTOFD:
469 if (redir->ndup.vname) {
470 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
471 fixredir(redir, fn.list->text, 1);
472 }
473 break;
474 }
475 }
476 }
477
478
479
480 /*
481 * Evaluate a pipeline. All the processes in the pipeline are children
482 * of the process creating the pipeline. (This differs from some versions
483 * of the shell, which make the last process in a pipeline the parent
484 * of all the rest.)
485 */
486
487 STATIC void
488 evalpipe(union node *n)
489 {
490 struct job *jp;
491 struct nodelist *lp;
492 int pipelen;
493 int prevfd;
494 int pip[2];
495
496 TRACE(("evalpipe(0x%lx) called\n", (long)n));
497 pipelen = 0;
498 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
499 pipelen++;
500 INTOFF;
501 jp = makejob(n, pipelen);
502 prevfd = -1;
503 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
504 prehash(lp->n);
505 pip[1] = -1;
506 if (lp->next) {
507 if (sh_pipe(pip) < 0) {
508 close(prevfd);
509 error("Pipe call failed");
510 }
511 }
512 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
513 INTON;
514 if (prevfd > 0) {
515 close(0);
516 copyfd(prevfd, 0);
517 close(prevfd);
518 }
519 if (pip[1] >= 0) {
520 close(pip[0]);
521 if (pip[1] != 1) {
522 close(1);
523 copyfd(pip[1], 1);
524 close(pip[1]);
525 }
526 }
527 evaltree(lp->n, EV_EXIT);
528 }
529 if (prevfd >= 0)
530 close(prevfd);
531 prevfd = pip[0];
532 close(pip[1]);
533 }
534 if (n->npipe.backgnd == 0) {
535 exitstatus = waitforjob(jp);
536 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
537 }
538 INTON;
539 }
540
541
542
543 /*
544 * Execute a command inside back quotes. If it's a builtin command, we
545 * want to save its output in a block obtained from malloc. Otherwise
546 * we fork off a subprocess and get the output of the command via a pipe.
547 * Should be called with interrupts off.
548 */
549
550 void
551 evalbackcmd(union node *n, struct backcmd *result)
552 {
553 int pip[2];
554 struct job *jp;
555 struct stackmark smark; /* unnecessary */
556
557 setstackmark(&smark);
558 result->fd = -1;
559 result->buf = NULL;
560 result->nleft = 0;
561 result->jp = NULL;
562 if (n == NULL) {
563 goto out;
564 }
565 #ifdef notyet
566 /*
567 * For now we disable executing builtins in the same
568 * context as the shell, because we are not keeping
569 * enough state to recover from changes that are
570 * supposed only to affect subshells. eg. echo "`cd /`"
571 */
572 if (n->type == NCMD) {
573 exitstatus = oexitstatus;
574 evalcommand(n, EV_BACKCMD, result);
575 } else
576 #endif
577 {
578 INTOFF;
579 if (sh_pipe(pip) < 0)
580 error("Pipe call failed");
581 jp = makejob(n, 1);
582 if (forkshell(jp, n, FORK_NOJOB) == 0) {
583 FORCEINTON;
584 close(pip[0]);
585 if (pip[1] != 1) {
586 close(1);
587 copyfd(pip[1], 1);
588 close(pip[1]);
589 }
590 eflag = 0;
591 evaltree(n, EV_EXIT);
592 /* NOTREACHED */
593 }
594 close(pip[1]);
595 result->fd = pip[0];
596 result->jp = jp;
597 INTON;
598 }
599 out:
600 popstackmark(&smark);
601 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
602 result->fd, result->buf, result->nleft, result->jp));
603 }
604
605 static const char *
606 syspath(void)
607 {
608 static char *sys_path = NULL;
609 #ifndef __linux__
610 static int mib[] = {CTL_USER, USER_CS_PATH};
611 #endif
612 static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
613
614 if (sys_path == NULL) {
615 #ifndef __linux__
616 size_t len;
617 if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
618 (sys_path = ckmalloc(len + 5)) != NULL &&
619 sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
620 memcpy(sys_path, "PATH=", 5);
621 } else
622 #endif
623 {
624 ckfree(sys_path);
625 /* something to keep things happy */
626 sys_path = def_path;
627 }
628 }
629 return sys_path;
630 }
631
632 static int
633 parse_command_args(int argc, char **argv, int *use_syspath)
634 {
635 int sv_argc = argc;
636 char *cp, c;
637
638 *use_syspath = 0;
639
640 for (;;) {
641 argv++;
642 if (--argc == 0)
643 break;
644 cp = *argv;
645 if (*cp++ != '-')
646 break;
647 if (*cp == '-' && cp[1] == 0) {
648 argv++;
649 argc--;
650 break;
651 }
652 while ((c = *cp++)) {
653 switch (c) {
654 case 'p':
655 *use_syspath = 1;
656 break;
657 default:
658 /* run 'typecmd' for other options */
659 return 0;
660 }
661 }
662 }
663 return sv_argc - argc;
664 }
665
666 int vforked = 0;
667
668 /*
669 * Execute a simple command.
670 */
671
672 STATIC void
673 evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
674 {
675 struct stackmark smark;
676 union node *argp;
677 struct arglist arglist;
678 struct arglist varlist;
679 char **argv;
680 int argc;
681 char **envp;
682 int varflag;
683 struct strlist *sp;
684 int mode;
685 int pip[2];
686 struct cmdentry cmdentry;
687 struct job *jp;
688 struct jmploc jmploc;
689 struct jmploc *volatile savehandler;
690 char *volatile savecmdname;
691 volatile struct shparam saveparam;
692 struct localvar *volatile savelocalvars;
693 volatile int e;
694 char *lastarg;
695 const char *path = pathval();
696 volatile int temp_path;
697 #if __GNUC__
698 /* Avoid longjmp clobbering */
699 (void) &argv;
700 (void) &argc;
701 (void) &lastarg;
702 (void) &flags;
703 #endif
704
705 vforked = 0;
706 /* First expand the arguments. */
707 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
708 setstackmark(&smark);
709 back_exitstatus = 0;
710
711 arglist.lastp = &arglist.list;
712 varflag = 1;
713 /* Expand arguments, ignoring the initial 'name=value' ones */
714 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
715 char *p = argp->narg.text;
716 if (varflag && is_name(*p)) {
717 do {
718 p++;
719 } while (is_in_name(*p));
720 if (*p == '=')
721 continue;
722 }
723 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
724 varflag = 0;
725 }
726 *arglist.lastp = NULL;
727
728 expredir(cmd->ncmd.redirect);
729
730 /* Now do the initial 'name=value' ones we skipped above */
731 varlist.lastp = &varlist.list;
732 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
733 char *p = argp->narg.text;
734 if (!is_name(*p))
735 break;
736 do
737 p++;
738 while (is_in_name(*p));
739 if (*p != '=')
740 break;
741 expandarg(argp, &varlist, EXP_VARTILDE);
742 }
743 *varlist.lastp = NULL;
744
745 argc = 0;
746 for (sp = arglist.list ; sp ; sp = sp->next)
747 argc++;
748 argv = stalloc(sizeof (char *) * (argc + 1));
749
750 for (sp = arglist.list ; sp ; sp = sp->next) {
751 TRACE(("evalcommand arg: %s\n", sp->text));
752 *argv++ = sp->text;
753 }
754 *argv = NULL;
755 lastarg = NULL;
756 if (iflag && funcnest == 0 && argc > 0)
757 lastarg = argv[-1];
758 argv -= argc;
759
760 /* Print the command if xflag is set. */
761 if (xflag) {
762 char sep = 0;
763 out2str(ps4val());
764 for (sp = varlist.list ; sp ; sp = sp->next) {
765 if (sep != 0)
766 outc(sep, &errout);
767 out2str(sp->text);
768 sep = ' ';
769 }
770 for (sp = arglist.list ; sp ; sp = sp->next) {
771 if (sep != 0)
772 outc(sep, &errout);
773 out2str(sp->text);
774 sep = ' ';
775 }
776 outc('\n', &errout);
777 flushout(&errout);
778 }
779
780 /* Now locate the command. */
781 if (argc == 0) {
782 cmdentry.cmdtype = CMDSPLBLTIN;
783 cmdentry.u.bltin = bltincmd;
784 } else {
785 static const char PATH[] = "PATH=";
786 int cmd_flags = DO_ERR;
787
788 /*
789 * Modify the command lookup path, if a PATH= assignment
790 * is present
791 */
792 for (sp = varlist.list; sp; sp = sp->next)
793 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
794 path = sp->text + sizeof(PATH) - 1;
795
796 do {
797 int argsused, use_syspath;
798 find_command(argv[0], &cmdentry, cmd_flags, path);
799 if (cmdentry.cmdtype == CMDUNKNOWN) {
800 exitstatus = 127;
801 flushout(&errout);
802 goto out;
803 }
804
805 /* implement the 'command' builtin here */
806 if (cmdentry.cmdtype != CMDBUILTIN ||
807 cmdentry.u.bltin != bltincmd)
808 break;
809 cmd_flags |= DO_NOFUNC;
810 argsused = parse_command_args(argc, argv, &use_syspath);
811 if (argsused == 0) {
812 /* use 'type' builting to display info */
813 cmdentry.u.bltin = typecmd;
814 break;
815 }
816 argc -= argsused;
817 argv += argsused;
818 if (use_syspath)
819 path = syspath() + 5;
820 } while (argc != 0);
821 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
822 /* posix mandates that 'command <splbltin>' act as if
823 <splbltin> was a normal builtin */
824 cmdentry.cmdtype = CMDBUILTIN;
825 }
826
827 /* Fork off a child process if necessary. */
828 if (cmd->ncmd.backgnd
829 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
830 || ((flags & EV_BACKCMD) != 0
831 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
832 || cmdentry.u.bltin == dotcmd
833 || cmdentry.u.bltin == evalcmd))) {
834 INTOFF;
835 jp = makejob(cmd, 1);
836 mode = cmd->ncmd.backgnd;
837 if (flags & EV_BACKCMD) {
838 mode = FORK_NOJOB;
839 if (sh_pipe(pip) < 0)
840 error("Pipe call failed");
841 }
842 #ifdef DO_SHAREDVFORK
843 /* It is essential that if DO_SHAREDVFORK is defined that the
844 * child's address space is actually shared with the parent as
845 * we rely on this.
846 */
847 if (cmdentry.cmdtype == CMDNORMAL) {
848 pid_t pid;
849
850 savelocalvars = localvars;
851 localvars = NULL;
852 vforked = 1;
853 switch (pid = vfork()) {
854 case -1:
855 TRACE(("Vfork failed, errno=%d\n", errno));
856 INTON;
857 error("Cannot vfork");
858 break;
859 case 0:
860 /* Make sure that exceptions only unwind to
861 * after the vfork(2)
862 */
863 if (setjmp(jmploc.loc)) {
864 if (exception == EXSHELLPROC) {
865 /* We can't progress with the vfork,
866 * so, set vforked = 2 so the parent
867 * knows, and _exit();
868 */
869 vforked = 2;
870 _exit(0);
871 } else {
872 _exit(exerrno);
873 }
874 }
875 savehandler = handler;
876 handler = &jmploc;
877 listmklocal(varlist.list, VEXPORT | VNOFUNC);
878 forkchild(jp, cmd, mode, vforked);
879 break;
880 default:
881 handler = savehandler; /* restore from vfork(2) */
882 poplocalvars();
883 localvars = savelocalvars;
884 if (vforked == 2) {
885 vforked = 0;
886
887 (void)waitpid(pid, NULL, 0);
888 /* We need to progress in a normal fork fashion */
889 goto normal_fork;
890 }
891 vforked = 0;
892 forkparent(jp, cmd, mode, pid);
893 goto parent;
894 }
895 } else {
896 normal_fork:
897 #endif
898 if (forkshell(jp, cmd, mode) != 0)
899 goto parent; /* at end of routine */
900 FORCEINTON;
901 #ifdef DO_SHAREDVFORK
902 }
903 #endif
904 if (flags & EV_BACKCMD) {
905 if (!vforked) {
906 FORCEINTON;
907 }
908 close(pip[0]);
909 if (pip[1] != 1) {
910 close(1);
911 copyfd(pip[1], 1);
912 close(pip[1]);
913 }
914 }
915 flags |= EV_EXIT;
916 }
917
918 /* This is the child process if a fork occurred. */
919 /* Execute the command. */
920 switch (cmdentry.cmdtype) {
921 case CMDFUNCTION:
922 #ifdef DEBUG
923 trputs("Shell function: "); trargs(argv);
924 #endif
925 redirect(cmd->ncmd.redirect, REDIR_PUSH);
926 saveparam = shellparam;
927 shellparam.malloc = 0;
928 shellparam.reset = 1;
929 shellparam.nparam = argc - 1;
930 shellparam.p = argv + 1;
931 shellparam.optnext = NULL;
932 INTOFF;
933 savelocalvars = localvars;
934 localvars = NULL;
935 INTON;
936 if (setjmp(jmploc.loc)) {
937 if (exception == EXSHELLPROC) {
938 freeparam((volatile struct shparam *)
939 &saveparam);
940 } else {
941 freeparam(&shellparam);
942 shellparam = saveparam;
943 }
944 poplocalvars();
945 localvars = savelocalvars;
946 handler = savehandler;
947 longjmp(handler->loc, 1);
948 }
949 savehandler = handler;
950 handler = &jmploc;
951 listmklocal(varlist.list, 0);
952 /* stop shell blowing its stack */
953 if (++funcnest > 1000)
954 error("too many nested function calls");
955 evaltree(cmdentry.u.func, flags & EV_TESTED);
956 funcnest--;
957 INTOFF;
958 poplocalvars();
959 localvars = savelocalvars;
960 freeparam(&shellparam);
961 shellparam = saveparam;
962 handler = savehandler;
963 popredir();
964 INTON;
965 if (evalskip == SKIPFUNC) {
966 evalskip = 0;
967 skipcount = 0;
968 }
969 if (flags & EV_EXIT)
970 exitshell(exitstatus);
971 break;
972
973 case CMDBUILTIN:
974 case CMDSPLBLTIN:
975 #ifdef DEBUG
976 trputs("builtin command: "); trargs(argv);
977 #endif
978 mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
979 if (flags == EV_BACKCMD) {
980 memout.nleft = 0;
981 memout.nextc = memout.buf;
982 memout.bufsize = 64;
983 mode |= REDIR_BACKQ;
984 }
985 e = -1;
986 savehandler = handler;
987 savecmdname = commandname;
988 handler = &jmploc;
989 if (!setjmp(jmploc.loc)) {
990 /* We need to ensure the command hash table isn't
991 * corruped by temporary PATH assignments.
992 * However we must ensure the 'local' command works!
993 */
994 if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
995 cmdentry.u.bltin == typecmd)) {
996 savelocalvars = localvars;
997 localvars = 0;
998 mklocal(path - 5 /* PATH= */, 0);
999 temp_path = 1;
1000 } else
1001 temp_path = 0;
1002 redirect(cmd->ncmd.redirect, mode);
1003
1004 /* exec is a special builtin, but needs this list... */
1005 cmdenviron = varlist.list;
1006 /* we must check 'readonly' flag for all builtins */
1007 listsetvar(varlist.list,
1008 cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
1009 commandname = argv[0];
1010 /* initialize nextopt */
1011 argptr = argv + 1;
1012 optptr = NULL;
1013 /* and getopt */
1014 #ifndef __linux__
1015 optreset = 1;
1016 #endif
1017 optind = 1;
1018 exitstatus = cmdentry.u.bltin(argc, argv);
1019 } else {
1020 e = exception;
1021 exitstatus = e == EXINT ? SIGINT + 128 :
1022 e == EXEXEC ? exerrno : 2;
1023 }
1024 handler = savehandler;
1025 flushall();
1026 out1 = &output;
1027 out2 = &errout;
1028 freestdout();
1029 if (temp_path) {
1030 poplocalvars();
1031 localvars = savelocalvars;
1032 }
1033 cmdenviron = NULL;
1034 if (e != EXSHELLPROC) {
1035 commandname = savecmdname;
1036 if (flags & EV_EXIT)
1037 exitshell(exitstatus);
1038 }
1039 if (e != -1) {
1040 if ((e != EXERROR && e != EXEXEC)
1041 || cmdentry.cmdtype == CMDSPLBLTIN)
1042 exraise(e);
1043 FORCEINTON;
1044 }
1045 if (cmdentry.u.bltin != execcmd)
1046 popredir();
1047 if (flags == EV_BACKCMD) {
1048 backcmd->buf = memout.buf;
1049 backcmd->nleft = memout.nextc - memout.buf;
1050 memout.buf = NULL;
1051 }
1052 break;
1053
1054 default:
1055 #ifdef DEBUG
1056 trputs("normal command: "); trargs(argv);
1057 #endif
1058 clearredir(vforked);
1059 redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0);
1060 if (!vforked)
1061 for (sp = varlist.list ; sp ; sp = sp->next)
1062 setvareq(sp->text, VEXPORT|VSTACK);
1063 envp = environment();
1064 shellexec(argv, envp, path, cmdentry.u.index, vforked);
1065 break;
1066 }
1067 goto out;
1068
1069 parent: /* parent process gets here (if we forked) */
1070 if (mode == FORK_FG) { /* argument to fork */
1071 exitstatus = waitforjob(jp);
1072 } else if (mode == FORK_NOJOB) {
1073 backcmd->fd = pip[0];
1074 close(pip[1]);
1075 backcmd->jp = jp;
1076 }
1077 FORCEINTON;
1078
1079 out:
1080 if (lastarg)
1081 /* dsl: I think this is intended to be used to support
1082 * '_' in 'vi' command mode during line editing...
1083 * However I implemented that within libedit itself.
1084 */
1085 setvar("_", lastarg, 0);
1086 popstackmark(&smark);
1087
1088 if (eflag && exitstatus && !(flags & EV_TESTED))
1089 exitshell(exitstatus);
1090 }
1091
1092
1093 /*
1094 * Search for a command. This is called before we fork so that the
1095 * location of the command will be available in the parent as well as
1096 * the child. The check for "goodname" is an overly conservative
1097 * check that the name will not be subject to expansion.
1098 */
1099
1100 STATIC void
1101 prehash(union node *n)
1102 {
1103 struct cmdentry entry;
1104
1105 if (n->type == NCMD && n->ncmd.args)
1106 if (goodname(n->ncmd.args->narg.text))
1107 find_command(n->ncmd.args->narg.text, &entry, 0,
1108 pathval());
1109 }
1110
1111
1112
1113 /*
1114 * Builtin commands. Builtin commands whose functions are closely
1115 * tied to evaluation are implemented here.
1116 */
1117
1118 /*
1119 * No command given.
1120 */
1121
1122 int
1123 bltincmd(int argc, char **argv)
1124 {
1125 /*
1126 * Preserve exitstatus of a previous possible redirection
1127 * as POSIX mandates
1128 */
1129 return back_exitstatus;
1130 }
1131
1132
1133 /*
1134 * Handle break and continue commands. Break, continue, and return are
1135 * all handled by setting the evalskip flag. The evaluation routines
1136 * above all check this flag, and if it is set they start skipping
1137 * commands rather than executing them. The variable skipcount is
1138 * the number of loops to break/continue, or the number of function
1139 * levels to return. (The latter is always 1.) It should probably
1140 * be an error to break out of more loops than exist, but it isn't
1141 * in the standard shell so we don't make it one here.
1142 */
1143
1144 int
1145 breakcmd(int argc, char **argv)
1146 {
1147 int n = argc > 1 ? number(argv[1]) : 1;
1148
1149 if (n > loopnest)
1150 n = loopnest;
1151 if (n > 0) {
1152 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1153 skipcount = n;
1154 }
1155 return 0;
1156 }
1157
1158
1159 /*
1160 * The return command.
1161 */
1162
1163 int
1164 returncmd(int argc, char **argv)
1165 {
1166 int ret = argc > 1 ? number(argv[1]) : exitstatus;
1167
1168 if (funcnest) {
1169 evalskip = SKIPFUNC;
1170 skipcount = 1;
1171 return ret;
1172 }
1173 else {
1174 /* Do what ksh does; skip the rest of the file */
1175 evalskip = SKIPFILE;
1176 skipcount = 1;
1177 return ret;
1178 }
1179 }
1180
1181
1182 int
1183 falsecmd(int argc, char **argv)
1184 {
1185 return 1;
1186 }
1187
1188
1189 int
1190 truecmd(int argc, char **argv)
1191 {
1192 return 0;
1193 }
1194
1195
1196 int
1197 execcmd(int argc, char **argv)
1198 {
1199 if (argc > 1) {
1200 struct strlist *sp;
1201
1202 iflag = 0; /* exit on error */
1203 mflag = 0;
1204 optschanged();
1205 for (sp = cmdenviron; sp; sp = sp->next)
1206 setvareq(sp->text, VEXPORT|VSTACK);
1207 shellexec(argv + 1, environment(), pathval(), 0, 0);
1208 }
1209 return 0;
1210 }
1211
1212 static int
1213 conv_time(clock_t ticks, char *seconds, size_t l)
1214 {
1215 static clock_t tpm = 0;
1216 clock_t mins;
1217 int i;
1218
1219 mins = ticks / tpm;
1220 snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm );
1221
1222 if (seconds[0] == '6' && seconds[1] == '0') {
1223 /* 59.99995 got rounded up... */
1224 mins++;
1225 strlcpy(seconds, "0.0", l);
1226 return mins;
1227 }
1228
1229 /* suppress trailing zeros */
1230 i = strlen(seconds) - 1;
1231 for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--)
1232 seconds[i] = 0;
1233 return mins;
1234 }
1235
1236 int
1237 timescmd(int argc, char **argv)
1238 {
1239 struct tms tms;
1240 int u, s, cu, cs;
1241 char us[8], ss[8], cus[8], css[8];
1242
1243 nextopt("");
1244
1245 times(&tms);
1246
1247 u = conv_time(tms.tms_utime, us, sizeof(us));
1248 s = conv_time(tms.tms_stime, ss, sizeof(ss));
1249 cu = conv_time(tms.tms_cutime, cus, sizeof(cus));
1250 cs = conv_time(tms.tms_cstime, css, sizeof(css));
1251
1252 outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n",
1253 u, us, s, ss, cu, cus, cs, css);
1254
1255 return 0;
1256 }
+0
-64
sh/eval.h less more
0 /* $NetBSD: eval.h,v 1.14 2003/08/07 09:05:31 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)eval.h 8.2 (Berkeley) 5/4/95
34 */
35
36 extern char *commandname; /* currently executing command */
37 extern int exitstatus; /* exit status of last command */
38 extern int back_exitstatus; /* exit status of backquoted command */
39 extern struct strlist *cmdenviron; /* environment for builtin command */
40
41
42 struct backcmd { /* result of evalbackcmd */
43 int fd; /* file descriptor to read from */
44 char *buf; /* buffer */
45 int nleft; /* number of chars in buffer */
46 struct job *jp; /* job structure for command */
47 };
48
49 void evalstring(char *, int);
50 union node; /* BLETCH for ansi C */
51 void evaltree(union node *, int);
52 void evalbackcmd(union node *, struct backcmd *);
53
54 /* in_function returns nonzero if we are currently evaluating a function */
55 #define in_function() funcnest
56 extern int funcnest;
57 extern int evalskip;
58
59 /* reasons for skipping commands (see comment on breakcmd routine) */
60 #define SKIPBREAK 1
61 #define SKIPCONT 2
62 #define SKIPFUNC 3
63 #define SKIPFILE 4
+0
-1063
sh/exec.c less more
0 /* $NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
38 #else
39 __RCSID("$NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/wait.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51
52 /*
53 * When commands are first encountered, they are entered in a hash table.
54 * This ensures that a full path search will not have to be done for them
55 * on each invocation.
56 *
57 * We should investigate converting to a linear search, even though that
58 * would make the command name "hash" a misnomer.
59 */
60
61 #include "shell.h"
62 #include "main.h"
63 #include "nodes.h"
64 #include "parser.h"
65 #include "redir.h"
66 #include "eval.h"
67 #include "exec.h"
68 #include "builtins.h"
69 #include "var.h"
70 #include "options.h"
71 #include "input.h"
72 #include "output.h"
73 #include "syntax.h"
74 #include "memalloc.h"
75 #include "error.h"
76 #include "init.h"
77 #include "mystring.h"
78 #include "show.h"
79 #include "jobs.h"
80 #include "alias.h"
81
82
83 #define CMDTABLESIZE 31 /* should be prime */
84 #define ARB 1 /* actual size determined at run time */
85
86
87
88 struct tblentry {
89 struct tblentry *next; /* next entry in hash chain */
90 union param param; /* definition of builtin function */
91 short cmdtype; /* index identifying command */
92 char rehash; /* if set, cd done since entry created */
93 char cmdname[ARB]; /* name of command */
94 };
95
96
97 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
98 STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
99 int exerrno = 0; /* Last exec error */
100
101
102 STATIC void tryexec(char *, char **, char **, int);
103 STATIC void execinterp(char **, char **);
104 STATIC void printentry(struct tblentry *, int);
105 STATIC void clearcmdentry(int);
106 STATIC struct tblentry *cmdlookup(const char *, int);
107 STATIC void delete_cmd_entry(void);
108
109
110 extern char *const parsekwd[];
111
112 /*
113 * Exec a program. Never returns. If you change this routine, you may
114 * have to change the find_command routine as well.
115 */
116
117 void
118 shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
119 {
120 char *cmdname;
121 int e;
122
123 if (strchr(argv[0], '/') != NULL) {
124 tryexec(argv[0], argv, envp, vforked);
125 e = errno;
126 } else {
127 e = ENOENT;
128 while ((cmdname = padvance(&path, argv[0])) != NULL) {
129 if (--idx < 0 && pathopt == NULL) {
130 tryexec(cmdname, argv, envp, vforked);
131 if (errno != ENOENT && errno != ENOTDIR)
132 e = errno;
133 }
134 stunalloc(cmdname);
135 }
136 }
137
138 /* Map to POSIX errors */
139 switch (e) {
140 case EACCES:
141 exerrno = 126;
142 break;
143 case ENOENT:
144 exerrno = 127;
145 break;
146 default:
147 exerrno = 2;
148 break;
149 }
150 TRACE(("shellexec failed for %s, errno %d, vforked %d, suppressint %d\n",
151 argv[0], e, vforked, suppressint ));
152 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
153 /* NOTREACHED */
154 }
155
156
157 STATIC void
158 tryexec(char *cmd, char **argv, char **envp, int vforked)
159 {
160 int e;
161 #ifndef BSD
162 char *p;
163 #endif
164
165 #ifdef SYSV
166 do {
167 execve(cmd, argv, envp);
168 } while (errno == EINTR);
169 #else
170 execve(cmd, argv, envp);
171 #endif
172 e = errno;
173 if (e == ENOEXEC) {
174 if (vforked) {
175 /* We are currently vfork(2)ed, so raise an
176 * exception, and evalcommand will try again
177 * with a normal fork(2).
178 */
179 exraise(EXSHELLPROC);
180 }
181 initshellproc();
182 setinputfile(cmd, 0);
183 commandname = arg0 = savestr(argv[0]);
184 #if !defined(BSD) && !defined(__linux__)
185 pgetc(); pungetc(); /* fill up input buffer */
186 p = parsenextc;
187 if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
188 argv[0] = cmd;
189 execinterp(argv, envp);
190 }
191 #endif
192 setparam(argv + 1);
193 exraise(EXSHELLPROC);
194 }
195 errno = e;
196 }
197
198
199 #if !defined(BSD) && !defined(__linux__)
200 /*
201 * Execute an interpreter introduced by "#!", for systems where this
202 * feature has not been built into the kernel. If the interpreter is
203 * the shell, return (effectively ignoring the "#!"). If the execution
204 * of the interpreter fails, exit.
205 *
206 * This code peeks inside the input buffer in order to avoid actually
207 * reading any input. It would benefit from a rewrite.
208 */
209
210 #define NEWARGS 5
211
212 STATIC void
213 execinterp(char **argv, char **envp)
214 {
215 int n;
216 char *inp;
217 char *outp;
218 char c;
219 char *p;
220 char **ap;
221 char *newargs[NEWARGS];
222 int i;
223 char **ap2;
224 char **new;
225
226 n = parsenleft - 2;
227 inp = parsenextc + 2;
228 ap = newargs;
229 for (;;) {
230 while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
231 inp++;
232 if (n < 0)
233 goto bad;
234 if ((c = *inp++) == '\n')
235 break;
236 if (ap == &newargs[NEWARGS])
237 bad: error("Bad #! line");
238 STARTSTACKSTR(outp);
239 do {
240 STPUTC(c, outp);
241 } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
242 STPUTC('\0', outp);
243 n++, inp--;
244 *ap++ = grabstackstr(outp);
245 }
246 if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
247 p = newargs[0];
248 for (;;) {
249 if (equal(p, "sh") || equal(p, "ash")) {
250 return;
251 }
252 while (*p != '/') {
253 if (*p == '\0')
254 goto break2;
255 p++;
256 }
257 p++;
258 }
259 break2:;
260 }
261 i = (char *)ap - (char *)newargs; /* size in bytes */
262 if (i == 0)
263 error("Bad #! line");
264 for (ap2 = argv ; *ap2++ != NULL ; );
265 new = ckmalloc(i + ((char *)ap2 - (char *)argv));
266 ap = newargs, ap2 = new;
267 while ((i -= sizeof (char **)) >= 0)
268 *ap2++ = *ap++;
269 ap = argv;
270 while (*ap2++ = *ap++);
271 shellexec(new, envp, pathval(), 0);
272 /* NOTREACHED */
273 }
274 #endif
275
276
277
278 /*
279 * Do a path search. The variable path (passed by reference) should be
280 * set to the start of the path before the first call; padvance will update
281 * this value as it proceeds. Successive calls to padvance will return
282 * the possible path expansions in sequence. If an option (indicated by
283 * a percent sign) appears in the path entry then the global variable
284 * pathopt will be set to point to it; otherwise pathopt will be set to
285 * NULL.
286 */
287
288 const char *pathopt;
289
290 char *
291 padvance(const char **path, const char *name)
292 {
293 const char *p;
294 char *q;
295 const char *start;
296 int len;
297
298 if (*path == NULL)
299 return NULL;
300 start = *path;
301 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
302 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
303 while (stackblocksize() < len)
304 growstackblock();
305 q = stackblock();
306 if (p != start) {
307 memcpy(q, start, p - start);
308 q += p - start;
309 *q++ = '/';
310 }
311 strcpy(q, name);
312 pathopt = NULL;
313 if (*p == '%') {
314 pathopt = ++p;
315 while (*p && *p != ':') p++;
316 }
317 if (*p == ':')
318 *path = p + 1;
319 else
320 *path = NULL;
321 return stalloc(len);
322 }
323
324
325
326 /*** Command hashing code ***/
327
328
329 int
330 hashcmd(int argc, char **argv)
331 {
332 struct tblentry **pp;
333 struct tblentry *cmdp;
334 int c;
335 int verbose;
336 struct cmdentry entry;
337 char *name;
338
339 verbose = 0;
340 while ((c = nextopt("rv")) != '\0') {
341 if (c == 'r') {
342 clearcmdentry(0);
343 } else if (c == 'v') {
344 verbose++;
345 }
346 }
347 if (*argptr == NULL) {
348 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
349 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
350 if (verbose || cmdp->cmdtype == CMDNORMAL)
351 printentry(cmdp, verbose);
352 }
353 }
354 return 0;
355 }
356 while ((name = *argptr) != NULL) {
357 if ((cmdp = cmdlookup(name, 0)) != NULL
358 && (cmdp->cmdtype == CMDNORMAL
359 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
360 delete_cmd_entry();
361 find_command(name, &entry, DO_ERR, pathval());
362 if (verbose) {
363 if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
364 cmdp = cmdlookup(name, 0);
365 printentry(cmdp, verbose);
366 }
367 flushall();
368 }
369 argptr++;
370 }
371 return 0;
372 }
373
374
375 STATIC void
376 printentry(struct tblentry *cmdp, int verbose)
377 {
378 int idx;
379 const char *path;
380 char *name;
381
382 switch (cmdp->cmdtype) {
383 case CMDNORMAL:
384 idx = cmdp->param.index;
385 path = pathval();
386 do {
387 name = padvance(&path, cmdp->cmdname);
388 stunalloc(name);
389 } while (--idx >= 0);
390 out1str(name);
391 break;
392 case CMDSPLBLTIN:
393 out1fmt("special builtin %s", cmdp->cmdname);
394 break;
395 case CMDBUILTIN:
396 out1fmt("builtin %s", cmdp->cmdname);
397 break;
398 case CMDFUNCTION:
399 out1fmt("function %s", cmdp->cmdname);
400 if (verbose) {
401 struct procstat ps;
402 INTOFF;
403 commandtext(&ps, cmdp->param.func);
404 INTON;
405 out1str("() { ");
406 out1str(ps.cmd);
407 out1str("; }");
408 }
409 break;
410 default:
411 error("internal error: %s cmdtype %d", cmdp->cmdname, cmdp->cmdtype);
412 }
413 if (cmdp->rehash)
414 out1c('*');
415 out1c('\n');
416 }
417
418
419
420 /*
421 * Resolve a command name. If you change this routine, you may have to
422 * change the shellexec routine as well.
423 */
424
425 void
426 find_command(char *name, struct cmdentry *entry, int act, const char *path)
427 {
428 struct tblentry *cmdp, loc_cmd;
429 int idx;
430 int prev;
431 char *fullname;
432 struct stat statb;
433 int e;
434 int (*bltin)(int,char **);
435
436 /* If name contains a slash, don't use PATH or hash table */
437 if (strchr(name, '/') != NULL) {
438 if (act & DO_ABS) {
439 while (stat(name, &statb) < 0) {
440 #ifdef SYSV
441 if (errno == EINTR)
442 continue;
443 #endif
444 if (errno != ENOENT && errno != ENOTDIR)
445 e = errno;
446 entry->cmdtype = CMDUNKNOWN;
447 entry->u.index = -1;
448 return;
449 }
450 entry->cmdtype = CMDNORMAL;
451 entry->u.index = -1;
452 return;
453 }
454 entry->cmdtype = CMDNORMAL;
455 entry->u.index = 0;
456 return;
457 }
458
459 if (path != pathval())
460 act |= DO_ALTPATH;
461
462 if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL)
463 act |= DO_ALTBLTIN;
464
465 /* If name is in the table, check answer will be ok */
466 if ((cmdp = cmdlookup(name, 0)) != NULL) {
467 do {
468 switch (cmdp->cmdtype) {
469 case CMDNORMAL:
470 if (act & DO_ALTPATH) {
471 cmdp = NULL;
472 continue;
473 }
474 break;
475 case CMDFUNCTION:
476 if (act & DO_NOFUNC) {
477 cmdp = NULL;
478 continue;
479 }
480 break;
481 case CMDBUILTIN:
482 if ((act & DO_ALTBLTIN) || builtinloc >= 0) {
483 cmdp = NULL;
484 continue;
485 }
486 break;
487 }
488 /* if not invalidated by cd, we're done */
489 if (cmdp->rehash == 0)
490 goto success;
491 } while (0);
492 }
493
494 /* If %builtin not in path, check for builtin next */
495 if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc < 0) &&
496 (bltin = find_builtin(name)) != 0)
497 goto builtin_success;
498
499 /* We have to search path. */
500 prev = -1; /* where to start */
501 if (cmdp) { /* doing a rehash */
502 if (cmdp->cmdtype == CMDBUILTIN)
503 prev = builtinloc;
504 else
505 prev = cmdp->param.index;
506 }
507
508 e = ENOENT;
509 idx = -1;
510 loop:
511 while ((fullname = padvance(&path, name)) != NULL) {
512 stunalloc(fullname);
513 idx++;
514 if (pathopt) {
515 if (prefix("builtin", pathopt)) {
516 if ((bltin = find_builtin(name)) == 0)
517 goto loop;
518 goto builtin_success;
519 } else if (prefix("func", pathopt)) {
520 /* handled below */
521 } else {
522 /* ignore unimplemented options */
523 goto loop;
524 }
525 }
526 /* if rehash, don't redo absolute path names */
527 if (fullname[0] == '/' && idx <= prev) {
528 if (idx < prev)
529 goto loop;
530 TRACE(("searchexec \"%s\": no change\n", name));
531 goto success;
532 }
533 while (stat(fullname, &statb) < 0) {
534 #ifdef SYSV
535 if (errno == EINTR)
536 continue;
537 #endif
538 if (errno != ENOENT && errno != ENOTDIR)
539 e = errno;
540 goto loop;
541 }
542 e = EACCES; /* if we fail, this will be the error */
543 if (!S_ISREG(statb.st_mode))
544 goto loop;
545 if (pathopt) { /* this is a %func directory */
546 if (act & DO_NOFUNC)
547 goto loop;
548 stalloc(strlen(fullname) + 1);
549 readcmdfile(fullname);
550 if ((cmdp = cmdlookup(name, 0)) == NULL ||
551 cmdp->cmdtype != CMDFUNCTION)
552 error("%s not defined in %s", name, fullname);
553 stunalloc(fullname);
554 goto success;
555 }
556 #ifdef notdef
557 /* XXX this code stops root executing stuff, and is buggy
558 if you need a group from the group list. */
559 if (statb.st_uid == geteuid()) {
560 if ((statb.st_mode & 0100) == 0)
561 goto loop;
562 } else if (statb.st_gid == getegid()) {
563 if ((statb.st_mode & 010) == 0)
564 goto loop;
565 } else {
566 if ((statb.st_mode & 01) == 0)
567 goto loop;
568 }
569 #endif
570 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
571 INTOFF;
572 if (act & DO_ALTPATH) {
573 stalloc(strlen(fullname) + 1);
574 cmdp = &loc_cmd;
575 } else
576 cmdp = cmdlookup(name, 1);
577 cmdp->cmdtype = CMDNORMAL;
578 cmdp->param.index = idx;
579 INTON;
580 goto success;
581 }
582
583 /* We failed. If there was an entry for this command, delete it */
584 if (cmdp)
585 delete_cmd_entry();
586 if (act & DO_ERR)
587 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
588 entry->cmdtype = CMDUNKNOWN;
589 return;
590
591 builtin_success:
592 INTOFF;
593 if (act & DO_ALTPATH)
594 cmdp = &loc_cmd;
595 else
596 cmdp = cmdlookup(name, 1);
597 if (cmdp->cmdtype == CMDFUNCTION)
598 /* DO_NOFUNC must have been set */
599 cmdp = &loc_cmd;
600 cmdp->cmdtype = CMDBUILTIN;
601 cmdp->param.bltin = bltin;
602 INTON;
603 success:
604 cmdp->rehash = 0;
605 entry->cmdtype = cmdp->cmdtype;
606 entry->u = cmdp->param;
607 }
608
609
610
611 /*
612 * Search the table of builtin commands.
613 */
614
615 int
616 (*find_builtin(name))(int, char **)
617 char *name;
618 {
619 const struct builtincmd *bp;
620
621 for (bp = builtincmd ; bp->name ; bp++) {
622 if (*bp->name == *name && equal(bp->name, name))
623 return bp->builtin;
624 }
625 return 0;
626 }
627
628 int
629 (*find_splbltin(name))(int, char **)
630 char *name;
631 {
632 const struct builtincmd *bp;
633
634 for (bp = splbltincmd ; bp->name ; bp++) {
635 if (*bp->name == *name && equal(bp->name, name))
636 return bp->builtin;
637 }
638 return 0;
639 }
640
641 /*
642 * At shell startup put special builtins into hash table.
643 * ensures they are executed first (see posix).
644 * We stop functions being added with the same name
645 * (as they are impossible to call)
646 */
647
648 void
649 hash_special_builtins(void)
650 {
651 const struct builtincmd *bp;
652 struct tblentry *cmdp;
653
654 for (bp = splbltincmd ; bp->name ; bp++) {
655 cmdp = cmdlookup(bp->name, 1);
656 cmdp->cmdtype = CMDSPLBLTIN;
657 cmdp->param.bltin = bp->builtin;
658 }
659 }
660
661
662
663 /*
664 * Called when a cd is done. Marks all commands so the next time they
665 * are executed they will be rehashed.
666 */
667
668 void
669 hashcd(void)
670 {
671 struct tblentry **pp;
672 struct tblentry *cmdp;
673
674 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
675 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
676 if (cmdp->cmdtype == CMDNORMAL
677 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
678 cmdp->rehash = 1;
679 }
680 }
681 }
682
683
684
685 /*
686 * Fix command hash table when PATH changed.
687 * Called before PATH is changed. The argument is the new value of PATH;
688 * pathval() still returns the old value at this point.
689 * Called with interrupts off.
690 */
691
692 void
693 changepath(const char *newval)
694 {
695 const char *old, *new;
696 int idx;
697 int firstchange;
698 int bltin;
699
700 old = pathval();
701 new = newval;
702 firstchange = 9999; /* assume no change */
703 idx = 0;
704 bltin = -1;
705 for (;;) {
706 if (*old != *new) {
707 firstchange = idx;
708 if ((*old == '\0' && *new == ':')
709 || (*old == ':' && *new == '\0'))
710 firstchange++;
711 old = new; /* ignore subsequent differences */
712 }
713 if (*new == '\0')
714 break;
715 if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
716 bltin = idx;
717 if (*new == ':') {
718 idx++;
719 }
720 new++, old++;
721 }
722 if (builtinloc < 0 && bltin >= 0)
723 builtinloc = bltin; /* zap builtins */
724 if (builtinloc >= 0 && bltin < 0)
725 firstchange = 0;
726 clearcmdentry(firstchange);
727 builtinloc = bltin;
728 }
729
730
731 /*
732 * Clear out command entries. The argument specifies the first entry in
733 * PATH which has changed.
734 */
735
736 STATIC void
737 clearcmdentry(int firstchange)
738 {
739 struct tblentry **tblp;
740 struct tblentry **pp;
741 struct tblentry *cmdp;
742
743 INTOFF;
744 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
745 pp = tblp;
746 while ((cmdp = *pp) != NULL) {
747 if ((cmdp->cmdtype == CMDNORMAL &&
748 cmdp->param.index >= firstchange)
749 || (cmdp->cmdtype == CMDBUILTIN &&
750 builtinloc >= firstchange)) {
751 *pp = cmdp->next;
752 ckfree(cmdp);
753 } else {
754 pp = &cmdp->next;
755 }
756 }
757 }
758 INTON;
759 }
760
761
762 /*
763 * Delete all functions.
764 */
765
766 #ifdef mkinit
767 MKINIT void deletefuncs(void);
768 MKINIT void hash_special_builtins(void);
769
770 INIT {
771 hash_special_builtins();
772 }
773
774 SHELLPROC {
775 deletefuncs();
776 }
777 #endif
778
779 void
780 deletefuncs(void)
781 {
782 struct tblentry **tblp;
783 struct tblentry **pp;
784 struct tblentry *cmdp;
785
786 INTOFF;
787 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
788 pp = tblp;
789 while ((cmdp = *pp) != NULL) {
790 if (cmdp->cmdtype == CMDFUNCTION) {
791 *pp = cmdp->next;
792 freefunc(cmdp->param.func);
793 ckfree(cmdp);
794 } else {
795 pp = &cmdp->next;
796 }
797 }
798 }
799 INTON;
800 }
801
802
803
804 /*
805 * Locate a command in the command hash table. If "add" is nonzero,
806 * add the command to the table if it is not already present. The
807 * variable "lastcmdentry" is set to point to the address of the link
808 * pointing to the entry, so that delete_cmd_entry can delete the
809 * entry.
810 */
811
812 struct tblentry **lastcmdentry;
813
814
815 STATIC struct tblentry *
816 cmdlookup(const char *name, int add)
817 {
818 int hashval;
819 const char *p;
820 struct tblentry *cmdp;
821 struct tblentry **pp;
822
823 p = name;
824 hashval = *p << 4;
825 while (*p)
826 hashval += *p++;
827 hashval &= 0x7FFF;
828 pp = &cmdtable[hashval % CMDTABLESIZE];
829 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
830 if (equal(cmdp->cmdname, name))
831 break;
832 pp = &cmdp->next;
833 }
834 if (add && cmdp == NULL) {
835 INTOFF;
836 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
837 + strlen(name) + 1);
838 cmdp->next = NULL;
839 cmdp->cmdtype = CMDUNKNOWN;
840 cmdp->rehash = 0;
841 strcpy(cmdp->cmdname, name);
842 INTON;
843 }
844 lastcmdentry = pp;
845 return cmdp;
846 }
847
848 /*
849 * Delete the command entry returned on the last lookup.
850 */
851
852 STATIC void
853 delete_cmd_entry(void)
854 {
855 struct tblentry *cmdp;
856
857 INTOFF;
858 cmdp = *lastcmdentry;
859 *lastcmdentry = cmdp->next;
860 ckfree(cmdp);
861 INTON;
862 }
863
864
865
866 #ifdef notdef
867 void
868 getcmdentry(char *name, struct cmdentry *entry)
869 {
870 struct tblentry *cmdp = cmdlookup(name, 0);
871
872 if (cmdp) {
873 entry->u = cmdp->param;
874 entry->cmdtype = cmdp->cmdtype;
875 } else {
876 entry->cmdtype = CMDUNKNOWN;
877 entry->u.index = 0;
878 }
879 }
880 #endif
881
882
883 /*
884 * Add a new command entry, replacing any existing command entry for
885 * the same name - except special builtins.
886 */
887
888 STATIC void
889 addcmdentry(char *name, struct cmdentry *entry)
890 {
891 struct tblentry *cmdp;
892
893 INTOFF;
894 cmdp = cmdlookup(name, 1);
895 if (cmdp->cmdtype != CMDSPLBLTIN) {
896 if (cmdp->cmdtype == CMDFUNCTION) {
897 freefunc(cmdp->param.func);
898 }
899 cmdp->cmdtype = entry->cmdtype;
900 cmdp->param = entry->u;
901 }
902 INTON;
903 }
904
905
906 /*
907 * Define a shell function.
908 */
909
910 void
911 defun(char *name, union node *func)
912 {
913 struct cmdentry entry;
914
915 INTOFF;
916 entry.cmdtype = CMDFUNCTION;
917 entry.u.func = copyfunc(func);
918 addcmdentry(name, &entry);
919 INTON;
920 }
921
922
923 /*
924 * Delete a function if it exists.
925 */
926
927 int
928 unsetfunc(char *name)
929 {
930 struct tblentry *cmdp;
931
932 if ((cmdp = cmdlookup(name, 0)) != NULL &&
933 cmdp->cmdtype == CMDFUNCTION) {
934 freefunc(cmdp->param.func);
935 delete_cmd_entry();
936 return (0);
937 }
938 return (1);
939 }
940
941 /*
942 * Locate and print what a word is...
943 * also used for 'command -[v|V]'
944 */
945
946 int
947 typecmd(int argc, char **argv)
948 {
949 struct cmdentry entry;
950 struct tblentry *cmdp;
951 char * const *pp;
952 struct alias *ap;
953 int err = 0;
954 char *arg;
955 int c;
956 int V_flag = 0;
957 int v_flag = 0;
958 int p_flag = 0;
959
960 while ((c = nextopt("vVp")) != 0) {
961 switch (c) {
962 case 'v': v_flag = 1; break;
963 case 'V': V_flag = 1; break;
964 case 'p': p_flag = 1; break;
965 }
966 }
967
968 if (p_flag && (v_flag || V_flag))
969 error("cannot specify -p with -v or -V");
970
971 while ((arg = *argptr++)) {
972 if (!v_flag)
973 out1str(arg);
974 /* First look at the keywords */
975 for (pp = parsekwd; *pp; pp++)
976 if (**pp == *arg && equal(*pp, arg))
977 break;
978
979 if (*pp) {
980 if (v_flag)
981 err = 1;
982 else
983 out1str(" is a shell keyword\n");
984 continue;
985 }
986
987 /* Then look at the aliases */
988 if ((ap = lookupalias(arg, 1)) != NULL) {
989 if (!v_flag)
990 out1fmt(" is an alias for \n");
991 out1fmt("%s\n", ap->val);
992 continue;
993 }
994
995 /* Then check if it is a tracked alias */
996 if ((cmdp = cmdlookup(arg, 0)) != NULL) {
997 entry.cmdtype = cmdp->cmdtype;
998 entry.u = cmdp->param;
999 } else {
1000 /* Finally use brute force */
1001 find_command(arg, &entry, DO_ABS, pathval());
1002 }
1003
1004 switch (entry.cmdtype) {
1005 case CMDNORMAL: {
1006 if (strchr(arg, '/') == NULL) {
1007 const char *path = pathval();
1008 char *name;
1009 int j = entry.u.index;
1010 do {
1011 name = padvance(&path, arg);
1012 stunalloc(name);
1013 } while (--j >= 0);
1014 if (!v_flag)
1015 out1fmt(" is%s ",
1016 cmdp ? " a tracked alias for" : "");
1017 out1fmt("%s\n", name);
1018 } else {
1019 if (access(arg, X_OK) == 0) {
1020 if (!v_flag)
1021 out1fmt(" is ");
1022 out1fmt("%s\n", arg);
1023 } else {
1024 if (!v_flag)
1025 out1fmt(": %s\n",
1026 strerror(errno));
1027 else
1028 err = 126;
1029 }
1030 }
1031 break;
1032 }
1033 case CMDFUNCTION:
1034 if (!v_flag)
1035 out1str(" is a shell function\n");
1036 else
1037 out1fmt("%s\n", arg);
1038 break;
1039
1040 case CMDBUILTIN:
1041 if (!v_flag)
1042 out1str(" is a shell builtin\n");
1043 else
1044 out1fmt("%s\n", arg);
1045 break;
1046
1047 case CMDSPLBLTIN:
1048 if (!v_flag)
1049 out1str(" is a special shell builtin\n");
1050 else
1051 out1fmt("%s\n", arg);
1052 break;
1053
1054 default:
1055 if (!v_flag)
1056 out1str(": not found\n");
1057 err = 127;
1058 break;
1059 }
1060 }
1061 return err;
1062 }
+0
-79
sh/exec.h less more
0 /* $NetBSD: exec.h,v 1.21 2003/08/07 09:05:31 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)exec.h 8.3 (Berkeley) 6/8/95
34 */
35
36 /* values of cmdtype */
37 #define CMDUNKNOWN -1 /* no entry in table for command */
38 #define CMDNORMAL 0 /* command is an executable program */
39 #define CMDFUNCTION 1 /* command is a shell function */
40 #define CMDBUILTIN 2 /* command is a shell builtin */
41 #define CMDSPLBLTIN 3 /* command is a special shell builtin */
42
43
44 struct cmdentry {
45 int cmdtype;
46 union param {
47 int index;
48 int (*bltin)(int, char**);
49 union node *func;
50 } u;
51 };
52
53
54 /* action to find_command() */
55 #define DO_ERR 0x01 /* prints errors */
56 #define DO_ABS 0x02 /* checks absolute paths */
57 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
58 #define DO_ALTPATH 0x08 /* using alternate path */
59 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
60
61 extern const char *pathopt; /* set by padvance */
62
63 void shellexec(char **, char **, const char *, int, int)
64 __attribute__((__noreturn__));
65 char *padvance(const char **, const char *);
66 int hashcmd(int, char **);
67 void find_command(char *, struct cmdentry *, int, const char *);
68 int (*find_builtin(char *))(int, char **);
69 int (*find_splbltin(char *))(int, char **);
70 void hashcd(void);
71 void changepath(const char *);
72 void deletefuncs(void);
73 void getcmdentry(char *, struct cmdentry *);
74 void addcmdentry(char *, struct cmdentry *);
75 void defun(char *, union node *);
76 int unsetfunc(char *);
77 int typecmd(int, char **);
78 void hash_special_builtins(void);
+0
-1559
sh/expand.c less more
0 /* $NetBSD: expand.c,v 1.68.2.2 2005/04/07 11:37:39 tron Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
38 #else
39 __RCSID("$NetBSD: expand.c,v 1.68.2.2 2005/04/07 11:37:39 tron Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <dirent.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51
52 /*
53 * Routines to expand arguments to commands. We have to deal with
54 * backquotes, shell variables, and file metacharacters.
55 */
56
57 #include "shell.h"
58 #include "main.h"
59 #include "nodes.h"
60 #include "eval.h"
61 #include "expand.h"
62 #include "syntax.h"
63 #include "parser.h"
64 #include "jobs.h"
65 #include "options.h"
66 #include "var.h"
67 #include "input.h"
68 #include "output.h"
69 #include "memalloc.h"
70 #include "error.h"
71 #include "mystring.h"
72 #include "show.h"
73
74 /*
75 * Structure specifying which parts of the string should be searched
76 * for IFS characters.
77 */
78
79 struct ifsregion {
80 struct ifsregion *next; /* next region in list */
81 int begoff; /* offset of start of region */
82 int endoff; /* offset of end of region */
83 int inquotes; /* search for nul bytes only */
84 };
85
86
87 char *expdest; /* output of current string */
88 struct nodelist *argbackq; /* list of back quote expressions */
89 struct ifsregion ifsfirst; /* first struct in list of ifs regions */
90 struct ifsregion *ifslastp; /* last struct in list */
91 struct arglist exparg; /* holds expanded arg list */
92
93 STATIC void argstr(char *, int);
94 STATIC char *exptilde(char *, int);
95 STATIC void expbackq(union node *, int, int);
96 STATIC int subevalvar(char *, char *, int, int, int, int);
97 STATIC char *evalvar(char *, int);
98 STATIC int varisset(char *, int);
99 STATIC void varvalue(char *, int, int, int);
100 STATIC void recordregion(int, int, int);
101 STATIC void removerecordregions(int);
102 STATIC void ifsbreakup(char *, struct arglist *);
103 STATIC void ifsfree(void);
104 STATIC void expandmeta(struct strlist *, int);
105 STATIC void expmeta(char *, char *);
106 STATIC void addfname(char *);
107 STATIC struct strlist *expsort(struct strlist *);
108 STATIC struct strlist *msort(struct strlist *, int);
109 STATIC int pmatch(char *, char *, int);
110 STATIC char *cvtnum(int, char *);
111
112 /*
113 * Expand shell variables and backquotes inside a here document.
114 */
115
116 void
117 expandhere(union node *arg, int fd)
118 {
119 herefd = fd;
120 expandarg(arg, (struct arglist *)NULL, 0);
121 xwrite(fd, stackblock(), expdest - stackblock());
122 }
123
124
125 /*
126 * Perform variable substitution and command substitution on an argument,
127 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
128 * perform splitting and file name expansion. When arglist is NULL, perform
129 * here document expansion.
130 */
131
132 void
133 expandarg(union node *arg, struct arglist *arglist, int flag)
134 {
135 struct strlist *sp;
136 char *p;
137
138 argbackq = arg->narg.backquote;
139 STARTSTACKSTR(expdest);
140 ifsfirst.next = NULL;
141 ifslastp = NULL;
142 argstr(arg->narg.text, flag);
143 if (arglist == NULL) {
144 return; /* here document expanded */
145 }
146 STPUTC('\0', expdest);
147 p = grabstackstr(expdest);
148 exparg.lastp = &exparg.list;
149 /*
150 * TODO - EXP_REDIR
151 */
152 if (flag & EXP_FULL) {
153 ifsbreakup(p, &exparg);
154 *exparg.lastp = NULL;
155 exparg.lastp = &exparg.list;
156 expandmeta(exparg.list, flag);
157 } else {
158 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
159 rmescapes(p);
160 sp = (struct strlist *)stalloc(sizeof (struct strlist));
161 sp->text = p;
162 *exparg.lastp = sp;
163 exparg.lastp = &sp->next;
164 }
165 ifsfree();
166 *exparg.lastp = NULL;
167 if (exparg.list) {
168 *arglist->lastp = exparg.list;
169 arglist->lastp = exparg.lastp;
170 }
171 }
172
173
174
175 /*
176 * Perform variable and command substitution.
177 * If EXP_FULL is set, output CTLESC characters to allow for further processing.
178 * Otherwise treat $@ like $* since no splitting will be performed.
179 */
180
181 STATIC void
182 argstr(char *p, int flag)
183 {
184 char c;
185 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
186 int firsteq = 1;
187 const char *ifs = 0;
188 int ifs_split = EXP_IFS_SPLIT;
189
190 if (flag & EXP_IFS_SPLIT)
191 ifs = ifsset() ? ifsval() : " \t\n";
192
193 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
194 p = exptilde(p, flag);
195 for (;;) {
196 switch (c = *p++) {
197 case '\0':
198 case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */
199 return;
200 case CTLQUOTEMARK:
201 /* "$@" syntax adherence hack */
202 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
203 break;
204 if ((flag & EXP_FULL) != 0)
205 STPUTC(c, expdest);
206 ifs_split = 0;
207 break;
208 case CTLQUOTEEND:
209 ifs_split = EXP_IFS_SPLIT;
210 break;
211 case CTLESC:
212 if (quotes)
213 STPUTC(c, expdest);
214 c = *p++;
215 STPUTC(c, expdest);
216 break;
217 case CTLVAR:
218 p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
219 break;
220 case CTLBACKQ:
221 case CTLBACKQ|CTLQUOTE:
222 expbackq(argbackq->n, c & CTLQUOTE, flag);
223 argbackq = argbackq->next;
224 break;
225 case CTLENDARI:
226 expari(flag);
227 break;
228 case ':':
229 case '=':
230 /*
231 * sort of a hack - expand tildes in variable
232 * assignments (after the first '=' and after ':'s).
233 */
234 STPUTC(c, expdest);
235 if (flag & EXP_VARTILDE && *p == '~') {
236 if (c == '=') {
237 if (firsteq)
238 firsteq = 0;
239 else
240 break;
241 }
242 p = exptilde(p, flag);
243 }
244 break;
245 default:
246 STPUTC(c, expdest);
247 if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) {
248 /* We need to get the output split here... */
249 recordregion(expdest - stackblock() - 1,
250 expdest - stackblock(), 0);
251 }
252 break;
253 }
254 }
255 }
256
257 STATIC char *
258 exptilde(char *p, int flag)
259 {
260 char c, *startp = p;
261 const char *home;
262 int quotes = flag & (EXP_FULL | EXP_CASE);
263
264 while ((c = *p) != '\0') {
265 switch(c) {
266 case CTLESC:
267 return (startp);
268 case CTLQUOTEMARK:
269 return (startp);
270 case ':':
271 if (flag & EXP_VARTILDE)
272 goto done;
273 break;
274 case '/':
275 goto done;
276 }
277 p++;
278 }
279 done:
280 *p = '\0';
281 if (*(startp+1) == '\0') {
282 if ((home = lookupvar("HOME")) == NULL)
283 goto lose;
284 } else
285 goto lose;
286 if (*home == '\0')
287 goto lose;
288 *p = c;
289 while ((c = *home++) != '\0') {
290 if (quotes && SQSYNTAX[(int)c] == CCTL)
291 STPUTC(CTLESC, expdest);
292 STPUTC(c, expdest);
293 }
294 return (p);
295 lose:
296 *p = c;
297 return (startp);
298 }
299
300
301 STATIC void
302 removerecordregions(int endoff)
303 {
304 if (ifslastp == NULL)
305 return;
306
307 if (ifsfirst.endoff > endoff) {
308 while (ifsfirst.next != NULL) {
309 struct ifsregion *ifsp;
310 INTOFF;
311 ifsp = ifsfirst.next->next;
312 ckfree(ifsfirst.next);
313 ifsfirst.next = ifsp;
314 INTON;
315 }
316 if (ifsfirst.begoff > endoff)
317 ifslastp = NULL;
318 else {
319 ifslastp = &ifsfirst;
320 ifsfirst.endoff = endoff;
321 }
322 return;
323 }
324
325 ifslastp = &ifsfirst;
326 while (ifslastp->next && ifslastp->next->begoff < endoff)
327 ifslastp=ifslastp->next;
328 while (ifslastp->next != NULL) {
329 struct ifsregion *ifsp;
330 INTOFF;
331 ifsp = ifslastp->next->next;
332 ckfree(ifslastp->next);
333 ifslastp->next = ifsp;
334 INTON;
335 }
336 if (ifslastp->endoff > endoff)
337 ifslastp->endoff = endoff;
338 }
339
340
341 /*
342 * Expand arithmetic expression. Backup to start of expression,
343 * evaluate, place result in (backed up) result, adjust string position.
344 */
345 void
346 expari(int flag)
347 {
348 char *p, *start;
349 int result;
350 int begoff;
351 int quotes = flag & (EXP_FULL | EXP_CASE);
352 int quoted;
353
354 /* ifsfree(); */
355
356 /*
357 * This routine is slightly over-complicated for
358 * efficiency. First we make sure there is
359 * enough space for the result, which may be bigger
360 * than the expression if we add exponentation. Next we
361 * scan backwards looking for the start of arithmetic. If the
362 * next previous character is a CTLESC character, then we
363 * have to rescan starting from the beginning since CTLESC
364 * characters have to be processed left to right.
365 */
366 #if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
367 #error "integers with more than 10 digits are not supported"
368 #endif
369 CHECKSTRSPACE(12 - 2, expdest);
370 USTPUTC('\0', expdest);
371 start = stackblock();
372 p = expdest - 1;
373 while (*p != CTLARI && p >= start)
374 --p;
375 if (*p != CTLARI)
376 error("missing CTLARI (shouldn't happen)");
377 if (p > start && *(p-1) == CTLESC)
378 for (p = start; *p != CTLARI; p++)
379 if (*p == CTLESC)
380 p++;
381
382 if (p[1] == '"')
383 quoted=1;
384 else
385 quoted=0;
386 begoff = p - start;
387 removerecordregions(begoff);
388 if (quotes)
389 rmescapes(p+2);
390 result = arith(p+2);
391 fmtstr(p, 12, "%d", result);
392
393 while (*p++)
394 ;
395
396 if (quoted == 0)
397 recordregion(begoff, p - 1 - start, 0);
398 result = expdest - p + 1;
399 STADJUST(-result, expdest);
400 }
401
402
403 /*
404 * Expand stuff in backwards quotes.
405 */
406
407 STATIC void
408 expbackq(union node *cmd, int quoted, int flag)
409 {
410 struct backcmd in;
411 int i;
412 char buf[128];
413 char *p;
414 char *dest = expdest;
415 struct ifsregion saveifs, *savelastp;
416 struct nodelist *saveargbackq;
417 char lastc;
418 int startloc = dest - stackblock();
419 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
420 int saveherefd;
421 int quotes = flag & (EXP_FULL | EXP_CASE);
422
423 INTOFF;
424 saveifs = ifsfirst;
425 savelastp = ifslastp;
426 saveargbackq = argbackq;
427 saveherefd = herefd;
428 herefd = -1;
429 p = grabstackstr(dest);
430 evalbackcmd(cmd, &in);
431 ungrabstackstr(p, dest);
432 ifsfirst = saveifs;
433 ifslastp = savelastp;
434 argbackq = saveargbackq;
435 herefd = saveherefd;
436
437 p = in.buf;
438 lastc = '\0';
439 for (;;) {
440 if (--in.nleft < 0) {
441 if (in.fd < 0)
442 break;
443 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
444 TRACE(("expbackq: read returns %d\n", i));
445 if (i <= 0)
446 break;
447 p = buf;
448 in.nleft = i - 1;
449 }
450 lastc = *p++;
451 if (lastc != '\0') {
452 if (quotes && syntax[(int)lastc] == CCTL)
453 STPUTC(CTLESC, dest);
454 STPUTC(lastc, dest);
455 }
456 }
457
458 /* Eat all trailing newlines */
459 p = stackblock() + startloc;
460 while (dest > p && dest[-1] == '\n')
461 STUNPUTC(dest);
462
463 if (in.fd >= 0)
464 close(in.fd);
465 if (in.buf)
466 ckfree(in.buf);
467 if (in.jp)
468 back_exitstatus = waitforjob(in.jp);
469 if (quoted == 0)
470 recordregion(startloc, dest - stackblock(), 0);
471 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
472 (dest - stackblock()) - startloc,
473 (dest - stackblock()) - startloc,
474 stackblock() + startloc));
475 expdest = dest;
476 INTON;
477 }
478
479
480
481 STATIC int
482 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags)
483 {
484 char *startp;
485 char *loc = NULL;
486 char *q;
487 int c = 0;
488 int saveherefd = herefd;
489 struct nodelist *saveargbackq = argbackq;
490 int amount;
491
492 herefd = -1;
493 argstr(p, 0);
494 STACKSTRNUL(expdest);
495 herefd = saveherefd;
496 argbackq = saveargbackq;
497 startp = stackblock() + startloc;
498 if (str == NULL)
499 str = stackblock() + strloc;
500
501 switch (subtype) {
502 case VSASSIGN:
503 setvar(str, startp, 0);
504 amount = startp - expdest;
505 STADJUST(amount, expdest);
506 varflags &= ~VSNUL;
507 if (c != 0)
508 *loc = c;
509 return 1;
510
511 case VSQUESTION:
512 if (*p != CTLENDVAR) {
513 outfmt(&errout, "%s\n", startp);
514 error((char *)NULL);
515 }
516 error("%.*s: parameter %snot set", p - str - 1,
517 str, (varflags & VSNUL) ? "null or "
518 : nullstr);
519 /* NOTREACHED */
520
521 case VSTRIMLEFT:
522 for (loc = startp; loc < str; loc++) {
523 c = *loc;
524 *loc = '\0';
525 if (patmatch(str, startp, varflags & VSQUOTE))
526 goto recordleft;
527 *loc = c;
528 if ((varflags & VSQUOTE) && *loc == CTLESC)
529 loc++;
530 }
531 return 0;
532
533 case VSTRIMLEFTMAX:
534 for (loc = str - 1; loc >= startp;) {
535 c = *loc;
536 *loc = '\0';
537 if (patmatch(str, startp, varflags & VSQUOTE))
538 goto recordleft;
539 *loc = c;
540 loc--;
541 if ((varflags & VSQUOTE) && loc > startp &&
542 *(loc - 1) == CTLESC) {
543 for (q = startp; q < loc; q++)
544 if (*q == CTLESC)
545 q++;
546 if (q > loc)
547 loc--;
548 }
549 }
550 return 0;
551
552 case VSTRIMRIGHT:
553 for (loc = str - 1; loc >= startp;) {
554 if (patmatch(str, loc, varflags & VSQUOTE))
555 goto recordright;
556 loc--;
557 if ((varflags & VSQUOTE) && loc > startp &&
558 *(loc - 1) == CTLESC) {
559 for (q = startp; q < loc; q++)
560 if (*q == CTLESC)
561 q++;
562 if (q > loc)
563 loc--;
564 }
565 }
566 return 0;
567
568 case VSTRIMRIGHTMAX:
569 for (loc = startp; loc < str - 1; loc++) {
570 if (patmatch(str, loc, varflags & VSQUOTE))
571 goto recordright;
572 if ((varflags & VSQUOTE) && *loc == CTLESC)
573 loc++;
574 }
575 return 0;
576
577 default:
578 abort();
579 }
580
581 recordleft:
582 *loc = c;
583 amount = ((str - 1) - (loc - startp)) - expdest;
584 STADJUST(amount, expdest);
585 while (loc != str - 1)
586 *startp++ = *loc++;
587 return 1;
588
589 recordright:
590 amount = loc - expdest;
591 STADJUST(amount, expdest);
592 STPUTC('\0', expdest);
593 STADJUST(-1, expdest);
594 return 1;
595 }
596
597
598 /*
599 * Expand a variable, and return a pointer to the next character in the
600 * input string.
601 */
602
603 STATIC char *
604 evalvar(char *p, int flag)
605 {
606 int subtype;
607 int varflags;
608 char *var;
609 char *val;
610 int patloc;
611 int c;
612 int set;
613 int special;
614 int startloc;
615 int varlen;
616 int apply_ifs;
617 int quotes = flag & (EXP_FULL | EXP_CASE);
618
619 varflags = (unsigned char)*p++;
620 subtype = varflags & VSTYPE;
621 var = p;
622 special = !is_name(*p);
623 p = strchr(p, '=') + 1;
624
625 again: /* jump here after setting a variable with ${var=text} */
626 if (special) {
627 set = varisset(var, varflags & VSNUL);
628 val = NULL;
629 } else {
630 val = lookupvar(var);
631 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
632 val = NULL;
633 set = 0;
634 } else
635 set = 1;
636 }
637
638 varlen = 0;
639 startloc = expdest - stackblock();
640
641 if (!set && uflag) {
642 switch (subtype) {
643 case VSNORMAL:
644 case VSTRIMLEFT:
645 case VSTRIMLEFTMAX:
646 case VSTRIMRIGHT:
647 case VSTRIMRIGHTMAX:
648 case VSLENGTH:
649 error("%.*s: parameter not set", p - var - 1, var);
650 /* NOTREACHED */
651 }
652 }
653
654 if (set && subtype != VSPLUS) {
655 /* insert the value of the variable */
656 if (special) {
657 varvalue(var, varflags & VSQUOTE, subtype, flag);
658 if (subtype == VSLENGTH) {
659 varlen = expdest - stackblock() - startloc;
660 STADJUST(-varlen, expdest);
661 }
662 } else {
663 char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
664 : BASESYNTAX;
665
666 if (subtype == VSLENGTH) {
667 for (;*val; val++)
668 varlen++;
669 } else {
670 while (*val) {
671 if (quotes && syntax[(int)*val] == CCTL)
672 STPUTC(CTLESC, expdest);
673 STPUTC(*val++, expdest);
674 }
675
676 }
677 }
678 }
679
680
681 apply_ifs = ((varflags & VSQUOTE) == 0 ||
682 (*var == '@' && shellparam.nparam != 1));
683
684 switch (subtype) {
685 case VSLENGTH:
686 expdest = cvtnum(varlen, expdest);
687 break;
688
689 case VSNORMAL:
690 break;
691
692 case VSPLUS:
693 set = !set;
694 /* FALLTHROUGH */
695 case VSMINUS:
696 if (!set) {
697 argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
698 /*
699 * ${x-a b c} doesn't get split, but removing the
700 * 'apply_ifs = 0' apparantly breaks ${1+"$@"}..
701 * ${x-'a b' c} should generate 2 args.
702 */
703 /* We should have marked stuff already */
704 apply_ifs = 0;
705 }
706 break;
707
708 case VSTRIMLEFT:
709 case VSTRIMLEFTMAX:
710 case VSTRIMRIGHT:
711 case VSTRIMRIGHTMAX:
712 if (!set)
713 break;
714 /*
715 * Terminate the string and start recording the pattern
716 * right after it
717 */
718 STPUTC('\0', expdest);
719 patloc = expdest - stackblock();
720 if (subevalvar(p, NULL, patloc, subtype,
721 startloc, varflags) == 0) {
722 int amount = (expdest - stackblock() - patloc) + 1;
723 STADJUST(-amount, expdest);
724 }
725 /* Remove any recorded regions beyond start of variable */
726 removerecordregions(startloc);
727 apply_ifs = 1;
728 break;
729
730 case VSASSIGN:
731 case VSQUESTION:
732 if (set)
733 break;
734 if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
735 varflags &= ~VSNUL;
736 /*
737 * Remove any recorded regions beyond
738 * start of variable
739 */
740 removerecordregions(startloc);
741 goto again;
742 }
743 apply_ifs = 0;
744 break;
745
746 default:
747 abort();
748 }
749
750 if (apply_ifs)
751 recordregion(startloc, expdest - stackblock(),
752 varflags & VSQUOTE);
753
754 if (subtype != VSNORMAL) { /* skip to end of alternative */
755 int nesting = 1;
756 for (;;) {
757 if ((c = *p++) == CTLESC)
758 p++;
759 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
760 if (set)
761 argbackq = argbackq->next;
762 } else if (c == CTLVAR) {
763 if ((*p++ & VSTYPE) != VSNORMAL)
764 nesting++;
765 } else if (c == CTLENDVAR) {
766 if (--nesting == 0)
767 break;
768 }
769 }
770 }
771 return p;
772 }
773
774
775
776 /*
777 * Test whether a specialized variable is set.
778 */
779
780 STATIC int
781 varisset(char *name, int nulok)
782 {
783 if (*name == '!')
784 return backgndpid != -1;
785 else if (*name == '@' || *name == '*') {
786 if (*shellparam.p == NULL)
787 return 0;
788
789 if (nulok) {
790 char **av;
791
792 for (av = shellparam.p; *av; av++)
793 if (**av != '\0')
794 return 1;
795 return 0;
796 }
797 } else if (is_digit(*name)) {
798 char *ap;
799 int num = atoi(name);
800
801 if (num > shellparam.nparam)
802 return 0;
803
804 if (num == 0)
805 ap = arg0;
806 else
807 ap = shellparam.p[num - 1];
808
809 if (nulok && (ap == NULL || *ap == '\0'))
810 return 0;
811 }
812 return 1;
813 }
814
815
816
817 /*
818 * Add the value of a specialized variable to the stack string.
819 */
820
821 STATIC void
822 varvalue(char *name, int quoted, int subtype, int flag)
823 {
824 int num;
825 char *p;
826 int i;
827 char sep;
828 char **ap;
829 char const *syntax;
830
831 #define STRTODEST(p) \
832 do {\
833 if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
834 syntax = quoted? DQSYNTAX : BASESYNTAX; \
835 while (*p) { \
836 if (syntax[(int)*p] == CCTL) \
837 STPUTC(CTLESC, expdest); \
838 STPUTC(*p++, expdest); \
839 } \
840 } else \
841 while (*p) \
842 STPUTC(*p++, expdest); \
843 } while (0)
844
845
846 switch (*name) {
847 case '$':
848 num = rootpid;
849 goto numvar;
850 case '?':
851 num = exitstatus;
852 goto numvar;
853 case '#':
854 num = shellparam.nparam;
855 goto numvar;
856 case '!':
857 num = backgndpid;
858 numvar:
859 expdest = cvtnum(num, expdest);
860 break;
861 case '-':
862 for (i = 0; optlist[i].name; i++) {
863 if (optlist[i].val)
864 STPUTC(optlist[i].letter, expdest);
865 }
866 break;
867 case '@':
868 if (flag & EXP_FULL && quoted) {
869 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
870 STRTODEST(p);
871 if (*ap)
872 STPUTC('\0', expdest);
873 }
874 break;
875 }
876 /* fall through */
877 case '*':
878 if (ifsset() != 0)
879 sep = ifsval()[0];
880 else
881 sep = ' ';
882 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
883 STRTODEST(p);
884 if (*ap && sep)
885 STPUTC(sep, expdest);
886 }
887 break;
888 case '0':
889 p = arg0;
890 STRTODEST(p);
891 break;
892 default:
893 if (is_digit(*name)) {
894 num = atoi(name);
895 if (num > 0 && num <= shellparam.nparam) {
896 p = shellparam.p[num - 1];
897 STRTODEST(p);
898 }
899 }
900 break;
901 }
902 }
903
904
905
906 /*
907 * Record the fact that we have to scan this region of the
908 * string for IFS characters.
909 */
910
911 STATIC void
912 recordregion(int start, int end, int inquotes)
913 {
914 struct ifsregion *ifsp;
915
916 if (ifslastp == NULL) {
917 ifsp = &ifsfirst;
918 } else {
919 if (ifslastp->endoff == start
920 && ifslastp->inquotes == inquotes) {
921 /* extend previous area */
922 ifslastp->endoff = end;
923 return;
924 }
925 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
926 ifslastp->next = ifsp;
927 }
928 ifslastp = ifsp;
929 ifslastp->next = NULL;
930 ifslastp->begoff = start;
931 ifslastp->endoff = end;
932 ifslastp->inquotes = inquotes;
933 }
934
935
936
937 /*
938 * Break the argument string into pieces based upon IFS and add the
939 * strings to the argument list. The regions of the string to be
940 * searched for IFS characters have been stored by recordregion.
941 */
942 STATIC void
943 ifsbreakup(char *string, struct arglist *arglist)
944 {
945 struct ifsregion *ifsp;
946 struct strlist *sp;
947 char *start;
948 char *p;
949 char *q;
950 const char *ifs;
951 const char *ifsspc;
952 int inquotes;
953
954 start = string;
955 ifsspc = NULL;
956 inquotes = 0;
957
958 if (ifslastp == NULL) {
959 /* Return entire argument, IFS doesn't apply to any of it */
960 sp = (struct strlist *)stalloc(sizeof *sp);
961 sp->text = start;
962 *arglist->lastp = sp;
963 arglist->lastp = &sp->next;
964 return;
965 }
966
967 ifs = ifsset() ? ifsval() : " \t\n";
968
969 for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
970 p = string + ifsp->begoff;
971 inquotes = ifsp->inquotes;
972 ifsspc = NULL;
973 while (p < string + ifsp->endoff) {
974 q = p;
975 if (*p == CTLESC)
976 p++;
977 if (inquotes) {
978 /* Only NULs (probably from "$@") end args */
979 if (*p != 0) {
980 p++;
981 continue;
982 }
983 } else {
984 if (!strchr(ifs, *p)) {
985 p++;
986 continue;
987 }
988 ifsspc = strchr(" \t\n", *p);
989
990 /* Ignore IFS whitespace at start */
991 if (q == start && ifsspc != NULL) {
992 p++;
993 start = p;
994 continue;
995 }
996 }
997
998 /* Save this argument... */
999 *q = '\0';
1000 sp = (struct strlist *)stalloc(sizeof *sp);
1001 sp->text = start;
1002 *arglist->lastp = sp;
1003 arglist->lastp = &sp->next;
1004 p++;
1005
1006 if (ifsspc != NULL) {
1007 /* Ignore further trailing IFS whitespace */
1008 for (; p < string + ifsp->endoff; p++) {
1009 q = p;
1010 if (*p == CTLESC)
1011 p++;
1012 if (strchr(ifs, *p) == NULL) {
1013 p = q;
1014 break;
1015 }
1016 if (strchr(" \t\n", *p) == NULL) {
1017 p++;
1018 break;
1019 }
1020 }
1021 }
1022 start = p;
1023 }
1024 }
1025
1026 /*
1027 * Save anything left as an argument.
1028 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1029 * generating 2 arguments, the second of which is empty.
1030 * Some recent clarification of the Posix spec say that it
1031 * should only generate one....
1032 */
1033 if (*start /* || (!ifsspc && start > string) */) {
1034 sp = (struct strlist *)stalloc(sizeof *sp);
1035 sp->text = start;
1036 *arglist->lastp = sp;
1037 arglist->lastp = &sp->next;
1038 }
1039 }
1040
1041 STATIC void
1042 ifsfree(void)
1043 {
1044 while (ifsfirst.next != NULL) {
1045 struct ifsregion *ifsp;
1046 INTOFF;
1047 ifsp = ifsfirst.next->next;
1048 ckfree(ifsfirst.next);
1049 ifsfirst.next = ifsp;
1050 INTON;
1051 }
1052 ifslastp = NULL;
1053 ifsfirst.next = NULL;
1054 }
1055
1056
1057
1058 /*
1059 * Expand shell metacharacters. At this point, the only control characters
1060 * should be escapes. The results are stored in the list exparg.
1061 */
1062
1063 char *expdir;
1064
1065
1066 STATIC void
1067 expandmeta(struct strlist *str, int flag)
1068 {
1069 char *p;
1070 struct strlist **savelastp;
1071 struct strlist *sp;
1072 char c;
1073 /* TODO - EXP_REDIR */
1074
1075 while (str) {
1076 if (fflag)
1077 goto nometa;
1078 p = str->text;
1079 for (;;) { /* fast check for meta chars */
1080 if ((c = *p++) == '\0')
1081 goto nometa;
1082 if (c == '*' || c == '?' || c == '[' || c == '!')
1083 break;
1084 }
1085 savelastp = exparg.lastp;
1086 INTOFF;
1087 if (expdir == NULL) {
1088 int i = strlen(str->text);
1089 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
1090 }
1091
1092 expmeta(expdir, str->text);
1093 ckfree(expdir);
1094 expdir = NULL;
1095 INTON;
1096 if (exparg.lastp == savelastp) {
1097 /*
1098 * no matches
1099 */
1100 nometa:
1101 *exparg.lastp = str;
1102 rmescapes(str->text);
1103 exparg.lastp = &str->next;
1104 } else {
1105 *exparg.lastp = NULL;
1106 *savelastp = sp = expsort(*savelastp);
1107 while (sp->next != NULL)
1108 sp = sp->next;
1109 exparg.lastp = &sp->next;
1110 }
1111 str = str->next;
1112 }
1113 }
1114
1115
1116 /*
1117 * Do metacharacter (i.e. *, ?, [...]) expansion.
1118 */
1119
1120 STATIC void
1121 expmeta(char *enddir, char *name)
1122 {
1123 char *p;
1124 const char *cp;
1125 char *q;
1126 char *start;
1127 char *endname;
1128 int metaflag;
1129 struct stat statb;
1130 DIR *dirp;
1131 struct dirent *dp;
1132 int atend;
1133 int matchdot;
1134
1135 metaflag = 0;
1136 start = name;
1137 for (p = name ; ; p++) {
1138 if (*p == '*' || *p == '?')
1139 metaflag = 1;
1140 else if (*p == '[') {
1141 q = p + 1;
1142 if (*q == '!')
1143 q++;
1144 for (;;) {
1145 while (*q == CTLQUOTEMARK)
1146 q++;
1147 if (*q == CTLESC)
1148 q++;
1149 if (*q == '/' || *q == '\0')
1150 break;
1151 if (*++q == ']') {
1152 metaflag = 1;
1153 break;
1154 }
1155 }
1156 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
1157 metaflag = 1;
1158 } else if (*p == '\0')
1159 break;
1160 else if (*p == CTLQUOTEMARK)
1161 continue;
1162 else if (*p == CTLESC)
1163 p++;
1164 if (*p == '/') {
1165 if (metaflag)
1166 break;
1167 start = p + 1;
1168 }
1169 }
1170 if (metaflag == 0) { /* we've reached the end of the file name */
1171 if (enddir != expdir)
1172 metaflag++;
1173 for (p = name ; ; p++) {
1174 if (*p == CTLQUOTEMARK)
1175 continue;
1176 if (*p == CTLESC)
1177 p++;
1178 *enddir++ = *p;
1179 if (*p == '\0')
1180 break;
1181 }
1182 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1183 addfname(expdir);
1184 return;
1185 }
1186 endname = p;
1187 if (start != name) {
1188 p = name;
1189 while (p < start) {
1190 while (*p == CTLQUOTEMARK)
1191 p++;
1192 if (*p == CTLESC)
1193 p++;
1194 *enddir++ = *p++;
1195 }
1196 }
1197 if (enddir == expdir) {
1198 cp = ".";
1199 } else if (enddir == expdir + 1 && *expdir == '/') {
1200 cp = "/";
1201 } else {
1202 cp = expdir;
1203 enddir[-1] = '\0';
1204 }
1205 if ((dirp = opendir(cp)) == NULL)
1206 return;
1207 if (enddir != expdir)
1208 enddir[-1] = '/';
1209 if (*endname == 0) {
1210 atend = 1;
1211 } else {
1212 atend = 0;
1213 *endname++ = '\0';
1214 }
1215 matchdot = 0;
1216 p = start;
1217 while (*p == CTLQUOTEMARK)
1218 p++;
1219 if (*p == CTLESC)
1220 p++;
1221 if (*p == '.')
1222 matchdot++;
1223 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1224 if (dp->d_name[0] == '.' && ! matchdot)
1225 continue;
1226 if (patmatch(start, dp->d_name, 0)) {
1227 if (atend) {
1228 scopy(dp->d_name, enddir);
1229 addfname(expdir);
1230 } else {
1231 for (p = enddir, cp = dp->d_name;
1232 (*p++ = *cp++) != '\0';)
1233 continue;
1234 p[-1] = '/';
1235 expmeta(p, endname);
1236 }
1237 }
1238 }
1239 closedir(dirp);
1240 if (! atend)
1241 endname[-1] = '/';
1242 }
1243
1244
1245 /*
1246 * Add a file name to the list.
1247 */
1248
1249 STATIC void
1250 addfname(char *name)
1251 {
1252 char *p;
1253 struct strlist *sp;
1254
1255 p = stalloc(strlen(name) + 1);
1256 scopy(name, p);
1257 sp = (struct strlist *)stalloc(sizeof *sp);
1258 sp->text = p;
1259 *exparg.lastp = sp;
1260 exparg.lastp = &sp->next;
1261 }
1262
1263
1264 /*
1265 * Sort the results of file name expansion. It calculates the number of
1266 * strings to sort and then calls msort (short for merge sort) to do the
1267 * work.
1268 */
1269
1270 STATIC struct strlist *
1271 expsort(struct strlist *str)
1272 {
1273 int len;
1274 struct strlist *sp;
1275
1276 len = 0;
1277 for (sp = str ; sp ; sp = sp->next)
1278 len++;
1279 return msort(str, len);
1280 }
1281
1282
1283 STATIC struct strlist *
1284 msort(struct strlist *list, int len)
1285 {
1286 struct strlist *p, *q = NULL;
1287 struct strlist **lpp;
1288 int half;
1289 int n;
1290
1291 if (len <= 1)
1292 return list;
1293 half = len >> 1;
1294 p = list;
1295 for (n = half ; --n >= 0 ; ) {
1296 q = p;
1297 p = p->next;
1298 }
1299 q->next = NULL; /* terminate first half of list */
1300 q = msort(list, half); /* sort first half of list */
1301 p = msort(p, len - half); /* sort second half */
1302 lpp = &list;
1303 for (;;) {
1304 if (strcmp(p->text, q->text) < 0) {
1305 *lpp = p;
1306 lpp = &p->next;
1307 if ((p = *lpp) == NULL) {
1308 *lpp = q;
1309 break;
1310 }
1311 } else {
1312 *lpp = q;
1313 lpp = &q->next;
1314 if ((q = *lpp) == NULL) {
1315 *lpp = p;
1316 break;
1317 }
1318 }
1319 }
1320 return list;
1321 }
1322
1323
1324
1325 /*
1326 * Returns true if the pattern matches the string.
1327 */
1328
1329 int
1330 patmatch(char *pattern, char *string, int squoted)
1331 {
1332 #ifdef notdef
1333 if (pattern[0] == '!' && pattern[1] == '!')
1334 return 1 - pmatch(pattern + 2, string);
1335 else
1336 #endif
1337 return pmatch(pattern, string, squoted);
1338 }
1339
1340
1341 STATIC int
1342 pmatch(char *pattern, char *string, int squoted)
1343 {
1344 char *p, *q;
1345 char c;
1346
1347 p = pattern;
1348 q = string;
1349 for (;;) {
1350 switch (c = *p++) {
1351 case '\0':
1352 goto breakloop;
1353 case CTLESC:
1354 if (squoted && *q == CTLESC)
1355 q++;
1356 if (*q++ != *p++)
1357 return 0;
1358 break;
1359 case CTLQUOTEMARK:
1360 continue;
1361 case '?':
1362 if (squoted && *q == CTLESC)
1363 q++;
1364 if (*q++ == '\0')
1365 return 0;
1366 break;
1367 case '*':
1368 c = *p;
1369 while (c == CTLQUOTEMARK || c == '*')
1370 c = *++p;
1371 if (c != CTLESC && c != CTLQUOTEMARK &&
1372 c != '?' && c != '*' && c != '[') {
1373 while (*q != c) {
1374 if (squoted && *q == CTLESC &&
1375 q[1] == c)
1376 break;
1377 if (*q == '\0')
1378 return 0;
1379 if (squoted && *q == CTLESC)
1380 q++;
1381 q++;
1382 }
1383 }
1384 do {
1385 if (pmatch(p, q, squoted))
1386 return 1;
1387 if (squoted && *q == CTLESC)
1388 q++;
1389 } while (*q++ != '\0');
1390 return 0;
1391 case '[': {
1392 char *endp;
1393 int invert, found;
1394 char chr;
1395
1396 endp = p;
1397 if (*endp == '!')
1398 endp++;
1399 for (;;) {
1400 while (*endp == CTLQUOTEMARK)
1401 endp++;
1402 if (*endp == '\0')
1403 goto dft; /* no matching ] */
1404 if (*endp == CTLESC)
1405 endp++;
1406 if (*++endp == ']')
1407 break;
1408 }
1409 invert = 0;
1410 if (*p == '!') {
1411 invert++;
1412 p++;
1413 }
1414 found = 0;
1415 chr = *q++;
1416 if (squoted && chr == CTLESC)
1417 chr = *q++;
1418 if (chr == '\0')
1419 return 0;
1420 c = *p++;
1421 do {
1422 if (c == CTLQUOTEMARK)
1423 continue;
1424 if (c == CTLESC)
1425 c = *p++;
1426 if (*p == '-' && p[1] != ']') {
1427 p++;
1428 while (*p == CTLQUOTEMARK)
1429 p++;
1430 if (*p == CTLESC)
1431 p++;
1432 if (chr >= c && chr <= *p)
1433 found = 1;
1434 p++;
1435 } else {
1436 if (chr == c)
1437 found = 1;
1438 }
1439 } while ((c = *p++) != ']');
1440 if (found == invert)
1441 return 0;
1442 break;
1443 }
1444 dft: default:
1445 if (squoted && *q == CTLESC)
1446 q++;
1447 if (*q++ != c)
1448 return 0;
1449 break;
1450 }
1451 }
1452 breakloop:
1453 if (*q != '\0')
1454 return 0;
1455 return 1;
1456 }
1457
1458
1459
1460 /*
1461 * Remove any CTLESC characters from a string.
1462 */
1463
1464 void
1465 rmescapes(char *str)
1466 {
1467 char *p, *q;
1468
1469 p = str;
1470 while (*p != CTLESC && *p != CTLQUOTEMARK) {
1471 if (*p++ == '\0')
1472 return;
1473 }
1474 q = p;
1475 while (*p) {
1476 if (*p == CTLQUOTEMARK) {
1477 p++;
1478 continue;
1479 }
1480 if (*p == CTLESC)
1481 p++;
1482 *q++ = *p++;
1483 }
1484 *q = '\0';
1485 }
1486
1487
1488
1489 /*
1490 * See if a pattern matches in a case statement.
1491 */
1492
1493 int
1494 casematch(union node *pattern, char *val)
1495 {
1496 struct stackmark smark;
1497 int result;
1498 char *p;
1499
1500 setstackmark(&smark);
1501 argbackq = pattern->narg.backquote;
1502 STARTSTACKSTR(expdest);
1503 ifslastp = NULL;
1504 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1505 STPUTC('\0', expdest);
1506 p = grabstackstr(expdest);
1507 result = patmatch(p, val, 0);
1508 popstackmark(&smark);
1509 return result;
1510 }
1511
1512 /*
1513 * Our own itoa().
1514 */
1515
1516 STATIC char *
1517 cvtnum(int num, char *buf)
1518 {
1519 char temp[32];
1520 int neg = num < 0;
1521 char *p = temp + 31;
1522
1523 temp[31] = '\0';
1524
1525 do {
1526 *--p = num % 10 + '0';
1527 } while ((num /= 10) != 0);
1528
1529 if (neg)
1530 *--p = '-';
1531
1532 while (*p)
1533 STPUTC(*p++, buf);
1534 return buf;
1535 }
1536
1537 /*
1538 * Do most of the work for wordexp(3).
1539 */
1540
1541 int
1542 wordexpcmd(int argc, char **argv)
1543 {
1544 size_t len;
1545 int i;
1546
1547 out1fmt("%d", argc - 1);
1548 out1c('\0');
1549 for (i = 1, len = 0; i < argc; i++)
1550 len += strlen(argv[i]);
1551 out1fmt("%zd", len);
1552 out1c('\0');
1553 for (i = 1; i < argc; i++) {
1554 out1str(argv[i]);
1555 out1c('\0');
1556 }
1557 return (0);
1558 }
+0
-72
sh/expand.h less more
0 /* $NetBSD: expand.h,v 1.16 2004/07/13 15:05:59 seb Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)expand.h 8.2 (Berkeley) 5/4/95
34 */
35
36 struct strlist {
37 struct strlist *next;
38 char *text;
39 };
40
41
42 struct arglist {
43 struct strlist *list;
44 struct strlist **lastp;
45 };
46
47 /*
48 * expandarg() flags
49 */
50 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
51 #define EXP_TILDE 0x2 /* do normal tilde expansion */
52 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
53 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
54 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
55 #define EXP_IFS_SPLIT 0x20 /* need to record arguments for ifs breakup */
56
57
58 union node;
59 void expandhere(union node *, int);
60 void expandarg(union node *, struct arglist *, int);
61 void expari(int);
62 int patmatch(char *, char *, int);
63 void rmescapes(char *);
64 int casematch(union node *, char *);
65 int wordexpcmd(int, char **);
66
67 /* From arith.y */
68 int arith(const char *);
69 int expcmd(int , char **);
70 void arith_lex_reset(void);
71 int yylex(void);
+0
-50
sh/funcs/cmv less more
0 # $NetBSD: cmv,v 1.7 1995/05/11 21:31:05 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)cmv 8.2 (Berkeley) 5/4/95
36
37 # Conditional move--don't replace an existing file.
38
39 cmv() {
40 if test $# != 2
41 then echo "cmv: arg count"
42 return 2
43 fi
44 if test -f "$2" -o -w "$2"
45 then echo "$2 exists"
46 return 2
47 fi
48 /bin/mv "$1" "$2"
49 }
+0
-74
sh/funcs/dirs less more
0 # $NetBSD: dirs,v 1.7 1995/05/11 21:31:08 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)dirs 8.2 (Berkeley) 5/4/95
36
37 # pushd, popd, and dirs --- written by Chris Bertin
38 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
39 # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
40
41 pushd () {
42 SAVE=`pwd`
43 if [ "$1" = "" ]
44 then if [ "$DSTACK" = "" ]
45 then echo "pushd: directory stack empty."
46 return 1
47 fi
48 set $DSTACK
49 cd $1 || return
50 shift 1
51 DSTACK="$*"
52 else cd $1 > /dev/null || return
53 fi
54 DSTACK="$SAVE $DSTACK"
55 dirs
56 }
57
58 popd () {
59 if [ "$DSTACK" = "" ]
60 then echo "popd: directory stack empty."
61 return 1
62 fi
63 set $DSTACK
64 cd $1
65 shift
66 DSTACK=$*
67 dirs
68 }
69
70 dirs () {
71 echo "`pwd` $DSTACK"
72 return 0
73 }
+0
-50
sh/funcs/kill less more
0 # $NetBSD: kill,v 1.7 1995/05/11 21:31:10 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)kill 8.2 (Berkeley) 5/4/95
36
37 # Convert job names to process ids and then run /bin/kill.
38
39 kill() {
40 local args x
41 args=
42 for x in "$@"
43 do case $x in
44 %*) x=`jobid "$x"` ;;
45 esac
46 args="$args $x"
47 done
48 /bin/kill $args
49 }
+0
-39
sh/funcs/login less more
0 # $NetBSD: login,v 1.7 1995/05/11 21:31:11 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)login 8.2 (Berkeley) 5/4/95
36
37 # replaces the login builtin in the BSD shell
38 login () exec login "$@"
+0
-38
sh/funcs/newgrp less more
0 # $NetBSD: newgrp,v 1.7 1995/05/11 21:31:12 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)newgrp 8.2 (Berkeley) 5/4/95
36
37 newgrp() exec newgrp "$@"
+0
-74
sh/funcs/popd less more
0 # $NetBSD: popd,v 1.7 1995/05/11 21:31:13 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)popd 8.2 (Berkeley) 5/4/95
36
37 # pushd, popd, and dirs --- written by Chris Bertin
38 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
39 # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
40
41 pushd () {
42 SAVE=`pwd`
43 if [ "$1" = "" ]
44 then if [ "$DSTACK" = "" ]
45 then echo "pushd: directory stack empty."
46 return 1
47 fi
48 set $DSTACK
49 cd $1 || return
50 shift 1
51 DSTACK="$*"
52 else cd $1 > /dev/null || return
53 fi
54 DSTACK="$SAVE $DSTACK"
55 dirs
56 }
57
58 popd () {
59 if [ "$DSTACK" = "" ]
60 then echo "popd: directory stack empty."
61 return 1
62 fi
63 set $DSTACK
64 cd $1
65 shift
66 DSTACK=$*
67 dirs
68 }
69
70 dirs () {
71 echo "`pwd` $DSTACK"
72 return 0
73 }
+0
-74
sh/funcs/pushd less more
0 # $NetBSD: pushd,v 1.7 1995/05/11 21:31:15 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)pushd 8.2 (Berkeley) 5/4/95
36
37 # pushd, popd, and dirs --- written by Chris Bertin
38 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
39 # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
40
41 pushd () {
42 SAVE=`pwd`
43 if [ "$1" = "" ]
44 then if [ "$DSTACK" = "" ]
45 then echo "pushd: directory stack empty."
46 return 1
47 fi
48 set $DSTACK
49 cd $1 || return
50 shift 1
51 DSTACK="$*"
52 else cd $1 > /dev/null || return
53 fi
54 DSTACK="$SAVE $DSTACK"
55 dirs
56 }
57
58 popd () {
59 if [ "$DSTACK" = "" ]
60 then echo "popd: directory stack empty."
61 return 1
62 fi
63 set $DSTACK
64 cd $1
65 shift
66 DSTACK=$*
67 dirs
68 }
69
70 dirs () {
71 echo "`pwd` $DSTACK"
72 return 0
73 }
+0
-42
sh/funcs/suspend less more
0 # $NetBSD: suspend,v 1.7 1995/05/11 21:31:17 christos Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. All advertising materials mentioning features or use of this software
16 # must display the following acknowledgement:
17 # This product includes software developed by the University of
18 # California, Berkeley and its contributors.
19 # 4. Neither the name of the University nor the names of its contributors
20 # may be used to endorse or promote products derived from this software
21 # without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # SUCH DAMAGE.
34 #
35 # @(#)suspend 8.2 (Berkeley) 5/4/95
36
37 suspend() {
38 local -
39 set +j
40 kill -TSTP 0
41 }
+0
-540
sh/histedit.c less more
0 /* $NetBSD: histedit.c,v 1.34 2003/10/27 06:19:29 lukem Exp $ */
1
2 /*-
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: histedit.c,v 1.34 2003/10/27 06:19:29 lukem Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <sys/param.h>
44 #include <paths.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 /*
49 * Editline and history functions (and glue).
50 */
51 #include "shell.h"
52 #include "parser.h"
53 #include "var.h"
54 #include "options.h"
55 #include "main.h"
56 #include "output.h"
57 #include "mystring.h"
58 #include "myhistedit.h"
59 #include "error.h"
60 #ifndef SMALL
61 #include "eval.h"
62 #include "memalloc.h"
63
64 #define MAXHISTLOOPS 4 /* max recursions through fc */
65 #define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
66
67 History *hist; /* history cookie */
68 EditLine *el; /* editline cookie */
69 int displayhist;
70 static FILE *el_in, *el_out;
71
72 STATIC const char *fc_replace(const char *, char *, char *);
73
74 #ifdef DEBUG
75 extern FILE *tracefile;
76 #endif
77
78 /*
79 * Set history and editing status. Called whenever the status may
80 * have changed (figures out what to do).
81 */
82 void
83 histedit(void)
84 {
85 FILE *el_err;
86
87 #define editing (Eflag || Vflag)
88
89 if (iflag) {
90 if (!hist) {
91 /*
92 * turn history on
93 */
94 INTOFF;
95 hist = history_init();
96 INTON;
97
98 if (hist != NULL)
99 sethistsize(histsizeval());
100 else
101 out2str("sh: can't initialize history\n");
102 }
103 if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
104 /*
105 * turn editing on
106 */
107 char *term, *shname;
108
109 INTOFF;
110 if (el_in == NULL)
111 el_in = fdopen(0, "r");
112 if (el_out == NULL)
113 el_out = fdopen(2, "w");
114 if (el_in == NULL || el_out == NULL)
115 goto bad;
116 el_err = el_out;
117 #if DEBUG
118 if (tracefile)
119 el_err = tracefile;
120 #endif
121 term = lookupvar("TERM");
122 if (term)
123 setenv("TERM", term, 1);
124 else
125 unsetenv("TERM");
126 shname = arg0;
127 if (shname[0] == '-')
128 shname++;
129 el = el_init(shname, el_in, el_out, el_err);
130 if (el != NULL) {
131 if (hist)
132 el_set(el, EL_HIST, history, hist);
133 el_set(el, EL_PROMPT, getprompt);
134 el_set(el, EL_SIGNAL, 1);
135 } else {
136 bad:
137 out2str("sh: can't initialize editing\n");
138 }
139 INTON;
140 } else if (!editing && el) {
141 INTOFF;
142 el_end(el);
143 el = NULL;
144 INTON;
145 }
146 if (el) {
147 if (Vflag)
148 el_set(el, EL_EDITOR, "vi");
149 else if (Eflag)
150 el_set(el, EL_EDITOR, "emacs");
151 el_source(el, NULL);
152 }
153 } else {
154 INTOFF;
155 if (el) { /* no editing if not interactive */
156 el_end(el);
157 el = NULL;
158 }
159 if (hist) {
160 history_end(hist);
161 hist = NULL;
162 }
163 INTON;
164 }
165 }
166
167
168 void
169 sethistsize(const char *hs)
170 {
171 int histsize;
172 HistEvent he;
173
174 if (hist != NULL) {
175 if (hs == NULL || *hs == '\0' ||
176 (histsize = atoi(hs)) < 0)
177 histsize = 100;
178 history(hist, &he, H_SETSIZE, histsize);
179 }
180 }
181
182 void
183 setterm(const char *term)
184 {
185 if (el != NULL && term != NULL)
186 if (el_set(el, EL_TERMINAL, term) != 0) {
187 outfmt(out2, "sh: Can't set terminal type %s\n", term);
188 outfmt(out2, "sh: Using dumb terminal settings.\n");
189 }
190 }
191
192 int
193 inputrc(argc, argv)
194 int argc;
195 char **argv;
196 {
197 if (argc != 2) {
198 out2str("usage: inputrc file\n");
199 return 1;
200 }
201 if (el != NULL) {
202 if (el_source(el, argv[1])) {
203 out2str("inputrc: failed\n");
204 return 1;
205 } else
206 return 0;
207 } else {
208 out2str("sh: inputrc ignored, not editing\n");
209 return 1;
210 }
211 }
212
213 /*
214 * This command is provided since POSIX decided to standardize
215 * the Korn shell fc command. Oh well...
216 */
217 int
218 histcmd(int argc, char **argv)
219 {
220 int ch;
221 const char *editor = NULL;
222 HistEvent he;
223 int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
224 int i, retval;
225 const char *firststr, *laststr;
226 int first, last, direction;
227 char *pat = NULL, *repl; /* ksh "fc old=new" crap */
228 static int active = 0;
229 struct jmploc jmploc;
230 struct jmploc *volatile savehandler;
231 char editfile[MAXPATHLEN + 1];
232 FILE *efp;
233 #ifdef __GNUC__
234 /* Avoid longjmp clobbering */
235 (void) &editor;
236 (void) &lflg;
237 (void) &nflg;
238 (void) &rflg;
239 (void) &sflg;
240 (void) &firststr;
241 (void) &laststr;
242 (void) &pat;
243 (void) &repl;
244 (void) &efp;
245 (void) &argc;
246 (void) &argv;
247 #endif
248
249 if (hist == NULL)
250 error("history not active");
251
252 if (argc == 1)
253 error("missing history argument");
254
255 optreset = 1; optind = 1; /* initialize getopt */
256 while (not_fcnumber(argv[optind]) &&
257 (ch = getopt(argc, argv, ":e:lnrs")) != -1)
258 switch ((char)ch) {
259 case 'e':
260 editor = optionarg;
261 break;
262 case 'l':
263 lflg = 1;
264 break;
265 case 'n':
266 nflg = 1;
267 break;
268 case 'r':
269 rflg = 1;
270 break;
271 case 's':
272 sflg = 1;
273 break;
274 case ':':
275 error("option -%c expects argument", optopt);
276 /* NOTREACHED */
277 case '?':
278 default:
279 error("unknown option: -%c", optopt);
280 /* NOTREACHED */
281 }
282 argc -= optind, argv += optind;
283
284 /*
285 * If executing...
286 */
287 if (lflg == 0 || editor || sflg) {
288 lflg = 0; /* ignore */
289 editfile[0] = '\0';
290 /*
291 * Catch interrupts to reset active counter and
292 * cleanup temp files.
293 */
294 if (setjmp(jmploc.loc)) {
295 active = 0;
296 if (*editfile)
297 unlink(editfile);
298 handler = savehandler;
299 longjmp(handler->loc, 1);
300 }
301 savehandler = handler;
302 handler = &jmploc;
303 if (++active > MAXHISTLOOPS) {
304 active = 0;
305 displayhist = 0;
306 error("called recursively too many times");
307 }
308 /*
309 * Set editor.
310 */
311 if (sflg == 0) {
312 if (editor == NULL &&
313 (editor = bltinlookup("FCEDIT", 1)) == NULL &&
314 (editor = bltinlookup("EDITOR", 1)) == NULL)
315 editor = DEFEDITOR;
316 if (editor[0] == '-' && editor[1] == '\0') {
317 sflg = 1; /* no edit */
318 editor = NULL;
319 }
320 }
321 }
322
323 /*
324 * If executing, parse [old=new] now
325 */
326 if (lflg == 0 && argc > 0 &&
327 ((repl = strchr(argv[0], '=')) != NULL)) {
328 pat = argv[0];
329 *repl++ = '\0';
330 argc--, argv++;
331 }
332 /*
333 * determine [first] and [last]
334 */
335 switch (argc) {
336 case 0:
337 firststr = lflg ? "-16" : "-1";
338 laststr = "-1";
339 break;
340 case 1:
341 firststr = argv[0];
342 laststr = lflg ? "-1" : argv[0];
343 break;
344 case 2:
345 firststr = argv[0];
346 laststr = argv[1];
347 break;
348 default:
349 error("too many args");
350 /* NOTREACHED */
351 }
352 /*
353 * Turn into event numbers.
354 */
355 first = str_to_event(firststr, 0);
356 last = str_to_event(laststr, 1);
357
358 if (rflg) {
359 i = last;
360 last = first;
361 first = i;
362 }
363 /*
364 * XXX - this should not depend on the event numbers
365 * always increasing. Add sequence numbers or offset
366 * to the history element in next (diskbased) release.
367 */
368 direction = first < last ? H_PREV : H_NEXT;
369
370 /*
371 * If editing, grab a temp file.
372 */
373 if (editor) {
374 int fd;
375 INTOFF; /* easier */
376 snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
377 if ((fd = mkstemp(editfile)) < 0)
378 error("can't create temporary file %s", editfile);
379 if ((efp = fdopen(fd, "w")) == NULL) {
380 close(fd);
381 error("can't allocate stdio buffer for temp");
382 }
383 }
384
385 /*
386 * Loop through selected history events. If listing or executing,
387 * do it now. Otherwise, put into temp file and call the editor
388 * after.
389 *
390 * The history interface needs rethinking, as the following
391 * convolutions will demonstrate.
392 */
393 history(hist, &he, H_FIRST);
394 retval = history(hist, &he, H_NEXT_EVENT, first);
395 for (;retval != -1; retval = history(hist, &he, direction)) {
396 if (lflg) {
397 if (!nflg)
398 out1fmt("%5d ", he.num);
399 out1str(he.str);
400 } else {
401 const char *s = pat ?
402 fc_replace(he.str, pat, repl) : he.str;
403
404 if (sflg) {
405 if (displayhist) {
406 out2str(s);
407 }
408
409 evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
410 if (displayhist && hist) {
411 /*
412 * XXX what about recursive and
413 * relative histnums.
414 */
415 history(hist, &he, H_ENTER, s);
416 }
417 } else
418 fputs(s, efp);
419 }
420 /*
421 * At end? (if we were to lose last, we'd sure be
422 * messed up).
423 */
424 if (he.num == last)
425 break;
426 }
427 if (editor) {
428 char *editcmd;
429
430 fclose(efp);
431 editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
432 sprintf(editcmd, "%s %s", editor, editfile);
433 evalstring(editcmd, 0); /* XXX - should use no JC command */
434 INTON;
435 readcmdfile(editfile); /* XXX - should read back - quick tst */
436 unlink(editfile);
437 }
438
439 if (lflg == 0 && active > 0)
440 --active;
441 if (displayhist)
442 displayhist = 0;
443 return 0;
444 }
445
446 STATIC const char *
447 fc_replace(const char *s, char *p, char *r)
448 {
449 char *dest;
450 int plen = strlen(p);
451
452 STARTSTACKSTR(dest);
453 while (*s) {
454 if (*s == *p && strncmp(s, p, plen) == 0) {
455 while (*r)
456 STPUTC(*r++, dest);
457 s += plen;
458 *p = '\0'; /* so no more matches */
459 } else
460 STPUTC(*s++, dest);
461 }
462 STACKSTRNUL(dest);
463 dest = grabstackstr(dest);
464
465 return (dest);
466 }
467
468 int
469 not_fcnumber(char *s)
470 {
471 if (s == NULL)
472 return 0;
473 if (*s == '-')
474 s++;
475 return (!is_number(s));
476 }
477
478 int
479 str_to_event(const char *str, int last)
480 {
481 HistEvent he;
482 const char *s = str;
483 int relative = 0;
484 int i, retval;
485
486 retval = history(hist, &he, H_FIRST);
487 switch (*s) {
488 case '-':
489 relative = 1;
490 /*FALLTHROUGH*/
491 case '+':
492 s++;
493 }
494 if (is_number(s)) {
495 i = atoi(s);
496 if (relative) {
497 while (retval != -1 && i--) {
498 retval = history(hist, &he, H_NEXT);
499 }
500 if (retval == -1)
501 retval = history(hist, &he, H_LAST);
502 } else {
503 retval = history(hist, &he, H_NEXT_EVENT, i);
504 if (retval == -1) {
505 /*
506 * the notion of first and last is
507 * backwards to that of the history package
508 */
509 retval = history(hist, &he,
510 last ? H_FIRST : H_LAST);
511 }
512 }
513 if (retval == -1)
514 error("history number %s not found (internal error)",
515 str);
516 } else {
517 /*
518 * pattern
519 */
520 retval = history(hist, &he, H_PREV_STR, str);
521 if (retval == -1)
522 error("history pattern not found: %s", str);
523 }
524 return (he.num);
525 }
526 #else
527 int
528 histcmd(int argc, char **argv)
529 {
530 error("not compiled with history support");
531 /* NOTREACHED */
532 }
533 int
534 inputrc(int argc, char **argv)
535 {
536 error("not compiled with history support");
537 /* NOTREACHED */
538 }
539 #endif
+0
-1090
sh/init.c less more
0 /*
1 * This file was generated by the mkinit program.
2 */
3
4 #include "shell.h"
5 #include "mystring.h"
6 #include "init.h"
7 #include "eval.h"
8 #include <stdio.h>
9 #include "input.h"
10 #include "error.h"
11 #include <stdlib.h>
12 #include "options.h"
13 #include "redir.h"
14 #include <signal.h>
15 #include "trap.h"
16 #include "output.h"
17 #include "memalloc.h"
18 #include "var.h"
19
20
21
22 #undef ATABSIZE
23 #define ATABSIZE 39
24 #undef YYBISON
25 #define YYBISON 1
26 #undef YYSKELETON_NAME
27 #define YYSKELETON_NAME "yacc.c"
28 #undef YYPURE
29 #define YYPURE 0
30 #undef YYLSP_NEEDED
31 #define YYLSP_NEEDED 0
32 #undef ARITH_NUM
33 #define ARITH_NUM 258
34 #undef ARITH_LPAREN
35 #define ARITH_LPAREN 259
36 #undef ARITH_RPAREN
37 #define ARITH_RPAREN 260
38 #undef ARITH_OR
39 #define ARITH_OR 261
40 #undef ARITH_AND
41 #define ARITH_AND 262
42 #undef ARITH_BOR
43 #define ARITH_BOR 263
44 #undef ARITH_BXOR
45 #define ARITH_BXOR 264
46 #undef ARITH_BAND
47 #define ARITH_BAND 265
48 #undef ARITH_NE
49 #define ARITH_NE 266
50 #undef ARITH_EQ
51 #define ARITH_EQ 267
52 #undef ARITH_LE
53 #define ARITH_LE 268
54 #undef ARITH_GE
55 #define ARITH_GE 269
56 #undef ARITH_GT
57 #define ARITH_GT 270
58 #undef ARITH_LT
59 #define ARITH_LT 271
60 #undef ARITH_RSHIFT
61 #define ARITH_RSHIFT 272
62 #undef ARITH_LSHIFT
63 #define ARITH_LSHIFT 273
64 #undef ARITH_SUB
65 #define ARITH_SUB 274
66 #undef ARITH_ADD
67 #define ARITH_ADD 275
68 #undef ARITH_REM
69 #define ARITH_REM 276
70 #undef ARITH_DIV
71 #define ARITH_DIV 277
72 #undef ARITH_MUL
73 #define ARITH_MUL 278
74 #undef ARITH_BNOT
75 #define ARITH_BNOT 279
76 #undef ARITH_NOT
77 #define ARITH_NOT 280
78 #undef ARITH_UNARYPLUS
79 #define ARITH_UNARYPLUS 281
80 #undef ARITH_UNARYMINUS
81 #define ARITH_UNARYMINUS 282
82 #undef YYFINAL
83 #define YYFINAL 14
84 #undef YYLAST
85 #define YYLAST 170
86 #undef YYNTOKENS
87 #define YYNTOKENS 28
88 #undef YYNNTS
89 #define YYNNTS 3
90 #undef YYNRULES
91 #define YYNRULES 26
92 #undef YYNSTATES
93 #define YYNSTATES 52
94 #undef YYUNDEFTOK
95 #define YYUNDEFTOK 2
96 #undef YYMAXUTOK
97 #define YYMAXUTOK 282
98 #undef YYPACT_NINF
99 #define YYPACT_NINF -13
100 #undef YYTABLE_NINF
101 #define YYTABLE_NINF -1
102 #undef yyerrok
103 #define yyerrok (yyerrstatus = 0)
104 #undef yyclearin
105 #define yyclearin (yychar = YYEMPTY)
106 #undef YYEMPTY
107 #define YYEMPTY (-2)
108 #undef YYEOF
109 #define YYEOF 0
110 #undef YYACCEPT
111 #define YYACCEPT goto yyacceptlab
112 #undef YYABORT
113 #define YYABORT goto yyabortlab
114 #undef YYERROR
115 #define YYERROR goto yyerrorlab
116 #undef YYFAIL
117 #define YYFAIL goto yyerrlab
118 #undef YYTERROR
119 #define YYTERROR 1
120 #undef YYERRCODE
121 #define YYERRCODE 256
122 #undef YYPOPSTACK
123 #define YYPOPSTACK (yyvsp--, yyssp--)
124 #undef YY_INT_ALIGNED
125 #define YY_INT_ALIGNED short int
126 #undef FLEX_SCANNER
127 #define FLEX_SCANNER
128 #undef YY_FLEX_MAJOR_VERSION
129 #define YY_FLEX_MAJOR_VERSION 2
130 #undef YY_FLEX_MINOR_VERSION
131 #define YY_FLEX_MINOR_VERSION 5
132 #undef YY_FLEX_SUBMINOR_VERSION
133 #define YY_FLEX_SUBMINOR_VERSION 31
134 #undef FLEX_BETA
135 #define FLEX_BETA
136 #undef FLEXINT_H
137 #define FLEXINT_H
138 #undef INT8_MIN
139 #define INT8_MIN (-128)
140 #undef INT16_MIN
141 #define INT16_MIN (-32767-1)
142 #undef INT32_MIN
143 #define INT32_MIN (-2147483647-1)
144 #undef INT8_MAX
145 #define INT8_MAX (127)
146 #undef INT16_MAX
147 #define INT16_MAX (32767)
148 #undef INT32_MAX
149 #define INT32_MAX (2147483647)
150 #undef UINT8_MAX
151 #define UINT8_MAX (255U)
152 #undef UINT16_MAX
153 #define UINT16_MAX (65535U)
154 #undef UINT32_MAX
155 #define UINT32_MAX (4294967295U)
156 #undef YY_USE_CONST
157 #define YY_USE_CONST
158 #undef YY_USE_CONST
159 #define YY_USE_CONST
160 #undef yyconst
161 #define yyconst const
162 #undef yyconst
163 #define yyconst
164 #undef YY_NULL
165 #define YY_NULL 0
166 #undef BEGIN
167 #define BEGIN (yy_start) = 1 + 2 *
168 #undef YY_START
169 #define YY_START (((yy_start) - 1) / 2)
170 #undef YYSTATE
171 #define YYSTATE YY_START
172 #undef YY_NEW_FILE
173 #define YY_NEW_FILE yyrestart(yyin )
174 #undef YY_END_OF_BUFFER_CHAR
175 #define YY_END_OF_BUFFER_CHAR 0
176 #undef YY_BUF_SIZE
177 #define YY_BUF_SIZE 16384
178 #undef YY_TYPEDEF_YY_BUFFER_STATE
179 #define YY_TYPEDEF_YY_BUFFER_STATE
180 #undef EOB_ACT_CONTINUE_SCAN
181 #define EOB_ACT_CONTINUE_SCAN 0
182 #undef EOB_ACT_END_OF_FILE
183 #define EOB_ACT_END_OF_FILE 1
184 #undef EOB_ACT_LAST_MATCH
185 #define EOB_ACT_LAST_MATCH 2
186 #undef YY_TYPEDEF_YY_SIZE_T
187 #define YY_TYPEDEF_YY_SIZE_T
188 #undef YY_STRUCT_YY_BUFFER_STATE
189 #define YY_STRUCT_YY_BUFFER_STATE
190 #undef YY_BUFFER_NEW
191 #define YY_BUFFER_NEW 0
192 #undef YY_BUFFER_NORMAL
193 #define YY_BUFFER_NORMAL 1
194 #undef YY_BUFFER_EOF_PENDING
195 #define YY_BUFFER_EOF_PENDING 2
196 #undef YY_CURRENT_BUFFER
197 #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
198 #undef YY_CURRENT_BUFFER_LVALUE
199 #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
200 #undef YY_FLUSH_BUFFER
201 #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
202 #undef yy_new_buffer
203 #define yy_new_buffer yy_create_buffer
204 #undef YY_SKIP_YYWRAP
205 #define YY_SKIP_YYWRAP
206 #undef yytext_ptr
207 #define yytext_ptr yytext
208 #undef YY_DO_BEFORE_ACTION
209 #define YY_DO_BEFORE_ACTION \
210 #undef YY_NUM_RULES
211 #define YY_NUM_RULES 29
212 #undef YY_END_OF_BUFFER
213 #define YY_END_OF_BUFFER 30
214 #undef REJECT
215 #define REJECT reject_used_but_not_detected
216 #undef YY_MORE_ADJ
217 #define YY_MORE_ADJ 0
218 #undef YY_RESTORE_YY_MORE_OFFSET
219 #define YY_RESTORE_YY_MORE_OFFSET
220 #undef YY_NO_UNPUT
221 #define YY_NO_UNPUT
222 #undef INITIAL
223 #define INITIAL 0
224 #undef YY_EXTRA_TYPE
225 #define YY_EXTRA_TYPE void *
226 #undef YY_READ_BUF_SIZE
227 #define YY_READ_BUF_SIZE 8192
228 #undef ECHO
229 #define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
230 #undef YY_START_STACK_INCR
231 #define YY_START_STACK_INCR 25
232 #undef YY_DECL_IS_OURS
233 #define YY_DECL_IS_OURS 1
234 #undef YY_DECL
235 #define YY_DECL int yylex (void)
236 #undef YY_USER_ACTION
237 #define YY_USER_ACTION
238 #undef YY_BREAK
239 #define YY_BREAK break;
240 #undef YY_RULE_SETUP
241 #define YY_RULE_SETUP \
242 #undef YY_EXIT_FAILURE
243 #define YY_EXIT_FAILURE 2
244 #undef YYTABLES_NAME
245 #define YYTABLES_NAME "yytables"
246 #undef MAXPWD
247 #define MAXPWD 256
248 #undef signal
249 #define signal bsd_signal
250 #undef ALL
251 #define ALL (E_OPEN|E_CREAT|E_EXEC)
252 #undef EV_EXIT
253 #define EV_EXIT 01 /* exit after evaluating tree */
254 #undef EV_TESTED
255 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
256 #undef EV_BACKCMD
257 #define EV_BACKCMD 04 /* command executing within back quotes */
258 #undef CMDTABLESIZE
259 #define CMDTABLESIZE 31 /* should be prime */
260 #undef ARB
261 #define ARB 1 /* actual size determined at run time */
262 #undef NEWARGS
263 #define NEWARGS 5
264 #undef EOF_NLEFT
265 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
266 #undef _PATH_DEVNULL
267 #define _PATH_DEVNULL "/dev/null"
268 #undef PROFILE
269 #define PROFILE 0
270 #undef SIGSSIZE
271 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
272 #undef MINSIZE
273 #define MINSIZE 504 /* minimum size of a block */
274 #undef DEFINE_OPTIONS
275 #define DEFINE_OPTIONS
276 #undef EOFMARKLEN
277 #define EOFMARKLEN 79
278 #undef OPENBRACE
279 #define OPENBRACE '{'
280 #undef CLOSEBRACE
281 #define CLOSEBRACE '}'
282 #undef EMPTY
283 #define EMPTY -2 /* marks an unused slot in redirtab */
284 #undef signal
285 #define signal bsd_signal
286 #undef sys_signame
287 #define sys_signame sys_siglist
288 #undef S_DFL
289 #define S_DFL 1 /* default signal handling (SIG_DFL) */
290 #undef S_CATCH
291 #define S_CATCH 2 /* signal is caught */
292 #undef S_IGN
293 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
294 #undef S_HARD_IGN
295 #define S_HARD_IGN 4 /* signal is ignored permenantly */
296 #undef S_RESET
297 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
298 #undef OUTBUFSIZ
299 #define OUTBUFSIZ BUFSIZ
300 #undef BLOCK_OUT
301 #define BLOCK_OUT -2 /* output to a fixed block of memory */
302 #undef MEM_OUT
303 #define MEM_OUT -3 /* output to dynamically allocated memory */
304 #undef OUTPUT_ERR
305 #define OUTPUT_ERR 01 /* error occurred on output */
306 #undef TEMPSIZE
307 #define TEMPSIZE 24
308 #undef HAVE_VASPRINTF
309 #define HAVE_VASPRINTF 1
310 #undef VTABSIZE
311 #define VTABSIZE 39
312 #undef VTABSIZE
313 #define VTABSIZE 517
314 #undef ATABSIZE
315 #define ATABSIZE 39
316 #undef YYBISON
317 #define YYBISON 1
318 #undef YYSKELETON_NAME
319 #define YYSKELETON_NAME "yacc.c"
320 #undef YYPURE
321 #define YYPURE 0
322 #undef YYLSP_NEEDED
323 #define YYLSP_NEEDED 0
324 #undef ARITH_NUM
325 #define ARITH_NUM 258
326 #undef ARITH_LPAREN
327 #define ARITH_LPAREN 259
328 #undef ARITH_RPAREN
329 #define ARITH_RPAREN 260
330 #undef ARITH_OR
331 #define ARITH_OR 261
332 #undef ARITH_AND
333 #define ARITH_AND 262
334 #undef ARITH_BOR
335 #define ARITH_BOR 263
336 #undef ARITH_BXOR
337 #define ARITH_BXOR 264
338 #undef ARITH_BAND
339 #define ARITH_BAND 265
340 #undef ARITH_NE
341 #define ARITH_NE 266
342 #undef ARITH_EQ
343 #define ARITH_EQ 267
344 #undef ARITH_LE
345 #define ARITH_LE 268
346 #undef ARITH_GE
347 #define ARITH_GE 269
348 #undef ARITH_GT
349 #define ARITH_GT 270
350 #undef ARITH_LT
351 #define ARITH_LT 271
352 #undef ARITH_RSHIFT
353 #define ARITH_RSHIFT 272
354 #undef ARITH_LSHIFT
355 #define ARITH_LSHIFT 273
356 #undef ARITH_SUB
357 #define ARITH_SUB 274
358 #undef ARITH_ADD
359 #define ARITH_ADD 275
360 #undef ARITH_REM
361 #define ARITH_REM 276
362 #undef ARITH_DIV
363 #define ARITH_DIV 277
364 #undef ARITH_MUL
365 #define ARITH_MUL 278
366 #undef ARITH_BNOT
367 #define ARITH_BNOT 279
368 #undef ARITH_NOT
369 #define ARITH_NOT 280
370 #undef ARITH_UNARYPLUS
371 #define ARITH_UNARYPLUS 281
372 #undef ARITH_UNARYMINUS
373 #define ARITH_UNARYMINUS 282
374 #undef YYFINAL
375 #define YYFINAL 14
376 #undef YYLAST
377 #define YYLAST 170
378 #undef YYNTOKENS
379 #define YYNTOKENS 28
380 #undef YYNNTS
381 #define YYNNTS 3
382 #undef YYNRULES
383 #define YYNRULES 26
384 #undef YYNSTATES
385 #define YYNSTATES 52
386 #undef YYUNDEFTOK
387 #define YYUNDEFTOK 2
388 #undef YYMAXUTOK
389 #define YYMAXUTOK 282
390 #undef YYPACT_NINF
391 #define YYPACT_NINF -13
392 #undef YYTABLE_NINF
393 #define YYTABLE_NINF -1
394 #undef yyerrok
395 #define yyerrok (yyerrstatus = 0)
396 #undef yyclearin
397 #define yyclearin (yychar = YYEMPTY)
398 #undef YYEMPTY
399 #define YYEMPTY (-2)
400 #undef YYEOF
401 #define YYEOF 0
402 #undef YYACCEPT
403 #define YYACCEPT goto yyacceptlab
404 #undef YYABORT
405 #define YYABORT goto yyabortlab
406 #undef YYERROR
407 #define YYERROR goto yyerrorlab
408 #undef YYFAIL
409 #define YYFAIL goto yyerrlab
410 #undef YYTERROR
411 #define YYTERROR 1
412 #undef YYERRCODE
413 #define YYERRCODE 256
414 #undef YYPOPSTACK
415 #define YYPOPSTACK (yyvsp--, yyssp--)
416 #undef YY_INT_ALIGNED
417 #define YY_INT_ALIGNED short int
418 #undef FLEX_SCANNER
419 #define FLEX_SCANNER
420 #undef YY_FLEX_MAJOR_VERSION
421 #define YY_FLEX_MAJOR_VERSION 2
422 #undef YY_FLEX_MINOR_VERSION
423 #define YY_FLEX_MINOR_VERSION 5
424 #undef YY_FLEX_SUBMINOR_VERSION
425 #define YY_FLEX_SUBMINOR_VERSION 31
426 #undef FLEX_BETA
427 #define FLEX_BETA
428 #undef FLEXINT_H
429 #define FLEXINT_H
430 #undef INT8_MIN
431 #define INT8_MIN (-128)
432 #undef INT16_MIN
433 #define INT16_MIN (-32767-1)
434 #undef INT32_MIN
435 #define INT32_MIN (-2147483647-1)
436 #undef INT8_MAX
437 #define INT8_MAX (127)
438 #undef INT16_MAX
439 #define INT16_MAX (32767)
440 #undef INT32_MAX
441 #define INT32_MAX (2147483647)
442 #undef UINT8_MAX
443 #define UINT8_MAX (255U)
444 #undef UINT16_MAX
445 #define UINT16_MAX (65535U)
446 #undef UINT32_MAX
447 #define UINT32_MAX (4294967295U)
448 #undef YY_USE_CONST
449 #define YY_USE_CONST
450 #undef YY_USE_CONST
451 #define YY_USE_CONST
452 #undef yyconst
453 #define yyconst const
454 #undef yyconst
455 #define yyconst
456 #undef YY_NULL
457 #define YY_NULL 0
458 #undef BEGIN
459 #define BEGIN (yy_start) = 1 + 2 *
460 #undef YY_START
461 #define YY_START (((yy_start) - 1) / 2)
462 #undef YYSTATE
463 #define YYSTATE YY_START
464 #undef YY_NEW_FILE
465 #define YY_NEW_FILE yyrestart(yyin )
466 #undef YY_END_OF_BUFFER_CHAR
467 #define YY_END_OF_BUFFER_CHAR 0
468 #undef YY_BUF_SIZE
469 #define YY_BUF_SIZE 16384
470 #undef YY_TYPEDEF_YY_BUFFER_STATE
471 #define YY_TYPEDEF_YY_BUFFER_STATE
472 #undef EOB_ACT_CONTINUE_SCAN
473 #define EOB_ACT_CONTINUE_SCAN 0
474 #undef EOB_ACT_END_OF_FILE
475 #define EOB_ACT_END_OF_FILE 1
476 #undef EOB_ACT_LAST_MATCH
477 #define EOB_ACT_LAST_MATCH 2
478 #undef YY_TYPEDEF_YY_SIZE_T
479 #define YY_TYPEDEF_YY_SIZE_T
480 #undef YY_STRUCT_YY_BUFFER_STATE
481 #define YY_STRUCT_YY_BUFFER_STATE
482 #undef YY_BUFFER_NEW
483 #define YY_BUFFER_NEW 0
484 #undef YY_BUFFER_NORMAL
485 #define YY_BUFFER_NORMAL 1
486 #undef YY_BUFFER_EOF_PENDING
487 #define YY_BUFFER_EOF_PENDING 2
488 #undef YY_CURRENT_BUFFER
489 #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
490 #undef YY_CURRENT_BUFFER_LVALUE
491 #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
492 #undef YY_FLUSH_BUFFER
493 #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
494 #undef yy_new_buffer
495 #define yy_new_buffer yy_create_buffer
496 #undef YY_SKIP_YYWRAP
497 #define YY_SKIP_YYWRAP
498 #undef yytext_ptr
499 #define yytext_ptr yytext
500 #undef YY_DO_BEFORE_ACTION
501 #define YY_DO_BEFORE_ACTION \
502 #undef YY_NUM_RULES
503 #define YY_NUM_RULES 29
504 #undef YY_END_OF_BUFFER
505 #define YY_END_OF_BUFFER 30
506 #undef REJECT
507 #define REJECT reject_used_but_not_detected
508 #undef YY_MORE_ADJ
509 #define YY_MORE_ADJ 0
510 #undef YY_RESTORE_YY_MORE_OFFSET
511 #define YY_RESTORE_YY_MORE_OFFSET
512 #undef YY_NO_UNPUT
513 #define YY_NO_UNPUT
514 #undef INITIAL
515 #define INITIAL 0
516 #undef YY_EXTRA_TYPE
517 #define YY_EXTRA_TYPE void *
518 #undef YY_READ_BUF_SIZE
519 #define YY_READ_BUF_SIZE 8192
520 #undef ECHO
521 #define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
522 #undef YY_START_STACK_INCR
523 #define YY_START_STACK_INCR 25
524 #undef YY_DECL_IS_OURS
525 #define YY_DECL_IS_OURS 1
526 #undef YY_DECL
527 #define YY_DECL int yylex (void)
528 #undef YY_USER_ACTION
529 #define YY_USER_ACTION
530 #undef YY_BREAK
531 #define YY_BREAK break;
532 #undef YY_RULE_SETUP
533 #define YY_RULE_SETUP \
534 #undef YY_EXIT_FAILURE
535 #define YY_EXIT_FAILURE 2
536 #undef YYTABLES_NAME
537 #define YYTABLES_NAME "yytables"
538 #undef MAXPWD
539 #define MAXPWD 256
540 #undef signal
541 #define signal bsd_signal
542 #undef ALL
543 #define ALL (E_OPEN|E_CREAT|E_EXEC)
544 #undef EV_EXIT
545 #define EV_EXIT 01 /* exit after evaluating tree */
546 #undef EV_TESTED
547 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
548 #undef EV_BACKCMD
549 #define EV_BACKCMD 04 /* command executing within back quotes */
550 #undef CMDTABLESIZE
551 #define CMDTABLESIZE 31 /* should be prime */
552 #undef ARB
553 #define ARB 1 /* actual size determined at run time */
554 #undef NEWARGS
555 #define NEWARGS 5
556 #undef EOF_NLEFT
557 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
558 #undef _PATH_DEVNULL
559 #define _PATH_DEVNULL "/dev/null"
560 #undef PROFILE
561 #define PROFILE 0
562 #undef SIGSSIZE
563 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
564 #undef MINSIZE
565 #define MINSIZE 504 /* minimum size of a block */
566 #undef DEFINE_OPTIONS
567 #define DEFINE_OPTIONS
568 #undef EOFMARKLEN
569 #define EOFMARKLEN 79
570 #undef OPENBRACE
571 #define OPENBRACE '{'
572 #undef CLOSEBRACE
573 #define CLOSEBRACE '}'
574 #undef EMPTY
575 #define EMPTY -2 /* marks an unused slot in redirtab */
576 #undef signal
577 #define signal bsd_signal
578 #undef sys_signame
579 #define sys_signame sys_siglist
580 #undef S_DFL
581 #define S_DFL 1 /* default signal handling (SIG_DFL) */
582 #undef S_CATCH
583 #define S_CATCH 2 /* signal is caught */
584 #undef S_IGN
585 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
586 #undef S_HARD_IGN
587 #define S_HARD_IGN 4 /* signal is ignored permenantly */
588 #undef S_RESET
589 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
590 #undef OUTBUFSIZ
591 #define OUTBUFSIZ BUFSIZ
592 #undef BLOCK_OUT
593 #define BLOCK_OUT -2 /* output to a fixed block of memory */
594 #undef MEM_OUT
595 #define MEM_OUT -3 /* output to dynamically allocated memory */
596 #undef OUTPUT_ERR
597 #define OUTPUT_ERR 01 /* error occurred on output */
598 #undef TEMPSIZE
599 #define TEMPSIZE 24
600 #undef HAVE_VASPRINTF
601 #define HAVE_VASPRINTF 1
602 #undef VTABSIZE
603 #define VTABSIZE 39
604 #undef VTABSIZE
605 #define VTABSIZE 517
606 #undef main
607 #define main echocmd
608 #undef YYBISON
609 #define YYBISON 1
610 #undef YYSKELETON_NAME
611 #define YYSKELETON_NAME "yacc.c"
612 #undef YYPURE
613 #define YYPURE 0
614 #undef YYLSP_NEEDED
615 #define YYLSP_NEEDED 0
616 #undef ARITH_NUM
617 #define ARITH_NUM 258
618 #undef ARITH_LPAREN
619 #define ARITH_LPAREN 259
620 #undef ARITH_RPAREN
621 #define ARITH_RPAREN 260
622 #undef ARITH_OR
623 #define ARITH_OR 261
624 #undef ARITH_AND
625 #define ARITH_AND 262
626 #undef ARITH_BOR
627 #define ARITH_BOR 263
628 #undef ARITH_BXOR
629 #define ARITH_BXOR 264
630 #undef ARITH_BAND
631 #define ARITH_BAND 265
632 #undef ARITH_NE
633 #define ARITH_NE 266
634 #undef ARITH_EQ
635 #define ARITH_EQ 267
636 #undef ARITH_LE
637 #define ARITH_LE 268
638 #undef ARITH_GE
639 #define ARITH_GE 269
640 #undef ARITH_GT
641 #define ARITH_GT 270
642 #undef ARITH_LT
643 #define ARITH_LT 271
644 #undef ARITH_RSHIFT
645 #define ARITH_RSHIFT 272
646 #undef ARITH_LSHIFT
647 #define ARITH_LSHIFT 273
648 #undef ARITH_SUB
649 #define ARITH_SUB 274
650 #undef ARITH_ADD
651 #define ARITH_ADD 275
652 #undef ARITH_REM
653 #define ARITH_REM 276
654 #undef ARITH_DIV
655 #define ARITH_DIV 277
656 #undef ARITH_MUL
657 #define ARITH_MUL 278
658 #undef ARITH_BNOT
659 #define ARITH_BNOT 279
660 #undef ARITH_NOT
661 #define ARITH_NOT 280
662 #undef ARITH_UNARYPLUS
663 #define ARITH_UNARYPLUS 281
664 #undef ARITH_UNARYMINUS
665 #define ARITH_UNARYMINUS 282
666 #undef YYFINAL
667 #define YYFINAL 14
668 #undef YYLAST
669 #define YYLAST 170
670 #undef YYNTOKENS
671 #define YYNTOKENS 28
672 #undef YYNNTS
673 #define YYNNTS 3
674 #undef YYNRULES
675 #define YYNRULES 26
676 #undef YYNSTATES
677 #define YYNSTATES 52
678 #undef YYUNDEFTOK
679 #define YYUNDEFTOK 2
680 #undef YYMAXUTOK
681 #define YYMAXUTOK 282
682 #undef YYPACT_NINF
683 #define YYPACT_NINF -13
684 #undef YYTABLE_NINF
685 #define YYTABLE_NINF -1
686 #undef yyerrok
687 #define yyerrok (yyerrstatus = 0)
688 #undef yyclearin
689 #define yyclearin (yychar = YYEMPTY)
690 #undef YYEMPTY
691 #define YYEMPTY (-2)
692 #undef YYEOF
693 #define YYEOF 0
694 #undef YYACCEPT
695 #define YYACCEPT goto yyacceptlab
696 #undef YYABORT
697 #define YYABORT goto yyabortlab
698 #undef YYERROR
699 #define YYERROR goto yyerrorlab
700 #undef YYFAIL
701 #define YYFAIL goto yyerrlab
702 #undef YYTERROR
703 #define YYTERROR 1
704 #undef YYERRCODE
705 #define YYERRCODE 256
706 #undef YYPOPSTACK
707 #define YYPOPSTACK (yyvsp--, yyssp--)
708 #undef YY_INT_ALIGNED
709 #define YY_INT_ALIGNED short int
710 #undef FLEX_SCANNER
711 #define FLEX_SCANNER
712 #undef YY_FLEX_MAJOR_VERSION
713 #define YY_FLEX_MAJOR_VERSION 2
714 #undef YY_FLEX_MINOR_VERSION
715 #define YY_FLEX_MINOR_VERSION 5
716 #undef YY_FLEX_SUBMINOR_VERSION
717 #define YY_FLEX_SUBMINOR_VERSION 31
718 #undef FLEX_BETA
719 #define FLEX_BETA
720 #undef FLEXINT_H
721 #define FLEXINT_H
722 #undef INT8_MIN
723 #define INT8_MIN (-128)
724 #undef INT16_MIN
725 #define INT16_MIN (-32767-1)
726 #undef INT32_MIN
727 #define INT32_MIN (-2147483647-1)
728 #undef INT8_MAX
729 #define INT8_MAX (127)
730 #undef INT16_MAX
731 #define INT16_MAX (32767)
732 #undef INT32_MAX
733 #define INT32_MAX (2147483647)
734 #undef UINT8_MAX
735 #define UINT8_MAX (255U)
736 #undef UINT16_MAX
737 #define UINT16_MAX (65535U)
738 #undef UINT32_MAX
739 #define UINT32_MAX (4294967295U)
740 #undef YY_USE_CONST
741 #define YY_USE_CONST
742 #undef YY_USE_CONST
743 #define YY_USE_CONST
744 #undef yyconst
745 #define yyconst const
746 #undef yyconst
747 #define yyconst
748 #undef YY_NULL
749 #define YY_NULL 0
750 #undef BEGIN
751 #define BEGIN (yy_start) = 1 + 2 *
752 #undef YY_START
753 #define YY_START (((yy_start) - 1) / 2)
754 #undef YYSTATE
755 #define YYSTATE YY_START
756 #undef YY_NEW_FILE
757 #define YY_NEW_FILE yyrestart(yyin )
758 #undef YY_END_OF_BUFFER_CHAR
759 #define YY_END_OF_BUFFER_CHAR 0
760 #undef YY_BUF_SIZE
761 #define YY_BUF_SIZE 16384
762 #undef YY_TYPEDEF_YY_BUFFER_STATE
763 #define YY_TYPEDEF_YY_BUFFER_STATE
764 #undef EOB_ACT_CONTINUE_SCAN
765 #define EOB_ACT_CONTINUE_SCAN 0
766 #undef EOB_ACT_END_OF_FILE
767 #define EOB_ACT_END_OF_FILE 1
768 #undef EOB_ACT_LAST_MATCH
769 #define EOB_ACT_LAST_MATCH 2
770 #undef YY_TYPEDEF_YY_SIZE_T
771 #define YY_TYPEDEF_YY_SIZE_T
772 #undef YY_STRUCT_YY_BUFFER_STATE
773 #define YY_STRUCT_YY_BUFFER_STATE
774 #undef YY_BUFFER_NEW
775 #define YY_BUFFER_NEW 0
776 #undef YY_BUFFER_NORMAL
777 #define YY_BUFFER_NORMAL 1
778 #undef YY_BUFFER_EOF_PENDING
779 #define YY_BUFFER_EOF_PENDING 2
780 #undef YY_CURRENT_BUFFER
781 #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
782 #undef YY_CURRENT_BUFFER_LVALUE
783 #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
784 #undef YY_FLUSH_BUFFER
785 #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
786 #undef yy_new_buffer
787 #define yy_new_buffer yy_create_buffer
788 #undef yytext_ptr
789 #define yytext_ptr yytext
790 #undef YY_DO_BEFORE_ACTION
791 #define YY_DO_BEFORE_ACTION \
792 #undef YY_NUM_RULES
793 #define YY_NUM_RULES 29
794 #undef YY_END_OF_BUFFER
795 #define YY_END_OF_BUFFER 30
796 #undef REJECT
797 #define REJECT reject_used_but_not_detected
798 #undef YY_MORE_ADJ
799 #define YY_MORE_ADJ 0
800 #undef YY_RESTORE_YY_MORE_OFFSET
801 #define YY_RESTORE_YY_MORE_OFFSET
802 #undef YY_NO_UNPUT
803 #define YY_NO_UNPUT
804 #undef INITIAL
805 #define INITIAL 0
806 #undef YY_EXTRA_TYPE
807 #define YY_EXTRA_TYPE void *
808 #undef YY_READ_BUF_SIZE
809 #define YY_READ_BUF_SIZE 8192
810 #undef ECHO
811 #define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
812 #undef YY_START_STACK_INCR
813 #define YY_START_STACK_INCR 25
814 #undef YY_DECL_IS_OURS
815 #define YY_DECL_IS_OURS 1
816 #undef YY_DECL
817 #define YY_DECL int yylex (void)
818 #undef YY_USER_ACTION
819 #define YY_USER_ACTION
820 #undef YY_BREAK
821 #define YY_BREAK break;
822 #undef YY_RULE_SETUP
823 #define YY_RULE_SETUP \
824 #undef YY_EXIT_FAILURE
825 #define YY_EXIT_FAILURE 2
826 #undef YYTABLES_NAME
827 #define YYTABLES_NAME "yytables"
828 #undef MAXPWD
829 #define MAXPWD 256
830 #undef ALL
831 #define ALL (E_OPEN|E_CREAT|E_EXEC)
832 #undef EV_EXIT
833 #define EV_EXIT 01 /* exit after evaluating tree */
834 #undef EV_TESTED
835 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
836 #undef EV_BACKCMD
837 #define EV_BACKCMD 04 /* command executing within back quotes */
838 #undef CMDTABLESIZE
839 #define CMDTABLESIZE 31 /* should be prime */
840 #undef ARB
841 #define ARB 1 /* actual size determined at run time */
842 #undef NEWARGS
843 #define NEWARGS 5
844 #undef EOF_NLEFT
845 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
846 #undef _PATH_DEVNULL
847 #define _PATH_DEVNULL "/dev/null"
848 #undef PROFILE
849 #define PROFILE 0
850 #undef SIGSSIZE
851 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
852 #undef MINSIZE
853 #define MINSIZE 504 /* minimum size of a block */
854 #undef DEFINE_OPTIONS
855 #define DEFINE_OPTIONS
856 #undef EOFMARKLEN
857 #define EOFMARKLEN 79
858 #undef OPENBRACE
859 #define OPENBRACE '{'
860 #undef CLOSEBRACE
861 #define CLOSEBRACE '}'
862 #undef EMPTY
863 #define EMPTY -2 /* marks an unused slot in redirtab */
864 #undef S_DFL
865 #define S_DFL 1 /* default signal handling (SIG_DFL) */
866 #undef S_CATCH
867 #define S_CATCH 2 /* signal is caught */
868 #undef S_IGN
869 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
870 #undef S_HARD_IGN
871 #define S_HARD_IGN 4 /* signal is ignored permenantly */
872 #undef S_RESET
873 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
874 #undef OUTBUFSIZ
875 #define OUTBUFSIZ BUFSIZ
876 #undef BLOCK_OUT
877 #define BLOCK_OUT -2 /* output to a fixed block of memory */
878 #undef MEM_OUT
879 #define MEM_OUT -3 /* output to dynamically allocated memory */
880 #undef OUTPUT_ERR
881 #define OUTPUT_ERR 01 /* error occurred on output */
882 #undef TEMPSIZE
883 #define TEMPSIZE 24
884 #undef HAVE_VASPRINTF
885 #define HAVE_VASPRINTF 1
886 #undef VTABSIZE
887 #define VTABSIZE 39
888 #undef VTABSIZE
889 #define VTABSIZE 517
890 #undef main
891 #define main echocmd
892
893
894
895 extern void rmaliases(void);
896
897 extern int loopnest; /* current loop nesting level */
898
899 extern void deletefuncs(void);
900 extern void hash_special_builtins(void);
901
902 struct strpush {
903 struct strpush *prev; /* preceding string on stack */
904 char *prevstring;
905 int prevnleft;
906 int prevlleft;
907 struct alias *ap; /* if push was associated with an alias */
908 };
909
910 struct parsefile {
911 struct parsefile *prev; /* preceding file on stack */
912 int linno; /* current line */
913 int fd; /* file descriptor (or -1 if string) */
914 int nleft; /* number of chars left in this line */
915 int lleft; /* number of chars left in this buffer */
916 char *nextc; /* next char in buffer */
917 char *buf; /* input buffer */
918 struct strpush *strpush; /* for pushing strings at this level */
919 struct strpush basestrpush; /* so pushing one is fast */
920 };
921
922 extern int parselleft; /* copy of parsefile->lleft */
923 extern struct parsefile basepf; /* top level input file */
924 extern char basebuf[BUFSIZ]; /* buffer for top level input file */
925
926 extern pid_t backgndpid; /* pid of last background process */
927 extern int jobctl;
928
929 extern int tokpushback; /* last token pushed back */
930 extern int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
931
932 struct redirtab {
933 struct redirtab *next;
934 short renamed[10];
935 };
936
937 extern struct redirtab *redirlist;
938
939 extern char sigmode[NSIG]; /* current value of signal */
940
941 extern char **environ;
942
943
944
945 /*
946 * Initialization code.
947 */
948
949 void
950 init() {
951
952 /* from exec.c: */
953 {
954 hash_special_builtins();
955 }
956
957 /* from input.c: */
958 {
959 basepf.nextc = basepf.buf = basebuf;
960 }
961
962 /* from var.c: */
963 {
964 char **envp;
965
966 initvar();
967 for (envp = environ ; *envp ; envp++) {
968 if (strchr(*envp, '=')) {
969 setvareq(*envp, VEXPORT|VTEXTFIXED);
970 }
971 }
972 }
973 }
974
975
976
977 /*
978 * This routine is called when an error or an interrupt occurs in an
979 * interactive shell and control is returned to the main command loop.
980 */
981
982 void
983 reset() {
984
985 /* from eval.c: */
986 {
987 evalskip = 0;
988 loopnest = 0;
989 funcnest = 0;
990 }
991
992 /* from input.c: */
993 {
994 if (exception != EXSHELLPROC)
995 parselleft = parsenleft = 0; /* clear input buffer */
996 popallfiles();
997 }
998
999 /* from parser.c: */
1000 {
1001 tokpushback = 0;
1002 checkkwd = 0;
1003 }
1004
1005 /* from redir.c: */
1006 {
1007 while (redirlist)
1008 popredir();
1009 }
1010
1011 /* from output.c: */
1012 {
1013 out1 = &output;
1014 out2 = &errout;
1015 if (memout.buf != NULL) {
1016 ckfree(memout.buf);
1017 memout.buf = NULL;
1018 }
1019 }
1020 }
1021
1022
1023
1024 /*
1025 * This routine is called to initialize the shell to run a shell procedure.
1026 */
1027
1028 void
1029 initshellproc() {
1030
1031 /* from alias.c: */
1032 {
1033 rmaliases();
1034 }
1035
1036 /* from eval.c: */
1037 {
1038 exitstatus = 0;
1039 }
1040
1041 /* from exec.c: */
1042 {
1043 deletefuncs();
1044 }
1045
1046 /* from input.c: */
1047 {
1048 popallfiles();
1049 }
1050
1051 /* from jobs.c: */
1052 {
1053 backgndpid = -1;
1054 #if JOBS
1055 jobctl = 0;
1056 #endif
1057 }
1058
1059 /* from options.c: */
1060 {
1061 int i;
1062
1063 for (i = 0; optlist[i].name; i++)
1064 optlist[i].val = 0;
1065 optschanged();
1066
1067 }
1068
1069 /* from redir.c: */
1070 {
1071 clearredir(0);
1072 }
1073
1074 /* from trap.c: */
1075 {
1076 char *sm;
1077
1078 clear_traps(0);
1079 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
1080 if (*sm == S_IGN)
1081 *sm = S_HARD_IGN;
1082 }
1083 }
1084
1085 /* from var.c: */
1086 {
1087 shprocvar();
1088 }
1089 }
+0
-39
sh/init.h less more
0 /* $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)init.h 8.2 (Berkeley) 5/4/95
34 */
35
36 void init(void);
37 void reset(void);
38 void initshellproc(void);
+0
-531
sh/input.c less more
0 /* $NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
38 #else
39 __RCSID("$NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <stdio.h> /* defines BUFSIZ */
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <string.h>
49
50 /*
51 * This file implements the input routines used by the parser.
52 */
53
54 #include "shell.h"
55 #include "redir.h"
56 #include "syntax.h"
57 #include "input.h"
58 #include "output.h"
59 #include "options.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "alias.h"
63 #include "parser.h"
64 #include "myhistedit.h"
65
66 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
67
68 MKINIT
69 struct strpush {
70 struct strpush *prev; /* preceding string on stack */
71 char *prevstring;
72 int prevnleft;
73 int prevlleft;
74 struct alias *ap; /* if push was associated with an alias */
75 };
76
77 /*
78 * The parsefile structure pointed to by the global variable parsefile
79 * contains information about the current file being read.
80 */
81
82 MKINIT
83 struct parsefile {
84 struct parsefile *prev; /* preceding file on stack */
85 int linno; /* current line */
86 int fd; /* file descriptor (or -1 if string) */
87 int nleft; /* number of chars left in this line */
88 int lleft; /* number of chars left in this buffer */
89 char *nextc; /* next char in buffer */
90 char *buf; /* input buffer */
91 struct strpush *strpush; /* for pushing strings at this level */
92 struct strpush basestrpush; /* so pushing one is fast */
93 };
94
95
96 int plinno = 1; /* input line number */
97 int parsenleft; /* copy of parsefile->nleft */
98 MKINIT int parselleft; /* copy of parsefile->lleft */
99 char *parsenextc; /* copy of parsefile->nextc */
100 MKINIT struct parsefile basepf; /* top level input file */
101 MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */
102 struct parsefile *parsefile = &basepf; /* current input file */
103 int init_editline = 0; /* editline library initialized? */
104 int whichprompt; /* 1 == PS1, 2 == PS2 */
105
106 #if WITH_HISTORY
107 EditLine *el; /* cookie for editline package */
108 #endif
109
110 STATIC void pushfile(void);
111 static int preadfd(void);
112
113 #ifdef mkinit
114 INCLUDE <stdio.h>
115 INCLUDE "input.h"
116 INCLUDE "error.h"
117
118 INIT {
119 basepf.nextc = basepf.buf = basebuf;
120 }
121
122 RESET {
123 if (exception != EXSHELLPROC)
124 parselleft = parsenleft = 0; /* clear input buffer */
125 popallfiles();
126 }
127
128 SHELLPROC {
129 popallfiles();
130 }
131 #endif
132
133
134 /*
135 * Read a line from the script.
136 */
137
138 char *
139 pfgets(char *line, int len)
140 {
141 char *p = line;
142 int nleft = len;
143 int c;
144
145 while (--nleft > 0) {
146 c = pgetc_macro();
147 if (c == PEOF) {
148 if (p == line)
149 return NULL;
150 break;
151 }
152 *p++ = c;
153 if (c == '\n')
154 break;
155 }
156 *p = '\0';
157 return line;
158 }
159
160
161
162 /*
163 * Read a character from the script, returning PEOF on end of file.
164 * Nul characters in the input are silently discarded.
165 */
166
167 int
168 pgetc(void)
169 {
170 return pgetc_macro();
171 }
172
173
174 static int
175 preadfd(void)
176 {
177 int nr;
178 char *buf = parsefile->buf;
179 parsenextc = buf;
180
181 retry:
182 #ifdef WITH_HISTORY
183 if (parsefile->fd == 0 && el) {
184 static const char *rl_cp;
185 static int el_len;
186
187 if (rl_cp == NULL)
188 rl_cp = el_gets(el, &el_len);
189 if (rl_cp == NULL)
190 nr = 0;
191 else {
192 nr = el_len;
193 if (nr > BUFSIZ - 8)
194 nr = BUFSIZ - 8;
195 memcpy(buf, rl_cp, nr);
196 if (nr != el_len) {
197 el_len -= nr;
198 rl_cp += nr;
199 } else
200 rl_cp = 0;
201 }
202
203 } else
204 #endif
205 nr = read(parsefile->fd, buf, BUFSIZ - 8);
206
207
208 if (nr <= 0) {
209 if (nr < 0) {
210 if (errno == EINTR)
211 goto retry;
212 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
213 int flags = fcntl(0, F_GETFL, 0);
214 if (flags >= 0 && flags & O_NONBLOCK) {
215 flags &=~ O_NONBLOCK;
216 if (fcntl(0, F_SETFL, flags) >= 0) {
217 out2str("sh: turning off NDELAY mode\n");
218 goto retry;
219 }
220 }
221 }
222 }
223 nr = -1;
224 }
225 return nr;
226 }
227
228 /*
229 * Refill the input buffer and return the next input character:
230 *
231 * 1) If a string was pushed back on the input, pop it;
232 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
233 * from a string so we can't refill the buffer, return EOF.
234 * 3) If the is more stuff in this buffer, use it else call read to fill it.
235 * 4) Process input up to the next newline, deleting nul characters.
236 */
237
238 int
239 preadbuffer(void)
240 {
241 char *p, *q;
242 int more;
243 int something;
244 char savec;
245
246 if (parsefile->strpush) {
247 popstring();
248 if (--parsenleft >= 0)
249 return (*parsenextc++);
250 }
251 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
252 return PEOF;
253 flushout(&output);
254 flushout(&errout);
255
256 again:
257 if (parselleft <= 0) {
258 if ((parselleft = preadfd()) == -1) {
259 parselleft = parsenleft = EOF_NLEFT;
260 return PEOF;
261 }
262 }
263
264 q = p = parsenextc;
265
266 /* delete nul characters */
267 something = 0;
268 for (more = 1; more;) {
269 switch (*p) {
270 case '\0':
271 p++; /* Skip nul */
272 goto check;
273
274 case '\t':
275 case ' ':
276 break;
277
278 case '\n':
279 parsenleft = q - parsenextc;
280 more = 0; /* Stop processing here */
281 break;
282
283 default:
284 something = 1;
285 break;
286 }
287
288 *q++ = *p++;
289 check:
290 if (--parselleft <= 0) {
291 parsenleft = q - parsenextc - 1;
292 if (parsenleft < 0)
293 goto again;
294 *q = '\0';
295 more = 0;
296 }
297 }
298
299 savec = *q;
300 *q = '\0';
301
302 #ifdef WITH_HISTORY
303 if (parsefile->fd == 0 && hist && something) {
304 HistEvent he;
305 INTOFF;
306 history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
307 parsenextc);
308 INTON;
309 }
310 #endif
311
312 if (vflag) {
313 out2str(parsenextc);
314 flushout(out2);
315 }
316
317 *q = savec;
318
319 return *parsenextc++;
320 }
321
322 /*
323 * Undo the last call to pgetc. Only one character may be pushed back.
324 * PEOF may be pushed back.
325 */
326
327 void
328 pungetc(void)
329 {
330 parsenleft++;
331 parsenextc--;
332 }
333
334 /*
335 * Push a string back onto the input at this current parsefile level.
336 * We handle aliases this way.
337 */
338 void
339 pushstring(char *s, int len, void *ap)
340 {
341 struct strpush *sp;
342
343 INTOFF;
344 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
345 if (parsefile->strpush) {
346 sp = ckmalloc(sizeof (struct strpush));
347 sp->prev = parsefile->strpush;
348 parsefile->strpush = sp;
349 } else
350 sp = parsefile->strpush = &(parsefile->basestrpush);
351 sp->prevstring = parsenextc;
352 sp->prevnleft = parsenleft;
353 sp->prevlleft = parselleft;
354 sp->ap = (struct alias *)ap;
355 if (ap)
356 ((struct alias *)ap)->flag |= ALIASINUSE;
357 parsenextc = s;
358 parsenleft = len;
359 INTON;
360 }
361
362 void
363 popstring(void)
364 {
365 struct strpush *sp = parsefile->strpush;
366
367 INTOFF;
368 parsenextc = sp->prevstring;
369 parsenleft = sp->prevnleft;
370 parselleft = sp->prevlleft;
371 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
372 if (sp->ap)
373 sp->ap->flag &= ~ALIASINUSE;
374 parsefile->strpush = sp->prev;
375 if (sp != &(parsefile->basestrpush))
376 ckfree(sp);
377 INTON;
378 }
379
380 /*
381 * Set the input to take input from a file. If push is set, push the
382 * old input onto the stack first.
383 */
384
385 void
386 setinputfile(const char *fname, int push)
387 {
388 int fd;
389 int fd2;
390
391 INTOFF;
392 if ((fd = open(fname, O_RDONLY)) < 0)
393 error("Can't open %s", fname);
394 if (fd < 10) {
395 fd2 = copyfd(fd, 10);
396 close(fd);
397 if (fd2 < 0)
398 error("Out of file descriptors");
399 fd = fd2;
400 }
401 setinputfd(fd, push);
402 INTON;
403 }
404
405
406 /*
407 * Like setinputfile, but takes an open file descriptor. Call this with
408 * interrupts off.
409 */
410
411 void
412 setinputfd(int fd, int push)
413 {
414 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
415 if (push) {
416 pushfile();
417 parsefile->buf = ckmalloc(BUFSIZ);
418 }
419 if (parsefile->fd > 0)
420 close(parsefile->fd);
421 parsefile->fd = fd;
422 if (parsefile->buf == NULL)
423 parsefile->buf = ckmalloc(BUFSIZ);
424 parselleft = parsenleft = 0;
425 plinno = 1;
426 }
427
428
429 /*
430 * Like setinputfile, but takes input from a string.
431 */
432
433 void
434 setinputstring(char *string, int push)
435 {
436 INTOFF;
437 if (push)
438 pushfile();
439 parsenextc = string;
440 parselleft = parsenleft = strlen(string);
441 parsefile->buf = NULL;
442 plinno = 1;
443 INTON;
444 }
445
446
447
448 /*
449 * To handle the "." command, a stack of input files is used. Pushfile
450 * adds a new entry to the stack and popfile restores the previous level.
451 */
452
453 STATIC void
454 pushfile(void)
455 {
456 struct parsefile *pf;
457
458 parsefile->nleft = parsenleft;
459 parsefile->lleft = parselleft;
460 parsefile->nextc = parsenextc;
461 parsefile->linno = plinno;
462 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
463 pf->prev = parsefile;
464 pf->fd = -1;
465 pf->strpush = NULL;
466 pf->basestrpush.prev = NULL;
467 parsefile = pf;
468 }
469
470
471 void
472 popfile(void)
473 {
474 struct parsefile *pf = parsefile;
475
476 INTOFF;
477 if (pf->fd >= 0)
478 close(pf->fd);
479 if (pf->buf)
480 ckfree(pf->buf);
481 while (pf->strpush)
482 popstring();
483 parsefile = pf->prev;
484 ckfree(pf);
485 parsenleft = parsefile->nleft;
486 parselleft = parsefile->lleft;
487 parsenextc = parsefile->nextc;
488 plinno = parsefile->linno;
489 INTON;
490 }
491
492
493 /*
494 * Return to top level.
495 */
496
497 void
498 popallfiles(void)
499 {
500 while (parsefile != &basepf)
501 popfile();
502 }
503
504
505
506 /*
507 * Close the file(s) that the shell is reading commands from. Called
508 * after a fork is done.
509 *
510 * Takes one arg, vfork, which tells it to not modify its global vars
511 * as it is still running in the parent.
512 *
513 * This code is (probably) unnecessary as the 'close on exec' flag is
514 * set and should be enough. In the vfork case it is definitely wrong
515 * to close the fds as another fork() may be done later to feed data
516 * from a 'here' document into a pipe and we don't want to close the
517 * pipe!
518 */
519
520 void
521 closescript(int vforked)
522 {
523 if (vforked)
524 return;
525 popallfiles();
526 if (parsefile->fd > 0) {
527 close(parsefile->fd);
528 parsefile->fd = 0;
529 }
530 }
+0
-62
sh/input.h less more
0 /* $NetBSD: input.h,v 1.15 2003/08/07 09:05:33 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)input.h 8.2 (Berkeley) 5/4/95
34 */
35
36 /* PEOF (the end of file marker) is defined in syntax.h */
37
38 /*
39 * The input line number. Input.c just defines this variable, and saves
40 * and restores it when files are pushed and popped. The user of this
41 * package must set its value.
42 */
43 extern int plinno;
44 extern int parsenleft; /* number of characters left in input buffer */
45 extern char *parsenextc; /* next character in input buffer */
46 extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */
47
48 char *pfgets(char *, int);
49 int pgetc(void);
50 int preadbuffer(void);
51 void pungetc(void);
52 void pushstring(char *, int, void *);
53 void popstring(void);
54 void setinputfile(const char *, int);
55 void setinputfd(int, int);
56 void setinputstring(char *, int);
57 void popfile(void);
58 void popallfiles(void);
59 void closescript(int);
60
61 #define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
+0
-1487
sh/jobs.c less more
0 /* $NetBSD: jobs.c,v 1.62 2003/12/18 00:56:05 christos Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: jobs.c,v 1.62 2003/12/18 00:56:05 christos Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <fcntl.h>
44 #include <signal.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #define _PATH_DEVNULL "/dev/null"
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #ifdef BSD
52 #include <sys/wait.h>
53 #include <sys/time.h>
54 #include <sys/resource.h>
55 #endif
56 #include <sys/wait.h>
57 #define killpg(s,i) kill(-(s),i)
58 #include <sys/ioctl.h>
59
60 #include "shell.h"
61 #if JOBS
62 #if OLD_TTY_DRIVER
63 #include "sgtty.h"
64 #else
65 #include <termios.h>
66 #endif
67 #undef CEOF /* syntax.h redefines this */
68 #endif
69 #include "redir.h"
70 #include "show.h"
71 #include "main.h"
72 #include "parser.h"
73 #include "nodes.h"
74 #include "jobs.h"
75 #include "options.h"
76 #include "trap.h"
77 #include "syntax.h"
78 #include "input.h"
79 #include "output.h"
80 #include "memalloc.h"
81 #include "error.h"
82 #include "mystring.h"
83
84 // Use of process groups is disabled to allow adb shell children to terminate when the shell dies
85 #define USE_PROCESS_GROUPS
86
87
88 static struct job *jobtab; /* array of jobs */
89 static int njobs; /* size of array */
90 static int jobs_invalid; /* set in child */
91 MKINIT pid_t backgndpid = -1; /* pid of last background process */
92 #if JOBS
93 int initialpgrp; /* pgrp of shell on invocation */
94 static int curjob = -1; /* current job */
95 #endif
96 static int ttyfd = -1;
97
98 STATIC void restartjob(struct job *);
99 STATIC void freejob(struct job *);
100 STATIC struct job *getjob(const char *, int);
101 STATIC int dowait(int, struct job *);
102 STATIC int onsigchild(void);
103 STATIC int waitproc(int, struct job *, int *);
104 STATIC void cmdtxt(union node *);
105 STATIC void cmdlist(union node *, int);
106 STATIC void cmdputs(const char *);
107
108 #ifdef OLD_TTY_DRIVER
109 static pid_t tcgetpgrp(int fd);
110 static int tcsetpgrp(int fd, pid_t pgrp);
111
112 static pid_t
113 tcgetpgrp(int fd)
114 {
115 pid_t pgrp;
116 if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1)
117 return -1;
118 else
119 return pgrp;
120 }
121
122 static int
123 tcsetpgrp(int fd, pid_tpgrp)
124 {
125 return ioctl(fd, TIOCSPGRP, (char *)&pgrp);
126 }
127 #endif
128
129 /*
130 * Turn job control on and off.
131 *
132 * Note: This code assumes that the third arg to ioctl is a character
133 * pointer, which is true on Berkeley systems but not System V. Since
134 * System V doesn't have job control yet, this isn't a problem now.
135 */
136
137 MKINIT int jobctl;
138
139 void
140 setjobctl(int on)
141 {
142 #ifdef OLD_TTY_DRIVER
143 int ldisc;
144 #endif
145
146 if (on == jobctl || rootshell == 0)
147 return;
148 if (on) {
149 #if defined(FIOCLEX) || defined(FD_CLOEXEC)
150 int err;
151 int i;
152 if (ttyfd != -1)
153 close(ttyfd);
154 if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
155 for (i = 0; i < 3; i++) {
156 if (isatty(i) && (ttyfd = dup(i)) != -1)
157 break;
158 }
159 if (i == 3)
160 goto out;
161 }
162 /* Move to a high fd */
163 for (i = 10; i > 2; i--) {
164 if ((err = fcntl(ttyfd, F_DUPFD, (1 << i) - 1)) != -1)
165 break;
166 }
167 if (err != -1) {
168 close(ttyfd);
169 ttyfd = err;
170 }
171 #ifdef FIOCLEX
172 err = ioctl(ttyfd, FIOCLEX, 0);
173 #elif FD_CLOEXEC
174 err = fcntl(ttyfd, F_SETFD,
175 fcntl(ttyfd, F_GETFD, 0) | FD_CLOEXEC);
176 #endif
177 if (err == -1) {
178 close(ttyfd);
179 ttyfd = -1;
180 goto out;
181 }
182 #else
183 out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
184 goto out;
185 #endif
186 do { /* while we are in the background */
187 if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
188 out:
189 out2str("sh: can't access tty; job control turned off\n");
190 mflag = 0;
191 return;
192 }
193 if (initialpgrp == -1)
194 initialpgrp = getpgrp();
195 else if (initialpgrp != getpgrp()) {
196 killpg(0, SIGTTIN);
197 continue;
198 }
199 } while (0);
200
201 #ifdef OLD_TTY_DRIVER
202 if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
203 || ldisc != NTTYDISC) {
204 out2str("sh: need new tty driver to run job control; job control turned off\n");
205 mflag = 0;
206 return;
207 }
208 #endif
209 setsignal(SIGTSTP, 0);
210 setsignal(SIGTTOU, 0);
211 setsignal(SIGTTIN, 0);
212 #ifdef USE_PROCESS_GROUPS
213 if (getpgid(0) != rootpid && setpgid(0, rootpid) == -1)
214 error("Cannot set process group (%s) at %d",
215 strerror(errno), __LINE__);
216 if (tcsetpgrp(ttyfd, rootpid) == -1)
217 error("Cannot set tty process group (%s) at %d",
218 strerror(errno), __LINE__);
219 #endif
220 } else { /* turning job control off */
221 #ifdef USE_PROCESS_GROUPS
222 if (getpgid(0) != initialpgrp && setpgid(0, initialpgrp) == -1)
223 error("Cannot set process group (%s) at %d",
224 strerror(errno), __LINE__);
225 if (tcsetpgrp(ttyfd, initialpgrp) == -1)
226 error("Cannot set tty process group (%s) at %d",
227 strerror(errno), __LINE__);
228 #endif
229 close(ttyfd);
230 ttyfd = -1;
231 setsignal(SIGTSTP, 0);
232 setsignal(SIGTTOU, 0);
233 setsignal(SIGTTIN, 0);
234 }
235 jobctl = on;
236 }
237
238
239 #ifdef mkinit
240 INCLUDE <stdlib.h>
241
242 SHELLPROC {
243 backgndpid = -1;
244 #if JOBS
245 jobctl = 0;
246 #endif
247 }
248
249 #endif
250
251
252
253 #if JOBS
254 int
255 fgcmd(int argc, char **argv)
256 {
257 struct job *jp;
258 int i;
259 int status;
260
261 nextopt("");
262 jp = getjob(*argptr, 0);
263 if (jp->jobctl == 0)
264 error("job not created under job control");
265 out1fmt("%s", jp->ps[0].cmd);
266 for (i = 1; i < jp->nprocs; i++)
267 out1fmt(" | %s", jp->ps[i].cmd );
268 out1c('\n');
269 flushall();
270
271 for (i = 0; i < jp->nprocs; i++)
272 if (tcsetpgrp(ttyfd, jp->ps[i].pid) != -1)
273 break;
274
275 if (i >= jp->nprocs) {
276 error("Cannot set tty process group (%s) at %d",
277 strerror(errno), __LINE__);
278 }
279 restartjob(jp);
280 INTOFF;
281 status = waitforjob(jp);
282 INTON;
283 return status;
284 }
285
286 static void
287 set_curjob(struct job *jp, int mode)
288 {
289 struct job *jp1, *jp2;
290 int i, ji;
291
292 ji = jp - jobtab;
293
294 /* first remove from list */
295 if (ji == curjob)
296 curjob = jp->prev_job;
297 else {
298 for (i = 0; i < njobs; i++) {
299 if (jobtab[i].prev_job != ji)
300 continue;
301 jobtab[i].prev_job = jp->prev_job;
302 break;
303 }
304 }
305
306 /* Then re-insert in correct position */
307 switch (mode) {
308 case 0: /* job being deleted */
309 jp->prev_job = -1;
310 break;
311 case 1: /* newly created job or backgrounded job,
312 put after all stopped jobs. */
313 if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) {
314 for (jp1 = jobtab + curjob; ; jp1 = jp2) {
315 if (jp1->prev_job == -1)
316 break;
317 jp2 = jobtab + jp1->prev_job;
318 if (jp2->state != JOBSTOPPED)
319 break;
320 }
321 jp->prev_job = jp1->prev_job;
322 jp1->prev_job = ji;
323 break;
324 }
325 /* FALLTHROUGH */
326 case 2: /* newly stopped job - becomes curjob */
327 jp->prev_job = curjob;
328 curjob = ji;
329 break;
330 }
331 }
332
333 int
334 bgcmd(int argc, char **argv)
335 {
336 struct job *jp;
337 int i;
338
339 nextopt("");
340 do {
341 jp = getjob(*argptr, 0);
342 if (jp->jobctl == 0)
343 error("job not created under job control");
344 set_curjob(jp, 1);
345 out1fmt("[%ld] %s", (long)(jp - jobtab + 1), jp->ps[0].cmd);
346 for (i = 1; i < jp->nprocs; i++)
347 out1fmt(" | %s", jp->ps[i].cmd );
348 out1c('\n');
349 flushall();
350 restartjob(jp);
351 } while (*argptr && *++argptr);
352 return 0;
353 }
354
355
356 STATIC void
357 restartjob(struct job *jp)
358 {
359 struct procstat *ps;
360 int i;
361
362 if (jp->state == JOBDONE)
363 return;
364 INTOFF;
365 for (i = 0; i < jp->nprocs; i++)
366 if (killpg(jp->ps[i].pid, SIGCONT) != -1)
367 break;
368 if (i >= jp->nprocs)
369 error("Cannot continue job (%s)", strerror(errno));
370 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
371 if (WIFSTOPPED(ps->status)) {
372 ps->status = -1;
373 jp->state = JOBRUNNING;
374 }
375 }
376 INTON;
377 }
378 #endif
379
380 static void
381 showjob(struct output *out, struct job *jp, int mode)
382 {
383 int procno;
384 int st;
385 struct procstat *ps;
386 int col;
387 char s[64];
388
389 #if JOBS
390 if (mode & SHOW_PGID) {
391 /* just output process (group) id of pipeline */
392 outfmt(out, "%ld\n", (long)jp->ps->pid);
393 return;
394 }
395 #endif
396
397 procno = jp->nprocs;
398 if (!procno)
399 return;
400
401 if (mode & SHOW_PID)
402 mode |= SHOW_MULTILINE;
403
404 if ((procno > 1 && !(mode & SHOW_MULTILINE))
405 || (mode & SHOW_SIGNALLED)) {
406 /* See if we have more than one status to report */
407 ps = jp->ps;
408 st = ps->status;
409 do {
410 int st1 = ps->status;
411 if (st1 != st)
412 /* yes - need multi-line output */
413 mode |= SHOW_MULTILINE;
414 if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
415 continue;
416 if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
417 && st1 != SIGINT && st1 != SIGPIPE))
418 mode |= SHOW_ISSIG;
419
420 } while (ps++, --procno);
421 procno = jp->nprocs;
422 }
423
424 if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
425 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
426 TRACE(("showjob: freeing job %d\n", jp - jobtab + 1));
427 freejob(jp);
428 }
429 return;
430 }
431
432 for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */
433 if (ps == jp->ps)
434 fmtstr(s, 16, "[%ld] %c ",
435 (long)(jp - jobtab + 1),
436 #if JOBS
437 jp == jobtab + curjob ? '+' :
438 curjob != -1 && jp == jobtab +
439 jobtab[curjob].prev_job ? '-' :
440 #endif
441 ' ');
442 else
443 fmtstr(s, 16, " " );
444 col = strlen(s);
445 if (mode & SHOW_PID) {
446 fmtstr(s + col, 16, "%ld ", (long)ps->pid);
447 col += strlen(s + col);
448 }
449 if (ps->status == -1) {
450 scopy("Running", s + col);
451 } else if (WIFEXITED(ps->status)) {
452 st = WEXITSTATUS(ps->status);
453 if (st)
454 fmtstr(s + col, 16, "Done(%d)", st);
455 else
456 fmtstr(s + col, 16, "Done");
457 } else {
458 #if JOBS
459 if (WIFSTOPPED(ps->status))
460 st = WSTOPSIG(ps->status);
461 else /* WIFSIGNALED(ps->status) */
462 #endif
463 st = WTERMSIG(ps->status);
464 st &= 0x7f;
465 if (st < NSIG && sys_siglist[st])
466 scopyn(sys_siglist[st], s + col, 32);
467 else
468 fmtstr(s + col, 16, "Signal %d", st);
469 if (WCOREDUMP(ps->status)) {
470 col += strlen(s + col);
471 scopyn(" (core dumped)", s + col, 64 - col);
472 }
473 }
474 col += strlen(s + col);
475 outstr(s, out);
476 do {
477 outc(' ', out);
478 col++;
479 } while (col < 30);
480 outstr(ps->cmd, out);
481 if (mode & SHOW_MULTILINE) {
482 if (procno > 0) {
483 outc(' ', out);
484 outc('|', out);
485 }
486 } else {
487 while (--procno >= 0)
488 outfmt(out, " | %s", (++ps)->cmd );
489 }
490 outc('\n', out);
491 }
492 flushout(out);
493 jp->changed = 0;
494 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
495 freejob(jp);
496 }
497
498
499 int
500 jobscmd(int argc, char **argv)
501 {
502 int mode, m;
503 int sv = jobs_invalid;
504
505 jobs_invalid = 0;
506 mode = 0;
507 while ((m = nextopt("lp")))
508 if (m == 'l')
509 mode = SHOW_PID;
510 else
511 mode = SHOW_PGID;
512 if (*argptr)
513 do
514 showjob(out1, getjob(*argptr,0), mode);
515 while (*++argptr);
516 else
517 showjobs(out1, mode);
518 jobs_invalid = sv;
519 return 0;
520 }
521
522
523 /*
524 * Print a list of jobs. If "change" is nonzero, only print jobs whose
525 * statuses have changed since the last call to showjobs.
526 *
527 * If the shell is interrupted in the process of creating a job, the
528 * result may be a job structure containing zero processes. Such structures
529 * will be freed here.
530 */
531
532 void
533 showjobs(struct output *out, int mode)
534 {
535 int jobno;
536 struct job *jp;
537 int silent = 0, gotpid;
538
539 TRACE(("showjobs(%x) called\n", mode));
540
541 /* If not even one one job changed, there is nothing to do */
542 gotpid = dowait(0, NULL);
543 while (dowait(0, NULL) > 0)
544 continue;
545 #ifdef JOBS
546 /*
547 * Check if we are not in our foreground group, and if not
548 * put us in it.
549 */
550 if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) {
551 if (tcsetpgrp(ttyfd, getpid()) == -1)
552 error("Cannot set tty process group (%s) at %d",
553 strerror(errno), __LINE__);
554 TRACE(("repaired tty process group\n"));
555 silent = 1;
556 }
557 #endif
558 if (jobs_invalid)
559 return;
560
561 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
562 if (!jp->used)
563 continue;
564 if (jp->nprocs == 0) {
565 freejob(jp);
566 continue;
567 }
568 if ((mode & SHOW_CHANGED) && !jp->changed)
569 continue;
570 if (silent && jp->changed) {
571 jp->changed = 0;
572 continue;
573 }
574 showjob(out, jp, mode);
575 }
576 }
577
578 /*
579 * Mark a job structure as unused.
580 */
581
582 STATIC void
583 freejob(struct job *jp)
584 {
585 INTOFF;
586 if (jp->ps != &jp->ps0) {
587 ckfree(jp->ps);
588 jp->ps = &jp->ps0;
589 }
590 jp->nprocs = 0;
591 jp->used = 0;
592 #if JOBS
593 set_curjob(jp, 0);
594 #endif
595 INTON;
596 }
597
598
599
600 int
601 waitcmd(int argc, char **argv)
602 {
603 struct job *job;
604 int status, retval = 127;
605 struct job *jp;
606
607 nextopt("");
608
609 if (!*argptr) {
610 /* wait for all jobs */
611 jp = jobtab;
612 if (jobs_invalid)
613 return 0;
614 for (;;) {
615 if (jp >= jobtab + njobs) {
616 /* no running procs */
617 return 0;
618 }
619 if (!jp->used || jp->state != JOBRUNNING) {
620 jp++;
621 continue;
622 }
623 if (dowait(1, (struct job *)NULL) == -1)
624 return 128 + SIGINT;
625 jp = jobtab;
626 }
627 }
628
629 for (; *argptr; argptr++) {
630 job = getjob(*argptr, 1);
631 if (!job) {
632 retval = 127;
633 continue;
634 }
635 /* loop until process terminated or stopped */
636 while (job->state == JOBRUNNING) {
637 if (dowait(1, (struct job *)NULL) == -1)
638 return 128 + SIGINT;
639 }
640 status = job->ps[job->nprocs].status;
641 if (WIFEXITED(status))
642 retval = WEXITSTATUS(status);
643 #if JOBS
644 else if (WIFSTOPPED(status))
645 retval = WSTOPSIG(status) + 128;
646 #endif
647 else {
648 /* XXX: limits number of signals */
649 retval = WTERMSIG(status) + 128;
650 }
651 if (!iflag)
652 freejob(job);
653 }
654 return retval;
655 }
656
657
658
659 int
660 jobidcmd(int argc, char **argv)
661 {
662 struct job *jp;
663 int i;
664
665 nextopt("");
666 jp = getjob(*argptr, 0);
667 for (i = 0 ; i < jp->nprocs ; ) {
668 out1fmt("%ld", (long)jp->ps[i].pid);
669 out1c(++i < jp->nprocs ? ' ' : '\n');
670 }
671 return 0;
672 }
673
674 int
675 getjobpgrp(const char *name)
676 {
677 struct job *jp;
678
679 jp = getjob(name, 1);
680 if (jp == 0)
681 return 0;
682 return -jp->ps[0].pid;
683 }
684
685 /*
686 * Convert a job name to a job structure.
687 */
688
689 STATIC struct job *
690 getjob(const char *name, int noerror)
691 {
692 int jobno = -1;
693 struct job *jp;
694 int pid;
695 int i;
696 const char *err_msg = "No such job: %s";
697
698 if (name == NULL) {
699 #if JOBS
700 jobno = curjob;
701 #endif
702 err_msg = "No current job";
703 } else if (name[0] == '%') {
704 if (is_number(name + 1)) {
705 jobno = number(name + 1) - 1;
706 } else if (!name[2]) {
707 switch (name[1]) {
708 #if JOBS
709 case 0:
710 case '+':
711 case '%':
712 jobno = curjob;
713 err_msg = "No current job";
714 break;
715 case '-':
716 jobno = curjob;
717 if (jobno != -1)
718 jobno = jobtab[jobno].prev_job;
719 err_msg = "No previous job";
720 break;
721 #endif
722 default:
723 goto check_pattern;
724 }
725 } else {
726 struct job *found;
727 check_pattern:
728 found = NULL;
729 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
730 if (!jp->used || jp->nprocs <= 0)
731 continue;
732 if ((name[1] == '?'
733 && strstr(jp->ps[0].cmd, name + 2))
734 || prefix(name + 1, jp->ps[0].cmd)) {
735 if (found) {
736 err_msg = "%s: ambiguous";
737 found = 0;
738 break;
739 }
740 found = jp;
741 }
742 }
743 if (found)
744 return found;
745 }
746
747 } else if (is_number(name)) {
748 pid = number(name);
749 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
750 if (jp->used && jp->nprocs > 0
751 && jp->ps[jp->nprocs - 1].pid == pid)
752 return jp;
753 }
754 }
755
756 if (!jobs_invalid && jobno >= 0 && jobno < njobs) {
757 jp = jobtab + jobno;
758 if (jp->used)
759 return jp;
760 }
761 if (!noerror)
762 error(err_msg, name);
763 return 0;
764 }
765
766
767
768 /*
769 * Return a new job structure,
770 */
771
772 struct job *
773 makejob(union node *node, int nprocs)
774 {
775 int i;
776 struct job *jp;
777
778 if (jobs_invalid) {
779 for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
780 if (jp->used)
781 freejob(jp);
782 }
783 jobs_invalid = 0;
784 }
785
786 for (i = njobs, jp = jobtab ; ; jp++) {
787 if (--i < 0) {
788 INTOFF;
789 if (njobs == 0) {
790 jobtab = ckmalloc(4 * sizeof jobtab[0]);
791 } else {
792 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
793 memcpy(jp, jobtab, njobs * sizeof jp[0]);
794 /* Relocate `ps' pointers */
795 for (i = 0; i < njobs; i++)
796 if (jp[i].ps == &jobtab[i].ps0)
797 jp[i].ps = &jp[i].ps0;
798 ckfree(jobtab);
799 jobtab = jp;
800 }
801 jp = jobtab + njobs;
802 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
803 INTON;
804 break;
805 }
806 if (jp->used == 0)
807 break;
808 }
809 INTOFF;
810 jp->state = JOBRUNNING;
811 jp->used = 1;
812 jp->changed = 0;
813 jp->nprocs = 0;
814 #if JOBS
815 jp->jobctl = jobctl;
816 set_curjob(jp, 1);
817 #endif
818 if (nprocs > 1) {
819 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
820 } else {
821 jp->ps = &jp->ps0;
822 }
823 INTON;
824 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
825 jp - jobtab + 1));
826 return jp;
827 }
828
829
830 /*
831 * Fork off a subshell. If we are doing job control, give the subshell its
832 * own process group. Jp is a job structure that the job is to be added to.
833 * N is the command that will be evaluated by the child. Both jp and n may
834 * be NULL. The mode parameter can be one of the following:
835 * FORK_FG - Fork off a foreground process.
836 * FORK_BG - Fork off a background process.
837 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
838 * process group even if job control is on.
839 *
840 * When job control is turned off, background processes have their standard
841 * input redirected to /dev/null (except for the second and later processes
842 * in a pipeline).
843 */
844
845 int
846 forkshell(struct job *jp, union node *n, int mode)
847 {
848 int pid;
849
850 TRACE(("forkshell(%%%d, %p, %d) called\n", jp - jobtab, n, mode));
851 switch ((pid = fork())) {
852 case -1:
853 TRACE(("Fork failed, errno=%d\n", errno));
854 INTON;
855 error("Cannot fork");
856 break;
857 case 0:
858 forkchild(jp, n, mode, 0);
859 return 0;
860 default:
861 return forkparent(jp, n, mode, pid);
862 }
863 }
864
865 int
866 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
867 {
868 int pgrp;
869
870 if (rootshell && mode != FORK_NOJOB && mflag) {
871 if (jp == NULL || jp->nprocs == 0)
872 pgrp = pid;
873 else
874 pgrp = jp->ps[0].pid;
875 #ifdef USE_PROCESS_GROUPS
876 /* This can fail because we are doing it in the child also */
877 (void)setpgid(pid, pgrp);
878 #endif
879 }
880 if (mode == FORK_BG)
881 backgndpid = pid; /* set $! */
882 if (jp) {
883 struct procstat *ps = &jp->ps[jp->nprocs++];
884 ps->pid = pid;
885 ps->status = -1;
886 ps->cmd[0] = 0;
887 if (/* iflag && rootshell && */ n)
888 commandtext(ps, n);
889 }
890 TRACE(("In parent shell: child = %d\n", pid));
891 return pid;
892 }
893
894 void
895 forkchild(struct job *jp, union node *n, int mode, int vforked)
896 {
897 int wasroot;
898 int pgrp;
899 const char *devnull = _PATH_DEVNULL;
900 const char *nullerr = "Can't open %s";
901
902 wasroot = rootshell;
903 TRACE(("Child shell %d\n", getpid()));
904 if (!vforked)
905 rootshell = 0;
906
907 closescript(vforked);
908 clear_traps(vforked);
909 #if JOBS
910 if (!vforked)
911 jobctl = 0; /* do job control only in root shell */
912 if (wasroot && mode != FORK_NOJOB && mflag) {
913 if (jp == NULL || jp->nprocs == 0)
914 pgrp = getpid();
915 else
916 pgrp = jp->ps[0].pid;
917 #ifdef USE_PROCESS_GROUPS
918 /* This can fail because we are doing it in the parent also */
919 (void)setpgid(0, pgrp);
920 if (mode == FORK_FG) {
921 if (tcsetpgrp(ttyfd, pgrp) == -1)
922 error("Cannot set tty process group (%s) at %d",
923 strerror(errno), __LINE__);
924 }
925 #endif
926 setsignal(SIGTSTP, vforked);
927 setsignal(SIGTTOU, vforked);
928 } else if (mode == FORK_BG) {
929 ignoresig(SIGINT, vforked);
930 ignoresig(SIGQUIT, vforked);
931 if ((jp == NULL || jp->nprocs == 0) &&
932 ! fd0_redirected_p ()) {
933 close(0);
934 if (open(devnull, O_RDONLY) != 0)
935 error(nullerr, devnull);
936 }
937 }
938 #else
939 if (mode == FORK_BG) {
940 ignoresig(SIGINT, vforked);
941 ignoresig(SIGQUIT, vforked);
942 if ((jp == NULL || jp->nprocs == 0) &&
943 ! fd0_redirected_p ()) {
944 close(0);
945 if (open(devnull, O_RDONLY) != 0)
946 error(nullerr, devnull);
947 }
948 }
949 #endif
950 if (wasroot && iflag) {
951 setsignal(SIGINT, vforked);
952 setsignal(SIGQUIT, vforked);
953 setsignal(SIGTERM, vforked);
954 }
955
956 if (!vforked)
957 jobs_invalid = 1;
958 }
959
960 /*
961 * Wait for job to finish.
962 *
963 * Under job control we have the problem that while a child process is
964 * running interrupts generated by the user are sent to the child but not
965 * to the shell. This means that an infinite loop started by an inter-
966 * active user may be hard to kill. With job control turned off, an
967 * interactive user may place an interactive program inside a loop. If
968 * the interactive program catches interrupts, the user doesn't want
969 * these interrupts to also abort the loop. The approach we take here
970 * is to have the shell ignore interrupt signals while waiting for a
971 * forground process to terminate, and then send itself an interrupt
972 * signal if the child process was terminated by an interrupt signal.
973 * Unfortunately, some programs want to do a bit of cleanup and then
974 * exit on interrupt; unless these processes terminate themselves by
975 * sending a signal to themselves (instead of calling exit) they will
976 * confuse this approach.
977 */
978
979 int
980 waitforjob(struct job *jp)
981 {
982 #if JOBS
983 int mypgrp = getpgrp();
984 #endif
985 int status;
986 int st;
987
988 INTOFF;
989 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
990 while (jp->state == JOBRUNNING) {
991 dowait(1, jp);
992 }
993 #if JOBS
994 if (jp->jobctl) {
995 if (tcsetpgrp(ttyfd, mypgrp) == -1)
996 error("Cannot set tty process group (%s) at %d",
997 strerror(errno), __LINE__);
998 }
999 if (jp->state == JOBSTOPPED && curjob != jp - jobtab)
1000 set_curjob(jp, 2);
1001 #endif
1002 status = jp->ps[jp->nprocs - 1].status;
1003 /* convert to 8 bits */
1004 if (WIFEXITED(status))
1005 st = WEXITSTATUS(status);
1006 #if JOBS
1007 else if (WIFSTOPPED(status))
1008 st = WSTOPSIG(status) + 128;
1009 #endif
1010 else
1011 st = WTERMSIG(status) + 128;
1012 TRACE(("waitforjob: job %d, nproc %d, status %x, st %x\n",
1013 jp - jobtab + 1, jp->nprocs, status, st ));
1014 #if JOBS
1015 if (jp->jobctl) {
1016 /*
1017 * This is truly gross.
1018 * If we're doing job control, then we did a TIOCSPGRP which
1019 * caused us (the shell) to no longer be in the controlling
1020 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
1021 * intuit from the subprocess exit status whether a SIGINT
1022 * occurred, and if so interrupt ourselves. Yuck. - mycroft
1023 */
1024 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1025 raise(SIGINT);
1026 }
1027 #endif
1028 if (! JOBS || jp->state == JOBDONE)
1029 freejob(jp);
1030 INTON;
1031 return st;
1032 }
1033
1034
1035
1036 /*
1037 * Wait for a process to terminate.
1038 */
1039
1040 STATIC int
1041 dowait(int block, struct job *job)
1042 {
1043 int pid;
1044 int status;
1045 struct procstat *sp;
1046 struct job *jp;
1047 struct job *thisjob;
1048 int done;
1049 int stopped;
1050 extern volatile char gotsig[];
1051
1052 TRACE(("dowait(%d) called\n", block));
1053 do {
1054 pid = waitproc(block, job, &status);
1055 TRACE(("wait returns pid %d, status %d\n", pid, status));
1056 } while (pid == -1 && errno == EINTR && gotsig[SIGINT - 1] == 0);
1057 if (pid <= 0)
1058 return pid;
1059 INTOFF;
1060 thisjob = NULL;
1061 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1062 if (jp->used) {
1063 done = 1;
1064 stopped = 1;
1065 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1066 if (sp->pid == -1)
1067 continue;
1068 if (sp->pid == pid) {
1069 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - jobtab + 1, pid, sp->status, status));
1070 sp->status = status;
1071 thisjob = jp;
1072 }
1073 if (sp->status == -1)
1074 stopped = 0;
1075 else if (WIFSTOPPED(sp->status))
1076 done = 0;
1077 }
1078 if (stopped) { /* stopped or done */
1079 int state = done ? JOBDONE : JOBSTOPPED;
1080 if (jp->state != state) {
1081 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
1082 jp->state = state;
1083 #if JOBS
1084 if (done)
1085 set_curjob(jp, 0);
1086 #endif
1087 }
1088 }
1089 }
1090 }
1091
1092 if (thisjob && thisjob->state != JOBRUNNING) {
1093 int mode = 0;
1094 if (!rootshell || !iflag)
1095 mode = SHOW_SIGNALLED;
1096 if (job == thisjob)
1097 mode = SHOW_SIGNALLED | SHOW_NO_FREE;
1098 if (mode)
1099 showjob(out2, thisjob, mode);
1100 else {
1101 TRACE(("Not printing status, rootshell=%d, job=%p\n",
1102 rootshell, job));
1103 thisjob->changed = 1;
1104 }
1105 }
1106
1107 INTON;
1108 return pid;
1109 }
1110
1111
1112
1113 /*
1114 * Do a wait system call. If job control is compiled in, we accept
1115 * stopped processes. If block is zero, we return a value of zero
1116 * rather than blocking.
1117 *
1118 * System V doesn't have a non-blocking wait system call. It does
1119 * have a SIGCLD signal that is sent to a process when one of it's
1120 * children dies. The obvious way to use SIGCLD would be to install
1121 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
1122 * was received, and have waitproc bump another counter when it got
1123 * the status of a process. Waitproc would then know that a wait
1124 * system call would not block if the two counters were different.
1125 * This approach doesn't work because if a process has children that
1126 * have not been waited for, System V will send it a SIGCLD when it
1127 * installs a signal handler for SIGCLD. What this means is that when
1128 * a child exits, the shell will be sent SIGCLD signals continuously
1129 * until is runs out of stack space, unless it does a wait call before
1130 * restoring the signal handler. The code below takes advantage of
1131 * this (mis)feature by installing a signal handler for SIGCLD and
1132 * then checking to see whether it was called. If there are any
1133 * children to be waited for, it will be.
1134 *
1135 * If neither SYSV nor BSD is defined, we don't implement nonblocking
1136 * waits at all. In this case, the user will not be informed when
1137 * a background process until the next time she runs a real program
1138 * (as opposed to running a builtin command or just typing return),
1139 * and the jobs command may give out of date information.
1140 */
1141
1142 #ifdef SYSV
1143 STATIC int gotsigchild;
1144
1145 STATIC int onsigchild() {
1146 gotsigchild = 1;
1147 }
1148 #endif
1149
1150
1151 STATIC int
1152 waitproc(int block, struct job *jp, int *status)
1153 {
1154 #ifdef BSD
1155 int flags = 0;
1156
1157 #if JOBS
1158 if (jp != NULL && jp->jobctl)
1159 flags |= WUNTRACED;
1160 #endif
1161 if (block == 0)
1162 flags |= WNOHANG;
1163 return wait3(status, flags, (struct rusage *)NULL);
1164 #else
1165 #ifdef SYSV
1166 int (*save)();
1167
1168 if (block == 0) {
1169 gotsigchild = 0;
1170 save = signal(SIGCLD, onsigchild);
1171 signal(SIGCLD, save);
1172 if (gotsigchild == 0)
1173 return 0;
1174 }
1175 return wait(status);
1176 #else
1177 if (block == 0)
1178 return 0;
1179 return wait(status);
1180 #endif
1181 #endif
1182 }
1183
1184 /*
1185 * return 1 if there are stopped jobs, otherwise 0
1186 */
1187 int job_warning = 0;
1188 int
1189 stoppedjobs(void)
1190 {
1191 int jobno;
1192 struct job *jp;
1193
1194 if (job_warning || jobs_invalid)
1195 return (0);
1196 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1197 if (jp->used == 0)
1198 continue;
1199 if (jp->state == JOBSTOPPED) {
1200 out2str("You have stopped jobs.\n");
1201 job_warning = 2;
1202 return (1);
1203 }
1204 }
1205
1206 return (0);
1207 }
1208
1209 /*
1210 * Return a string identifying a command (to be printed by the
1211 * jobs command).
1212 */
1213
1214 STATIC char *cmdnextc;
1215 STATIC int cmdnleft;
1216
1217 void
1218 commandtext(struct procstat *ps, union node *n)
1219 {
1220 int len;
1221
1222 cmdnextc = ps->cmd;
1223 if (iflag || mflag || sizeof ps->cmd < 100)
1224 len = sizeof(ps->cmd);
1225 else
1226 len = sizeof(ps->cmd) / 10;
1227 cmdnleft = len;
1228 cmdtxt(n);
1229 if (cmdnleft <= 0) {
1230 char *p = ps->cmd + len - 4;
1231 p[0] = '.';
1232 p[1] = '.';
1233 p[2] = '.';
1234 p[3] = 0;
1235 } else
1236 *cmdnextc = '\0';
1237 TRACE(("commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",
1238 ps->cmd, cmdnextc, cmdnleft, ps->cmd));
1239 }
1240
1241
1242 STATIC void
1243 cmdtxt(union node *n)
1244 {
1245 union node *np;
1246 struct nodelist *lp;
1247 const char *p;
1248 int i;
1249 char s[2];
1250
1251 if (n == NULL || cmdnleft <= 0)
1252 return;
1253 switch (n->type) {
1254 case NSEMI:
1255 cmdtxt(n->nbinary.ch1);
1256 cmdputs("; ");
1257 cmdtxt(n->nbinary.ch2);
1258 break;
1259 case NAND:
1260 cmdtxt(n->nbinary.ch1);
1261 cmdputs(" && ");
1262 cmdtxt(n->nbinary.ch2);
1263 break;
1264 case NOR:
1265 cmdtxt(n->nbinary.ch1);
1266 cmdputs(" || ");
1267 cmdtxt(n->nbinary.ch2);
1268 break;
1269 case NPIPE:
1270 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1271 cmdtxt(lp->n);
1272 if (lp->next)
1273 cmdputs(" | ");
1274 }
1275 break;
1276 case NSUBSHELL:
1277 cmdputs("(");
1278 cmdtxt(n->nredir.n);
1279 cmdputs(")");
1280 break;
1281 case NREDIR:
1282 case NBACKGND:
1283 cmdtxt(n->nredir.n);
1284 break;
1285 case NIF:
1286 cmdputs("if ");
1287 cmdtxt(n->nif.test);
1288 cmdputs("; then ");
1289 cmdtxt(n->nif.ifpart);
1290 if (n->nif.elsepart) {
1291 cmdputs("; else ");
1292 cmdtxt(n->nif.elsepart);
1293 }
1294 cmdputs("; fi");
1295 break;
1296 case NWHILE:
1297 cmdputs("while ");
1298 goto until;
1299 case NUNTIL:
1300 cmdputs("until ");
1301 until:
1302 cmdtxt(n->nbinary.ch1);
1303 cmdputs("; do ");
1304 cmdtxt(n->nbinary.ch2);
1305 cmdputs("; done");
1306 break;
1307 case NFOR:
1308 cmdputs("for ");
1309 cmdputs(n->nfor.var);
1310 cmdputs(" in ");
1311 cmdlist(n->nfor.args, 1);
1312 cmdputs("; do ");
1313 cmdtxt(n->nfor.body);
1314 cmdputs("; done");
1315 break;
1316 case NCASE:
1317 cmdputs("case ");
1318 cmdputs(n->ncase.expr->narg.text);
1319 cmdputs(" in ");
1320 for (np = n->ncase.cases; np; np = np->nclist.next) {
1321 cmdtxt(np->nclist.pattern);
1322 cmdputs(") ");
1323 cmdtxt(np->nclist.body);
1324 cmdputs(";; ");
1325 }
1326 cmdputs("esac");
1327 break;
1328 case NDEFUN:
1329 cmdputs(n->narg.text);
1330 cmdputs("() { ... }");
1331 break;
1332 case NCMD:
1333 cmdlist(n->ncmd.args, 1);
1334 cmdlist(n->ncmd.redirect, 0);
1335 break;
1336 case NARG:
1337 cmdputs(n->narg.text);
1338 break;
1339 case NTO:
1340 p = ">"; i = 1; goto redir;
1341 case NCLOBBER:
1342 p = ">|"; i = 1; goto redir;
1343 case NAPPEND:
1344 p = ">>"; i = 1; goto redir;
1345 case NTOFD:
1346 p = ">&"; i = 1; goto redir;
1347 case NFROM:
1348 p = "<"; i = 0; goto redir;
1349 case NFROMFD:
1350 p = "<&"; i = 0; goto redir;
1351 case NFROMTO:
1352 p = "<>"; i = 0; goto redir;
1353 redir:
1354 if (n->nfile.fd != i) {
1355 s[0] = n->nfile.fd + '0';
1356 s[1] = '\0';
1357 cmdputs(s);
1358 }
1359 cmdputs(p);
1360 if (n->type == NTOFD || n->type == NFROMFD) {
1361 s[0] = n->ndup.dupfd + '0';
1362 s[1] = '\0';
1363 cmdputs(s);
1364 } else {
1365 cmdtxt(n->nfile.fname);
1366 }
1367 break;
1368 case NHERE:
1369 case NXHERE:
1370 cmdputs("<<...");
1371 break;
1372 default:
1373 cmdputs("???");
1374 break;
1375 }
1376 }
1377
1378 STATIC void
1379 cmdlist(union node *np, int sep)
1380 {
1381 for (; np; np = np->narg.next) {
1382 if (!sep)
1383 cmdputs(" ");
1384 cmdtxt(np);
1385 if (sep && np->narg.next)
1386 cmdputs(" ");
1387 }
1388 }
1389
1390
1391 STATIC void
1392 cmdputs(const char *s)
1393 {
1394 const char *p, *str = 0;
1395 char c, cc[2] = " ";
1396 char *nextc;
1397 int nleft;
1398 int subtype = 0;
1399 int quoted = 0;
1400 static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
1401 "#", "##", "%", "%%" };
1402
1403 p = s;
1404 nextc = cmdnextc;
1405 nleft = cmdnleft;
1406 while (nleft > 0 && (c = *p++) != 0) {
1407 switch (c) {
1408 case CTLESC:
1409 c = *p++;
1410 break;
1411 case CTLVAR:
1412 subtype = *p++;
1413 if ((subtype & VSTYPE) == VSLENGTH)
1414 str = "${#";
1415 else
1416 str = "${";
1417 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
1418 quoted ^= 1;
1419 c = '"';
1420 } else
1421 c = *str++;
1422 break;
1423 case CTLENDVAR:
1424 if (quoted & 1) {
1425 c = '"';
1426 str = "}";
1427 } else
1428 c = '}';
1429 quoted >>= 1;
1430 subtype = 0;
1431 break;
1432 case CTLBACKQ:
1433 c = '$';
1434 str = "(...)";
1435 break;
1436 case CTLBACKQ+CTLQUOTE:
1437 c = '"';
1438 str = "$(...)\"";
1439 break;
1440 case CTLARI:
1441 c = '$';
1442 str = "((";
1443 break;
1444 case CTLENDARI:
1445 c = ')';
1446 str = ")";
1447 break;
1448 case CTLQUOTEMARK:
1449 quoted ^= 1;
1450 c = '"';
1451 break;
1452 case '=':
1453 if (subtype == 0)
1454 break;
1455 str = vstype[subtype & VSTYPE];
1456 if (subtype & VSNUL)
1457 c = ':';
1458 else
1459 c = *str++;
1460 if (c != '}')
1461 quoted <<= 1;
1462 break;
1463 case '\'':
1464 case '\\':
1465 case '"':
1466 case '$':
1467 /* These can only happen inside quotes */
1468 cc[0] = c;
1469 str = cc;
1470 c = '\\';
1471 break;
1472 default:
1473 break;
1474 }
1475 do {
1476 *nextc++ = c;
1477 } while (--nleft > 0 && str && (c = *str++));
1478 str = 0;
1479 }
1480 if ((quoted & 1) && nleft) {
1481 *nextc++ = '"';
1482 nleft--;
1483 }
1484 cmdnleft = nleft;
1485 cmdnextc = nextc;
1486 }
+0
-106
sh/jobs.h less more
0 /* $NetBSD: jobs.h,v 1.19 2003/11/27 21:16:14 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)jobs.h 8.2 (Berkeley) 5/4/95
34 */
35
36 #include "output.h"
37
38 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
39 #define FORK_FG 0
40 #define FORK_BG 1
41 #define FORK_NOJOB 2
42
43 /* mode flags for showjob(s) */
44 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
45 #define SHOW_MULTILINE 0x02 /* one line per process */
46 #define SHOW_PID 0x04 /* include process pid */
47 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
48 #define SHOW_SIGNALLED 0x10 /* only if stopped/exited on signal */
49 #define SHOW_ISSIG 0x20 /* job was signalled */
50 #define SHOW_NO_FREE 0x40 /* do not free job */
51
52
53 /*
54 * A job structure contains information about a job. A job is either a
55 * single process or a set of processes contained in a pipeline. In the
56 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
57 * array of pids.
58 */
59 #define MAXCMDTEXT 200
60
61 struct procstat {
62 pid_t pid; /* process id */
63 int status; /* last process status from wait() */
64 char cmd[MAXCMDTEXT];/* text of command being run */
65 };
66
67 struct job {
68 struct procstat ps0; /* status of process */
69 struct procstat *ps; /* status or processes when more than one */
70 int nprocs; /* number of processes */
71 pid_t pgrp; /* process group of this job */
72 char state;
73 #define JOBRUNNING 0 /* at least one proc running */
74 #define JOBSTOPPED 1 /* all procs are stopped */
75 #define JOBDONE 2 /* all procs are completed */
76 char used; /* true if this entry is in used */
77 char changed; /* true if status has changed */
78 #if JOBS
79 char jobctl; /* job running under job control */
80 int prev_job; /* previous job index */
81 #endif
82 };
83
84 extern pid_t backgndpid; /* pid of last background process */
85 extern int job_warning; /* user was warned about stopped jobs */
86
87 void setjobctl(int);
88 int fgcmd(int, char **);
89 int bgcmd(int, char **);
90 int jobscmd(int, char **);
91 void showjobs(struct output *, int);
92 int waitcmd(int, char **);
93 int jobidcmd(int, char **);
94 struct job *makejob(union node *, int);
95 int forkshell(struct job *, union node *, int);
96 void forkchild(struct job *, union node *, int, int);
97 int forkparent(struct job *, union node *, int, pid_t);
98 int waitforjob(struct job *);
99 int stoppedjobs(void);
100 void commandtext(struct procstat *, union node *);
101 int getjobpgrp(const char *);
102
103 #if ! JOBS
104 #define setjobctl(on) /* do nothing */
105 #endif
+0
-47
sh/machdep.h less more
0 /* $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)machdep.h 8.2 (Berkeley) 5/4/95
34 */
35
36 /*
37 * Most machines require the value returned from malloc to be aligned
38 * in some way. The following macro will get this right on many machines.
39 */
40
41 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
42 /*
43 * It appears that grabstackstr() will barf with such alignments
44 * because stalloc() will return a string allocated in a new stackblock.
45 */
46 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
+0
-394
sh/main.c less more
0 /* $NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\
37 The Regents of the University of California. All rights reserved.\n");
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
43 #else
44 __RCSID("$NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $");
45 #endif
46 #endif /* not lint */
47
48 #include <errno.h>
49 #include <stdio.h>
50 #include <signal.h>
51 #include <sys/stat.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54
55
56 #include "shell.h"
57 #include "main.h"
58 #include "options.h"
59 #include "output.h"
60 #include "parser.h"
61 #include "nodes.h"
62 #include "expand.h"
63 #include "eval.h"
64 #include "jobs.h"
65 #include "input.h"
66 #include "trap.h"
67 #include "var.h"
68 #include "show.h"
69 #include "memalloc.h"
70 #include "error.h"
71 #include "init.h"
72 #include "mystring.h"
73 #include "exec.h"
74 #include "cd.h"
75
76 #define PROFILE 0
77
78 int rootpid;
79 int rootshell;
80 STATIC union node *curcmd;
81 STATIC union node *prevcmd;
82 #if PROFILE
83 short profile_buf[16384];
84 extern int etext();
85 #endif
86
87 STATIC void read_profile(const char *);
88 STATIC char *find_dot_file(char *);
89 int main(int, char **);
90
91 /*
92 * Main routine. We initialize things, parse the arguments, execute
93 * profiles if we're a login shell, and then call cmdloop to execute
94 * commands. The setjmp call sets up the location to jump to when an
95 * exception occurs. When an exception occurs the variable "state"
96 * is used to figure out how far we had gotten.
97 */
98
99 int
100 main(int argc, char **argv)
101 {
102 struct jmploc jmploc;
103 struct stackmark smark;
104 volatile int state;
105 char *shinit;
106
107 #if PROFILE
108 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
109 #endif
110 state = 0;
111 if (setjmp(jmploc.loc)) {
112 /*
113 * When a shell procedure is executed, we raise the
114 * exception EXSHELLPROC to clean up before executing
115 * the shell procedure.
116 */
117 switch (exception) {
118 case EXSHELLPROC:
119 rootpid = getpid();
120 rootshell = 1;
121 minusc = NULL;
122 state = 3;
123 break;
124
125 case EXEXEC:
126 exitstatus = exerrno;
127 break;
128
129 case EXERROR:
130 exitstatus = 2;
131 break;
132
133 default:
134 break;
135 }
136
137 if (exception != EXSHELLPROC) {
138 if (state == 0 || iflag == 0 || ! rootshell)
139 exitshell(exitstatus);
140 }
141 reset();
142 if (exception == EXINT
143 #if ATTY
144 && (! attyset() || equal(termval(), "emacs"))
145 #endif
146 ) {
147 out2c('\n');
148 flushout(&errout);
149 }
150 popstackmark(&smark);
151 FORCEINTON; /* enable interrupts */
152 if (state == 1)
153 goto state1;
154 else if (state == 2)
155 goto state2;
156 else if (state == 3)
157 goto state3;
158 else
159 goto state4;
160 }
161 handler = &jmploc;
162 #ifdef DEBUG
163 #if DEBUG == 2
164 debug = 1;
165 #endif
166 opentrace();
167 trputs("Shell args: "); trargs(argv);
168 #endif
169 rootpid = getpid();
170 rootshell = 1;
171 init();
172 setstackmark(&smark);
173 procargs(argc, argv);
174 if (argv[0] && argv[0][0] == '-') {
175 state = 1;
176 read_profile("/etc/profile");
177 state1:
178 state = 2;
179 read_profile(".profile");
180 }
181 state2:
182 state = 3;
183 if (getuid() == geteuid() && getgid() == getegid()) {
184 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
185 state = 3;
186 read_profile(shinit);
187 }
188 }
189 state3:
190 state = 4;
191 if (sflag == 0 || minusc) {
192 static int sigs[] = {
193 SIGINT, SIGQUIT, SIGHUP,
194 #ifdef SIGTSTP
195 SIGTSTP,
196 #endif
197 SIGPIPE
198 };
199 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
200 int i;
201
202 for (i = 0; i < SIGSSIZE; i++)
203 setsignal(sigs[i], 0);
204 }
205
206 if (minusc)
207 evalstring(minusc, 0);
208
209 if (sflag || minusc == NULL) {
210 state4: /* XXX ??? - why isn't this before the "if" statement */
211 cmdloop(1);
212 }
213 #if PROFILE
214 monitor(0);
215 #endif
216 exitshell(exitstatus);
217 /* NOTREACHED */
218 }
219
220
221 /*
222 * Read and execute commands. "Top" is nonzero for the top level command
223 * loop; it turns on prompting if the shell is interactive.
224 */
225
226 void
227 cmdloop(int top)
228 {
229 union node *n;
230 struct stackmark smark;
231 int inter;
232 int numeof = 0;
233
234 TRACE(("cmdloop(%d) called\n", top));
235 setstackmark(&smark);
236 for (;;) {
237 if (pendingsigs)
238 dotrap();
239 inter = 0;
240 if (iflag && top) {
241 inter = 1;
242 showjobs(out2, SHOW_CHANGED);
243 flushout(&errout);
244 }
245 n = parsecmd(inter);
246 /* showtree(n); DEBUG */
247 if (n == NEOF) {
248 if (!top || numeof >= 50)
249 break;
250 if (!stoppedjobs()) {
251 if (!Iflag)
252 break;
253 out2str("\nUse \"exit\" to leave shell.\n");
254 }
255 numeof++;
256 } else if (n != NULL && nflag == 0) {
257 job_warning = (job_warning == 2) ? 1 : 0;
258 numeof = 0;
259 evaltree(n, 0);
260 }
261 popstackmark(&smark);
262 setstackmark(&smark);
263 if (evalskip == SKIPFILE) {
264 evalskip = 0;
265 break;
266 }
267 }
268 popstackmark(&smark);
269 }
270
271
272
273 /*
274 * Read /etc/profile or .profile. Return on error.
275 */
276
277 STATIC void
278 read_profile(const char *name)
279 {
280 int fd;
281 int xflag_set = 0;
282 int vflag_set = 0;
283
284 INTOFF;
285 if ((fd = open(name, O_RDONLY)) >= 0)
286 setinputfd(fd, 1);
287 INTON;
288 if (fd < 0)
289 return;
290 /* -q turns off -x and -v just when executing init files */
291 if (qflag) {
292 if (xflag)
293 xflag = 0, xflag_set = 1;
294 if (vflag)
295 vflag = 0, vflag_set = 1;
296 }
297 cmdloop(0);
298 if (qflag) {
299 if (xflag_set)
300 xflag = 1;
301 if (vflag_set)
302 vflag = 1;
303 }
304 popfile();
305 }
306
307
308
309 /*
310 * Read a file containing shell functions.
311 */
312
313 void
314 readcmdfile(char *name)
315 {
316 int fd;
317
318 INTOFF;
319 if ((fd = open(name, O_RDONLY)) >= 0)
320 setinputfd(fd, 1);
321 else
322 error("Can't open %s", name);
323 INTON;
324 cmdloop(0);
325 popfile();
326 }
327
328
329
330 /*
331 * Take commands from a file. To be compatible we should do a path
332 * search for the file, which is necessary to find sub-commands.
333 */
334
335
336 STATIC char *
337 find_dot_file(char *basename)
338 {
339 char *fullname;
340 const char *path = pathval();
341 struct stat statb;
342
343 /* don't try this for absolute or relative paths */
344 if (strchr(basename, '/'))
345 return basename;
346
347 while ((fullname = padvance(&path, basename)) != NULL) {
348 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
349 /*
350 * Don't bother freeing here, since it will
351 * be freed by the caller.
352 */
353 return fullname;
354 }
355 stunalloc(fullname);
356 }
357
358 /* not found in the PATH */
359 error("%s: not found", basename);
360 /* NOTREACHED */
361 }
362
363 int
364 dotcmd(int argc, char **argv)
365 {
366 exitstatus = 0;
367
368 if (argc >= 2) { /* That's what SVR2 does */
369 char *fullname;
370 struct stackmark smark;
371
372 setstackmark(&smark);
373 fullname = find_dot_file(argv[1]);
374 setinputfile(fullname, 1);
375 commandname = fullname;
376 cmdloop(0);
377 popfile();
378 popstackmark(&smark);
379 }
380 return exitstatus;
381 }
382
383
384 int
385 exitcmd(int argc, char **argv)
386 {
387 if (stoppedjobs())
388 return 0;
389 if (argc > 1)
390 exitstatus = number(argv[1]);
391 exitshell(exitstatus);
392 /* NOTREACHED */
393 }
+0
-43
sh/main.h less more
0 /* $NetBSD: main.h,v 1.10 2003/08/07 09:05:34 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)main.h 8.2 (Berkeley) 5/4/95
34 */
35
36 extern int rootpid; /* pid of main shell */
37 extern int rootshell; /* true if we aren't a child of the main shell */
38
39 void readcmdfile(char *);
40 void cmdloop(int);
41 int dotcmd(int, char **);
42 int exitcmd(int, char **);
+0
-307
sh/memalloc.c less more
0 /* $NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <stdlib.h>
44 #include <unistd.h>
45
46 #include "shell.h"
47 #include "output.h"
48 #include "memalloc.h"
49 #include "error.h"
50 #include "machdep.h"
51 #include "mystring.h"
52
53 /*
54 * Like malloc, but returns an error when out of space.
55 */
56
57 pointer
58 ckmalloc(int nbytes)
59 {
60 pointer p;
61
62 p = malloc(nbytes);
63 if (p == NULL)
64 error("Out of space");
65 return p;
66 }
67
68
69 /*
70 * Same for realloc.
71 */
72
73 pointer
74 ckrealloc(pointer p, int nbytes)
75 {
76 p = realloc(p, nbytes);
77 if (p == NULL)
78 error("Out of space");
79 return p;
80 }
81
82
83 /*
84 * Make a copy of a string in safe storage.
85 */
86
87 char *
88 savestr(const char *s)
89 {
90 char *p;
91
92 p = ckmalloc(strlen(s) + 1);
93 scopy(s, p);
94 return p;
95 }
96
97
98 /*
99 * Parse trees for commands are allocated in lifo order, so we use a stack
100 * to make this more efficient, and also to avoid all sorts of exception
101 * handling code to handle interrupts in the middle of a parse.
102 *
103 * The size 504 was chosen because the Ultrix malloc handles that size
104 * well.
105 */
106
107 #define MINSIZE 504 /* minimum size of a block */
108
109 struct stack_block {
110 struct stack_block *prev;
111 char space[MINSIZE];
112 };
113
114 struct stack_block stackbase;
115 struct stack_block *stackp = &stackbase;
116 struct stackmark *markp;
117 char *stacknxt = stackbase.space;
118 int stacknleft = MINSIZE;
119 int sstrnleft;
120 int herefd = -1;
121
122 pointer
123 stalloc(int nbytes)
124 {
125 char *p;
126
127 nbytes = SHELL_ALIGN(nbytes);
128 if (nbytes > stacknleft) {
129 int blocksize;
130 struct stack_block *sp;
131
132 blocksize = nbytes;
133 if (blocksize < MINSIZE)
134 blocksize = MINSIZE;
135 INTOFF;
136 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
137 sp->prev = stackp;
138 stacknxt = sp->space;
139 stacknleft = blocksize;
140 stackp = sp;
141 INTON;
142 }
143 p = stacknxt;
144 stacknxt += nbytes;
145 stacknleft -= nbytes;
146 return p;
147 }
148
149
150 void
151 stunalloc(pointer p)
152 {
153 if (p == NULL) { /*DEBUG */
154 write(2, "stunalloc\n", 10);
155 abort();
156 }
157 stacknleft += stacknxt - (char *)p;
158 stacknxt = p;
159 }
160
161
162
163 void
164 setstackmark(struct stackmark *mark)
165 {
166 mark->stackp = stackp;
167 mark->stacknxt = stacknxt;
168 mark->stacknleft = stacknleft;
169 mark->marknext = markp;
170 markp = mark;
171 }
172
173
174 void
175 popstackmark(struct stackmark *mark)
176 {
177 struct stack_block *sp;
178
179 INTOFF;
180 markp = mark->marknext;
181 while (stackp != mark->stackp) {
182 sp = stackp;
183 stackp = sp->prev;
184 ckfree(sp);
185 }
186 stacknxt = mark->stacknxt;
187 stacknleft = mark->stacknleft;
188 INTON;
189 }
190
191
192 /*
193 * When the parser reads in a string, it wants to stick the string on the
194 * stack and only adjust the stack pointer when it knows how big the
195 * string is. Stackblock (defined in stack.h) returns a pointer to a block
196 * of space on top of the stack and stackblocklen returns the length of
197 * this block. Growstackblock will grow this space by at least one byte,
198 * possibly moving it (like realloc). Grabstackblock actually allocates the
199 * part of the block that has been used.
200 */
201
202 void
203 growstackblock(void)
204 {
205 int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
206
207 if (stacknxt == stackp->space && stackp != &stackbase) {
208 struct stack_block *oldstackp;
209 struct stackmark *xmark;
210 struct stack_block *sp;
211
212 INTOFF;
213 oldstackp = stackp;
214 sp = stackp;
215 stackp = sp->prev;
216 sp = ckrealloc((pointer)sp,
217 sizeof(struct stack_block) - MINSIZE + newlen);
218 sp->prev = stackp;
219 stackp = sp;
220 stacknxt = sp->space;
221 stacknleft = newlen;
222
223 /*
224 * Stack marks pointing to the start of the old block
225 * must be relocated to point to the new block
226 */
227 xmark = markp;
228 while (xmark != NULL && xmark->stackp == oldstackp) {
229 xmark->stackp = stackp;
230 xmark->stacknxt = stacknxt;
231 xmark->stacknleft = stacknleft;
232 xmark = xmark->marknext;
233 }
234 INTON;
235 } else {
236 char *oldspace = stacknxt;
237 int oldlen = stacknleft;
238 char *p = stalloc(newlen);
239
240 (void)memcpy(p, oldspace, oldlen);
241 stacknxt = p; /* free the space */
242 stacknleft += newlen; /* we just allocated */
243 }
244 }
245
246 void
247 grabstackblock(int len)
248 {
249 len = SHELL_ALIGN(len);
250 stacknxt += len;
251 stacknleft -= len;
252 }
253
254 /*
255 * The following routines are somewhat easier to use than the above.
256 * The user declares a variable of type STACKSTR, which may be declared
257 * to be a register. The macro STARTSTACKSTR initializes things. Then
258 * the user uses the macro STPUTC to add characters to the string. In
259 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
260 * grown as necessary. When the user is done, she can just leave the
261 * string there and refer to it using stackblock(). Or she can allocate
262 * the space for it using grabstackstr(). If it is necessary to allow
263 * someone else to use the stack temporarily and then continue to grow
264 * the string, the user should use grabstack to allocate the space, and
265 * then call ungrabstr(p) to return to the previous mode of operation.
266 *
267 * USTPUTC is like STPUTC except that it doesn't check for overflow.
268 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
269 * is space for at least one character.
270 */
271
272 char *
273 growstackstr(void)
274 {
275 int len = stackblocksize();
276 if (herefd >= 0 && len >= 1024) {
277 xwrite(herefd, stackblock(), len);
278 sstrnleft = len - 1;
279 return stackblock();
280 }
281 growstackblock();
282 sstrnleft = stackblocksize() - len - 1;
283 return stackblock() + len;
284 }
285
286 /*
287 * Called from CHECKSTRSPACE.
288 */
289
290 char *
291 makestrspace(void)
292 {
293 int len = stackblocksize() - sstrnleft;
294 growstackblock();
295 sstrnleft = stackblocksize() - len;
296 return stackblock() + len;
297 }
298
299 void
300 ungrabstackstr(char *s, char *p)
301 {
302 stacknleft += stacknxt - s;
303 stacknxt = s;
304 sstrnleft = stacknleft - (p - s);
305
306 }
+0
-77
sh/memalloc.h less more
0 /* $NetBSD: memalloc.h,v 1.14 2003/08/07 09:05:34 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)memalloc.h 8.2 (Berkeley) 5/4/95
34 */
35
36 struct stackmark {
37 struct stack_block *stackp;
38 char *stacknxt;
39 int stacknleft;
40 struct stackmark *marknext;
41 };
42
43
44 extern char *stacknxt;
45 extern int stacknleft;
46 extern int sstrnleft;
47 extern int herefd;
48
49 pointer ckmalloc(int);
50 pointer ckrealloc(pointer, int);
51 char *savestr(const char *);
52 pointer stalloc(int);
53 void stunalloc(pointer);
54 void setstackmark(struct stackmark *);
55 void popstackmark(struct stackmark *);
56 void growstackblock(void);
57 void grabstackblock(int);
58 char *growstackstr(void);
59 char *makestrspace(void);
60 void ungrabstackstr(char *, char *);
61
62
63
64 #define stackblock() stacknxt
65 #define stackblocksize() stacknleft
66 #define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
67 #define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
68 #define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); }
69 #define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
70 #define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
71 #define STUNPUTC(p) (++sstrnleft, --p)
72 #define STTOPC(p) p[-1]
73 #define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
74 #define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
75
76 #define ckfree(p) free((pointer)(p))
+0
-447
sh/miscbltin.c less more
0 /* $NetBSD: miscbltin.c,v 1.34.2.1 2005/04/07 11:34:20 tron Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: miscbltin.c,v 1.34.2.1 2005/04/07 11:34:20 tron Exp $");
40 #endif
41 #endif /* not lint */
42
43 /*
44 * Miscelaneous builtins.
45 */
46
47 #include <sys/types.h> /* quad_t */
48 #include <sys/param.h> /* BSD4_4 */
49 #include <sys/stat.h>
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <ctype.h>
55 #include <errno.h>
56
57 #include "shell.h"
58 #include "options.h"
59 #include "var.h"
60 #include "output.h"
61 #include "memalloc.h"
62 #include "error.h"
63 #include "miscbltin.h"
64 #include "mystring.h"
65
66 #undef rflag
67
68
69
70 /*
71 * The read builtin.
72 * Backslahes escape the next char unless -r is specified.
73 *
74 * This uses unbuffered input, which may be avoidable in some cases.
75 *
76 * Note that if IFS=' :' then read x y should work so that:
77 * 'a b' x='a', y='b'
78 * ' a b ' x='a', y='b'
79 * ':b' x='', y='b'
80 * ':' x='', y=''
81 * '::' x='', y=''
82 * ': :' x='', y=''
83 * ':::' x='', y='::'
84 * ':b c:' x='', y='b c:'
85 */
86
87 int
88 readcmd(int argc, char **argv)
89 {
90 char **ap;
91 char c;
92 int rflag;
93 char *prompt;
94 const char *ifs;
95 char *p;
96 int startword;
97 int status;
98 int i;
99 int is_ifs;
100 int saveall = 0;
101
102 rflag = 0;
103 prompt = NULL;
104 while ((i = nextopt("p:r")) != '\0') {
105 if (i == 'p')
106 prompt = optionarg;
107 else
108 rflag = 1;
109 }
110
111 if (prompt && isatty(0)) {
112 out2str(prompt);
113 flushall();
114 }
115
116 if (*(ap = argptr) == NULL)
117 error("arg count");
118
119 if ((ifs = bltinlookup("IFS", 1)) == NULL)
120 ifs = " \t\n";
121
122 status = 0;
123 startword = 2;
124 STARTSTACKSTR(p);
125 for (;;) {
126 if (read(0, &c, 1) != 1) {
127 status = 1;
128 break;
129 }
130 if (c == '\0')
131 continue;
132 if (c == '\\' && !rflag) {
133 if (read(0, &c, 1) != 1) {
134 status = 1;
135 break;
136 }
137 if (c != '\n')
138 STPUTC(c, p);
139 continue;
140 }
141 if (c == '\n')
142 break;
143 if (strchr(ifs, c))
144 is_ifs = strchr(" \t\n", c) ? 1 : 2;
145 else
146 is_ifs = 0;
147
148 if (startword != 0) {
149 if (is_ifs == 1) {
150 /* Ignore leading IFS whitespace */
151 if (saveall)
152 STPUTC(c, p);
153 continue;
154 }
155 if (is_ifs == 2 && startword == 1) {
156 /* Only one non-whitespace IFS per word */
157 startword = 2;
158 if (saveall)
159 STPUTC(c, p);
160 continue;
161 }
162 }
163
164 if (is_ifs == 0) {
165 /* append this character to the current variable */
166 startword = 0;
167 if (saveall)
168 /* Not just a spare terminator */
169 saveall++;
170 STPUTC(c, p);
171 continue;
172 }
173
174 /* end of variable... */
175 startword = is_ifs;
176
177 if (ap[1] == NULL) {
178 /* Last variable needs all IFS chars */
179 saveall++;
180 STPUTC(c, p);
181 continue;
182 }
183
184 STACKSTRNUL(p);
185 setvar(*ap, stackblock(), 0);
186 ap++;
187 STARTSTACKSTR(p);
188 }
189 STACKSTRNUL(p);
190
191 /* Remove trailing IFS chars */
192 for (; stackblock() <= --p; *p = 0) {
193 if (!strchr(ifs, *p))
194 break;
195 if (strchr(" \t\n", *p))
196 /* Always remove whitespace */
197 continue;
198 if (saveall > 1)
199 /* Don't remove non-whitespace unless it was naked */
200 break;
201 }
202 setvar(*ap, stackblock(), 0);
203
204 /* Set any remaining args to "" */
205 while (*++ap != NULL)
206 setvar(*ap, nullstr, 0);
207 return status;
208 }
209
210
211
212 int
213 umaskcmd(int argc, char **argv)
214 {
215 char *ap;
216 int mask;
217 int i;
218 int symbolic_mode = 0;
219
220 while ((i = nextopt("S")) != '\0') {
221 symbolic_mode = 1;
222 }
223
224 INTOFF;
225 mask = umask(0);
226 umask(mask);
227 INTON;
228
229 if ((ap = *argptr) == NULL) {
230 if (symbolic_mode) {
231 char u[4], g[4], o[4];
232
233 i = 0;
234 if ((mask & S_IRUSR) == 0)
235 u[i++] = 'r';
236 if ((mask & S_IWUSR) == 0)
237 u[i++] = 'w';
238 if ((mask & S_IXUSR) == 0)
239 u[i++] = 'x';
240 u[i] = '\0';
241
242 i = 0;
243 if ((mask & S_IRGRP) == 0)
244 g[i++] = 'r';
245 if ((mask & S_IWGRP) == 0)
246 g[i++] = 'w';
247 if ((mask & S_IXGRP) == 0)
248 g[i++] = 'x';
249 g[i] = '\0';
250
251 i = 0;
252 if ((mask & S_IROTH) == 0)
253 o[i++] = 'r';
254 if ((mask & S_IWOTH) == 0)
255 o[i++] = 'w';
256 if ((mask & S_IXOTH) == 0)
257 o[i++] = 'x';
258 o[i] = '\0';
259
260 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
261 } else {
262 out1fmt("%.4o\n", mask);
263 }
264 } else {
265 if (isdigit((unsigned char)*ap)) {
266 mask = 0;
267 do {
268 if (*ap >= '8' || *ap < '0')
269 error("Illegal number: %s", argv[1]);
270 mask = (mask << 3) + (*ap - '0');
271 } while (*++ap != '\0');
272 umask(mask);
273 } else
274 error("Illegal mode: %s", ap);
275 }
276 return 0;
277 }
278
279 typedef unsigned long rlim_t;
280
281 #if 1
282 /*
283 * ulimit builtin
284 *
285 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
286 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
287 * ash by J.T. Conklin.
288 *
289 * Public domain.
290 */
291
292 struct limits {
293 const char *name;
294 int cmd;
295 int factor; /* multiply by to get rlim_{cur,max} values */
296 char option;
297 };
298
299 static const struct limits limits[] = {
300 #ifdef RLIMIT_CPU
301 { "time(seconds)", RLIMIT_CPU, 1, 't' },
302 #endif
303 #ifdef RLIMIT_FSIZE
304 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
305 #endif
306 #ifdef RLIMIT_DATA
307 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
308 #endif
309 #ifdef RLIMIT_STACK
310 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
311 #endif
312 #ifdef RLIMIT_CORE
313 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
314 #endif
315 #ifdef RLIMIT_RSS
316 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
317 #endif
318 #ifdef RLIMIT_MEMLOCK
319 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
320 #endif
321 #ifdef RLIMIT_NPROC
322 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
323 #endif
324 #ifdef RLIMIT_NOFILE
325 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
326 #endif
327 #ifdef RLIMIT_VMEM
328 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
329 #endif
330 #ifdef RLIMIT_SWAP
331 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
332 #endif
333 #ifdef RLIMIT_SBSIZE
334 { "sbsize(bytes)", RLIMIT_SBSIZE, 1, 'b' },
335 #endif
336 { (char *) 0, 0, 0, '\0' }
337 };
338
339 int
340 ulimitcmd(int argc, char **argv)
341 {
342 int c;
343 rlim_t val = 0;
344 enum { SOFT = 0x1, HARD = 0x2 }
345 how = SOFT | HARD;
346 const struct limits *l;
347 int set, all = 0;
348 int optc, what;
349 struct rlimit limit;
350
351 what = 'f';
352 while ((optc = nextopt("HSabtfdsmcnpl")) != '\0')
353 switch (optc) {
354 case 'H':
355 how = HARD;
356 break;
357 case 'S':
358 how = SOFT;
359 break;
360 case 'a':
361 all = 1;
362 break;
363 default:
364 what = optc;
365 }
366
367 for (l = limits; l->name && l->option != what; l++)
368 ;
369 if (!l->name)
370 error("internal error (%c)", what);
371
372 set = *argptr ? 1 : 0;
373 if (set) {
374 char *p = *argptr;
375
376 if (all || argptr[1])
377 error("too many arguments");
378 if (strcmp(p, "unlimited") == 0)
379 val = RLIM_INFINITY;
380 else {
381 val = (rlim_t) 0;
382
383 while ((c = *p++) >= '0' && c <= '9')
384 {
385 val = (val * 10) + (long)(c - '0');
386 if ((long)val < 0)
387 break;
388 }
389 if (c)
390 error("bad number");
391 val *= l->factor;
392 }
393 }
394 if (all) {
395 for (l = limits; l->name; l++) {
396 getrlimit(l->cmd, &limit);
397 if (how & SOFT)
398 val = limit.rlim_cur;
399 else if (how & HARD)
400 val = limit.rlim_max;
401
402 out1fmt("%-20s ", l->name);
403 if (val == RLIM_INFINITY)
404 out1fmt("unlimited\n");
405 else
406 {
407 val /= l->factor;
408 #ifdef BSD4_4
409 out1fmt("%lld\n", (long long) val);
410 #else
411 out1fmt("%ld\n", (long) val);
412 #endif
413 }
414 }
415 return 0;
416 }
417
418 getrlimit(l->cmd, &limit);
419 if (set) {
420 if (how & HARD)
421 limit.rlim_max = val;
422 if (how & SOFT)
423 limit.rlim_cur = val;
424 if (setrlimit(l->cmd, &limit) < 0)
425 error("error setting limit (%s)", strerror(errno));
426 } else {
427 if (how & SOFT)
428 val = limit.rlim_cur;
429 else if (how & HARD)
430 val = limit.rlim_max;
431
432 if (val == RLIM_INFINITY)
433 out1fmt("unlimited\n");
434 else
435 {
436 val /= l->factor;
437 #ifdef BSD4_4
438 out1fmt("%lld\n", (long long) val);
439 #else
440 out1fmt("%ld\n", (long) val);
441 #endif
442 }
443 }
444 return 0;
445 }
446 #endif
+0
-31
sh/miscbltin.h less more
0 /* $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $ */
1
2 /*
3 * Copyright (c) 1997 Christos Zoulas. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 int readcmd(int, char **);
29 int umaskcmd(int, char **);
30 int ulimitcmd(int, char **);
+0
-136
sh/mkbuiltins less more
0 #!/bin/sh -
1 # $NetBSD: mkbuiltins,v 1.21 2004/06/06 07:03:11 christos Exp $
2 #
3 # Copyright (c) 1991, 1993
4 # The Regents of the University of California. All rights reserved.
5 #
6 # This code is derived from software contributed to Berkeley by
7 # Kenneth Almquist.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 # 3. Neither the name of the University nor the names of its contributors
18 # may be used to endorse or promote products derived from this software
19 # without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # SUCH DAMAGE.
32 #
33 # @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
34
35 havehist=1
36 if [ "X$1" = "X-h" ]; then
37 havehist=0
38 shift
39 fi
40
41 shell=$1
42 builtins=$2
43 objdir=$3
44
45 havejobs=0
46 if grep '^#define JOBS[ ]*1' ${shell} > /dev/null
47 then
48 havejobs=1
49 fi
50
51 exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h
52
53 echo '/*
54 * This file was generated by the mkbuiltins program.
55 */
56
57 #include "shell.h"
58 #include "builtins.h"
59
60 const struct builtincmd builtincmd[] = {
61 ' >&3
62
63 echo '/*
64 * This file was generated by the mkbuiltins program.
65 */
66
67 #include <sys/cdefs.h>
68
69 struct builtincmd {
70 const char *name;
71 int (*builtin)(int, char **);
72 };
73
74 extern const struct builtincmd builtincmd[];
75 extern const struct builtincmd splbltincmd[];
76
77 ' >&4
78
79 specials=
80
81 while read line
82 do
83 set -- $line
84 [ -z "$1" ] && continue
85 case "$1" in
86 \#if*|\#def*|\#end*)
87 echo $line >&3
88 echo $line >&4
89 continue
90 ;;
91 esac
92 l1="${line###}"
93 [ "$l1" != "$line" ] && continue
94
95
96 func=$1
97 shift
98 [ x"$1" = x'-j' ] && {
99 [ $havejobs = 0 ] && continue
100 shift
101 }
102 [ x"$1" = x'-h' ] && {
103 [ $havehist = 0 ] && continue
104 shift
105 }
106 echo 'int '"$func"'(int, char **);' >&4
107 while
108 [ $# != 0 -a "$1" != '#' ]
109 do
110 [ "$1" = '-s' ] && {
111 specials="$specials $2 $func"
112 shift 2
113 continue;
114 }
115 [ "$1" = '-u' ] && shift
116 echo ' { "'$1'", '"$func"' },' >&3
117 shift
118 done
119 done
120
121 echo ' { 0, 0 },' >&3
122 echo '};' >&3
123 echo >&3
124 echo 'const struct builtincmd splbltincmd[] = {' >&3
125
126 set -- $specials
127 while
128 [ $# != 0 ]
129 do
130 echo ' { "'$1'", '"$2"' },' >&3
131 shift 2
132 done
133
134 echo ' { 0, 0 },' >&3
135 echo "};" >&3
+0
-197
sh/mkinit.sh less more
0 #! /bin/sh
1 # $NetBSD: mkinit.sh,v 1.2 2004/06/15 23:09:54 dsl Exp $
2
3 # Copyright (c) 2003 The NetBSD Foundation, Inc.
4 # All rights reserved.
5 #
6 # This code is derived from software contributed to The NetBSD Foundation
7 # by David Laight.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 # 3. Neither the name of The NetBSD Foundation nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32
33 srcs="$*"
34
35 nl='
36 '
37 openparen='('
38 backslash='\'
39
40 includes=' "shell.h" "mystring.h" "init.h" '
41 defines=
42 decles=
43 event_init=
44 event_reset=
45 event_shellproc=
46
47 for src in $srcs; do
48 exec <$src
49 decnl="$nl"
50 while IFS=; read -r line; do
51 [ "$line" = x ]
52 case "$line " in
53 INIT["{ "]* ) event=init;;
54 RESET["{ "]* ) event=reset;;
55 SHELLPROC["{ "]* ) event=shellproc;;
56 INCLUDE[\ \ ]* )
57 IFS=' '
58 set -- $line
59 # ignore duplicates
60 [ "${includes}" != "${includes%* $2 }" ] && continue
61 includes="$includes$2 "
62 continue
63 ;;
64 MKINIT\ )
65 # struct declaration
66 decles="$decles$nl"
67 while
68 read -r line
69 decles="${decles}${line}${nl}"
70 [ "$line" != "};" ]
71 do
72 :
73 done
74 decnl="$nl"
75 continue
76 ;;
77 MKINIT["{ "]* )
78 # strip initialiser
79 def=${line#MKINIT}
80 comment="${def#*;}"
81 def="${def%;$comment}"
82 def="${def%%=*}"
83 def="${def% }"
84 decles="${decles}${decnl}extern${def};${comment}${nl}"
85 decnl=
86 continue
87 ;;
88 \#define[\ \ ]* )
89 IFS=' '
90 set -- $line
91 # Ignore those with arguments
92 [ "$2" = "${2##*$openparen}" ] || continue
93 # and multiline definitions
94 [ "$line" = "${line%$backslash}" ] || continue
95 defines="${defines}#undef $2${nl}${line}${nl}"
96 continue
97 ;;
98 * ) continue;;
99 esac
100 # code for events
101 ev="${nl} /* from $src: */${nl} {${nl}"
102 while
103 read -r line
104 [ "$line" != "}" ]
105 do
106 # The C program indented by an extra 6 chars using
107 # tabs then spaces. I need to compare the output :-(
108 indent=6
109 while
110 l=${line# }
111 [ "$l" != "$line" ]
112 do
113 indent=$(($indent + 8))
114 line="$l"
115 done
116 while
117 l=${line# }
118 [ "$l" != "$line" ]
119 do
120 indent=$(($indent + 1))
121 line="$l"
122 done
123 [ -z "$line" -o "$line" != "${line###}" ] && indent=0
124 while
125 [ $indent -ge 8 ]
126 do
127 ev="$ev "
128 indent="$(($indent - 8))"
129 done
130 while
131 [ $indent -gt 0 ]
132 do
133 ev="$ev "
134 indent="$(($indent - 1))"
135 done
136 ev="${ev}${line}${nl}"
137 done
138 ev="${ev} }${nl}"
139 eval event_$event=\"\$event_$event\$ev\"
140 done
141 done
142
143 exec >init.c.tmp
144
145 echo "/*"
146 echo " * This file was generated by the mkinit program."
147 echo " */"
148 echo
149
150 IFS=' '
151 for f in $includes; do
152 echo "#include $f"
153 done
154
155 echo
156 echo
157 echo
158 echo "$defines"
159 echo
160 echo "$decles"
161 echo
162 echo
163 echo "/*"
164 echo " * Initialization code."
165 echo " */"
166 echo
167 echo "void"
168 echo "init() {"
169 echo "${event_init%$nl}"
170 echo "}"
171 echo
172 echo
173 echo
174 echo "/*"
175 echo " * This routine is called when an error or an interrupt occurs in an"
176 echo " * interactive shell and control is returned to the main command loop."
177 echo " */"
178 echo
179 echo "void"
180 echo "reset() {"
181 echo "${event_reset%$nl}"
182 echo "}"
183 echo
184 echo
185 echo
186 echo "/*"
187 echo " * This routine is called to initialize the shell to run a shell procedure."
188 echo " */"
189 echo
190 echo "void"
191 echo "initshellproc() {"
192 echo "${event_shellproc%$nl}"
193 echo "}"
194
195 exec >&-
196 mv init.c.tmp init.c
+0
-217
sh/mknodes.sh less more
0 #! /bin/sh
1 # $NetBSD: mknodes.sh,v 1.1 2004/01/16 23:24:38 dsl Exp $
2
3 # Copyright (c) 2003 The NetBSD Foundation, Inc.
4 # All rights reserved.
5 #
6 # This code is derived from software contributed to The NetBSD Foundation
7 # by David Laight.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 # 3. Neither the name of The NetBSD Foundation nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32
33 nodetypes=$1
34 nodes_pat=$2
35 objdir="$3"
36
37 exec <$nodetypes
38 exec >$objdir/nodes.h.tmp
39
40 echo "/*"
41 echo " * This file was generated by mknodes.sh"
42 echo " */"
43 echo
44
45 tagno=0
46 while IFS=; read -r line; do
47 line="${line%%#*}"
48 IFS=' '
49 set -- $line
50 IFS=
51 [ -z "$2" ] && continue
52 case "$line" in
53 [" "]* )
54 IFS=' '
55 [ $field = 0 ] && struct_list="$struct_list $struct"
56 eval field_${struct}_$field=\"\$*\"
57 eval numfld_$struct=\$field
58 field=$(($field + 1))
59 ;;
60 * )
61 define=$1
62 struct=$2
63 echo "#define $define $tagno"
64 tagno=$(($tagno + 1))
65 eval define_$struct=\"\$define_$struct \$define\"
66 struct_define="$struct_define $struct"
67 field=0
68 ;;
69 esac
70 done
71
72 echo
73
74 IFS=' '
75 for struct in $struct_list; do
76 echo
77 echo
78 echo "struct $struct {"
79 field=0
80 while
81 eval line=\"\$field_${struct}_$field\"
82 field=$(($field + 1))
83 [ -n "$line" ]
84 do
85 IFS=' '
86 set -- $line
87 name=$1
88 case $2 in
89 nodeptr ) type="union node *";;
90 nodelist ) type="struct nodelist *";;
91 string ) type="char *";;
92 int ) type="int ";;
93 * ) name=; shift 2; type="$*";;
94 esac
95 echo " $type$name;"
96 done
97 echo "};"
98 done
99
100 echo
101 echo
102 echo "union node {"
103 echo " int type;"
104 for struct in $struct_list; do
105 echo " struct $struct $struct;"
106 done
107 echo "};"
108 echo
109 echo
110 echo "struct nodelist {"
111 echo " struct nodelist *next;"
112 echo " union node *n;"
113 echo "};"
114 echo
115 echo
116 echo "union node *copyfunc(union node *);"
117 echo "void freefunc(union node *);"
118
119 mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1
120
121 exec <$nodes_pat
122 exec >$objdir/nodes.c.tmp
123
124 echo "/*"
125 echo " * This file was generated by mknodes.sh"
126 echo " */"
127 echo
128
129 while IFS=; read -r line; do
130 IFS=' '
131 set -- $line
132 IFS=
133 case "$1" in
134 '%SIZES' )
135 echo "static const short nodesize[$tagno] = {"
136 IFS=' '
137 for struct in $struct_define; do
138 echo " SHELL_ALIGN(sizeof (struct $struct)),"
139 done
140 echo "};"
141 ;;
142 '%CALCSIZE' )
143 echo " if (n == NULL)"
144 echo " return;"
145 echo " funcblocksize += nodesize[n->type];"
146 echo " switch (n->type) {"
147 IFS=' '
148 for struct in $struct_list; do
149 eval defines=\"\$define_$struct\"
150 for define in $defines; do
151 echo " case $define:"
152 done
153 eval field=\$numfld_$struct
154 while
155 [ $field != 0 ]
156 do
157 eval line=\"\$field_${struct}_$field\"
158 field=$(($field - 1))
159 IFS=' '
160 set -- $line
161 name=$1
162 cl=")"
163 case $2 in
164 nodeptr ) fn=calcsize;;
165 nodelist ) fn=sizenodelist;;
166 string ) fn="funcstringsize += strlen"
167 cl=") + 1";;
168 * ) continue;;
169 esac
170 echo " ${fn}(n->$struct.$name${cl};"
171 done
172 echo " break;"
173 done
174 echo " };"
175 ;;
176 '%COPY' )
177 echo " if (n == NULL)"
178 echo " return NULL;"
179 echo " new = funcblock;"
180 echo " funcblock = (char *) funcblock + nodesize[n->type];"
181 echo " switch (n->type) {"
182 IFS=' '
183 for struct in $struct_list; do
184 eval defines=\"\$define_$struct\"
185 for define in $defines; do
186 echo " case $define:"
187 done
188 eval field=\$numfld_$struct
189 while
190 [ $field != 0 ]
191 do
192 eval line=\"\$field_${struct}_$field\"
193 field=$(($field - 1))
194 IFS=' '
195 set -- $line
196 name=$1
197 case $2 in
198 nodeptr ) fn="copynode(";;
199 nodelist ) fn="copynodelist(";;
200 string ) fn="nodesavestr(";;
201 int ) fn=;;
202 * ) continue;;
203 esac
204 f="$struct.$name"
205 echo " new->$f = ${fn}n->$f${fn:+)};"
206 done
207 echo " break;"
208 done
209 echo " };"
210 echo " new->type = n->type;"
211 ;;
212 * ) echo "$line";;
213 esac
214 done
215
216 mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1
+0
-92
sh/mktokens less more
0 #!/bin/sh -
1 # $NetBSD: mktokens,v 1.10 2003/08/22 11:22:23 agc Exp $
2 #
3 # Copyright (c) 1991, 1993
4 # The Regents of the University of California. All rights reserved.
5 #
6 # This code is derived from software contributed to Berkeley by
7 # Kenneth Almquist.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 # 3. Neither the name of the University nor the names of its contributors
18 # may be used to endorse or promote products derived from this software
19 # without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # SUCH DAMAGE.
32 #
33 # @(#)mktokens 8.1 (Berkeley) 5/31/93
34
35 # The following is a list of tokens. The second column is nonzero if the
36 # token marks the end of a list. The third column is the name to print in
37 # error messages.
38
39 cat > /tmp/ka$$ <<\!
40 TEOF 1 end of file
41 TNL 0 newline
42 TSEMI 0 ";"
43 TBACKGND 0 "&"
44 TAND 0 "&&"
45 TOR 0 "||"
46 TPIPE 0 "|"
47 TLP 0 "("
48 TRP 1 ")"
49 TENDCASE 1 ";;"
50 TENDBQUOTE 1 "`"
51 TREDIR 0 redirection
52 TWORD 0 word
53 TIF 0 "if"
54 TTHEN 1 "then"
55 TELSE 1 "else"
56 TELIF 1 "elif"
57 TFI 1 "fi"
58 TWHILE 0 "while"
59 TUNTIL 0 "until"
60 TFOR 0 "for"
61 TDO 1 "do"
62 TDONE 1 "done"
63 TBEGIN 0 "{"
64 TEND 1 "}"
65 TCASE 0 "case"
66 TESAC 1 "esac"
67 TNOT 0 "!"
68 !
69 nl=`wc -l /tmp/ka$$`
70 exec > token.h
71 awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
72 echo '
73 /* Array indicating which tokens mark the end of a list */
74 const char tokendlist[] = {'
75 awk '{print "\t" $2 ","}' /tmp/ka$$
76 echo '};
77
78 const char *const tokname[] = {'
79 sed -e 's/"/\\"/g' \
80 -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
81 /tmp/ka$$
82 echo '};
83 '
84 sed 's/"//g' /tmp/ka$$ | awk '
85 /TIF/{print "#define KWDOFFSET " NR-1; print "";
86 print "const char *const parsekwd[] = {"}
87 /TIF/,/neverfound/{print " \"" $3 "\","}'
88 echo ' 0
89 };'
90
91 rm /tmp/ka$$
+0
-49
sh/myhistedit.h less more
0 /* $NetBSD: myhistedit.h,v 1.10 2003/08/07 09:05:35 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
31 */
32
33 #ifdef WITH_HISTORY
34 #include <histedit.h>
35
36 extern History *hist;
37 extern EditLine *el;
38 extern int displayhist;
39
40 void histedit(void);
41 void sethistsize(const char *);
42 void setterm(const char *);
43 int histcmd(int, char **);
44 int inputrc(int, char **);
45 int not_fcnumber(char *);
46 int str_to_event(const char *, int);
47 #endif
48
+0
-133
sh/mystring.c less more
0 /* $NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 /*
44 * String functions.
45 *
46 * equal(s1, s2) Return true if strings are equal.
47 * scopy(from, to) Copy a string.
48 * scopyn(from, to, n) Like scopy, but checks for overflow.
49 * number(s) Convert a string of digits to an integer.
50 * is_number(s) Return true if s is a string of digits.
51 */
52
53 #include <stdlib.h>
54 #include "shell.h"
55 #include "syntax.h"
56 #include "error.h"
57 #include "mystring.h"
58
59
60 char nullstr[1]; /* zero length string */
61
62 /*
63 * equal - #defined in mystring.h
64 */
65
66 /*
67 * scopy - #defined in mystring.h
68 */
69
70
71 /*
72 * scopyn - copy a string from "from" to "to", truncating the string
73 * if necessary. "To" is always nul terminated, even if
74 * truncation is performed. "Size" is the size of "to".
75 */
76
77 void
78 scopyn(const char *from, char *to, int size)
79 {
80
81 while (--size > 0) {
82 if ((*to++ = *from++) == '\0')
83 return;
84 }
85 *to = '\0';
86 }
87
88
89 /*
90 * prefix -- see if pfx is a prefix of string.
91 */
92
93 int
94 prefix(const char *pfx, const char *string)
95 {
96 while (*pfx) {
97 if (*pfx++ != *string++)
98 return 0;
99 }
100 return 1;
101 }
102
103
104 /*
105 * Convert a string of digits to an integer, printing an error message on
106 * failure.
107 */
108
109 int
110 number(const char *s)
111 {
112
113 if (! is_number(s))
114 error("Illegal number: %s", s);
115 return atoi(s);
116 }
117
118
119
120 /*
121 * Check for a valid number. This should be elsewhere.
122 */
123
124 int
125 is_number(const char *p)
126 {
127 do {
128 if (! is_digit(*p))
129 return 0;
130 } while (*++p != '\0');
131 return 1;
132 }
+0
-45
sh/mystring.h less more
0 /* $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)mystring.h 8.2 (Berkeley) 5/4/95
34 */
35
36 #include <string.h>
37
38 void scopyn(const char *, char *, int);
39 int prefix(const char *, const char *);
40 int number(const char *);
41 int is_number(const char *);
42
43 #define equal(s1, s2) (strcmp(s1, s2) == 0)
44 #define scopy(s1, s2) ((void)strcpy(s2, s1))
+0
-347
sh/nodes.c less more
0 /*
1 * This file was generated by mknodes.sh
2 */
3
4 /* $NetBSD: nodes.c.pat,v 1.12 2004/06/15 22:57:27 dsl Exp $ */
5
6 /*-
7 * Copyright (c) 1991, 1993
8 * The Regents of the University of California. All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Kenneth Almquist.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
38 */
39
40 #include <stdlib.h>
41 /*
42 * Routine for dealing with parsed shell commands.
43 */
44
45 #include "shell.h"
46 #include "nodes.h"
47 #include "memalloc.h"
48 #include "machdep.h"
49 #include "mystring.h"
50
51
52 int funcblocksize; /* size of structures in function */
53 int funcstringsize; /* size of strings in node */
54 pointer funcblock; /* block to allocate function from */
55 char *funcstring; /* block to allocate strings from */
56
57 static const short nodesize[26] = {
58 SHELL_ALIGN(sizeof (struct nbinary)),
59 SHELL_ALIGN(sizeof (struct ncmd)),
60 SHELL_ALIGN(sizeof (struct npipe)),
61 SHELL_ALIGN(sizeof (struct nredir)),
62 SHELL_ALIGN(sizeof (struct nredir)),
63 SHELL_ALIGN(sizeof (struct nredir)),
64 SHELL_ALIGN(sizeof (struct nbinary)),
65 SHELL_ALIGN(sizeof (struct nbinary)),
66 SHELL_ALIGN(sizeof (struct nif)),
67 SHELL_ALIGN(sizeof (struct nbinary)),
68 SHELL_ALIGN(sizeof (struct nbinary)),
69 SHELL_ALIGN(sizeof (struct nfor)),
70 SHELL_ALIGN(sizeof (struct ncase)),
71 SHELL_ALIGN(sizeof (struct nclist)),
72 SHELL_ALIGN(sizeof (struct narg)),
73 SHELL_ALIGN(sizeof (struct narg)),
74 SHELL_ALIGN(sizeof (struct nfile)),
75 SHELL_ALIGN(sizeof (struct nfile)),
76 SHELL_ALIGN(sizeof (struct nfile)),
77 SHELL_ALIGN(sizeof (struct nfile)),
78 SHELL_ALIGN(sizeof (struct nfile)),
79 SHELL_ALIGN(sizeof (struct ndup)),
80 SHELL_ALIGN(sizeof (struct ndup)),
81 SHELL_ALIGN(sizeof (struct nhere)),
82 SHELL_ALIGN(sizeof (struct nhere)),
83 SHELL_ALIGN(sizeof (struct nnot)),
84 };
85
86
87 STATIC void calcsize(union node *);
88 STATIC void sizenodelist(struct nodelist *);
89 STATIC union node *copynode(union node *);
90 STATIC struct nodelist *copynodelist(struct nodelist *);
91 STATIC char *nodesavestr(char *);
92
93
94
95 /*
96 * Make a copy of a parse tree.
97 */
98
99 union node *
100 copyfunc(n)
101 union node *n;
102 {
103 if (n == NULL)
104 return NULL;
105 funcblocksize = 0;
106 funcstringsize = 0;
107 calcsize(n);
108 funcblock = ckmalloc(funcblocksize + funcstringsize);
109 funcstring = (char *) funcblock + funcblocksize;
110 return copynode(n);
111 }
112
113
114
115 STATIC void
116 calcsize(n)
117 union node *n;
118 {
119 if (n == NULL)
120 return;
121 funcblocksize += nodesize[n->type];
122 switch (n->type) {
123 case NSEMI:
124 case NAND:
125 case NOR:
126 case NWHILE:
127 case NUNTIL:
128 calcsize(n->nbinary.ch2);
129 calcsize(n->nbinary.ch1);
130 break;
131 case NCMD:
132 calcsize(n->ncmd.redirect);
133 calcsize(n->ncmd.args);
134 break;
135 case NPIPE:
136 sizenodelist(n->npipe.cmdlist);
137 break;
138 case NREDIR:
139 case NBACKGND:
140 case NSUBSHELL:
141 calcsize(n->nredir.redirect);
142 calcsize(n->nredir.n);
143 break;
144 case NIF:
145 calcsize(n->nif.elsepart);
146 calcsize(n->nif.ifpart);
147 calcsize(n->nif.test);
148 break;
149 case NFOR:
150 funcstringsize += strlen(n->nfor.var) + 1;
151 calcsize(n->nfor.body);
152 calcsize(n->nfor.args);
153 break;
154 case NCASE:
155 calcsize(n->ncase.cases);
156 calcsize(n->ncase.expr);
157 break;
158 case NCLIST:
159 calcsize(n->nclist.body);
160 calcsize(n->nclist.pattern);
161 calcsize(n->nclist.next);
162 break;
163 case NDEFUN:
164 case NARG:
165 sizenodelist(n->narg.backquote);
166 funcstringsize += strlen(n->narg.text) + 1;
167 calcsize(n->narg.next);
168 break;
169 case NTO:
170 case NCLOBBER:
171 case NFROM:
172 case NFROMTO:
173 case NAPPEND:
174 calcsize(n->nfile.fname);
175 calcsize(n->nfile.next);
176 break;
177 case NTOFD:
178 case NFROMFD:
179 calcsize(n->ndup.vname);
180 calcsize(n->ndup.next);
181 break;
182 case NHERE:
183 case NXHERE:
184 calcsize(n->nhere.doc);
185 calcsize(n->nhere.next);
186 break;
187 case NNOT:
188 calcsize(n->nnot.com);
189 break;
190 };
191 }
192
193
194
195 STATIC void
196 sizenodelist(lp)
197 struct nodelist *lp;
198 {
199 while (lp) {
200 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
201 calcsize(lp->n);
202 lp = lp->next;
203 }
204 }
205
206
207
208 STATIC union node *
209 copynode(n)
210 union node *n;
211 {
212 union node *new;
213
214 if (n == NULL)
215 return NULL;
216 new = funcblock;
217 funcblock = (char *) funcblock + nodesize[n->type];
218 switch (n->type) {
219 case NSEMI:
220 case NAND:
221 case NOR:
222 case NWHILE:
223 case NUNTIL:
224 new->nbinary.ch2 = copynode(n->nbinary.ch2);
225 new->nbinary.ch1 = copynode(n->nbinary.ch1);
226 break;
227 case NCMD:
228 new->ncmd.redirect = copynode(n->ncmd.redirect);
229 new->ncmd.args = copynode(n->ncmd.args);
230 new->ncmd.backgnd = n->ncmd.backgnd;
231 break;
232 case NPIPE:
233 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
234 new->npipe.backgnd = n->npipe.backgnd;
235 break;
236 case NREDIR:
237 case NBACKGND:
238 case NSUBSHELL:
239 new->nredir.redirect = copynode(n->nredir.redirect);
240 new->nredir.n = copynode(n->nredir.n);
241 break;
242 case NIF:
243 new->nif.elsepart = copynode(n->nif.elsepart);
244 new->nif.ifpart = copynode(n->nif.ifpart);
245 new->nif.test = copynode(n->nif.test);
246 break;
247 case NFOR:
248 new->nfor.var = nodesavestr(n->nfor.var);
249 new->nfor.body = copynode(n->nfor.body);
250 new->nfor.args = copynode(n->nfor.args);
251 break;
252 case NCASE:
253 new->ncase.cases = copynode(n->ncase.cases);
254 new->ncase.expr = copynode(n->ncase.expr);
255 break;
256 case NCLIST:
257 new->nclist.body = copynode(n->nclist.body);
258 new->nclist.pattern = copynode(n->nclist.pattern);
259 new->nclist.next = copynode(n->nclist.next);
260 break;
261 case NDEFUN:
262 case NARG:
263 new->narg.backquote = copynodelist(n->narg.backquote);
264 new->narg.text = nodesavestr(n->narg.text);
265 new->narg.next = copynode(n->narg.next);
266 break;
267 case NTO:
268 case NCLOBBER:
269 case NFROM:
270 case NFROMTO:
271 case NAPPEND:
272 new->nfile.fname = copynode(n->nfile.fname);
273 new->nfile.fd = n->nfile.fd;
274 new->nfile.next = copynode(n->nfile.next);
275 break;
276 case NTOFD:
277 case NFROMFD:
278 new->ndup.vname = copynode(n->ndup.vname);
279 new->ndup.dupfd = n->ndup.dupfd;
280 new->ndup.fd = n->ndup.fd;
281 new->ndup.next = copynode(n->ndup.next);
282 break;
283 case NHERE:
284 case NXHERE:
285 new->nhere.doc = copynode(n->nhere.doc);
286 new->nhere.fd = n->nhere.fd;
287 new->nhere.next = copynode(n->nhere.next);
288 break;
289 case NNOT:
290 new->nnot.com = copynode(n->nnot.com);
291 break;
292 };
293 new->type = n->type;
294 return new;
295 }
296
297
298 STATIC struct nodelist *
299 copynodelist(lp)
300 struct nodelist *lp;
301 {
302 struct nodelist *start;
303 struct nodelist **lpp;
304
305 lpp = &start;
306 while (lp) {
307 *lpp = funcblock;
308 funcblock = (char *) funcblock +
309 SHELL_ALIGN(sizeof(struct nodelist));
310 (*lpp)->n = copynode(lp->n);
311 lp = lp->next;
312 lpp = &(*lpp)->next;
313 }
314 *lpp = NULL;
315 return start;
316 }
317
318
319
320 STATIC char *
321 nodesavestr(s)
322 char *s;
323 {
324 register char *p = s;
325 register char *q = funcstring;
326 char *rtn = funcstring;
327
328 while ((*q++ = *p++) != 0)
329 continue;
330 funcstring = q;
331 return rtn;
332 }
333
334
335
336 /*
337 * Free a parse tree.
338 */
339
340 void
341 freefunc(n)
342 union node *n;
343 {
344 if (n)
345 ckfree(n);
346 }
+0
-166
sh/nodes.c.pat less more
0 /* $NetBSD: nodes.c.pat,v 1.12 2004/06/15 22:57:27 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
34 */
35
36 #include <stdlib.h>
37 /*
38 * Routine for dealing with parsed shell commands.
39 */
40
41 #include "shell.h"
42 #include "nodes.h"
43 #include "memalloc.h"
44 #include "machdep.h"
45 #include "mystring.h"
46
47
48 int funcblocksize; /* size of structures in function */
49 int funcstringsize; /* size of strings in node */
50 pointer funcblock; /* block to allocate function from */
51 char *funcstring; /* block to allocate strings from */
52
53 %SIZES
54
55
56 STATIC void calcsize(union node *);
57 STATIC void sizenodelist(struct nodelist *);
58 STATIC union node *copynode(union node *);
59 STATIC struct nodelist *copynodelist(struct nodelist *);
60 STATIC char *nodesavestr(char *);
61
62
63
64 /*
65 * Make a copy of a parse tree.
66 */
67
68 union node *
69 copyfunc(n)
70 union node *n;
71 {
72 if (n == NULL)
73 return NULL;
74 funcblocksize = 0;
75 funcstringsize = 0;
76 calcsize(n);
77 funcblock = ckmalloc(funcblocksize + funcstringsize);
78 funcstring = (char *) funcblock + funcblocksize;
79 return copynode(n);
80 }
81
82
83
84 STATIC void
85 calcsize(n)
86 union node *n;
87 {
88 %CALCSIZE
89 }
90
91
92
93 STATIC void
94 sizenodelist(lp)
95 struct nodelist *lp;
96 {
97 while (lp) {
98 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
99 calcsize(lp->n);
100 lp = lp->next;
101 }
102 }
103
104
105
106 STATIC union node *
107 copynode(n)
108 union node *n;
109 {
110 union node *new;
111
112 %COPY
113 return new;
114 }
115
116
117 STATIC struct nodelist *
118 copynodelist(lp)
119 struct nodelist *lp;
120 {
121 struct nodelist *start;
122 struct nodelist **lpp;
123
124 lpp = &start;
125 while (lp) {
126 *lpp = funcblock;
127 funcblock = (char *) funcblock +
128 SHELL_ALIGN(sizeof(struct nodelist));
129 (*lpp)->n = copynode(lp->n);
130 lp = lp->next;
131 lpp = &(*lpp)->next;
132 }
133 *lpp = NULL;
134 return start;
135 }
136
137
138
139 STATIC char *
140 nodesavestr(s)
141 char *s;
142 {
143 register char *p = s;
144 register char *q = funcstring;
145 char *rtn = funcstring;
146
147 while ((*q++ = *p++) != 0)
148 continue;
149 funcstring = q;
150 return rtn;
151 }
152
153
154
155 /*
156 * Free a parse tree.
157 */
158
159 void
160 freefunc(n)
161 union node *n;
162 {
163 if (n)
164 ckfree(n);
165 }
+0
-159
sh/nodes.h less more
0 /*
1 * This file was generated by mknodes.sh
2 */
3
4 #define NSEMI 0
5 #define NCMD 1
6 #define NPIPE 2
7 #define NREDIR 3
8 #define NBACKGND 4
9 #define NSUBSHELL 5
10 #define NAND 6
11 #define NOR 7
12 #define NIF 8
13 #define NWHILE 9
14 #define NUNTIL 10
15 #define NFOR 11
16 #define NCASE 12
17 #define NCLIST 13
18 #define NDEFUN 14
19 #define NARG 15
20 #define NTO 16
21 #define NCLOBBER 17
22 #define NFROM 18
23 #define NFROMTO 19
24 #define NAPPEND 20
25 #define NTOFD 21
26 #define NFROMFD 22
27 #define NHERE 23
28 #define NXHERE 24
29 #define NNOT 25
30
31
32
33 struct nbinary {
34 int type;
35 union node *ch1;
36 union node *ch2;
37 };
38
39
40 struct ncmd {
41 int type;
42 int backgnd;
43 union node *args;
44 union node *redirect;
45 };
46
47
48 struct npipe {
49 int type;
50 int backgnd;
51 struct nodelist *cmdlist;
52 };
53
54
55 struct nredir {
56 int type;
57 union node *n;
58 union node *redirect;
59 };
60
61
62 struct nif {
63 int type;
64 union node *test;
65 union node *ifpart;
66 union node *elsepart;
67 };
68
69
70 struct nfor {
71 int type;
72 union node *args;
73 union node *body;
74 char *var;
75 };
76
77
78 struct ncase {
79 int type;
80 union node *expr;
81 union node *cases;
82 };
83
84
85 struct nclist {
86 int type;
87 union node *next;
88 union node *pattern;
89 union node *body;
90 };
91
92
93 struct narg {
94 int type;
95 union node *next;
96 char *text;
97 struct nodelist *backquote;
98 };
99
100
101 struct nfile {
102 int type;
103 union node *next;
104 int fd;
105 union node *fname;
106 char *expfname;
107 };
108
109
110 struct ndup {
111 int type;
112 union node *next;
113 int fd;
114 int dupfd;
115 union node *vname;
116 };
117
118
119 struct nhere {
120 int type;
121 union node *next;
122 int fd;
123 union node *doc;
124 };
125
126
127 struct nnot {
128 int type;
129 union node *com;
130 };
131
132
133 union node {
134 int type;
135 struct nbinary nbinary;
136 struct ncmd ncmd;
137 struct npipe npipe;
138 struct nredir nredir;
139 struct nif nif;
140 struct nfor nfor;
141 struct ncase ncase;
142 struct nclist nclist;
143 struct narg narg;
144 struct nfile nfile;
145 struct ndup ndup;
146 struct nhere nhere;
147 struct nnot nnot;
148 };
149
150
151 struct nodelist {
152 struct nodelist *next;
153 union node *n;
154 };
155
156
157 union node *copyfunc(union node *);
158 void freefunc(union node *);
+0
-143
sh/nodetypes less more
0 # $NetBSD: nodetypes,v 1.12 2003/08/22 11:22:23 agc Exp $
1 # Copyright (c) 1991, 1993
2 # The Regents of the University of California. All rights reserved.
3 #
4 # This code is derived from software contributed to Berkeley by
5 # Kenneth Almquist.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. Neither the name of the University nor the names of its contributors
16 # may be used to endorse or promote products derived from this software
17 # without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 # SUCH DAMAGE.
30 #
31 # @(#)nodetypes 8.2 (Berkeley) 5/4/95
32
33 # This file describes the nodes used in parse trees. Unindented lines
34 # contain a node type followed by a structure tag. Subsequent indented
35 # lines specify the fields of the structure. Several node types can share
36 # the same structure, in which case the fields of the structure should be
37 # specified only once.
38 #
39 # A field of a structure is described by the name of the field followed
40 # by a type. The currently implemented types are:
41 # nodeptr - a pointer to a node
42 # nodelist - a pointer to a list of nodes
43 # string - a pointer to a nul terminated string
44 # int - an integer
45 # other - any type that can be copied by assignment
46 # temp - a field that doesn't have to be copied when the node is copied
47 # The last two types should be followed by the text of a C declaration for
48 # the field.
49
50 NSEMI nbinary # two commands separated by a semicolon
51 type int
52 ch1 nodeptr # the first child
53 ch2 nodeptr # the second child
54
55 NCMD ncmd # a simple command
56 type int
57 backgnd int # set to run command in background
58 args nodeptr # the arguments
59 redirect nodeptr # list of file redirections
60
61 NPIPE npipe # a pipeline
62 type int
63 backgnd int # set to run pipeline in background
64 cmdlist nodelist # the commands in the pipeline
65
66 NREDIR nredir # redirection (of a complex command)
67 type int
68 n nodeptr # the command
69 redirect nodeptr # list of file redirections
70
71 NBACKGND nredir # run command in background
72 NSUBSHELL nredir # run command in a subshell
73
74 NAND nbinary # the && operator
75 NOR nbinary # the || operator
76
77 NIF nif # the if statement. Elif clauses are handled
78 type int # using multiple if nodes.
79 test nodeptr # if test
80 ifpart nodeptr # then ifpart
81 elsepart nodeptr # else elsepart
82
83 NWHILE nbinary # the while statement. First child is the test
84 NUNTIL nbinary # the until statement
85
86 NFOR nfor # the for statement
87 type int
88 args nodeptr # for var in args
89 body nodeptr # do body; done
90 var string # the for variable
91
92 NCASE ncase # a case statement
93 type int
94 expr nodeptr # the word to switch on
95 cases nodeptr # the list of cases (NCLIST nodes)
96
97 NCLIST nclist # a case
98 type int
99 next nodeptr # the next case in list
100 pattern nodeptr # list of patterns for this case
101 body nodeptr # code to execute for this case
102
103
104 NDEFUN narg # define a function. The "next" field contains
105 # the body of the function.
106
107 NARG narg # represents a word
108 type int
109 next nodeptr # next word in list
110 text string # the text of the word
111 backquote nodelist # list of commands in back quotes
112
113 NTO nfile # fd> fname
114 NCLOBBER nfile # fd>| fname
115 NFROM nfile # fd< fname
116 NFROMTO nfile # fd<> fname
117 NAPPEND nfile # fd>> fname
118 type int
119 next nodeptr # next redirection in list
120 fd int # file descriptor being redirected
121 fname nodeptr # file name, in a NARG node
122 expfname temp char *expfname # actual file name
123
124 NTOFD ndup # fd<&dupfd
125 NFROMFD ndup # fd>&dupfd
126 type int
127 next nodeptr # next redirection in list
128 fd int # file descriptor being redirected
129 dupfd int # file descriptor to duplicate
130 vname nodeptr # file name if fd>&$var
131
132
133 NHERE nhere # fd<<\!
134 NXHERE nhere # fd<<!
135 type int
136 next nodeptr # next redirection in list
137 fd int # file descriptor being redirected
138 doc nodeptr # input to command (NARG node)
139
140 NNOT nnot # ! command (actually pipeline)
141 type int
142 com nodeptr
+0
-530
sh/options.c less more
0 /* $NetBSD: options.c,v 1.37 2004/10/30 19:29:27 christos Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: options.c,v 1.37 2004/10/30 19:29:27 christos Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <signal.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46
47 #include "shell.h"
48 #define DEFINE_OPTIONS
49 #include "options.h"
50 #undef DEFINE_OPTIONS
51 #include "nodes.h" /* for other header files */
52 #include "eval.h"
53 #include "jobs.h"
54 #include "input.h"
55 #include "output.h"
56 #include "trap.h"
57 #include "var.h"
58 #include "memalloc.h"
59 #include "error.h"
60 #include "mystring.h"
61 #ifndef SMALL
62 #include "myhistedit.h"
63 #endif
64 #include "show.h"
65
66 char *arg0; /* value of $0 */
67 struct shparam shellparam; /* current positional parameters */
68 char **argptr; /* argument list for builtin commands */
69 char *optionarg; /* set by nextopt (like getopt) */
70 char *optptr; /* used by nextopt */
71
72 char *minusc; /* argument to -c option */
73
74
75 STATIC void options(int);
76 STATIC void minus_o(char *, int);
77 STATIC void setoption(int, int);
78 STATIC int getopts(char *, char *, char **, char ***, char **);
79
80
81 /*
82 * Process the shell command line arguments.
83 */
84
85 void
86 procargs(int argc, char **argv)
87 {
88 int i;
89
90 argptr = argv;
91 if (argc > 0)
92 argptr++;
93 for (i = 0; i < NOPTS; i++)
94 optlist[i].val = 2;
95 options(1);
96 if (*argptr == NULL && minusc == NULL)
97 sflag = 1;
98 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
99 iflag = 1;
100 if (mflag == 2)
101 mflag = iflag;
102 for (i = 0; i < NOPTS; i++)
103 if (optlist[i].val == 2)
104 optlist[i].val = 0;
105 #if DEBUG == 2
106 debug = 1;
107 #endif
108 arg0 = argv[0];
109 if (sflag == 0 && minusc == NULL) {
110 commandname = argv[0];
111 arg0 = *argptr++;
112 setinputfile(arg0, 0);
113 commandname = arg0;
114 }
115 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
116 if (minusc != NULL) {
117 if (argptr == NULL || *argptr == NULL)
118 error("Bad -c option");
119 minusc = *argptr++;
120 if (*argptr != 0)
121 arg0 = *argptr++;
122 }
123
124 shellparam.p = argptr;
125 shellparam.reset = 1;
126 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
127 while (*argptr) {
128 shellparam.nparam++;
129 argptr++;
130 }
131 optschanged();
132 }
133
134
135 void
136 optschanged(void)
137 {
138 setinteractive(iflag);
139 #ifdef WITH_HISTORY
140 histedit();
141 #endif
142 setjobctl(mflag);
143 }
144
145 /*
146 * Process shell options. The global variable argptr contains a pointer
147 * to the argument list; we advance it past the options.
148 */
149
150 STATIC void
151 options(int cmdline)
152 {
153 static char empty[] = "";
154 char *p;
155 int val;
156 int c;
157
158 if (cmdline)
159 minusc = NULL;
160 while ((p = *argptr) != NULL) {
161 argptr++;
162 if ((c = *p++) == '-') {
163 val = 1;
164 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
165 if (!cmdline) {
166 /* "-" means turn off -x and -v */
167 if (p[0] == '\0')
168 xflag = vflag = 0;
169 /* "--" means reset params */
170 else if (*argptr == NULL)
171 setparam(argptr);
172 }
173 break; /* "-" or "--" terminates options */
174 }
175 } else if (c == '+') {
176 val = 0;
177 } else {
178 argptr--;
179 break;
180 }
181 while ((c = *p++) != '\0') {
182 if (c == 'c' && cmdline) {
183 /* command is after shell args*/
184 minusc = empty;
185 } else if (c == 'o') {
186 minus_o(*argptr, val);
187 if (*argptr)
188 argptr++;
189 } else {
190 setoption(c, val);
191 }
192 }
193 }
194 }
195
196 static void
197 set_opt_val(int i, int val)
198 {
199 int j;
200 int flag;
201
202 if (val && (flag = optlist[i].opt_set)) {
203 /* some options (eg vi/emacs) are mutually exclusive */
204 for (j = 0; j < NOPTS; j++)
205 if (optlist[j].opt_set == flag)
206 optlist[j].val = 0;
207 }
208 optlist[i].val = val;
209 #ifdef DEBUG
210 if (&optlist[i].val == &debug)
211 opentrace();
212 #endif
213 }
214
215 STATIC void
216 minus_o(char *name, int val)
217 {
218 int i;
219
220 if (name == NULL) {
221 out1str("Current option settings\n");
222 for (i = 0; i < NOPTS; i++)
223 out1fmt("%-16s%s\n", optlist[i].name,
224 optlist[i].val ? "on" : "off");
225 } else {
226 for (i = 0; i < NOPTS; i++)
227 if (equal(name, optlist[i].name)) {
228 set_opt_val(i, val);
229 return;
230 }
231 error("Illegal option -o %s", name);
232 }
233 }
234
235
236 STATIC void
237 setoption(int flag, int val)
238 {
239 int i;
240
241 for (i = 0; i < NOPTS; i++)
242 if (optlist[i].letter == flag) {
243 set_opt_val( i, val );
244 return;
245 }
246 error("Illegal option -%c", flag);
247 /* NOTREACHED */
248 }
249
250
251
252 #ifdef mkinit
253 INCLUDE "options.h"
254
255 SHELLPROC {
256 int i;
257
258 for (i = 0; optlist[i].name; i++)
259 optlist[i].val = 0;
260 optschanged();
261
262 }
263 #endif
264
265
266 /*
267 * Set the shell parameters.
268 */
269
270 void
271 setparam(char **argv)
272 {
273 char **newparam;
274 char **ap;
275 int nparam;
276
277 for (nparam = 0 ; argv[nparam] ; nparam++);
278 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
279 while (*argv) {
280 *ap++ = savestr(*argv++);
281 }
282 *ap = NULL;
283 freeparam(&shellparam);
284 shellparam.malloc = 1;
285 shellparam.nparam = nparam;
286 shellparam.p = newparam;
287 shellparam.optnext = NULL;
288 }
289
290
291 /*
292 * Free the list of positional parameters.
293 */
294
295 void
296 freeparam(volatile struct shparam *param)
297 {
298 char **ap;
299
300 if (param->malloc) {
301 for (ap = param->p ; *ap ; ap++)
302 ckfree(*ap);
303 ckfree(param->p);
304 }
305 }
306
307
308
309 /*
310 * The shift builtin command.
311 */
312
313 int
314 shiftcmd(int argc, char **argv)
315 {
316 int n;
317 char **ap1, **ap2;
318
319 n = 1;
320 if (argc > 1)
321 n = number(argv[1]);
322 if (n > shellparam.nparam)
323 error("can't shift that many");
324 INTOFF;
325 shellparam.nparam -= n;
326 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
327 if (shellparam.malloc)
328 ckfree(*ap1);
329 }
330 ap2 = shellparam.p;
331 while ((*ap2++ = *ap1++) != NULL);
332 shellparam.optnext = NULL;
333 INTON;
334 return 0;
335 }
336
337
338
339 /*
340 * The set command builtin.
341 */
342
343 int
344 setcmd(int argc, char **argv)
345 {
346 if (argc == 1)
347 return showvars(0, 0, 1);
348 INTOFF;
349 options(0);
350 optschanged();
351 if (*argptr != NULL) {
352 setparam(argptr);
353 }
354 INTON;
355 return 0;
356 }
357
358
359 void
360 getoptsreset(value)
361 const char *value;
362 {
363 if (number(value) == 1) {
364 shellparam.optnext = NULL;
365 shellparam.reset = 1;
366 }
367 }
368
369 /*
370 * The getopts builtin. Shellparam.optnext points to the next argument
371 * to be processed. Shellparam.optptr points to the next character to
372 * be processed in the current argument. If shellparam.optnext is NULL,
373 * then it's the first time getopts has been called.
374 */
375
376 int
377 getoptscmd(int argc, char **argv)
378 {
379 char **optbase;
380
381 if (argc < 3)
382 error("usage: getopts optstring var [arg]");
383 else if (argc == 3)
384 optbase = shellparam.p;
385 else
386 optbase = &argv[3];
387
388 if (shellparam.reset == 1) {
389 shellparam.optnext = optbase;
390 shellparam.optptr = NULL;
391 shellparam.reset = 0;
392 }
393
394 return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
395 &shellparam.optptr);
396 }
397
398 STATIC int
399 getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr)
400 {
401 char *p, *q;
402 char c = '?';
403 int done = 0;
404 int ind = 0;
405 int err = 0;
406 char s[12];
407
408 if ((p = *optpptr) == NULL || *p == '\0') {
409 /* Current word is done, advance */
410 if (*optnext == NULL)
411 return 1;
412 p = **optnext;
413 if (p == NULL || *p != '-' || *++p == '\0') {
414 atend:
415 ind = *optnext - optfirst + 1;
416 *optnext = NULL;
417 p = NULL;
418 done = 1;
419 goto out;
420 }
421 (*optnext)++;
422 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
423 goto atend;
424 }
425
426 c = *p++;
427 for (q = optstr; *q != c; ) {
428 if (*q == '\0') {
429 if (optstr[0] == ':') {
430 s[0] = c;
431 s[1] = '\0';
432 err |= setvarsafe("OPTARG", s, 0);
433 } else {
434 outfmt(&errout, "Illegal option -%c\n", c);
435 (void) unsetvar("OPTARG", 0);
436 }
437 c = '?';
438 goto bad;
439 }
440 if (*++q == ':')
441 q++;
442 }
443
444 if (*++q == ':') {
445 if (*p == '\0' && (p = **optnext) == NULL) {
446 if (optstr[0] == ':') {
447 s[0] = c;
448 s[1] = '\0';
449 err |= setvarsafe("OPTARG", s, 0);
450 c = ':';
451 } else {
452 outfmt(&errout, "No arg for -%c option\n", c);
453 (void) unsetvar("OPTARG", 0);
454 c = '?';
455 }
456 goto bad;
457 }
458
459 if (p == **optnext)
460 (*optnext)++;
461 err |= setvarsafe("OPTARG", p, 0);
462 p = NULL;
463 } else
464 err |= setvarsafe("OPTARG", "", 0);
465 ind = *optnext - optfirst + 1;
466 goto out;
467
468 bad:
469 ind = 1;
470 *optnext = NULL;
471 p = NULL;
472 out:
473 *optpptr = p;
474 fmtstr(s, sizeof(s), "%d", ind);
475 err |= setvarsafe("OPTIND", s, VNOFUNC);
476 s[0] = c;
477 s[1] = '\0';
478 err |= setvarsafe(optvar, s, 0);
479 if (err) {
480 *optnext = NULL;
481 *optpptr = NULL;
482 flushall();
483 exraise(EXERROR);
484 }
485 return done;
486 }
487
488 /*
489 * XXX - should get rid of. have all builtins use getopt(3). the
490 * library getopt must have the BSD extension static variable "optreset"
491 * otherwise it can't be used within the shell safely.
492 *
493 * Standard option processing (a la getopt) for builtin routines. The
494 * only argument that is passed to nextopt is the option string; the
495 * other arguments are unnecessary. It return the character, or '\0' on
496 * end of input.
497 */
498
499 int
500 nextopt(const char *optstring)
501 {
502 char *p;
503 const char *q;
504 char c;
505
506 if ((p = optptr) == NULL || *p == '\0') {
507 p = *argptr;
508 if (p == NULL || *p != '-' || *++p == '\0')
509 return '\0';
510 argptr++;
511 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
512 return '\0';
513 }
514 c = *p++;
515 for (q = optstring ; *q != c ; ) {
516 if (*q == '\0')
517 error("Illegal option -%c", c);
518 if (*++q == ':')
519 q++;
520 }
521 if (*++q == ':') {
522 if (*p == '\0' && (p = *argptr++) == NULL)
523 error("No arg for -%c option", c);
524 optionarg = p;
525 p = NULL;
526 }
527 optptr = p;
528 return c;
529 }
+0
-131
sh/options.h less more
0 /* $NetBSD: options.h,v 1.17 2003/08/07 09:05:36 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)options.h 8.2 (Berkeley) 5/4/95
34 */
35
36 struct shparam {
37 int nparam; /* # of positional parameters (without $0) */
38 unsigned char malloc; /* if parameter list dynamically allocated */
39 unsigned char reset; /* if getopts has been reset */
40 char **p; /* parameter list */
41 char **optnext; /* next parameter to be processed by getopts */
42 char *optptr; /* used by getopts */
43 };
44
45
46 struct optent {
47 const char *name; /* for set -o <name> */
48 const char letter; /* set [+/-]<letter> and $- */
49 const char opt_set; /* mutually exclusive option set */
50 char val; /* value of <letter>flag */
51 };
52
53 /* Those marked [U] are required by posix, but have no effect! */
54
55 #ifdef DEFINE_OPTIONS
56 #define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0},
57 struct optent optlist[] = {
58 #else
59 #define DEF_OPTS(name, letter, opt_set)
60 #endif
61 #define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0)
62
63 DEF_OPT( "errexit", 'e' ) /* exit on error */
64 #define eflag optlist[0].val
65 DEF_OPT( "noglob", 'f' ) /* no pathname expansion */
66 #define fflag optlist[1].val
67 DEF_OPT( "ignoreeof", 'I' ) /* do not exit on EOF */
68 #define Iflag optlist[2].val
69 DEF_OPT( "interactive",'i' ) /* interactive shell */
70 #define iflag optlist[3].val
71 DEF_OPT( "monitor", 'm' ) /* job control */
72 #define mflag optlist[4].val
73 DEF_OPT( "noexec", 'n' ) /* [U] do not exec commands */
74 #define nflag optlist[5].val
75 DEF_OPT( "stdin", 's' ) /* read from stdin */
76 #define sflag optlist[6].val
77 DEF_OPT( "xtrace", 'x' ) /* trace after expansion */
78 #define xflag optlist[7].val
79 DEF_OPT( "verbose", 'v' ) /* trace read input */
80 #define vflag optlist[8].val
81 DEF_OPTS( "vi", 'V', 'V' ) /* vi style editing */
82 #define Vflag optlist[9].val
83 DEF_OPTS( "emacs", 'E', 'V' ) /* emacs style editing */
84 #define Eflag optlist[10].val
85 DEF_OPT( "noclobber", 'C' ) /* do not overwrite files with > */
86 #define Cflag optlist[11].val
87 DEF_OPT( "allexport", 'a' ) /* export all variables */
88 #define aflag optlist[12].val
89 DEF_OPT( "notify", 'b' ) /* [U] report completion of background jobs */
90 #define bflag optlist[13].val
91 DEF_OPT( "nounset", 'u' ) /* error expansion of unset variables */
92 #define uflag optlist[14].val
93 DEF_OPT( "quietprofile", 'q' )
94 #define qflag optlist[15].val
95 DEF_OPT( "nolog", 0 ) /* [U] no functon defs in command history */
96 #define nolog optlist[16].val
97 DEF_OPT( "cdprint", 0 ) /* always print result of cd */
98 #define cdprint optlist[17].val
99 #ifdef DEBUG
100 DEF_OPT( "debug", 0 ) /* enable debug prints */
101 #define debug optlist[18].val
102 #endif
103
104 #ifdef DEFINE_OPTIONS
105 { 0, 0, 0, 0 },
106 };
107 #define NOPTS (sizeof optlist / sizeof optlist[0] - 1)
108 int sizeof_optlist = sizeof optlist;
109 #else
110 extern struct optent optlist[];
111 extern int sizeof_optlist;
112 #endif
113
114
115 extern char *minusc; /* argument to -c option */
116 extern char *arg0; /* $0 */
117 extern struct shparam shellparam; /* $@ */
118 extern char **argptr; /* argument list for builtin commands */
119 extern char *optionarg; /* set by nextopt */
120 extern char *optptr; /* used by nextopt */
121
122 void procargs(int, char **);
123 void optschanged(void);
124 void setparam(char **);
125 void freeparam(volatile struct shparam *);
126 int shiftcmd(int, char **);
127 int setcmd(int, char **);
128 int getoptscmd(int, char **);
129 int nextopt(const char *);
130 void getoptsreset(const char *);
+0
-516
sh/output.c less more
0 /* $NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $");
40 #endif
41 #endif /* not lint */
42
43 /*
44 * Shell output routines. We use our own output routines because:
45 * When a builtin command is interrupted we have to discard
46 * any pending output.
47 * When a builtin command appears in back quotes, we want to
48 * save the output of the command in a region obtained
49 * via malloc, rather than doing a fork and reading the
50 * output of the command via a pipe.
51 * Our output routines may be smaller than the stdio routines.
52 */
53
54 #include <sys/types.h> /* quad_t */
55 #include <sys/param.h> /* BSD4_4 */
56 #include <sys/ioctl.h>
57
58 #include <stdio.h> /* defines BUFSIZ */
59 #include <string.h>
60 #include <errno.h>
61 #include <unistd.h>
62 #include <stdlib.h>
63
64 #include "shell.h"
65 #include "syntax.h"
66 #include "output.h"
67 #include "memalloc.h"
68 #include "error.h"
69
70
71 #define OUTBUFSIZ BUFSIZ
72 #define BLOCK_OUT -2 /* output to a fixed block of memory */
73 #define MEM_OUT -3 /* output to dynamically allocated memory */
74 #define OUTPUT_ERR 01 /* error occurred on output */
75
76
77 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
78 struct output errout = {NULL, 0, NULL, 100, 2, 0};
79 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
80 struct output *out1 = &output;
81 struct output *out2 = &errout;
82
83
84
85 #ifdef mkinit
86
87 INCLUDE "output.h"
88 INCLUDE "memalloc.h"
89
90 RESET {
91 out1 = &output;
92 out2 = &errout;
93 if (memout.buf != NULL) {
94 ckfree(memout.buf);
95 memout.buf = NULL;
96 }
97 }
98
99 #endif
100
101
102 #ifdef notdef /* no longer used */
103 /*
104 * Set up an output file to write to memory rather than a file.
105 */
106
107 void
108 open_mem(char *block, int length, struct output *file)
109 {
110 file->nextc = block;
111 file->nleft = --length;
112 file->fd = BLOCK_OUT;
113 file->flags = 0;
114 }
115 #endif
116
117
118 void
119 out1str(const char *p)
120 {
121 outstr(p, out1);
122 }
123
124
125 void
126 out2str(const char *p)
127 {
128 outstr(p, out2);
129 }
130
131
132 void
133 outstr(const char *p, struct output *file)
134 {
135 while (*p)
136 outc(*p++, file);
137 if (file == out2)
138 flushout(file);
139 }
140
141
142 char out_junk[16];
143
144
145 void
146 emptyoutbuf(struct output *dest)
147 {
148 int offset;
149
150 if (dest->fd == BLOCK_OUT) {
151 dest->nextc = out_junk;
152 dest->nleft = sizeof out_junk;
153 dest->flags |= OUTPUT_ERR;
154 } else if (dest->buf == NULL) {
155 INTOFF;
156 dest->buf = ckmalloc(dest->bufsize);
157 dest->nextc = dest->buf;
158 dest->nleft = dest->bufsize;
159 INTON;
160 } else if (dest->fd == MEM_OUT) {
161 offset = dest->bufsize;
162 INTOFF;
163 dest->bufsize <<= 1;
164 dest->buf = ckrealloc(dest->buf, dest->bufsize);
165 dest->nleft = dest->bufsize - offset;
166 dest->nextc = dest->buf + offset;
167 INTON;
168 } else {
169 flushout(dest);
170 }
171 dest->nleft--;
172 }
173
174
175 void
176 flushall(void)
177 {
178 flushout(&output);
179 flushout(&errout);
180 }
181
182
183 void
184 flushout(struct output *dest)
185 {
186
187 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
188 return;
189 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
190 dest->flags |= OUTPUT_ERR;
191 dest->nextc = dest->buf;
192 dest->nleft = dest->bufsize;
193 }
194
195
196 void
197 freestdout(void)
198 {
199 INTOFF;
200 if (output.buf) {
201 ckfree(output.buf);
202 output.buf = NULL;
203 output.nleft = 0;
204 }
205 INTON;
206 }
207
208
209 void
210 outfmt(struct output *file, const char *fmt, ...)
211 {
212 va_list ap;
213
214 va_start(ap, fmt);
215 doformat(file, fmt, ap);
216 va_end(ap);
217 }
218
219
220 void
221 out1fmt(const char *fmt, ...)
222 {
223 va_list ap;
224
225 va_start(ap, fmt);
226 doformat(out1, fmt, ap);
227 va_end(ap);
228 }
229
230 void
231 dprintf(const char *fmt, ...)
232 {
233 va_list ap;
234
235 va_start(ap, fmt);
236 doformat(out2, fmt, ap);
237 va_end(ap);
238 flushout(out2);
239 }
240
241 void
242 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
243 {
244 va_list ap;
245 struct output strout;
246
247 va_start(ap, fmt);
248 strout.nextc = outbuf;
249 strout.nleft = length;
250 strout.fd = BLOCK_OUT;
251 strout.flags = 0;
252 doformat(&strout, fmt, ap);
253 outc('\0', &strout);
254 if (strout.flags & OUTPUT_ERR)
255 outbuf[length - 1] = '\0';
256 va_end(ap);
257 }
258
259 /*
260 * Formatted output. This routine handles a subset of the printf formats:
261 * - Formats supported: d, u, o, p, X, s, and c.
262 * - The x format is also accepted but is treated like X.
263 * - The l, ll and q modifiers are accepted.
264 * - The - and # flags are accepted; # only works with the o format.
265 * - Width and precision may be specified with any format except c.
266 * - An * may be given for the width or precision.
267 * - The obsolete practice of preceding the width with a zero to get
268 * zero padding is not supported; use the precision field.
269 * - A % may be printed by writing %% in the format string.
270 */
271
272 #define TEMPSIZE 24
273
274 #ifdef BSD4_4
275 #define HAVE_VASPRINTF 1
276 #endif
277
278 void
279 doformat(struct output *dest, const char *f, va_list ap)
280 {
281 #if HAVE_VASPRINTF
282 char *s;
283
284 vasprintf(&s, f, ap);
285 outstr(s, dest);
286 free(s);
287 #else /* !HAVE_VASPRINTF */
288 static const char digit[] = "0123456789ABCDEF";
289 char c;
290 char temp[TEMPSIZE];
291 int flushleft;
292 int sharp;
293 int width;
294 int prec;
295 int islong;
296 int isquad;
297 char *p;
298 int sign;
299 #ifdef BSD4_4
300 quad_t l;
301 u_quad_t num;
302 #else
303 long l;
304 u_long num;
305 #endif
306 unsigned base;
307 int len;
308 int size;
309 int pad;
310
311 while ((c = *f++) != '\0') {
312 if (c != '%') {
313 outc(c, dest);
314 continue;
315 }
316 flushleft = 0;
317 sharp = 0;
318 width = 0;
319 prec = -1;
320 islong = 0;
321 isquad = 0;
322 for (;;) {
323 if (*f == '-')
324 flushleft++;
325 else if (*f == '#')
326 sharp++;
327 else
328 break;
329 f++;
330 }
331 if (*f == '*') {
332 width = va_arg(ap, int);
333 f++;
334 } else {
335 while (is_digit(*f)) {
336 width = 10 * width + digit_val(*f++);
337 }
338 }
339 if (*f == '.') {
340 if (*++f == '*') {
341 prec = va_arg(ap, int);
342 f++;
343 } else {
344 prec = 0;
345 while (is_digit(*f)) {
346 prec = 10 * prec + digit_val(*f++);
347 }
348 }
349 }
350 if (*f == 'l') {
351 f++;
352 if (*f == 'l') {
353 isquad++;
354 f++;
355 } else
356 islong++;
357 } else if (*f == 'q') {
358 isquad++;
359 f++;
360 }
361 switch (*f) {
362 case 'd':
363 #ifdef BSD4_4
364 if (isquad)
365 l = va_arg(ap, quad_t);
366 else
367 #endif
368 if (islong)
369 l = va_arg(ap, long);
370 else
371 l = va_arg(ap, int);
372 sign = 0;
373 num = l;
374 if (l < 0) {
375 num = -l;
376 sign = 1;
377 }
378 base = 10;
379 goto number;
380 case 'u':
381 base = 10;
382 goto uns_number;
383 case 'o':
384 base = 8;
385 goto uns_number;
386 case 'p':
387 outc('0', dest);
388 outc('x', dest);
389 /*FALLTHROUGH*/
390 case 'x':
391 /* we don't implement 'x'; treat like 'X' */
392 case 'X':
393 base = 16;
394 uns_number: /* an unsigned number */
395 sign = 0;
396 #ifdef BSD4_4
397 if (isquad)
398 num = va_arg(ap, u_quad_t);
399 else
400 #endif
401 if (islong)
402 num = va_arg(ap, unsigned long);
403 else
404 num = va_arg(ap, unsigned int);
405 number: /* process a number */
406 p = temp + TEMPSIZE - 1;
407 *p = '\0';
408 while (num) {
409 *--p = digit[num % base];
410 num /= base;
411 }
412 len = (temp + TEMPSIZE - 1) - p;
413 if (prec < 0)
414 prec = 1;
415 if (sharp && *f == 'o' && prec <= len)
416 prec = len + 1;
417 pad = 0;
418 if (width) {
419 size = len;
420 if (size < prec)
421 size = prec;
422 size += sign;
423 pad = width - size;
424 if (flushleft == 0) {
425 while (--pad >= 0)
426 outc(' ', dest);
427 }
428 }
429 if (sign)
430 outc('-', dest);
431 prec -= len;
432 while (--prec >= 0)
433 outc('0', dest);
434 while (*p)
435 outc(*p++, dest);
436 while (--pad >= 0)
437 outc(' ', dest);
438 break;
439 case 's':
440 p = va_arg(ap, char *);
441 pad = 0;
442 if (width) {
443 len = strlen(p);
444 if (prec >= 0 && len > prec)
445 len = prec;
446 pad = width - len;
447 if (flushleft == 0) {
448 while (--pad >= 0)
449 outc(' ', dest);
450 }
451 }
452 prec++;
453 while (--prec != 0 && *p)
454 outc(*p++, dest);
455 while (--pad >= 0)
456 outc(' ', dest);
457 break;
458 case 'c':
459 c = va_arg(ap, int);
460 outc(c, dest);
461 break;
462 default:
463 outc(*f, dest);
464 break;
465 }
466 f++;
467 }
468 #endif /* !HAVE_VASPRINTF */
469 }
470
471
472
473 /*
474 * Version of write which resumes after a signal is caught.
475 */
476
477 int
478 xwrite(int fd, char *buf, int nbytes)
479 {
480 int ntry;
481 int i;
482 int n;
483
484 n = nbytes;
485 ntry = 0;
486 for (;;) {
487 i = write(fd, buf, n);
488 if (i > 0) {
489 if ((n -= i) <= 0)
490 return nbytes;
491 buf += i;
492 ntry = 0;
493 } else if (i == 0) {
494 if (++ntry > 10)
495 return nbytes - n;
496 } else if (errno != EINTR) {
497 return -1;
498 }
499 }
500 }
501
502
503 /*
504 * Version of ioctl that retries after a signal is caught.
505 * XXX unused function
506 */
507
508 int
509 xioctl(int fd, unsigned long request, char *arg)
510 {
511 int i;
512
513 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
514 return i;
515 }
+0
-81
sh/output.h less more
0 /* $NetBSD: output.h,v 1.17 2003/08/07 09:05:36 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)output.h 8.2 (Berkeley) 5/4/95
34 */
35
36 #ifndef OUTPUT_INCL
37
38 #include <stdarg.h>
39
40 struct output {
41 char *nextc;
42 int nleft;
43 char *buf;
44 int bufsize;
45 short fd;
46 short flags;
47 };
48
49 extern struct output output;
50 extern struct output errout;
51 extern struct output memout;
52 extern struct output *out1;
53 extern struct output *out2;
54
55 void open_mem(char *, int, struct output *);
56 void out1str(const char *);
57 void out2str(const char *);
58 void outstr(const char *, struct output *);
59 void emptyoutbuf(struct output *);
60 void flushall(void);
61 void flushout(struct output *);
62 void freestdout(void);
63 void outfmt(struct output *, const char *, ...)
64 __attribute__((__format__(__printf__,2,3)));
65 void out1fmt(const char *, ...)
66 __attribute__((__format__(__printf__,1,2)));
67 void dprintf(const char *, ...)
68 __attribute__((__format__(__printf__,1,2)));
69 void fmtstr(char *, size_t, const char *, ...)
70 __attribute__((__format__(__printf__,3,4)));
71 void doformat(struct output *, const char *, va_list);
72 int xwrite(int, char *, int);
73 int xioctl(int, unsigned long, char *);
74
75 #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
76 #define out1c(c) outc(c, out1);
77 #define out2c(c) outc(c, out2);
78
79 #define OUTPUT_INCL
80 #endif
+0
-1651
sh/parser.c less more
0 /* $NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
38 #else
39 __RCSID("$NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <stdlib.h>
44
45 #include "shell.h"
46 #include "parser.h"
47 #include "nodes.h"
48 #include "expand.h" /* defines rmescapes() */
49 #include "eval.h" /* defines commandname */
50 #include "redir.h" /* defines copyfd() */
51 #include "syntax.h"
52 #include "options.h"
53 #include "input.h"
54 #include "output.h"
55 #include "var.h"
56 #include "error.h"
57 #include "memalloc.h"
58 #include "mystring.h"
59 #include "alias.h"
60 #include "show.h"
61 #ifndef SMALL
62 #include "myhistedit.h"
63 #endif
64
65 /*
66 * Shell command parser.
67 */
68
69 #define EOFMARKLEN 79
70
71 /* values returned by readtoken */
72 #include "token.h"
73
74 #define OPENBRACE '{'
75 #define CLOSEBRACE '}'
76
77
78 struct heredoc {
79 struct heredoc *next; /* next here document in list */
80 union node *here; /* redirection node */
81 char *eofmark; /* string indicating end of input */
82 int striptabs; /* if set, strip leading tabs */
83 };
84
85
86
87 static int noalias = 0; /* when set, don't handle aliases */
88 struct heredoc *heredoclist; /* list of here documents to read */
89 int parsebackquote; /* nonzero if we are inside backquotes */
90 int doprompt; /* if set, prompt the user */
91 int needprompt; /* true if interactive and at start of line */
92 int lasttoken; /* last token read */
93 MKINIT int tokpushback; /* last token pushed back */
94 char *wordtext; /* text of last word returned by readtoken */
95 MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
96 struct nodelist *backquotelist;
97 union node *redirnode;
98 struct heredoc *heredoc;
99 int quoteflag; /* set if (part of) last token was quoted */
100 int startlinno; /* line # where last token started */
101
102
103 STATIC union node *list(int);
104 STATIC union node *andor(void);
105 STATIC union node *pipeline(void);
106 STATIC union node *command(void);
107 STATIC union node *simplecmd(union node **, union node *);
108 STATIC union node *makename(void);
109 STATIC void parsefname(void);
110 STATIC void parseheredoc(void);
111 STATIC int peektoken(void);
112 STATIC int readtoken(void);
113 STATIC int xxreadtoken(void);
114 STATIC int readtoken1(int, char const *, char *, int);
115 STATIC int noexpand(char *);
116 STATIC void synexpect(int) __attribute__((__noreturn__));
117 STATIC void synerror(const char *) __attribute__((__noreturn__));
118 STATIC void setprompt(int);
119
120
121 /*
122 * Read and parse a command. Returns NEOF on end of file. (NULL is a
123 * valid parse tree indicating a blank line.)
124 */
125
126 union node *
127 parsecmd(int interact)
128 {
129 int t;
130
131 tokpushback = 0;
132 doprompt = interact;
133 if (doprompt)
134 setprompt(1);
135 else
136 setprompt(0);
137 needprompt = 0;
138 t = readtoken();
139 if (t == TEOF)
140 return NEOF;
141 if (t == TNL)
142 return NULL;
143 tokpushback++;
144 return list(1);
145 }
146
147
148 STATIC union node *
149 list(int nlflag)
150 {
151 union node *n1, *n2, *n3;
152 int tok;
153
154 checkkwd = 2;
155 if (nlflag == 0 && tokendlist[peektoken()])
156 return NULL;
157 n1 = NULL;
158 for (;;) {
159 n2 = andor();
160 tok = readtoken();
161 if (tok == TBACKGND) {
162 if (n2->type == NCMD || n2->type == NPIPE) {
163 n2->ncmd.backgnd = 1;
164 } else if (n2->type == NREDIR) {
165 n2->type = NBACKGND;
166 } else {
167 n3 = (union node *)stalloc(sizeof (struct nredir));
168 n3->type = NBACKGND;
169 n3->nredir.n = n2;
170 n3->nredir.redirect = NULL;
171 n2 = n3;
172 }
173 }
174 if (n1 == NULL) {
175 n1 = n2;
176 }
177 else {
178 n3 = (union node *)stalloc(sizeof (struct nbinary));
179 n3->type = NSEMI;
180 n3->nbinary.ch1 = n1;
181 n3->nbinary.ch2 = n2;
182 n1 = n3;
183 }
184 switch (tok) {
185 case TBACKGND:
186 case TSEMI:
187 tok = readtoken();
188 /* fall through */
189 case TNL:
190 if (tok == TNL) {
191 parseheredoc();
192 if (nlflag)
193 return n1;
194 } else {
195 tokpushback++;
196 }
197 checkkwd = 2;
198 if (tokendlist[peektoken()])
199 return n1;
200 break;
201 case TEOF:
202 if (heredoclist)
203 parseheredoc();
204 else
205 pungetc(); /* push back EOF on input */
206 return n1;
207 default:
208 if (nlflag)
209 synexpect(-1);
210 tokpushback++;
211 return n1;
212 }
213 }
214 }
215
216
217
218 STATIC union node *
219 andor(void)
220 {
221 union node *n1, *n2, *n3;
222 int t;
223
224 n1 = pipeline();
225 for (;;) {
226 if ((t = readtoken()) == TAND) {
227 t = NAND;
228 } else if (t == TOR) {
229 t = NOR;
230 } else {
231 tokpushback++;
232 return n1;
233 }
234 n2 = pipeline();
235 n3 = (union node *)stalloc(sizeof (struct nbinary));
236 n3->type = t;
237 n3->nbinary.ch1 = n1;
238 n3->nbinary.ch2 = n2;
239 n1 = n3;
240 }
241 }
242
243
244
245 STATIC union node *
246 pipeline(void)
247 {
248 union node *n1, *n2, *pipenode;
249 struct nodelist *lp, *prev;
250 int negate;
251
252 negate = 0;
253 TRACE(("pipeline: entered\n"));
254 while (readtoken() == TNOT)
255 negate = !negate;
256 tokpushback++;
257 n1 = command();
258 if (readtoken() == TPIPE) {
259 pipenode = (union node *)stalloc(sizeof (struct npipe));
260 pipenode->type = NPIPE;
261 pipenode->npipe.backgnd = 0;
262 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
263 pipenode->npipe.cmdlist = lp;
264 lp->n = n1;
265 do {
266 prev = lp;
267 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
268 lp->n = command();
269 prev->next = lp;
270 } while (readtoken() == TPIPE);
271 lp->next = NULL;
272 n1 = pipenode;
273 }
274 tokpushback++;
275 if (negate) {
276 n2 = (union node *)stalloc(sizeof (struct nnot));
277 n2->type = NNOT;
278 n2->nnot.com = n1;
279 return n2;
280 } else
281 return n1;
282 }
283
284
285
286 STATIC union node *
287 command(void)
288 {
289 union node *n1, *n2;
290 union node *ap, **app;
291 union node *cp, **cpp;
292 union node *redir, **rpp;
293 int t, negate = 0;
294
295 checkkwd = 2;
296 redir = NULL;
297 n1 = NULL;
298 rpp = &redir;
299
300 /* Check for redirection which may precede command */
301 while (readtoken() == TREDIR) {
302 *rpp = n2 = redirnode;
303 rpp = &n2->nfile.next;
304 parsefname();
305 }
306 tokpushback++;
307
308 while (readtoken() == TNOT) {
309 TRACE(("command: TNOT recognized\n"));
310 negate = !negate;
311 }
312 tokpushback++;
313
314 switch (readtoken()) {
315 case TIF:
316 n1 = (union node *)stalloc(sizeof (struct nif));
317 n1->type = NIF;
318 n1->nif.test = list(0);
319 if (readtoken() != TTHEN)
320 synexpect(TTHEN);
321 n1->nif.ifpart = list(0);
322 n2 = n1;
323 while (readtoken() == TELIF) {
324 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
325 n2 = n2->nif.elsepart;
326 n2->type = NIF;
327 n2->nif.test = list(0);
328 if (readtoken() != TTHEN)
329 synexpect(TTHEN);
330 n2->nif.ifpart = list(0);
331 }
332 if (lasttoken == TELSE)
333 n2->nif.elsepart = list(0);
334 else {
335 n2->nif.elsepart = NULL;
336 tokpushback++;
337 }
338 if (readtoken() != TFI)
339 synexpect(TFI);
340 checkkwd = 1;
341 break;
342 case TWHILE:
343 case TUNTIL: {
344 int got;
345 n1 = (union node *)stalloc(sizeof (struct nbinary));
346 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
347 n1->nbinary.ch1 = list(0);
348 if ((got=readtoken()) != TDO) {
349 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
350 synexpect(TDO);
351 }
352 n1->nbinary.ch2 = list(0);
353 if (readtoken() != TDONE)
354 synexpect(TDONE);
355 checkkwd = 1;
356 break;
357 }
358 case TFOR:
359 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
360 synerror("Bad for loop variable");
361 n1 = (union node *)stalloc(sizeof (struct nfor));
362 n1->type = NFOR;
363 n1->nfor.var = wordtext;
364 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
365 app = &ap;
366 while (readtoken() == TWORD) {
367 n2 = (union node *)stalloc(sizeof (struct narg));
368 n2->type = NARG;
369 n2->narg.text = wordtext;
370 n2->narg.backquote = backquotelist;
371 *app = n2;
372 app = &n2->narg.next;
373 }
374 *app = NULL;
375 n1->nfor.args = ap;
376 if (lasttoken != TNL && lasttoken != TSEMI)
377 synexpect(-1);
378 } else {
379 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
380 '@', '=', '\0'};
381 n2 = (union node *)stalloc(sizeof (struct narg));
382 n2->type = NARG;
383 n2->narg.text = argvars;
384 n2->narg.backquote = NULL;
385 n2->narg.next = NULL;
386 n1->nfor.args = n2;
387 /*
388 * Newline or semicolon here is optional (but note
389 * that the original Bourne shell only allowed NL).
390 */
391 if (lasttoken != TNL && lasttoken != TSEMI)
392 tokpushback++;
393 }
394 checkkwd = 2;
395 if ((t = readtoken()) == TDO)
396 t = TDONE;
397 else if (t == TBEGIN)
398 t = TEND;
399 else
400 synexpect(-1);
401 n1->nfor.body = list(0);
402 if (readtoken() != t)
403 synexpect(t);
404 checkkwd = 1;
405 break;
406 case TCASE:
407 n1 = (union node *)stalloc(sizeof (struct ncase));
408 n1->type = NCASE;
409 if (readtoken() != TWORD)
410 synexpect(TWORD);
411 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
412 n2->type = NARG;
413 n2->narg.text = wordtext;
414 n2->narg.backquote = backquotelist;
415 n2->narg.next = NULL;
416 while (readtoken() == TNL);
417 if (lasttoken != TWORD || ! equal(wordtext, "in"))
418 synerror("expecting \"in\"");
419 cpp = &n1->ncase.cases;
420 noalias = 1;
421 checkkwd = 2, readtoken();
422 do {
423 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
424 cp->type = NCLIST;
425 app = &cp->nclist.pattern;
426 for (;;) {
427 *app = ap = (union node *)stalloc(sizeof (struct narg));
428 ap->type = NARG;
429 ap->narg.text = wordtext;
430 ap->narg.backquote = backquotelist;
431 if (checkkwd = 2, readtoken() != TPIPE)
432 break;
433 app = &ap->narg.next;
434 readtoken();
435 }
436 ap->narg.next = NULL;
437 noalias = 0;
438 if (lasttoken != TRP) {
439 synexpect(TRP);
440 }
441 cp->nclist.body = list(0);
442
443 checkkwd = 2;
444 if ((t = readtoken()) != TESAC) {
445 if (t != TENDCASE) {
446 noalias = 0;
447 synexpect(TENDCASE);
448 } else {
449 noalias = 1;
450 checkkwd = 2;
451 readtoken();
452 }
453 }
454 cpp = &cp->nclist.next;
455 } while(lasttoken != TESAC);
456 noalias = 0;
457 *cpp = NULL;
458 checkkwd = 1;
459 break;
460 case TLP:
461 n1 = (union node *)stalloc(sizeof (struct nredir));
462 n1->type = NSUBSHELL;
463 n1->nredir.n = list(0);
464 n1->nredir.redirect = NULL;
465 if (readtoken() != TRP)
466 synexpect(TRP);
467 checkkwd = 1;
468 break;
469 case TBEGIN:
470 n1 = list(0);
471 if (readtoken() != TEND)
472 synexpect(TEND);
473 checkkwd = 1;
474 break;
475 /* Handle an empty command like other simple commands. */
476 case TSEMI:
477 /*
478 * An empty command before a ; doesn't make much sense, and
479 * should certainly be disallowed in the case of `if ;'.
480 */
481 if (!redir)
482 synexpect(-1);
483 case TAND:
484 case TOR:
485 case TNL:
486 case TEOF:
487 case TWORD:
488 case TRP:
489 tokpushback++;
490 n1 = simplecmd(rpp, redir);
491 goto checkneg;
492 default:
493 synexpect(-1);
494 /* NOTREACHED */
495 }
496
497 /* Now check for redirection which may follow command */
498 while (readtoken() == TREDIR) {
499 *rpp = n2 = redirnode;
500 rpp = &n2->nfile.next;
501 parsefname();
502 }
503 tokpushback++;
504 *rpp = NULL;
505 if (redir) {
506 if (n1->type != NSUBSHELL) {
507 n2 = (union node *)stalloc(sizeof (struct nredir));
508 n2->type = NREDIR;
509 n2->nredir.n = n1;
510 n1 = n2;
511 }
512 n1->nredir.redirect = redir;
513 }
514
515 checkneg:
516 if (negate) {
517 n2 = (union node *)stalloc(sizeof (struct nnot));
518 n2->type = NNOT;
519 n2->nnot.com = n1;
520 return n2;
521 }
522 else
523 return n1;
524 }
525
526
527 STATIC union node *
528 simplecmd(union node **rpp, union node *redir)
529 {
530 union node *args, **app;
531 union node **orig_rpp = rpp;
532 union node *n = NULL, *n2;
533 int negate = 0;
534
535 /* If we don't have any redirections already, then we must reset */
536 /* rpp to be the address of the local redir variable. */
537 if (redir == 0)
538 rpp = &redir;
539
540 args = NULL;
541 app = &args;
542 /*
543 * We save the incoming value, because we need this for shell
544 * functions. There can not be a redirect or an argument between
545 * the function name and the open parenthesis.
546 */
547 orig_rpp = rpp;
548
549 while (readtoken() == TNOT) {
550 TRACE(("command: TNOT recognized\n"));
551 negate = !negate;
552 }
553 tokpushback++;
554
555 for (;;) {
556 if (readtoken() == TWORD) {
557 n = (union node *)stalloc(sizeof (struct narg));
558 n->type = NARG;
559 n->narg.text = wordtext;
560 n->narg.backquote = backquotelist;
561 *app = n;
562 app = &n->narg.next;
563 } else if (lasttoken == TREDIR) {
564 *rpp = n = redirnode;
565 rpp = &n->nfile.next;
566 parsefname(); /* read name of redirection file */
567 } else if (lasttoken == TLP && app == &args->narg.next
568 && rpp == orig_rpp) {
569 /* We have a function */
570 if (readtoken() != TRP)
571 synexpect(TRP);
572 #ifdef notdef
573 if (! goodname(n->narg.text))
574 synerror("Bad function name");
575 #endif
576 n->type = NDEFUN;
577 n->narg.next = command();
578 goto checkneg;
579 } else {
580 tokpushback++;
581 break;
582 }
583 }
584 *app = NULL;
585 *rpp = NULL;
586 n = (union node *)stalloc(sizeof (struct ncmd));
587 n->type = NCMD;
588 n->ncmd.backgnd = 0;
589 n->ncmd.args = args;
590 n->ncmd.redirect = redir;
591
592 checkneg:
593 if (negate) {
594 n2 = (union node *)stalloc(sizeof (struct nnot));
595 n2->type = NNOT;
596 n2->nnot.com = n;
597 return n2;
598 }
599 else
600 return n;
601 }
602
603 STATIC union node *
604 makename(void)
605 {
606 union node *n;
607
608 n = (union node *)stalloc(sizeof (struct narg));
609 n->type = NARG;
610 n->narg.next = NULL;
611 n->narg.text = wordtext;
612 n->narg.backquote = backquotelist;
613 return n;
614 }
615
616 void fixredir(union node *n, const char *text, int err)
617 {
618 TRACE(("Fix redir %s %d\n", text, err));
619 if (!err)
620 n->ndup.vname = NULL;
621
622 if (is_digit(text[0]) && text[1] == '\0')
623 n->ndup.dupfd = digit_val(text[0]);
624 else if (text[0] == '-' && text[1] == '\0')
625 n->ndup.dupfd = -1;
626 else {
627
628 if (err)
629 synerror("Bad fd number");
630 else
631 n->ndup.vname = makename();
632 }
633 }
634
635
636 STATIC void
637 parsefname(void)
638 {
639 union node *n = redirnode;
640
641 if (readtoken() != TWORD)
642 synexpect(-1);
643 if (n->type == NHERE) {
644 struct heredoc *here = heredoc;
645 struct heredoc *p;
646 int i;
647
648 if (quoteflag == 0)
649 n->type = NXHERE;
650 TRACE(("Here document %d\n", n->type));
651 if (here->striptabs) {
652 while (*wordtext == '\t')
653 wordtext++;
654 }
655 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
656 synerror("Illegal eof marker for << redirection");
657 rmescapes(wordtext);
658 here->eofmark = wordtext;
659 here->next = NULL;
660 if (heredoclist == NULL)
661 heredoclist = here;
662 else {
663 for (p = heredoclist ; p->next ; p = p->next);
664 p->next = here;
665 }
666 } else if (n->type == NTOFD || n->type == NFROMFD) {
667 fixredir(n, wordtext, 0);
668 } else {
669 n->nfile.fname = makename();
670 }
671 }
672
673
674 /*
675 * Input any here documents.
676 */
677
678 STATIC void
679 parseheredoc(void)
680 {
681 struct heredoc *here;
682 union node *n;
683
684 while (heredoclist) {
685 here = heredoclist;
686 heredoclist = here->next;
687 if (needprompt) {
688 setprompt(2);
689 needprompt = 0;
690 }
691 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
692 here->eofmark, here->striptabs);
693 n = (union node *)stalloc(sizeof (struct narg));
694 n->narg.type = NARG;
695 n->narg.next = NULL;
696 n->narg.text = wordtext;
697 n->narg.backquote = backquotelist;
698 here->here->nhere.doc = n;
699 }
700 }
701
702 STATIC int
703 peektoken(void)
704 {
705 int t;
706
707 t = readtoken();
708 tokpushback++;
709 return (t);
710 }
711
712 STATIC int
713 readtoken(void)
714 {
715 int t;
716 int savecheckkwd = checkkwd;
717 #ifdef DEBUG
718 int alreadyseen = tokpushback;
719 #endif
720 struct alias *ap;
721
722 top:
723 t = xxreadtoken();
724
725 if (checkkwd) {
726 /*
727 * eat newlines
728 */
729 if (checkkwd == 2) {
730 checkkwd = 0;
731 while (t == TNL) {
732 parseheredoc();
733 t = xxreadtoken();
734 }
735 } else
736 checkkwd = 0;
737 /*
738 * check for keywords and aliases
739 */
740 if (t == TWORD && !quoteflag)
741 {
742 const char *const *pp;
743
744 for (pp = parsekwd; *pp; pp++) {
745 if (**pp == *wordtext && equal(*pp, wordtext))
746 {
747 lasttoken = t = pp -
748 parsekwd + KWDOFFSET;
749 TRACE(("keyword %s recognized\n", tokname[t]));
750 goto out;
751 }
752 }
753 if(!noalias &&
754 (ap = lookupalias(wordtext, 1)) != NULL) {
755 pushstring(ap->val, strlen(ap->val), ap);
756 checkkwd = savecheckkwd;
757 goto top;
758 }
759 }
760 out:
761 checkkwd = (t == TNOT) ? savecheckkwd : 0;
762 }
763 #ifdef DEBUG
764 if (!alreadyseen)
765 TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
766 else
767 TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
768 #endif
769 return (t);
770 }
771
772
773 /*
774 * Read the next input token.
775 * If the token is a word, we set backquotelist to the list of cmds in
776 * backquotes. We set quoteflag to true if any part of the word was
777 * quoted.
778 * If the token is TREDIR, then we set redirnode to a structure containing
779 * the redirection.
780 * In all cases, the variable startlinno is set to the number of the line
781 * on which the token starts.
782 *
783 * [Change comment: here documents and internal procedures]
784 * [Readtoken shouldn't have any arguments. Perhaps we should make the
785 * word parsing code into a separate routine. In this case, readtoken
786 * doesn't need to have any internal procedures, but parseword does.
787 * We could also make parseoperator in essence the main routine, and
788 * have parseword (readtoken1?) handle both words and redirection.]
789 */
790
791 #define RETURN(token) return lasttoken = token
792
793 STATIC int
794 xxreadtoken(void)
795 {
796 int c;
797
798 if (tokpushback) {
799 tokpushback = 0;
800 return lasttoken;
801 }
802 if (needprompt) {
803 setprompt(2);
804 needprompt = 0;
805 }
806 startlinno = plinno;
807 for (;;) { /* until token or start of word found */
808 c = pgetc_macro();
809 if (c == ' ' || c == '\t')
810 continue; /* quick check for white space first */
811 switch (c) {
812 case ' ': case '\t':
813 continue;
814 case '#':
815 while ((c = pgetc()) != '\n' && c != PEOF);
816 pungetc();
817 continue;
818 case '\\':
819 if (pgetc() == '\n') {
820 startlinno = ++plinno;
821 if (doprompt)
822 setprompt(2);
823 else
824 setprompt(0);
825 continue;
826 }
827 pungetc();
828 goto breakloop;
829 case '\n':
830 plinno++;
831 needprompt = doprompt;
832 RETURN(TNL);
833 case PEOF:
834 RETURN(TEOF);
835 case '&':
836 if (pgetc() == '&')
837 RETURN(TAND);
838 pungetc();
839 RETURN(TBACKGND);
840 case '|':
841 if (pgetc() == '|')
842 RETURN(TOR);
843 pungetc();
844 RETURN(TPIPE);
845 case ';':
846 if (pgetc() == ';')
847 RETURN(TENDCASE);
848 pungetc();
849 RETURN(TSEMI);
850 case '(':
851 RETURN(TLP);
852 case ')':
853 RETURN(TRP);
854 default:
855 goto breakloop;
856 }
857 }
858 breakloop:
859 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
860 #undef RETURN
861 }
862
863
864
865 /*
866 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
867 * is not NULL, read a here document. In the latter case, eofmark is the
868 * word which marks the end of the document and striptabs is true if
869 * leading tabs should be stripped from the document. The argument firstc
870 * is the first character of the input token or document.
871 *
872 * Because C does not have internal subroutines, I have simulated them
873 * using goto's to implement the subroutine linkage. The following macros
874 * will run code that appears at the end of readtoken1.
875 */
876
877 #define CHECKEND() {goto checkend; checkend_return:;}
878 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
879 #define PARSESUB() {goto parsesub; parsesub_return:;}
880 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
881 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
882 #define PARSEARITH() {goto parsearith; parsearith_return:;}
883
884 /*
885 * Keep track of nested doublequotes in dblquote and doublequotep.
886 * We use dblquote for the first 32 levels, and we expand to a malloc'ed
887 * region for levels above that. Usually we never need to malloc.
888 * This code assumes that an int is 32 bits. We don't use uint32_t,
889 * because the rest of the code does not.
890 */
891 #define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \
892 (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32))))
893
894 #define SETDBLQUOTE() \
895 if (varnest < 32) \
896 dblquote |= (1 << varnest); \
897 else \
898 dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32))
899
900 #define CLRDBLQUOTE() \
901 if (varnest < 32) \
902 dblquote &= ~(1 << varnest); \
903 else \
904 dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32))
905
906 STATIC int
907 readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
908 {
909 int c = firstc;
910 char *out;
911 int len;
912 char line[EOFMARKLEN + 1];
913 struct nodelist *bqlist;
914 int quotef;
915 int *dblquotep = NULL;
916 size_t maxnest = 32;
917 int dblquote;
918 int varnest; /* levels of variables expansion */
919 int arinest; /* levels of arithmetic expansion */
920 int parenlevel; /* levels of parens in arithmetic */
921 int oldstyle;
922 char const *prevsyntax = NULL; /* syntax before arithmetic */
923 #if __GNUC__
924 /* Avoid longjmp clobbering */
925 (void) &maxnest;
926 (void) &dblquotep;
927 (void) &out;
928 (void) &quotef;
929 (void) &dblquote;
930 (void) &varnest;
931 (void) &arinest;
932 (void) &parenlevel;
933 (void) &oldstyle;
934 (void) &prevsyntax;
935 (void) &syntax;
936 #endif
937
938 startlinno = plinno;
939 dblquote = 0;
940 varnest = 0;
941 if (syntax == DQSYNTAX) {
942 SETDBLQUOTE();
943 }
944 quotef = 0;
945 bqlist = NULL;
946 arinest = 0;
947 parenlevel = 0;
948
949 STARTSTACKSTR(out);
950 loop: { /* for each line, until end of word */
951 #if ATTY
952 if (c == '\034' && doprompt
953 && attyset() && ! equal(termval(), "emacs")) {
954 attyline();
955 if (syntax == BASESYNTAX)
956 return readtoken();
957 c = pgetc();
958 goto loop;
959 }
960 #endif
961 CHECKEND(); /* set c to PEOF if at end of here document */
962 for (;;) { /* until end of line or end of word */
963 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
964 switch(syntax[c]) {
965 case CNL: /* '\n' */
966 if (syntax == BASESYNTAX)
967 goto endword; /* exit outer loop */
968 USTPUTC(c, out);
969 plinno++;
970 if (doprompt)
971 setprompt(2);
972 else
973 setprompt(0);
974 c = pgetc();
975 goto loop; /* continue outer loop */
976 case CWORD:
977 USTPUTC(c, out);
978 break;
979 case CCTL:
980 if (eofmark == NULL || ISDBLQUOTE())
981 USTPUTC(CTLESC, out);
982 USTPUTC(c, out);
983 break;
984 case CBACK: /* backslash */
985 c = pgetc();
986 if (c == PEOF) {
987 USTPUTC('\\', out);
988 pungetc();
989 break;
990 }
991 if (c == '\n') {
992 if (doprompt)
993 setprompt(2);
994 else
995 setprompt(0);
996 break;
997 }
998 quotef = 1;
999 if (ISDBLQUOTE() && c != '\\' &&
1000 c != '`' && c != '$' &&
1001 (c != '"' || eofmark != NULL))
1002 USTPUTC('\\', out);
1003 if (SQSYNTAX[c] == CCTL)
1004 USTPUTC(CTLESC, out);
1005 else if (eofmark == NULL) {
1006 USTPUTC(CTLQUOTEMARK, out);
1007 USTPUTC(c, out);
1008 if (varnest != 0)
1009 USTPUTC(CTLQUOTEEND, out);
1010 break;
1011 }
1012 USTPUTC(c, out);
1013 break;
1014 case CSQUOTE:
1015 if (syntax != SQSYNTAX) {
1016 if (eofmark == NULL)
1017 USTPUTC(CTLQUOTEMARK, out);
1018 quotef = 1;
1019 syntax = SQSYNTAX;
1020 break;
1021 }
1022 if (eofmark != NULL && arinest == 0 &&
1023 varnest == 0) {
1024 /* Ignore inside quoted here document */
1025 USTPUTC(c, out);
1026 break;
1027 }
1028 /* End of single quotes... */
1029 if (arinest)
1030 syntax = ARISYNTAX;
1031 else {
1032 syntax = BASESYNTAX;
1033 if (varnest != 0)
1034 USTPUTC(CTLQUOTEEND, out);
1035 }
1036 break;
1037 case CDQUOTE:
1038 if (eofmark != NULL && arinest == 0 &&
1039 varnest == 0) {
1040 /* Ignore inside here document */
1041 USTPUTC(c, out);
1042 break;
1043 }
1044 quotef = 1;
1045 if (arinest) {
1046 if (ISDBLQUOTE()) {
1047 syntax = ARISYNTAX;
1048 CLRDBLQUOTE();
1049 } else {
1050 syntax = DQSYNTAX;
1051 SETDBLQUOTE();
1052 USTPUTC(CTLQUOTEMARK, out);
1053 }
1054 break;
1055 }
1056 if (eofmark != NULL)
1057 break;
1058 if (ISDBLQUOTE()) {
1059 if (varnest != 0)
1060 USTPUTC(CTLQUOTEEND, out);
1061 syntax = BASESYNTAX;
1062 CLRDBLQUOTE();
1063 } else {
1064 syntax = DQSYNTAX;
1065 SETDBLQUOTE();
1066 USTPUTC(CTLQUOTEMARK, out);
1067 }
1068 break;
1069 case CVAR: /* '$' */
1070 PARSESUB(); /* parse substitution */
1071 break;
1072 case CENDVAR: /* CLOSEBRACE */
1073 if (varnest > 0 && !ISDBLQUOTE()) {
1074 varnest--;
1075 USTPUTC(CTLENDVAR, out);
1076 } else {
1077 USTPUTC(c, out);
1078 }
1079 break;
1080 case CLP: /* '(' in arithmetic */
1081 parenlevel++;
1082 USTPUTC(c, out);
1083 break;
1084 case CRP: /* ')' in arithmetic */
1085 if (parenlevel > 0) {
1086 USTPUTC(c, out);
1087 --parenlevel;
1088 } else {
1089 if (pgetc() == ')') {
1090 if (--arinest == 0) {
1091 USTPUTC(CTLENDARI, out);
1092 syntax = prevsyntax;
1093 if (syntax == DQSYNTAX)
1094 SETDBLQUOTE();
1095 else
1096 CLRDBLQUOTE();
1097 } else
1098 USTPUTC(')', out);
1099 } else {
1100 /*
1101 * unbalanced parens
1102 * (don't 2nd guess - no error)
1103 */
1104 pungetc();
1105 USTPUTC(')', out);
1106 }
1107 }
1108 break;
1109 case CBQUOTE: /* '`' */
1110 PARSEBACKQOLD();
1111 break;
1112 case CEOF:
1113 goto endword; /* exit outer loop */
1114 default:
1115 if (varnest == 0)
1116 goto endword; /* exit outer loop */
1117 USTPUTC(c, out);
1118 }
1119 c = pgetc_macro();
1120 }
1121 }
1122 endword:
1123 if (syntax == ARISYNTAX)
1124 synerror("Missing '))'");
1125 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1126 synerror("Unterminated quoted string");
1127 if (varnest != 0) {
1128 startlinno = plinno;
1129 /* { */
1130 synerror("Missing '}'");
1131 }
1132 USTPUTC('\0', out);
1133 len = out - stackblock();
1134 out = stackblock();
1135 if (eofmark == NULL) {
1136 if ((c == '>' || c == '<')
1137 && quotef == 0
1138 && len <= 2
1139 && (*out == '\0' || is_digit(*out))) {
1140 PARSEREDIR();
1141 return lasttoken = TREDIR;
1142 } else {
1143 pungetc();
1144 }
1145 }
1146 quoteflag = quotef;
1147 backquotelist = bqlist;
1148 grabstackblock(len);
1149 wordtext = out;
1150 if (dblquotep != NULL)
1151 ckfree(dblquotep);
1152 return lasttoken = TWORD;
1153 /* end of readtoken routine */
1154
1155
1156
1157 /*
1158 * Check to see whether we are at the end of the here document. When this
1159 * is called, c is set to the first character of the next input line. If
1160 * we are at the end of the here document, this routine sets the c to PEOF.
1161 */
1162
1163 checkend: {
1164 if (eofmark) {
1165 if (striptabs) {
1166 while (c == '\t')
1167 c = pgetc();
1168 }
1169 if (c == *eofmark) {
1170 if (pfgets(line, sizeof line) != NULL) {
1171 char *p, *q;
1172
1173 p = line;
1174 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1175 if (*p == '\n' && *q == '\0') {
1176 c = PEOF;
1177 plinno++;
1178 needprompt = doprompt;
1179 } else {
1180 pushstring(line, strlen(line), NULL);
1181 }
1182 }
1183 }
1184 }
1185 goto checkend_return;
1186 }
1187
1188
1189 /*
1190 * Parse a redirection operator. The variable "out" points to a string
1191 * specifying the fd to be redirected. The variable "c" contains the
1192 * first character of the redirection operator.
1193 */
1194
1195 parseredir: {
1196 char fd = *out;
1197 union node *np;
1198
1199 np = (union node *)stalloc(sizeof (struct nfile));
1200 if (c == '>') {
1201 np->nfile.fd = 1;
1202 c = pgetc();
1203 if (c == '>')
1204 np->type = NAPPEND;
1205 else if (c == '|')
1206 np->type = NCLOBBER;
1207 else if (c == '&')
1208 np->type = NTOFD;
1209 else {
1210 np->type = NTO;
1211 pungetc();
1212 }
1213 } else { /* c == '<' */
1214 np->nfile.fd = 0;
1215 switch (c = pgetc()) {
1216 case '<':
1217 if (sizeof (struct nfile) != sizeof (struct nhere)) {
1218 np = (union node *)stalloc(sizeof (struct nhere));
1219 np->nfile.fd = 0;
1220 }
1221 np->type = NHERE;
1222 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1223 heredoc->here = np;
1224 if ((c = pgetc()) == '-') {
1225 heredoc->striptabs = 1;
1226 } else {
1227 heredoc->striptabs = 0;
1228 pungetc();
1229 }
1230 break;
1231
1232 case '&':
1233 np->type = NFROMFD;
1234 break;
1235
1236 case '>':
1237 np->type = NFROMTO;
1238 break;
1239
1240 default:
1241 np->type = NFROM;
1242 pungetc();
1243 break;
1244 }
1245 }
1246 if (fd != '\0')
1247 np->nfile.fd = digit_val(fd);
1248 redirnode = np;
1249 goto parseredir_return;
1250 }
1251
1252
1253 /*
1254 * Parse a substitution. At this point, we have read the dollar sign
1255 * and nothing else.
1256 */
1257
1258 parsesub: {
1259 int subtype;
1260 int typeloc;
1261 int flags;
1262 char *p;
1263 static const char types[] = "}-+?=";
1264
1265 c = pgetc();
1266 if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
1267 USTPUTC('$', out);
1268 pungetc();
1269 } else if (c == '(') { /* $(command) or $((arith)) */
1270 if (pgetc() == '(') {
1271 PARSEARITH();
1272 } else {
1273 pungetc();
1274 PARSEBACKQNEW();
1275 }
1276 } else {
1277 USTPUTC(CTLVAR, out);
1278 typeloc = out - stackblock();
1279 USTPUTC(VSNORMAL, out);
1280 subtype = VSNORMAL;
1281 if (c == OPENBRACE) {
1282 c = pgetc();
1283 if (c == '#') {
1284 if ((c = pgetc()) == CLOSEBRACE)
1285 c = '#';
1286 else
1287 subtype = VSLENGTH;
1288 }
1289 else
1290 subtype = 0;
1291 }
1292 if (is_name(c)) {
1293 do {
1294 STPUTC(c, out);
1295 c = pgetc();
1296 } while (is_in_name(c));
1297 } else if (is_digit(c)) {
1298 do {
1299 USTPUTC(c, out);
1300 c = pgetc();
1301 } while (is_digit(c));
1302 }
1303 else if (is_special(c)) {
1304 USTPUTC(c, out);
1305 c = pgetc();
1306 }
1307 else
1308 badsub: synerror("Bad substitution");
1309
1310 STPUTC('=', out);
1311 flags = 0;
1312 if (subtype == 0) {
1313 switch (c) {
1314 case ':':
1315 flags = VSNUL;
1316 c = pgetc();
1317 /*FALLTHROUGH*/
1318 default:
1319 p = strchr(types, c);
1320 if (p == NULL)
1321 goto badsub;
1322 subtype = p - types + VSNORMAL;
1323 break;
1324 case '%':
1325 case '#':
1326 {
1327 int cc = c;
1328 subtype = c == '#' ? VSTRIMLEFT :
1329 VSTRIMRIGHT;
1330 c = pgetc();
1331 if (c == cc)
1332 subtype++;
1333 else
1334 pungetc();
1335 break;
1336 }
1337 }
1338 } else {
1339 pungetc();
1340 }
1341 if (ISDBLQUOTE() || arinest)
1342 flags |= VSQUOTE;
1343 *(stackblock() + typeloc) = subtype | flags;
1344 if (subtype != VSNORMAL) {
1345 varnest++;
1346 if (varnest >= maxnest) {
1347 dblquotep = ckrealloc(dblquotep, maxnest / 8);
1348 dblquotep[(maxnest / 32) - 1] = 0;
1349 maxnest += 32;
1350 }
1351 }
1352 }
1353 goto parsesub_return;
1354 }
1355
1356
1357 /*
1358 * Called to parse command substitutions. Newstyle is set if the command
1359 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1360 * list of commands (passed by reference), and savelen is the number of
1361 * characters on the top of the stack which must be preserved.
1362 */
1363
1364 parsebackq: {
1365 struct nodelist **nlpp;
1366 int savepbq;
1367 union node *n;
1368 char *volatile str;
1369 struct jmploc jmploc;
1370 struct jmploc *volatile savehandler;
1371 int savelen;
1372 int saveprompt;
1373 #ifdef __GNUC__
1374 (void) &saveprompt;
1375 #endif
1376
1377 savepbq = parsebackquote;
1378 if (setjmp(jmploc.loc)) {
1379 if (str)
1380 ckfree(str);
1381 parsebackquote = 0;
1382 handler = savehandler;
1383 longjmp(handler->loc, 1);
1384 }
1385 INTOFF;
1386 str = NULL;
1387 savelen = out - stackblock();
1388 if (savelen > 0) {
1389 str = ckmalloc(savelen);
1390 memcpy(str, stackblock(), savelen);
1391 }
1392 savehandler = handler;
1393 handler = &jmploc;
1394 INTON;
1395 if (oldstyle) {
1396 /* We must read until the closing backquote, giving special
1397 treatment to some slashes, and then push the string and
1398 reread it as input, interpreting it normally. */
1399 char *pout;
1400 int pc;
1401 int psavelen;
1402 char *pstr;
1403
1404
1405 STARTSTACKSTR(pout);
1406 for (;;) {
1407 if (needprompt) {
1408 setprompt(2);
1409 needprompt = 0;
1410 }
1411 switch (pc = pgetc()) {
1412 case '`':
1413 goto done;
1414
1415 case '\\':
1416 if ((pc = pgetc()) == '\n') {
1417 plinno++;
1418 if (doprompt)
1419 setprompt(2);
1420 else
1421 setprompt(0);
1422 /*
1423 * If eating a newline, avoid putting
1424 * the newline into the new character
1425 * stream (via the STPUTC after the
1426 * switch).
1427 */
1428 continue;
1429 }
1430 if (pc != '\\' && pc != '`' && pc != '$'
1431 && (!ISDBLQUOTE() || pc != '"'))
1432 STPUTC('\\', pout);
1433 break;
1434
1435 case '\n':
1436 plinno++;
1437 needprompt = doprompt;
1438 break;
1439
1440 case PEOF:
1441 startlinno = plinno;
1442 synerror("EOF in backquote substitution");
1443 break;
1444
1445 default:
1446 break;
1447 }
1448 STPUTC(pc, pout);
1449 }
1450 done:
1451 STPUTC('\0', pout);
1452 psavelen = pout - stackblock();
1453 if (psavelen > 0) {
1454 pstr = grabstackstr(pout);
1455 setinputstring(pstr, 1);
1456 }
1457 }
1458 nlpp = &bqlist;
1459 while (*nlpp)
1460 nlpp = &(*nlpp)->next;
1461 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1462 (*nlpp)->next = NULL;
1463 parsebackquote = oldstyle;
1464
1465 if (oldstyle) {
1466 saveprompt = doprompt;
1467 doprompt = 0;
1468 }
1469
1470 n = list(0);
1471
1472 if (oldstyle)
1473 doprompt = saveprompt;
1474 else {
1475 if (readtoken() != TRP)
1476 synexpect(TRP);
1477 }
1478
1479 (*nlpp)->n = n;
1480 if (oldstyle) {
1481 /*
1482 * Start reading from old file again, ignoring any pushed back
1483 * tokens left from the backquote parsing
1484 */
1485 popfile();
1486 tokpushback = 0;
1487 }
1488 while (stackblocksize() <= savelen)
1489 growstackblock();
1490 STARTSTACKSTR(out);
1491 if (str) {
1492 memcpy(out, str, savelen);
1493 STADJUST(savelen, out);
1494 INTOFF;
1495 ckfree(str);
1496 str = NULL;
1497 INTON;
1498 }
1499 parsebackquote = savepbq;
1500 handler = savehandler;
1501 if (arinest || ISDBLQUOTE())
1502 USTPUTC(CTLBACKQ | CTLQUOTE, out);
1503 else
1504 USTPUTC(CTLBACKQ, out);
1505 if (oldstyle)
1506 goto parsebackq_oldreturn;
1507 else
1508 goto parsebackq_newreturn;
1509 }
1510
1511 /*
1512 * Parse an arithmetic expansion (indicate start of one and set state)
1513 */
1514 parsearith: {
1515
1516 if (++arinest == 1) {
1517 prevsyntax = syntax;
1518 syntax = ARISYNTAX;
1519 USTPUTC(CTLARI, out);
1520 if (ISDBLQUOTE())
1521 USTPUTC('"',out);
1522 else
1523 USTPUTC(' ',out);
1524 } else {
1525 /*
1526 * we collapse embedded arithmetic expansion to
1527 * parenthesis, which should be equivalent
1528 */
1529 USTPUTC('(', out);
1530 }
1531 goto parsearith_return;
1532 }
1533
1534 } /* end of readtoken */
1535
1536
1537
1538 #ifdef mkinit
1539 RESET {
1540 tokpushback = 0;
1541 checkkwd = 0;
1542 }
1543 #endif
1544
1545 /*
1546 * Returns true if the text contains nothing to expand (no dollar signs
1547 * or backquotes).
1548 */
1549
1550 STATIC int
1551 noexpand(char *text)
1552 {
1553 char *p;
1554 char c;
1555
1556 p = text;
1557 while ((c = *p++) != '\0') {
1558 if (c == CTLQUOTEMARK)
1559 continue;
1560 if (c == CTLESC)
1561 p++;
1562 else if (BASESYNTAX[(int)c] == CCTL)
1563 return 0;
1564 }
1565 return 1;
1566 }
1567
1568
1569 /*
1570 * Return true if the argument is a legal variable name (a letter or
1571 * underscore followed by zero or more letters, underscores, and digits).
1572 */
1573
1574 int
1575 goodname(char *name)
1576 {
1577 char *p;
1578
1579 p = name;
1580 if (! is_name(*p))
1581 return 0;
1582 while (*++p) {
1583 if (! is_in_name(*p))
1584 return 0;
1585 }
1586 return 1;
1587 }
1588
1589
1590 /*
1591 * Called when an unexpected token is read during the parse. The argument
1592 * is the token that is expected, or -1 if more than one type of token can
1593 * occur at this point.
1594 */
1595
1596 STATIC void
1597 synexpect(int token)
1598 {
1599 char msg[64];
1600
1601 if (token >= 0) {
1602 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1603 tokname[lasttoken], tokname[token]);
1604 } else {
1605 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1606 }
1607 synerror(msg);
1608 /* NOTREACHED */
1609 }
1610
1611
1612 STATIC void
1613 synerror(const char *msg)
1614 {
1615 if (commandname)
1616 outfmt(&errout, "%s: %d: ", commandname, startlinno);
1617 outfmt(&errout, "Syntax error: %s\n", msg);
1618 error((char *)NULL);
1619 /* NOTREACHED */
1620 }
1621
1622 STATIC void
1623 setprompt(int which)
1624 {
1625 whichprompt = which;
1626
1627 #ifdef WITH_HISTORY
1628 if (!el)
1629 #endif
1630 out2str(getprompt(NULL));
1631 }
1632
1633 /*
1634 * called by editline -- any expansions to the prompt
1635 * should be added here.
1636 */
1637 const char *
1638 getprompt(void *unused)
1639 {
1640 switch (whichprompt) {
1641 case 0:
1642 return "";
1643 case 1:
1644 return ps1val();
1645 case 2:
1646 return ps2val();
1647 default:
1648 return "<internal prompt error>";
1649 }
1650 }
+0
-82
sh/parser.h less more
0 /* $NetBSD: parser.h,v 1.17 2004/06/26 22:09:49 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)parser.h 8.3 (Berkeley) 5/4/95
34 */
35
36 /* control characters in argument strings */
37 #define CTL_FIRST '\201' /* first 'special' character */
38 #define CTLESC '\201' /* escape next character */
39 #define CTLVAR '\202' /* variable defn */
40 #define CTLENDVAR '\203'
41 #define CTLBACKQ '\204'
42 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
43 /* CTLBACKQ | CTLQUOTE == '\205' */
44 #define CTLARI '\206' /* arithmetic expression */
45 #define CTLENDARI '\207'
46 #define CTLQUOTEMARK '\210'
47 #define CTLQUOTEEND '\211' /* only inside ${...} */
48 #define CTL_LAST '\211' /* last 'special' character */
49
50 /* variable substitution byte (follows CTLVAR) */
51 #define VSTYPE 0x0f /* type of variable substitution */
52 #define VSNUL 0x10 /* colon--treat the empty string as unset */
53 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
54
55 /* values of VSTYPE field */
56 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
57 #define VSMINUS 0x2 /* ${var-text} */
58 #define VSPLUS 0x3 /* ${var+text} */
59 #define VSQUESTION 0x4 /* ${var?message} */
60 #define VSASSIGN 0x5 /* ${var=text} */
61 #define VSTRIMLEFT 0x6 /* ${var#pattern} */
62 #define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
63 #define VSTRIMRIGHT 0x8 /* ${var%pattern} */
64 #define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
65 #define VSLENGTH 0xa /* ${#var} */
66
67
68 /*
69 * NEOF is returned by parsecmd when it encounters an end of file. It
70 * must be distinct from NULL, so we use the address of a variable that
71 * happens to be handy.
72 */
73 extern int tokpushback;
74 #define NEOF ((union node *)&tokpushback)
75 extern int whichprompt; /* 1 == PS1, 2 == PS2 */
76
77
78 union node *parsecmd(int);
79 void fixredir(union node *, const char *, int);
80 int goodname(char *);
81 const char *getprompt(void *);
+0
-389
sh/redir.c less more
0 /* $NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <sys/types.h>
44 #include <sys/param.h> /* PIPE_BUF */
45 #include <signal.h>
46 #include <string.h>
47 #include <fcntl.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51
52 /*
53 * Code for dealing with input/output redirection.
54 */
55
56 #include "main.h"
57 #include "shell.h"
58 #include "nodes.h"
59 #include "jobs.h"
60 #include "options.h"
61 #include "expand.h"
62 #include "redir.h"
63 #include "output.h"
64 #include "memalloc.h"
65 #include "error.h"
66
67
68 #define EMPTY -2 /* marks an unused slot in redirtab */
69 #ifndef PIPE_BUF
70 # define PIPESIZE 4096 /* amount of buffering in a pipe */
71 #else
72 # define PIPESIZE PIPE_BUF
73 #endif
74
75 #define signal bsd_signal
76
77 MKINIT
78 struct redirtab {
79 struct redirtab *next;
80 short renamed[10];
81 };
82
83
84 MKINIT struct redirtab *redirlist;
85
86 /*
87 * We keep track of whether or not fd0 has been redirected. This is for
88 * background commands, where we want to redirect fd0 to /dev/null only
89 * if it hasn't already been redirected.
90 */
91 int fd0_redirected = 0;
92
93 STATIC void openredirect(union node *, char[10], int);
94 STATIC int openhere(union node *);
95
96
97 /*
98 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
99 * old file descriptors are stashed away so that the redirection can be
100 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
101 * standard output, and the standard error if it becomes a duplicate of
102 * stdout, is saved in memory.
103 */
104
105 void
106 redirect(union node *redir, int flags)
107 {
108 union node *n;
109 struct redirtab *sv = NULL;
110 int i;
111 int fd;
112 int try;
113 char memory[10]; /* file descriptors to write to memory */
114
115 for (i = 10 ; --i >= 0 ; )
116 memory[i] = 0;
117 memory[1] = flags & REDIR_BACKQ;
118 if (flags & REDIR_PUSH) {
119 /* We don't have to worry about REDIR_VFORK here, as
120 * flags & REDIR_PUSH is never true if REDIR_VFORK is set.
121 */
122 sv = ckmalloc(sizeof (struct redirtab));
123 for (i = 0 ; i < 10 ; i++)
124 sv->renamed[i] = EMPTY;
125 sv->next = redirlist;
126 redirlist = sv;
127 }
128 for (n = redir ; n ; n = n->nfile.next) {
129 fd = n->nfile.fd;
130 try = 0;
131 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
132 n->ndup.dupfd == fd)
133 continue; /* redirect from/to same file descriptor */
134
135 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
136 INTOFF;
137 again:
138 if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
139 switch (errno) {
140 case EBADF:
141 if (!try) {
142 openredirect(n, memory, flags);
143 try++;
144 goto again;
145 }
146 /* FALLTHROUGH*/
147 default:
148 INTON;
149 error("%d: %s", fd, strerror(errno));
150 /* NOTREACHED */
151 }
152 }
153 if (!try) {
154 sv->renamed[fd] = i;
155 close(fd);
156 }
157 INTON;
158 } else {
159 close(fd);
160 }
161 if (fd == 0)
162 fd0_redirected++;
163 if (!try)
164 openredirect(n, memory, flags);
165 }
166 if (memory[1])
167 out1 = &memout;
168 if (memory[2])
169 out2 = &memout;
170 }
171
172
173 STATIC void
174 openredirect(union node *redir, char memory[10], int flags)
175 {
176 int fd = redir->nfile.fd;
177 char *fname;
178 int f;
179 int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags;
180
181 /*
182 * We suppress interrupts so that we won't leave open file
183 * descriptors around. This may not be such a good idea because
184 * an open of a device or a fifo can block indefinitely.
185 */
186 INTOFF;
187 memory[fd] = 0;
188 switch (redir->nfile.type) {
189 case NFROM:
190 fname = redir->nfile.expfname;
191 if (flags & REDIR_VFORK)
192 eflags = O_NONBLOCK;
193 else
194 eflags = 0;
195 if ((f = open(fname, O_RDONLY|eflags)) < 0)
196 goto eopen;
197 if (eflags)
198 (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags);
199 break;
200 case NFROMTO:
201 fname = redir->nfile.expfname;
202 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
203 goto ecreate;
204 break;
205 case NTO:
206 if (Cflag)
207 oflags |= O_EXCL;
208 /* FALLTHROUGH */
209 case NCLOBBER:
210 fname = redir->nfile.expfname;
211 if ((f = open(fname, oflags, 0666)) < 0)
212 goto ecreate;
213 break;
214 case NAPPEND:
215 fname = redir->nfile.expfname;
216 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
217 goto ecreate;
218 break;
219 case NTOFD:
220 case NFROMFD:
221 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
222 if (memory[redir->ndup.dupfd])
223 memory[fd] = 1;
224 else
225 copyfd(redir->ndup.dupfd, fd);
226 }
227 INTON;
228 return;
229 case NHERE:
230 case NXHERE:
231 f = openhere(redir);
232 break;
233 default:
234 abort();
235 }
236
237 if (f != fd) {
238 copyfd(f, fd);
239 close(f);
240 }
241 INTON;
242 return;
243 ecreate:
244 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
245 eopen:
246 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
247 }
248
249
250 /*
251 * Handle here documents. Normally we fork off a process to write the
252 * data to a pipe. If the document is short, we can stuff the data in
253 * the pipe without forking.
254 */
255
256 STATIC int
257 openhere(union node *redir)
258 {
259 int pip[2];
260 int len = 0;
261
262 if (pipe(pip) < 0)
263 error("Pipe call failed");
264 if (redir->type == NHERE) {
265 len = strlen(redir->nhere.doc->narg.text);
266 if (len <= PIPESIZE) {
267 xwrite(pip[1], redir->nhere.doc->narg.text, len);
268 goto out;
269 }
270 }
271 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
272 close(pip[0]);
273 signal(SIGINT, SIG_IGN);
274 signal(SIGQUIT, SIG_IGN);
275 signal(SIGHUP, SIG_IGN);
276 #ifdef SIGTSTP
277 signal(SIGTSTP, SIG_IGN);
278 #endif
279 signal(SIGPIPE, SIG_DFL);
280 if (redir->type == NHERE)
281 xwrite(pip[1], redir->nhere.doc->narg.text, len);
282 else
283 expandhere(redir->nhere.doc, pip[1]);
284 _exit(0);
285 }
286 out:
287 close(pip[1]);
288 return pip[0];
289 }
290
291
292
293 /*
294 * Undo the effects of the last redirection.
295 */
296
297 void
298 popredir(void)
299 {
300 struct redirtab *rp = redirlist;
301 int i;
302
303 for (i = 0 ; i < 10 ; i++) {
304 if (rp->renamed[i] != EMPTY) {
305 if (i == 0)
306 fd0_redirected--;
307 close(i);
308 if (rp->renamed[i] >= 0) {
309 copyfd(rp->renamed[i], i);
310 close(rp->renamed[i]);
311 }
312 }
313 }
314 INTOFF;
315 redirlist = rp->next;
316 ckfree(rp);
317 INTON;
318 }
319
320 /*
321 * Undo all redirections. Called on error or interrupt.
322 */
323
324 #ifdef mkinit
325
326 INCLUDE "redir.h"
327
328 RESET {
329 while (redirlist)
330 popredir();
331 }
332
333 SHELLPROC {
334 clearredir(0);
335 }
336
337 #endif
338
339 /* Return true if fd 0 has already been redirected at least once. */
340 int
341 fd0_redirected_p () {
342 return fd0_redirected != 0;
343 }
344
345 /*
346 * Discard all saved file descriptors.
347 */
348
349 void
350 clearredir(vforked)
351 int vforked;
352 {
353 struct redirtab *rp;
354 int i;
355
356 for (rp = redirlist ; rp ; rp = rp->next) {
357 for (i = 0 ; i < 10 ; i++) {
358 if (rp->renamed[i] >= 0) {
359 close(rp->renamed[i]);
360 }
361 if (!vforked)
362 rp->renamed[i] = EMPTY;
363 }
364 }
365 }
366
367
368
369 /*
370 * Copy a file descriptor to be >= to. Returns -1
371 * if the source file descriptor is closed, EMPTY if there are no unused
372 * file descriptors left.
373 */
374
375 int
376 copyfd(int from, int to)
377 {
378 int newfd;
379
380 newfd = fcntl(from, F_DUPFD, to);
381 if (newfd < 0) {
382 if (errno == EMFILE)
383 return EMPTY;
384 else
385 error("%d: %s", from, strerror(errno));
386 }
387 return newfd;
388 }
+0
-48
sh/redir.h less more
0 /* $NetBSD: redir.h,v 1.15 2003/08/07 09:05:37 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)redir.h 8.2 (Berkeley) 5/4/95
34 */
35
36 /* flags passed to redirect */
37 #define REDIR_PUSH 01 /* save previous values of file descriptors */
38 #define REDIR_BACKQ 02 /* save the command output in memory */
39 #define REDIR_VFORK 04 /* running under vfork(2), be careful */
40
41 union node;
42 void redirect(union node *, int);
43 void popredir(void);
44 int fd0_redirected_p(void);
45 void clearredir(int);
46 int copyfd(int, int);
47
+0
-1928
sh/sh.1 less more
0 .\" $NetBSD: sh.1,v 1.78 2004/06/03 19:54:37 hubertf Exp $
1 .\" Copyright (c) 1991, 1993
2 .\" The Regents of the University of California. All rights reserved.
3 .\"
4 .\" This code is derived from software contributed to Berkeley by
5 .\" Kenneth Almquist.
6 .\"
7 .\" Redistribution and use in source and binary forms, with or without
8 .\" modification, are permitted provided that the following conditions
9 .\" are met:
10 .\" 1. Redistributions of source code must retain the above copyright
11 .\" notice, this list of conditions and the following disclaimer.
12 .\" 2. Redistributions in binary form must reproduce the above copyright
13 .\" notice, this list of conditions and the following disclaimer in the
14 .\" documentation and/or other materials provided with the distribution.
15 .\" 3. Neither the name of the University nor the names of its contributors
16 .\" may be used to endorse or promote products derived from this software
17 .\" without specific prior written permission.
18 .\"
19 .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 .\" SUCH DAMAGE.
30 .\"
31 .\" @(#)sh.1 8.6 (Berkeley) 5/4/95
32 .\"
33 .Dd April 17, 2004
34 .Os
35 .Dt SH 1
36 .Sh NAME
37 .Nm sh
38 .Nd command interpreter (shell)
39 .Sh SYNOPSIS
40 .Nm
41 .Bk -words
42 .Op Fl aCefnuvxIimqVEb
43 .Op Cm +aCefnuvxIimqVEb
44 .Ek
45 .Bk -words
46 .Op Fl o Ar option_name
47 .Op Cm +o Ar option_name
48 .Ek
49 .Bk -words
50 .Op Ar command_file Oo Ar argument ... Oc
51 .Ek
52 .Nm
53 .Fl c
54 .Bk -words
55 .Op Fl aCefnuvxIimqVEb
56 .Op Cm +aCefnuvxIimqVEb
57 .Ek
58 .Bk -words
59 .Op Fl o Ar option_name
60 .Op Cm +o Ar option_name
61 .Ek
62 .Bk -words
63 .Ar command_string
64 .Op Ar command_name Oo Ar argument ... Oc
65 .Ek
66 .Nm
67 .Fl s
68 .Bk -words
69 .Op Fl aCefnuvxIimqVEb
70 .Op Cm +aCefnuvxIimqVEb
71 .Ek
72 .Bk -words
73 .Op Fl o Ar option_name
74 .Op Cm +o Ar option_name
75 .Ek
76 .Bk -words
77 .Op Ar argument ...
78 .Ek
79 .Sh DESCRIPTION
80 .Nm
81 is the standard command interpreter for the system.
82 The current version of
83 .Nm
84 is in the process of being changed to conform with the
85 .Tn POSIX
86 1003.2 and 1003.2a specifications for the shell.
87 This version has many
88 features which make it appear similar in some respects to the Korn shell,
89 but it is not a Korn shell clone (see
90 .Xr ksh 1 ) .
91 Only features designated by
92 .Tn POSIX ,
93 plus a few Berkeley extensions, are being incorporated into this shell.
94 .\" We expect
95 .\" .Tn POSIX
96 .\" conformance by the time 4.4 BSD is released.
97 This man page is not intended
98 to be a tutorial or a complete specification of the shell.
99 .Ss Overview
100 The shell is a command that reads lines from either a file or the
101 terminal, interprets them, and generally executes other commands.
102 It is the program that is running when a user logs into the system
103 (although a user can select a different shell with the
104 .Xr chsh 1
105 command).
106 The shell implements a language that has flow control
107 constructs, a macro facility that provides a variety of features in
108 addition to data storage, along with built in history and line editing
109 capabilities.
110 It incorporates many features to aid interactive use and
111 has the advantage that the interpretative language is common to both
112 interactive and non-interactive use (shell scripts).
113 That is, commands
114 can be typed directly to the running shell or can be put into a file and
115 the file can be executed directly by the shell.
116 .Ss Invocation
117 If no args are present and if the standard input of the shell
118 is connected to a terminal (or if the
119 .Fl i
120 flag is set),
121 and the
122 .Fl c
123 option is not present, the shell is considered an interactive shell.
124 An interactive shell generally prompts before each command and handles
125 programming and command errors differently (as described below).
126 When first starting,
127 the shell inspects argument 0, and if it begins with a dash
128 .Sq - ,
129 the shell is also considered
130 a login shell.
131 This is normally done automatically by the system
132 when the user first logs in.
133 A login shell first reads commands
134 from the files
135 .Pa /etc/profile
136 and
137 .Pa .profile
138 if they exist.
139 If the environment variable
140 .Ev ENV
141 is set on entry to a shell, or is set in the
142 .Pa .profile
143 of a login shell, the shell next reads
144 commands from the file named in
145 .Ev ENV .
146 Therefore, a user should place commands that are to be executed only at
147 login time in the
148 .Pa .profile
149 file, and commands that are executed for every shell inside the
150 .Ev ENV
151 file.
152 To set the
153 .Ev ENV
154 variable to some file, place the following line in your
155 .Pa .profile
156 of your home directory
157 .Pp
158 .Dl ENV=$HOME/.shinit; export ENV
159 .Pp
160 substituting for
161 .Dq .shinit
162 any filename you wish.
163 Since the
164 .Ev ENV
165 file is read for every invocation of the shell, including shell scripts
166 and non-interactive shells, the following paradigm is useful for
167 restricting commands in the
168 .Ev ENV
169 file to interactive invocations.
170 Place commands within the
171 .Dq case
172 and
173 .Dq esac
174 below (these commands are described later):
175 .Pp
176 .Bl -item -compact -offset indent
177 .It
178 .Li case $- in *i*)
179 .Bl -item -compact -offset indent
180 .It
181 .Li # commands for interactive use only
182 .It
183 .Li ...
184 .El
185 .It
186 .Li esac
187 .El
188 .Pp
189 If command line arguments besides the options have been specified, then
190 the shell treats the first argument as the name of a file from which to
191 read commands (a shell script), and the remaining arguments are set as the
192 positional parameters of the shell ($1, $2, etc).
193 Otherwise, the shell
194 reads commands from its standard input.
195 .Ss Argument List Processing
196 All of the single letter options have a corresponding name that can be
197 used as an argument to the
198 .Fl o
199 option.
200 The set
201 .Fl o
202 name is provided next to the single letter option in
203 the description below.
204 Specifying a dash
205 .Dq -
206 turns the option on, while using a plus
207 .Dq +
208 disables the option.
209 The following options can be set from the command line or
210 with the
211 .Ic set
212 builtin (described later).
213 .Bl -tag -width aaaallexportfoo -offset indent
214 .It Fl a Em allexport
215 Export all variables assigned to.
216 .It Fl c
217 Read commands from the
218 .Ar command_string
219 operand instead of from the standard input.
220 Special parameter 0 will be set from the
221 .Ar command_name
222 operand and the positional parameters ($1, $2, etc.)
223 set from the remaining argument operands.
224 .It Fl C Em noclobber
225 Don't overwrite existing files with
226 .Dq \*[Gt] .
227 .It Fl e Em errexit
228 If not interactive, exit immediately if any untested command fails.
229 The exit status of a command is considered to be
230 explicitly tested if the command is used to control an
231 .Ic if ,
232 .Ic elif ,
233 .Ic while ,
234 or
235 .Ic until ;
236 or if the command is the left hand operand of an
237 .Dq \*[Am]\*[Am]
238 or
239 .Dq ||
240 operator.
241 .It Fl f Em noglob
242 Disable pathname expansion.
243 .It Fl n Em noexec
244 If not interactive, read commands but do not execute them.
245 This is useful for checking the syntax of shell scripts.
246 .It Fl u Em nounset
247 Write a message to standard error when attempting to expand a variable
248 that is not set, and if the shell is not interactive, exit immediately.
249 .It Fl v Em verbose
250 The shell writes its input to standard error as it is read.
251 Useful for debugging.
252 .It Fl x Em xtrace
253 Write each command to standard error (preceded by a
254 .Sq +\ )
255 before it is executed.
256 Useful for debugging.
257 .It Fl q Em quietprofile
258 If the
259 .Fl v
260 or
261 .Fl x
262 options have been set, do not apply them when reading
263 initialization files, these being
264 .Pa /etc/profile ,
265 .Pa .profile ,
266 and the file specified by the
267 .Ev ENV
268 environment variable.
269 .It Fl I Em ignoreeof
270 Ignore EOF's from input when interactive.
271 .It Fl i Em interactive
272 Force the shell to behave interactively.
273 .It Fl m Em monitor
274 Turn on job control (set automatically when interactive).
275 .It Fl s Em stdin
276 Read commands from standard input (set automatically if no file arguments
277 are present).
278 This option has no effect when set after the shell has
279 already started running (i.e. with
280 .Ic set ) .
281 .It Fl V Em vi
282 Enable the built-in
283 .Xr vi 1
284 command line editor (disables
285 .Fl E
286 if it has been set).
287 (See the
288 .Sx Command Line Editing
289 section below.)
290 .It Fl E Em emacs
291 Enable the built-in emacs style
292 command line editor (disables
293 .Fl V
294 if it has been set).
295 (See the
296 .Sx Command Line Editing
297 section below.)
298 .It Fl b Em notify
299 Enable asynchronous notification of background job completion.
300 (UNIMPLEMENTED for 4.4alpha)
301 .It "\ \ " Em cdprint
302 Make an interactive shell always print the new directory name when
303 changed by the
304 .Ic cd
305 command.
306 .El
307 .Ss Lexical Structure
308 The shell reads input in terms of lines from a file and breaks it up into
309 words at whitespace (blanks and tabs), and at certain sequences of
310 characters that are special to the shell called
311 .Dq operators .
312 There are two types of operators: control operators and redirection
313 operators (their meaning is discussed later).
314 Following is a list of operators:
315 .Bl -ohang -offset indent
316 .It "Control operators:"
317 .Dl \*[Am] \*[Am]\*[Am] \&( \&) \&; ;; | || \*[Lt]newline\*[Gt]
318 .It "Redirection operators:"
319 .Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]\*[Am] \*[Gt]\*[Am] \*[Lt]\*[Lt]- \*[Lt]\*[Gt]
320 .El
321 .Ss Quoting
322 Quoting is used to remove the special meaning of certain characters or
323 words to the shell, such as operators, whitespace, or keywords.
324 There are three types of quoting: matched single quotes,
325 matched double quotes, and backslash.
326 .Ss Backslash
327 A backslash preserves the literal meaning of the following
328 character, with the exception of
329 .Aq newline .
330 A backslash preceding a
331 .Aq newline
332 is treated as a line continuation.
333 .Ss Single Quotes
334 Enclosing characters in single quotes preserves the literal meaning of all
335 the characters (except single quotes, making it impossible to put
336 single-quotes in a single-quoted string).
337 .Ss Double Quotes
338 Enclosing characters within double quotes preserves the literal
339 meaning of all characters except dollarsign
340 .Pq $ ,
341 backquote
342 .Pq ` ,
343 and backslash
344 .Pq \e .
345 The backslash inside double quotes is historically weird, and serves to
346 quote only the following characters:
347 .Dl $ ` \*q \e \*[Lt]newline\*[Gt] .
348 Otherwise it remains literal.
349 .Ss Reserved Words
350 Reserved words are words that have special meaning to the
351 shell and are recognized at the beginning of a line and
352 after a control operator.
353 The following are reserved words:
354 .Bl -column while while while while while -offset indent
355 .It ! Ta elif Ta fi Ta while Ta case
356 .It else Ta for Ta then Ta { Ta }
357 .It do Ta done Ta until Ta if Ta esac
358 .El
359 .Pp
360 Their meaning is discussed later.
361 .Ss Aliases
362 An alias is a name and corresponding value set using the
363 .Ic alias
364 builtin command.
365 Whenever a reserved word may occur (see above),
366 and after checking for reserved words, the shell
367 checks the word to see if it matches an alias.
368 If it does, it replaces it in the input stream with its value.
369 For example, if there is an alias called
370 .Dq lf
371 with the value
372 .Dq "ls -F" ,
373 then the input:
374 .Pp
375 .Dl lf foobar Aq return
376 .Pp
377 would become
378 .Pp
379 .Dl ls -F foobar Aq return
380 .Pp
381 Aliases provide a convenient way for naive users to create shorthands for
382 commands without having to learn how to create functions with arguments.
383 They can also be used to create lexically obscure code.
384 This use is discouraged.
385 .Ss Commands
386 The shell interprets the words it reads according to a language, the
387 specification of which is outside the scope of this man page (refer to the
388 BNF in the
389 .Tn POSIX
390 1003.2 document).
391 Essentially though, a line is read and if the first
392 word of the line (or after a control operator) is not a reserved word,
393 then the shell has recognized a simple command.
394 Otherwise, a complex
395 command or some other special construct may have been recognized.
396 .Ss Simple Commands
397 If a simple command has been recognized, the shell performs
398 the following actions:
399 .Bl -enum -offset indent
400 .It
401 Leading words of the form
402 .Dq name=value
403 are stripped off and assigned to the environment of the simple command.
404 Redirection operators and their arguments (as described below) are
405 stripped off and saved for processing.
406 .It
407 The remaining words are expanded as described in
408 the section called
409 .Dq Expansions ,
410 and the first remaining word is considered the command name and the
411 command is located.
412 The remaining words are considered the arguments of the command.
413 If no command name resulted, then the
414 .Dq name=value
415 variable assignments recognized in item 1 affect the current shell.
416 .It
417 Redirections are performed as described in the next section.
418 .El
419 .Ss Redirections
420 Redirections are used to change where a command reads its input or sends
421 its output.
422 In general, redirections open, close, or duplicate an
423 existing reference to a file.
424 The overall format used for redirection is:
425 .Pp
426 .Dl [n] Va redir-op Ar file
427 .Pp
428 where
429 .Va redir-op
430 is one of the redirection operators mentioned previously.
431 Following is a list of the possible redirections.
432 The
433 .Bq n
434 is an optional number, as in
435 .Sq 3
436 (not
437 .Sq Bq 3 ) ,
438 that refers to a file descriptor.
439 .Bl -tag -width aaabsfiles -offset indent
440 .It [n] Ns \*[Gt] file
441 Redirect standard output (or n) to file.
442 .It [n] Ns \*[Gt]| file
443 Same, but override the
444 .Fl C
445 option.
446 .It [n] Ns \*[Gt]\*[Gt] file
447 Append standard output (or n) to file.
448 .It [n] Ns \*[Lt] file
449 Redirect standard input (or n) from file.
450 .It [n1] Ns \*[Lt]\*[Am] Ns n2
451 Duplicate standard input (or n1) from file descriptor n2.
452 .It [n] Ns \*[Lt]\*[Am]-
453 Close standard input (or n).
454 .It [n1] Ns \*[Gt]\*[Am] Ns n2
455 Duplicate standard output (or n1) to n2.
456 .It [n] Ns \*[Gt]\*[Am]-
457 Close standard output (or n).
458 .It [n] Ns \*[Lt]\*[Gt] file
459 Open file for reading and writing on standard input (or n).
460 .El
461 .Pp
462 The following redirection is often called a
463 .Dq here-document .
464 .Bl -item -offset indent
465 .It
466 .Li [n]\*[Lt]\*[Lt] delimiter
467 .Dl here-doc-text ...
468 .Li delimiter
469 .El
470 .Pp
471 All the text on successive lines up to the delimiter is saved away and
472 made available to the command on standard input, or file descriptor n if
473 it is specified.
474 If the delimiter as specified on the initial line is
475 quoted, then the here-doc-text is treated literally, otherwise the text is
476 subjected to parameter expansion, command substitution, and arithmetic
477 expansion (as described in the section on
478 .Dq Expansions ) .
479 If the operator is
480 .Dq \*[Lt]\*[Lt]-
481 instead of
482 .Dq \*[Lt]\*[Lt] ,
483 then leading tabs in the here-doc-text are stripped.
484 .Ss Search and Execution
485 There are three types of commands: shell functions, builtin commands, and
486 normal programs -- and the command is searched for (by name) in that order.
487 They each are executed in a different way.
488 .Pp
489 When a shell function is executed, all of the shell positional parameters
490 (except $0, which remains unchanged) are set to the arguments of the shell
491 function.
492 The variables which are explicitly placed in the environment of
493 the command (by placing assignments to them before the function name) are
494 made local to the function and are set to the values given.
495 Then the command given in the function definition is executed.
496 The positional parameters are restored to their original values
497 when the command completes.
498 This all occurs within the current shell.
499 .Pp
500 Shell builtins are executed internally to the shell, without spawning a
501 new process.
502 .Pp
503 Otherwise, if the command name doesn't match a function or builtin, the
504 command is searched for as a normal program in the file system (as
505 described in the next section).
506 When a normal program is executed, the shell runs the program,
507 passing the arguments and the environment to the program.
508 If the program is not a normal executable file (i.e., if it does
509 not begin with the "magic number" whose
510 .Tn ASCII
511 representation is "#!", so
512 .Xr execve 2
513 returns
514 .Er ENOEXEC
515 then) the shell will interpret the program in a subshell.
516 The child shell will reinitialize itself in this case,
517 so that the effect will be as if a
518 new shell had been invoked to handle the ad-hoc shell script, except that
519 the location of hashed commands located in the parent shell will be
520 remembered by the child.
521 .Pp
522 Note that previous versions of this document and the source code itself
523 misleadingly and sporadically refer to a shell script without a magic
524 number as a "shell procedure".
525 .Ss Path Search
526 When locating a command, the shell first looks to see if it has a shell
527 function by that name.
528 Then it looks for a builtin command by that name.
529 If a builtin command is not found, one of two things happen:
530 .Bl -enum
531 .It
532 Command names containing a slash are simply executed without performing
533 any searches.
534 .It
535 The shell searches each entry in
536 .Ev PATH
537 in turn for the command.
538 The value of the
539 .Ev PATH
540 variable should be a series of entries separated by colons.
541 Each entry consists of a directory name.
542 The current directory may be indicated
543 implicitly by an empty directory name, or explicitly by a single period.
544 .El
545 .Ss Command Exit Status
546 Each command has an exit status that can influence the behavior
547 of other shell commands.
548 The paradigm is that a command exits
549 with zero for normal or success, and non-zero for failure,
550 error, or a false indication.
551 The man page for each command
552 should indicate the various exit codes and what they mean.
553 Additionally, the builtin commands return exit codes, as does
554 an executed shell function.
555 .Pp
556 If a command consists entirely of variable assignments then the
557 exit status of the command is that of the last command substitution
558 if any, otherwise 0.
559 .Ss Complex Commands
560 Complex commands are combinations of simple commands with control
561 operators or reserved words, together creating a larger complex command.
562 More generally, a command is one of the following:
563 .Bl -bullet
564 .It
565 simple command
566 .It
567 pipeline
568 .It
569 list or compound-list
570 .It
571 compound command
572 .It
573 function definition
574 .El
575 .Pp
576 Unless otherwise stated, the exit status of a command is that of the last
577 simple command executed by the command.
578 .Ss Pipelines
579 A pipeline is a sequence of one or more commands separated
580 by the control operator |.
581 The standard output of all but
582 the last command is connected to the standard input
583 of the next command.
584 The standard output of the last
585 command is inherited from the shell, as usual.
586 .Pp
587 The format for a pipeline is:
588 .Pp
589 .Dl [!] command1 [ | command2 ...]
590 .Pp
591 The standard output of command1 is connected to the standard input of
592 command2.
593 The standard input, standard output, or both of a command is
594 considered to be assigned by the pipeline before any redirection specified
595 by redirection operators that are part of the command.
596 .Pp
597 If the pipeline is not in the background (discussed later), the shell
598 waits for all commands to complete.
599 .Pp
600 If the reserved word ! does not precede the pipeline, the exit status is
601 the exit status of the last command specified in the pipeline.
602 Otherwise, the exit status is the logical NOT of the exit status of the
603 last command.
604 That is, if the last command returns zero, the exit status
605 is 1; if the last command returns greater than zero, the exit status is
606 zero.
607 .Pp
608 Because pipeline assignment of standard input or standard output or both
609 takes place before redirection, it can be modified by redirection.
610 For example:
611 .Pp
612 .Dl $ command1 2\*[Gt]\*[Am]1 | command2
613 .Pp
614 sends both the standard output and standard error of command1
615 to the standard input of command2.
616 .Pp
617 A ; or
618 .Aq newline
619 terminator causes the preceding AND-OR-list (described
620 next) to be executed sequentially; a \*[Am] causes asynchronous execution of
621 the preceding AND-OR-list.
622 .Pp
623 Note that unlike some other shells, each process in the pipeline is a
624 child of the invoking shell (unless it is a shell builtin, in which case
625 it executes in the current shell -- but any effect it has on the
626 environment is wiped).
627 .Ss Background Commands -- \*[Am]
628 If a command is terminated by the control operator ampersand (\*[Am]), the
629 shell executes the command asynchronously -- that is, the shell does not
630 wait for the command to finish before executing the next command.
631 .Pp
632 The format for running a command in background is:
633 .Pp
634 .Dl command1 \*[Am] [command2 \*[Am] ...]
635 .Pp
636 If the shell is not interactive, the standard input of an asynchronous
637 command is set to
638 .Pa /dev/null .
639 .Ss Lists -- Generally Speaking
640 A list is a sequence of zero or more commands separated by newlines,
641 semicolons, or ampersands, and optionally terminated by one of these three
642 characters.
643 The commands in a list are executed in the order they are written.
644 If command is followed by an ampersand, the shell starts the
645 command and immediately proceed onto the next command; otherwise it waits
646 for the command to terminate before proceeding to the next one.
647 .Ss Short-Circuit List Operators
648 .Dq \*[Am]\*[Am]
649 and
650 .Dq ||
651 are AND-OR list operators.
652 .Dq \*[Am]\*[Am]
653 executes the first command, and then executes the second command if and only
654 if the exit status of the first command is zero.
655 .Dq ||
656 is similar, but executes the second command if and only if the exit status
657 of the first command is nonzero.
658 .Dq \*[Am]\*[Am]
659 and
660 .Dq ||
661 both have the same priority.
662 Note that these operators are left-associative, so
663 .Dq true || echo bar && echo baz
664 writes
665 .Dq baz
666 and nothing else.
667 This is not the way it works in C.
668 .Ss Flow-Control Constructs -- if, while, for, case
669 The syntax of the if command is
670 .Bd -literal -offset indent
671 if list
672 then list
673 [ elif list
674 then list ] ...
675 [ else list ]
676 fi
677 .Ed
678 .Pp
679 The syntax of the while command is
680 .Bd -literal -offset indent
681 while list
682 do list
683 done
684 .Ed
685 .Pp
686 The two lists are executed repeatedly while the exit status of the
687 first list is zero.
688 The until command is similar, but has the word
689 until in place of while, which causes it to
690 repeat until the exit status of the first list is zero.
691 .Pp
692 The syntax of the for command is
693 .Bd -literal -offset indent
694 for variable in word ...
695 do list
696 done
697 .Ed
698 .Pp
699 The words are expanded, and then the list is executed repeatedly with the
700 variable set to each word in turn.
701 do and done may be replaced with
702 .Dq {
703 and
704 .Dq } .
705 .Pp
706 The syntax of the break and continue command is
707 .Bd -literal -offset indent
708 break [ num ]
709 continue [ num ]
710 .Ed
711 .Pp
712 Break terminates the num innermost for or while loops.
713 Continue continues with the next iteration of the innermost loop.
714 These are implemented as builtin commands.
715 .Pp
716 The syntax of the case command is
717 .Bd -literal -offset indent
718 case word in
719 pattern) list ;;
720 \&...
721 esac
722 .Ed
723 .Pp
724 The pattern can actually be one or more patterns (see
725 .Sx Shell Patterns
726 described later), separated by
727 .Dq \*(Ba
728 characters.
729 .Ss Grouping Commands Together
730 Commands may be grouped by writing either
731 .Pp
732 .Dl (list)
733 .Pp
734 or
735 .Pp
736 .Dl { list; }
737 .Pp
738 The first of these executes the commands in a subshell.
739 Builtin commands grouped into a (list) will not affect the current shell.
740 The second form does not fork another shell so is slightly more efficient.
741 Grouping commands together this way allows you to redirect
742 their output as though they were one program:
743 .Pp
744 .Bd -literal -offset indent
745 { echo -n \*q hello \*q ; echo \*q world" ; } \*[Gt] greeting
746 .Ed
747 .Pp
748 Note that
749 .Dq }
750 must follow a control operator (here,
751 .Dq \&; )
752 so that it is recognized as a reserved word and not as another command argument.
753 .Ss Functions
754 The syntax of a function definition is
755 .Pp
756 .Dl name ( ) command
757 .Pp
758 A function definition is an executable statement; when executed it
759 installs a function named name and returns an exit status of zero.
760 The command is normally a list enclosed between
761 .Dq {
762 and
763 .Dq } .
764 .Pp
765 Variables may be declared to be local to a function by using a local
766 command.
767 This should appear as the first statement of a function, and the syntax is
768 .Pp
769 .Dl local [ variable | - ] ...
770 .Pp
771 Local is implemented as a builtin command.
772 .Pp
773 When a variable is made local, it inherits the initial value and exported
774 and readonly flags from the variable with the same name in the surrounding
775 scope, if there is one.
776 Otherwise, the variable is initially unset.
777 The shell uses dynamic scoping, so that if you make the variable x local to
778 function f, which then calls function g, references to the variable x made
779 inside g will refer to the variable x declared inside f, not to the global
780 variable named x.
781 .Pp
782 The only special parameter that can be made local is
783 .Dq - .
784 Making
785 .Dq -
786 local any shell options that are changed via the set command inside the
787 function to be restored to their original values when the function
788 returns.
789 .Pp
790 The syntax of the return command is
791 .Pp
792 .Dl return [ exitstatus ]
793 .Pp
794 It terminates the currently executing function.
795 Return is implemented as a builtin command.
796 .Ss Variables and Parameters
797 The shell maintains a set of parameters.
798 A parameter denoted by a name is called a variable.
799 When starting up, the shell turns all the environment
800 variables into shell variables.
801 New variables can be set using the form
802 .Pp
803 .Dl name=value
804 .Pp
805 Variables set by the user must have a name consisting solely of
806 alphabetics, numerics, and underscores - the first of which must not be
807 numeric.
808 A parameter can also be denoted by a number or a special
809 character as explained below.
810 .Ss Positional Parameters
811 A positional parameter is a parameter denoted by a number (n \*[Gt] 0).
812 The shell sets these initially to the values of its command line arguments
813 that follow the name of the shell script.
814 The
815 .Ic set
816 builtin can also be used to set or reset them.
817 .Ss Special Parameters
818 A special parameter is a parameter denoted by one of the following special
819 characters.
820 The value of the parameter is listed next to its character.
821 .Bl -tag -width thinhyphena
822 .It *
823 Expands to the positional parameters, starting from one.
824 When the
825 expansion occurs within a double-quoted string it expands to a single
826 field with the value of each parameter separated by the first character of
827 the
828 .Ev IFS
829 variable, or by a
830 .Aq space
831 if
832 .Ev IFS
833 is unset.
834 .It @
835 Expands to the positional parameters, starting from one.
836 When the expansion occurs within double-quotes, each positional
837 parameter expands as a separate argument.
838 If there are no positional parameters, the
839 expansion of @ generates zero arguments, even when @ is
840 double-quoted.
841 What this basically means, for example, is
842 if $1 is
843 .Dq abc
844 and $2 is
845 .Dq def ghi ,
846 then
847 .Qq $@
848 expands to
849 the two arguments:
850 .Pp
851 .Sm off
852 .Dl \*q abc \*q \ \*q def\ ghi \*q
853 .Sm on
854 .It #
855 Expands to the number of positional parameters.
856 .It \&?
857 Expands to the exit status of the most recent pipeline.
858 .It - (Hyphen.)
859 Expands to the current option flags (the single-letter
860 option names concatenated into a string) as specified on
861 invocation, by the set builtin command, or implicitly
862 by the shell.
863 .It $
864 Expands to the process ID of the invoked shell.
865 A subshell retains the same value of $ as its parent.
866 .It \&!
867 Expands to the process ID of the most recent background
868 command executed from the current shell.
869 For a pipeline, the process ID is that of the last command in the pipeline.
870 .It 0 (Zero.)
871 Expands to the name of the shell or shell script.
872 .El
873 .Ss Word Expansions
874 This clause describes the various expansions that are performed on words.
875 Not all expansions are performed on every word, as explained later.
876 .Pp
877 Tilde expansions, parameter expansions, command substitutions, arithmetic
878 expansions, and quote removals that occur within a single word expand to a
879 single field.
880 It is only field splitting or pathname expansion that can
881 create multiple fields from a single word.
882 The single exception to this
883 rule is the expansion of the special parameter @ within double-quotes, as
884 was described above.
885 .Pp
886 The order of word expansion is:
887 .Bl -enum
888 .It
889 Tilde Expansion, Parameter Expansion, Command Substitution,
890 Arithmetic Expansion (these all occur at the same time).
891 .It
892 Field Splitting is performed on fields
893 generated by step (1) unless the
894 .Ev IFS
895 variable is null.
896 .It
897 Pathname Expansion (unless set
898 .Fl f
899 is in effect).
900 .It
901 Quote Removal.
902 .El
903 .Pp
904 The $ character is used to introduce parameter expansion, command
905 substitution, or arithmetic evaluation.
906 .Ss Tilde Expansion (substituting a user's home directory)
907 A word beginning with an unquoted tilde character (~) is
908 subjected to tilde expansion.
909 All the characters up to
910 a slash (/) or the end of the word are treated as a username
911 and are replaced with the user's home directory.
912 If the username is missing (as in
913 .Pa ~/foobar ) ,
914 the tilde is replaced with the value of the
915 .Va HOME
916 variable (the current user's home directory).
917 .Ss Parameter Expansion
918 The format for parameter expansion is as follows:
919 .Pp
920 .Dl ${expression}
921 .Pp
922 where expression consists of all characters until the matching
923 .Dq } .
924 Any
925 .Dq }
926 escaped by a backslash or within a quoted string, and characters in
927 embedded arithmetic expansions, command substitutions, and variable
928 expansions, are not examined in determining the matching
929 .Dq } .
930 .Pp
931 The simplest form for parameter expansion is:
932 .Pp
933 .Dl ${parameter}
934 .Pp
935 The value, if any, of parameter is substituted.
936 .Pp
937 The parameter name or symbol can be enclosed in braces, which are
938 optional except for positional parameters with more than one digit or
939 when parameter is followed by a character that could be interpreted as
940 part of the name.
941 If a parameter expansion occurs inside double-quotes:
942 .Bl -enum
943 .It
944 Pathname expansion is not performed on the results of the expansion.
945 .It
946 Field splitting is not performed on the results of the
947 expansion, with the exception of @.
948 .El
949 .Pp
950 In addition, a parameter expansion can be modified by using one of the
951 following formats.
952 .Bl -tag -width aaparameterwordaaaaa
953 .It ${parameter:-word}
954 Use Default Values.
955 If parameter is unset or null, the expansion of word
956 is substituted; otherwise, the value of parameter is substituted.
957 .It ${parameter:=word}
958 Assign Default Values.
959 If parameter is unset or null, the expansion of
960 word is assigned to parameter.
961 In all cases, the final value of parameter is substituted.
962 Only variables, not positional parameters or special
963 parameters, can be assigned in this way.
964 .It ${parameter:?[word]}
965 Indicate Error if Null or Unset.
966 If parameter is unset or null, the
967 expansion of word (or a message indicating it is unset if word is omitted)
968 is written to standard error and the shell exits with a nonzero exit status.
969 Otherwise, the value of parameter is substituted.
970 An interactive shell need not exit.
971 .It ${parameter:+word}
972 Use Alternative Value.
973 If parameter is unset or null, null is
974 substituted; otherwise, the expansion of word is substituted.
975 .El
976 .Pp
977 In the parameter expansions shown previously, use of the colon in the
978 format results in a test for a parameter that is unset or null; omission
979 of the colon results in a test for a parameter that is only unset.
980 .Bl -tag -width aaparameterwordaaaaa
981 .It ${#parameter}
982 String Length.
983 The length in characters of the value of parameter.
984 .El
985 .Pp
986 The following four varieties of parameter expansion provide for substring
987 processing.
988 In each case, pattern matching notation (see
989 .Sx Shell Patterns ) ,
990 rather than regular expression notation, is used to evaluate the patterns.
991 If parameter is * or @, the result of the expansion is unspecified.
992 Enclosing the full parameter expansion string in double-quotes does not
993 cause the following four varieties of pattern characters to be quoted,
994 whereas quoting characters within the braces has this effect.
995 .Bl -tag -width aaparameterwordaaaaa
996 .It ${parameter%word}
997 Remove Smallest Suffix Pattern.
998 The word is expanded to produce a pattern.
999 The parameter expansion then results in parameter, with the
1000 smallest portion of the suffix matched by the pattern deleted.
1001 .It ${parameter%%word}
1002 Remove Largest Suffix Pattern.
1003 The word is expanded to produce a pattern.
1004 The parameter expansion then results in parameter, with the largest
1005 portion of the suffix matched by the pattern deleted.
1006 .It ${parameter#word}
1007 Remove Smallest Prefix Pattern.
1008 The word is expanded to produce a pattern.
1009 The parameter expansion then results in parameter, with the
1010 smallest portion of the prefix matched by the pattern deleted.
1011 .It ${parameter##word}
1012 Remove Largest Prefix Pattern.
1013 The word is expanded to produce a pattern.
1014 The parameter expansion then results in parameter, with the largest
1015 portion of the prefix matched by the pattern deleted.
1016 .El
1017 .Ss Command Substitution
1018 Command substitution allows the output of a command to be substituted in
1019 place of the command name itself.
1020 Command substitution occurs when the command is enclosed as follows:
1021 .Pp
1022 .Dl $(command)
1023 .Pp
1024 or
1025 .Po
1026 .Dq backquoted
1027 version
1028 .Pc :
1029 .Pp
1030 .Dl `command`
1031 .Pp
1032 The shell expands the command substitution by executing command in a
1033 subshell environment and replacing the command substitution with the
1034 standard output of the command, removing sequences of one or more
1035 .Ao newline Ac Ns s
1036 at the end of the substitution.
1037 (Embedded
1038 .Ao newline Ac Ns s
1039 before
1040 the end of the output are not removed; however, during field splitting,
1041 they may be translated into
1042 .Ao space Ac Ns s ,
1043 depending on the value of
1044 .Ev IFS
1045 and quoting that is in effect.)
1046 .Ss Arithmetic Expansion
1047 Arithmetic expansion provides a mechanism for evaluating an arithmetic
1048 expression and substituting its value.
1049 The format for arithmetic expansion is as follows:
1050 .Pp
1051 .Dl $((expression))
1052 .Pp
1053 The expression is treated as if it were in double-quotes, except
1054 that a double-quote inside the expression is not treated specially.
1055 The shell expands all tokens in the expression for parameter expansion,
1056 command substitution, and quote removal.
1057 .Pp
1058 Next, the shell treats this as an arithmetic expression and
1059 substitutes the value of the expression.
1060 .Ss White Space Splitting (Field Splitting)
1061 After parameter expansion, command substitution, and
1062 arithmetic expansion the shell scans the results of
1063 expansions and substitutions that did not occur in double-quotes for
1064 field splitting and multiple fields can result.
1065 .Pp
1066 The shell treats each character of the
1067 .Ev IFS
1068 as a delimiter and use the delimiters to split the results of parameter
1069 expansion and command substitution into fields.
1070 .Ss Pathname Expansion (File Name Generation)
1071 Unless the
1072 .Fl f
1073 flag is set, file name generation is performed after word splitting is
1074 complete.
1075 Each word is viewed as a series of patterns, separated by slashes.
1076 The process of expansion replaces the word with the names of all
1077 existing files whose names can be formed by replacing each pattern with a
1078 string that matches the specified pattern.
1079 There are two restrictions on
1080 this: first, a pattern cannot match a string containing a slash, and
1081 second, a pattern cannot match a string starting with a period unless the
1082 first character of the pattern is a period.
1083 The next section describes the
1084 patterns used for both Pathname Expansion and the
1085 .Ic case
1086 command.
1087 .Ss Shell Patterns
1088 A pattern consists of normal characters, which match themselves,
1089 and meta-characters.
1090 The meta-characters are
1091 .Dq \&! ,
1092 .Dq * ,
1093 .Dq \&? ,
1094 and
1095 .Dq \&[ .
1096 These characters lose their special meanings if they are quoted.
1097 When command or variable substitution is performed
1098 and the dollar sign or back quotes are not double quoted,
1099 the value of the variable or the output of
1100 the command is scanned for these characters and they are turned into
1101 meta-characters.
1102 .Pp
1103 An asterisk
1104 .Pq Dq *
1105 matches any string of characters.
1106 A question mark matches any single character.
1107 A left bracket
1108 .Pq Dq \&[
1109 introduces a character class.
1110 The end of the character class is indicated by a
1111 .Pq Dq \&] ;
1112 if the
1113 .Dq \&]
1114 is missing then the
1115 .Dq \&[
1116 matches a
1117 .Dq \&[
1118 rather than introducing a character class.
1119 A character class matches any of the characters between the square brackets.
1120 A range of characters may be specified using a minus sign.
1121 The character class may be complemented
1122 by making an exclamation point the first character of the character class.
1123 .Pp
1124 To include a
1125 .Dq \&]
1126 in a character class, make it the first character listed (after the
1127 .Dq \&! ,
1128 if any).
1129 To include a minus sign, make it the first or last character listed.
1130 .Ss Builtins
1131 This section lists the builtin commands which are builtin because they
1132 need to perform some operation that can't be performed by a separate
1133 process.
1134 In addition to these, there are several other commands that may
1135 be builtin for efficiency (e.g.
1136 .Xr printf 1 ,
1137 .Xr echo 1 ,
1138 .Xr test 1 ,
1139 etc).
1140 .Bl -tag -width 5n
1141 .It :
1142 A null command that returns a 0 (true) exit value.
1143 .It \&. file
1144 The commands in the specified file are read and executed by the shell.
1145 .It alias Op Ar name Ns Op Ar "=string ..."
1146 If
1147 .Ar name=string
1148 is specified, the shell defines the alias
1149 .Ar name
1150 with value
1151 .Ar string .
1152 If just
1153 .Ar name
1154 is specified, the value of the alias
1155 .Ar name
1156 is printed.
1157 With no arguments, the
1158 .Ic alias
1159 builtin prints the
1160 names and values of all defined aliases (see
1161 .Ic unalias ) .
1162 .It bg [ Ar job ] ...
1163 Continue the specified jobs (or the current job if no
1164 jobs are given) in the background.
1165 .It Xo command
1166 .Op Fl p
1167 .Op Fl v
1168 .Op Fl V
1169 .Ar command
1170 .Op Ar arg ...
1171 .Xc
1172 Execute the specified command but ignore shell functions when searching
1173 for it.
1174 (This is useful when you
1175 have a shell function with the same name as a builtin command.)
1176 .Bl -tag -width 5n
1177 .It Fl p
1178 search for command using a
1179 .Ev PATH
1180 that guarantees to find all the standard utilities.
1181 .It Fl V
1182 Do not execute the command but
1183 search for the command and print the resolution of the
1184 command search.
1185 This is the same as the type builtin.
1186 .It Fl v
1187 Do not execute the command but
1188 search for the command and print the absolute pathname
1189 of utilities, the name for builtins or the expansion of aliases.
1190 .El
1191 .It cd Op Ar directory Op Ar replace
1192 Switch to the specified directory (default
1193 .Ev $HOME ) .
1194 If
1195 .Ar replace
1196 is specified, then the new directory name is generated by replacing
1197 the first occurrence of
1198 .Ar directory
1199 in the current directory name with
1200 .Ar replace .
1201 Otherwise if an entry for
1202 .Ev CDPATH
1203 appears in the environment of the
1204 .Ic cd
1205 command or the shell variable
1206 .Ev CDPATH
1207 is set and the directory name does not begin with a slash, then the
1208 directories listed in
1209 .Ev CDPATH
1210 will be searched for the specified directory.
1211 The format of
1212 .Ev CDPATH
1213 is the same as that of
1214 .Ev PATH .
1215 In an interactive shell, the
1216 .Ic cd
1217 command will print out the name of the
1218 directory that it actually switched to if this is different from the name
1219 that the user gave.
1220 These may be different either because the
1221 .Ev CDPATH
1222 mechanism was used or because a symbolic link was crossed.
1223 .It eval Ar string ...
1224 Concatenate all the arguments with spaces.
1225 Then re-parse and execute the command.
1226 .It exec Op Ar command arg ...
1227 Unless command is omitted, the shell process is replaced with the
1228 specified program (which must be a real program, not a shell builtin or
1229 function).
1230 Any redirections on the
1231 .Ic exec
1232 command are marked as permanent, so that they are not undone when the
1233 .Ic exec
1234 command finishes.
1235 .It exit Op Ar exitstatus
1236 Terminate the shell process.
1237 If
1238 .Ar exitstatus
1239 is given it is used as the exit status of the shell; otherwise the
1240 exit status of the preceding command is used.
1241 .It export Ar name ...
1242 .It export Fl p
1243 The specified names are exported so that they will appear in the
1244 environment of subsequent commands.
1245 The only way to un-export a variable is to unset it.
1246 The shell allows the value of a variable to be set at the
1247 same time it is exported by writing
1248 .Pp
1249 .Dl export name=value
1250 .Pp
1251 With no arguments the export command lists the names of all exported variables.
1252 With the
1253 .Fl p
1254 option specified the output will be formatted suitably for non-interactive use.
1255 .It Xo fc Op Fl e Ar editor
1256 .Op Ar first Op Ar last
1257 .Xc
1258 .It Xo fc Fl l
1259 .Op Fl nr
1260 .Op Ar first Op Ar last
1261 .Xc
1262 .It Xo fc Fl s Op Ar old=new
1263 .Op Ar first
1264 .Xc
1265 The
1266 .Ic fc
1267 builtin lists, or edits and re-executes, commands previously entered
1268 to an interactive shell.
1269 .Bl -tag -width 5n
1270 .It Fl e No editor
1271 Use the editor named by editor to edit the commands.
1272 The editor string is a command name, subject to search via the
1273 .Ev PATH
1274 variable.
1275 The value in the
1276 .Ev FCEDIT
1277 variable is used as a default when
1278 .Fl e
1279 is not specified.
1280 If
1281 .Ev FCEDIT
1282 is null or unset, the value of the
1283 .Ev EDITOR
1284 variable is used.
1285 If
1286 .Ev EDITOR
1287 is null or unset,
1288 .Xr ed 1
1289 is used as the editor.
1290 .It Fl l No (ell)
1291 List the commands rather than invoking an editor on them.
1292 The commands are written in the sequence indicated by
1293 the first and last operands, as affected by
1294 .Fl r ,
1295 with each command preceded by the command number.
1296 .It Fl n
1297 Suppress command numbers when listing with -l.
1298 .It Fl r
1299 Reverse the order of the commands listed (with
1300 .Fl l )
1301 or edited (with neither
1302 .Fl l
1303 nor
1304 .Fl s ) .
1305 .It Fl s
1306 Re-execute the command without invoking an editor.
1307 .It first
1308 .It last
1309 Select the commands to list or edit.
1310 The number of previous commands that
1311 can be accessed are determined by the value of the
1312 .Ev HISTSIZE
1313 variable.
1314 The value of first or last or both are one of the following:
1315 .Bl -tag -width 5n
1316 .It [+]number
1317 A positive number representing a command number; command numbers can be
1318 displayed with the
1319 .Fl l
1320 option.
1321 .It Fl number
1322 A negative decimal number representing the command that was executed
1323 number of commands previously.
1324 For example, \-1 is the immediately previous command.
1325 .El
1326 .It string
1327 A string indicating the most recently entered command that begins with
1328 that string.
1329 If the old=new operand is not also specified with
1330 .Fl s ,
1331 the string form of the first operand cannot contain an embedded equal sign.
1332 .El
1333 .Pp
1334 The following environment variables affect the execution of fc:
1335 .Bl -tag -width HISTSIZE
1336 .It Ev FCEDIT
1337 Name of the editor to use.
1338 .It Ev HISTSIZE
1339 The number of previous commands that are accessible.
1340 .El
1341 .It fg Op Ar job
1342 Move the specified job or the current job to the foreground.
1343 .It getopts Ar optstring var
1344 The
1345 .Tn POSIX
1346 .Ic getopts
1347 command, not to be confused with the
1348 .Em Bell Labs
1349 -derived
1350 .Xr getopt 1 .
1351 .Pp
1352 The first argument should be a series of letters, each of which may be
1353 optionally followed by a colon to indicate that the option requires an
1354 argument.
1355 The variable specified is set to the parsed option.
1356 .Pp
1357 The
1358 .Ic getopts
1359 command deprecates the older
1360 .Xr getopt 1
1361 utility due to its handling of arguments containing whitespace.
1362 .Pp
1363 The
1364 .Ic getopts
1365 builtin may be used to obtain options and their arguments
1366 from a list of parameters.
1367 When invoked,
1368 .Ic getopts
1369 places the value of the next option from the option string in the list in
1370 the shell variable specified by
1371 .Va var
1372 and its index in the shell variable
1373 .Ev OPTIND .
1374 When the shell is invoked,
1375 .Ev OPTIND
1376 is initialized to 1.
1377 For each option that requires an argument, the
1378 .Ic getopts
1379 builtin will place it in the shell variable
1380 .Ev OPTARG .
1381 If an option is not allowed for in the
1382 .Va optstring ,
1383 then
1384 .Ev OPTARG
1385 will be unset.
1386 .Pp
1387 .Va optstring
1388 is a string of recognized option letters (see
1389 .Xr getopt 3 ) .
1390 If a letter is followed by a colon, the option is expected to have an
1391 argument which may or may not be separated from it by white space.
1392 If an option character is not found where expected,
1393 .Ic getopts
1394 will set the variable
1395 .Va var
1396 to a
1397 .Dq \&? ;
1398 .Ic getopts
1399 will then unset
1400 .Ev OPTARG
1401 and write output to standard error.
1402 By specifying a colon as the first character of
1403 .Va optstring
1404 all errors will be ignored.
1405 .Pp
1406 A nonzero value is returned when the last option is reached.
1407 If there are no remaining arguments,
1408 .Ic getopts
1409 will set
1410 .Va var
1411 to the special option,
1412 .Dq -- ,
1413 otherwise, it will set
1414 .Va var
1415 to
1416 .Dq \&? .
1417 .Pp
1418 The following code fragment shows how one might process the arguments
1419 for a command that can take the options
1420 .Op a
1421 and
1422 .Op b ,
1423 and the option
1424 .Op c ,
1425 which requires an argument.
1426 .Pp
1427 .Bd -literal -offset indent
1428 while getopts abc: f
1429 do
1430 case $f in
1431 a | b) flag=$f;;
1432 c) carg=$OPTARG;;
1433 \\?) echo $USAGE; exit 1;;
1434 esac
1435 done
1436 shift `expr $OPTIND - 1`
1437 .Ed
1438 .Pp
1439 This code will accept any of the following as equivalent:
1440 .Pp
1441 .Bd -literal -offset indent
1442 cmd \-acarg file file
1443 cmd \-a \-c arg file file
1444 cmd \-carg -a file file
1445 cmd \-a \-carg \-\- file file
1446 .Ed
1447 .It hash Fl rv Ar command ...
1448 The shell maintains a hash table which remembers the
1449 locations of commands.
1450 With no arguments whatsoever,
1451 the
1452 .Ic hash
1453 command prints out the contents of this table.
1454 Entries which have not been looked at since the last
1455 .Ic cd
1456 command are marked with an asterisk; it is possible for these entries
1457 to be invalid.
1458 .Pp
1459 With arguments, the
1460 .Ic hash
1461 command removes the specified commands from the hash table (unless
1462 they are functions) and then locates them.
1463 With the
1464 .Fl v
1465 option, hash prints the locations of the commands as it finds them.
1466 The
1467 .Fl r
1468 option causes the hash command to delete all the entries in the hash table
1469 except for functions.
1470 .It inputrc Ar file
1471 Read the
1472 .Va file
1473 to set keybindings as defined by
1474 .Xr editrc 5 .
1475 .It jobid Op Ar job
1476 Print the process id's of the processes in the job.
1477 If the
1478 .Ar job
1479 argument is omitted, the current job is used.
1480 .It jobs
1481 This command lists out all the background processes
1482 which are children of the current shell process.
1483 .It pwd Op Fl LP
1484 Print the current directory.
1485 If
1486 .Fl L
1487 is specified the cached value (initially set from
1488 .Ev PWD )
1489 is checked to see if it refers to the current directory, if it does
1490 the value is printed.
1491 Otherwise the current directory name is found using
1492 .Xr getcwd(3) .
1493 The environment variable
1494 .Ev PWD
1495 is set to printed value.
1496 .Pp
1497 The default is
1498 .Ic pwd
1499 .Fl L ,
1500 but note that the builtin
1501 .Ic cd
1502 command doesn't currently support
1503 .Fl L
1504 or
1505 .Fl P
1506 and will cache (almost) the absolute path.
1507 If
1508 .Ic cd
1509 is changed,
1510 .Ic pwd
1511 may be changed to default to
1512 .Ic pwd
1513 .Fl P .
1514 .Pp
1515 If the current directory is renamed and replaced by a symlink to the
1516 same directory, or the initial
1517 .Ev PWD
1518 value followed a symbolic link, then the cached value may not
1519 be the absolute path.
1520 .Pp
1521 The builtin command may differ from the program of the same name because
1522 the program will use
1523 .Ev PWD
1524 and the builtin uses a separately cached value.
1525 .It Xo read Op Fl p Ar prompt
1526 .Op Fl r
1527 .Ar variable
1528 .Op Ar ...
1529 .Xc
1530 The prompt is printed if the
1531 .Fl p
1532 option is specified and the standard input is a terminal.
1533 Then a line is read from the standard input.
1534 The trailing newline is deleted from the
1535 line and the line is split as described in the section on word splitting
1536 above, and the pieces are assigned to the variables in order.
1537 If there are more pieces than variables, the remaining pieces
1538 (along with the characters in
1539 .Ev IFS
1540 that separated them) are assigned to the last variable.
1541 If there are more variables than pieces,
1542 the remaining variables are assigned the null string.
1543 The
1544 .Ic read
1545 builtin will indicate success unless EOF is encountered on input, in
1546 which case failure is returned.
1547 .Pp
1548 By default, unless the
1549 .Fl r
1550 option is specified, the backslash
1551 .Dq \e
1552 acts as an escape character, causing the following character to be treated
1553 literally.
1554 If a backslash is followed by a newline, the backslash and the
1555 newline will be deleted.
1556 .It readonly Ar name ...
1557 .It readonly Fl p
1558 The specified names are marked as read only, so that they cannot be
1559 subsequently modified or unset.
1560 The shell allows the value of a variable
1561 to be set at the same time it is marked read only by writing
1562 .Pp
1563 .Dl readonly name=value
1564 .Pp
1565 With no arguments the readonly command lists the names of all read only
1566 variables.
1567 With the
1568 .Fl p
1569 option specified the output will be formatted suitably for non-interactive use.
1570 .Pp
1571 .It Xo set
1572 .Oo {
1573 .Fl options | Cm +options | Cm -- }
1574 .Oc Ar arg ...
1575 .Xc
1576 The
1577 .Ic set
1578 command performs three different functions.
1579 .Pp
1580 With no arguments, it lists the values of all shell variables.
1581 .Pp
1582 If options are given, it sets the specified option
1583 flags, or clears them as described in the section called
1584 .Sx Argument List Processing .
1585 .Pp
1586 The third use of the set command is to set the values of the shell's
1587 positional parameters to the specified args.
1588 To change the positional
1589 parameters without changing any options, use
1590 .Dq --
1591 as the first argument to set.
1592 If no args are present, the set command
1593 will clear all the positional parameters (equivalent to executing
1594 .Dq shift $# . )
1595 .It setvar Ar variable Ar value
1596 Assigns value to variable.
1597 (In general it is better to write
1598 variable=value rather than using
1599 .Ic setvar .
1600 .Ic setvar
1601 is intended to be used in
1602 functions that assign values to variables whose names are passed as
1603 parameters.)
1604 .It shift Op Ar n
1605 Shift the positional parameters n times.
1606 A
1607 .Ic shift
1608 sets the value of
1609 .Va $1
1610 to the value of
1611 .Va $2 ,
1612 the value of
1613 .Va $2
1614 to the value of
1615 .Va $3 ,
1616 and so on, decreasing
1617 the value of
1618 .Va $#
1619 by one.
1620 If there are zero positional parameters,
1621 .Ic shift
1622 does nothing.
1623 .It Xo trap
1624 .Op Fl l
1625 .Xc
1626 .It Xo trap
1627 .Op Ar action
1628 .Ar signal ...
1629 .Xc
1630 Cause the shell to parse and execute action when any of the specified
1631 signals are received.
1632 The signals are specified by signal number or as the name of the signal.
1633 If
1634 .Ar signal
1635 is
1636 .Li 0 ,
1637 the action is executed when the shell exits.
1638 .Ar action
1639 may be null, which cause the specified signals to be ignored.
1640 With
1641 .Ar action
1642 omitted or set to `-' the specified signals are set to their default action.
1643 When the shell forks off a subshell, it resets trapped (but not ignored)
1644 signals to the default action.
1645 The
1646 .Ic trap
1647 command has no effect on signals that were
1648 ignored on entry to the shell.
1649 Issuing
1650 .Ic trap
1651 with option
1652 .Ar -l
1653 will print a list of valid signal names.
1654 .Ic trap
1655 without any arguments cause it to write a list of signals and their
1656 associated action to the standard output in a format that is suitable
1657 as an input to the shell that achieves the same trapping results.
1658 .Pp
1659 Examples:
1660 .Pp
1661 .Dl trap
1662 .Pp
1663 List trapped signals and their corresponding action
1664 .Pp
1665 .Dl trap -l
1666 .Pp
1667 Print a list of valid signals
1668 .Pp
1669 .Dl trap '' INT QUIT tstp 30
1670 .Pp
1671 Ignore signals INT QUIT TSTP USR1
1672 .Pp
1673 .Dl trap date INT
1674 .Pp
1675 Print date upon receiving signal INT
1676 .It type Op Ar name ...
1677 Interpret each name as a command and print the resolution of the command
1678 search.
1679 Possible resolutions are:
1680 shell keyword, alias, shell builtin,
1681 command, tracked alias and not found.
1682 For aliases the alias expansion is
1683 printed; for commands and tracked aliases the complete pathname of the
1684 command is printed.
1685 .It ulimit Xo
1686 .Op Fl H \*(Ba Fl S
1687 .Op Fl a \*(Ba Fl tfdscmlpn Op Ar value
1688 .Xc
1689 Inquire about or set the hard or soft limits on processes or set new
1690 limits.
1691 The choice between hard limit (which no process is allowed to
1692 violate, and which may not be raised once it has been lowered) and soft
1693 limit (which causes processes to be signaled but not necessarily killed,
1694 and which may be raised) is made with these flags:
1695 .Bl -tag -width Fl
1696 .It Fl H
1697 set or inquire about hard limits
1698 .It Fl S
1699 set or inquire about soft limits.
1700 If neither
1701 .Fl H
1702 nor
1703 .Fl S
1704 is specified, the soft limit is displayed or both limits are set.
1705 If both are specified, the last one wins.
1706 .El
1707 .Pp
1708 .Bl -tag -width Fl
1709 The limit to be interrogated or set, then, is chosen by specifying
1710 any one of these flags:
1711 .It Fl a
1712 show all the current limits
1713 .It Fl b
1714 show or set the limit on the socket buffer size of a process (in bytes)
1715 .It Fl t
1716 show or set the limit on CPU time (in seconds)
1717 .It Fl f
1718 show or set the limit on the largest file that can be created
1719 (in 512-byte blocks)
1720 .It Fl d
1721 show or set the limit on the data segment size of a process (in kilobytes)
1722 .It Fl s
1723 show or set the limit on the stack size of a process (in kilobytes)
1724 .It Fl c
1725 show or set the limit on the largest core dump size that can be produced
1726 (in 512-byte blocks)
1727 .It Fl m
1728 show or set the limit on the total physical memory that can be
1729 in use by a process (in kilobytes)
1730 .It Fl l
1731 show or set the limit on how much memory a process can lock with
1732 .Xr mlock 2
1733 (in kilobytes)
1734 .It Fl p
1735 show or set the limit on the number of processes this user can
1736 have at one time
1737 .It Fl n
1738 show or set the limit on the number of files a process can have open at once
1739 .El
1740 .Pp
1741 If none of these is specified, it is the limit on file size that is shown
1742 or set.
1743 If value is specified, the limit is set to that number; otherwise
1744 the current limit is displayed.
1745 .Pp
1746 Limits of an arbitrary process can be displayed or set using the
1747 .Xr sysctl 8
1748 utility.
1749 .Pp
1750 .It umask Op Ar mask
1751 Set the value of umask (see
1752 .Xr umask 2 )
1753 to the specified octal value.
1754 If the argument is omitted, the umask value is printed.
1755 .It unalias Xo
1756 .Op Fl a
1757 .Op Ar name
1758 .Xc
1759 If
1760 .Ar name
1761 is specified, the shell removes that alias.
1762 If
1763 .Fl a
1764 is specified, all aliases are removed.
1765 .It unset Ar name ...
1766 The specified variables and functions are unset and unexported.
1767 If a given name corresponds to both a variable and a function, both
1768 the variable and the function are unset.
1769 .It wait Op Ar job
1770 Wait for the specified job to complete and return the exit status of the
1771 last process in the job.
1772 If the argument is omitted, wait for all jobs to
1773 complete and then return an exit status of zero.
1774 .El
1775 .Ss Command Line Editing
1776 When
1777 .Nm
1778 is being used interactively from a terminal, the current command
1779 and the command history (see
1780 .Ic fc
1781 in
1782 .Sx Builtins )
1783 can be edited using emacs-mode or vi-mode command-line editing.
1784 The command
1785 .Ql set -o emacs
1786 enables emacs-mode editing.
1787 The command
1788 .Ql set -o vi
1789 enables vi-mode editing and places sh into vi insert mode.
1790 (See the
1791 .Sx Argument List Processing
1792 section above.)
1793 .Pp
1794 The vi mode uses commands similar to a subset of those described in the
1795 .Xr vi 1
1796 man page.
1797 With vi-mode
1798 enabled, sh can be switched between insert mode and command mode.
1799 It's similar to vi: typing
1800 .Aq ESC
1801 will throw you into command VI command mode.
1802 Hitting
1803 .Aq return
1804 while in command mode will pass the line to the shell.
1805 .Pp
1806 The emacs mode uses commands similar to a subset available in
1807 the emacs editor.
1808 With emacs-mode enabled, special keys can be used to modify the text
1809 in the buffer using the control key.
1810 .Pp
1811 .Nm
1812 uses the
1813 .Xr editline 3
1814 library.
1815 .Sh EXIT STATUS
1816 Errors that are detected by the shell, such as a syntax error, will cause the
1817 shell to exit with a non-zero exit status.
1818 If the shell is not an
1819 interactive shell, the execution of the shell file will be aborted.
1820 Otherwise
1821 the shell will return the exit status of the last command executed, or
1822 if the exit builtin is used with a numeric argument, it will return the
1823 argument.
1824 .Sh ENVIRONMENT
1825 .Bl -tag -width MAILCHECK
1826 .It Ev HOME
1827 Set automatically by
1828 .Xr login 1
1829 from the user's login directory in the password file
1830 .Pq Xr passwd 5 .
1831 This environment variable also functions as the default argument for the
1832 cd builtin.
1833 .It Ev PATH
1834 The default search path for executables.
1835 See the above section
1836 .Sx Path Search .
1837 .It Ev CDPATH
1838 The search path used with the cd builtin.
1839 .It Ev LANG
1840 The string used to specify localization information that allows users
1841 to work with different culture-specific and language conventions.
1842 See
1843 .Xr nls 7 .
1844 .It Ev MAIL
1845 The name of a mail file, that will be checked for the arrival of new mail.
1846 Overridden by
1847 .Ev MAILPATH .
1848 .It Ev MAILCHECK
1849 The frequency in seconds that the shell checks for the arrival of mail
1850 in the files specified by the
1851 .Ev MAILPATH
1852 or the
1853 .Ev MAIL
1854 file.
1855 If set to 0, the check will occur at each prompt.
1856 .It Ev MAILPATH
1857 A colon
1858 .Dq \&:
1859 separated list of file names, for the shell to check for incoming mail.
1860 This environment setting overrides the
1861 .Ev MAIL
1862 setting.
1863 There is a maximum of 10 mailboxes that can be monitored at once.
1864 .It Ev PS1
1865 The primary prompt string, which defaults to
1866 .Dq $ \ ,
1867 unless you are the superuser, in which case it defaults to
1868 .Dq # \ .
1869 .It Ev PS2
1870 The secondary prompt string, which defaults to
1871 .Dq \*[Gt] \ .
1872 .It Ev PS4
1873 Output before each line when execution trace (set -x) is enabled,
1874 defaults to
1875 .Dq + \ .
1876 .It Ev IFS
1877 Input Field Separators.
1878 This is normally set to
1879 .Aq space ,
1880 .Aq tab ,
1881 and
1882 .Aq newline .
1883 See the
1884 .Sx White Space Splitting
1885 section for more details.
1886 .It Ev TERM
1887 The default terminal setting for the shell.
1888 This is inherited by
1889 children of the shell, and is used in the history editing modes.
1890 .It Ev HISTSIZE
1891 The number of lines in the history buffer for the shell.
1892 .El
1893 .Sh FILES
1894 .Bl -item -width HOMEprofilexxxx
1895 .It
1896 .Pa $HOME/.profile
1897 .It
1898 .Pa /etc/profile
1899 .El
1900 .Sh SEE ALSO
1901 .Xr csh 1 ,
1902 .Xr echo 1 ,
1903 .Xr getopt 1 ,
1904 .Xr ksh 1 ,
1905 .Xr login 1 ,
1906 .Xr printf 1 ,
1907 .Xr test 1 ,
1908 .Xr editline 3 ,
1909 .Xr getopt 3 ,
1910 .\" .Xr profile 4 ,
1911 .Xr editrc 5 ,
1912 .Xr passwd 5 ,
1913 .Xr environ 7 ,
1914 .Xr nls 7 ,
1915 .Xr sysctl 8
1916 .Sh HISTORY
1917 A
1918 .Nm
1919 command appeared in
1920 .At v1 .
1921 It was, however, unmaintainable so we wrote this one.
1922 .Sh BUGS
1923 Setuid shell scripts should be avoided at all costs, as they are a
1924 significant security risk.
1925 .Pp
1926 PS1, PS2, and PS4 should be subject to parameter expansion before
1927 being displayed.
+0
-83
sh/shell.h less more
0 /* $NetBSD: shell.h,v 1.17 2003/08/07 09:05:38 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)shell.h 8.2 (Berkeley) 5/4/95
34 */
35
36 /*
37 * The follow should be set to reflect the type of system you have:
38 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
39 * SHORTNAMES -> 1 if your linker cannot handle long names.
40 * define BSD if you are running 4.2 BSD or later.
41 * define SYSV if you are running under System V.
42 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
43 * define DEBUG=2 to compile in and turn on debugging.
44 * define DO_SHAREDVFORK to indicate that vfork(2) shares its address
45 * with its parent.
46 *
47 * When debugging is on, debugging info will be written to ./trace and
48 * a quit signal will generate a core dump.
49 */
50
51 #include <sys/param.h>
52
53 #define JOBS 1
54 #ifndef BSD
55 #define BSD 1
56 #endif
57
58 #ifndef DO_SHAREDVFORK
59 #if __NetBSD_Version__ >= 104000000
60 #define DO_SHAREDVFORK
61 #endif
62 #endif
63
64 typedef void *pointer;
65 #ifndef NULL
66 #define NULL (void *)0
67 #endif
68 #define STATIC /* empty */
69 #define MKINIT /* empty */
70
71 #include <sys/cdefs.h>
72
73 extern char nullstr[1]; /* null string */
74
75
76 #ifdef DEBUG
77 #define TRACE(param) trace param
78 #define TRACEV(param) tracev param
79 #else
80 #define TRACE(param)
81 #define TRACEV(param)
82 #endif
+0
-425
sh/show.c less more
0 /* $NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <stdio.h>
44 #include <stdarg.h>
45 #include <stdlib.h>
46
47 #include "shell.h"
48 #include "parser.h"
49 #include "nodes.h"
50 #include "mystring.h"
51 #include "show.h"
52 #include "options.h"
53
54
55 #ifdef DEBUG
56 static void shtree(union node *, int, char *, FILE*);
57 static void shcmd(union node *, FILE *);
58 static void sharg(union node *, FILE *);
59 static void indent(int, char *, FILE *);
60 static void trstring(char *);
61
62
63 void
64 showtree(union node *n)
65 {
66 trputs("showtree called\n");
67 shtree(n, 1, NULL, stdout);
68 }
69
70
71 static void
72 shtree(union node *n, int ind, char *pfx, FILE *fp)
73 {
74 struct nodelist *lp;
75 const char *s;
76
77 if (n == NULL)
78 return;
79
80 indent(ind, pfx, fp);
81 switch(n->type) {
82 case NSEMI:
83 s = "; ";
84 goto binop;
85 case NAND:
86 s = " && ";
87 goto binop;
88 case NOR:
89 s = " || ";
90 binop:
91 shtree(n->nbinary.ch1, ind, NULL, fp);
92 /* if (ind < 0) */
93 fputs(s, fp);
94 shtree(n->nbinary.ch2, ind, NULL, fp);
95 break;
96 case NCMD:
97 shcmd(n, fp);
98 if (ind >= 0)
99 putc('\n', fp);
100 break;
101 case NPIPE:
102 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
103 shcmd(lp->n, fp);
104 if (lp->next)
105 fputs(" | ", fp);
106 }
107 if (n->npipe.backgnd)
108 fputs(" &", fp);
109 if (ind >= 0)
110 putc('\n', fp);
111 break;
112 default:
113 fprintf(fp, "<node type %d>", n->type);
114 if (ind >= 0)
115 putc('\n', fp);
116 break;
117 }
118 }
119
120
121
122 static void
123 shcmd(union node *cmd, FILE *fp)
124 {
125 union node *np;
126 int first;
127 const char *s;
128 int dftfd;
129
130 first = 1;
131 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
132 if (! first)
133 putchar(' ');
134 sharg(np, fp);
135 first = 0;
136 }
137 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
138 if (! first)
139 putchar(' ');
140 switch (np->nfile.type) {
141 case NTO: s = ">"; dftfd = 1; break;
142 case NCLOBBER: s = ">|"; dftfd = 1; break;
143 case NAPPEND: s = ">>"; dftfd = 1; break;
144 case NTOFD: s = ">&"; dftfd = 1; break;
145 case NFROM: s = "<"; dftfd = 0; break;
146 case NFROMFD: s = "<&"; dftfd = 0; break;
147 case NFROMTO: s = "<>"; dftfd = 0; break;
148 default: s = "*error*"; dftfd = 0; break;
149 }
150 if (np->nfile.fd != dftfd)
151 fprintf(fp, "%d", np->nfile.fd);
152 fputs(s, fp);
153 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
154 fprintf(fp, "%d", np->ndup.dupfd);
155 } else {
156 sharg(np->nfile.fname, fp);
157 }
158 first = 0;
159 }
160 }
161
162
163
164 static void
165 sharg(union node *arg, FILE *fp)
166 {
167 char *p;
168 struct nodelist *bqlist;
169 int subtype;
170
171 if (arg->type != NARG) {
172 printf("<node type %d>\n", arg->type);
173 abort();
174 }
175 bqlist = arg->narg.backquote;
176 for (p = arg->narg.text ; *p ; p++) {
177 switch (*p) {
178 case CTLESC:
179 putc(*++p, fp);
180 break;
181 case CTLVAR:
182 putc('$', fp);
183 putc('{', fp);
184 subtype = *++p;
185 if (subtype == VSLENGTH)
186 putc('#', fp);
187
188 while (*p != '=')
189 putc(*p++, fp);
190
191 if (subtype & VSNUL)
192 putc(':', fp);
193
194 switch (subtype & VSTYPE) {
195 case VSNORMAL:
196 putc('}', fp);
197 break;
198 case VSMINUS:
199 putc('-', fp);
200 break;
201 case VSPLUS:
202 putc('+', fp);
203 break;
204 case VSQUESTION:
205 putc('?', fp);
206 break;
207 case VSASSIGN:
208 putc('=', fp);
209 break;
210 case VSTRIMLEFT:
211 putc('#', fp);
212 break;
213 case VSTRIMLEFTMAX:
214 putc('#', fp);
215 putc('#', fp);
216 break;
217 case VSTRIMRIGHT:
218 putc('%', fp);
219 break;
220 case VSTRIMRIGHTMAX:
221 putc('%', fp);
222 putc('%', fp);
223 break;
224 case VSLENGTH:
225 break;
226 default:
227 printf("<subtype %d>", subtype);
228 }
229 break;
230 case CTLENDVAR:
231 putc('}', fp);
232 break;
233 case CTLBACKQ:
234 case CTLBACKQ|CTLQUOTE:
235 putc('$', fp);
236 putc('(', fp);
237 shtree(bqlist->n, -1, NULL, fp);
238 putc(')', fp);
239 break;
240 default:
241 putc(*p, fp);
242 break;
243 }
244 }
245 }
246
247
248 static void
249 indent(int amount, char *pfx, FILE *fp)
250 {
251 int i;
252
253 for (i = 0 ; i < amount ; i++) {
254 if (pfx && i == amount - 1)
255 fputs(pfx, fp);
256 putc('\t', fp);
257 }
258 }
259 #endif
260
261
262
263 /*
264 * Debugging stuff.
265 */
266
267
268 FILE *tracefile;
269
270
271 #ifdef DEBUG
272 void
273 trputc(int c)
274 {
275 if (debug != 1)
276 return;
277 putc(c, tracefile);
278 }
279 #endif
280
281 void
282 trace(const char *fmt, ...)
283 {
284 #ifdef DEBUG
285 va_list va;
286
287 if (debug != 1)
288 return;
289 va_start(va, fmt);
290 (void) vfprintf(tracefile, fmt, va);
291 va_end(va);
292 #endif
293 }
294
295 void
296 tracev(const char *fmt, va_list va)
297 {
298 #ifdef DEBUG
299 if (debug != 1)
300 return;
301 (void) vfprintf(tracefile, fmt, va);
302 #endif
303 }
304
305
306 #ifdef DEBUG
307 void
308 trputs(const char *s)
309 {
310 if (debug != 1)
311 return;
312 fputs(s, tracefile);
313 }
314
315
316 static void
317 trstring(char *s)
318 {
319 char *p;
320 char c;
321
322 if (debug != 1)
323 return;
324 putc('"', tracefile);
325 for (p = s ; *p ; p++) {
326 switch (*p) {
327 case '\n': c = 'n'; goto backslash;
328 case '\t': c = 't'; goto backslash;
329 case '\r': c = 'r'; goto backslash;
330 case '"': c = '"'; goto backslash;
331 case '\\': c = '\\'; goto backslash;
332 case CTLESC: c = 'e'; goto backslash;
333 case CTLVAR: c = 'v'; goto backslash;
334 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
335 case CTLBACKQ: c = 'q'; goto backslash;
336 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
337 backslash: putc('\\', tracefile);
338 putc(c, tracefile);
339 break;
340 default:
341 if (*p >= ' ' && *p <= '~')
342 putc(*p, tracefile);
343 else {
344 putc('\\', tracefile);
345 putc(*p >> 6 & 03, tracefile);
346 putc(*p >> 3 & 07, tracefile);
347 putc(*p & 07, tracefile);
348 }
349 break;
350 }
351 }
352 putc('"', tracefile);
353 }
354 #endif
355
356
357 void
358 trargs(char **ap)
359 {
360 #ifdef DEBUG
361 if (debug != 1)
362 return;
363 while (*ap) {
364 trstring(*ap++);
365 if (*ap)
366 putc(' ', tracefile);
367 else
368 putc('\n', tracefile);
369 }
370 #endif
371 }
372
373
374 #ifdef DEBUG
375 void
376 opentrace(void)
377 {
378 char s[100];
379 #ifdef O_APPEND
380 int flags;
381 #endif
382
383 if (debug != 1) {
384 if (tracefile)
385 fflush(tracefile);
386 /* leave open because libedit might be using it */
387 return;
388 }
389 #ifdef not_this_way
390 {
391 char *p;
392 if ((p = getenv("HOME")) == NULL) {
393 if (geteuid() == 0)
394 p = "/";
395 else
396 p = "/tmp";
397 }
398 scopy(p, s);
399 strcat(s, "/trace");
400 }
401 #else
402 scopy("./trace", s);
403 #endif /* not_this_way */
404 if (tracefile) {
405 if (!freopen(s, "a", tracefile)) {
406 fprintf(stderr, "Can't re-open %s\n", s);
407 debug = 0;
408 return;
409 }
410 } else {
411 if ((tracefile = fopen(s, "a")) == NULL) {
412 fprintf(stderr, "Can't open %s\n", s);
413 debug = 0;
414 return;
415 }
416 }
417 #ifdef O_APPEND
418 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
419 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
420 #endif
421 setlinebuf(tracefile);
422 fputs("\nTracing started.\n", tracefile);
423 }
424 #endif /* DEBUG */
+0
-45
sh/show.h less more
0 /* $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1995
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#)show.h 1.1 (Berkeley) 5/4/95
31 */
32
33 #include <stdarg.h>
34
35 union node;
36 void showtree(union node *);
37 void trace(const char *, ...);
38 void tracev(const char *, va_list);
39 void trargs(char **);
40 #ifdef DEBUG
41 void trputc(int);
42 void trputs(const char *);
43 void opentrace(void);
44 #endif
+0
-102
sh/syntax.c less more
0 /* $NetBSD: syntax.c,v 1.1 2004/01/17 17:38:12 dsl Exp $ */
1
2 #include "shell.h"
3 #include "syntax.h"
4 #include "parser.h"
5 #include <limits.h>
6
7 #if CWORD != 0
8 #error initialisation assumes 'CWORD' is zero
9 #endif
10
11 #define ndx(ch) (ch + 1 - CHAR_MIN)
12 #define set(ch, val) [ndx(ch)] = val,
13 #define set_range(s, e, val) [ndx(s) ... ndx(e)] = val,
14
15 /* syntax table used when not in quotes */
16 const char basesyntax[257] = { CEOF,
17 set_range(CTL_FIRST, CTL_LAST, CCTL)
18 set('\n', CNL)
19 set('\\', CBACK)
20 set('\'', CSQUOTE)
21 set('"', CDQUOTE)
22 set('`', CBQUOTE)
23 set('$', CVAR)
24 set('}', CENDVAR)
25 set('<', CSPCL)
26 set('>', CSPCL)
27 set('(', CSPCL)
28 set(')', CSPCL)
29 set(';', CSPCL)
30 set('&', CSPCL)
31 set('|', CSPCL)
32 set(' ', CSPCL)
33 set('\t', CSPCL)
34 };
35
36 /* syntax table used when in double quotes */
37 const char dqsyntax[257] = { CEOF,
38 set_range(CTL_FIRST, CTL_LAST, CCTL)
39 set('\n', CNL)
40 set('\\', CBACK)
41 set('"', CDQUOTE)
42 set('`', CBQUOTE)
43 set('$', CVAR)
44 set('}', CENDVAR)
45 /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
46 set('!', CCTL)
47 set('*', CCTL)
48 set('?', CCTL)
49 set('[', CCTL)
50 set('=', CCTL)
51 set('~', CCTL)
52 set(':', CCTL)
53 set('/', CCTL)
54 set('-', CCTL)
55 };
56
57 /* syntax table used when in single quotes */
58 const char sqsyntax[257] = { CEOF,
59 set_range(CTL_FIRST, CTL_LAST, CCTL)
60 set('\n', CNL)
61 set('\'', CSQUOTE)
62 /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
63 set('!', CCTL)
64 set('*', CCTL)
65 set('?', CCTL)
66 set('[', CCTL)
67 set('=', CCTL)
68 set('~', CCTL)
69 set(':', CCTL)
70 set('/', CCTL)
71 set('-', CCTL)
72 };
73
74 /* syntax table used when in arithmetic */
75 const char arisyntax[257] = { CEOF,
76 set_range(CTL_FIRST, CTL_LAST, CCTL)
77 set('\n', CNL)
78 set('\\', CBACK)
79 set('`', CBQUOTE)
80 set('\'', CSQUOTE)
81 set('"', CDQUOTE)
82 set('$', CVAR)
83 set('}', CENDVAR)
84 set('(', CLP)
85 set(')', CRP)
86 };
87
88 /* character classification table */
89 const char is_type[257] = { 0,
90 set_range('0', '9', ISDIGIT)
91 set_range('a', 'z', ISLOWER)
92 set_range('A', 'Z', ISUPPER)
93 set('_', ISUNDER)
94 set('#', ISSPECL)
95 set('?', ISSPECL)
96 set('$', ISSPECL)
97 set('!', ISSPECL)
98 set('-', ISSPECL)
99 set('*', ISSPECL)
100 set('@', ISSPECL)
101 };
+0
-83
sh/syntax.h less more
0 /* $NetBSD: syntax.h,v 1.2 2004/01/17 17:38:12 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #include <ctype.h>
36
37 /* Syntax classes */
38 #define CWORD 0 /* character is nothing special */
39 #define CNL 1 /* newline character */
40 #define CBACK 2 /* a backslash character */
41 #define CSQUOTE 3 /* single quote */
42 #define CDQUOTE 4 /* double quote */
43 #define CBQUOTE 5 /* backwards single quote */
44 #define CVAR 6 /* a dollar sign */
45 #define CENDVAR 7 /* a '}' character */
46 #define CLP 8 /* a left paren in arithmetic */
47 #define CRP 9 /* a right paren in arithmetic */
48 #define CEOF 10 /* end of file */
49 #define CCTL 11 /* like CWORD, except it must be escaped */
50 #define CSPCL 12 /* these terminate a word */
51
52 /* Syntax classes for is_ functions */
53 #define ISDIGIT 01 /* a digit */
54 #define ISUPPER 02 /* an upper case letter */
55 #define ISLOWER 04 /* a lower case letter */
56 #define ISUNDER 010 /* an underscore */
57 #define ISSPECL 020 /* the name of a special parameter */
58
59 #define PEOF (CHAR_MIN - 1)
60 #define SYNBASE (-PEOF)
61 /* XXX UPEOF is CHAR_MAX, so is a valid 'char' value... */
62 #define UPEOF ((char)PEOF)
63
64
65 #define BASESYNTAX (basesyntax + SYNBASE)
66 #define DQSYNTAX (dqsyntax + SYNBASE)
67 #define SQSYNTAX (sqsyntax + SYNBASE)
68 #define ARISYNTAX (arisyntax + SYNBASE)
69
70 /* These defines assume that the digits are contiguous */
71 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
72 #define is_alpha(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char)(c)))
73 #define is_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char)(c))))
74 #define is_in_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char)(c))))
75 #define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
76 #define digit_val(c) ((c) - '0')
77
78 extern const char basesyntax[];
79 extern const char dqsyntax[];
80 extern const char sqsyntax[];
81 extern const char arisyntax[];
82 extern const char is_type[];
+0
-112
sh/token.h less more
0 #define TEOF 0
1 #define TNL 1
2 #define TSEMI 2
3 #define TBACKGND 3
4 #define TAND 4
5 #define TOR 5
6 #define TPIPE 6
7 #define TLP 7
8 #define TRP 8
9 #define TENDCASE 9
10 #define TENDBQUOTE 10
11 #define TREDIR 11
12 #define TWORD 12
13 #define TIF 13
14 #define TTHEN 14
15 #define TELSE 15
16 #define TELIF 16
17 #define TFI 17
18 #define TWHILE 18
19 #define TUNTIL 19
20 #define TFOR 20
21 #define TDO 21
22 #define TDONE 22
23 #define TBEGIN 23
24 #define TEND 24
25 #define TCASE 25
26 #define TESAC 26
27 #define TNOT 27
28
29 /* Array indicating which tokens mark the end of a list */
30 const char tokendlist[] = {
31 1,
32 0,
33 0,
34 0,
35 0,
36 0,
37 0,
38 0,
39 1,
40 1,
41 1,
42 0,
43 0,
44 0,
45 1,
46 1,
47 1,
48 1,
49 0,
50 0,
51 0,
52 1,
53 1,
54 0,
55 1,
56 0,
57 1,
58 0,
59 };
60
61 const char *const tokname[] = {
62 "end of file",
63 "newline",
64 "\";\"",
65 "\"&\"",
66 "\"&&\"",
67 "\"||\"",
68 "\"|\"",
69 "\"(\"",
70 "\")\"",
71 "\";;\"",
72 "\"`\"",
73 "redirection",
74 "word",
75 "\"if\"",
76 "\"then\"",
77 "\"else\"",
78 "\"elif\"",
79 "\"fi\"",
80 "\"while\"",
81 "\"until\"",
82 "\"for\"",
83 "\"do\"",
84 "\"done\"",
85 "\"{\"",
86 "\"}\"",
87 "\"case\"",
88 "\"esac\"",
89 "\"!\"",
90 };
91
92 #define KWDOFFSET 13
93
94 const char *const parsekwd[] = {
95 "if",
96 "then",
97 "else",
98 "elif",
99 "fi",
100 "while",
101 "until",
102 "for",
103 "do",
104 "done",
105 "{",
106 "}",
107 "case",
108 "esac",
109 "!",
110 0
111 };
+0
-470
sh/trap.c less more
0 /* $NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
38 #else
39 __RCSID("$NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <signal.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46
47 #include "shell.h"
48 #include "main.h"
49 #include "nodes.h" /* for other headers */
50 #include "eval.h"
51 #include "jobs.h"
52 #include "show.h"
53 #include "options.h"
54 #include "syntax.h"
55 #include "output.h"
56 #include "memalloc.h"
57 #include "error.h"
58 #include "trap.h"
59 #include "mystring.h"
60 #include "var.h"
61
62 static const char *sys_signame[NSIG] = {
63 "Unused",
64 "HUP", "INT", "QUIT", "ILL",
65 "TRAP", "ABRT", "BUS", "FPE",
66 "KILL", "USR1", "SEGV", "USR2",
67 "PIPE", "ALRM", "TERM",
68 "Unknown",
69 "CHLD",
70 "CONT", "STOP", "TSTP", "TTIN",
71 "TTOU", "URG", "XCPU", "XFSZ",
72 "VTALRM", "PROF", "WINCH", "IO",
73 "PWR", "SYS"
74 };
75
76 /*
77 * Sigmode records the current value of the signal handlers for the various
78 * modes. A value of zero means that the current handler is not known.
79 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
80 */
81
82 #define S_DFL 1 /* default signal handling (SIG_DFL) */
83 #define S_CATCH 2 /* signal is caught */
84 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
85 #define S_HARD_IGN 4 /* signal is ignored permenantly */
86 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
87
88
89 char *trap[NSIG+1]; /* trap handler commands */
90 MKINIT char sigmode[NSIG]; /* current value of signal */
91 char gotsig[NSIG]; /* indicates specified signal received */
92 int pendingsigs; /* indicates some signal received */
93
94 static int getsigaction(int, sig_t *);
95
96 /*
97 * return the signal number described by `p' (as a number or a name)
98 * or -1 if it isn't one
99 */
100
101 static int
102 signame_to_signum(const char *p)
103 {
104 int i;
105
106 if (is_number(p))
107 return number(p);
108
109 if (strcasecmp(p, "exit") == 0 )
110 return 0;
111
112 if (strncasecmp(p, "sig", 3) == 0)
113 p += 3;
114
115 for (i = 0; i < NSIG; ++i)
116 if (strcasecmp (p, sys_signame[i]) == 0)
117 return i;
118 return -1;
119 }
120
121 /*
122 * Print a list of valid signal names
123 */
124 static void
125 printsignals(void)
126 {
127 int n;
128
129 out1str("EXIT ");
130
131 for (n = 1; n < NSIG; n++) {
132 out1fmt("%s", sys_signame[n]);
133 if ((n == NSIG/2) || n == (NSIG - 1))
134 out1str("\n");
135 else
136 out1c(' ');
137 }
138 }
139
140 /*
141 * The trap builtin.
142 */
143
144 int
145 trapcmd(int argc, char **argv)
146 {
147 char *action;
148 char **ap;
149 int signo;
150
151 if (argc <= 1) {
152 for (signo = 0 ; signo <= NSIG ; signo++)
153 if (trap[signo] != NULL) {
154 out1fmt("trap -- ");
155 print_quoted(trap[signo]);
156 out1fmt(" %s\n",
157 (signo) ? sys_signame[signo] : "EXIT");
158 }
159 return 0;
160 }
161 ap = argv + 1;
162
163 action = NULL;
164
165 if (strcmp(*ap, "--") == 0)
166 if (*++ap == NULL)
167 return 0;
168
169 if (signame_to_signum(*ap) == -1) {
170 if ((*ap)[0] == '-') {
171 if ((*ap)[1] == '\0')
172 ap++;
173 else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') {
174 printsignals();
175 return 0;
176 }
177 else
178 error("bad option %s\n", *ap);
179 }
180 else
181 action = *ap++;
182 }
183
184 while (*ap) {
185 if (is_number(*ap))
186 signo = number(*ap);
187 else
188 signo = signame_to_signum(*ap);
189
190 if (signo < 0 || signo > NSIG)
191 error("%s: bad trap", *ap);
192
193 INTOFF;
194 if (action)
195 action = savestr(action);
196
197 if (trap[signo])
198 ckfree(trap[signo]);
199
200 trap[signo] = action;
201
202 if (signo != 0)
203 setsignal(signo, 0);
204 INTON;
205 ap++;
206 }
207 return 0;
208 }
209
210
211
212 /*
213 * Clear traps on a fork or vfork.
214 * Takes one arg vfork, to tell it to not be destructive of
215 * the parents variables.
216 */
217
218 void
219 clear_traps(int vforked)
220 {
221 char **tp;
222
223 for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
224 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
225 INTOFF;
226 if (!vforked) {
227 ckfree(*tp);
228 *tp = NULL;
229 }
230 if (tp != &trap[0])
231 setsignal(tp - trap, vforked);
232 INTON;
233 }
234 }
235 }
236
237
238
239 /*
240 * Set the signal handler for the specified signal. The routine figures
241 * out what it should be set to.
242 */
243
244 long
245 setsignal(int signo, int vforked)
246 {
247 int action;
248 sig_t sigact = SIG_DFL;
249 struct sigaction act, oact;
250 char *t, tsig;
251
252 if ((t = trap[signo]) == NULL)
253 action = S_DFL;
254 else if (*t != '\0')
255 action = S_CATCH;
256 else
257 action = S_IGN;
258 if (rootshell && !vforked && action == S_DFL) {
259 switch (signo) {
260 case SIGINT:
261 if (iflag || minusc || sflag == 0)
262 action = S_CATCH;
263 break;
264 case SIGQUIT:
265 #ifdef DEBUG
266 if (debug)
267 break;
268 #endif
269 /* FALLTHROUGH */
270 case SIGTERM:
271 if (iflag)
272 action = S_IGN;
273 break;
274 #if JOBS
275 case SIGTSTP:
276 case SIGTTOU:
277 if (mflag)
278 action = S_IGN;
279 break;
280 #endif
281 }
282 }
283
284 t = &sigmode[signo - 1];
285 tsig = *t;
286 if (tsig == 0) {
287 /*
288 * current setting unknown
289 */
290 if (!getsigaction(signo, &sigact)) {
291 /*
292 * Pretend it worked; maybe we should give a warning
293 * here, but other shells don't. We don't alter
294 * sigmode, so that we retry every time.
295 */
296 return 0;
297 }
298 if (sigact == SIG_IGN) {
299 if (mflag && (signo == SIGTSTP ||
300 signo == SIGTTIN || signo == SIGTTOU)) {
301 tsig = S_IGN; /* don't hard ignore these */
302 } else
303 tsig = S_HARD_IGN;
304 } else {
305 tsig = S_RESET; /* force to be set */
306 }
307 }
308 if (tsig == S_HARD_IGN || tsig == action)
309 return 0;
310 switch (action) {
311 case S_DFL: sigact = SIG_DFL; break;
312 case S_CATCH: sigact = onsig; break;
313 case S_IGN: sigact = SIG_IGN; break;
314 }
315 if (!vforked)
316 *t = action;
317 act.sa_handler = sigact;
318 sigemptyset(&act.sa_mask);
319 act.sa_flags = 0;
320 #ifdef SA_INTERRUPT
321 act.sa_flags |= SA_INTERRUPT;
322 #endif
323 if(sigaction(signo, &act, &oact) < 0)
324 return (long) SIG_ERR;
325 return (long) oact.sa_handler;
326 }
327
328 /*
329 * Return the current setting for sig w/o changing it.
330 */
331 static int
332 getsigaction(int signo, sig_t *sigact)
333 {
334 struct sigaction sa;
335
336 if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
337 return 0;
338 *sigact = (sig_t) sa.sa_handler;
339 return 1;
340 }
341
342 /*
343 * Ignore a signal.
344 */
345
346 void
347 ignoresig(int signo, int vforked)
348 {
349 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN)
350 bsd_signal(signo, SIG_IGN);
351 if (!vforked)
352 sigmode[signo - 1] = S_HARD_IGN;
353 }
354
355
356 #ifdef mkinit
357 INCLUDE <signal.h>
358 INCLUDE "trap.h"
359
360 SHELLPROC {
361 char *sm;
362
363 clear_traps(0);
364 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
365 if (*sm == S_IGN)
366 *sm = S_HARD_IGN;
367 }
368 }
369 #endif
370
371
372
373 /*
374 * Signal handler.
375 */
376
377 void
378 onsig(int signo)
379 {
380 bsd_signal(signo, onsig);
381 if (signo == SIGINT && trap[SIGINT] == NULL) {
382 onint();
383 return;
384 }
385 gotsig[signo - 1] = 1;
386 pendingsigs++;
387 }
388
389
390
391 /*
392 * Called to execute a trap. Perhaps we should avoid entering new trap
393 * handlers while we are executing a trap handler.
394 */
395
396 void
397 dotrap(void)
398 {
399 int i;
400 int savestatus;
401
402 for (;;) {
403 for (i = 1 ; ; i++) {
404 if (gotsig[i - 1])
405 break;
406 if (i >= NSIG)
407 goto done;
408 }
409 gotsig[i - 1] = 0;
410 savestatus=exitstatus;
411 evalstring(trap[i], 0);
412 exitstatus=savestatus;
413 }
414 done:
415 pendingsigs = 0;
416 }
417
418
419
420 /*
421 * Controls whether the shell is interactive or not.
422 */
423
424
425 void
426 setinteractive(int on)
427 {
428 static int is_interactive;
429
430 if (on == is_interactive)
431 return;
432 setsignal(SIGINT, 0);
433 setsignal(SIGQUIT, 0);
434 setsignal(SIGTERM, 0);
435 is_interactive = on;
436 }
437
438
439
440 /*
441 * Called to exit the shell.
442 */
443
444 void
445 exitshell(int status)
446 {
447 struct jmploc loc1, loc2;
448 char *p;
449
450 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
451 if (setjmp(loc1.loc)) {
452 goto l1;
453 }
454 if (setjmp(loc2.loc)) {
455 goto l2;
456 }
457 handler = &loc1;
458 if ((p = trap[0]) != NULL && *p != '\0') {
459 trap[0] = NULL;
460 evalstring(p, 0);
461 }
462 l1: handler = &loc2; /* probably unnecessary */
463 flushall();
464 #if JOBS
465 setjobctl(0);
466 #endif
467 l2: _exit(status);
468 /* NOTREACHED */
469 }
+0
-46
sh/trap.h less more
0 /* $NetBSD: trap.h,v 1.17 2003/08/07 09:05:39 agc Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)trap.h 8.3 (Berkeley) 6/5/95
34 */
35
36 extern int pendingsigs;
37
38 int trapcmd(int, char **);
39 void clear_traps(int);
40 long setsignal(int, int);
41 void ignoresig(int, int);
42 void onsig(int);
43 void dotrap(void);
44 void setinteractive(int);
45 void exitshell(int) __attribute__((__noreturn__));
+0
-825
sh/var.c less more
0 /* $NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
38 #else
39 __RCSID("$NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <paths.h>
46
47 /*
48 * Shell variables.
49 */
50
51 #include "shell.h"
52 #include "output.h"
53 #include "expand.h"
54 #include "nodes.h" /* for other headers */
55 #include "eval.h" /* defines cmdenviron */
56 #include "exec.h"
57 #include "syntax.h"
58 #include "options.h"
59 #include "var.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "mystring.h"
63 #include "parser.h"
64 #include "show.h"
65 #ifndef SMALL
66 #include "myhistedit.h"
67 #endif
68
69 #ifdef SMALL
70 #define VTABSIZE 39
71 #else
72 #define VTABSIZE 517
73 #endif
74
75
76 struct varinit {
77 struct var *var;
78 int flags;
79 const char *text;
80 void (*func)(const char *);
81 };
82
83
84 #if ATTY
85 struct var vatty;
86 #endif
87 #ifdef WITH_HISTORY
88 struct var vhistsize;
89 struct var vterm;
90 #endif
91 struct var vifs;
92 struct var vmpath;
93 struct var vpath;
94 struct var vps1;
95 struct var vps2;
96 struct var vps4;
97 struct var vvers;
98 struct var voptind;
99
100 const struct varinit varinit[] = {
101 #if ATTY
102 { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
103 NULL },
104 #endif
105 #ifdef WITH_HISTORY
106 { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
107 sethistsize },
108 #endif
109 { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n",
110 NULL },
111 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
112 NULL },
113 { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH,
114 changepath },
115 /*
116 * vps1 depends on uid
117 */
118 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
119 NULL },
120 { &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ",
121 NULL },
122 #ifdef WITH_HISTORY
123 { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
124 setterm },
125 #endif
126 { &voptind, VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1",
127 getoptsreset },
128 { NULL, 0, NULL,
129 NULL }
130 };
131
132 struct var *vartab[VTABSIZE];
133
134 STATIC int strequal(const char *, const char *);
135 STATIC struct var *find_var(const char *, struct var ***, int *);
136
137 /*
138 * Initialize the varable symbol tables and import the environment
139 */
140
141 #ifdef mkinit
142 INCLUDE "var.h"
143 MKINIT char **environ;
144 INIT {
145 char **envp;
146
147 initvar();
148 for (envp = environ ; *envp ; envp++) {
149 if (strchr(*envp, '=')) {
150 setvareq(*envp, VEXPORT|VTEXTFIXED);
151 }
152 }
153 }
154 #endif
155
156
157 /*
158 * This routine initializes the builtin variables. It is called when the
159 * shell is initialized and again when a shell procedure is spawned.
160 */
161
162 void
163 initvar(void)
164 {
165 const struct varinit *ip;
166 struct var *vp;
167 struct var **vpp;
168
169 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
170 if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
171 continue;
172 vp->next = *vpp;
173 *vpp = vp;
174 vp->text = strdup(ip->text);
175 vp->flags = ip->flags;
176 vp->func = ip->func;
177 }
178 /*
179 * PS1 depends on uid
180 */
181 if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
182 vps1.next = *vpp;
183 *vpp = &vps1;
184 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
185 vps1.flags = VSTRFIXED|VTEXTFIXED;
186 }
187 }
188
189 /*
190 * Safe version of setvar, returns 1 on success 0 on failure.
191 */
192
193 int
194 setvarsafe(const char *name, const char *val, int flags)
195 {
196 struct jmploc jmploc;
197 struct jmploc *volatile savehandler = handler;
198 int err = 0;
199 #ifdef __GNUC__
200 (void) &err;
201 #endif
202
203 if (setjmp(jmploc.loc))
204 err = 1;
205 else {
206 handler = &jmploc;
207 setvar(name, val, flags);
208 }
209 handler = savehandler;
210 return err;
211 }
212
213 /*
214 * Set the value of a variable. The flags argument is ored with the
215 * flags of the variable. If val is NULL, the variable is unset.
216 */
217
218 void
219 setvar(const char *name, const char *val, int flags)
220 {
221 const char *p;
222 const char *q;
223 char *d;
224 int len;
225 int namelen;
226 char *nameeq;
227 int isbad;
228
229 isbad = 0;
230 p = name;
231 if (! is_name(*p))
232 isbad = 1;
233 p++;
234 for (;;) {
235 if (! is_in_name(*p)) {
236 if (*p == '\0' || *p == '=')
237 break;
238 isbad = 1;
239 }
240 p++;
241 }
242 namelen = p - name;
243 if (isbad)
244 error("%.*s: bad variable name", namelen, name);
245 len = namelen + 2; /* 2 is space for '=' and '\0' */
246 if (val == NULL) {
247 flags |= VUNSET;
248 } else {
249 len += strlen(val);
250 }
251 d = nameeq = ckmalloc(len);
252 q = name;
253 while (--namelen >= 0)
254 *d++ = *q++;
255 *d++ = '=';
256 *d = '\0';
257 if (val)
258 scopy(val, d);
259 setvareq(nameeq, flags);
260 }
261
262
263
264 /*
265 * Same as setvar except that the variable and value are passed in
266 * the first argument as name=value. Since the first argument will
267 * be actually stored in the table, it should not be a string that
268 * will go away.
269 */
270
271 void
272 setvareq(char *s, int flags)
273 {
274 struct var *vp, **vpp;
275 int nlen;
276
277 if (aflag)
278 flags |= VEXPORT;
279 vp = find_var(s, &vpp, &nlen);
280 if (vp != NULL) {
281 if (vp->flags & VREADONLY)
282 error("%.*s: is read only", vp->name_len, s);
283 if (flags & VNOSET)
284 return;
285 INTOFF;
286
287 if (vp->func && (flags & VNOFUNC) == 0)
288 (*vp->func)(s + vp->name_len + 1);
289
290 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
291 ckfree(vp->text);
292
293 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
294 vp->flags |= flags & ~VNOFUNC;
295 vp->text = s;
296
297 INTON;
298 return;
299 }
300 /* not found */
301 if (flags & VNOSET)
302 return;
303 vp = ckmalloc(sizeof (*vp));
304 vp->flags = flags & ~VNOFUNC;
305 vp->text = s;
306 vp->name_len = nlen;
307 vp->next = *vpp;
308 vp->func = NULL;
309 *vpp = vp;
310 }
311
312
313
314 /*
315 * Process a linked list of variable assignments.
316 */
317
318 void
319 listsetvar(struct strlist *list, int flags)
320 {
321 struct strlist *lp;
322
323 INTOFF;
324 for (lp = list ; lp ; lp = lp->next) {
325 setvareq(savestr(lp->text), flags);
326 }
327 INTON;
328 }
329
330 void
331 listmklocal(struct strlist *list, int flags)
332 {
333 struct strlist *lp;
334
335 for (lp = list ; lp ; lp = lp->next)
336 mklocal(lp->text, flags);
337 }
338
339
340 /*
341 * Find the value of a variable. Returns NULL if not set.
342 */
343
344 char *
345 lookupvar(const char *name)
346 {
347 struct var *v;
348
349 v = find_var(name, NULL, NULL);
350 if (v == NULL || v->flags & VUNSET)
351 return NULL;
352 return v->text + v->name_len + 1;
353 }
354
355
356
357 /*
358 * Search the environment of a builtin command. If the second argument
359 * is nonzero, return the value of a variable even if it hasn't been
360 * exported.
361 */
362
363 char *
364 bltinlookup(const char *name, int doall)
365 {
366 struct strlist *sp;
367 struct var *v;
368
369 for (sp = cmdenviron ; sp ; sp = sp->next) {
370 if (strequal(sp->text, name))
371 return strchr(sp->text, '=') + 1;
372 }
373
374 v = find_var(name, NULL, NULL);
375
376 if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
377 return NULL;
378 return v->text + v->name_len + 1;
379 }
380
381
382
383 /*
384 * Generate a list of exported variables. This routine is used to construct
385 * the third argument to execve when executing a program.
386 */
387
388 char **
389 environment(void)
390 {
391 int nenv;
392 struct var **vpp;
393 struct var *vp;
394 char **env;
395 char **ep;
396
397 nenv = 0;
398 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
399 for (vp = *vpp ; vp ; vp = vp->next)
400 if (vp->flags & VEXPORT)
401 nenv++;
402 }
403 ep = env = stalloc((nenv + 1) * sizeof *env);
404 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
405 for (vp = *vpp ; vp ; vp = vp->next)
406 if (vp->flags & VEXPORT)
407 *ep++ = vp->text;
408 }
409 *ep = NULL;
410 return env;
411 }
412
413
414 /*
415 * Called when a shell procedure is invoked to clear out nonexported
416 * variables. It is also necessary to reallocate variables of with
417 * VSTACK set since these are currently allocated on the stack.
418 */
419
420 #ifdef mkinit
421 void shprocvar(void);
422
423 SHELLPROC {
424 shprocvar();
425 }
426 #endif
427
428 void
429 shprocvar(void)
430 {
431 struct var **vpp;
432 struct var *vp, **prev;
433
434 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
435 for (prev = vpp ; (vp = *prev) != NULL ; ) {
436 if ((vp->flags & VEXPORT) == 0) {
437 *prev = vp->next;
438 if ((vp->flags & VTEXTFIXED) == 0)
439 ckfree(vp->text);
440 if ((vp->flags & VSTRFIXED) == 0)
441 ckfree(vp);
442 } else {
443 if (vp->flags & VSTACK) {
444 vp->text = savestr(vp->text);
445 vp->flags &=~ VSTACK;
446 }
447 prev = &vp->next;
448 }
449 }
450 }
451 initvar();
452 }
453
454
455
456 /*
457 * Command to list all variables which are set. Currently this command
458 * is invoked from the set command when the set command is called without
459 * any variables.
460 */
461
462 void
463 print_quoted(const char *p)
464 {
465 const char *q;
466
467 if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
468 out1fmt("%s", p);
469 return;
470 }
471 while (*p) {
472 if (*p == '\'') {
473 out1fmt("\\'");
474 p++;
475 continue;
476 }
477 q = index(p, '\'');
478 if (!q) {
479 out1fmt("'%s'", p );
480 return;
481 }
482 out1fmt("'%.*s'", (int)(q - p), p );
483 p = q;
484 }
485 }
486
487 static int
488 sort_var(const void *v_v1, const void *v_v2)
489 {
490 const struct var * const *v1 = v_v1;
491 const struct var * const *v2 = v_v2;
492
493 /* XXX Will anyone notice we include the '=' of the shorter name? */
494 return strcmp((*v1)->text, (*v2)->text);
495 }
496
497 /*
498 * POSIX requires that 'set' (but not export or readonly) output the
499 * variables in lexicographic order - by the locale's collating order (sigh).
500 * Maybe we could keep them in an ordered balanced binary tree
501 * instead of hashed lists.
502 * For now just roll 'em through qsort for printing...
503 */
504
505 int
506 showvars(const char *name, int flag, int show_value)
507 {
508 struct var **vpp;
509 struct var *vp;
510 const char *p;
511
512 static struct var **list; /* static in case we are interrupted */
513 static int list_len;
514 int count = 0;
515
516 if (!list) {
517 list_len = 32;
518 list = ckmalloc(list_len * sizeof *list);
519 }
520
521 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
522 for (vp = *vpp ; vp ; vp = vp->next) {
523 if (flag && !(vp->flags & flag))
524 continue;
525 if (vp->flags & VUNSET && !(show_value & 2))
526 continue;
527 if (count >= list_len) {
528 list = ckrealloc(list,
529 (list_len << 1) * sizeof *list);
530 list_len <<= 1;
531 }
532 list[count++] = vp;
533 }
534 }
535
536 qsort(list, count, sizeof *list, sort_var);
537
538 for (vpp = list; count--; vpp++) {
539 vp = *vpp;
540 if (name)
541 out1fmt("%s ", name);
542 for (p = vp->text ; *p != '=' ; p++)
543 out1c(*p);
544 if (!(vp->flags & VUNSET) && show_value) {
545 out1fmt("=");
546 print_quoted(++p);
547 }
548 out1c('\n');
549 }
550 return 0;
551 }
552
553
554
555 /*
556 * The export and readonly commands.
557 */
558
559 int
560 exportcmd(int argc, char **argv)
561 {
562 struct var *vp;
563 char *name;
564 const char *p;
565 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
566 int pflag;
567
568 pflag = nextopt("p") == 'p' ? 3 : 0;
569 if (argc <= 1 || pflag) {
570 showvars( pflag ? argv[0] : 0, flag, pflag );
571 return 0;
572 }
573
574 while ((name = *argptr++) != NULL) {
575 if ((p = strchr(name, '=')) != NULL) {
576 p++;
577 } else {
578 vp = find_var(name, NULL, NULL);
579 if (vp != NULL) {
580 vp->flags |= flag;
581 continue;
582 }
583 }
584 setvar(name, p, flag);
585 }
586 return 0;
587 }
588
589
590 /*
591 * The "local" command.
592 */
593
594 int
595 localcmd(int argc, char **argv)
596 {
597 char *name;
598
599 if (! in_function())
600 error("Not in a function");
601 while ((name = *argptr++) != NULL) {
602 mklocal(name, 0);
603 }
604 return 0;
605 }
606
607
608 /*
609 * Make a variable a local variable. When a variable is made local, it's
610 * value and flags are saved in a localvar structure. The saved values
611 * will be restored when the shell function returns. We handle the name
612 * "-" as a special case.
613 */
614
615 void
616 mklocal(const char *name, int flags)
617 {
618 struct localvar *lvp;
619 struct var **vpp;
620 struct var *vp;
621
622 INTOFF;
623 lvp = ckmalloc(sizeof (struct localvar));
624 if (name[0] == '-' && name[1] == '\0') {
625 char *p;
626 p = ckmalloc(sizeof_optlist);
627 lvp->text = memcpy(p, optlist, sizeof_optlist);
628 vp = NULL;
629 } else {
630 vp = find_var(name, &vpp, NULL);
631 if (vp == NULL) {
632 if (strchr(name, '='))
633 setvareq(savestr(name), VSTRFIXED|flags);
634 else
635 setvar(name, NULL, VSTRFIXED|flags);
636 vp = *vpp; /* the new variable */
637 lvp->text = NULL;
638 lvp->flags = VUNSET;
639 } else {
640 lvp->text = vp->text;
641 lvp->flags = vp->flags;
642 vp->flags |= VSTRFIXED|VTEXTFIXED;
643 if (name[vp->name_len] == '=')
644 setvareq(savestr(name), flags);
645 }
646 }
647 lvp->vp = vp;
648 lvp->next = localvars;
649 localvars = lvp;
650 INTON;
651 }
652
653
654 /*
655 * Called after a function returns.
656 */
657
658 void
659 poplocalvars(void)
660 {
661 struct localvar *lvp;
662 struct var *vp;
663
664 while ((lvp = localvars) != NULL) {
665 localvars = lvp->next;
666 vp = lvp->vp;
667 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
668 if (vp == NULL) { /* $- saved */
669 memcpy(optlist, lvp->text, sizeof_optlist);
670 ckfree(lvp->text);
671 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
672 (void)unsetvar(vp->text, 0);
673 } else {
674 if (vp->func && (vp->flags & VNOFUNC) == 0)
675 (*vp->func)(lvp->text + vp->name_len + 1);
676 if ((vp->flags & VTEXTFIXED) == 0)
677 ckfree(vp->text);
678 vp->flags = lvp->flags;
679 vp->text = lvp->text;
680 }
681 ckfree(lvp);
682 }
683 }
684
685
686 int
687 setvarcmd(int argc, char **argv)
688 {
689 if (argc <= 2)
690 return unsetcmd(argc, argv);
691 else if (argc == 3)
692 setvar(argv[1], argv[2], 0);
693 else
694 error("List assignment not implemented");
695 return 0;
696 }
697
698
699 /*
700 * The unset builtin command. We unset the function before we unset the
701 * variable to allow a function to be unset when there is a readonly variable
702 * with the same name.
703 */
704
705 int
706 unsetcmd(int argc, char **argv)
707 {
708 char **ap;
709 int i;
710 int flg_func = 0;
711 int flg_var = 0;
712 int ret = 0;
713
714 while ((i = nextopt("evf")) != '\0') {
715 if (i == 'f')
716 flg_func = 1;
717 else
718 flg_var = i;
719 }
720 if (flg_func == 0 && flg_var == 0)
721 flg_var = 1;
722
723 for (ap = argptr; *ap ; ap++) {
724 if (flg_func)
725 ret |= unsetfunc(*ap);
726 if (flg_var)
727 ret |= unsetvar(*ap, flg_var == 'e');
728 }
729 return ret;
730 }
731
732
733 /*
734 * Unset the specified variable.
735 */
736
737 int
738 unsetvar(const char *s, int unexport)
739 {
740 struct var **vpp;
741 struct var *vp;
742
743 vp = find_var(s, &vpp, NULL);
744 if (vp == NULL)
745 return 1;
746
747 if (vp->flags & VREADONLY)
748 return (1);
749
750 INTOFF;
751 if (unexport) {
752 vp->flags &= ~VEXPORT;
753 } else {
754 if (vp->text[vp->name_len + 1] != '\0')
755 setvar(s, nullstr, 0);
756 vp->flags &= ~VEXPORT;
757 vp->flags |= VUNSET;
758 if ((vp->flags & VSTRFIXED) == 0) {
759 if ((vp->flags & VTEXTFIXED) == 0)
760 ckfree(vp->text);
761 *vpp = vp->next;
762 ckfree(vp);
763 }
764 }
765 INTON;
766 return 0;
767 }
768
769
770 /*
771 * Returns true if the two strings specify the same varable. The first
772 * variable name is terminated by '='; the second may be terminated by
773 * either '=' or '\0'.
774 */
775
776 STATIC int
777 strequal(const char *p, const char *q)
778 {
779 while (*p == *q++) {
780 if (*p++ == '=')
781 return 1;
782 }
783 if (*p == '=' && *(q - 1) == '\0')
784 return 1;
785 return 0;
786 }
787
788 /*
789 * Search for a variable.
790 * 'name' may be terminated by '=' or a NUL.
791 * vppp is set to the pointer to vp, or the list head if vp isn't found
792 * lenp is set to the number of charactets in 'name'
793 */
794
795 STATIC struct var *
796 find_var(const char *name, struct var ***vppp, int *lenp)
797 {
798 unsigned int hashval;
799 int len;
800 struct var *vp, **vpp;
801 const char *p = name;
802
803 hashval = 0;
804 while (*p && *p != '=')
805 hashval = 2 * hashval + (unsigned char)*p++;
806 len = p - name;
807
808 if (lenp)
809 *lenp = len;
810 vpp = &vartab[hashval % VTABSIZE];
811 if (vppp)
812 *vppp = vpp;
813
814 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
815 if (vp->name_len != len)
816 continue;
817 if (memcmp(vp->text, name, len) != 0)
818 continue;
819 if (vppp)
820 *vppp = vpp;
821 return vp;
822 }
823 return NULL;
824 }
+0
-131
sh/var.h less more
0 /* $NetBSD: var.h,v 1.23 2004/10/02 12:16:53 dsl Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)var.h 8.2 (Berkeley) 5/4/95
34 */
35
36 /*
37 * Shell variables.
38 */
39
40 /* flags */
41 #define VEXPORT 0x01 /* variable is exported */
42 #define VREADONLY 0x02 /* variable cannot be modified */
43 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
44 #define VTEXTFIXED 0x08 /* text is statically allocated */
45 #define VSTACK 0x10 /* text is allocated on the stack */
46 #define VUNSET 0x20 /* the variable is not set */
47 #define VNOFUNC 0x40 /* don't call the callback function */
48 #define VNOSET 0x80 /* do not set variable - just readonly test */
49
50
51 struct var {
52 struct var *next; /* next entry in hash list */
53 int flags; /* flags are defined above */
54 char *text; /* name=value */
55 int name_len; /* length of name */
56 void (*func)(const char *);
57 /* function to be called when */
58 /* the variable gets set/unset */
59 };
60
61
62 struct localvar {
63 struct localvar *next; /* next local variable in list */
64 struct var *vp; /* the variable that was made local */
65 int flags; /* saved flags */
66 char *text; /* saved text */
67 };
68
69
70 struct localvar *localvars;
71
72 #if ATTY
73 extern struct var vatty;
74 #endif
75 extern struct var vifs;
76 extern struct var vmpath;
77 extern struct var vpath;
78 extern struct var vps1;
79 extern struct var vps2;
80 extern struct var vps4;
81 #ifdef WITH_HISTORY
82 extern struct var vterm;
83 extern struct var vtermcap;
84 extern struct var vhistsize;
85 #endif
86
87 /*
88 * The following macros access the values of the above variables.
89 * They have to skip over the name. They return the null string
90 * for unset variables.
91 */
92
93 #define ifsval() (vifs.text + 4)
94 #define ifsset() ((vifs.flags & VUNSET) == 0)
95 #define mpathval() (vmpath.text + 9)
96 #define pathval() (vpath.text + 5)
97 #define ps1val() (vps1.text + 4)
98 #define ps2val() (vps2.text + 4)
99 #define ps4val() (vps4.text + 4)
100 #define optindval() (voptind.text + 7)
101 #ifdef WITH_HISTORY
102 #define histsizeval() (vhistsize.text + 9)
103 #define termval() (vterm.text + 5)
104 #endif
105
106 #if ATTY
107 #define attyset() ((vatty.flags & VUNSET) == 0)
108 #endif
109 #define mpathset() ((vmpath.flags & VUNSET) == 0)
110
111 void initvar(void);
112 void setvar(const char *, const char *, int);
113 void setvareq(char *, int);
114 struct strlist;
115 void listsetvar(struct strlist *, int);
116 char *lookupvar(const char *);
117 char *bltinlookup(const char *, int);
118 char **environment(void);
119 void shprocvar(void);
120 int showvars(const char *, int, int);
121 int exportcmd(int, char **);
122 int localcmd(int, char **);
123 void mklocal(const char *, int);
124 void listmklocal(struct strlist *, int);
125 void poplocalvars(void);
126 int setvarcmd(int, char **);
127 int unsetcmd(int, char **);
128 int unsetvar(const char *, int);
129 int setvarsafe(const char *, const char *, int);
130 void print_quoted(const char *);
+0
-91
toolbox/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1 include $(CLEAR_VARS)
2
3 TOOLS := \
4 ls \
5 mount \
6 cat \
7 ps \
8 kill \
9 ln \
10 insmod \
11 rmmod \
12 lsmod \
13 ifconfig \
14 setconsole \
15 rm \
16 mkdir \
17 rmdir \
18 reboot \
19 getevent \
20 sendevent \
21 date \
22 wipe \
23 sync \
24 umount \
25 start \
26 stop \
27 notify \
28 cmp \
29 dmesg \
30 route \
31 hd \
32 dd \
33 df \
34 getprop \
35 setprop \
36 watchprops \
37 log \
38 sleep \
39 renice \
40 printenv \
41 smd \
42 chmod \
43 chown \
44 mkdosfs \
45 netstat \
46 ioctl \
47 mv \
48 schedtop \
49 top \
50 iftop \
51 id \
52 vmstat
53
54 LOCAL_SRC_FILES:= \
55 toolbox.c \
56 $(patsubst %,%.c,$(TOOLS))
57
58 LOCAL_SHARED_LIBRARIES := libcutils libc
59
60 LOCAL_MODULE:= toolbox
61
62 # Including this will define $(intermediates).
63 #
64 include $(BUILD_EXECUTABLE)
65
66 $(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h
67
68 TOOLS_H := $(intermediates)/tools.h
69 $(TOOLS_H): PRIVATE_TOOLS := $(TOOLS)
70 $(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done
71 $(TOOLS_H): $(LOCAL_PATH)/Android.mk
72 $(TOOLS_H):
73 $(transform-generated-source)
74
75 # Make #!/system/bin/toolbox launchers for each tool.
76 #
77 SYMLINKS := $(addprefix $(TARGET_OUT)/bin/,$(TOOLS))
78 $(SYMLINKS): TOOLBOX_BINARY := $(LOCAL_MODULE)
79 $(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
80 @echo "Symlink: $@ -> $(TOOLBOX_BINARY)"
81 @mkdir -p $(dir $@)
82 @rm -rf $@
83 $(hide) ln -sf $(TOOLBOX_BINARY) $@
84
85 ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
86
87 # We need this so that the installed files could be picked up based on the
88 # local module name
89 ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
90 $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
+0
-0
toolbox/MODULE_LICENSE_BSD less more
(Empty file)
+0
-131
toolbox/NOTICE less more
0
1 Copyright (c) 2008, The Android Open Source Project
2 All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in
11 the documentation and/or other materials provided with the
12 distribution.
13 * Neither the name of The Android Open Source Project nor the names
14 of its contributors may be used to endorse or promote products
15 derived from this software without specific prior written
16 permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30
31
32 Copyright (c) 1998 Robert Nordier
33 Copyright (c) 1989, 1993
34 The Regents of the University of California. All rights reserved.
35
36 This code is derived from software contributed to Berkeley by
37 Kevin Fall.
38 This code is derived from software contributed to Berkeley by
39 Keith Muller of the University of California, San Diego and Lance
40 Visser of Convex Computer Corporation.
41 This code is derived from software contributed to Berkeley by
42 Mike Muuss.
43
44 Redistribution and use in source and binary forms, with or without
45 modification, are permitted provided that the following conditions
46 are met:
47 1. Redistributions of source code must retain the above copyright
48 notice, this list of conditions and the following disclaimer.
49 2. Redistributions in binary form must reproduce the above copyright
50 notice, this list of conditions and the following disclaimer in the
51 documentation and/or other materials provided with the distribution.
52 3. Neither the name of the University nor the names of its contributors
53 may be used to endorse or promote products derived from this software
54 without specific prior written permission.
55
56 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 SUCH DAMAGE.
67
68
69 Copyright (c) 1989, 1993
70 The Regents of the University of California. All rights reserved.
71
72 This code is derived from software contributed to Berkeley by
73 Kevin Fall.
74
75 Redistribution and use in source and binary forms, with or without
76 modification, are permitted provided that the following conditions
77 are met:
78 1. Redistributions of source code must retain the above copyright
79 notice, this list of conditions and the following disclaimer.
80 2. Redistributions in binary form must reproduce the above copyright
81 notice, this list of conditions and the following disclaimer in the
82 documentation and/or other materials provided with the distribution.
83 3. Neither the name of the University nor the names of its contributors
84 may be used to endorse or promote products derived from this software
85 without specific prior written permission.
86
87 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
88 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
91 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
92 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
93 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
94 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
95 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
96 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
97 SUCH DAMAGE.
98
99
100 Copyright (c) 1991, 1993, 1994
101 The Regents of the University of California. All rights reserved.
102
103 This code is derived from software contributed to Berkeley by
104 Keith Muller of the University of California, San Diego and Lance
105 Visser of Convex Computer Corporation.
106
107 Redistribution and use in source and binary forms, with or without
108 modification, are permitted provided that the following conditions
109 are met:
110 1. Redistributions of source code must retain the above copyright
111 notice, this list of conditions and the following disclaimer.
112 2. Redistributions in binary form must reproduce the above copyright
113 notice, this list of conditions and the following disclaimer in the
114 documentation and/or other materials provided with the distribution.
115 3. Neither the name of the University nor the names of its contributors
116 may be used to endorse or promote products derived from this software
117 without specific prior written permission.
118
119 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
120 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
121 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
122 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
123 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
124 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
125 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
126 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
127 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
128 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
129 SUCH DAMAGE.
130
+0
-190
toolbox/alarm.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <time.h>
6 #include <asm/ioctl.h>
7 //#include <linux/rtc.h>
8 #include <linux/android_alarm.h>
9
10 int alarm_main(int argc, char *argv[])
11 {
12 int c;
13 int res;
14 struct tm tm;
15 time_t t;
16 struct timespec ts;
17 // struct rtc_time rtc_time;
18 char strbuf[26];
19 int afd;
20 int nfd;
21 // struct timeval timeout = { 0, 0 };
22 int wait = 0;
23 fd_set rfds;
24 const char wake_lock_id[] = "alarm_test";
25 int waitalarmmask = 0;
26
27 int useutc = 0;
28 android_alarm_type_t alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
29 android_alarm_type_t alarmtype_high = ANDROID_ALARM_RTC_WAKEUP;
30 android_alarm_type_t alarmtype = 0;
31
32 do {
33 //c = getopt(argc, argv, "uw:");
34 c = getopt(argc, argv, "uwat:");
35 if (c == EOF)
36 break;
37 switch (c) {
38 case 'u':
39 useutc = 1;
40 break;
41 case 't':
42 alarmtype_low = alarmtype_high = strtol(optarg, NULL, 0);
43 break;
44 case 'a':
45 alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
46 alarmtype_high = ANDROID_ALARM_TYPE_COUNT - 1;
47 break;
48 case 'w':
49 //timeout.tv_sec = strtol(optarg, NULL, 0);
50 wait = 1;
51 break;
52 case '?':
53 fprintf(stderr, "%s: invalid option -%c\n",
54 argv[0], optopt);
55 exit(1);
56 }
57 } while (1);
58 if(optind + 2 < argc) {
59 fprintf(stderr,"%s [-uwa] [-t type] [seconds]\n", argv[0]);
60 return 1;
61 }
62
63 afd = open("/dev/alarm", O_RDWR);
64 if(afd < 0) {
65 fprintf(stderr, "Unable to open rtc: %s\n", strerror(errno));
66 return 1;
67 }
68
69 if(optind == argc) {
70 for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
71 waitalarmmask |= 1U << alarmtype;
72 }
73 #if 0
74 res = ioctl(fd, RTC_ALM_READ, &tm);
75 if(res < 0) {
76 fprintf(stderr, "Unable to read alarm: %s\n", strerror(errno));
77 return 1;
78 }
79 #endif
80 #if 0
81 t = timegm(&tm);
82 if(useutc)
83 gmtime_r(&t, &tm);
84 else
85 localtime_r(&t, &tm);
86 #endif
87 #if 0
88 asctime_r(&tm, strbuf);
89 printf("%s", strbuf);
90 #endif
91 }
92 else if(optind + 1 == argc) {
93 #if 0
94 res = ioctl(fd, RTC_RD_TIME, &tm);
95 if(res < 0) {
96 fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
97 return 1;
98 }
99 asctime_r(&tm, strbuf);
100 printf("Now: %s", strbuf);
101 time(&tv.tv_sec);
102 #endif
103 #if 0
104 time(&ts.tv_sec);
105 ts.tv_nsec = 0;
106
107 //strptime(argv[optind], NULL, &tm);
108 //tv.tv_sec = mktime(&tm);
109 //tv.tv_usec = 0;
110 #endif
111 for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
112 waitalarmmask |= 1U << alarmtype;
113 res = ioctl(afd, ANDROID_ALARM_GET_TIME(alarmtype), &ts);
114 if(res < 0) {
115 fprintf(stderr, "Unable to get current time: %s\n", strerror(errno));
116 return 1;
117 }
118 ts.tv_sec += strtol(argv[optind], NULL, 0);
119 //strtotimeval(argv[optind], &tv);
120 gmtime_r(&ts.tv_sec, &tm);
121 printf("time %s -> %ld.%09ld\n", argv[optind], ts.tv_sec, ts.tv_nsec);
122 asctime_r(&tm, strbuf);
123 printf("Requested %s", strbuf);
124
125 res = ioctl(afd, ANDROID_ALARM_SET(alarmtype), &ts);
126 if(res < 0) {
127 fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
128 return 1;
129 }
130 }
131 #if 0
132 res = ioctl(fd, RTC_ALM_SET, &tm);
133 if(res < 0) {
134 fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
135 return 1;
136 }
137 res = ioctl(fd, RTC_AIE_ON);
138 if(res < 0) {
139 fprintf(stderr, "Unable to enable alarm: %s\n", strerror(errno));
140 return 1;
141 }
142 #endif
143 }
144 else {
145 fprintf(stderr,"%s [-u] [date]\n", argv[0]);
146 return 1;
147 }
148
149 if(wait) {
150 while(waitalarmmask) {
151 printf("wait for alarm %x\n", waitalarmmask);
152 res = ioctl(afd, ANDROID_ALARM_WAIT);
153 if(res < 0) {
154 fprintf(stderr, "alarm wait failed\n");
155 }
156 printf("got alarm %x\n", res);
157 waitalarmmask &= ~res;
158 nfd = open("/sys/android_power/acquire_full_wake_lock", O_RDWR);
159 write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
160 close(nfd);
161 //sleep(5);
162 nfd = open("/sys/android_power/release_wake_lock", O_RDWR);
163 write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
164 close(nfd);
165 }
166 printf("done\n");
167 }
168 #if 0
169 FD_ZERO(&rfds);
170 FD_SET(fd, &rfds);
171 res = select(fd + 1, &rfds, NULL, NULL, &timeout);
172 if(res < 0) {
173 fprintf(stderr, "select failed: %s\n", strerror(errno));
174 return 1;
175 }
176 if(res > 0) {
177 int event;
178 read(fd, &event, sizeof(event));
179 fprintf(stderr, "got %x\n", event);
180 }
181 else {
182 fprintf(stderr, "timeout waiting for alarm\n");
183 }
184 #endif
185
186 close(afd);
187
188 return 0;
189 }
+0
-291
toolbox/cat.c less more
0 /* $NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $ */
1
2 /*
3 * Copyright (c) 1989, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Kevin Fall.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/stat.h>
36
37 #include <ctype.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #define CAT_BUFSIZ (4096)
46
47 static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
48 static int rval;
49 static const char *filename;
50
51 static void
52 cook_buf(FILE *fp)
53 {
54 int ch, gobble, line, prev;
55 int stdout_err = 0;
56
57 line = gobble = 0;
58 for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
59 if (prev == '\n') {
60 if (ch == '\n') {
61 if (sflag) {
62 if (!gobble && putchar(ch) == EOF)
63 break;
64 gobble = 1;
65 continue;
66 }
67 if (nflag) {
68 if (!bflag) {
69 if (fprintf(stdout,
70 "%6d\t", ++line) < 0) {
71 stdout_err++;
72 break;
73 }
74 } else if (eflag) {
75 if (fprintf(stdout,
76 "%6s\t", "") < 0) {
77 stdout_err++;
78 break;
79 }
80 }
81 }
82 } else if (nflag) {
83 if (fprintf(stdout, "%6d\t", ++line) < 0) {
84 stdout_err++;
85 break;
86 }
87 }
88 }
89 gobble = 0;
90 if (ch == '\n') {
91 if (eflag)
92 if (putchar('$') == EOF)
93 break;
94 } else if (ch == '\t') {
95 if (tflag) {
96 if (putchar('^') == EOF || putchar('I') == EOF)
97 break;
98 continue;
99 }
100 } else if (vflag) {
101 if (!isascii(ch)) {
102 if (putchar('M') == EOF || putchar('-') == EOF)
103 break;
104 ch = (ch) & 0x7f;
105 }
106 if (iscntrl(ch)) {
107 if (putchar('^') == EOF ||
108 putchar(ch == '\177' ? '?' :
109 ch | 0100) == EOF)
110 break;
111 continue;
112 }
113 }
114 if (putchar(ch) == EOF)
115 break;
116 }
117 if (stdout_err) {
118 perror(filename);
119 rval = 1;
120 }
121 }
122
123 static void
124 cook_args(char **argv)
125 {
126 FILE *fp;
127
128 fp = stdin;
129 filename = "stdin";
130 do {
131 if (*argv) {
132 if (!strcmp(*argv, "-"))
133 fp = stdin;
134 else if ((fp = fopen(*argv,
135 fflag ? "rf" : "r")) == NULL) {
136 perror("fopen");
137 rval = 1;
138 ++argv;
139 continue;
140 }
141 filename = *argv++;
142 }
143 cook_buf(fp);
144 if (fp != stdin)
145 fclose(fp);
146 } while (*argv);
147 }
148
149 static void
150 raw_cat(int rfd)
151 {
152 static char *buf;
153 static char fb_buf[CAT_BUFSIZ];
154 static size_t bsize;
155
156 struct stat sbuf;
157 ssize_t nr, nw, off;
158 int wfd;
159
160 wfd = fileno(stdout);
161 if (buf == NULL) {
162 if (fstat(wfd, &sbuf) == 0) {
163 bsize = sbuf.st_blksize > CAT_BUFSIZ ?
164 sbuf.st_blksize : CAT_BUFSIZ;
165 buf = malloc(bsize);
166 }
167 if (buf == NULL) {
168 buf = fb_buf;
169 bsize = CAT_BUFSIZ;
170 }
171 }
172 while ((nr = read(rfd, buf, bsize)) > 0)
173 for (off = 0; nr; nr -= nw, off += nw)
174 if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
175 {
176 perror("write");
177 exit(EXIT_FAILURE);
178 }
179 if (nr < 0) {
180 fprintf(stderr,"%s: invalid length\n", filename);
181 rval = 1;
182 }
183 }
184
185 static void
186 raw_args(char **argv)
187 {
188 int fd;
189
190 fd = fileno(stdin);
191 filename = "stdin";
192 do {
193 if (*argv) {
194 if (!strcmp(*argv, "-"))
195 fd = fileno(stdin);
196 else if (fflag) {
197 struct stat st;
198 fd = open(*argv, O_RDONLY|O_NONBLOCK, 0);
199 if (fd < 0)
200 goto skip;
201
202 if (fstat(fd, &st) == -1) {
203 close(fd);
204 goto skip;
205 }
206 if (!S_ISREG(st.st_mode)) {
207 close(fd);
208 errno = EINVAL;
209 goto skipnomsg;
210 }
211 }
212 else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
213 skip:
214 perror(*argv);
215 skipnomsg:
216 rval = 1;
217 ++argv;
218 continue;
219 }
220 filename = *argv++;
221 }
222 raw_cat(fd);
223 if (fd != fileno(stdin))
224 close(fd);
225 } while (*argv);
226 }
227
228 int
229 cat_main(int argc, char *argv[])
230 {
231 int ch;
232 struct flock stdout_lock;
233
234 while ((ch = getopt(argc, argv, "beflnstv")) != -1)
235 switch (ch) {
236 case 'b':
237 bflag = nflag = 1; /* -b implies -n */
238 break;
239 case 'e':
240 eflag = vflag = 1; /* -e implies -v */
241 break;
242 case 'f':
243 fflag = 1;
244 break;
245 case 'l':
246 lflag = 1;
247 break;
248 case 'n':
249 nflag = 1;
250 break;
251 case 's':
252 sflag = 1;
253 break;
254 case 't':
255 tflag = vflag = 1; /* -t implies -v */
256 break;
257 case 'v':
258 vflag = 1;
259 break;
260 default:
261 case '?':
262 fprintf(stderr,
263 "usage: cat [-beflnstv] [-] [file ...]\n");
264 exit(EXIT_FAILURE);
265 }
266 argv += optind;
267
268 if (lflag) {
269 stdout_lock.l_len = 0;
270 stdout_lock.l_start = 0;
271 stdout_lock.l_type = F_WRLCK;
272 stdout_lock.l_whence = SEEK_SET;
273 if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
274 {
275 perror("fcntl");
276 exit(EXIT_FAILURE);
277 }
278 }
279
280 if (bflag || eflag || nflag || sflag || tflag || vflag)
281 cook_args(argv);
282 else
283 raw_args(argv);
284 if (fclose(stdout))
285 {
286 perror("fclose");
287 exit(EXIT_FAILURE);
288 }
289 exit(rval);
290 }
+0
-40
toolbox/chmod.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <dirent.h>
5 #include <errno.h>
6
7 #include <unistd.h>
8 #include <time.h>
9
10 int chmod_main(int argc, char **argv)
11 {
12 int i;
13
14 if (argc < 3) {
15 fprintf(stderr, "Usage: chmod <MODE> <FILE>\n");
16 return 10;
17 }
18
19 int mode = 0;
20 const char* s = argv[1];
21 while (*s) {
22 if (*s >= '0' && *s <= '7') {
23 mode = (mode<<3) | (*s-'0');
24 }
25 else {
26 fprintf(stderr, "Bad mode\n");
27 return 10;
28 }
29 s++;
30 }
31 for (i = 2; i < argc; i++) {
32 if (chmod(argv[i], mode) < 0) {
33 fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
34 return 10;
35 }
36 }
37 return 0;
38 }
39
+0
-62
toolbox/chown.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <dirent.h>
5 #include <errno.h>
6 #include <pwd.h>
7 #include <grp.h>
8
9 #include <unistd.h>
10 #include <time.h>
11
12 int chown_main(int argc, char **argv)
13 {
14 int i;
15
16 if (argc < 3) {
17 fprintf(stderr, "Usage: chown <USER>[.GROUP] <FILE1> [FILE2] ...\n");
18 return 10;
19 }
20
21 // Copy argv[1] to 'user' so we can truncate it at the period
22 // if a group id specified.
23 char user[32];
24 char *group = NULL;
25 strncpy(user, argv[1], sizeof(user));
26 if ((group = strchr(user, '.')) != NULL) {
27 *group++ = '\0';
28 }
29
30 // Lookup uid (and gid if specified)
31 struct passwd *pw;
32 struct group *grp = NULL;
33 uid_t uid;
34 gid_t gid = -1; // passing -1 to chown preserves current group
35
36 pw = getpwnam(user);
37 if (pw == NULL) {
38 fprintf(stderr, "No such user '%s'\n", user);
39 return 10;
40 }
41 uid = pw->pw_uid;
42
43 if (group != NULL) {
44 grp = getgrnam(group);
45 if (grp == NULL) {
46 fprintf(stderr, "No such group '%s'\n", group);
47 return 10;
48 }
49 gid = grp->gr_gid;
50 }
51
52 for (i = 2; i < argc; i++) {
53 if (chown(argv[i], uid, gid) < 0) {
54 fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
55 return 10;
56 }
57 }
58
59 return 0;
60 }
61
+0
-90
toolbox/cmp.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6 #include <errno.h>
7
8 int cmp_main(int argc, char *argv[])
9 {
10 int c;
11 int fd1, fd2;
12 char buf1[4096], buf2[4096];
13 int res, res1, res2;
14 int rv = 0;
15 int i;
16 int filepos = 0;
17
18 int show_byte = 0;
19 int show_all = 0;
20 int limit = 0;
21
22 do {
23 c = getopt(argc, argv, "bln:");
24 if (c == EOF)
25 break;
26 switch (c) {
27 case 'b':
28 show_byte = 1;
29 break;
30 case 'l':
31 show_all = 1;
32 break;
33 case 'n':
34 limit = atoi(optarg);
35 break;
36 case '?':
37 fprintf(stderr, "%s: invalid option -%c\n",
38 argv[0], optopt);
39 exit(1);
40 }
41 } while (1);
42
43 if (optind + 2 != argc) {
44 fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]);
45 exit(1);
46 }
47
48 fd1 = open(argv[optind], O_RDONLY);
49 if(fd1 < 0) {
50 fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
51 return 1;
52 }
53
54 fd2 = open(argv[optind+1], O_RDONLY);
55 if(fd2 < 0) {
56 fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno));
57 return 1;
58 }
59
60 while(1) {
61 res1 = read(fd1, &buf1, sizeof(buf1));
62 res2 = read(fd2, &buf2, sizeof(buf2));
63 res = res1 < res2 ? res1 : res2;
64 if(res1 == 0 && res2 == 0) {
65 return rv;
66 }
67 for(i = 0; i < res; i++) {
68 if(buf1[i] != buf2[i]) {
69 printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i);
70 if(show_byte)
71 printf(" 0x%02x 0x%02x", buf1[i], buf2[i]);
72 printf("\n");
73 if(!show_all)
74 return 1;
75 rv = 1;
76 }
77 if(limit) {
78 limit--;
79 if(limit == 0)
80 return rv;
81 }
82 }
83 if(res1 != res2 || res < 0) {
84 printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]);
85 return 1;
86 }
87 filepos += res;
88 }
89 }
+0
-132
toolbox/date.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <time.h>
6 #include <linux/android_alarm.h>
7
8 static void settime(char *s) {
9 struct tm tm;
10 int day = atoi(s);
11 int hour;
12 time_t t;
13 int fd;
14 struct timespec ts;
15
16 while (*s && *s != '.')
17 s++;
18
19 if (*s)
20 s++;
21
22 hour = atoi(s);
23
24 tm.tm_year = day / 10000 - 1900;
25 tm.tm_mon = (day % 10000) / 100 - 1;
26 tm.tm_mday = (day % 100);
27 tm.tm_hour = hour / 10000;
28 tm.tm_min = (hour % 10000) / 100;
29 tm.tm_sec = (hour % 100);
30 tm.tm_isdst = -1;
31
32 t = mktime(&tm);
33
34 fd = open("/dev/alarm", O_RDWR);
35 ts.tv_sec = t;
36 ts.tv_nsec = 0;
37 ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
38 }
39
40 int date_main(int argc, char *argv[])
41 {
42 int c;
43 int res;
44 struct tm tm;
45 time_t t;
46 struct timeval tv;
47 struct timespec ts;
48 char strbuf[260];
49 int fd;
50
51 int useutc = 0;
52
53 tzset();
54
55 do {
56 c = getopt(argc, argv, "us:");
57 if (c == EOF)
58 break;
59 switch (c) {
60 case 'u':
61 useutc = 1;
62 break;
63 case 's':
64 settime(optarg);
65 break;
66 case '?':
67 fprintf(stderr, "%s: invalid option -%c\n",
68 argv[0], optopt);
69 exit(1);
70 }
71 } while (1);
72 if(optind + 2 < argc) {
73 fprintf(stderr,"%s [-u] [date]\n", argv[0]);
74 return 1;
75 }
76
77 int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
78 if(optind == argc || hasfmt) {
79 char buf[2000];
80 time(&t);
81 if (useutc) {
82 gmtime_r(&t, &tm);
83 strftime(strbuf, sizeof(strbuf),
84 (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S GMT %Y"),
85 &tm);
86 } else {
87 localtime_r(&t, &tm);
88 strftime(strbuf, sizeof(strbuf),
89 (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S %Z %Y"),
90 &tm);
91 }
92 printf("%s\n", strbuf);
93 }
94 else if(optind + 1 == argc) {
95 #if 0
96 struct tm *tmptr;
97 tmptr = getdate(argv[optind]);
98 if(tmptr == NULL) {
99 fprintf(stderr,"getdate_r failed\n");
100 return 1;
101 }
102 tm = *tmptr;
103 #if 0
104 if(getdate_r(argv[optind], &tm) < 0) {
105 fprintf(stderr,"getdate_r failed %s\n", strerror(errno));
106 return 1;
107 }
108 #endif
109 #endif
110 //strptime(argv[optind], NULL, &tm);
111 //tv.tv_sec = mktime(&tm);
112 //tv.tv_usec = 0;
113 strtotimeval(argv[optind], &tv);
114 printf("time %s -> %d.%d\n", argv[optind], tv.tv_sec, tv.tv_usec);
115 fd = open("/dev/alarm", O_RDWR);
116 ts.tv_sec = tv.tv_sec;
117 ts.tv_nsec = tv.tv_usec * 1000;
118 res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
119 //res = settimeofday(&tv, NULL);
120 if(res < 0) {
121 fprintf(stderr,"settimeofday failed %s\n", strerror(errno));
122 return 1;
123 }
124 }
125 else {
126 fprintf(stderr,"%s [-s 20070325.123456] [-u] [date]\n", argv[0]);
127 return 1;
128 }
129
130 return 0;
131 }
+0
-1358
toolbox/dd.c less more
0 /* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Keith Muller of the University of California, San Diego and Lance
8 * Visser of Convex Computer Corporation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
38 The Regents of the University of California. All rights reserved.\n");
39 #endif /* not lint */
40
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
44 #else
45 __RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $");
46 #endif
47 #endif /* not lint */
48
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <sys/time.h>
53
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63
64 #include "dd.h"
65
66 #define NO_CONV
67
68 //#include "extern.h"
69 void block(void);
70 void block_close(void);
71 void dd_out(int);
72 void def(void);
73 void def_close(void);
74 void jcl(char **);
75 void pos_in(void);
76 void pos_out(void);
77 void summary(void);
78 void summaryx(int);
79 void terminate(int);
80 void unblock(void);
81 void unblock_close(void);
82 ssize_t bwrite(int, const void *, size_t);
83
84 extern IO in, out;
85 extern STAT st;
86 extern void (*cfunc)(void);
87 extern uint64_t cpy_cnt;
88 extern uint64_t cbsz;
89 extern u_int ddflags;
90 extern u_int files_cnt;
91 extern int progress;
92 extern const u_char *ctab;
93 extern const u_char a2e_32V[], a2e_POSIX[];
94 extern const u_char e2a_32V[], e2a_POSIX[];
95 extern const u_char a2ibm_32V[], a2ibm_POSIX[];
96 extern u_char casetab[];
97
98
99 #define MAX(a, b) ((a) > (b) ? (a) : (b))
100
101 static void dd_close(void);
102 static void dd_in(void);
103 static void getfdtype(IO *);
104 static int redup_clean_fd(int);
105 static void setup(void);
106
107
108 IO in, out; /* input/output state */
109 STAT st; /* statistics */
110 void (*cfunc)(void); /* conversion function */
111 uint64_t cpy_cnt; /* # of blocks to copy */
112 static off_t pending = 0; /* pending seek if sparse */
113 u_int ddflags; /* conversion options */
114 uint64_t cbsz; /* conversion block size */
115 u_int files_cnt = 1; /* # of files to copy */
116 int progress = 0; /* display sign of life */
117 const u_char *ctab; /* conversion table */
118 sigset_t infoset; /* a set blocking SIGINFO */
119
120 int
121 dd_main(int argc, char *argv[])
122 {
123 int ch;
124
125 while ((ch = getopt(argc, argv, "")) != -1) {
126 switch (ch) {
127 default:
128 fprintf(stderr, "usage: dd [operand ...]\n");
129 exit(1);
130 /* NOTREACHED */
131 }
132 }
133 argc -= (optind - 1);
134 argv += (optind - 1);
135
136 jcl(argv);
137 setup();
138
139 // (void)signal(SIGINFO, summaryx);
140 (void)signal(SIGINT, terminate);
141 (void)sigemptyset(&infoset);
142 // (void)sigaddset(&infoset, SIGINFO);
143
144 (void)atexit(summary);
145
146 while (files_cnt--)
147 dd_in();
148
149 dd_close();
150 exit(0);
151 /* NOTREACHED */
152 }
153
154 static void
155 setup(void)
156 {
157
158 if (in.name == NULL) {
159 in.name = "stdin";
160 in.fd = STDIN_FILENO;
161 } else {
162 in.fd = open(in.name, O_RDONLY, 0);
163 if (in.fd < 0) {
164 fprintf(stderr, "%s: cannot open for read: %s\n",
165 in.name, strerror(errno));
166 exit(1);
167 /* NOTREACHED */
168 }
169
170 /* Ensure in.fd is outside the stdio descriptor range */
171 in.fd = redup_clean_fd(in.fd);
172 }
173
174 getfdtype(&in);
175
176 if (files_cnt > 1 && !(in.flags & ISTAPE)) {
177 fprintf(stderr,
178 "files is not supported for non-tape devices\n");
179 exit(1);
180 /* NOTREACHED */
181 }
182
183 if (out.name == NULL) {
184 /* No way to check for read access here. */
185 out.fd = STDOUT_FILENO;
186 out.name = "stdout";
187 } else {
188 #define OFLAGS \
189 (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
190 out.fd = open(out.name, O_RDWR | OFLAGS /*, DEFFILEMODE */);
191 /*
192 * May not have read access, so try again with write only.
193 * Without read we may have a problem if output also does
194 * not support seeks.
195 */
196 if (out.fd < 0) {
197 out.fd = open(out.name, O_WRONLY | OFLAGS /*, DEFFILEMODE */);
198 out.flags |= NOREAD;
199 }
200 if (out.fd < 0) {
201 fprintf(stderr, "%s: cannot open for write: %s\n",
202 out.name, strerror(errno));
203 exit(1);
204 /* NOTREACHED */
205 }
206
207 /* Ensure out.fd is outside the stdio descriptor range */
208 out.fd = redup_clean_fd(out.fd);
209 }
210
211 getfdtype(&out);
212
213 /*
214 * Allocate space for the input and output buffers. If not doing
215 * record oriented I/O, only need a single buffer.
216 */
217 if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
218 if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
219 exit(1);
220 /* NOTREACHED */
221 }
222 out.db = in.db;
223 } else if ((in.db =
224 malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
225 (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
226 exit(1);
227 /* NOTREACHED */
228 }
229 in.dbp = in.db;
230 out.dbp = out.db;
231
232 /* Position the input/output streams. */
233 if (in.offset)
234 pos_in();
235 if (out.offset)
236 pos_out();
237
238 /*
239 * Truncate the output file; ignore errors because it fails on some
240 * kinds of output files, tapes, for example.
241 */
242 if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
243 (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
244
245 /*
246 * If converting case at the same time as another conversion, build a
247 * table that does both at once. If just converting case, use the
248 * built-in tables.
249 */
250 if (ddflags & (C_LCASE|C_UCASE)) {
251 #ifdef NO_CONV
252 /* Should not get here, but just in case... */
253 fprintf(stderr, "case conv and -DNO_CONV\n");
254 exit(1);
255 /* NOTREACHED */
256 #else /* NO_CONV */
257 u_int cnt;
258
259 if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
260 if (ddflags & C_LCASE) {
261 for (cnt = 0; cnt < 0377; ++cnt)
262 casetab[cnt] = tolower(ctab[cnt]);
263 } else {
264 for (cnt = 0; cnt < 0377; ++cnt)
265 casetab[cnt] = toupper(ctab[cnt]);
266 }
267 } else {
268 if (ddflags & C_LCASE) {
269 for (cnt = 0; cnt < 0377; ++cnt)
270 casetab[cnt] = tolower(cnt);
271 } else {
272 for (cnt = 0; cnt < 0377; ++cnt)
273 casetab[cnt] = toupper(cnt);
274 }
275 }
276
277 ctab = casetab;
278 #endif /* NO_CONV */
279 }
280
281 (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
282 }
283
284 static void
285 getfdtype(IO *io)
286 {
287 // struct mtget mt;
288 struct stat sb;
289
290 if (fstat(io->fd, &sb)) {
291 fprintf(stderr, "%s: cannot fstat: %s\n",
292 io->name, strerror(errno));
293 exit(1);
294 /* NOTREACHED */
295 }
296 if (S_ISCHR(sb.st_mode))
297 io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
298 else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
299 io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
300 }
301
302 /*
303 * Move the parameter file descriptor to a descriptor that is outside the
304 * stdio descriptor range, if necessary. This is required to avoid
305 * accidentally outputting completion or error messages into the
306 * output file that were intended for the tty.
307 */
308 static int
309 redup_clean_fd(int fd)
310 {
311 int newfd;
312
313 if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
314 fd != STDERR_FILENO)
315 /* File descriptor is ok, return immediately. */
316 return fd;
317
318 /*
319 * 3 is the first descriptor greater than STD*_FILENO. Any
320 * free descriptor valued 3 or above is acceptable...
321 */
322 newfd = fcntl(fd, F_DUPFD, 3);
323 if (newfd < 0) {
324 fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
325 exit(1);
326 /* NOTREACHED */
327 }
328
329 close(fd);
330
331 return newfd;
332 }
333
334 static void
335 dd_in(void)
336 {
337 int flags;
338 int64_t n;
339
340 for (flags = ddflags;;) {
341 if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
342 return;
343
344 /*
345 * Clear the buffer first if doing "sync" on input.
346 * If doing block operations use spaces. This will
347 * affect not only the C_NOERROR case, but also the
348 * last partial input block which should be padded
349 * with zero and not garbage.
350 */
351 if (flags & C_SYNC) {
352 if (flags & (C_BLOCK|C_UNBLOCK))
353 (void)memset(in.dbp, ' ', in.dbsz);
354 else
355 (void)memset(in.dbp, 0, in.dbsz);
356 }
357
358 n = read(in.fd, in.dbp, in.dbsz);
359 if (n == 0) {
360 in.dbrcnt = 0;
361 return;
362 }
363
364 /* Read error. */
365 if (n < 0) {
366
367 /*
368 * If noerror not specified, die. POSIX requires that
369 * the warning message be followed by an I/O display.
370 */
371 fprintf(stderr, "%s: read error: %s\n",
372 in.name, strerror(errno));
373 if (!(flags & C_NOERROR)) {
374 exit(1);
375 /* NOTREACHED */
376 }
377 summary();
378
379 /*
380 * If it's not a tape drive or a pipe, seek past the
381 * error. If your OS doesn't do the right thing for
382 * raw disks this section should be modified to re-read
383 * in sector size chunks.
384 */
385 if (!(in.flags & (ISPIPE|ISTAPE)) &&
386 lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
387 fprintf(stderr, "%s: seek error: %s\n",
388 in.name, strerror(errno));
389
390 /* If sync not specified, omit block and continue. */
391 if (!(ddflags & C_SYNC))
392 continue;
393
394 /* Read errors count as full blocks. */
395 in.dbcnt += in.dbrcnt = in.dbsz;
396 ++st.in_full;
397
398 /* Handle full input blocks. */
399 } else if (n == in.dbsz) {
400 in.dbcnt += in.dbrcnt = n;
401 ++st.in_full;
402
403 /* Handle partial input blocks. */
404 } else {
405 /* If sync, use the entire block. */
406 if (ddflags & C_SYNC)
407 in.dbcnt += in.dbrcnt = in.dbsz;
408 else
409 in.dbcnt += in.dbrcnt = n;
410 ++st.in_part;
411 }
412
413 /*
414 * POSIX states that if bs is set and no other conversions
415 * than noerror, notrunc or sync are specified, the block
416 * is output without buffering as it is read.
417 */
418 if (ddflags & C_BS) {
419 out.dbcnt = in.dbcnt;
420 dd_out(1);
421 in.dbcnt = 0;
422 continue;
423 }
424
425 /* if (ddflags & C_SWAB) {
426 if ((n = in.dbrcnt) & 1) {
427 ++st.swab;
428 --n;
429 }
430 swab(in.dbp, in.dbp, n);
431 }
432 */
433 in.dbp += in.dbrcnt;
434 (*cfunc)();
435 }
436 }
437
438 /*
439 * Cleanup any remaining I/O and flush output. If necesssary, output file
440 * is truncated.
441 */
442 static void
443 dd_close(void)
444 {
445
446 if (cfunc == def)
447 def_close();
448 else if (cfunc == block)
449 block_close();
450 else if (cfunc == unblock)
451 unblock_close();
452 if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
453 (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
454 out.dbcnt = out.dbsz;
455 }
456 /* If there are pending sparse blocks, make sure
457 * to write out the final block un-sparse
458 */
459 if ((out.dbcnt == 0) && pending) {
460 memset(out.db, 0, out.dbsz);
461 out.dbcnt = out.dbsz;
462 out.dbp = out.db + out.dbcnt;
463 pending -= out.dbsz;
464 }
465 if (out.dbcnt)
466 dd_out(1);
467
468 /*
469 * Reporting nfs write error may be defered until next
470 * write(2) or close(2) system call. So, we need to do an
471 * extra check. If an output is stdout, the file structure
472 * may be shared among with other processes and close(2) just
473 * decreases the reference count.
474 */
475 if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
476 fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
477 exit(1);
478 /* NOTREACHED */
479 }
480 if (close(out.fd) == -1) {
481 fprintf(stderr, "close: %s\n", strerror(errno));
482 exit(1);
483 /* NOTREACHED */
484 }
485 }
486
487 void
488 dd_out(int force)
489 {
490 static int warned;
491 int64_t cnt, n, nw;
492 u_char *outp;
493
494 /*
495 * Write one or more blocks out. The common case is writing a full
496 * output block in a single write; increment the full block stats.
497 * Otherwise, we're into partial block writes. If a partial write,
498 * and it's a character device, just warn. If a tape device, quit.
499 *
500 * The partial writes represent two cases. 1: Where the input block
501 * was less than expected so the output block was less than expected.
502 * 2: Where the input block was the right size but we were forced to
503 * write the block in multiple chunks. The original versions of dd(1)
504 * never wrote a block in more than a single write, so the latter case
505 * never happened.
506 *
507 * One special case is if we're forced to do the write -- in that case
508 * we play games with the buffer size, and it's usually a partial write.
509 */
510 outp = out.db;
511 for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
512 for (cnt = n;; cnt -= nw) {
513
514 if (!force && ddflags & C_SPARSE) {
515 int sparse, i;
516 sparse = 1; /* Is buffer sparse? */
517 for (i = 0; i < cnt; i++)
518 if (outp[i] != 0) {
519 sparse = 0;
520 break;
521 }
522 if (sparse) {
523 pending += cnt;
524 outp += cnt;
525 nw = 0;
526 break;
527 }
528 }
529 if (pending != 0) {
530 if (lseek(out.fd, pending, SEEK_CUR) ==
531 -1) {
532 fprintf(stderr,
533 "%s: seek error creating "
534 "sparse file: %s\n",
535 out.name, strerror(errno));
536 exit(1);
537 }
538 }
539 nw = bwrite(out.fd, outp, cnt);
540 if (nw <= 0) {
541 if (nw == 0) {
542 fprintf(stderr, "%s: end of device\n",
543 out.name);
544 exit(1);
545 /* NOTREACHED */
546 }
547 if (errno != EINTR) {
548 fprintf(stderr, "%s: write error: %s\n",
549 out.name, strerror(errno));
550 /* NOTREACHED */
551 exit(1);
552 }
553 nw = 0;
554 }
555 if (pending) {
556 st.bytes += pending;
557 st.sparse += pending/out.dbsz;
558 st.out_full += pending/out.dbsz;
559 pending = 0;
560 }
561 outp += nw;
562 st.bytes += nw;
563 if (nw == n) {
564 if (n != out.dbsz)
565 ++st.out_part;
566 else
567 ++st.out_full;
568 break;
569 }
570 ++st.out_part;
571 if (nw == cnt)
572 break;
573 if (out.flags & ISCHR && !warned) {
574 warned = 1;
575 fprintf(stderr, "%s: short write on character "
576 "device\n", out.name);
577 }
578 if (out.flags & ISTAPE) {
579 fprintf(stderr,
580 "%s: short write on tape device",
581 out.name);
582 exit(1);
583 /* NOTREACHED */
584 }
585 }
586 if ((out.dbcnt -= n) < out.dbsz)
587 break;
588 }
589
590 /* Reassemble the output block. */
591 if (out.dbcnt)
592 (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
593 out.dbp = out.db + out.dbcnt;
594
595 if (progress)
596 (void)write(STDERR_FILENO, ".", 1);
597 }
598
599 /*
600 * A protected against SIGINFO write
601 */
602 ssize_t
603 bwrite(int fd, const void *buf, size_t len)
604 {
605 sigset_t oset;
606 ssize_t rv;
607 int oerrno;
608
609 (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
610 rv = write(fd, buf, len);
611 oerrno = errno;
612 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
613 errno = oerrno;
614 return (rv);
615 }
616
617 /*
618 * Position input/output data streams before starting the copy. Device type
619 * dependent. Seekable devices use lseek, and the rest position by reading.
620 * Seeking past the end of file can cause null blocks to be written to the
621 * output.
622 */
623 void
624 pos_in(void)
625 {
626 int bcnt, cnt, nr, warned;
627
628 /* If not a pipe or tape device, try to seek on it. */
629 if (!(in.flags & (ISPIPE|ISTAPE))) {
630 if (lseek(in.fd,
631 (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
632 fprintf(stderr, "%s: seek error: %s",
633 in.name, strerror(errno));
634 exit(1);
635 /* NOTREACHED */
636 }
637 return;
638 /* NOTREACHED */
639 }
640
641 /*
642 * Read the data. If a pipe, read until satisfy the number of bytes
643 * being skipped. No differentiation for reading complete and partial
644 * blocks for other devices.
645 */
646 for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
647 if ((nr = read(in.fd, in.db, bcnt)) > 0) {
648 if (in.flags & ISPIPE) {
649 if (!(bcnt -= nr)) {
650 bcnt = in.dbsz;
651 --cnt;
652 }
653 } else
654 --cnt;
655 continue;
656 }
657
658 if (nr == 0) {
659 if (files_cnt > 1) {
660 --files_cnt;
661 continue;
662 }
663 fprintf(stderr, "skip reached end of input\n");
664 exit(1);
665 /* NOTREACHED */
666 }
667
668 /*
669 * Input error -- either EOF with no more files, or I/O error.
670 * If noerror not set die. POSIX requires that the warning
671 * message be followed by an I/O display.
672 */
673 if (ddflags & C_NOERROR) {
674 if (!warned) {
675
676 fprintf(stderr, "%s: error occurred\n",
677 in.name);
678 warned = 1;
679 summary();
680 }
681 continue;
682 }
683 fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
684 exit(1);
685 /* NOTREACHED */
686 }
687 }
688
689 void
690 pos_out(void)
691 {
692 // struct mtop t_op;
693 int cnt, n;
694
695 /*
696 * If not a tape, try seeking on the file. Seeking on a pipe is
697 * going to fail, but don't protect the user -- they shouldn't
698 * have specified the seek operand.
699 */
700 if (!(out.flags & ISTAPE)) {
701 if (lseek(out.fd,
702 (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) {
703 fprintf(stderr, "%s: seek error: %s\n",
704 out.name, strerror(errno));
705 exit(1);
706 /* NOTREACHED */
707 }
708 return;
709 }
710
711 /* If no read access, try using mtio. */
712 if (out.flags & NOREAD) {
713 /* t_op.mt_op = MTFSR;
714 t_op.mt_count = out.offset;
715
716 if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
717 fprintf(stderr, "%s: cannot read", out.name);
718 exit(1);
719 /* NOTREACHED */
720 return;
721 }
722
723 /* Read it. */
724 for (cnt = 0; cnt < out.offset; ++cnt) {
725 if ((n = read(out.fd, out.db, out.dbsz)) > 0)
726 continue;
727
728 if (n < 0) {
729 fprintf(stderr, "%s: cannot position by reading: %s\n",
730 out.name, strerror(errno));
731 exit(1);
732 /* NOTREACHED */
733 }
734
735 /*
736 * If reach EOF, fill with NUL characters; first, back up over
737 * the EOF mark. Note, cnt has not yet been incremented, so
738 * the EOF read does not count as a seek'd block.
739 */
740 /* t_op.mt_op = MTBSR;
741 t_op.mt_count = 1;
742 if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
743 fprintf(stderr, "%s: cannot position\n", out.name);
744 exit(1);
745 /* NOTREACHED */
746 }
747
748 while (cnt++ < out.offset)
749 if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
750 fprintf(stderr, "%s: cannot position "
751 "by writing: %s\n",
752 out.name, strerror(errno));
753 exit(1);
754 /* NOTREACHED */
755 }
756 break;
757 }
758 }
759
760 /*
761 * def --
762 * Copy input to output. Input is buffered until reaches obs, and then
763 * output until less than obs remains. Only a single buffer is used.
764 * Worst case buffer calculation is (ibs + obs - 1).
765 */
766 void
767 def(void)
768 {
769 uint64_t cnt;
770 u_char *inp;
771 const u_char *t;
772
773 if ((t = ctab) != NULL)
774 for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
775 *inp = t[*inp];
776
777 /* Make the output buffer look right. */
778 out.dbp = in.dbp;
779 out.dbcnt = in.dbcnt;
780
781 if (in.dbcnt >= out.dbsz) {
782 /* If the output buffer is full, write it. */
783 dd_out(0);
784
785 /*
786 * Ddout copies the leftover output to the beginning of
787 * the buffer and resets the output buffer. Reset the
788 * input buffer to match it.
789 */
790 in.dbp = out.dbp;
791 in.dbcnt = out.dbcnt;
792 }
793 }
794
795 void
796 def_close(void)
797 {
798
799 /* Just update the count, everything is already in the buffer. */
800 if (in.dbcnt)
801 out.dbcnt = in.dbcnt;
802 }
803
804 #ifdef NO_CONV
805 /* Build a smaller version (i.e. for a miniroot) */
806 /* These can not be called, but just in case... */
807 static const char no_block[] = "unblock and -DNO_CONV?\n";
808 void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
809 void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
810 void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); }
811 void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); }
812 #else /* NO_CONV */
813
814 /*
815 * Copy variable length newline terminated records with a max size cbsz
816 * bytes to output. Records less than cbs are padded with spaces.
817 *
818 * max in buffer: MAX(ibs, cbsz)
819 * max out buffer: obs + cbsz
820 */
821 void
822 block(void)
823 {
824 static int intrunc;
825 int ch = 0; /* pacify gcc */
826 uint64_t cnt, maxlen;
827 u_char *inp, *outp;
828 const u_char *t;
829
830 /*
831 * Record truncation can cross block boundaries. If currently in a
832 * truncation state, keep tossing characters until reach a newline.
833 * Start at the beginning of the buffer, as the input buffer is always
834 * left empty.
835 */
836 if (intrunc) {
837 for (inp = in.db, cnt = in.dbrcnt;
838 cnt && *inp++ != '\n'; --cnt);
839 if (!cnt) {
840 in.dbcnt = 0;
841 in.dbp = in.db;
842 return;
843 }
844 intrunc = 0;
845 /* Adjust the input buffer numbers. */
846 in.dbcnt = cnt - 1;
847 in.dbp = inp + cnt - 1;
848 }
849
850 /*
851 * Copy records (max cbsz size chunks) into the output buffer. The
852 * translation is done as we copy into the output buffer.
853 */
854 for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
855 maxlen = MIN(cbsz, in.dbcnt);
856 if ((t = ctab) != NULL)
857 for (cnt = 0;
858 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
859 *outp++ = t[ch];
860 else
861 for (cnt = 0;
862 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
863 *outp++ = ch;
864 /*
865 * Check for short record without a newline. Reassemble the
866 * input block.
867 */
868 if (ch != '\n' && in.dbcnt < cbsz) {
869 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
870 break;
871 }
872
873 /* Adjust the input buffer numbers. */
874 in.dbcnt -= cnt;
875 if (ch == '\n')
876 --in.dbcnt;
877
878 /* Pad short records with spaces. */
879 if (cnt < cbsz)
880 (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
881 else {
882 /*
883 * If the next character wouldn't have ended the
884 * block, it's a truncation.
885 */
886 if (!in.dbcnt || *inp != '\n')
887 ++st.trunc;
888
889 /* Toss characters to a newline. */
890 for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
891 if (!in.dbcnt)
892 intrunc = 1;
893 else
894 --in.dbcnt;
895 }
896
897 /* Adjust output buffer numbers. */
898 out.dbp += cbsz;
899 if ((out.dbcnt += cbsz) >= out.dbsz)
900 dd_out(0);
901 outp = out.dbp;
902 }
903 in.dbp = in.db + in.dbcnt;
904 }
905
906 void
907 block_close(void)
908 {
909
910 /*
911 * Copy any remaining data into the output buffer and pad to a record.
912 * Don't worry about truncation or translation, the input buffer is
913 * always empty when truncating, and no characters have been added for
914 * translation. The bottom line is that anything left in the input
915 * buffer is a truncated record. Anything left in the output buffer
916 * just wasn't big enough.
917 */
918 if (in.dbcnt) {
919 ++st.trunc;
920 (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
921 (void)memset(out.dbp + in.dbcnt,
922 ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
923 out.dbcnt += cbsz;
924 }
925 }
926
927 /*
928 * Convert fixed length (cbsz) records to variable length. Deletes any
929 * trailing blanks and appends a newline.
930 *
931 * max in buffer: MAX(ibs, cbsz) + cbsz
932 * max out buffer: obs + cbsz
933 */
934 void
935 unblock(void)
936 {
937 uint64_t cnt;
938 u_char *inp;
939 const u_char *t;
940
941 /* Translation and case conversion. */
942 if ((t = ctab) != NULL)
943 for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
944 *inp = t[*inp];
945 /*
946 * Copy records (max cbsz size chunks) into the output buffer. The
947 * translation has to already be done or we might not recognize the
948 * spaces.
949 */
950 for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
951 for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
952 if (t >= inp) {
953 cnt = t - inp + 1;
954 (void)memmove(out.dbp, inp, cnt);
955 out.dbp += cnt;
956 out.dbcnt += cnt;
957 }
958 ++out.dbcnt;
959 *out.dbp++ = '\n';
960 if (out.dbcnt >= out.dbsz)
961 dd_out(0);
962 }
963 if (in.dbcnt)
964 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
965 in.dbp = in.db + in.dbcnt;
966 }
967
968 void
969 unblock_close(void)
970 {
971 uint64_t cnt;
972 u_char *t;
973
974 if (in.dbcnt) {
975 warnx("%s: short input record", in.name);
976 for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
977 if (t >= in.db) {
978 cnt = t - in.db + 1;
979 (void)memmove(out.dbp, in.db, cnt);
980 out.dbp += cnt;
981 out.dbcnt += cnt;
982 }
983 ++out.dbcnt;
984 *out.dbp++ = '\n';
985 }
986 }
987
988 #endif /* NO_CONV */
989
990 #define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
991
992 void
993 summary(void)
994 {
995 char buf[100];
996 int64_t mS;
997 struct timeval tv;
998
999 if (progress)
1000 (void)write(STDERR_FILENO, "\n", 1);
1001
1002 (void)gettimeofday(&tv, NULL);
1003 mS = tv2mS(tv) - tv2mS(st.start);
1004 if (mS == 0)
1005 mS = 1;
1006 /* Use snprintf(3) so that we don't reenter stdio(3). */
1007 (void)snprintf(buf, sizeof(buf),
1008 "%llu+%llu records in\n%llu+%llu records out\n",
1009 (unsigned long long)st.in_full, (unsigned long long)st.in_part,
1010 (unsigned long long)st.out_full, (unsigned long long)st.out_part);
1011 (void)write(STDERR_FILENO, buf, strlen(buf));
1012 if (st.swab) {
1013 (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
1014 (unsigned long long)st.swab,
1015 (st.swab == 1) ? "block" : "blocks");
1016 (void)write(STDERR_FILENO, buf, strlen(buf));
1017 }
1018 if (st.trunc) {
1019 (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
1020 (unsigned long long)st.trunc,
1021 (st.trunc == 1) ? "block" : "blocks");
1022 (void)write(STDERR_FILENO, buf, strlen(buf));
1023 }
1024 if (st.sparse) {
1025 (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
1026 (unsigned long long)st.sparse,
1027 (st.sparse == 1) ? "block" : "blocks");
1028 (void)write(STDERR_FILENO, buf, strlen(buf));
1029 }
1030 (void)snprintf(buf, sizeof(buf),
1031 "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
1032 (unsigned long long) st.bytes,
1033 (long) (mS / 1000),
1034 (int) (mS % 1000),
1035 (unsigned long long) (st.bytes * 1000LL / mS));
1036 (void)write(STDERR_FILENO, buf, strlen(buf));
1037 }
1038
1039 void
1040 terminate(int notused)
1041 {
1042
1043 exit(0);
1044 /* NOTREACHED */
1045 }
1046
1047 static int c_arg(const void *, const void *);
1048 #ifndef NO_CONV
1049 static int c_conv(const void *, const void *);
1050 #endif
1051 static void f_bs(char *);
1052 static void f_cbs(char *);
1053 static void f_conv(char *);
1054 static void f_count(char *);
1055 static void f_files(char *);
1056 static void f_ibs(char *);
1057 static void f_if(char *);
1058 static void f_obs(char *);
1059 static void f_of(char *);
1060 static void f_seek(char *);
1061 static void f_skip(char *);
1062 static void f_progress(char *);
1063
1064 static const struct arg {
1065 const char *name;
1066 void (*f)(char *);
1067 u_int set, noset;
1068 } args[] = {
1069 /* the array needs to be sorted by the first column so
1070 bsearch() can be used to find commands quickly */
1071 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
1072 { "cbs", f_cbs, C_CBS, C_CBS },
1073 { "conv", f_conv, 0, 0 },
1074 { "count", f_count, C_COUNT, C_COUNT },
1075 { "files", f_files, C_FILES, C_FILES },
1076 { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
1077 { "if", f_if, C_IF, C_IF },
1078 { "obs", f_obs, C_OBS, C_BS|C_OBS },
1079 { "of", f_of, C_OF, C_OF },
1080 { "progress", f_progress, 0, 0 },
1081 { "seek", f_seek, C_SEEK, C_SEEK },
1082 { "skip", f_skip, C_SKIP, C_SKIP },
1083 };
1084
1085 /*
1086 * args -- parse JCL syntax of dd.
1087 */
1088 void
1089 jcl(char **argv)
1090 {
1091 struct arg *ap, tmp;
1092 char *oper, *arg;
1093
1094 in.dbsz = out.dbsz = 512;
1095
1096 while ((oper = *++argv) != NULL) {
1097 if ((arg = strchr(oper, '=')) == NULL) {
1098 fprintf(stderr, "unknown operand %s\n", oper);
1099 exit(1);
1100 /* NOTREACHED */
1101 }
1102 *arg++ = '\0';
1103 if (!*arg) {
1104 fprintf(stderr, "no value specified for %s\n", oper);
1105 exit(1);
1106 /* NOTREACHED */
1107 }
1108 tmp.name = oper;
1109 if (!(ap = (struct arg *)bsearch(&tmp, args,
1110 sizeof(args)/sizeof(struct arg), sizeof(struct arg),
1111 c_arg))) {
1112 fprintf(stderr, "unknown operand %s\n", tmp.name);
1113 exit(1);
1114 /* NOTREACHED */
1115 }
1116 if (ddflags & ap->noset) {
1117 fprintf(stderr,
1118 "%s: illegal argument combination or already set\n",
1119 tmp.name);
1120 exit(1);
1121 /* NOTREACHED */
1122 }
1123 ddflags |= ap->set;
1124 ap->f(arg);
1125 }
1126
1127 /* Final sanity checks. */
1128
1129 if (ddflags & C_BS) {
1130 /*
1131 * Bs is turned off by any conversion -- we assume the user
1132 * just wanted to set both the input and output block sizes
1133 * and didn't want the bs semantics, so we don't warn.
1134 */
1135 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
1136 C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
1137 ddflags &= ~C_BS;
1138 ddflags |= C_IBS|C_OBS;
1139 }
1140
1141 /* Bs supersedes ibs and obs. */
1142 if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
1143 fprintf(stderr, "bs supersedes ibs and obs\n");
1144 }
1145
1146 /*
1147 * Ascii/ebcdic and cbs implies block/unblock.
1148 * Block/unblock requires cbs and vice-versa.
1149 */
1150 if (ddflags & (C_BLOCK|C_UNBLOCK)) {
1151 if (!(ddflags & C_CBS)) {
1152 fprintf(stderr, "record operations require cbs\n");
1153 exit(1);
1154 /* NOTREACHED */
1155 }
1156 cfunc = ddflags & C_BLOCK ? block : unblock;
1157 } else if (ddflags & C_CBS) {
1158 if (ddflags & (C_ASCII|C_EBCDIC)) {
1159 if (ddflags & C_ASCII) {
1160 ddflags |= C_UNBLOCK;
1161 cfunc = unblock;
1162 } else {
1163 ddflags |= C_BLOCK;
1164 cfunc = block;
1165 }
1166 } else {
1167 fprintf(stderr,
1168 "cbs meaningless if not doing record operations\n");
1169 exit(1);
1170 /* NOTREACHED */
1171 }
1172 } else
1173 cfunc = def;
1174
1175 /* Read, write and seek calls take off_t as arguments.
1176 *
1177 * The following check is not done because an off_t is a quad
1178 * for current NetBSD implementations.
1179 *
1180 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
1181 * errx(1, "seek offsets cannot be larger than %d", INT_MAX);
1182 */
1183 }
1184
1185 static int
1186 c_arg(const void *a, const void *b)
1187 {
1188
1189 return (strcmp(((const struct arg *)a)->name,
1190 ((const struct arg *)b)->name));
1191 }
1192
1193 static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max)
1194 {
1195 long long result;
1196
1197 if (sscanf(arg, "%lld", &result) == 0)
1198 result = def;
1199 return result;
1200 }
1201
1202 static void
1203 f_bs(char *arg)
1204 {
1205
1206 in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
1207 }
1208
1209 static void
1210 f_cbs(char *arg)
1211 {
1212
1213 cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
1214 }
1215
1216 static void
1217 f_count(char *arg)
1218 {
1219
1220 cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
1221 if (!cpy_cnt)
1222 terminate(0);
1223 }
1224
1225 static void
1226 f_files(char *arg)
1227 {
1228
1229 files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
1230 if (!files_cnt)
1231 terminate(0);
1232 }
1233
1234 static void
1235 f_ibs(char *arg)
1236 {
1237
1238 if (!(ddflags & C_BS))
1239 in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
1240 }
1241
1242 static void
1243 f_if(char *arg)
1244 {
1245
1246 in.name = arg;
1247 }
1248
1249 static void
1250 f_obs(char *arg)
1251 {
1252
1253 if (!(ddflags & C_BS))
1254 out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
1255 }
1256
1257 static void
1258 f_of(char *arg)
1259 {
1260
1261 out.name = arg;
1262 }
1263
1264 static void
1265 f_seek(char *arg)
1266 {
1267
1268 out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
1269 }
1270
1271 static void
1272 f_skip(char *arg)
1273 {
1274
1275 in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
1276 }
1277
1278 static void
1279 f_progress(char *arg)
1280 {
1281
1282 if (*arg != '0')
1283 progress = 1;
1284 }
1285
1286 #ifdef NO_CONV
1287 /* Build a small version (i.e. for a ramdisk root) */
1288 static void
1289 f_conv(char *arg)
1290 {
1291
1292 fprintf(stderr, "conv option disabled\n");
1293 exit(1);
1294 /* NOTREACHED */
1295 }
1296 #else /* NO_CONV */
1297
1298 static const struct conv {
1299 const char *name;
1300 u_int set, noset;
1301 const u_char *ctab;
1302 } clist[] = {
1303 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
1304 { "block", C_BLOCK, C_UNBLOCK, NULL },
1305 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
1306 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
1307 { "lcase", C_LCASE, C_UCASE, NULL },
1308 { "noerror", C_NOERROR, 0, NULL },
1309 { "notrunc", C_NOTRUNC, 0, NULL },
1310 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V },
1311 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V },
1312 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V },
1313 { "osync", C_OSYNC, C_BS, NULL },
1314 { "sparse", C_SPARSE, 0, NULL },
1315 { "swab", C_SWAB, 0, NULL },
1316 { "sync", C_SYNC, 0, NULL },
1317 { "ucase", C_UCASE, C_LCASE, NULL },
1318 { "unblock", C_UNBLOCK, C_BLOCK, NULL },
1319 /* If you add items to this table, be sure to add the
1320 * conversions to the C_BS check in the jcl routine above.
1321 */
1322 };
1323
1324 static void
1325 f_conv(char *arg)
1326 {
1327 struct conv *cp, tmp;
1328
1329 while (arg != NULL) {
1330 tmp.name = strsep(&arg, ",");
1331 if (!(cp = (struct conv *)bsearch(&tmp, clist,
1332 sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
1333 c_conv))) {
1334 errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
1335 /* NOTREACHED */
1336 }
1337 if (ddflags & cp->noset) {
1338 errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name);
1339 /* NOTREACHED */
1340 }
1341 ddflags |= cp->set;
1342 if (cp->ctab)
1343 ctab = cp->ctab;
1344 }
1345 }
1346
1347 static int
1348 c_conv(const void *a, const void *b)
1349 {
1350
1351 return (strcmp(((const struct conv *)a)->name,
1352 ((const struct conv *)b)->name));
1353 }
1354
1355 #endif /* NO_CONV */
1356
1357
+0
-91
toolbox/dd.h less more
0 /* $NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 dbj Exp $ */
1
2 /*-
3 * Copyright (c) 1991, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Keith Muller of the University of California, San Diego and Lance
8 * Visser of Convex Computer Corporation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)dd.h 8.3 (Berkeley) 4/2/94
35 */
36
37 /* Input/output stream state. */
38 typedef struct {
39 u_char *db; /* buffer address */
40 u_char *dbp; /* current buffer I/O address */
41 uint64_t dbcnt; /* current buffer byte count */
42 int64_t dbrcnt; /* last read byte count */
43 uint64_t dbsz; /* buffer size */
44
45 #define ISCHR 0x01 /* character device (warn on short) */
46 #define ISPIPE 0x02 /* pipe (not truncatable) */
47 #define ISTAPE 0x04 /* tape (not seekable) */
48 #define NOREAD 0x08 /* not readable */
49 u_int flags;
50
51 const char *name; /* name */
52 int fd; /* file descriptor */
53 uint64_t offset; /* # of blocks to skip */
54 } IO;
55
56 typedef struct {
57 uint64_t in_full; /* # of full input blocks */
58 uint64_t in_part; /* # of partial input blocks */
59 uint64_t out_full; /* # of full output blocks */
60 uint64_t out_part; /* # of partial output blocks */
61 uint64_t trunc; /* # of truncated records */
62 uint64_t swab; /* # of odd-length swab blocks */
63 uint64_t sparse; /* # of sparse output blocks */
64 uint64_t bytes; /* # of bytes written */
65 struct timeval start; /* start time of dd */
66 } STAT;
67
68 /* Flags (in ddflags). */
69 #define C_ASCII 0x00001
70 #define C_BLOCK 0x00002
71 #define C_BS 0x00004
72 #define C_CBS 0x00008
73 #define C_COUNT 0x00010
74 #define C_EBCDIC 0x00020
75 #define C_FILES 0x00040
76 #define C_IBS 0x00080
77 #define C_IF 0x00100
78 #define C_LCASE 0x00200
79 #define C_NOERROR 0x00400
80 #define C_NOTRUNC 0x00800
81 #define C_OBS 0x01000
82 #define C_OF 0x02000
83 #define C_SEEK 0x04000
84 #define C_SKIP 0x08000
85 #define C_SWAB 0x10000
86 #define C_SYNC 0x20000
87 #define C_UCASE 0x40000
88 #define C_UNBLOCK 0x80000
89 #define C_OSYNC 0x100000
90 #define C_SPARSE 0x200000
+0
-63
toolbox/df.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <sys/statfs.h>
5
6 static int ok = EXIT_SUCCESS;
7
8 static void df(char *s, int always) {
9 struct statfs st;
10
11 if (statfs(s, &st) < 0) {
12 fprintf(stderr, "%s: %s\n", s, strerror(errno));
13 ok = EXIT_FAILURE;
14 } else {
15 if (st.f_blocks == 0 && !always)
16 return;
17
18 printf("%s: %lldK total, %lldK used, %lldK available (block size %d)\n",
19 s,
20 ((long long)st.f_blocks * (long long)st.f_bsize) / 1024,
21 ((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize) / 1024,
22 ((long long)st.f_bfree * (long long)st.f_bsize) / 1024,
23 (int) st.f_bsize);
24 }
25 }
26
27 int df_main(int argc, char *argv[]) {
28 if (argc == 1) {
29 char s[2000];
30 FILE *f = fopen("/proc/mounts", "r");
31
32 while (fgets(s, 2000, f)) {
33 char *c, *e = s;
34
35 for (c = s; *c; c++) {
36 if (*c == ' ') {
37 e = c + 1;
38 break;
39 }
40 }
41
42 for (c = e; *c; c++) {
43 if (*c == ' ') {
44 *c = '\0';
45 break;
46 }
47 }
48
49 df(e, 0);
50 }
51
52 fclose(f);
53 } else {
54 int i;
55
56 for (i = 1; i < argc; i++) {
57 df(argv[i], 1);
58 }
59 }
60
61 exit(ok);
62 }
+0
-43
toolbox/dmesg.c less more
0 #include <stdlib.h>
1 #include <unistd.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <sys/klog.h>
5 #include <string.h>
6
7 #define KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT from our kernel */
8 #define KLOG_BUF_LEN (1 << KLOG_BUF_SHIFT)
9
10 int dmesg_main(int argc, char **argv)
11 {
12 char buffer[KLOG_BUF_LEN + 1];
13 char *p = buffer;
14 ssize_t ret;
15 int n, op;
16
17 if((argc == 2) && (!strcmp(argv[1],"-c"))) {
18 op = KLOG_READ_CLEAR;
19 } else {
20 op = KLOG_READ_ALL;
21 }
22
23 n = klogctl(op, buffer, KLOG_BUF_LEN);
24 if (n < 0) {
25 perror("klogctl");
26 return EXIT_FAILURE;
27 }
28 buffer[n] = '\0';
29
30 while((ret = write(STDOUT_FILENO, p, n))) {
31 if (ret == -1) {
32 if (errno == EINTR)
33 continue;
34 perror("write");
35 return EXIT_FAILURE;
36 }
37 p += ret;
38 n -= ret;
39 }
40
41 return 0;
42 }
+0
-16
toolbox/exists.c less more
0 #include <sys/types.h>
1 #include <sys/stat.h>
2 #include <unistd.h>
3
4 int exists_main(int argc, char *argv[])
5 {
6 struct stat s;
7
8 if(argc < 2) return 1;
9
10 if(stat(argv[1], &s)) {
11 return 1;
12 } else {
13 return 0;
14 }
15 }
+0
-427
toolbox/getevent.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <dirent.h>
5 #include <fcntl.h>
6 #include <sys/ioctl.h>
7 #include <sys/inotify.h>
8 #include <sys/limits.h>
9 #include <sys/poll.h>
10 #include <linux/input.h> // this does not compile
11 #include <errno.h>
12
13 static struct pollfd *ufds;
14 static char **device_names;
15 static int nfds;
16
17 enum {
18 PRINT_DEVICE_ERRORS = 1U << 0,
19 PRINT_DEVICE = 1U << 1,
20 PRINT_DEVICE_NAME = 1U << 2,
21 PRINT_DEVICE_INFO = 1U << 3,
22 PRINT_VERSION = 1U << 4,
23 PRINT_POSSIBLE_EVENTS = 1U << 5,
24 };
25
26 static int print_possible_events(int fd)
27 {
28 uint8_t *bits = NULL;
29 ssize_t bits_size = 0;
30 int i, j, k;
31 int res, res2;
32
33 printf(" events:\n");
34 for(i = 0; i <= EV_MAX; i++) {
35 int count = 0;
36 while(1) {
37 res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
38 if(res < bits_size)
39 break;
40 bits_size = res + 16;
41 bits = realloc(bits, bits_size * 2);
42 if(bits == NULL) {
43 fprintf(stderr, "failed to allocate buffer of size %d\n", bits_size);
44 return 1;
45 }
46 }
47 switch(i) {
48 case EV_KEY:
49 res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
50 break;
51 case EV_LED:
52 res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
53 break;
54 case EV_SND:
55 res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
56 break;
57 case EV_SW:
58 res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
59 break;
60 default:
61 res2 = 0;
62 }
63 for(j = 0; j < res; j++) {
64 for(k = 0; k < 8; k++)
65 if(bits[j] & 1 << k) {
66 char down;
67 if(j < res2 && (bits[j + bits_size] & 1 << k))
68 down = '*';
69 else
70 down = ' ';
71 if(count == 0)
72 printf(" type %04x:", i);
73 else if((count & 0x7) == 0 || i == EV_ABS)
74 printf("\n ");
75 printf(" %04x%c", j * 8 + k, down);
76 if(i == EV_ABS) {
77 struct input_absinfo abs;
78 if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
79 printf(" value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat);
80 }
81 }
82 count++;
83 }
84 }
85 if(count)
86 printf("\n");
87 }
88 free(bits);
89 return 0;
90 }
91
92 static int open_device(const char *device, int print_flags)
93 {
94 int version;
95 int fd;
96 struct pollfd *new_ufds;
97 char **new_device_names;
98 char name[80];
99 char location[80];
100 char idstr[80];
101 struct input_id id;
102
103 fd = open(device, O_RDWR);
104 if(fd < 0) {
105 if(print_flags & PRINT_DEVICE_ERRORS)
106 fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
107 return -1;
108 }
109
110 if(ioctl(fd, EVIOCGVERSION, &version)) {
111 if(print_flags & PRINT_DEVICE_ERRORS)
112 fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
113 return -1;
114 }
115 if(ioctl(fd, EVIOCGID, &id)) {
116 if(print_flags & PRINT_DEVICE_ERRORS)
117 fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
118 return -1;
119 }
120 name[sizeof(name) - 1] = '\0';
121 location[sizeof(location) - 1] = '\0';
122 idstr[sizeof(idstr) - 1] = '\0';
123 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
124 //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
125 name[0] = '\0';
126 }
127 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
128 //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
129 location[0] = '\0';
130 }
131 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
132 //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
133 idstr[0] = '\0';
134 }
135
136 new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
137 if(new_ufds == NULL) {
138 fprintf(stderr, "out of memory\n");
139 return -1;
140 }
141 ufds = new_ufds;
142 new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
143 if(new_device_names == NULL) {
144 fprintf(stderr, "out of memory\n");
145 return -1;
146 }
147 device_names = new_device_names;
148
149 if(print_flags & PRINT_DEVICE)
150 printf("add device %d: %s\n", nfds, device);
151 if(print_flags & PRINT_DEVICE_INFO)
152 printf(" bus: %04x\n"
153 " vendor %04x\n"
154 " product %04x\n"
155 " version %04x\n",
156 id.bustype, id.vendor, id.product, id.version);
157 if(print_flags & PRINT_DEVICE_NAME)
158 printf(" name: \"%s\"\n", name);
159 if(print_flags & PRINT_DEVICE_INFO)
160 printf(" location: \"%s\"\n"
161 " id: \"%s\"\n", location, idstr);
162 if(print_flags & PRINT_VERSION)
163 printf(" version: %d.%d.%d\n",
164 version >> 16, (version >> 8) & 0xff, version & 0xff);
165
166 if(print_flags & PRINT_POSSIBLE_EVENTS) {
167 print_possible_events(fd);
168 }
169
170 ufds[nfds].fd = fd;
171 ufds[nfds].events = POLLIN;
172 device_names[nfds] = strdup(device);
173 nfds++;
174
175 return 0;
176 }
177
178 int close_device(const char *device, int print_flags)
179 {
180 int i;
181 for(i = 1; i < nfds; i++) {
182 if(strcmp(device_names[i], device) == 0) {
183 int count = nfds - i - 1;
184 if(print_flags & PRINT_DEVICE)
185 printf("remove device %d: %s\n", i, device);
186 free(device_names[i]);
187 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
188 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
189 nfds--;
190 return 0;
191 }
192 }
193 if(print_flags & PRINT_DEVICE_ERRORS)
194 fprintf(stderr, "remote device: %s not found\n", device);
195 return -1;
196 }
197
198 static int read_notify(const char *dirname, int nfd, int print_flags)
199 {
200 int res;
201 char devname[PATH_MAX];
202 char *filename;
203 char event_buf[512];
204 int event_size;
205 int event_pos = 0;
206 struct inotify_event *event;
207
208 res = read(nfd, event_buf, sizeof(event_buf));
209 if(res < (int)sizeof(*event)) {
210 if(errno == EINTR)
211 return 0;
212 fprintf(stderr, "could not get event, %s\n", strerror(errno));
213 return 1;
214 }
215 //printf("got %d bytes of event information\n", res);
216
217 strcpy(devname, dirname);
218 filename = devname + strlen(devname);
219 *filename++ = '/';
220
221 while(res >= (int)sizeof(*event)) {
222 event = (struct inotify_event *)(event_buf + event_pos);
223 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
224 if(event->len) {
225 strcpy(filename, event->name);
226 if(event->mask & IN_CREATE) {
227 open_device(devname, print_flags);
228 }
229 else {
230 close_device(devname, print_flags);
231 }
232 }
233 event_size = sizeof(*event) + event->len;
234 res -= event_size;
235 event_pos += event_size;
236 }
237 return 0;
238 }
239
240 static int scan_dir(const char *dirname, int print_flags)
241 {
242 char devname[PATH_MAX];
243 char *filename;
244 DIR *dir;
245 struct dirent *de;
246 dir = opendir(dirname);
247 if(dir == NULL)
248 return -1;
249 strcpy(devname, dirname);
250 filename = devname + strlen(devname);
251 *filename++ = '/';
252 while((de = readdir(dir))) {
253 if(de->d_name[0] == '.' &&
254 (de->d_name[1] == '\0' ||
255 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
256 continue;
257 strcpy(filename, de->d_name);
258 open_device(devname, print_flags);
259 }
260 closedir(dir);
261 return 0;
262 }
263
264 static void usage(int argc, char *argv[])
265 {
266 fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-q] [-c count] [-r] [device]\n", argv[0]);
267 }
268
269 int getevent_main(int argc, char *argv[])
270 {
271 int c;
272 int i;
273 int res;
274 int pollres;
275 int get_time = 0;
276 int print_device = 0;
277 char *newline = "\n";
278 uint16_t get_switch = 0;
279 struct input_event event;
280 int version;
281 int print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
282 int print_flags_set = 0;
283 int dont_block = -1;
284 int event_count = 0;
285 int sync_rate = 0;
286 int64_t last_sync_time = 0;
287 const char *device = NULL;
288 const char *device_path = "/dev/input";
289
290 opterr = 0;
291 do {
292 c = getopt(argc, argv, "tns:Sv::qc:rh");
293 if (c == EOF)
294 break;
295 switch (c) {
296 case 't':
297 get_time = 1;
298 break;
299 case 'n':
300 newline = "";
301 break;
302 case 's':
303 get_switch = strtoul(optarg, NULL, 0);
304 if(dont_block == -1)
305 dont_block = 1;
306 break;
307 case 'S':
308 get_switch = ~0;
309 if(dont_block == -1)
310 dont_block = 1;
311 break;
312 case 'v':
313 if(optarg)
314 print_flags = strtoul(optarg, NULL, 0);
315 else
316 print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
317 print_flags_set = 1;
318 break;
319 case 'q':
320 print_flags = 0;
321 print_flags_set = 1;
322 break;
323 case 'c':
324 event_count = atoi(optarg);
325 dont_block = 0;
326 break;
327 case 'r':
328 sync_rate = 1;
329 break;
330 case '?':
331 fprintf(stderr, "%s: invalid option -%c\n",
332 argv[0], optopt);
333 case 'h':
334 usage(argc, argv);
335 exit(1);
336 }
337 } while (1);
338 if(dont_block == -1)
339 dont_block = 0;
340
341 if (optind + 1 == argc) {
342 device = argv[optind];
343 optind++;
344 }
345 if (optind != argc) {
346 usage(argc, argv);
347 exit(1);
348 }
349 nfds = 1;
350 ufds = calloc(1, sizeof(ufds[0]));
351 ufds[0].fd = inotify_init();
352 ufds[0].events = POLLIN;
353 if(device) {
354 if(!print_flags_set)
355 print_flags = PRINT_DEVICE_ERRORS;
356 res = open_device(device, print_flags);
357 if(res < 0) {
358 return 1;
359 }
360 }
361 else {
362 print_device = 1;
363 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
364 if(res < 0) {
365 fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
366 return 1;
367 }
368 res = scan_dir(device_path, print_flags);
369 if(res < 0) {
370 fprintf(stderr, "scan dir failed for %s\n", device_path);
371 return 1;
372 }
373 }
374
375 if(get_switch) {
376 for(i = 1; i < nfds; i++) {
377 uint16_t sw;
378 res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
379 if(res < 0) {
380 fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
381 return 1;
382 }
383 sw &= get_switch;
384 printf("%04x%s", sw, newline);
385 }
386 }
387
388 if(dont_block)
389 return 0;
390
391 while(1) {
392 pollres = poll(ufds, nfds, -1);
393 //printf("poll %d, returned %d\n", nfds, pollres);
394 if(ufds[0].revents & POLLIN) {
395 read_notify(device_path, ufds[0].fd, print_flags);
396 }
397 for(i = 1; i < nfds; i++) {
398 if(ufds[i].revents) {
399 if(ufds[i].revents & POLLIN) {
400 res = read(ufds[i].fd, &event, sizeof(event));
401 if(res < (int)sizeof(event)) {
402 fprintf(stderr, "could not get event\n");
403 return 1;
404 }
405 if(get_time) {
406 printf("%ld-%ld: ", event.time.tv_sec, event.time.tv_usec);
407 }
408 if(print_device)
409 printf("%s: ", device_names[i]);
410 printf("%04x %04x %08x", event.type, event.code, event.value);
411 if(sync_rate && event.type == 0 && event.code == 0) {
412 int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
413 if(last_sync_time)
414 printf(" rate %lld", 1000000LL / (now - last_sync_time));
415 last_sync_time = now;
416 }
417 printf("%s", newline);
418 if(event_count && --event_count == 0)
419 return 0;
420 }
421 }
422 }
423 }
424
425 return 0;
426 }
+0
-34
toolbox/getprop.c less more
0 #include <stdio.h>
1
2 #include <cutils/properties.h>
3
4 #include <sys/system_properties.h>
5
6 static void proplist(const char *key, const char *name,
7 void *user __attribute__((unused)))
8 {
9 printf("[%s]: [%s]\n", key, name);
10 }
11
12 int __system_property_wait(prop_info *pi);
13
14 int getprop_main(int argc, char *argv[])
15 {
16 int n = 0;
17
18 if (argc == 1) {
19 (void)property_list(proplist, NULL);
20 } else {
21 char value[PROPERTY_VALUE_MAX];
22 char *default_value;
23 if(argc > 2) {
24 default_value = argv[2];
25 } else {
26 default_value = "";
27 }
28
29 property_get(argv[1], value, default_value);
30 printf("%s\n", value);
31 }
32 return 0;
33 }
+0
-95
toolbox/hd.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6 #include <errno.h>
7
8 int hd_main(int argc, char *argv[])
9 {
10 int c;
11 int fd;
12 unsigned char buf[4096];
13 int res;
14 int read_len;
15 int rv = 0;
16 int i;
17 int filepos = 0;
18 int sum;
19 int lsum;
20
21 int base = -1;
22 int count = 0;
23 int repeat = 0;
24
25 do {
26 c = getopt(argc, argv, "b:c:r:");
27 if (c == EOF)
28 break;
29 switch (c) {
30 case 'b':
31 base = strtol(optarg, NULL, 0);
32 break;
33 case 'c':
34 count = strtol(optarg, NULL, 0);
35 break;
36 case 'r':
37 repeat = strtol(optarg, NULL, 0);
38 break;
39 case '?':
40 fprintf(stderr, "%s: invalid option -%c\n",
41 argv[0], optopt);
42 exit(1);
43 }
44 } while (1);
45
46 if (optind + 1 != argc) {
47 fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]);
48 exit(1);
49 }
50
51 fd = open(argv[optind], O_RDONLY);
52 if(fd < 0) {
53 fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
54 return 1;
55 }
56
57 do {
58 if(base >= 0) {
59 lseek(fd, base, SEEK_SET);
60 filepos = base;
61 }
62 sum = 0;
63 lsum = 0;
64 while(1) {
65 read_len = sizeof(buf);
66 if(count > 0 && base + count - filepos < read_len)
67 read_len = base + count - filepos;
68 res = read(fd, &buf, read_len);
69 for(i = 0; i < res; i++) {
70 if((i & 15) == 0) {
71 printf("%08x: ", filepos + i);
72 }
73 lsum += buf[i];
74 sum += buf[i];
75 printf("%02x ", buf[i]);
76 if(((i & 15) == 15) || (i == res - 1)) {
77 printf("s %x\n", lsum);
78 lsum = 0;
79 }
80 }
81 if(res <= 0) {
82 printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno));
83 return 1;
84 }
85 filepos += res;
86 if(filepos == base + count)
87 break;
88 }
89 printf("sum %x\n", sum);
90 if(repeat)
91 sleep(repeat);
92 } while(repeat);
93 return 0;
94 }
+0
-51
toolbox/id.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <pwd.h>
5 #include <grp.h>
6
7 static void print_uid(uid_t uid)
8 {
9 struct passwd *pw = getpwuid(uid);
10
11 if (pw) {
12 printf("%d(%s)", uid, pw->pw_name);
13 } else {
14 printf("%d",uid);
15 }
16 }
17
18 static void print_gid(gid_t gid)
19 {
20 struct group *gr = getgrgid(gid);
21 if (gr) {
22 printf("%d(%s)", gid, gr->gr_name);
23 } else {
24 printf("%d",gid);
25 }
26 }
27
28 int id_main(int argc, char **argv)
29 {
30 gid_t list[64];
31 int n, max;
32
33 max = getgroups(64, list);
34 if (max < 0) max = 0;
35
36 printf("uid=");
37 print_uid(getuid());
38 printf(" gid=");
39 print_gid(getgid());
40 if (max) {
41 printf(" groups=");
42 print_gid(list[0]);
43 for(n = 1; n < max; n++) {
44 printf(",");
45 print_gid(list[n]);
46 }
47 }
48 printf("\n");
49 return 0;
50 }
+0
-139
toolbox/ifconfig.c less more
0
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 #include <errno.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <linux/if.h>
12 #include <linux/sockios.h>
13 #include <arpa/inet.h>
14
15 static void die(const char *s)
16 {
17 fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
18 exit(-1);
19 }
20
21 static void setflags(int s, struct ifreq *ifr, int set, int clr)
22 {
23 if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS");
24 ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set;
25 if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS");
26 }
27
28 static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
29 {
30 sin->sin_family = AF_INET;
31 sin->sin_port = 0;
32 sin->sin_addr.s_addr = inet_addr(addr);
33 }
34
35 static void setnetmask(int s, struct ifreq *ifr, const char *addr)
36 {
37 init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
38 if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK");
39 }
40
41 static void setaddr(int s, struct ifreq *ifr, const char *addr)
42 {
43 init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
44 if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR");
45 }
46
47 int ifconfig_main(int argc, char *argv[])
48 {
49 struct ifreq ifr;
50 int s;
51 unsigned int addr, mask, flags;
52 char astring[20];
53 char mstring[20];
54 char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
55
56 argc--;
57 argv++;
58
59 if(argc == 0) return 0;
60
61 memset(&ifr, 0, sizeof(struct ifreq));
62 strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
63 ifr.ifr_name[IFNAMSIZ-1] = 0;
64 argc--, argv++;
65
66 if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
67 die("cannot open control socket\n");
68 }
69
70 if (argc == 0) {
71 if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
72 perror(ifr.ifr_name);
73 return -1;
74 } else
75 addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
76
77 if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
78 perror(ifr.ifr_name);
79 return -1;
80 } else
81 mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
82
83 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
84 perror(ifr.ifr_name);
85 return -1;
86 } else
87 flags = ifr.ifr_flags;
88
89 sprintf(astring, "%d.%d.%d.%d",
90 addr & 0xff,
91 ((addr >> 8) & 0xff),
92 ((addr >> 16) & 0xff),
93 ((addr >> 24) & 0xff));
94 sprintf(mstring, "%d.%d.%d.%d",
95 mask & 0xff,
96 ((mask >> 8) & 0xff),
97 ((mask >> 16) & 0xff),
98 ((mask >> 24) & 0xff));
99 printf("%s: ip %s mask %s flags [", ifr.ifr_name,
100 astring,
101 mstring
102 );
103
104 updown = (flags & IFF_UP) ? "up" : "down";
105 brdcst = (flags & IFF_BROADCAST) ? " broadcast" : "";
106 loopbk = (flags & IFF_LOOPBACK) ? " loopback" : "";
107 ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : "";
108 running = (flags & IFF_RUNNING) ? " running" : "";
109 multi = (flags & IFF_MULTICAST) ? " multicast" : "";
110 printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
111
112
113
114 /* char *updown, *brdcst, *loopbk, *ppp, *running, *multi; */
115
116 return 0;
117 }
118
119 while(argc > 0){
120 if(!strcmp(argv[0], "up")) {
121 setflags(s, &ifr, IFF_UP, 0);
122 } else if(!strcmp(argv[0], "down")) {
123 setflags(s, &ifr, 0, IFF_UP);
124 } else if(!strcmp(argv[0], "netmask")) {
125 argc--, argv++;
126 if (0 == argc) {
127 errno = EINVAL;
128 die("expecting an IP address for parameter \"netmask\"");
129 }
130 setnetmask(s, &ifr, argv[0]);
131 } else if(isdigit(argv[0][0])){
132 setaddr(s, &ifr, argv[0]);
133 }
134 argc--, argv++;
135 }
136
137 return 0;
138 }
+0
-278
toolbox/iftop.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <net/if.h>
41
42 #define PROC_NET_DEV "/proc/net/dev"
43
44 #define MAX_IF 8 /* max interfaces we can handle */
45
46 #ifndef PAGE_SIZE
47 # define PAGE_SIZE 4096
48 #endif
49
50 #define _STR(s) #s
51 #define STR(s) _STR(s)
52
53 struct if_stats {
54 char name[IFNAMSIZ];
55
56 unsigned int mtu;
57
58 unsigned int rx_bytes;
59 unsigned int rx_packets;
60 unsigned int rx_errors;
61 unsigned int rx_dropped;
62
63 unsigned int tx_bytes;
64 unsigned int tx_packets;
65 unsigned int tx_errors;
66 unsigned int tx_dropped;
67 };
68
69 static int get_mtu(const char *if_name)
70 {
71 struct ifreq ifr;
72 int s, ret;
73
74 s = socket(AF_INET, SOCK_DGRAM, 0);
75 if (s < 0) {
76 perror("socket");
77 exit(EXIT_FAILURE);
78 }
79
80 memset(&ifr, 0, sizeof(struct ifreq));
81 ifr.ifr_addr.sa_family = AF_INET;
82 strcpy(ifr.ifr_name, if_name);
83
84 ret = ioctl(s, SIOCGIFMTU, &ifr);
85 if (ret < 0) {
86 perror("ioctl");
87 exit(EXIT_FAILURE);
88 }
89
90 ret = close(s);
91 if (ret < 0) {
92 perror("close");
93 exit(EXIT_FAILURE);
94 }
95
96 return ifr.ifr_mtu;
97 }
98
99 static int get_interfaces(struct if_stats *ifs)
100 {
101 char buf[PAGE_SIZE];
102 char *p;
103 int ret, nr, fd;
104
105 fd = open(PROC_NET_DEV, O_RDONLY);
106 if (fd < 0) {
107 perror("open");
108 exit(EXIT_FAILURE);
109 }
110
111 ret = read(fd, buf, sizeof(buf) - 1);
112 if (ret < 0) {
113 perror("read");
114 exit(EXIT_FAILURE);
115 } else if (!ret) {
116 fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
117 exit(EXIT_FAILURE);
118 }
119 buf[ret] = '\0';
120
121 /* skip down to the third line */
122 p = strchr(buf, '\n');
123 if (!p) {
124 fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
125 exit(EXIT_FAILURE);
126 }
127 p = strchr(p + 1, '\n');
128 if (!p) {
129 fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
130 exit(EXIT_FAILURE);
131 }
132 p += 1;
133
134 /*
135 * Key:
136 * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
137 * (Tx) bytes packets errs drop fifo colls carrier compressed
138 */
139 for (nr = 0; nr < MAX_IF; nr++) {
140 char *c;
141
142 ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
143 if (ret != 1) {
144 fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
145 exit(EXIT_FAILURE);
146 }
147
148 /*
149 * This works around a bug in the proc file where large interface names
150 * or Rx byte counts eat the delimiter, breaking sscanf.
151 */
152 c = strchr(ifs->name, ':');
153 if (c)
154 *c = '\0';
155
156 p = strchr(p, ':') + 1;
157
158 ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
159 "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
160 &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
161 &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
162 if (ret != 8) {
163 fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
164 exit(EXIT_FAILURE);
165 }
166
167 ifs->mtu = get_mtu(ifs->name);
168
169 p = strchr(p, '\n') + 1;
170 if (*p == '\0') {
171 nr++;
172 break;
173 }
174
175 ifs++;
176 }
177
178 ret = close(fd);
179 if (ret) {
180 perror("close");
181 exit(EXIT_FAILURE);
182 }
183
184 return nr;
185 }
186
187 static void print_header(void)
188 {
189 printf(" Rx Tx\n");
190 printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
191 "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
192 "packets", "errs", "drpd");
193 }
194
195 static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
196 {
197 int i = 0;
198
199 while (nr--) {
200 if (old->rx_packets || old->tx_packets) {
201 printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
202 new->name, new->mtu,
203 new->rx_bytes - old->rx_bytes,
204 new->rx_packets - old->rx_packets,
205 new->rx_errors - old->rx_errors,
206 new->rx_dropped - old->rx_dropped,
207 new->tx_bytes - old->tx_bytes,
208 new->tx_packets - old->tx_packets,
209 new->tx_errors - old->tx_errors,
210 new->tx_dropped - old->tx_dropped);
211 i++;
212 }
213 old++;
214 new++;
215 }
216
217 return i;
218 }
219
220 static void usage(const char *cmd)
221 {
222 fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
223 }
224
225 int iftop_main(int argc, char *argv[])
226 {
227 struct if_stats ifs[2][MAX_IF];
228 int count = 0, header_interval = 22, delay = 1, i;
229 unsigned int toggle = 0;
230
231 for (i = 1; i < argc; i++) {
232 if (!strcmp(argv[i], "-d")) {
233 if (i >= argc - 1) {
234 fprintf(stderr, "Option -d requires an argument.\n");
235 exit(EXIT_FAILURE);
236 }
237 delay = atoi(argv[i++]);
238 if (!delay)
239 delay = 1;
240 continue;
241 }
242 if (!strcmp(argv[i], "-r")) {
243 if (i >= argc - 1) {
244 fprintf(stderr, "Option -r requires an argument.\n");
245 exit(EXIT_FAILURE);
246 }
247 header_interval = atoi(argv[i++]);
248 if (header_interval < MAX_IF)
249 header_interval = MAX_IF;
250 continue;
251 }
252 if (!strcmp(argv[i], "-h")) {
253 usage(argv[0]);
254 exit(EXIT_SUCCESS);
255 }
256 usage(argv[0]);
257 exit(EXIT_FAILURE);
258 }
259
260 get_interfaces(ifs[!toggle]);
261 if (header_interval)
262 print_header();
263 while (1) {
264 int nr;
265
266 sleep(delay);
267 nr = get_interfaces(ifs[toggle]);
268 if (header_interval && count + nr > header_interval) {
269 print_header();
270 count = 0;
271 }
272 count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
273 toggle = !toggle;
274 }
275
276 return 0;
277 }
+0
-98
toolbox/insmod.c less more
0 #include <stdio.h>
1 #include <string.h>
2 #include <fcntl.h>
3 #include <unistd.h>
4 #include <malloc.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9
10 extern int init_module(void *, unsigned long, const char *);
11
12 static void *read_file(const char *filename, ssize_t *_size)
13 {
14 int ret, fd;
15 struct stat sb;
16 ssize_t size;
17 void *buffer = NULL;
18
19 /* open the file */
20 fd = open(filename, O_RDONLY);
21 if (fd < 0)
22 return NULL;
23
24 /* find out how big it is */
25 if (fstat(fd, &sb) < 0)
26 goto bail;
27 size = sb.st_size;
28
29 /* allocate memory for it to be read into */
30 buffer = malloc(size);
31 if (!buffer)
32 goto bail;
33
34 /* slurp it into our buffer */
35 ret = read(fd, buffer, size);
36 if (ret != size)
37 goto bail;
38
39 /* let the caller know how big it is */
40 *_size = size;
41
42 bail:
43 close(fd);
44 return buffer;
45 }
46
47 #define min(x,y) ((x) < (y) ? (x) : (y))
48 int insmod_main(int argc, char **argv)
49 {
50 void *file;
51 ssize_t size = 0;
52 char opts[1024];
53 int ret;
54
55 /* make sure we've got an argument */
56 if (argc < 2) {
57 fprintf(stderr, "usage: insmod <module.o>\n");
58 return -1;
59 }
60
61 /* read the file into memory */
62 file = read_file(argv[1], &size);
63 if (!file) {
64 fprintf(stderr, "insmod: can't open '%s'\n", argv[1]);
65 return -1;
66 }
67
68 opts[0] = '\0';
69 if (argc > 2) {
70 int i, len;
71 char *end = opts + sizeof(opts) - 1;
72 char *ptr = opts;
73
74 for (i = 2; (i < argc) && (ptr < end); i++) {
75 len = min(strlen(argv[i]), end - ptr);
76 memcpy(ptr, argv[i], len);
77 ptr += len;
78 *ptr++ = ' ';
79 *ptr++ = '\0';
80 }
81 *(ptr - 1) = '\0';
82 }
83
84 /* pass it to the kernel */
85 ret = init_module(file, size, opts);
86 if (ret != 0) {
87 fprintf(stderr,
88 "insmod: init_module '%s' failed (%s)\n",
89 argv[1], strerror(errno));
90 }
91
92 /* free the file buffer */
93 free(file);
94
95 return ret;
96 }
97
+0
-125
toolbox/ioctl.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <linux/kd.h>
5 #include <linux/vt.h>
6 #include <errno.h>
7 #include <pthread.h>
8
9 int ioctl_main(int argc, char *argv[])
10 {
11 int c;
12 int fd;
13 int res;
14
15 int read_only = 0;
16 int length = -1;
17 int arg_size = 4;
18 int direct_arg = 0;
19 uint32_t ioctl_nr;
20 void *ioctl_args;
21 uint8_t *ioctl_argp;
22 uint8_t *ioctl_argp_save;
23 int rem;
24
25 do {
26 c = getopt(argc, argv, "rdl:a:h");
27 if (c == EOF)
28 break;
29 switch (c) {
30 case 'r':
31 read_only = 1;
32 break;
33 case 'd':
34 direct_arg = 1;
35 break;
36 case 'l':
37 length = strtol(optarg, NULL, 0);
38 break;
39 case 'a':
40 arg_size = strtol(optarg, NULL, 0);
41 break;
42 case 'h':
43 fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
44 " -l <lenght> Length of io buffer\n"
45 " -a <argsize> Size of each argument (1-8)\n"
46 " -r Open device in read only mode\n"
47 " -d Direct argument (no iobuffer)\n"
48 " -h Print help\n", argv[0]);
49 return -1;
50 case '?':
51 fprintf(stderr, "%s: invalid option -%c\n",
52 argv[0], optopt);
53 exit(1);
54 }
55 } while (1);
56
57 if(optind + 2 > argc) {
58 fprintf(stderr, "%s: too few arguments\n", argv[0]);
59 exit(1);
60 }
61
62 fd = open(argv[optind], O_RDWR | O_SYNC);
63 if (fd < 0) {
64 fprintf(stderr, "cannot open %s\n", argv[optind]);
65 return 1;
66 }
67 optind++;
68
69 ioctl_nr = strtol(argv[optind], NULL, 0);
70 optind++;
71
72 if(direct_arg) {
73 arg_size = 4;
74 length = 4;
75 }
76
77 if(length < 0) {
78 length = (argc - optind) * arg_size;
79 }
80 if(length) {
81 ioctl_args = calloc(1, length);
82
83 ioctl_argp_save = ioctl_argp = ioctl_args;
84 rem = length;
85 while(optind < argc) {
86 uint64_t tmp = strtoull(argv[optind], NULL, 0);
87 if(rem < arg_size) {
88 fprintf(stderr, "%s: too many arguments\n", argv[0]);
89 exit(1);
90 }
91 memcpy(ioctl_argp, &tmp, arg_size);
92 ioctl_argp += arg_size;
93 rem -= arg_size;
94 optind++;
95 }
96 }
97 printf("sending ioctl 0x%x", ioctl_nr);
98 rem = length;
99 while(rem--) {
100 printf(" 0x%02x", *ioctl_argp_save++);
101 }
102 printf("\n");
103
104 if(direct_arg)
105 res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
106 else if(length)
107 res = ioctl(fd, ioctl_nr, ioctl_args);
108 else
109 res = ioctl(fd, ioctl_nr, 0);
110 if (res < 0) {
111 fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
112 return 1;
113 }
114 if(length) {
115 printf("return buf:");
116 ioctl_argp = ioctl_args;
117 rem = length;
118 while(rem--) {
119 printf(" %02x", *ioctl_argp++);
120 }
121 printf("\n");
122 }
123 return 0;
124 }
+0
-35
toolbox/kill.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <errno.h>
3
4 #include <sys/types.h>
5 #include <signal.h>
6
7 int kill_main(int argc, char **argv)
8 {
9 int sig = SIGTERM;
10 int result = 0;
11
12 argc--;
13 argv++;
14
15 if(argc >= 2 && argv[0][0] == '-'){
16 sig = atoi(argv[0] + 1);
17 argc--;
18 argv++;
19 }
20
21 while(argc > 0){
22 int pid = atoi(argv[0]);
23 int err = kill(pid, sig);
24 if (err < 0) {
25 result = err;
26 fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
27 }
28
29 argc--;
30 argv++;
31 }
32
33 return result;
34 }
+0
-34
toolbox/ln.c less more
0 #include <stdio.h>
1 #include <unistd.h>
2 #include <string.h>
3 #include <errno.h>
4
5 static int usage()
6 {
7 fprintf(stderr,"ln [-s] <target> <name>\n");
8 return -1;
9 }
10
11 int ln_main(int argc, char *argv[])
12 {
13 int symbolic = 0;
14 int ret;
15 if(argc < 2) return usage();
16
17 if(!strcmp(argv[1],"-s")) {
18 symbolic = 1;
19 argc--;
20 argv++;
21 }
22
23 if(argc < 3) return usage();
24
25 if(symbolic) {
26 ret = symlink(argv[1], argv[2]);
27 } else {
28 ret = link(argv[1], argv[2]);
29 }
30 if(ret < 0)
31 fprintf(stderr, "link failed %s\n", strerror(errno));
32 return ret;
33 }
+0
-145
toolbox/log.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <stdio.h>
32 #include <cutils/logd.h>
33 #include <ctype.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #include <cutils/sockets.h>
38 #include <unistd.h>
39
40 /*
41 * Note: also accepts 0-9 priorities
42 * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
43 */
44 static android_LogPriority filterCharToPri (char c)
45 {
46 android_LogPriority pri;
47
48 c = tolower(c);
49
50 if (c >= '0' && c <= '9') {
51 if (c >= ('0'+ANDROID_LOG_SILENT)) {
52 pri = ANDROID_LOG_VERBOSE;
53 } else {
54 pri = (android_LogPriority)(c - '0');
55 }
56 } else if (c == 'v') {
57 pri = ANDROID_LOG_VERBOSE;
58 } else if (c == 'd') {
59 pri = ANDROID_LOG_DEBUG;
60 } else if (c == 'i') {
61 pri = ANDROID_LOG_INFO;
62 } else if (c == 'w') {
63 pri = ANDROID_LOG_WARN;
64 } else if (c == 'e') {
65 pri = ANDROID_LOG_ERROR;
66 } else if (c == 'f') {
67 pri = ANDROID_LOG_FATAL;
68 } else if (c == 's') {
69 pri = ANDROID_LOG_SILENT;
70 } else if (c == '*') {
71 pri = ANDROID_LOG_DEFAULT;
72 } else {
73 pri = ANDROID_LOG_UNKNOWN;
74 }
75
76 return pri;
77 }
78
79 static int usage(const char *s)
80 {
81 fprintf(stderr, "USAGE: %s [-p priorityChar] [-t tag] message\n", s);
82
83 fprintf(stderr, "\tpriorityChar should be one of:\n"
84 "\t\tv,d,i,w,e\n");
85 exit(-1);
86 }
87
88
89 int log_main(int argc, char *argv[])
90 {
91 android_LogPriority priority;
92 const char *tag = "log";
93 char buffer[4096];
94 int i;
95
96 priority = ANDROID_LOG_INFO;
97
98 for (;;) {
99 int ret;
100
101 ret = getopt(argc, argv, "t:p:h");
102
103 if (ret < 0) {
104 break;
105 }
106
107 switch(ret) {
108 case 't':
109 tag = optarg;
110 break;
111
112 case 'p':
113 priority = filterCharToPri(optarg[0]);
114 if (priority == ANDROID_LOG_UNKNOWN) {
115 usage(argv[0]);
116 }
117 break;
118
119 case 'h':
120 usage(argv[0]);
121 break;
122 }
123 }
124
125 if (optind == argc) {
126 usage(argv[0]);
127 }
128
129 buffer[0] = '\0';
130
131 for (i = optind ; i < argc ; i++) {
132 strncat(buffer, argv[i], sizeof(buffer)-1);
133 strncat(buffer, " ", sizeof(buffer)-1);
134 }
135
136 if(buffer[0] == 0) {
137 usage(argv[0]);
138 }
139
140 __android_log_print(priority, tag, "%s", buffer);
141
142 return 0;
143 }
144
+0
-285
toolbox/ls.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <dirent.h>
5 #include <errno.h>
6
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <time.h>
10
11 #include <pwd.h>
12 #include <grp.h>
13
14 #include <linux/kdev_t.h>
15
16 // bits for flags argument
17 #define LIST_LONG (1 << 0)
18 #define LIST_ALL (1 << 1)
19 #define LIST_RECURSIVE (1 << 2)
20
21 // fwd
22 static int listpath(const char *name, int flags);
23
24 static char mode2kind(unsigned mode)
25 {
26 switch(mode & S_IFMT){
27 case S_IFSOCK: return 's';
28 case S_IFLNK: return 'l';
29 case S_IFREG: return '-';
30 case S_IFDIR: return 'd';
31 case S_IFBLK: return 'b';
32 case S_IFCHR: return 'c';
33 case S_IFIFO: return 'p';
34 default: return '?';
35 }
36 }
37
38 static void mode2str(unsigned mode, char *out)
39 {
40 *out++ = mode2kind(mode);
41
42 *out++ = (mode & 0400) ? 'r' : '-';
43 *out++ = (mode & 0200) ? 'w' : '-';
44 if(mode & 04000) {
45 *out++ = (mode & 0100) ? 's' : 'S';
46 } else {
47 *out++ = (mode & 0100) ? 'x' : '-';
48 }
49 *out++ = (mode & 040) ? 'r' : '-';
50 *out++ = (mode & 020) ? 'w' : '-';
51 if(mode & 02000) {
52 *out++ = (mode & 010) ? 's' : 'S';
53 } else {
54 *out++ = (mode & 010) ? 'x' : '-';
55 }
56 *out++ = (mode & 04) ? 'r' : '-';
57 *out++ = (mode & 02) ? 'w' : '-';
58 if(mode & 01000) {
59 *out++ = (mode & 01) ? 't' : 'T';
60 } else {
61 *out++ = (mode & 01) ? 'x' : '-';
62 }
63 *out = 0;
64 }
65
66 static void user2str(unsigned uid, char *out)
67 {
68 struct passwd *pw = getpwuid(uid);
69 if(pw) {
70 strcpy(out, pw->pw_name);
71 } else {
72 sprintf(out, "%d", uid);
73 }
74 }
75
76 static void group2str(unsigned gid, char *out)
77 {
78 struct group *gr = getgrgid(gid);
79 if(gr) {
80 strcpy(out, gr->gr_name);
81 } else {
82 sprintf(out, "%d", gid);
83 }
84 }
85
86 static int listfile(const char *path, int flags)
87 {
88 struct stat s;
89 char date[32];
90 char mode[16];
91 char user[16];
92 char group[16];
93 const char *name;
94
95 /* name is anything after the final '/', or the whole path if none*/
96 name = strrchr(path, '/');
97 if(name == 0) {
98 name = path;
99 } else {
100 name++;
101 }
102
103 if(lstat(path, &s) < 0) {
104 return -1;
105 }
106
107 mode2str(s.st_mode, mode);
108 user2str(s.st_uid, user);
109 group2str(s.st_gid, group);
110
111 strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
112 date[31] = 0;
113
114 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
115 // MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
116
117 switch(s.st_mode & S_IFMT) {
118 case S_IFBLK:
119 case S_IFCHR:
120 printf("%s %-8s %-8s %3d, %3d %s %s\n",
121 mode, user, group,
122 (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
123 date, name);
124 break;
125 case S_IFREG:
126 printf("%s %-8s %-8s %8d %s %s\n",
127 mode, user, group, (int) s.st_size, date, name);
128 break;
129 case S_IFLNK: {
130 char linkto[256];
131 int len;
132
133 len = readlink(path, linkto, 256);
134 if(len < 0) return -1;
135
136 if(len > 255) {
137 linkto[252] = '.';
138 linkto[253] = '.';
139 linkto[254] = '.';
140 linkto[255] = 0;
141 } else {
142 linkto[len] = 0;
143 }
144
145 printf("%s %-8s %-8s %s %s -> %s\n",
146 mode, user, group, date, name, linkto);
147 break;
148 }
149 default:
150 printf("%s %-8s %-8s %s %s\n",
151 mode, user, group, date, name);
152
153 }
154 return 0;
155 }
156
157 static int listdir(const char *name, int flags)
158 {
159 char tmp[4096];
160 DIR *d;
161 struct dirent *de;
162
163 d = opendir(name);
164 if(d == 0) {
165 fprintf(stderr, "opendir failed, %s\n", strerror(errno));
166 return -1;
167 }
168
169 while((de = readdir(d)) != 0){
170 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
171 if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
172 if ((flags & LIST_LONG) != 0) {
173 sprintf(tmp, "%s/%s", name, de->d_name);
174 listfile(tmp, flags);
175 } else {
176 printf("%s\n", de->d_name);
177 }
178 }
179
180 if (flags & LIST_RECURSIVE) {
181 rewinddir(d);
182
183 while ((de = readdir(d)) != 0) {
184 struct stat s;
185 int err;
186
187 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
188 continue;
189 if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
190 continue;
191
192 if (!strcmp(name, "/")) sprintf(tmp, "/%s", de->d_name);
193 else sprintf(tmp, "%s/%s", name, de->d_name);
194
195 /*
196 * If the name ends in a '/', use stat() so we treat it like a
197 * directory even if it's a symlink.
198 */
199 if (tmp[strlen(tmp)-1] == '/')
200 err = stat(tmp, &s);
201 else
202 err = lstat(tmp, &s);
203
204 if (err < 0) {
205 perror(tmp);
206 closedir(d);
207 return -1;
208 }
209
210 if (S_ISDIR(s.st_mode)) {
211 printf("\n%s:\n", tmp);
212 listdir(tmp, flags);
213 }
214 }
215 }
216
217 closedir(d);
218 return 0;
219 }
220
221 static int listpath(const char *name, int flags)
222 {
223 struct stat s;
224 int err;
225
226 /*
227 * If the name ends in a '/', use stat() so we treat it like a
228 * directory even if it's a symlink.
229 */
230 if (name[strlen(name)-1] == '/')
231 err = stat(name, &s);
232 else
233 err = lstat(name, &s);
234
235 if (err < 0) {
236 perror(name);
237 return -1;
238 }
239
240 if (S_ISDIR(s.st_mode)) {
241 if (flags & LIST_RECURSIVE)
242 printf("\n%s:\n", name);
243 return listdir(name, flags);
244 } else {
245 if ((flags & LIST_LONG) != 0) {
246 /* yeah this calls stat() again*/
247 return listfile(name, flags);
248 } else {
249 printf("%s\n", name);
250 return 0;
251 }
252 }
253 }
254
255 int ls_main(int argc, char **argv)
256 {
257 int flags = 0;
258 int listed = 0;
259
260 if(argc > 1) {
261 int i;
262 int err = 0;
263
264 for (i = 1; i < argc; i++) {
265 if(!strcmp(argv[i], "-l")) {
266 flags |= LIST_LONG;
267 } else if (!strcmp(argv[i], "-a")) {
268 flags |= LIST_ALL;
269 } else if (!strcmp(argv[i], "-R")) {
270 flags |= LIST_RECURSIVE;
271 } else {
272 listed++;
273 if(listpath(argv[i], flags) != 0) {
274 err = EXIT_FAILURE;
275 }
276 }
277 }
278
279 if (listed > 0) return err;
280 }
281
282 // list working directory if no files or directories were specified
283 return listpath(".", flags);
284 }
+0
-10
toolbox/lsmod.c less more
0 #include <stdio.h>
1
2 extern int cat_main(int argc, char **argv);
3
4 int lsmod_main(int argc, char **argv)
5 {
6 char *cat_argv[] = { "cat", "/proc/modules", NULL };
7 return cat_main(2, cat_argv);
8 }
9
+0
-29
toolbox/mkdir.c less more
0 #include <stdio.h>
1 #include <unistd.h>
2 #include <string.h>
3 #include <errno.h>
4
5 static int usage()
6 {
7 fprintf(stderr,"mkdir <target>\n");
8 return -1;
9 }
10
11 int mkdir_main(int argc, char *argv[])
12 {
13 int symbolic = 0;
14 int ret;
15 if(argc < 2) return usage();
16
17 while(argc > 1) {
18 argc--;
19 argv++;
20 ret = mkdir(argv[0], 0777);
21 if(ret < 0) {
22 fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno));
23 return ret;
24 }
25 }
26
27 return 0;
28 }
+0
-849
toolbox/mkdosfs.c less more
0 /* $NetBSD: newfs_msdos.c,v 1.18.2.1 2005/05/01 18:44:02 tron Exp $ */
1
2 /*
3 * Copyright (c) 1998 Robert Nordier
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define __USE_FILE_OFFSET64
30
31 #include <sys/cdefs.h>
32
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #ifdef __FreeBSD__
36 #include <sys/diskslice.h>
37 #endif
38 #include <sys/mount.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41 #include <sys/ioctl.h>
42
43 #include <ctype.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <paths.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <time.h>
52 #include <unistd.h>
53 #ifdef __NetBSD__
54 #include <disktab.h>
55 #include <util.h>
56 #endif
57
58 #define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
59 #define BPN 4 /* bits per nibble */
60 #define NPB 2 /* nibbles per byte */
61
62 #define DOSMAGIC 0xaa55 /* DOS magic number */
63 #define MINBPS 128 /* minimum bytes per sector */
64 #define MAXSPC 128 /* maximum sectors per cluster */
65 #define MAXNFT 16 /* maximum number of FATs */
66 #define DEFBLK 4096 /* default block size */
67 #define DEFBLK16 2048 /* default block size FAT16 */
68 #define DEFRDE 512 /* default root directory entries */
69 #define RESFTE 2 /* reserved FAT entries */
70 #define MINCLS12 1 /* minimum FAT12 clusters */
71 #define MINCLS16 0x1000 /* minimum FAT16 clusters */
72 #define MINCLS32 2 /* minimum FAT32 clusters */
73 #define MAXCLS12 0xfed /* maximum FAT12 clusters */
74 #define MAXCLS16 0xfff5 /* maximum FAT16 clusters */
75 #define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */
76
77 #define mincls(fat) ((fat) == 12 ? MINCLS12 : \
78 (fat) == 16 ? MINCLS16 : \
79 MINCLS32)
80
81 #define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \
82 (fat) == 16 ? MAXCLS16 : \
83 MAXCLS32)
84
85 #define mk1(p, x) \
86 (p) = (u_int8_t)(x)
87
88 #define mk2(p, x) \
89 (p)[0] = (u_int8_t)(x), \
90 (p)[1] = (u_int8_t)((x) >> 010)
91
92 #define mk4(p, x) \
93 (p)[0] = (u_int8_t)(x), \
94 (p)[1] = (u_int8_t)((x) >> 010), \
95 (p)[2] = (u_int8_t)((x) >> 020), \
96 (p)[3] = (u_int8_t)((x) >> 030)
97
98 #define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg)
99 #define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg)
100 #define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg)
101 #define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg)
102
103 #ifndef MAX
104 #define MAX(x, y) ((x) > (y) ? (x) : (y))
105 #endif
106 #ifndef MIN
107 #define MIN(x, y) ((x) < (y) ? (x) : (y))
108 #endif
109
110 static int powerof2(int x) {
111 int i;
112 for (i = 0; i < 32; i++) {
113 if (x & 1) {
114 x >>= 1;
115 // if x is zero, then original x was a power of two
116 return (x == 0);
117 }
118 x >>= 1;
119 }
120
121 return 0;
122 }
123
124 #ifndef howmany
125 #define howmany(x, y) (((x)+((y)-1))/(y))
126 #endif
127
128 #pragma pack(push, 1)
129 struct bs {
130 u_int8_t jmp[3]; /* bootstrap entry point */
131 u_int8_t oem[8]; /* OEM name and version */
132 };
133 #define BS_SIZE 11
134
135 struct bsbpb {
136 u_int8_t bps[2]; /* bytes per sector */
137 u_int8_t spc; /* sectors per cluster */
138 u_int8_t res[2]; /* reserved sectors */
139 u_int8_t nft; /* number of FATs */
140 u_int8_t rde[2]; /* root directory entries */
141 u_int8_t sec[2]; /* total sectors */
142 u_int8_t mid; /* media descriptor */
143 u_int8_t spf[2]; /* sectors per FAT */
144 u_int8_t spt[2]; /* sectors per track */
145 u_int8_t hds[2]; /* drive heads */
146 u_int8_t hid[4]; /* hidden sectors */
147 u_int8_t bsec[4]; /* big total sectors */
148 };
149 #define BSBPB_SIZE 25
150
151 struct bsxbpb {
152 u_int8_t bspf[4]; /* big sectors per FAT */
153 u_int8_t xflg[2]; /* FAT control flags */
154 u_int8_t vers[2]; /* file system version */
155 u_int8_t rdcl[4]; /* root directory start cluster */
156 u_int8_t infs[2]; /* file system info sector */
157 u_int8_t bkbs[2]; /* backup boot sector */
158 u_int8_t rsvd[12]; /* reserved */
159 };
160 #define BSXBPB_SIZE 28
161
162 struct bsx {
163 u_int8_t drv; /* drive number */
164 u_int8_t rsvd; /* reserved */
165 u_int8_t sig; /* extended boot signature */
166 u_int8_t volid[4]; /* volume ID number */
167 u_int8_t label[11]; /* volume label */
168 u_int8_t type[8]; /* file system type */
169 };
170 #define BSX_SIZE 26
171
172 struct de {
173 u_int8_t namext[11]; /* name and extension */
174 u_int8_t attr; /* attributes */
175 u_int8_t rsvd[10]; /* reserved */
176 u_int8_t time[2]; /* creation time */
177 u_int8_t date[2]; /* creation date */
178 u_int8_t clus[2]; /* starting cluster */
179 u_int8_t size[4]; /* size */
180 #define DE_SIZE 32
181 };
182 #pragma pack(pop)
183
184 struct bpb {
185 u_int bps; /* bytes per sector */
186 u_int spc; /* sectors per cluster */
187 u_int res; /* reserved sectors */
188 u_int nft; /* number of FATs */
189 u_int rde; /* root directory entries */
190 u_int sec; /* total sectors */
191 u_int mid; /* media descriptor */
192 u_int spf; /* sectors per FAT */
193 u_int spt; /* sectors per track */
194 u_int hds; /* drive heads */
195 u_int hid; /* hidden sectors */
196 u_int bsec; /* big total sectors */
197 u_int bspf; /* big sectors per FAT */
198 u_int rdcl; /* root directory start cluster */
199 u_int infs; /* file system info sector */
200 u_int bkbs; /* backup boot sector */
201 };
202
203 static u_int8_t bootcode[] = {
204 0xfa, /* cli */
205 0x31, 0xc0, /* xor ax,ax */
206 0x8e, 0xd0, /* mov ss,ax */
207 0xbc, 0x00, 0x7c, /* mov sp,7c00h */
208 0xfb, /* sti */
209 0x8e, 0xd8, /* mov ds,ax */
210 0xe8, 0x00, 0x00, /* call $ + 3 */
211 0x5e, /* pop si */
212 0x83, 0xc6, 0x19, /* add si,+19h */
213 0xbb, 0x07, 0x00, /* mov bx,0007h */
214 0xfc, /* cld */
215 0xac, /* lodsb */
216 0x84, 0xc0, /* test al,al */
217 0x74, 0x06, /* jz $ + 8 */
218 0xb4, 0x0e, /* mov ah,0eh */
219 0xcd, 0x10, /* int 10h */
220 0xeb, 0xf5, /* jmp $ - 9 */
221 0x30, 0xe4, /* xor ah,ah */
222 0xcd, 0x16, /* int 16h */
223 0xcd, 0x19, /* int 19h */
224 0x0d, 0x0a,
225 'N', 'o', 'n', '-', 's', 'y', 's', 't',
226 'e', 'm', ' ', 'd', 'i', 's', 'k',
227 0x0d, 0x0a,
228 'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
229 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
230 ' ', 'r', 'e', 'b', 'o', 'o', 't',
231 0x0d, 0x0a,
232 0
233 };
234
235 static void print_bpb(struct bpb *);
236 static u_int ckgeom(const char *, u_int, const char *);
237 static u_int argtou(const char *, u_int, u_int, const char *);
238 static int oklabel(const char *);
239 static void mklabel(u_int8_t *, const char *);
240 static void setstr(u_int8_t *, const char *, size_t);
241 static void usage(char* progname);
242
243 /*
244 * Construct a FAT12, FAT16, or FAT32 file system.
245 */
246 int
247 mkdosfs_main(int argc, char *argv[])
248 {
249 static char opts[] = "NB:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
250 static const char *opt_B, *opt_L, *opt_O;
251 static u_int opt_F, opt_I, opt_S, opt_a, opt_b, opt_c, opt_e;
252 static u_int opt_h, opt_i, opt_k, opt_m, opt_n, opt_o, opt_r;
253 static u_int opt_s, opt_u;
254 static int opt_N;
255 static int Iflag, mflag, oflag;
256 char buf[MAXPATHLEN];
257 struct stat sb;
258 struct timeval tv;
259 struct bpb bpb;
260 struct tm *tm;
261 struct bs *bs;
262 struct bsbpb *bsbpb;
263 struct bsxbpb *bsxbpb;
264 struct bsx *bsx;
265 struct de *de;
266 u_int8_t *img;
267 const char *fname, *dtype, *bname;
268 ssize_t n;
269 time_t now;
270 u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
271 int ch, fd, fd1;
272 char* progname = argv[0];
273
274 while ((ch = getopt(argc, argv, opts)) != -1)
275 switch (ch) {
276 case 'N':
277 opt_N = 1;
278 break;
279 case 'B':
280 opt_B = optarg;
281 break;
282 case 'F':
283 if (strcmp(optarg, "12") &&
284 strcmp(optarg, "16") &&
285 strcmp(optarg, "32"))
286 fprintf(stderr, "%s: bad FAT type\n", optarg);
287 opt_F = atoi(optarg);
288 break;
289 case 'I':
290 opt_I = argto4(optarg, 0, "volume ID");
291 Iflag = 1;
292 break;
293 case 'L':
294 if (!oklabel(optarg))
295 fprintf(stderr, "%s: bad volume label\n", optarg);
296 opt_L = optarg;
297 break;
298 case 'O':
299 if (strlen(optarg) > 8)
300 fprintf(stderr, "%s: bad OEM string\n", optarg);
301 opt_O = optarg;
302 break;
303 case 'S':
304 opt_S = argto2(optarg, 1, "bytes/sector");
305 break;
306 case 'a':
307 opt_a = argto4(optarg, 1, "sectors/FAT");
308 break;
309 case 'b':
310 opt_b = argtox(optarg, 1, "block size");
311 opt_c = 0;
312 break;
313 case 'c':
314 opt_c = argto1(optarg, 1, "sectors/cluster");
315 opt_b = 0;
316 break;
317 case 'e':
318 opt_e = argto2(optarg, 1, "directory entries");
319 break;
320 case 'h':
321 opt_h = argto2(optarg, 1, "drive heads");
322 break;
323 case 'i':
324 opt_i = argto2(optarg, 1, "info sector");
325 break;
326 case 'k':
327 opt_k = argto2(optarg, 1, "backup sector");
328 break;
329 case 'm':
330 opt_m = argto1(optarg, 0, "media descriptor");
331 mflag = 1;
332 break;
333 case 'n':
334 opt_n = argto1(optarg, 1, "number of FATs");
335 break;
336 case 'o':
337 opt_o = argto4(optarg, 0, "hidden sectors");
338 oflag = 1;
339 break;
340 case 'r':
341 opt_r = argto2(optarg, 1, "reserved sectors");
342 break;
343 case 's':
344 opt_s = argto4(optarg, 1, "file system size");
345 break;
346 case 'u':
347 opt_u = argto2(optarg, 1, "sectors/track");
348 break;
349 default:
350 usage(progname);
351 }
352 argc -= optind;
353 argv += optind;
354 if (argc < 1 || argc > 2)
355 usage(progname);
356 fname = *argv++;
357 if (!strchr(fname, '/')) {
358 snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
359 if (!(fname = strdup(buf)))
360 fprintf(stderr, NULL);
361 }
362 dtype = *argv;
363 if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1 ||
364 fstat(fd, &sb))
365 fprintf(stderr, "%s\n", fname);
366 memset(&bpb, 0, sizeof(bpb));
367
368 if (opt_h)
369 bpb.hds = opt_h;
370 if (opt_u)
371 bpb.spt = opt_u;
372 if (opt_S)
373 bpb.bps = opt_S;
374 if (opt_s)
375 bpb.bsec = opt_s;
376 if (oflag)
377 bpb.hid = opt_o;
378
379 bpb.bps = 512; // 512 bytes/sector
380 bpb.spc = 8; // 4K clusters
381
382
383 fprintf(stderr, "opening %s\n", fname);
384 if ((fd1 = open(fname, O_RDONLY)) == -1) {
385 fprintf(stderr, "failed to open %s\n", fname);
386 exit(1);
387 }
388
389 lseek(fd1, 0, SEEK_SET);
390 off_t length = lseek(fd1, 0, SEEK_END);
391 fprintf(stderr, "lseek returned %ld\n", length);
392 if (length > 0) {
393 bpb.bsec = length / bpb.bps;
394 bpb.spt = bpb.bsec;
395 // use FAT32 for 2 gig or greater
396 if (length >= 2 *1024 *1024 *1024) {
397 fat = 32;
398 } else {
399 fat = 16;
400 }
401 }
402 close(fd1);
403 fd1 = -1;
404
405 if (!powerof2(bpb.bps))
406 fprintf(stderr, "bytes/sector (%u) is not a power of 2\n", bpb.bps);
407 if (bpb.bps < MINBPS)
408 fprintf(stderr, "bytes/sector (%u) is too small; minimum is %u\n",
409 bpb.bps, MINBPS);
410
411 if (!(fat = opt_F)) {
412 if (!opt_e && (opt_i || opt_k))
413 fat = 32;
414 }
415
416 if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
417 fprintf(stderr, "-%c is not a legal FAT%s option\n",
418 fat == 32 ? 'e' : opt_i ? 'i' : 'k',
419 fat == 32 ? "32" : "12/16");
420 if (fat == 32)
421 bpb.rde = 0;
422 if (opt_b) {
423 if (!powerof2(opt_b))
424 fprintf(stderr, "block size (%u) is not a power of 2\n", opt_b);
425 if (opt_b < bpb.bps)
426 fprintf(stderr, "block size (%u) is too small; minimum is %u\n",
427 opt_b, bpb.bps);
428 if (opt_b > bpb.bps * MAXSPC)
429 fprintf(stderr, "block size (%u) is too large; maximum is %u\n",
430 opt_b, bpb.bps * MAXSPC);
431 bpb.spc = opt_b / bpb.bps;
432 }
433 if (opt_c) {
434 if (!powerof2(opt_c))
435 fprintf(stderr, "sectors/cluster (%u) is not a power of 2\n", opt_c);
436 bpb.spc = opt_c;
437 }
438 if (opt_r)
439 bpb.res = opt_r;
440 if (opt_n) {
441 if (opt_n > MAXNFT)
442 fprintf(stderr, "number of FATs (%u) is too large; maximum is %u\n",
443 opt_n, MAXNFT);
444 bpb.nft = opt_n;
445 }
446 if (opt_e)
447 bpb.rde = opt_e;
448 if (mflag) {
449 if (opt_m < 0xf0)
450 fprintf(stderr, "illegal media descriptor (%#x)\n", opt_m);
451 bpb.mid = opt_m;
452 }
453 if (opt_a)
454 bpb.bspf = opt_a;
455 if (opt_i)
456 bpb.infs = opt_i;
457 if (opt_k)
458 bpb.bkbs = opt_k;
459 bss = 1;
460 bname = NULL;
461 fd1 = -1;
462 if (opt_B) {
463 bname = opt_B;
464 if (!strchr(bname, '/')) {
465 snprintf(buf, sizeof(buf), "/boot/%s", bname);
466 if (!(bname = strdup(buf)))
467 fprintf(stderr, NULL);
468 }
469 if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
470 fprintf(stderr, "%s", bname);
471 if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
472 sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
473 fprintf(stderr, "%s: inappropriate file type or format\n", bname);
474 bss = sb.st_size / bpb.bps;
475 }
476 if (!bpb.nft)
477 bpb.nft = 2;
478 if (!fat) {
479 if (bpb.bsec < (bpb.res ? bpb.res : bss) +
480 howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
481 ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
482 bpb.nft +
483 howmany(bpb.rde ? bpb.rde : DEFRDE,
484 bpb.bps / DE_SIZE) +
485 (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
486 (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
487 fat = 12;
488 else if (bpb.rde || bpb.bsec <
489 (bpb.res ? bpb.res : bss) +
490 howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
491 howmany(DEFRDE, bpb.bps / DE_SIZE) +
492 (MAXCLS16 + 1) *
493 (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
494 fat = 16;
495 else
496 fat = 32;
497 }
498 x = bss;
499 if (fat == 32) {
500 if (!bpb.infs) {
501 if (x == MAXU16 || x == bpb.bkbs)
502 fprintf(stderr, "no room for info sector\n");
503 bpb.infs = x;
504 }
505 if (bpb.infs != MAXU16 && x <= bpb.infs)
506 x = bpb.infs + 1;
507 if (!bpb.bkbs) {
508 if (x == MAXU16)
509 fprintf(stderr, "no room for backup sector\n");
510 bpb.bkbs = x;
511 } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
512 fprintf(stderr, "backup sector would overwrite info sector\n");
513 if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
514 x = bpb.bkbs + 1;
515 }
516 if (!bpb.res)
517 bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
518 else if (bpb.res < x)
519 fprintf(stderr, "too few reserved sectors (need %d have %d)\n", x, bpb.res);
520 if (fat != 32 && !bpb.rde)
521 bpb.rde = DEFRDE;
522 rds = howmany(bpb.rde, bpb.bps / DE_SIZE);
523 if (!bpb.spc)
524 for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
525 bpb.spc < MAXSPC &&
526 bpb.res +
527 howmany((RESFTE + maxcls(fat)) * (fat / BPN),
528 bpb.bps * NPB) * bpb.nft +
529 rds +
530 (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
531 bpb.spc <<= 1);
532 if (fat != 32 && bpb.bspf > MAXU16)
533 fprintf(stderr, "too many sectors/FAT for FAT12/16\n");
534 x1 = bpb.res + rds;
535 x = bpb.bspf ? bpb.bspf : 1;
536 if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
537 fprintf(stderr, "meta data exceeds file system size\n");
538 x1 += x * bpb.nft;
539 x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
540 (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
541 x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
542 bpb.bps * NPB);
543 if (!bpb.bspf) {
544 bpb.bspf = x2;
545 x1 += (bpb.bspf - 1) * bpb.nft;
546 }
547 cls = (bpb.bsec - x1) / bpb.spc;
548 x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
549 if (cls > x)
550 cls = x;
551 if (bpb.bspf < x2)
552 fprintf(stderr, "warning: sectors/FAT limits file system to %u clusters\n",
553 cls);
554 if (cls < mincls(fat))
555 fprintf(stderr, "%u clusters too few clusters for FAT%u, need %u\n", cls, fat,
556 mincls(fat));
557 if (cls > maxcls(fat)) {
558 cls = maxcls(fat);
559 bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
560 fprintf(stderr, "warning: FAT type limits file system to %u sectors\n",
561 bpb.bsec);
562 }
563 printf("%s: %u sector%s in %u FAT%u cluster%s "
564 "(%u bytes/cluster)\n", fname, cls * bpb.spc,
565 cls * bpb.spc == 1 ? "" : "s", cls, fat,
566 cls == 1 ? "" : "s", bpb.bps * bpb.spc);
567 if (!bpb.mid)
568 bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
569 if (fat == 32)
570 bpb.rdcl = RESFTE;
571 if (bpb.hid + bpb.bsec <= MAXU16) {
572 bpb.sec = bpb.bsec;
573 bpb.bsec = 0;
574 }
575 if (fat != 32) {
576 bpb.spf = bpb.bspf;
577 bpb.bspf = 0;
578 }
579 ch = 0;
580 if (fat == 12)
581 ch = 1; /* 001 Primary DOS with 12 bit FAT */
582 else if (fat == 16) {
583 if (bpb.bsec == 0)
584 ch = 4; /* 004 Primary DOS with 16 bit FAT <32M */
585 else
586 ch = 6; /* 006 Primary 'big' DOS, 16-bit FAT (> 32MB) */
587 /*
588 * XXX: what about:
589 * 014 DOS (16-bit FAT) - LBA
590 * ?
591 */
592 } else if (fat == 32) {
593 ch = 11; /* 011 Primary DOS with 32 bit FAT */
594 /*
595 * XXX: what about:
596 * 012 Primary DOS with 32 bit FAT - LBA
597 * ?
598 */
599 }
600 if (ch != 0)
601 printf("MBR type: %d\n", ch);
602 print_bpb(&bpb);
603 if (!opt_N) {
604 gettimeofday(&tv, NULL);
605 now = tv.tv_sec;
606 tm = localtime(&now);
607 if (!(img = malloc(bpb.bps)))
608 fprintf(stderr, NULL);
609 dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
610
611 for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
612 x = lsn;
613 if (opt_B &&
614 fat == 32 && bpb.bkbs != MAXU16 &&
615 bss <= bpb.bkbs && x >= bpb.bkbs) {
616 x -= bpb.bkbs;
617 if (!x && lseek(fd1, 0, SEEK_SET))
618 fprintf(stderr, "lseek failed for %s\n", bname);
619 }
620 if (opt_B && x < bss) {
621 if ((n = read(fd1, img, bpb.bps)) == -1)
622 fprintf(stderr, "%s\n", bname);
623 if (n != bpb.bps)
624 fprintf(stderr, "%s: can't read sector %u\n", bname, x);
625 } else
626 memset(img, 0, bpb.bps);
627 if (!lsn ||
628 (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
629 x1 = BS_SIZE;
630 bsbpb = (struct bsbpb *)(img + x1);
631 mk2(bsbpb->bps, bpb.bps);
632 mk1(bsbpb->spc, bpb.spc);
633 mk2(bsbpb->res, bpb.res);
634 mk1(bsbpb->nft, bpb.nft);
635 mk2(bsbpb->rde, bpb.rde);
636 mk2(bsbpb->sec, bpb.sec);
637 mk1(bsbpb->mid, bpb.mid);
638 mk2(bsbpb->spf, bpb.spf);
639 mk2(bsbpb->spt, bpb.spt);
640 mk2(bsbpb->hds, bpb.hds);
641 mk4(bsbpb->hid, bpb.hid);
642 mk4(bsbpb->bsec, bpb.bsec);
643 x1 += BSBPB_SIZE;
644 if (fat == 32) {
645 bsxbpb = (struct bsxbpb *)(img + x1);
646 mk4(bsxbpb->bspf, bpb.bspf);
647 mk2(bsxbpb->xflg, 0);
648 mk2(bsxbpb->vers, 0);
649 mk4(bsxbpb->rdcl, bpb.rdcl);
650 mk2(bsxbpb->infs, bpb.infs);
651 mk2(bsxbpb->bkbs, bpb.bkbs);
652 x1 += BSXBPB_SIZE;
653 }
654 bsx = (struct bsx *)(img + x1);
655 mk1(bsx->sig, 0x29);
656 if (Iflag)
657 x = opt_I;
658 else
659 x = (((u_int)(1 + tm->tm_mon) << 8 |
660 (u_int)tm->tm_mday) +
661 ((u_int)tm->tm_sec << 8 |
662 (u_int)(tv.tv_usec / 10))) << 16 |
663 ((u_int)(1900 + tm->tm_year) +
664 ((u_int)tm->tm_hour << 8 |
665 (u_int)tm->tm_min));
666 mk4(bsx->volid, x);
667 mklabel(bsx->label, opt_L ? opt_L : "NO_NAME");
668 snprintf(buf, sizeof(buf), "FAT%u", fat);
669 setstr(bsx->type, buf, sizeof(bsx->type));
670 if (!opt_B) {
671 x1 += BSX_SIZE;
672 bs = (struct bs *)img;
673 mk1(bs->jmp[0], 0xeb);
674 mk1(bs->jmp[1], x1 - 2);
675 mk1(bs->jmp[2], 0x90);
676 setstr(bs->oem, opt_O ? opt_O : "NetBSD",
677 sizeof(bs->oem));
678 memcpy(img + x1, bootcode, sizeof(bootcode));
679 mk2(img + bpb.bps - 2, DOSMAGIC);
680 }
681 } else if (fat == 32 && bpb.infs != MAXU16 &&
682 (lsn == bpb.infs ||
683 (bpb.bkbs != MAXU16 &&
684 lsn == bpb.bkbs + bpb.infs))) {
685 mk4(img, 0x41615252);
686 mk4(img + bpb.bps - 28, 0x61417272);
687 mk4(img + bpb.bps - 24, 0xffffffff);
688 mk4(img + bpb.bps - 20, bpb.rdcl);
689 mk2(img + bpb.bps - 2, DOSMAGIC);
690 } else if (lsn >= bpb.res && lsn < dir &&
691 !((lsn - bpb.res) %
692 (bpb.spf ? bpb.spf : bpb.bspf))) {
693 mk1(img[0], bpb.mid);
694 for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
695 mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
696 } else if (lsn == dir && opt_L) {
697 de = (struct de *)img;
698 mklabel(de->namext, opt_L);
699 mk1(de->attr, 050);
700 x = (u_int)tm->tm_hour << 11 |
701 (u_int)tm->tm_min << 5 |
702 (u_int)tm->tm_sec >> 1;
703 mk2(de->time, x);
704 x = (u_int)(tm->tm_year - 80) << 9 |
705 (u_int)(tm->tm_mon + 1) << 5 |
706 (u_int)tm->tm_mday;
707 mk2(de->date, x);
708 }
709 if ((n = write(fd, img, bpb.bps)) == -1)
710 fprintf(stderr, "%s\n", fname);
711 if (n != bpb.bps)
712 fprintf(stderr, "%s: can't write sector %u\n", fname, lsn);
713 }
714 }
715 return 0;
716 }
717
718 /*
719 * Print out BPB values.
720 */
721 static void
722 print_bpb(struct bpb *bpb)
723 {
724 printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
725 bpb->nft);
726 if (bpb->rde)
727 printf(" rde=%u", bpb->rde);
728 if (bpb->sec)
729 printf(" sec=%u", bpb->sec);
730 printf(" mid=%#x", bpb->mid);
731 if (bpb->spf)
732 printf(" spf=%u", bpb->spf);
733 printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
734 if (bpb->bsec)
735 printf(" bsec=%u", bpb->bsec);
736 if (!bpb->spf) {
737 printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
738 printf(" infs=");
739 printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
740 printf(" bkbs=");
741 printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
742 }
743 printf("\n");
744 }
745
746 /*
747 * Check a disk geometry value.
748 */
749 static u_int
750 ckgeom(const char *fname, u_int val, const char *msg)
751 {
752 if (!val)
753 fprintf(stderr, "%s: no default %s\n", fname, msg);
754 if (val > MAXU16)
755 fprintf(stderr, "%s: illegal %s\n", fname, msg);
756 return val;
757 }
758
759 /*
760 * Convert and check a numeric option argument.
761 */
762 static u_int
763 argtou(const char *arg, u_int lo, u_int hi, const char *msg)
764 {
765 char *s;
766 u_long x;
767
768 errno = 0;
769 x = strtoul(arg, &s, 0);
770 if (errno || !*arg || *s || x < lo || x > hi)
771 fprintf(stderr, "%s: bad %s\n", arg, msg);
772 return x;
773 }
774
775 /*
776 * Check a volume label.
777 */
778 static int
779 oklabel(const char *src)
780 {
781 int c, i;
782
783 for (i = 0; i <= 11; i++) {
784 c = (u_char)*src++;
785 if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
786 break;
787 }
788 return i && !c;
789 }
790
791 /*
792 * Make a volume label.
793 */
794 static void
795 mklabel(u_int8_t *dest, const char *src)
796 {
797 int c, i;
798
799 for (i = 0; i < 11; i++) {
800 c = *src ? toupper((unsigned char)*src++) : ' ';
801 *dest++ = !i && c == '\xe5' ? 5 : c;
802 }
803 }
804
805 /*
806 * Copy string, padding with spaces.
807 */
808 static void
809 setstr(u_int8_t *dest, const char *src, size_t len)
810 {
811 while (len--)
812 *dest++ = *src ? *src++ : ' ';
813 }
814
815 /*
816 * Print usage message.
817 */
818 static void
819 usage(char* progname)
820 {
821 fprintf(stderr,
822 "usage: %s [ -options ] special [disktype]\n", progname);
823 fprintf(stderr, "where the options are:\n");
824 fprintf(stderr, "\t-N don't create file system: "
825 "just print out parameters\n");
826 fprintf(stderr, "\t-B get bootstrap from file\n");
827 fprintf(stderr, "\t-F FAT type (12, 16, or 32)\n");
828 fprintf(stderr, "\t-I volume ID\n");
829 fprintf(stderr, "\t-L volume label\n");
830 fprintf(stderr, "\t-O OEM string\n");
831 fprintf(stderr, "\t-S bytes/sector\n");
832 fprintf(stderr, "\t-a sectors/FAT\n");
833 fprintf(stderr, "\t-b block size\n");
834 fprintf(stderr, "\t-c sectors/cluster\n");
835 fprintf(stderr, "\t-e root directory entries\n");
836 fprintf(stderr, "\t-h drive heads\n");
837 fprintf(stderr, "\t-i file system info sector\n");
838 fprintf(stderr, "\t-k backup boot sector\n");
839 fprintf(stderr, "\t-m media descriptor\n");
840 fprintf(stderr, "\t-n number of FATs\n");
841 fprintf(stderr, "\t-o hidden sectors\n");
842 fprintf(stderr, "\t-r reserved sectors\n");
843 fprintf(stderr, "\t-s file system size (sectors)\n");
844 fprintf(stderr, "\t-u sectors/track\n");
845 exit(1);
846 }
847
848
+0
-273
toolbox/mount.c less more
0 /*
1 * mount.c, by rmk
2 */
3
4 #include <sys/mount.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include <linux/loop.h>
14
15 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
16
17 // FIXME - only one loop mount is supported at a time
18 #define LOOP_DEVICE "/dev/block/loop0"
19
20 struct mount_opts {
21 const char str[8];
22 unsigned long rwmask;
23 unsigned long rwset;
24 unsigned long rwnoset;
25 };
26
27 struct extra_opts {
28 char *str;
29 char *end;
30 int used_size;
31 int alloc_size;
32 };
33
34 /*
35 * These options define the function of "mount(2)".
36 */
37 #define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
38
39
40 static const struct mount_opts options[] = {
41 /* name mask set noset */
42 { "async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS },
43 { "atime", MS_NOATIME, 0, MS_NOATIME },
44 { "bind", MS_TYPE, MS_BIND, 0, },
45 { "dev", MS_NODEV, 0, MS_NODEV },
46 { "diratime", MS_NODIRATIME, 0, MS_NODIRATIME },
47 { "dirsync", MS_DIRSYNC, MS_DIRSYNC, 0 },
48 { "exec", MS_NOEXEC, 0, MS_NOEXEC },
49 { "move", MS_TYPE, MS_MOVE, 0 },
50 { "recurse", MS_REC, MS_REC, 0 },
51 { "remount", MS_TYPE, MS_REMOUNT, 0 },
52 { "ro", MS_RDONLY, MS_RDONLY, 0 },
53 { "rw", MS_RDONLY, 0, MS_RDONLY },
54 { "suid", MS_NOSUID, 0, MS_NOSUID },
55 { "sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0 },
56 { "verbose", MS_VERBOSE, MS_VERBOSE, 0 },
57 };
58
59 static void add_extra_option(struct extra_opts *extra, char *s)
60 {
61 int len = strlen(s);
62 int newlen = extra->used_size + len;
63
64 if (extra->str)
65 len++; /* +1 for ',' */
66
67 if (newlen >= extra->alloc_size) {
68 char *new;
69
70 new = realloc(extra->str, newlen + 1); /* +1 for NUL */
71 if (!new)
72 return;
73
74 extra->str = new;
75 extra->end = extra->str + extra->used_size;
76 extra->alloc_size = newlen;
77 }
78
79 if (extra->used_size) {
80 *extra->end = ',';
81 extra->end++;
82 }
83 strcpy(extra->end, s);
84 extra->used_size += len;
85
86 }
87
88 static unsigned long
89 parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop)
90 {
91 char *s;
92
93 *loop = 0;
94 while ((s = strsep(&arg, ",")) != NULL) {
95 char *opt = s;
96 unsigned int i;
97 int res, no = s[0] == 'n' && s[1] == 'o';
98
99 if (no)
100 s += 2;
101
102 if (strcmp(s, "loop") == 0) {
103 *loop = 1;
104 continue;
105 }
106 for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
107 res = strcmp(s, options[i].str);
108
109 if (res == 0) {
110 rwflag &= ~options[i].rwmask;
111 if (no)
112 rwflag |= options[i].rwnoset;
113 else
114 rwflag |= options[i].rwset;
115 }
116 if (res <= 0)
117 break;
118 }
119
120 if (res != 0 && s[0])
121 add_extra_option(extra, opt);
122 }
123
124 return rwflag;
125 }
126
127 static char *progname;
128
129 static struct extra_opts extra;
130 static unsigned long rwflag;
131
132 static int
133 do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int loop)
134 {
135 char *s;
136 int error = 0;
137
138 if (loop) {
139 int file_fd, device_fd;
140
141 // FIXME - only one loop mount supported at a time
142 file_fd = open(dev, O_RDWR);
143 if (file_fd < -1) {
144 perror("open backing file failed");
145 return 1;
146 }
147 device_fd = open(LOOP_DEVICE, O_RDWR);
148 if (device_fd < -1) {
149 perror("open loop device failed");
150 close(file_fd);
151 return 1;
152 }
153 if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
154 perror("ioctl LOOP_SET_FD failed");
155 close(file_fd);
156 close(device_fd);
157 return 1;
158 }
159
160 close(file_fd);
161 close(device_fd);
162 dev = LOOP_DEVICE;
163 }
164
165 while ((s = strsep(&type, ",")) != NULL) {
166 retry:
167 if (mount(dev, dir, s, rwflag, data) == -1) {
168 error = errno;
169 /*
170 * If the filesystem is not found, or the
171 * superblock is invalid, try the next.
172 */
173 if (error == ENODEV || error == EINVAL)
174 continue;
175
176 /*
177 * If we get EACCESS, and we're trying to
178 * mount readwrite and this isn't a remount,
179 * try read only.
180 */
181 if (error == EACCES &&
182 (rwflag & (MS_REMOUNT|MS_RDONLY)) == 0) {
183 rwflag |= MS_RDONLY;
184 goto retry;
185 }
186 break;
187 }
188 }
189
190 if (error) {
191 errno = error;
192 perror("mount");
193 return 255;
194 }
195
196 return 0;
197 }
198
199 static int print_mounts()
200 {
201 FILE* f;
202 int length;
203 char buffer[100];
204
205 f = fopen("/proc/mounts", "r");
206 if (!f) {
207 fprintf(stdout, "could not open /proc/mounts\n");
208 return -1;
209 }
210
211 do {
212 length = fread(buffer, 1, 100, f);
213 if (length > 0)
214 fwrite(buffer, 1, length, stdout);
215 } while (length > 0);
216
217 fclose(f);
218 return 0;
219 }
220
221 int mount_main(int argc, char *argv[])
222 {
223 char *type = NULL;
224 int c;
225 int loop;
226
227 progname = argv[0];
228 rwflag = MS_VERBOSE;
229
230 // mount with no arguments is equivalent to "cat /proc/mounts"
231 if (argc == 1) return print_mounts();
232
233 do {
234 c = getopt(argc, argv, "o:rt:w");
235 if (c == EOF)
236 break;
237 switch (c) {
238 case 'o':
239 rwflag = parse_mount_options(optarg, rwflag, &extra, &loop);
240 break;
241 case 'r':
242 rwflag |= MS_RDONLY;
243 break;
244 case 't':
245 type = optarg;
246 break;
247 case 'w':
248 rwflag &= ~MS_RDONLY;
249 break;
250 case '?':
251 fprintf(stderr, "%s: invalid option -%c\n",
252 progname, optopt);
253 exit(1);
254 }
255 } while (1);
256
257 /*
258 * If remount, bind or move was specified, then we don't
259 * have a "type" as such. Use the dummy "none" type.
260 */
261 if (rwflag & MS_TYPE)
262 type = "none";
263
264 if (optind + 2 != argc || type == NULL) {
265 fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] "
266 "device directory\n", progname);
267 exit(1);
268 }
269
270 return do_mount(argv[optind], argv[optind + 1], type, rwflag,
271 extra.str, loop);
272 }
+0
-59
toolbox/mv.c less more
0 #include <stdio.h>
1 #include <string.h>
2 #include <errno.h>
3 #include <limits.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6
7
8 int mv_main(int argc, char *argv[])
9 {
10 const char* dest;
11 struct stat st;
12 int i;
13
14 if (argc < 3) {
15 fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]);
16 return -1;
17 }
18
19 /* check if destination exists */
20 dest = argv[argc - 1];
21 if (stat(dest, &st)) {
22 /* an error, unless the destination was missing */
23 if (errno != ENOENT) {
24 fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno));
25 return -1;
26 }
27 st.st_mode = 0;
28 }
29
30 for (i = 1; i < argc - 1; i++) {
31 const char *source = argv[i];
32 char fullDest[PATH_MAX + 1 + PATH_MAX + 1];
33 /* assume we build "dest/source", and let rename() fail on pathsize */
34 if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) {
35 fprintf(stderr, "path too long\n");
36 return -1;
37 }
38 strcpy(fullDest, dest);
39
40 /* if destination is a directory, concat the source file name */
41 if (S_ISDIR(st.st_mode)) {
42 const char *fileName = strrchr(source, '/');
43 if (fullDest[strlen(fullDest)-1] != '/') {
44 strcat(fullDest, "/");
45 }
46 strcat(fullDest, fileName ? fileName + 1 : source);
47 }
48
49 /* attempt to move it */
50 if (rename(source, fullDest)) {
51 fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno));
52 return -1;
53 }
54 }
55
56 return 0;
57 }
58
+0
-120
toolbox/netstat.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33
34 typedef union iaddr iaddr;
35
36 union iaddr {
37 unsigned u;
38 unsigned char b[4];
39 };
40
41 static const char *state2str(unsigned state)
42 {
43 switch(state){
44 case 0x1: return "ESTABLISHED";
45 case 0x2: return "SYN_SENT";
46 case 0x3: return "SYN_RECV";
47 case 0x4: return "FIN_WAIT1";
48 case 0x5: return "FIN_WAIT2";
49 case 0x6: return "TIME_WAIT";
50 case 0x7: return "CLOSE";
51 case 0x8: return "CLOSE_WAIT";
52 case 0x9: return "LAST_ACK";
53 case 0xA: return "LISTEN";
54 case 0xB: return "CLOSING";
55 default: return "UNKNOWN";
56 }
57 }
58
59 void addr2str(iaddr addr, unsigned port, char *buf)
60 {
61 if(port) {
62 snprintf(buf, 64, "%d.%d.%d.%d:%d",
63 addr.b[0], addr.b[1], addr.b[2], addr.b[3], port);
64 } else {
65 snprintf(buf, 64, "%d.%d.%d.%d:*",
66 addr.b[0], addr.b[1], addr.b[2], addr.b[3]);
67 }
68 }
69
70 int netstat_main(int argc, char *argv[])
71 {
72 char buf[512];
73 char lip[64];
74 char rip[64];
75 iaddr laddr, raddr;
76 unsigned lport, rport, state, txq, rxq, num;
77 int n;
78 FILE *fp;
79
80 printf("Proto Recv-Q Send-Q Local Address Foreign Address State\n");
81
82 fp = fopen("/proc/net/tcp", "r");
83 if(fp != 0) {
84 fgets(buf, 512, fp);
85 while(fgets(buf, 512, fp)){
86 n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
87 &num, &laddr.u, &lport, &raddr.u, &rport,
88 &state, &txq, &rxq);
89 if(n == 8) {
90 addr2str(laddr, lport, lip);
91 addr2str(raddr, rport, rip);
92
93 printf("tcp %6d %6d %-22s %-22s %s\n",
94 txq, rxq, lip, rip,
95 state2str(state));
96 }
97 }
98 fclose(fp);
99 }
100 fp = fopen("/proc/net/udp", "r");
101 if(fp != 0) {
102 fgets(buf, 512, fp);
103 while(fgets(buf, 512, fp)){
104 n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
105 &num, &laddr.u, &lport, &raddr.u, &rport,
106 &state, &txq, &rxq);
107 if(n == 8) {
108 addr2str(laddr, lport, lip);
109 addr2str(raddr, rport, rip);
110
111 printf("udp %6d %6d %-22s %-22s\n",
112 txq, rxq, lip, rip);
113 }
114 }
115 fclose(fp);
116 }
117
118 return 0;
119 }
+0
-144
toolbox/notify.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6 #include <sys/inotify.h>
7 #include <errno.h>
8
9 int notify_main(int argc, char *argv[])
10 {
11 int c;
12 int nfd, ffd;
13 int res;
14 char event_buf[512];
15 struct inotify_event *event;
16 int event_mask = IN_ALL_EVENTS;
17 int event_count = 1;
18 int print_files = 0;
19 int verbose = 2;
20 int width = 80;
21 char **file_names;
22 int file_count;
23 int id_offset = 0;
24 int i;
25 char *buf;
26
27 do {
28 c = getopt(argc, argv, "m:c:pv:w:");
29 if (c == EOF)
30 break;
31 switch (c) {
32 case 'm':
33 event_mask = strtol(optarg, NULL, 0);
34 break;
35 case 'c':
36 event_count = atoi(optarg);
37 break;
38 case 'p':
39 print_files = 1;
40 break;
41 case 'v':
42 verbose = atoi(optarg);
43 break;
44 case 'w':
45 width = atoi(optarg);
46 break;
47 case '?':
48 fprintf(stderr, "%s: invalid option -%c\n",
49 argv[0], optopt);
50 exit(1);
51 }
52 } while (1);
53
54 if (argc <= optind) {
55 fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]);
56 return 1;
57 }
58
59 nfd = inotify_init();
60 if(nfd < 0) {
61 fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
62 return 1;
63 }
64 file_names = argv + optind;
65 file_count = argc - optind;
66 for(i = 0; i < file_count; i++) {
67 res = inotify_add_watch(nfd, file_names[i], event_mask);
68 if(res < 0) {
69 fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno));
70 return 1;
71 }
72 if(i == 0)
73 id_offset = -res;
74 if(res + id_offset != i) {
75 fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i);
76 return 1;
77 }
78 }
79
80 buf = malloc(width + 2);
81
82 while(1) {
83 int event_pos = 0;
84 res = read(nfd, event_buf, sizeof(event_buf));
85 if(res < (int)sizeof(*event)) {
86 if(errno == EINTR)
87 continue;
88 fprintf(stderr, "could not get event, %s\n", strerror(errno));
89 return 1;
90 }
91 //printf("got %d bytes of event information\n", res);
92 while(res >= (int)sizeof(*event)) {
93 int event_size;
94 event = (struct inotify_event *)(event_buf + event_pos);
95 if(verbose >= 2)
96 printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : "");
97 else if(verbose >= 2)
98 printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : "");
99 else if(verbose >= 1)
100 printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
101 if(print_files && (event->mask & IN_MODIFY)) {
102 char filename[512];
103 ssize_t read_len;
104 char *display_name;
105 int buflen;
106 strcpy(filename, file_names[event->wd + id_offset]);
107 if(event->len) {
108 strcat(filename, "/");
109 strcat(filename, event->name);
110 }
111 ffd = open(filename, O_RDONLY);
112 display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
113 buflen = width - strlen(display_name);
114 read_len = read(ffd, buf, buflen);
115 if(read_len > 0) {
116 if(read_len < buflen && buf[read_len-1] != '\n') {
117 buf[read_len] = '\n';
118 read_len++;
119 }
120 if(read_len == buflen) {
121 buf[--read_len] = '\0';
122 buf[--read_len] = '\n';
123 buf[--read_len] = '.';
124 buf[--read_len] = '.';
125 buf[--read_len] = '.';
126 }
127 else {
128 buf[read_len] = '\0';
129 }
130 printf("%s: %s", display_name, buf);
131 }
132 close(ffd);
133 }
134 if(event_count && --event_count == 0)
135 return 0;
136 event_size = sizeof(*event) + event->len;
137 res -= event_size;
138 event_pos += event_size;
139 }
140 }
141
142 return 0;
143 }
+0
-441
toolbox/powerd.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <time.h>
6 #include <sys/select.h>
7 #include <sys/inotify.h>
8
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
10
11 //#include <linux/input.h> // this does not compile
12
13 // from <linux/input.h>
14
15 struct input_event {
16 struct timeval time;
17 __u16 type;
18 __u16 code;
19 __s32 value;
20 };
21
22 #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
23 #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
24 #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
25 #define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
26
27 #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
28 #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
29 #define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
30
31 #define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
32 #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
33 #define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
34 #define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
35
36 #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
37 #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
38 #define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
39
40 #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
41 #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
42 #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
43
44 #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
45
46 /*
47 * Event types
48 */
49
50 #define EV_SYN 0x00
51 #define EV_KEY 0x01
52 #define EV_REL 0x02
53 #define EV_ABS 0x03
54 #define EV_MSC 0x04
55 #define EV_SW 0x05
56 #define EV_LED 0x11
57 #define EV_SND 0x12
58 #define EV_REP 0x14
59 #define EV_FF 0x15
60 #define EV_PWR 0x16
61 #define EV_FF_STATUS 0x17
62 #define EV_MAX 0x1f
63
64 #define KEY_POWER 116
65 #define KEY_SLEEP 142
66 #define SW_0 0x00
67
68 // end <linux/input.h>
69
70 struct notify_entry {
71 int id;
72 int (*handler)(struct notify_entry *entry, struct inotify_event *event);
73 const char *filename;
74 };
75
76 int charging_state_notify_handler(struct notify_entry *entry, struct inotify_event *event)
77 {
78 static int state = -1;
79 int last_state;
80 char buf[40];
81 int read_len;
82 int fd;
83
84 last_state = state;
85 fd = open(entry->filename, O_RDONLY);
86 read_len = read(fd, buf, sizeof(buf));
87 if(read_len > 0) {
88 //printf("charging_state_notify_handler: \"%s\"\n", buf);
89 state = !(strncmp(buf, "Unknown", 7) == 0
90 || strncmp(buf, "Discharging", 11) == 0);
91 }
92 close(fd);
93 //printf("charging_state_notify_handler: %d -> %d\n", last_state, state);
94 return state > last_state;
95 }
96
97 struct notify_entry watched_files[] = {
98 {
99 .filename = "/sys/android_power/charging_state",
100 .handler = charging_state_notify_handler
101 }
102 };
103
104 int call_notify_handler(struct inotify_event *event)
105 {
106 unsigned int start, i;
107 start = event->wd - watched_files[0].id;
108 if(start >= ARRAY_SIZE(watched_files))
109 start = 0;
110 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
111 for(i = start; i < ARRAY_SIZE(watched_files); i++) {
112 if(event->wd == watched_files[i].id) {
113 if(watched_files[i].handler) {
114 return watched_files[i].handler(&watched_files[i], event);
115 }
116 return 1;
117 }
118 }
119 for(i = 0; i < start; i++) {
120 if(event->wd == watched_files[i].id) {
121 if(watched_files[i].handler) {
122 return watched_files[i].handler(&watched_files[i], event);
123 }
124 return 1;
125 }
126 }
127 return 0;
128 }
129
130 int handle_inotify_event(int nfd)
131 {
132 int res;
133 int wake_up = 0;
134 struct inotify_event *event;
135 char event_buf[512];
136 int event_pos = 0;
137
138 res = read(nfd, event_buf, sizeof(event_buf));
139 if(res < (int)sizeof(*event)) {
140 if(errno == EINTR)
141 return 0;
142 fprintf(stderr, "could not get event, %s\n", strerror(errno));
143 return 0;
144 }
145 printf("got %d bytes of event information\n", res);
146 while(res >= (int)sizeof(*event)) {
147 int event_size;
148 event = (struct inotify_event *)(event_buf + event_pos);
149 wake_up |= call_notify_handler(event);
150 event_size = sizeof(*event) + event->len;
151 res -= event_size;
152 event_pos += event_size;
153 }
154 return wake_up;
155 }
156
157 int powerd_main(int argc, char *argv[])
158 {
159 int c;
160 unsigned int i;
161 int res;
162 struct timeval tv;
163 int eventfd;
164 int notifyfd;
165 int powerfd;
166 int powerfd_is_sleep;
167 int user_activity_fd;
168 int acquire_partial_wake_lock_fd;
169 int acquire_full_wake_lock_fd;
170 int release_wake_lock_fd;
171 char *eventdev = "/dev/input/event0";
172 const char *android_sleepdev = "/sys/android_power/request_sleep";
173 const char *android_autooff_dev = "/sys/android_power/auto_off_timeout";
174 const char *android_user_activity_dev = "/sys/android_power/last_user_activity";
175 const char *android_acquire_partial_wake_lock_dev = "/sys/android_power/acquire_partial_wake_lock";
176 const char *android_acquire_full_wake_lock_dev = "/sys/android_power/acquire_full_wake_lock";
177 const char *android_release_wake_lock_dev = "/sys/android_power/release_wake_lock";
178 const char *powerdev = "/sys/power/state";
179 const char suspendstring[] = "standby";
180 const char wakelockstring[] = "powerd";
181 fd_set rfds;
182 struct input_event event;
183 struct input_event light_event;
184 struct input_event light_event2;
185 int gotkey = 1;
186 time_t idle_time = 5;
187 const char *idle_time_string = "5";
188 time_t lcd_light_time = 0;
189 time_t key_light_time = 0;
190 int verbose = 1;
191 int event_sleep = 0;
192 int got_power_key_down = 0;
193 struct timeval power_key_down_time = { 0, 0 };
194
195 light_event.type = EV_LED;
196 light_event.code = 4; // bright lcd backlight
197 light_event.value = 0; // light off -- sleep after timeout
198
199 light_event2.type = EV_LED;
200 light_event2.code = 8; // keyboard backlight
201 light_event2.value = 0; // light off -- sleep after timeout
202
203 do {
204 c = getopt(argc, argv, "e:ni:vql:k:");
205 if (c == EOF)
206 break;
207 switch (c) {
208 case 'e':
209 eventdev = optarg;
210 break;
211 case 'n':
212 gotkey = 0;
213 break;
214 case 'i':
215 idle_time = atoi(optarg);
216 idle_time_string = optarg;
217 break;
218 case 'v':
219 verbose = 2;
220 break;
221 case 'q':
222 verbose = 0;
223 break;
224 case 'l':
225 lcd_light_time = atoi(optarg);
226 break;
227 case 'k':
228 key_light_time = atoi(optarg);
229 break;
230 case '?':
231 fprintf(stderr, "%s: invalid option -%c\n",
232 argv[0], optopt);
233 exit(1);
234 }
235 } while (1);
236 if(optind != argc) {
237 fprintf(stderr,"%s [-e eventdev]\n", argv[0]);
238 return 1;
239 }
240
241 eventfd = open(eventdev, O_RDWR | O_NONBLOCK);
242 if(eventfd < 0) {
243 fprintf(stderr, "could not open %s, %s\n", eventdev, strerror(errno));
244 return 1;
245 }
246 if(key_light_time >= lcd_light_time) {
247 lcd_light_time = key_light_time + 1;
248 fprintf(stderr,"lcd bright backlight time must be longer than keyboard backlight time.\n"
249 "Setting lcd bright backlight time to %ld seconds\n", lcd_light_time);
250 }
251
252 user_activity_fd = open(android_user_activity_dev, O_RDWR);
253 if(user_activity_fd >= 0) {
254 int auto_off_fd = open(android_autooff_dev, O_RDWR);
255 write(auto_off_fd, idle_time_string, strlen(idle_time_string));
256 close(auto_off_fd);
257 }
258
259 powerfd = open(android_sleepdev, O_RDWR);
260 if(powerfd >= 0) {
261 powerfd_is_sleep = 1;
262 if(verbose > 0)
263 printf("Using android sleep dev: %s\n", android_sleepdev);
264 }
265 else {
266 powerfd_is_sleep = 0;
267 powerfd = open(powerdev, O_RDWR);
268 if(powerfd >= 0) {
269 if(verbose > 0)
270 printf("Using linux power dev: %s\n", powerdev);
271 }
272 }
273 if(powerfd < 0) {
274 fprintf(stderr, "could not open %s, %s\n", powerdev, strerror(errno));
275 return 1;
276 }
277
278 notifyfd = inotify_init();
279 if(notifyfd < 0) {
280 fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
281 return 1;
282 }
283 fcntl(notifyfd, F_SETFL, O_NONBLOCK | fcntl(notifyfd, F_GETFL));
284 for(i = 0; i < ARRAY_SIZE(watched_files); i++) {
285 watched_files[i].id = inotify_add_watch(notifyfd, watched_files[i].filename, IN_MODIFY);
286 printf("Watching %s, id %d\n", watched_files[i].filename, watched_files[i].id);
287 }
288
289 acquire_partial_wake_lock_fd = open(android_acquire_partial_wake_lock_dev, O_RDWR);
290 acquire_full_wake_lock_fd = open(android_acquire_full_wake_lock_dev, O_RDWR);
291 release_wake_lock_fd = open(android_release_wake_lock_dev, O_RDWR);
292
293 if(user_activity_fd >= 0) {
294 idle_time = 60*60*24; // driver handles real timeout
295 }
296 if(gotkey) {
297 tv.tv_sec = idle_time;
298 tv.tv_usec = 0;
299 }
300 else {
301 tv.tv_sec = 0;
302 tv.tv_usec = 500000;
303 }
304
305 while(1) {
306 FD_ZERO(&rfds);
307 //FD_SET(0, &rfds);
308 FD_SET(eventfd, &rfds);
309 FD_SET(notifyfd, &rfds);
310 res = select(((notifyfd > eventfd) ? notifyfd : eventfd) + 1, &rfds, NULL, NULL, &tv);
311 if(res < 0) {
312 fprintf(stderr, "select failed, %s\n", strerror(errno));
313 return 1;
314 }
315 if(res == 0) {
316 if(light_event2.value == 1)
317 goto light2_off;
318 if(light_event.value == 1)
319 goto light_off;
320 if(user_activity_fd < 0) {
321 if(gotkey && verbose > 0)
322 printf("Idle - sleep\n");
323 if(!gotkey && verbose > 1)
324 printf("Reenter sleep\n");
325 goto sleep;
326 }
327 else {
328 tv.tv_sec = 60*60*24;
329 tv.tv_usec = 0;
330 }
331 }
332 if(res > 0) {
333 //if(FD_ISSET(0, &rfds)) {
334 // printf("goto data on stdin quit\n");
335 // return 0;
336 //}
337 if(FD_ISSET(notifyfd, &rfds)) {
338 write(acquire_partial_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
339 if(handle_inotify_event(notifyfd) > 0) {
340 write(acquire_full_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
341 }
342 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
343 }
344 if(FD_ISSET(eventfd, &rfds)) {
345 write(acquire_partial_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
346 res = read(eventfd, &event, sizeof(event));
347 if(res < (int)sizeof(event)) {
348 fprintf(stderr, "could not get event\n");
349 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
350 return 1;
351 }
352 if(event.type == EV_PWR && event.code == KEY_SLEEP) {
353 event_sleep = event.value;
354 }
355 if(event.type == EV_KEY || (event.type == EV_SW && event.code == SW_0 && event.value == 1)) {
356 gotkey = 1;
357 if(user_activity_fd >= 0) {
358 char buf[32];
359 int len;
360 len = sprintf(buf, "%ld%06lu000", event.time.tv_sec, event.time.tv_usec);
361 write(user_activity_fd, buf, len);
362 }
363 if(lcd_light_time | key_light_time) {
364 tv.tv_sec = key_light_time;
365 light_event.value = 1;
366 write(eventfd, &light_event, sizeof(light_event));
367 light_event2.value = 1;
368 write(eventfd, &light_event2, sizeof(light_event2));
369 }
370 else {
371 tv.tv_sec = idle_time;
372 }
373 tv.tv_usec = 0;
374 if(verbose > 1)
375 printf("got %s %s %d%s\n", event.type == EV_KEY ? "key" : "switch", event.value ? "down" : "up", event.code, event_sleep ? " from sleep" : "");
376 if(event.code == KEY_POWER) {
377 if(event.value == 0) {
378 int tmp_got_power_key_down = got_power_key_down;
379 got_power_key_down = 0;
380 if(tmp_got_power_key_down) {
381 // power key released
382 if(verbose > 0)
383 printf("Power key released - sleep\n");
384 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
385 goto sleep;
386 }
387 }
388 else if(event_sleep == 0) {
389 got_power_key_down = 1;
390 power_key_down_time = event.time;
391 }
392 }
393 }
394 if(event.type == EV_SW && event.code == SW_0 && event.value == 0) {
395 if(verbose > 0)
396 printf("Flip closed - sleep\n");
397 power_key_down_time = event.time;
398 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
399 goto sleep;
400 }
401 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
402 }
403 }
404 if(0) {
405 light_off:
406 light_event.value = 0;
407 write(eventfd, &light_event, sizeof(light_event));
408 tv.tv_sec = idle_time - lcd_light_time;
409 }
410 if(0) {
411 light2_off:
412 light_event2.value = 0;
413 write(eventfd, &light_event2, sizeof(light_event2));
414 tv.tv_sec = lcd_light_time - key_light_time;
415 }
416 if(0) {
417 sleep:
418 if(light_event.value == 1) {
419 light_event.value = 0;
420 write(eventfd, &light_event, sizeof(light_event));
421 light_event2.value = 0;
422 write(eventfd, &light_event2, sizeof(light_event2));
423 tv.tv_sec = idle_time - lcd_light_time;
424 }
425 if(powerfd_is_sleep) {
426 char buf[32];
427 int len;
428 len = sprintf(buf, "%ld%06lu000", power_key_down_time.tv_sec, power_key_down_time.tv_usec);
429 write(powerfd, buf, len);
430 }
431 else
432 write(powerfd, suspendstring, sizeof(suspendstring) - 1);
433 gotkey = 0;
434 tv.tv_sec = 0;
435 tv.tv_usec = 500000;
436 }
437 }
438
439 return 0;
440 }
+0
-29
toolbox/printenv.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2
3 extern char** environ;
4
5 int printenv_main (int argc, char **argv)
6 {
7 char** e;
8 char* v;
9 int i;
10
11 if (argc == 1) {
12 e = environ;
13 while (*e) {
14 printf("%s\n", *e);
15 e++;
16 }
17 } else {
18 for (i=1; i<argc; i++) {
19 v = getenv(argv[i]);
20 if (v) {
21 printf("%s\n", v);
22 }
23 }
24 }
25
26 return 0;
27 }
28
+0
-214
toolbox/ps.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <ctype.h>
3 #include <fcntl.h>
4
5 #include <string.h>
6
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <dirent.h>
10
11 #include <pwd.h>
12
13
14 static char *nexttoksep(char **strp, char *sep)
15 {
16 char *p = strsep(strp,sep);
17 return (p == 0) ? "" : p;
18 }
19 static char *nexttok(char **strp)
20 {
21 return nexttoksep(strp, " ");
22 }
23
24 #define SHOW_PRIO 1
25 #define SHOW_TIME 2
26
27 static int display_flags = 0;
28
29 static int ps_line(int pid, int tid, char *namefilter)
30 {
31 char statline[1024];
32 char cmdline[1024];
33 char user[32];
34 struct stat stats;
35 int fd, r;
36 char *ptr, *name, *state;
37 int ppid, tty;
38 unsigned wchan, rss, vss, eip;
39 unsigned utime, stime;
40 int prio, nice, rtprio, sched;
41 struct passwd *pw;
42
43 sprintf(statline, "/proc/%d", pid);
44 stat(statline, &stats);
45
46 if(tid) {
47 sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
48 cmdline[0] = 0;
49 } else {
50 sprintf(statline, "/proc/%d/stat", pid);
51 sprintf(cmdline, "/proc/%d/cmdline", pid);
52 fd = open(cmdline, O_RDONLY);
53 if(fd == 0) {
54 r = 0;
55 } else {
56 r = read(fd, cmdline, 1023);
57 close(fd);
58 if(r < 0) r = 0;
59 }
60 cmdline[r] = 0;
61 }
62
63 fd = open(statline, O_RDONLY);
64 if(fd == 0) return -1;
65 r = read(fd, statline, 1023);
66 close(fd);
67 if(r < 0) return -1;
68 statline[r] = 0;
69
70 ptr = statline;
71 nexttok(&ptr); // skip pid
72 ptr++; // skip "("
73
74 name = ptr;
75 ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
76 *ptr++ = '\0'; // and null-terminate name.
77
78 ptr++; // skip " "
79 state = nexttok(&ptr);
80 ppid = atoi(nexttok(&ptr));
81 nexttok(&ptr); // pgrp
82 nexttok(&ptr); // sid
83 tty = atoi(nexttok(&ptr));
84
85 nexttok(&ptr); // tpgid
86 nexttok(&ptr); // flags
87 nexttok(&ptr); // minflt
88 nexttok(&ptr); // cminflt
89 nexttok(&ptr); // majflt
90 nexttok(&ptr); // cmajflt
91 #if 1
92 utime = atoi(nexttok(&ptr));
93 stime = atoi(nexttok(&ptr));
94 #else
95 nexttok(&ptr); // utime
96 nexttok(&ptr); // stime
97 #endif
98 nexttok(&ptr); // cutime
99 nexttok(&ptr); // cstime
100 prio = atoi(nexttok(&ptr));
101 nice = atoi(nexttok(&ptr));
102 nexttok(&ptr); // threads
103 nexttok(&ptr); // itrealvalue
104 nexttok(&ptr); // starttime
105 vss = strtoul(nexttok(&ptr), 0, 10); // vsize
106 rss = strtoul(nexttok(&ptr), 0, 10); // rss
107 nexttok(&ptr); // rlim
108 nexttok(&ptr); // startcode
109 nexttok(&ptr); // endcode
110 nexttok(&ptr); // startstack
111 nexttok(&ptr); // kstkesp
112 eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
113 nexttok(&ptr); // signal
114 nexttok(&ptr); // blocked
115 nexttok(&ptr); // sigignore
116 nexttok(&ptr); // sigcatch
117 wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
118 nexttok(&ptr); // nswap
119 nexttok(&ptr); // cnswap
120 nexttok(&ptr); // exit signal
121 nexttok(&ptr); // processor
122 rtprio = atoi(nexttok(&ptr)); // rt_priority
123 sched = atoi(nexttok(&ptr)); // scheduling policy
124
125 tty = atoi(nexttok(&ptr));
126
127 if(tid != 0) {
128 ppid = pid;
129 pid = tid;
130 }
131
132 pw = getpwuid(stats.st_uid);
133 if(pw == 0) {
134 sprintf(user,"%d",(int)stats.st_uid);
135 } else {
136 strcpy(user,pw->pw_name);
137 }
138
139 if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
140 printf("%-8s %-5d %-5d %-5d %-5d", user, pid, ppid, vss / 1024, rss * 4);
141 if(display_flags&SHOW_PRIO)
142 printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
143 printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
144 if(display_flags&SHOW_TIME)
145 printf(" (u:%d, s:%d)", utime, stime);
146 printf("\n");
147 }
148 return 0;
149 }
150
151
152 void ps_threads(int pid, char *namefilter)
153 {
154 char tmp[128];
155 DIR *d;
156 struct dirent *de;
157
158 sprintf(tmp,"/proc/%d/task",pid);
159 d = opendir(tmp);
160 if(d == 0) return;
161
162 while((de = readdir(d)) != 0){
163 if(isdigit(de->d_name[0])){
164 int tid = atoi(de->d_name);
165 if(tid == pid) continue;
166 ps_line(pid, tid, namefilter);
167 }
168 }
169 closedir(d);
170 }
171
172 int ps_main(int argc, char **argv)
173 {
174 DIR *d;
175 struct dirent *de;
176 char *namefilter = 0;
177 int pidfilter = 0;
178 int threads = 0;
179
180 d = opendir("/proc");
181 if(d == 0) return -1;
182
183 while(argc > 1){
184 if(!strcmp(argv[1],"-t")) {
185 threads = 1;
186 } else if(!strcmp(argv[1],"-x")) {
187 display_flags |= SHOW_TIME;
188 } else if(!strcmp(argv[1],"-p")) {
189 display_flags |= SHOW_PRIO;
190 } else if(isdigit(argv[1][0])){
191 pidfilter = atoi(argv[1]);
192 } else {
193 namefilter = argv[1];
194 }
195 argc--;
196 argv++;
197 }
198
199 printf("USER PID PPID VSIZE RSS %sWCHAN PC NAME\n",
200 (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"");
201 while((de = readdir(d)) != 0){
202 if(isdigit(de->d_name[0])){
203 int pid = atoi(de->d_name);
204 if(!pidfilter || (pidfilter == pid)) {
205 ps_line(pid, 0, namefilter);
206 if(threads) ps_threads(pid, namefilter);
207 }
208 }
209 }
210 closedir(d);
211 return 0;
212 }
213
+0
-74
toolbox/r.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <sys/mman.h>
3 #include <fcntl.h>
4 #include <string.h>
5
6 static int usage()
7 {
8 fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
9 return -1;
10 }
11
12 int r_main(int argc, char *argv[])
13 {
14 int width = 4, set = 0, fd;
15 unsigned addr, value;
16 void *page;
17
18 if(argc < 2) return usage();
19
20 if(!strcmp(argv[1], "-b")) {
21 width = 1;
22 argc--;
23 argv++;
24 } else if(!strcmp(argv[1], "-s")) {
25 width = 2;
26 argc--;
27 argv++;
28 }
29
30 if(argc < 2) return usage();
31 addr = strtoul(argv[1], 0, 16);
32
33 if(argc > 2) {
34 set = 1;
35 value = strtoul(argv[2], 0, 16);
36 }
37
38 fd = open("/dev/mem", O_RDWR | O_SYNC);
39 if(fd < 0) {
40 fprintf(stderr,"cannot open /dev/mem\n");
41 return -1;
42 }
43
44 page = mmap(0, 8192, PROT_READ | PROT_WRITE,
45 MAP_SHARED, fd, addr & (~4095));
46
47 if(page == MAP_FAILED){
48 fprintf(stderr,"cannot mmap region\n");
49 return -1;
50 }
51
52 switch(width){
53 case 4: {
54 unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
55 if(set) *x = value;
56 fprintf(stderr,"%08x: %08x\n", addr, *x);
57 break;
58 }
59 case 2: {
60 unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
61 if(set) *x = value;
62 fprintf(stderr,"%08x: %04x\n", addr, *x);
63 break;
64 }
65 case 1: {
66 unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
67 if(set) *x = value;
68 fprintf(stderr,"%08x: %02x\n", addr, *x);
69 break;
70 }
71 }
72 return 0;
73 }
+0
-183
toolbox/readtty.c less more
0 #include <ctype.h>
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/mman.h>
4 #include <fcntl.h>
5 #include <string.h>
6 #include <termios.h>
7 #include <unistd.h>
8
9 struct {
10 char key;
11 char *chars;
12 } map[] = {
13 { '1', "_ -1?!,.:;\"'<=>()_" },
14 { '2', "Cabc2ABC" },
15 { '3', "Fdef3DEF" },
16 { '4', "Ighi4GHI" },
17 { '5', "Ljkl5JKL" },
18 { '6', "Omno6MNO" },
19 { '7', "Spqrs7PQRS" },
20 { '8', "Vtuv8TUV" },
21 { '9', "Zwxyz9WXYZ" },
22 { '0', "*+&0@/#*" },
23 };
24
25 char next_char(char key, char current)
26 {
27 int i;
28 char *next;
29 for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
30 if(key == map[i].key) {
31 next = strchr(map[i].chars, current);
32 if(next && next[1])
33 return next[1];
34 return map[i].chars[1];
35 }
36 }
37 return key;
38 }
39
40 char prev_char(char key, char current)
41 {
42 int i;
43 char *next;
44 for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
45 if(key == map[i].key) {
46 next = strchr(map[i].chars+1, current);
47 if(next && next[-1])
48 return next[-1];
49 return map[i].chars[1];
50 }
51 }
52 return key;
53 }
54
55 int readtty_main(int argc, char *argv[])
56 {
57 int c;
58 //int flags;
59 char buf[1];
60 int res;
61 struct termios ttyarg;
62 struct termios savedttyarg;
63 int nonblock = 0;
64 int timeout = 0;
65 int flush = 0;
66 int phone = 0;
67 char *accept = NULL;
68 char *rejectstring = NULL;
69 char last_char_in = 0;
70 char current_char = 0;
71 char *exit_string = NULL;
72 int exit_match = 0;
73
74 do {
75 c = getopt(argc, argv, "nt:fa:r:pe:");
76 if (c == EOF)
77 break;
78 switch (c) {
79 case 't':
80 timeout = atoi(optarg);
81 break;
82 case 'n':
83 nonblock = 1;
84 break;
85 case 'f':
86 flush = 1;
87 break;
88 case 'a':
89 accept = optarg;
90 break;
91 case 'r':
92 rejectstring = optarg;
93 break;
94 case 'p':
95 phone = 1;
96 break;
97 case 'e':
98 exit_string = optarg;
99 break;
100 case '?':
101 fprintf(stderr, "%s: invalid option -%c\n",
102 argv[0], optopt);
103 exit(1);
104 }
105 } while (1);
106
107 if(flush)
108 tcflush(STDIN_FILENO, TCIFLUSH);
109 ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ; /* set changed tty arguments */
110 ttyarg = savedttyarg;
111 ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1; /* minimum of 0 chars */
112 ttyarg.c_cc[VTIME] = timeout; /* wait max 15/10 sec */
113 ttyarg.c_iflag = BRKINT | ICRNL;
114 ttyarg.c_lflag &= ~(ECHO | ICANON);
115 ioctl(STDIN_FILENO, TCSETS , &ttyarg);
116
117 while (1) {
118 res = read(STDIN_FILENO, buf, 1);
119 if(res <= 0) {
120 if(phone) {
121 if(current_char) {
122 write(STDERR_FILENO, &current_char, 1);
123 write(STDOUT_FILENO, &current_char, 1);
124 if(exit_string && current_char == exit_string[exit_match]) {
125 exit_match++;
126 if(exit_string[exit_match] == '\0')
127 break;
128 }
129 else
130 exit_match = 0;
131 current_char = 0;
132 }
133 continue;
134 }
135 break;
136 }
137 if(accept && strchr(accept, buf[0]) == NULL) {
138 if(rejectstring) {
139 write(STDOUT_FILENO, rejectstring, strlen(rejectstring));
140 break;
141 }
142 if(flush)
143 tcflush(STDIN_FILENO, TCIFLUSH);
144 continue;
145 }
146 if(phone) {
147 //if(!isprint(buf[0])) {
148 // fprintf(stderr, "got unprintable character 0x%x\n", buf[0]);
149 //}
150 if(buf[0] == '\0') {
151 if(current_char) {
152 current_char = prev_char(last_char_in, current_char);
153 write(STDERR_FILENO, &current_char, 1);
154 write(STDERR_FILENO, "\b", 1);
155 }
156 continue;
157 }
158 if(current_char && buf[0] != last_char_in) {
159 write(STDERR_FILENO, &current_char, 1);
160 write(STDOUT_FILENO, &current_char, 1);
161 if(exit_string && current_char == exit_string[exit_match]) {
162 exit_match++;
163 if(exit_string[exit_match] == '\0')
164 break;
165 }
166 else
167 exit_match = 0;
168 current_char = 0;
169 }
170 last_char_in = buf[0];
171 current_char = next_char(last_char_in, current_char);
172 write(STDERR_FILENO, &current_char, 1);
173 write(STDERR_FILENO, "\b", 1);
174 continue;
175 }
176 write(STDOUT_FILENO, buf, 1);
177 break;
178 }
179 ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ; /* set changed tty arguments */
180
181 return 0;
182 }
+0
-56
toolbox/reboot.c less more
0 #include <errno.h>
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/reboot.h>
4 #include <unistd.h>
5
6 int reboot_main(int argc, char *argv[])
7 {
8 int ret;
9 int nosync = 0;
10 int poweroff = 0;
11
12 opterr = 0;
13 do {
14 int c;
15
16 c = getopt(argc, argv, "np");
17
18 if (c == EOF) {
19 break;
20 }
21
22 switch (c) {
23 case 'n':
24 nosync = 1;
25 break;
26 case 'p':
27 poweroff = 1;
28 break;
29 case '?':
30 fprintf(stderr, "usage: %s [-n] [-p] [rebootcommand]\n", argv[0]);
31 exit(EXIT_FAILURE);
32 }
33 } while (1);
34
35 if(argc > optind + 1) {
36 fprintf(stderr, "%s: too many arguments\n", argv[0]);
37 exit(EXIT_FAILURE);
38 }
39
40 if(!nosync)
41 sync();
42
43 if(poweroff)
44 ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
45 else if(argc > optind)
46 ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
47 else
48 ret = reboot(RB_AUTOBOOT);
49 if(ret < 0) {
50 perror("reboot");
51 exit(EXIT_FAILURE);
52 }
53 fprintf(stderr, "reboot returned\n");
54 return 0;
55 }
+0
-144
toolbox/renice.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sched.h>
37
38 static void
39 usage(const char *s)
40 {
41 fprintf(stderr, "USAGE: %s [[-r] priority pids ...] [-g pid]\n", s);
42 exit(EXIT_FAILURE);
43 }
44
45 void print_prio(pid_t pid)
46 {
47 int sched;
48 struct sched_param sp;
49
50 printf("pid %d's priority: %d\n", pid, getpriority(PRIO_PROCESS, pid));
51
52 printf("scheduling class: ");
53 sched = sched_getscheduler(pid);
54 switch (sched) {
55 case SCHED_FIFO:
56 printf("FIFO\n");
57 break;
58 case SCHED_RR:
59 printf("RR\n");
60 break;
61 case SCHED_OTHER:
62 printf("Normal\n");
63 break;
64 case -1:
65 perror("sched_getscheduler");
66 break;
67 default:
68 printf("Unknown\n");
69 }
70
71 sched_getparam(pid, &sp);
72 printf("RT prio: %d (of %d to %d)\n", sp.sched_priority,
73 sched_get_priority_min(sched), sched_get_priority_max(sched));
74 }
75
76 int renice_main(int argc, char *argv[])
77 {
78 int prio;
79 int realtime = 0;
80 char *cmd = argv[0];
81
82 // consume command name
83 argc--;
84 argv++;
85
86 if (argc < 1)
87 usage(cmd);
88
89 if(strcmp("-r", argv[0]) == 0) {
90 // do realtime priority adjustment
91 realtime = 1;
92 argc--;
93 argv++;
94 }
95
96 if(strcmp("-g", argv[0]) == 0) {
97 if (argc < 2)
98 usage(cmd);
99 print_prio(atoi(argv[1]));
100 return 0;
101 }
102
103 if (argc < 1)
104 usage(cmd);
105
106 prio = atoi(argv[0]);
107 argc--;
108 argv++;
109
110 if (argc < 1)
111 usage(cmd);
112
113 while(argc) {
114 pid_t pid;
115
116 pid = atoi(argv[0]);
117 argc--;
118 argv++;
119
120 if (realtime) {
121 struct sched_param sp = { .sched_priority = prio };
122 int ret;
123
124 ret = sched_setscheduler(pid, SCHED_RR, &sp);
125 if (ret) {
126 perror("sched_set_scheduler");
127 exit(EXIT_FAILURE);
128 }
129 } else {
130 int ret;
131
132 ret = setpriority(PRIO_PROCESS, pid, prio);
133 if (ret) {
134 perror("setpriority");
135 exit(EXIT_FAILURE);
136 }
137 }
138 }
139
140 return 0;
141 }
142
143
+0
-92
toolbox/rm.c less more
0 #include <stdio.h>
1 #include <unistd.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <dirent.h>
5 #include <limits.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8
9 static int usage()
10 {
11 fprintf(stderr,"rm [-rR] <target>\n");
12 return -1;
13 }
14
15 /* return -1 on failure, with errno set to the first error */
16 static int unlink_recursive(const char* name)
17 {
18 struct stat st;
19 DIR *dir;
20 struct dirent *de;
21 int fail = 0;
22
23 /* is it a file or directory? */
24 if (lstat(name, &st) < 0)
25 return -1;
26
27 /* a file, so unlink it */
28 if (!S_ISDIR(st.st_mode))
29 return unlink(name);
30
31 /* a directory, so open handle */
32 dir = opendir(name);
33 if (dir == NULL)
34 return -1;
35
36 /* recurse over components */
37 errno = 0;
38 while ((de = readdir(dir)) != NULL) {
39 char dn[PATH_MAX];
40 if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
41 continue;
42 sprintf(dn, "%s/%s", name, de->d_name);
43 if (unlink_recursive(dn) < 0) {
44 fail = 1;
45 break;
46 }
47 errno = 0;
48 }
49 /* in case readdir or unlink_recursive failed */
50 if (fail || errno < 0) {
51 int save = errno;
52 closedir(dir);
53 errno = save;
54 return -1;
55 }
56
57 /* close directory handle */
58 if (closedir(dir) < 0)
59 return -1;
60
61 /* delete target directory */
62 return rmdir(name);
63 }
64
65 int rm_main(int argc, char *argv[])
66 {
67 int ret;
68 int i = 1;
69 int recursive = 0;
70
71 if (argc < 2)
72 return usage();
73
74 /* check if recursive */
75 if (argc >=2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "-R"))) {
76 recursive = 1;
77 i = 2;
78 }
79
80 /* loop over the file/directory args */
81 for (; i < argc; i++) {
82 int ret = recursive ? unlink_recursive(argv[i]) : unlink(argv[i]);
83 if (ret < 0) {
84 fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
85 return -1;
86 }
87 }
88
89 return 0;
90 }
91
+0
-29
toolbox/rmdir.c less more
0 #include <stdio.h>
1 #include <unistd.h>
2 #include <string.h>
3 #include <errno.h>
4
5 static int usage()
6 {
7 fprintf(stderr,"rmdir <directory>\n");
8 return -1;
9 }
10
11 int rmdir_main(int argc, char *argv[])
12 {
13 int symbolic = 0;
14 int ret;
15 if(argc < 2) return usage();
16
17 while(argc > 1) {
18 argc--;
19 argv++;
20 ret = rmdir(argv[0]);
21 if(ret < 0) {
22 fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno));
23 return ret;
24 }
25 }
26
27 return 0;
28 }
+0
-42
toolbox/rmmod.c less more
0 #include <stdio.h>
1 #include <string.h>
2 #include <fcntl.h>
3 #include <unistd.h>
4 #include <malloc.h>
5 #include <errno.h>
6 #include <asm/unistd.h>
7
8 extern int delete_module(const char *, unsigned int);
9
10 int rmmod_main(int argc, char **argv)
11 {
12 int ret;
13 char *modname, *dot;
14
15 /* make sure we've got an argument */
16 if (argc < 2) {
17 fprintf(stderr, "usage: rmmod <module>\n");
18 return -1;
19 }
20
21 /* if given /foo/bar/blah.ko, make a weak attempt
22 * to convert to "blah", just for convenience
23 */
24 modname = strrchr(argv[1], '/');
25 if (!modname)
26 modname = argv[1];
27 dot = strchr(argv[1], '.');
28 if (dot)
29 *dot = '\0';
30
31 /* pass it to the kernel */
32 ret = delete_module(modname, O_NONBLOCK | O_EXCL);
33 if (ret != 0) {
34 fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n",
35 modname, errno);
36 return -1;
37 }
38
39 return 0;
40 }
41
+0
-71
toolbox/rotatefb.c less more
0 #include <ctype.h>
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/mman.h>
4 #include <fcntl.h>
5 #include <string.h>
6 #include <termios.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <linux/fb.h>
10
11
12 int rotatefb_main(int argc, char *argv[])
13 {
14 int c;
15 char *fbdev = "/dev/graphics/fb0";
16 int rotation = 0;
17 int fd;
18 int res;
19 struct fb_var_screeninfo fbinfo;
20
21 do {
22 c = getopt(argc, argv, "d:");
23 if (c == EOF)
24 break;
25 switch (c) {
26 case 'd':
27 fbdev = optarg;
28 break;
29 case '?':
30 fprintf(stderr, "%s: invalid option -%c\n",
31 argv[0], optopt);
32 exit(1);
33 }
34 } while (1);
35
36 if(optind + 1 != argc) {
37 fprintf(stderr, "%s: specify rotation\n", argv[0]);
38 exit(1);
39 }
40 rotation = atoi(argv[optind]);
41
42 fd = open(fbdev, O_RDWR);
43 if(fd < 0) {
44 fprintf(stderr, "cannot open %s\n", fbdev);
45 return 1;
46 }
47
48 res = ioctl(fd, FBIOGET_VSCREENINFO, &fbinfo);
49 if(res < 0) {
50 fprintf(stderr, "failed to get fbinfo: %s\n", strerror(errno));
51 return 1;
52 }
53 if((fbinfo.rotate ^ rotation) & 1) {
54 unsigned int xres = fbinfo.yres;
55 fbinfo.yres = fbinfo.xres;
56 fbinfo.xres = xres;
57 fbinfo.xres_virtual = fbinfo.xres;
58 fbinfo.yres_virtual = fbinfo.yres * 2;
59 if(fbinfo.yoffset == xres)
60 fbinfo.yoffset = fbinfo.yres;
61 }
62 fbinfo.rotate = rotation;
63 res = ioctl(fd, FBIOPUT_VSCREENINFO, &fbinfo);
64 if(res < 0) {
65 fprintf(stderr, "failed to set fbinfo: %s\n", strerror(errno));
66 return 1;
67 }
68
69 return 0;
70 }
+0
-97
toolbox/route.c less more
0
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 #include <errno.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <linux/if.h>
12 #include <linux/sockios.h>
13 #include <arpa/inet.h>
14 #include <linux/route.h>
15
16 static void die(const char *s)
17 {
18 fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
19 exit(-1);
20 }
21
22 static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
23 {
24 sin->sin_family = AF_INET;
25 sin->sin_port = 0;
26 sin->sin_addr.s_addr = inet_addr(addr);
27 }
28
29 #define ADVANCE(argc, argv) do { argc--, argv++; } while(0)
30 #define EXPECT_NEXT(argc, argv) do { \
31 ADVANCE(argc, argv); \
32 if (0 == argc) { \
33 errno = EINVAL; \
34 die("expecting one more argument"); \
35 } \
36 } while(0)
37
38 /* current support two kinds of usage */
39 /* route add default dev wlan0 */
40 /* route add default gw 192.168.20.1 dev wlan0 */
41
42 int route_main(int argc, char *argv[])
43 {
44 struct ifreq ifr;
45 int s,i;
46 struct rtentry rt;
47 struct sockaddr_in ina;
48
49 if(argc == 0) return 0;
50
51 strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
52 ifr.ifr_name[IFNAMSIZ-1] = 0;
53 ADVANCE(argc, argv);
54
55 if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
56 die("cannot open control socket\n");
57 }
58
59 while(argc > 0){
60 if(!strcmp(argv[0], "add")) {
61 EXPECT_NEXT(argc, argv);
62 if(!strcmp(argv[0], "default")) {
63 EXPECT_NEXT(argc, argv);
64 memset((char *) &rt, 0, sizeof(struct rtentry));
65 rt.rt_dst.sa_family = AF_INET;
66 if(!strcmp(argv[0], "dev")) {
67 EXPECT_NEXT(argc, argv);
68 rt.rt_flags = RTF_UP | RTF_HOST;
69 rt.rt_dev = argv[0];
70 if (ioctl(s, SIOCADDRT, &rt) < 0) die("SIOCADDRT");
71 }else if(!strcmp(argv[0], "gw")) {
72 EXPECT_NEXT(argc, argv);
73 rt.rt_flags = RTF_UP | RTF_GATEWAY;
74 init_sockaddr_in((struct sockaddr_in *)&(rt.rt_genmask), "0.0.0.0");
75 if(isdigit(argv[0][0])){
76 init_sockaddr_in((struct sockaddr_in *)&(rt.rt_gateway), argv[0]);
77 }else{
78 die("expecting an IP address for parameter \"gw\"");
79 }
80 EXPECT_NEXT(argc, argv);
81 if(!strcmp(argv[0], "dev")) {
82 EXPECT_NEXT(argc, argv);
83 rt.rt_dev = argv[0];
84 if (ioctl(s, SIOCADDRT, &rt) < 0){
85 die("SIOCADDRT");
86 }
87 }
88 }
89 }
90 }
91 ADVANCE(argc, argv);
92 }
93
94 return 0;
95 }
96
+0
-335
toolbox/schedtop.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <ctype.h>
3 #include <fcntl.h>
4
5 #include <string.h>
6
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <dirent.h>
10 #include <signal.h>
11
12 #include <pwd.h>
13
14 struct thread_info {
15 int pid;
16 int tid;
17 char name[64];
18 uint64_t exec_time;
19 uint64_t delay_time;
20 uint32_t run_count;
21 };
22
23 struct thread_table {
24 size_t allocated;
25 size_t active;
26 struct thread_info *data;
27 };
28
29 enum {
30 FLAG_BATCH = 1U << 0,
31 FLAG_HIDE_IDLE = 1U << 1,
32 FLAG_SHOW_THREADS = 1U << 2,
33 FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
34 };
35
36 static int time_dp = 9;
37 static int time_div = 1;
38 #define NS_TO_S_D(ns) \
39 (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
40
41 struct thread_table processes;
42 struct thread_table last_processes;
43 struct thread_table threads;
44 struct thread_table last_threads;
45
46 static void grow_table(struct thread_table *table)
47 {
48 size_t size = table->allocated;
49 struct thread_info *new_table;
50 if (size < 128)
51 size = 128;
52 else
53 size *= 2;
54
55 new_table = realloc(table->data, size * sizeof(*table->data));
56 if (new_table == NULL) {
57 fprintf(stderr, "out of memory\n");
58 exit(1);
59 }
60 table->data = new_table;
61 table->allocated = size;
62 }
63
64 static struct thread_info *get_item(struct thread_table *table)
65 {
66 if (table->active >= table->allocated)
67 grow_table(table);
68 return table->data + table->active;
69 }
70
71 static void commit_item(struct thread_table *table)
72 {
73 table->active++;
74 }
75
76 static int read_line(char *line, size_t line_size)
77 {
78 int fd;
79 int len;
80 fd = open(line, O_RDONLY);
81 if(fd == 0)
82 return -1;
83 len = read(fd, line, line_size - 1);
84 close(fd);
85 if (len <= 0)
86 return -1;
87 line[len] = '\0';
88 return 0;
89 }
90
91 static void add_thread(int pid, int tid, struct thread_info *proc_info)
92 {
93 char line[1024];
94 char *name, *name_end;
95 size_t name_len;
96 struct thread_info *info;
97 if(tid == 0)
98 info = get_item(&processes);
99 else
100 info = get_item(&threads);
101 info->pid = pid;
102 info->tid = tid;
103
104 if(tid)
105 sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
106 else
107 sprintf(line, "/proc/%d/schedstat", pid);
108 if (read_line(line, sizeof(line)))
109 return;
110 if(sscanf(line, "%llu %llu %u", &info->exec_time, &info->delay_time, &info->run_count) != 3)
111 return;
112 if (proc_info) {
113 proc_info->exec_time += info->exec_time;
114 proc_info->delay_time += info->delay_time;
115 proc_info->run_count += info->run_count;
116 }
117
118 name = NULL;
119 if (!tid) {
120 sprintf(line, "/proc/%d/cmdline", pid);
121 if (read_line(line, sizeof(line)) == 0 && line[0]) {
122 name = line;
123 name_len = strlen(name);
124 }
125 }
126 if (!name) {
127 if (tid)
128 sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
129 else
130 sprintf(line, "/proc/%d/stat", pid);
131 if (read_line(line, sizeof(line)))
132 return;
133 name = strchr(line, '(');
134 if (name == NULL)
135 return;
136 name_end = strchr(name, ')');
137 if (name_end == NULL)
138 return;
139 name++;
140 name_len = name_end - name;
141 }
142 if (name_len >= sizeof(info->name))
143 name_len = sizeof(info->name) - 1;
144 memcpy(info->name, name, name_len);
145 info->name[name_len] = '\0';
146 if(tid == 0)
147 commit_item(&processes);
148 else
149 commit_item(&threads);
150 }
151
152 static void add_threads(int pid, struct thread_info *proc_info)
153 {
154 char path[1024];
155 DIR *d;
156 struct dirent *de;
157 sprintf(path, "/proc/%d/task", pid);
158 d = opendir(path);
159 if(d == 0) return;
160 while((de = readdir(d)) != 0){
161 if(isdigit(de->d_name[0])){
162 int tid = atoi(de->d_name);
163 add_thread(pid, tid, proc_info);
164 }
165 }
166 closedir(d);
167 }
168
169 static void print_threads(int pid, uint32_t flags)
170 {
171 size_t i, j;
172 for (i = 0; i < last_threads.active; i++) {
173 int epid = last_threads.data[i].pid;
174 int tid = last_threads.data[i].tid;
175 if (epid != pid)
176 continue;
177 for (j = 0; j < threads.active; j++)
178 if (tid == threads.data[j].tid)
179 break;
180 if (j == threads.active)
181 printf(" %5u died\n", tid);
182 else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
183 printf(" %5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", tid,
184 NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
185 NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
186 threads.data[j].run_count - last_threads.data[i].run_count,
187 NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
188 threads.data[j].run_count, threads.data[j].name);
189 }
190 }
191
192 static void update_table(DIR *d, uint32_t flags)
193 {
194 size_t i, j;
195 struct dirent *de;
196
197 rewinddir(d);
198 while((de = readdir(d)) != 0){
199 if(isdigit(de->d_name[0])){
200 int pid = atoi(de->d_name);
201 struct thread_info *proc_info;
202 add_thread(pid, 0, NULL);
203 proc_info = &processes.data[processes.active - 1];
204 proc_info->exec_time = 0;
205 proc_info->delay_time = 0;
206 proc_info->run_count = 0;
207 add_threads(pid, proc_info);
208 }
209 }
210 if (!(flags & FLAG_BATCH))
211 printf("\e[H\e[0J");
212 printf("Processes: %d, Threads %d\n", processes.active, threads.active);
213 switch (time_dp) {
214 case 3:
215 printf(" TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
216 printf(" PID EXEC_T DELAY SCHED EXEC_TIME DELAY_TIM SCHED NAME\n");
217 break;
218 case 6:
219 printf(" TID ------ SINCE LAST ------- ------------ TOTAL -----------\n");
220 printf(" PID EXEC_TIME DELAY_TIM SCHED EXEC_TIME DELAY_TIME SCHED NAME\n");
221 break;
222 default:
223 printf(" TID -------- SINCE LAST -------- ------------- TOTAL -------------\n");
224 printf(" PID EXEC_TIME DELAY_TIME SCHED EXEC_TIME DELAY_TIME SCHED NAME\n");
225 break;
226 }
227 for (i = 0; i < last_processes.active; i++) {
228 int pid = last_processes.data[i].pid;
229 int tid = last_processes.data[i].tid;
230 for (j = 0; j < processes.active; j++)
231 if (pid == processes.data[j].pid)
232 break;
233 if (j == processes.active)
234 printf("%5u died\n", pid);
235 else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
236 printf("%5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", pid,
237 NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
238 NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
239 processes.data[j].run_count - last_processes.data[i].run_count,
240 NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
241 processes.data[j].run_count, processes.data[j].name);
242 if (flags & FLAG_SHOW_THREADS)
243 print_threads(pid, flags);
244 }
245 }
246
247 {
248 struct thread_table tmp;
249 tmp = last_processes;
250 last_processes = processes;
251 processes = tmp;
252 processes.active = 0;
253 tmp = last_threads;
254 last_threads = threads;
255 threads = tmp;
256 threads.active = 0;
257 }
258 }
259
260 void
261 sig_abort(int signum)
262 {
263 printf("\e[?47l");
264 exit(0);
265 }
266
267
268 int schedtop_main(int argc, char **argv)
269 {
270 int c;
271 DIR *d;
272 struct dirent *de;
273 char *namefilter = 0;
274 int pidfilter = 0;
275 uint32_t flags = 0;
276 int delay = 3000000;
277 float delay_f;
278
279 while(1) {
280 c = getopt(argc, argv, "d:ibtamun");
281 if (c == EOF)
282 break;
283 switch (c) {
284 case 'd':
285 delay_f = atof(optarg);
286 delay = delay_f * 1000000;
287 break;
288 case 'b':
289 flags |= FLAG_BATCH;
290 break;
291 case 'i':
292 flags |= FLAG_HIDE_IDLE;
293 break;
294 case 't':
295 flags |= FLAG_SHOW_THREADS;
296 break;
297 case 'a':
298 flags |= FLAG_USE_ALTERNATE_SCREEN;
299 break;
300 case 'm':
301 time_dp = 3;
302 time_div = 1000000;
303 break;
304 case 'u':
305 time_dp = 6;
306 time_div = 1000;
307 break;
308 case 'n':
309 time_dp = 9;
310 time_div = 1;
311 break;
312 }
313 }
314
315 d = opendir("/proc");
316 if(d == 0) return -1;
317
318 if (!(flags & FLAG_BATCH)) {
319 if(flags & FLAG_USE_ALTERNATE_SCREEN) {
320 signal(SIGINT, sig_abort);
321 signal(SIGPIPE, sig_abort);
322 signal(SIGTERM, sig_abort);
323 printf("\e7\e[?47h");
324 }
325 printf("\e[2J");
326 }
327 while (1) {
328 update_table(d, flags);
329 usleep(delay);
330 }
331 closedir(d);
332 return 0;
333 }
334
+0
-80
toolbox/sendevent.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6 //#include <linux/input.h> // this does not compile
7 #include <errno.h>
8
9
10 // from <linux/input.h>
11
12 struct input_event {
13 struct timeval time;
14 __u16 type;
15 __u16 code;
16 __s32 value;
17 };
18
19 #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
20 #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
21 #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
22 #define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
23
24 #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
25 #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
26 #define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
27
28 #define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
29 #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
30 #define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
31 #define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
32
33 #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
34 #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
35 #define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
36
37 #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
38 #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
39 #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
40
41 #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
42
43 // end <linux/input.h>
44
45
46
47 int sendevent_main(int argc, char *argv[])
48 {
49 int i;
50 int fd;
51 int ret;
52 int version;
53 struct input_event event;
54
55 if(argc != 5) {
56 fprintf(stderr, "use: %s device type code value\n", argv[0]);
57 return 1;
58 }
59
60 fd = open(argv[1], O_RDWR);
61 if(fd < 0) {
62 fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
63 return 1;
64 }
65 if (ioctl(fd, EVIOCGVERSION, &version)) {
66 fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
67 return 1;
68 }
69 memset(&event, 0, sizeof(event));
70 event.type = atoi(argv[2]);
71 event.code = atoi(argv[3]);
72 event.value = atoi(argv[4]);
73 ret = write(fd, &event, sizeof(event));
74 if(ret < sizeof(event)) {
75 fprintf(stderr, "write event failed, %s\n", strerror(errno));
76 return -1;
77 }
78 return 0;
79 }
+0
-164
toolbox/setconsole.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <linux/kd.h>
5 #include <linux/vt.h>
6 #include <errno.h>
7 #include <pthread.h>
8
9 static int activate_thread_switch_vc;
10 static void *activate_thread(void *arg)
11 {
12 int res;
13 int fd = (int)arg;
14 while(activate_thread_switch_vc >= 0) {
15 do {
16 res = ioctl(fd, VT_ACTIVATE, (void*)activate_thread_switch_vc);
17 } while(res < 0 && errno == EINTR);
18 if (res < 0) {
19 fprintf(stderr, "ioctl( vcfd, VT_ACTIVATE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), activate_thread_switch_vc);
20 }
21 if(activate_thread_switch_vc >= 0)
22 sleep(1);
23 }
24 return NULL;
25 }
26
27
28 int setconsole_main(int argc, char *argv[])
29 {
30 int c;
31 int fd;
32 int res;
33
34 int mode = -1;
35 int new_vc = 0;
36 int close_vc = 0;
37 int switch_vc = -1;
38 int printvc = 0;
39 char *ttydev = "/dev/tty0";
40
41 do {
42 c = getopt(argc, argv, "d:gtncv:poh");
43 if (c == EOF)
44 break;
45 switch (c) {
46 case 'd':
47 ttydev = optarg;
48 break;
49 case 'g':
50 if(mode == KD_TEXT) {
51 fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
52 exit(1);
53 }
54 mode = KD_GRAPHICS;
55 break;
56 case 't':
57 if(mode == KD_GRAPHICS) {
58 fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
59 exit(1);
60 }
61 mode = KD_TEXT;
62 break;
63 case 'n':
64 new_vc = 1;
65 break;
66 case 'c':
67 close_vc = 1;
68 break;
69 case 'v':
70 switch_vc = atoi(optarg);
71 break;
72 case 'p':
73 printvc |= 1;
74 break;
75 case 'o':
76 printvc |= 2;
77 break;
78 case 'h':
79 fprintf(stderr, "%s [-d <dev>] [-v <vc>] [-gtncpoh]\n"
80 " -d <dev> Use <dev> instead of /dev/tty0\n"
81 " -v <vc> Switch to virtual console <vc>\n"
82 " -g Switch to graphics mode\n"
83 " -t Switch to text mode\n"
84 " -n Create and switch to new virtual console\n"
85 " -c Close unused virtual consoles\n"
86 " -p Print new virtual console\n"
87 " -o Print old virtual console\n"
88 " -h Print help\n", argv[0]);
89 return -1;
90 case '?':
91 fprintf(stderr, "%s: invalid option -%c\n",
92 argv[0], optopt);
93 exit(1);
94 }
95 } while (1);
96 if(mode == -1 && new_vc == 0 && close_vc == 0 && switch_vc == -1 && printvc == 0) {
97 fprintf(stderr,"%s [-d <dev>] [-v <vc>] [-gtncpoh]\n", argv[0]);
98 return -1;
99 }
100
101 fd = open(ttydev, O_RDWR | O_SYNC);
102 if (fd < 0) {
103 fprintf(stderr, "cannot open %s\n", ttydev);
104 return -1;
105 }
106
107 if ((printvc && !new_vc) || (printvc & 2)) {
108 struct vt_stat vs;
109
110 res = ioctl(fd, VT_GETSTATE, &vs);
111 if (res < 0) {
112 fprintf(stderr, "ioctl(vcfd, VT_GETSTATE, &vs) failed, %d\n", res);
113 }
114 printf("%d\n", vs.v_active);
115 }
116
117 if (new_vc) {
118 int vtnum;
119 res = ioctl(fd, VT_OPENQRY, &vtnum);
120 if (res < 0 || vtnum == -1) {
121 fprintf(stderr, "ioctl(vcfd, VT_OPENQRY, &vtnum) failed, res %d, vtnum %d\n", res, vtnum);
122 }
123 switch_vc = vtnum;
124 }
125 if (switch_vc != -1) {
126 pthread_t thread;
127 pthread_attr_t attr;
128 activate_thread_switch_vc = switch_vc;
129 pthread_attr_init(&attr);
130 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
131 pthread_create(&thread, &attr, activate_thread, (void*)fd);
132
133 do {
134 res = ioctl(fd, VT_WAITACTIVE, (void*)switch_vc);
135 } while(res < 0 && errno == EINTR);
136 activate_thread_switch_vc = -1;
137 if (res < 0) {
138 fprintf(stderr, "ioctl( vcfd, VT_WAITACTIVE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), switch_vc);
139 }
140 if(printvc & 1)
141 printf("%d\n", switch_vc);
142
143 close(fd);
144 fd = open(ttydev, O_RDWR | O_SYNC);
145 if (fd < 0) {
146 fprintf(stderr, "cannot open %s\n", ttydev);
147 return -1;
148 }
149 }
150 if (close_vc) {
151 res = ioctl(fd, VT_DISALLOCATE, 0);
152 if (res < 0) {
153 fprintf(stderr, "ioctl(vcfd, VT_DISALLOCATE, 0) failed, %d\n", res);
154 }
155 }
156 if (mode != -1) {
157 if (ioctl(fd, KDSETMODE, (void*)mode) < 0) {
158 fprintf(stderr, "KDSETMODE %d failed\n", mode);
159 return -1;
160 }
161 }
162 return 0;
163 }
+0
-89
toolbox/setkey.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <linux/kd.h>
5 #include <linux/vt.h>
6 #include <errno.h>
7
8 static void setkey_usage(char *argv[])
9 {
10 fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n"
11 " -t <table> Select table\n"
12 " -k <index> Select key\n"
13 " -v <value> Set entry\n"
14 " -r Read current entry\n"
15 " -h Print help\n", argv[0]);
16 }
17
18 #define TTYDEV "/dev/tty0"
19
20 int setkey_main(int argc, char *argv[])
21 {
22 int fd;
23 struct kbentry kbe;
24 int did_something = 0;
25
26 kbe.kb_table = 0;
27 kbe.kb_index = -1;
28 kbe.kb_value = 0;
29
30 fd = open(TTYDEV, O_RDWR | O_SYNC);
31 if (fd < 0) {
32 fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno));
33 return 1;
34 }
35
36 do {
37 int c, ret;
38
39 c = getopt(argc, argv, "t:k:v:hr");
40 if (c == EOF)
41 break;
42
43 switch (c) {
44 case 't':
45 kbe.kb_table = strtol(optarg, NULL, 0);
46 break;
47 case 'k':
48 kbe.kb_index = strtol(optarg, NULL, 0);
49 break;
50 case 'v':
51 kbe.kb_value = strtol(optarg, NULL, 0);
52 ret = ioctl(fd, KDSKBENT, &kbe);
53 if (ret < 0) {
54 fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n",
55 kbe.kb_table, kbe.kb_index, kbe.kb_value,
56 strerror(errno));
57 return 1;
58 }
59 did_something = 1;
60 break;
61 case 'r':
62 ret = ioctl(fd, KDGKBENT, &kbe);
63 if (ret < 0) {
64 fprintf(stderr, "KDGKBENT %d %d failed: %s\n",
65 kbe.kb_table, kbe.kb_index, strerror(errno));
66 return 1;
67 }
68 printf("0x%x 0x%x 0x%x\n",
69 kbe.kb_table, kbe.kb_index, kbe.kb_value);
70 did_something = 1;
71 break;
72 case 'h':
73 setkey_usage(argv);
74 return 1;
75 case '?':
76 fprintf(stderr, "%s: invalid option -%c\n",
77 argv[0], optopt);
78 return 1;
79 }
80 } while (1);
81
82 if(optind != argc || !did_something) {
83 setkey_usage(argv);
84 return 1;
85 }
86
87 return 0;
88 }
+0
-18
toolbox/setprop.c less more
0 #include <stdio.h>
1
2 #include <cutils/properties.h>
3
4 int setprop_main(int argc, char *argv[])
5 {
6 if(argc != 3) {
7 fprintf(stderr,"usage: setprop <key> <value>\n");
8 return 1;
9 }
10
11 if(property_set(argv[1], argv[2])){
12 fprintf(stderr,"could not set property\n");
13 return 1;
14 }
15
16 return 0;
17 }
+0
-64
toolbox/sleep.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34
35 static void
36 usage(const char *s)
37 {
38 fprintf(stderr, "USAGE: %s SECONDS\n", s);
39 exit(-1);
40 }
41
42 int sleep_main(int argc, char *argv[])
43 {
44 unsigned long seconds;
45 char *endptr;
46
47 if (argc != 2) {
48 usage(argv[0]);
49 }
50
51 seconds = strtoul(argv[1], &endptr, 10);
52
53 if (endptr == argv[1]) {
54 usage(argv[0]);
55 }
56
57
58 sleep((unsigned int)seconds);
59
60 return 0;
61 }
62
63
+0
-40
toolbox/smd.c less more
0 #include <stdio.h>
1 #include <string.h>
2 #include <fcntl.h>
3 #include <errno.h>
4
5 int smd_main(int argc, char **argv)
6 {
7 int fd, len, r, port = 0;
8 char devname[32];
9 argc--;
10 argv++;
11
12 if((argc > 0) && (argv[0][0] == '-')) {
13 port = atoi(argv[0] + 1);
14 argc--;
15 argv++;
16 }
17
18 sprintf(devname,"/dev/smd%d",port);
19 fd = open(devname, O_WRONLY);
20 if(fd < 0) {
21 fprintf(stderr,"failed to open smd0 - %s\n",
22 strerror(errno));
23 return -1;
24 }
25 while(argc > 0) {
26 len = strlen(argv[0]);
27 r = write(fd, argv[0], len);
28 if(r != len) {
29 fprintf(stderr,"failed to write smd0 (%d) %s\n",
30 r, strerror(errno));
31 return -1;
32 }
33 argc--;
34 argv++;
35 write(fd, argc ? " " : "\r", 1);
36 }
37 close(fd);
38 return 0;
39 }
+0
-20
toolbox/start.c less more
0
1 #include <string.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 #include <cutils/properties.h>
6
7 int start_main(int argc, char *argv[])
8 {
9 char buf[1024];
10 if(argc > 1) {
11 property_set("ctl.start", argv[1]);
12 } else {
13 /* default to "start zygote" "start runtime" */
14 property_set("ctl.start", "zygote");
15 property_set("ctl.start", "runtime");
16 }
17
18 return 0;
19 }
+0
-20
toolbox/stop.c less more
0 #include <stdio.h>
1 #include <string.h>
2
3 #include <cutils/properties.h>
4
5 int stop_main(int argc, char *argv[])
6 {
7 char buf[1024];
8
9 if(argc > 1) {
10 property_set("ctl.stop", argv[1]);
11 } else{
12 /* default to "stop runtime" "stop zygote" */
13 property_set("ctl.stop", "runtime");
14 property_set("ctl.stop", "zygote");
15 }
16
17 return 0;
18 }
19
+0
-7
toolbox/sync.c less more
0 #include <unistd.h>
1
2 int sync_main(int argc, char **argv)
3 {
4 sync();
5 return 0;
6 }
+0
-154
toolbox/syren.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <malloc.h>
6
7 /* ioctl crap */
8 #define SYREN_RD 101
9 #define SYREN_WR 102
10 #define SYREN_OLD_RD 108
11 #define SYREN_OLD_WR 109
12
13 struct syren_io_args {
14 unsigned long page;
15 unsigned long addr;
16 unsigned long value;
17 };
18
19 typedef struct {
20 u_char page;
21 u_char addr;
22 const char *name;
23 } syren_reg;
24
25 static syren_reg registers[] = {
26 { 0, 0x04, "TOGBR1" },
27 { 0, 0x05, "TOGBR2" },
28 { 0, 0x06, "VBDCTRL" },
29 { 1, 0x07, "VBUCTRL" },
30 { 1, 0x08, "VBCTRL" },
31 { 1, 0x09, "PWDNRG" },
32 { 1, 0x0a, "VBPOP" },
33 { 1, 0x0b, "VBCTRL2" },
34 { 1, 0x0f, "VAUDCTRL" },
35 { 1, 0x10, "VAUSCTRL" },
36 { 1, 0x11, "VAUOCTRL" },
37 { 1, 0x12, "VAUDPLL" },
38 { 1, 0x17, "VRPCSIMR" },
39 { 0, 0, 0 }
40 };
41
42 static syren_reg *find_reg(const char *name)
43 {
44 int i;
45
46 for (i = 0; registers[i].name != 0; i++) {
47 if (!strcasecmp(registers[i].name, name))
48 return &registers[i];
49 }
50
51 return NULL;
52 }
53
54 static int usage(void)
55 {
56 fprintf(stderr, "usage: syren [r/w] [REGNAME | page:addr] (value)\n");
57 return 1;
58 }
59
60 int
61 syren_main(int argc, char **argv)
62 {
63 int cmd = -1;
64 syren_reg *r;
65 struct syren_io_args sio;
66 char name[32];
67 int fd;
68
69 if (argc < 3) {
70 return usage();
71 }
72
73 switch(argv[1][0]) {
74 case 'r':
75 cmd = SYREN_RD;
76 break;
77 case 'w':
78 cmd = SYREN_WR;
79 break;
80 case 'R':
81 cmd = SYREN_OLD_RD;
82 break;
83 case 'W':
84 cmd = SYREN_OLD_WR;
85 break;
86 default:
87 return usage();
88 }
89
90 if (cmd == SYREN_WR || cmd == SYREN_OLD_WR) {
91 if (argc < 4)
92 return usage();
93 sio.value = strtoul(argv[3], 0, 0);
94 }
95
96 fd = open("/dev/eac", O_RDONLY);
97 if (fd < 0) {
98 fprintf(stderr, "can't open /dev/eac\n");
99 return 1;
100 }
101
102 if (strcasecmp(argv[2], "all") == 0) {
103 int i;
104 if (cmd != SYREN_RD && cmd != SYREN_OLD_RD) {
105 fprintf(stderr, "can only read all registers\n");
106 return 1;
107 }
108
109 for (i = 0; registers[i].name; i++) {
110 sio.page = registers[i].page;
111 sio.addr = registers[i].addr;
112 if (ioctl(fd, cmd, &sio) < 0) {
113 fprintf(stderr, "%s: error\n", registers[i].name);
114 } else {
115 fprintf(stderr, "%s: %04x\n", registers[i].name, sio.value);
116 }
117 }
118
119 close(fd);
120 return 0;
121 }
122
123 r = find_reg(argv[2]);
124 if (r == NULL) {
125 strcpy(name, argv[2]);
126 char *addr_str = strchr(argv[2], ':');
127 if (addr_str == NULL)
128 return usage();
129 *addr_str++ = 0;
130 sio.page = strtoul(argv[2], 0, 0);
131 sio.addr = strtoul(addr_str, 0, 0);
132 } else {
133 strcpy(name, r->name);
134 sio.page = r->page;
135 sio.addr = r->addr;
136 }
137
138 if (ioctl(fd, cmd, &sio) < 0) {
139 fprintf(stderr, "ioctl(%d) failed\n", cmd);
140 return 1;
141 }
142
143 if (cmd == SYREN_RD || cmd == SYREN_OLD_RD) {
144 printf("%s: %04x\n", name, sio.value);
145 } else {
146 printf("wrote %04x to %s\n", sio.value, name);
147 }
148
149 close(fd);
150
151 return 0;
152 }
153
+0
-57
toolbox/toolbox.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3
4 int main(int, char **);
5
6 static int toolbox_main(int argc, char **argv)
7 {
8 // "toolbox foo ..." is equivalent to "foo ..."
9 if (argc > 1) {
10 return main(argc - 1, argv + 1);
11 } else {
12 printf("Toolbox!\n");
13 return 0;
14 }
15 }
16
17 #define TOOL(name) int name##_main(int, char**);
18 #include "tools.h"
19 #undef TOOL
20
21 static struct
22 {
23 const char *name;
24 int (*func)(int, char**);
25 } tools[] = {
26 { "toolbox", toolbox_main },
27 #define TOOL(name) { #name, name##_main },
28 #include "tools.h"
29 #undef TOOL
30 { 0, 0 },
31 };
32
33 int main(int argc, char **argv)
34 {
35 int i;
36 char *name = argv[0];
37
38 if((argc > 1) && (argv[1][0] == '@')) {
39 name = argv[1] + 1;
40 argc--;
41 argv++;
42 } else {
43 char *cmd = strrchr(argv[0], '/');
44 if (cmd)
45 name = cmd + 1;
46 }
47
48 for(i = 0; tools[i].name; i++){
49 if(!strcmp(tools[i].name, name)){
50 return tools[i].func(argc, argv);
51 }
52 }
53
54 printf("%s: no such tool\n", argv[0]);
55 return -1;
56 }
+0
-550
toolbox/top.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <ctype.h>
32 #include <dirent.h>
33 #include <grp.h>
34 #include <pwd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40
41 struct cpu_info {
42 long unsigned utime, ntime, stime, itime;
43 long unsigned iowtime, irqtime, sirqtime;
44 };
45
46 #define PROC_NAME_LEN 64
47 #define THREAD_NAME_LEN 32
48
49 struct proc_info {
50 struct proc_info *next;
51 pid_t pid;
52 pid_t tid;
53 uid_t uid;
54 gid_t gid;
55 char name[PROC_NAME_LEN];
56 char tname[THREAD_NAME_LEN];
57 char state;
58 long unsigned utime;
59 long unsigned stime;
60 long unsigned delta_utime;
61 long unsigned delta_stime;
62 long unsigned delta_time;
63 long vss;
64 long rss;
65 int num_threads;
66 };
67
68 struct proc_list {
69 struct proc_info **array;
70 int size;
71 };
72
73 #define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
74
75 #define INIT_PROCS 50
76 #define THREAD_MULT 8
77 static struct proc_info **old_procs, **new_procs;
78 static int num_old_procs, num_new_procs;
79 static struct proc_info *free_procs;
80 static int num_used_procs, num_free_procs;
81
82 static int max_procs, delay, iterations, threads;
83
84 static struct cpu_info old_cpu, new_cpu;
85
86 static struct proc_info *alloc_proc(void);
87 static void free_proc(struct proc_info *proc);
88 static void read_procs(void);
89 static int read_stat(char *filename, struct proc_info *proc);
90 static void add_proc(int proc_num, struct proc_info *proc);
91 static int read_cmdline(char *filename, struct proc_info *proc);
92 static int read_status(char *filename, struct proc_info *proc);
93 static void print_procs(void);
94 static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
95 static void free_old_procs(void);
96 static int (*proc_cmp)(const void *a, const void *b);
97 static int proc_cpu_cmp(const void *a, const void *b);
98 static int proc_vss_cmp(const void *a, const void *b);
99 static int proc_rss_cmp(const void *a, const void *b);
100 static int proc_thr_cmp(const void *a, const void *b);
101 static int numcmp(long long a, long long b);
102 static void usage(char *cmd);
103
104 int top_main(int argc, char *argv[]) {
105 int i;
106
107 num_used_procs = num_free_procs = 0;
108
109 max_procs = 0;
110 delay = 3;
111 iterations = -1;
112 proc_cmp = &proc_cpu_cmp;
113 for (i = 1; i < argc; i++) {
114 if (!strcmp(argv[i], "-m")) {
115 if (i + 1 >= argc) {
116 fprintf(stderr, "Option -m expects an argument.\n");
117 usage(argv[0]);
118 exit(EXIT_FAILURE);
119 }
120 max_procs = atoi(argv[++i]);
121 continue;
122 }
123 if (!strcmp(argv[i], "-n")) {
124 if (i + 1 >= argc) {
125 fprintf(stderr, "Option -n expects an argument.\n");
126 usage(argv[0]);
127 exit(EXIT_FAILURE);
128 }
129 iterations = atoi(argv[++i]);
130 continue;
131 }
132 if (!strcmp(argv[i], "-d")) {
133 if (i + 1 >= argc) {
134 fprintf(stderr, "Option -d expects an argument.\n");
135 usage(argv[0]);
136 exit(EXIT_FAILURE);
137 }
138 delay = atoi(argv[++i]);
139 continue;
140 }
141 if (!strcmp(argv[i], "-s")) {
142 if (i + 1 >= argc) {
143 fprintf(stderr, "Option -s expects an argument.\n");
144 usage(argv[0]);
145 exit(EXIT_FAILURE);
146 }
147 ++i;
148 if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
149 if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
150 if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
151 if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
152 fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
153 exit(EXIT_FAILURE);
154 }
155 if (!strcmp(argv[i], "-t")) { threads = 1; continue; }
156 if (!strcmp(argv[i], "-h")) {
157 usage(argv[0]);
158 exit(EXIT_SUCCESS);
159 }
160 fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
161 usage(argv[0]);
162 exit(EXIT_FAILURE);
163 }
164
165 if (threads && proc_cmp == &proc_thr_cmp) {
166 fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
167 exit(EXIT_FAILURE);
168 }
169
170 free_procs = NULL;
171
172 num_new_procs = num_old_procs = 0;
173 new_procs = old_procs = NULL;
174
175 read_procs();
176 while ((iterations == -1) || (iterations-- > 0)) {
177 old_procs = new_procs;
178 num_old_procs = num_new_procs;
179 memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
180 sleep(delay);
181 read_procs();
182 print_procs();
183 free_old_procs();
184 }
185
186 return 0;
187 }
188
189 static struct proc_info *alloc_proc(void) {
190 struct proc_info *proc;
191
192 if (free_procs) {
193 proc = free_procs;
194 free_procs = free_procs->next;
195 num_free_procs--;
196 } else {
197 proc = malloc(sizeof(*proc));
198 if (!proc) die("Could not allocate struct process_info.\n");
199 }
200
201 num_used_procs++;
202
203 return proc;
204 }
205
206 static void free_proc(struct proc_info *proc) {
207 proc->next = free_procs;
208 free_procs = proc;
209
210 num_used_procs--;
211 num_free_procs++;
212 }
213
214 #define MAX_LINE 256
215
216 static void read_procs(void) {
217 DIR *proc_dir, *task_dir;
218 struct dirent *pid_dir, *tid_dir;
219 char filename[64];
220 FILE *file;
221 int proc_num;
222 struct proc_info *proc;
223 pid_t pid, tid;
224
225 int i;
226
227 proc_dir = opendir("/proc");
228 if (!proc_dir) die("Could not open /proc.\n");
229
230 new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
231 num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
232
233 file = fopen("/proc/stat", "r");
234 if (!file) die("Could not open /proc/stat.\n");
235 fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
236 &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
237 fclose(file);
238
239 proc_num = 0;
240 while ((pid_dir = readdir(proc_dir))) {
241 if (!isdigit(pid_dir->d_name[0]))
242 continue;
243
244 pid = atoi(pid_dir->d_name);
245
246 struct proc_info cur_proc;
247
248 if (!threads) {
249 proc = alloc_proc();
250
251 proc->pid = proc->tid = pid;
252
253 sprintf(filename, "/proc/%d/stat", pid);
254 read_stat(filename, proc);
255
256 sprintf(filename, "/proc/%d/cmdline", pid);
257 read_cmdline(filename, proc);
258
259 sprintf(filename, "/proc/%d/status", pid);
260 read_status(filename, proc);
261
262 proc->num_threads = 0;
263 } else {
264 sprintf(filename, "/proc/%d/cmdline", pid);
265 read_cmdline(filename, &cur_proc);
266
267 sprintf(filename, "/proc/%d/status", pid);
268 read_status(filename, &cur_proc);
269
270 proc = NULL;
271 }
272
273 sprintf(filename, "/proc/%d/task", pid);
274 task_dir = opendir(filename);
275 if (!task_dir) continue;
276
277 while ((tid_dir = readdir(task_dir))) {
278 if (!isdigit(tid_dir->d_name[0]))
279 continue;
280
281 if (threads) {
282 tid = atoi(tid_dir->d_name);
283
284 proc = alloc_proc();
285
286 proc->pid = pid; proc->tid = tid;
287
288 sprintf(filename, "/proc/%d/task/%d/stat", pid, tid);
289 read_stat(filename, proc);
290
291 strcpy(proc->name, cur_proc.name);
292 proc->uid = cur_proc.uid;
293 proc->gid = cur_proc.gid;
294
295 add_proc(proc_num++, proc);
296 } else {
297 proc->num_threads++;
298 }
299 }
300
301 closedir(task_dir);
302
303 if (!threads)
304 add_proc(proc_num++, proc);
305 }
306
307 for (i = proc_num; i < num_new_procs; i++)
308 new_procs[i] = NULL;
309
310 closedir(proc_dir);
311 }
312
313 static int read_stat(char *filename, struct proc_info *proc) {
314 FILE *file;
315 char buf[MAX_LINE], *open_paren, *close_paren;
316 int res, idx;
317
318 file = fopen(filename, "r");
319 if (!file) return 1;
320 fgets(buf, MAX_LINE, file);
321 fclose(file);
322
323 /* Split at first '(' and last ')' to get process name. */
324 open_paren = strchr(buf, '(');
325 close_paren = strrchr(buf, ')');
326 if (!open_paren || !close_paren) return 1;
327
328 *open_paren = *close_paren = '\0';
329 strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
330 proc->tname[THREAD_NAME_LEN-1] = 0;
331
332 /* Scan rest of string. */
333 sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
334 "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld",
335 &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss);
336
337 return 0;
338 }
339
340 static void add_proc(int proc_num, struct proc_info *proc) {
341 int i;
342
343 if (proc_num >= num_new_procs) {
344 new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
345 if (!new_procs) die("Could not expand procs array.\n");
346 for (i = num_new_procs; i < 2 * num_new_procs; i++)
347 new_procs[i] = NULL;
348 num_new_procs = 2 * num_new_procs;
349 }
350 new_procs[proc_num] = proc;
351 }
352
353 static int read_cmdline(char *filename, struct proc_info *proc) {
354 FILE *file;
355 char line[MAX_LINE];
356
357 line[0] = '\0';
358 file = fopen(filename, "r");
359 if (!file) return 1;
360 fgets(line, MAX_LINE, file);
361 fclose(file);
362 if (strlen(line) > 0) {
363 strncpy(proc->name, line, PROC_NAME_LEN);
364 proc->name[PROC_NAME_LEN-1] = 0;
365 } else
366 proc->name[0] = 0;
367 return 0;
368 }
369
370 static int read_status(char *filename, struct proc_info *proc) {
371 FILE *file;
372 char line[MAX_LINE];
373 unsigned int uid, gid;
374
375 file = fopen(filename, "r");
376 if (!file) return 1;
377 while (fgets(line, MAX_LINE, file)) {
378 sscanf(line, "Uid: %u", &uid);
379 sscanf(line, "Gid: %u", &gid);
380 }
381 fclose(file);
382 proc->uid = uid; proc->gid = gid;
383 return 0;
384 }
385
386 static void print_procs(void) {
387 int i;
388 struct proc_info *old_proc, *proc;
389 long unsigned total_delta_time;
390 struct passwd *user;
391 struct group *group;
392 char *user_str, user_buf[20];
393 char *group_str, group_buf[20];
394
395 for (i = 0; i < num_new_procs; i++) {
396 if (new_procs[i]) {
397 old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
398 if (old_proc) {
399 new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
400 new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
401 } else {
402 new_procs[i]->delta_utime = 0;
403 new_procs[i]->delta_stime = 0;
404 }
405 new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
406 }
407 }
408
409 total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
410 + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
411 - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
412 + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
413
414 qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
415
416 printf("\n\n\n");
417 printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
418 ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time,
419 ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
420 ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
421 ((new_cpu.irqtime + new_cpu.sirqtime)
422 - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
423 printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
424 new_cpu.utime - old_cpu.utime,
425 new_cpu.ntime - old_cpu.ntime,
426 new_cpu.stime - old_cpu.stime,
427 new_cpu.itime - old_cpu.itime,
428 new_cpu.iowtime - old_cpu.iowtime,
429 new_cpu.irqtime - old_cpu.irqtime,
430 new_cpu.sirqtime - old_cpu.sirqtime,
431 total_delta_time);
432 printf("\n");
433 if (!threads)
434 printf("%5s %4s %1s %5s %7s %7s %-8s %s\n", "PID", "CPU%", "S", "#THR", "VSS", "RSS", "UID", "Name");
435 else
436 printf("%5s %5s %4s %1s %7s %7s %-8s %-15s %s\n", "PID", "TID", "CPU%", "S", "VSS", "RSS", "UID", "Thread", "Proc");
437
438 for (i = 0; i < num_new_procs; i++) {
439 proc = new_procs[i];
440
441 if (!proc || (max_procs && (i >= max_procs)))
442 break;
443 user = getpwuid(proc->uid);
444 group = getgrgid(proc->gid);
445 if (user && user->pw_name) {
446 user_str = user->pw_name;
447 } else {
448 snprintf(user_buf, 20, "%d", proc->uid);
449 user_str = user_buf;
450 }
451 if (group && group->gr_name) {
452 group_str = group->gr_name;
453 } else {
454 snprintf(group_buf, 20, "%d", proc->gid);
455 group_str = group_buf;
456 }
457 if (!threads)
458 printf("%5d %3ld%% %c %5d %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
459 proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
460 else
461 printf("%5d %5d %3ld%% %c %6ldK %6ldK %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->delta_time * 100 / total_delta_time, proc->state,
462 proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->tname, proc->name);
463 }
464 }
465
466 static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
467 int i;
468
469 for (i = 0; i < num_old_procs; i++)
470 if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
471 return old_procs[i];
472
473 return NULL;
474 }
475
476 static void free_old_procs(void) {
477 int i;
478
479 for (i = 0; i < num_old_procs; i++)
480 if (old_procs[i])
481 free_proc(old_procs[i]);
482
483 free(old_procs);
484 }
485
486 static int proc_cpu_cmp(const void *a, const void *b) {
487 struct proc_info *pa, *pb;
488
489 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
490
491 if (!pa && !pb) return 0;
492 if (!pa) return 1;
493 if (!pb) return -1;
494
495 return -numcmp(pa->delta_time, pb->delta_time);
496 }
497
498 static int proc_vss_cmp(const void *a, const void *b) {
499 struct proc_info *pa, *pb;
500
501 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
502
503 if (!pa && !pb) return 0;
504 if (!pa) return 1;
505 if (!pb) return -1;
506
507 return -numcmp(pa->vss, pb->vss);
508 }
509
510 static int proc_rss_cmp(const void *a, const void *b) {
511 struct proc_info *pa, *pb;
512
513 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
514
515 if (!pa && !pb) return 0;
516 if (!pa) return 1;
517 if (!pb) return -1;
518
519 return -numcmp(pa->rss, pb->rss);
520 }
521
522 static int proc_thr_cmp(const void *a, const void *b) {
523 struct proc_info *pa, *pb;
524
525 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
526
527 if (!pa && !pb) return 0;
528 if (!pa) return 1;
529 if (!pb) return -1;
530
531 return -numcmp(pa->num_threads, pb->num_threads);
532 }
533
534 static int numcmp(long long a, long long b) {
535 if (a < b) return -1;
536 if (a > b) return 1;
537 return 0;
538 }
539
540 static void usage(char *cmd) {
541 fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
542 " -m num Maximum number of processes to display.\n"
543 " -n num Updates to show before exiting.\n"
544 " -d num Seconds to wait between updates.\n"
545 " -s col Column to sort by (cpu,vss,rss,thr).\n"
546 " -t Show threads instead of processes.\n"
547 " -h Display this help screen.\n",
548 cmd);
549 }
+0
-74
toolbox/umount.c less more
0
1 #include <sys/mount.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <linux/loop.h>
8
9 // FIXME - only one loop mount is supported at a time
10 #define LOOP_DEVICE "/dev/block/loop0"
11
12 static int is_loop_mount(const char* path)
13 {
14 FILE* f;
15 int count;
16 char device[256];
17 char mount_path[256];
18 char rest[256];
19 int result = 0;
20 int path_length = strlen(path);
21
22 f = fopen("/proc/mounts", "r");
23 if (!f) {
24 fprintf(stdout, "could not open /proc/mounts\n");
25 return -1;
26 }
27
28 do {
29 count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
30 if (count == 3) {
31 if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0) {
32 result = 1;
33 break;
34 }
35 }
36 } while (count == 3);
37
38 fclose(f);
39 return result;
40 }
41
42 int umount_main(int argc, char *argv[])
43 {
44 int loop, loop_fd;
45
46 if(argc != 2) {
47 fprintf(stderr,"umount <path>\n");
48 return 1;
49 }
50
51 loop = is_loop_mount(argv[1]);
52 if(umount(argv[1])){
53 fprintf(stderr,"failed.\n");
54 return 1;
55 }
56
57 if (loop) {
58 // free the loop device
59 loop_fd = open(LOOP_DEVICE, O_RDONLY);
60 if (loop_fd < -1) {
61 perror("open loop device failed");
62 return 1;
63 }
64 if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
65 perror("ioctl LOOP_CLR_FD failed");
66 return 1;
67 }
68
69 close(loop_fd);
70 }
71
72 return 0;
73 }
+0
-247
toolbox/vmstat.c less more
0 /*
1 * Copyright (c) 2008, The Android Open Source Project
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in
11 * the documentation and/or other materials provided with the
12 * distribution.
13 * * Neither the name of Google, Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/param.h>
35 #include <unistd.h>
36
37 struct state {
38 long procs_r;
39 long procs_b;
40
41 long mem_free;
42 long mem_mapped;
43 long mem_anon;
44 long mem_slab;
45
46 long sys_in;
47 long sys_cs;
48 long sys_flt;
49
50 long cpu_us;
51 long cpu_ni;
52 long cpu_sy;
53 long cpu_id;
54 long cpu_wa;
55 long cpu_ir;
56 long cpu_si;
57 };
58
59 #define MAX_LINE 256
60
61 char line[MAX_LINE];
62
63 static void read_state(struct state *s);
64 static int read_meminfo(struct state *s);
65 static int read_stat(struct state *s);
66 static int read_vmstat(struct state *s);
67 static void print_header(void);
68 static void print_line(struct state *old, struct state *new);
69 static void usage(char *cmd);
70
71 int vmstat_main(int argc, char *argv[]) {
72 struct state s[2];
73 int iterations, delay, header_interval;
74 int toggle, count;
75 int i;
76
77 iterations = 0;
78 delay = 1;
79 header_interval = 20;
80
81 for (i = 1; i < argc; i++) {
82 if (!strcmp(argv[i], "-n")) {
83 if (i >= argc - 1) {
84 fprintf(stderr, "Option -n requires an argument.\n");
85 exit(EXIT_FAILURE);
86 }
87 iterations = atoi(argv[++i]);
88 continue;
89 }
90 if (!strcmp(argv[i], "-d")) {
91 if (i >= argc - 1) {
92 fprintf(stderr, "Option -d requires an argument.\n");
93 exit(EXIT_FAILURE);
94 }
95 delay = atoi(argv[++i]);
96 continue;
97 }
98 if (!strcmp(argv[i], "-r")) {
99 if (i >= argc - 1) {
100 fprintf(stderr, "Option -r requires an argument.\n");
101 exit(EXIT_FAILURE);
102 }
103 header_interval = atoi(argv[++i]);
104 continue;
105 }
106 if (!strcmp(argv[i], "-h")) {
107 usage(argv[0]);
108 exit(EXIT_SUCCESS);
109 }
110 fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
111 usage(argv[0]);
112 exit(EXIT_FAILURE);
113 }
114
115 toggle = 0;
116 count = 0;
117
118 if (!header_interval)
119 print_header();
120 read_state(&s[1 - toggle]);
121 while ((iterations == 0) || (iterations-- > 0)) {
122 sleep(delay);
123 read_state(&s[toggle]);
124 if (header_interval) {
125 if (count == 0)
126 print_header();
127 count = (count + 1) % header_interval;
128 }
129 print_line(&s[1 - toggle], &s[toggle]);
130 toggle = 1 - toggle;
131 }
132
133 return 0;
134 }
135
136 static void read_state(struct state *s) {
137 int error;
138
139 error = read_meminfo(s);
140 if (error) {
141 fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error));
142 exit(EXIT_FAILURE);
143 }
144
145 error = read_stat(s);
146 if (error) {
147 fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error));
148 exit(EXIT_FAILURE);
149 }
150
151 error = read_vmstat(s);
152 if (error) {
153 fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error));
154 exit(EXIT_FAILURE);
155 }
156 }
157
158 static int read_meminfo(struct state *s) {
159 FILE *f;
160
161 f = fopen("/proc/meminfo", "r");
162 if (!f) return errno;
163
164 while (fgets(line, MAX_LINE, f)) {
165 sscanf(line, "MemFree: %ld kB", &s->mem_free);
166 sscanf(line, "AnonPages: %ld kB", &s->mem_anon);
167 sscanf(line, "Mapped: %ld kB", &s->mem_mapped);
168 sscanf(line, "Slab: %ld kB", &s->mem_slab);
169 }
170
171 fclose(f);
172
173 return 0;
174 }
175
176 static int read_stat(struct state *s) {
177 FILE *f;
178
179 f = fopen("/proc/stat", "r");
180 if (!f) return errno;
181
182 while (fgets(line, MAX_LINE, f)) {
183 if (!strncmp(line, "cpu ", 4)) {
184 sscanf(line, "cpu %ld %ld %ld %ld %ld %ld %ld",
185 &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa,
186 &s->cpu_ir, &s->cpu_si);
187 }
188 sscanf(line, "intr %ld", &s->sys_in);
189 sscanf(line, "ctxt %ld", &s->sys_cs);
190 sscanf(line, "procs_running %ld", &s->procs_r);
191 sscanf(line, "procs_blocked %ld", &s->procs_b);
192 }
193
194 fclose(f);
195
196 return 0;
197 }
198
199 static int read_vmstat(struct state *s) {
200 FILE *f;
201
202 f = fopen("/proc/vmstat", "r");
203 if (!f) return errno;
204
205 while (fgets(line, MAX_LINE, f)) {
206 sscanf(line, "pgmajfault %ld", &s->sys_flt);
207 }
208
209 fclose(f);
210
211 return 0;
212 }
213
214 static void print_header(void) {
215 printf("%-5s %-27s %-14s %-17s\n", "procs", "memory", "system", "cpu");
216 printf("%2s %2s %6s %6s %6s %6s %4s %4s %4s %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir");
217 }
218
219 /* Jiffies to percent conversion */
220 #define JP(jif) ((jif) * 100 / (HZ))
221 #define NORM(var) ((var) = (((var) > 99) ? (99) : (var)))
222
223 static void print_line(struct state *old, struct state *new) {
224 int us, ni, sy, id, wa, ir;
225 us = JP(new->cpu_us - old->cpu_us); NORM(us);
226 ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni);
227 sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy);
228 id = JP(new->cpu_id - old->cpu_id); NORM(id);
229 wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa);
230 ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir);
231 printf("%2ld %2ld %6ld %6ld %6ld %6ld %4ld %4ld %4ld %2d %2d %2d %2d %2d %2d\n",
232 new->procs_r ? (new->procs_r - 1) : 0, new->procs_b,
233 new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab,
234 new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt,
235 us, ni, sy, id, wa, ir);
236 }
237
238 static void usage(char *cmd) {
239 fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n"
240 " -n iterations How many rows of data to print.\n"
241 " -d delay How long to sleep between rows.\n"
242 " -r header_repeat How many rows to print before repeating\n"
243 " the header. Zero means never repeat.\n"
244 " -h Displays this help screen.\n",
245 cmd);
246 }
+0
-76
toolbox/watchprops.c less more
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <time.h>
3
4 #include <cutils/properties.h>
5
6 #include <sys/atomics.h>
7
8 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
9 #include <sys/_system_properties.h>
10
11
12 extern prop_area *__system_property_area__;
13
14 typedef struct pwatch pwatch;
15
16 struct pwatch
17 {
18 const prop_info *pi;
19 unsigned serial;
20 };
21
22 static pwatch watchlist[1024];
23
24 static void announce(const prop_info *pi)
25 {
26 char name[PROP_NAME_MAX];
27 char value[PROP_VALUE_MAX];
28 char *x;
29
30 __system_property_read(pi, name, value);
31
32 for(x = value; *x; x++) {
33 if((*x < 32) || (*x > 127)) *x = '.';
34 }
35
36 fprintf(stderr,"%10d %s = '%s'\n", (int) time(0), name, value);
37 }
38
39 int watchprops_main(int argc, char *argv[])
40 {
41 prop_area *pa = __system_property_area__;
42 unsigned serial = pa->serial;
43 unsigned count = pa->count;
44 unsigned n;
45
46 if(count >= 1024) exit(1);
47
48 for(n = 0; n < count; n++) {
49 watchlist[n].pi = __system_property_find_nth(n);
50 watchlist[n].serial = watchlist[n].pi->serial;
51 }
52
53 for(;;) {
54 do {
55 __futex_wait(&pa->serial, serial, 0);
56 } while(pa->serial == serial);
57
58 while(count < pa->count){
59 watchlist[count].pi = __system_property_find_nth(count);
60 watchlist[count].serial = watchlist[n].pi->serial;
61 announce(watchlist[count].pi);
62 count++;
63 if(count == 1024) exit(1);
64 }
65
66 for(n = 0; n < count; n++){
67 unsigned tmp = watchlist[n].pi->serial;
68 if(watchlist[n].serial != tmp) {
69 announce(watchlist[n].pi);
70 watchlist[n].serial = tmp;
71 }
72 }
73 }
74 return 0;
75 }
+0
-176
toolbox/wipe.c less more
0 #include <stdlib.h>
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <dirent.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <sys/reboot.h>
8 #include <sys/stat.h>
9
10 #ifndef PATH_MAX
11 #define PATH_MAX 4096
12 #endif
13
14
15 /* Directories created by init defined in system/rootdir/init.rc */
16 static char *INIT_DIRS[] = {
17 "/system/etc/ppp",
18 "/data/misc",
19 "/data/local",
20 "/data/local/tmp",
21 "/data/data",
22 "/data/app_private",
23 "/data/app",
24 NULL
25 };
26
27 static void wipe (const char *path);
28
29 static int usage()
30 {
31 fprintf(stderr, "wipe <system|data|all>\n\n"
32 "system means '/system'\n"
33 "data means '/data'\n");
34
35 return -1;
36 }
37
38 int wipe_main (int argc, char *argv[])
39 {
40 char *whatToWipe;
41
42 if (argc != 2) return usage();
43
44 whatToWipe = argv[1];
45
46 if (0 == strcmp (whatToWipe, "system")) {
47 fprintf(stdout, "Wiping /system\n");
48 wipe ("/system");
49 fprintf(stdout, "Done wiping /android\n");
50 } else if (0 == strcmp (whatToWipe, "data")) {
51 fprintf(stdout, "Wiping /data\n");
52 wipe ("/data");
53 fprintf(stdout, "Done wiping /data\n");
54 } else if (0 == strcmp (whatToWipe, "all")) {
55 fprintf(stdout, "Wiping /system and /data\n");
56 wipe ("/system");
57 wipe ("/data");
58 fprintf(stdout, "Done wiping /system and /data\n");
59 } else if (0 == strcmp(whatToWipe, "nuke")) {
60 int ret;
61 fprintf(stdout, "Nuking the device...\n");
62 wipe ("/system");
63 wipe ("/data");
64 fprintf(stdout, "Device nuked! Rebooting...\n");
65 ret = reboot(RB_AUTOBOOT);
66 if (ret < 0) {
67 fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
68 return 1;
69 }
70 } else {
71 return usage();
72 }
73
74 return 0;
75 }
76
77 static char nameBuffer[PATH_MAX];
78 static struct stat statBuffer;
79
80 static void wipe (const char *path)
81 {
82 DIR *dir;
83 struct dirent *de;
84 int ret;
85
86 dir = opendir(path);
87
88 if (dir == NULL) {
89 fprintf (stderr, "Error opendir'ing %s '%s'\n",
90 path, strerror(errno));
91 return;
92 }
93
94 char *filenameOffset;
95
96 strcpy(nameBuffer, path);
97 strcat(nameBuffer, "/");
98
99 filenameOffset = nameBuffer + strlen(nameBuffer);
100
101 for (;;) {
102 de = readdir(dir);
103
104 if (de == NULL) {
105 break;
106 }
107
108 if (0 == strcmp(de->d_name, ".")
109 || 0 == strcmp(de->d_name, "..")
110 || 0 == strcmp(de->d_name, "lost+found")
111 ) {
112 continue;
113 }
114
115 strcpy(filenameOffset, de->d_name);
116
117 ret = lstat (nameBuffer, &statBuffer);
118
119 if (ret != 0) {
120 fprintf(stderr, "stat() error on '%s' '%s'\n",
121 nameBuffer, strerror(errno));
122 }
123
124 if(S_ISDIR(statBuffer.st_mode)) {
125 int i;
126 char *newpath;
127
128 #if 0
129 closedir(dir);
130 #endif
131
132 newpath = strdup(nameBuffer);
133 wipe(newpath);
134
135 /* Leave directories created by init, they have special permissions. */
136 for (i = 0; INIT_DIRS[i]; i++) {
137 if (strcmp(INIT_DIRS[i], newpath) == 0) {
138 break;
139 }
140 }
141 if (INIT_DIRS[i] == NULL) {
142 ret = rmdir(newpath);
143 if (ret != 0) {
144 fprintf(stderr, "rmdir() error on '%s' '%s'\n",
145 newpath, strerror(errno));
146 }
147 }
148
149 free(newpath);
150
151 #if 0
152 dir = opendir(path);
153 if (dir == NULL) {
154 fprintf (stderr, "Error opendir'ing %s '%s'\n",
155 path, strerror(errno));
156 return;
157 }
158 #endif
159
160 strcpy(nameBuffer, path);
161 strcat(nameBuffer, "/");
162
163 } else {
164 ret = unlink(nameBuffer);
165
166 if (ret != 0) {
167 fprintf(stderr, "unlink() error on '%s' '%s'\n",
168 nameBuffer, strerror(errno));
169 }
170 }
171 }
172
173 closedir(dir);
174
175 }
+0
-32
vold/Android.mk less more
0 LOCAL_PATH:= $(call my-dir)
1
2 include $(CLEAR_VARS)
3
4 LOCAL_SRC_FILES:= \
5 vold.c \
6 cmd_dispatch.c \
7 uevent.c \
8 mmc.c \
9 misc.c \
10 blkdev.c \
11 ums.c \
12 geom_mbr_enc.c \
13 volmgr.c \
14 media.c \
15 volmgr_vfat.c \
16 volmgr_ext3.c \
17 logwrapper.c \
18 ProcessKiller.c\
19 switch.c \
20 format.c \
21 devmapper.c
22
23 LOCAL_MODULE:= vold
24
25 LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
26
27 LOCAL_CFLAGS :=
28
29 LOCAL_SHARED_LIBRARIES := libcutils
30
31 include $(BUILD_EXECUTABLE)
+0
-222
vold/ProcessKiller.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 ** mountd process killer
18 */
19
20 #include "vold.h"
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <ctype.h>
28 #include <pwd.h>
29 #include <stdlib.h>
30 #include <poll.h>
31 #include <sys/stat.h>
32
33
34 static boolean ReadSymLink(const char* path, char* link)
35 {
36 struct stat s;
37 int length;
38
39 if (lstat(path, &s) < 0)
40 return false;
41 if ((s.st_mode & S_IFMT) != S_IFLNK)
42 return false;
43
44 // we have a symlink
45 length = readlink(path, link, PATH_MAX - 1);
46 if (length <= 0)
47 return false;
48 link[length] = 0;
49 return true;
50 }
51
52 static boolean PathMatchesMountPoint(const char* path, const char* mountPoint)
53 {
54 int length = strlen(mountPoint);
55 if (length > 1 && strncmp(path, mountPoint, length) == 0)
56 {
57 // we need to do extra checking if mountPoint does not end in a '/'
58 if (mountPoint[length - 1] == '/')
59 return true;
60 // if mountPoint does not have a trailing slash, we need to make sure
61 // there is one in the path to avoid partial matches.
62 return (path[length] == 0 || path[length] == '/');
63 }
64
65 return false;
66 }
67
68 static void GetProcessName(int pid, char buffer[PATH_MAX])
69 {
70 int fd;
71 sprintf(buffer, "/proc/%d/cmdline", pid);
72 fd = open(buffer, O_RDONLY);
73 if (fd < 0) {
74 strcpy(buffer, "???");
75 } else {
76 int length = read(fd, buffer, PATH_MAX - 1);
77 buffer[length] = 0;
78 close(fd);
79 }
80 }
81
82 static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
83 {
84 DIR* dir;
85 struct dirent* de;
86 boolean fileOpen = false;
87 char path[PATH_MAX];
88 char link[PATH_MAX];
89 int parent_length;
90
91 // compute path to process's directory of open files
92 sprintf(path, "/proc/%d/fd", pid);
93 dir = opendir(path);
94 if (!dir)
95 return false;
96
97 // remember length of the path
98 parent_length = strlen(path);
99 // append a trailing '/'
100 path[parent_length++] = '/';
101
102 while ((de = readdir(dir)) != 0 && !fileOpen) {
103 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
104 continue;
105
106 // append the file name, after truncating to parent directory
107 path[parent_length] = 0;
108 strcat(path, de->d_name);
109
110 if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
111 {
112 char name[PATH_MAX];
113 GetProcessName(pid, name);
114 LOG_ERROR("process %s (%d) has open file %s", name, pid, link);
115 fileOpen = true;
116 }
117 }
118
119 closedir(dir);
120 return fileOpen;
121 }
122
123 static boolean CheckFileMaps(int pid, const char* mountPoint)
124 {
125 FILE* file;
126 char buffer[PATH_MAX + 100];
127 boolean mapOpen = false;
128
129 sprintf(buffer, "/proc/%d/maps", pid);
130 file = fopen(buffer, "r");
131 if (!file)
132 return false;
133
134 while (!mapOpen && fgets(buffer, sizeof(buffer), file))
135 {
136 // skip to the path
137 const char* path = strchr(buffer, '/');
138 if (path && PathMatchesMountPoint(path, mountPoint))
139 {
140 char name[PATH_MAX];
141 GetProcessName(pid, name);
142 LOG_ERROR("process %s (%d) has open file map for %s", name, pid, path);
143 mapOpen = true;
144 }
145 }
146
147 fclose(file);
148 return mapOpen;
149 }
150
151 static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
152 {
153 char path[PATH_MAX];
154 char link[PATH_MAX];
155
156 sprintf(path, "/proc/%d/%s", pid, name);
157 if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
158 {
159 char name[PATH_MAX];
160 GetProcessName(pid, name);
161 LOG_ERROR("process %s (%d) has %s in %s", name, pid, message, mountPoint);
162 return true;
163 }
164 else
165 return false;
166 }
167
168 static int get_pid(const char* s)
169 {
170 int result = 0;
171 while (*s) {
172 if (!isdigit(*s)) return -1;
173 result = 10 * result + (*s++ - '0');
174 }
175 return result;
176 }
177
178 // hunt down and kill processes that have files open on the given mount point
179 void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
180 {
181 DIR* dir;
182 struct dirent* de;
183
184 LOG_ERROR("KillProcessesWithOpenFiles %s", mountPoint);
185 dir = opendir("/proc");
186 if (!dir) return;
187
188 while ((de = readdir(dir)) != 0)
189 {
190 boolean killed = false;
191 // does the name look like a process ID?
192 int pid = get_pid(de->d_name);
193 if (pid == -1) continue;
194
195 if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files
196 || CheckFileMaps(pid, mountPoint) // check for mmap()
197 || CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory
198 || CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot()
199 || CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
200 )
201 {
202 int i;
203 boolean hit = false;
204
205 for (i = 0; i < num_excluded; i++) {
206 if (pid == excluded[i]) {
207 LOG_ERROR("I just need a little more TIME captain!");
208 hit = true;
209 break;
210 }
211 }
212
213 if (!hit) {
214 LOG_ERROR("Killing process %d", pid);
215 kill(pid, (sigkill ? SIGKILL : SIGTERM));
216 }
217 }
218 }
219
220 closedir(dir);
221 }
+0
-319
vold/blkdev.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/mman.h>
27
28 #include <linux/fs.h>
29 #include <linux/msdos_fs.h>
30
31 #include "vold.h"
32 #include "blkdev.h"
33 #include "diskmbr.h"
34
35 #define DEBUG_BLKDEV 0
36
37 static blkdev_list_t *list_root = NULL;
38
39 static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
40 int minor, char *type, struct media *media);
41
42 static int fat_valid_media(unsigned char media)
43 {
44 return 0xf8 <= media || media == 0xf0;
45 }
46
47 char *blkdev_get_devpath(blkdev_t *blk)
48 {
49 char *dp = malloc(256);
50 sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor);
51 return dp;
52 }
53
54 int blkdev_refresh(blkdev_t *blk)
55 {
56 int fd = 0;
57 char *devpath = NULL;
58 unsigned char *block = NULL;
59 int i, rc;
60
61 if (!(block = malloc(512)))
62 goto out;
63
64 /*
65 * Get the device size
66 */
67 devpath = blkdev_get_devpath(blk);
68
69 if ((fd = open(devpath, O_RDONLY)) < 0) {
70 LOGE("Unable to open device '%s' (%s)", devpath, strerror(errno));
71 return -errno;
72 }
73
74 if (ioctl(fd, BLKGETSIZE, &blk->nr_sec)) {
75 LOGE("Unable to get device size (%m)");
76 return -errno;
77 }
78 close(fd);
79 free(devpath);
80
81 /*
82 * Open the disk partition table
83 */
84 devpath = blkdev_get_devpath(blk->disk);
85 if ((fd = open(devpath, O_RDONLY)) < 0) {
86 LOGE("Unable to open device '%s' (%s)", devpath,
87 strerror(errno));
88 free(devpath);
89 return -errno;
90 }
91
92 free(devpath);
93
94 if ((rc = read(fd, block, 512)) != 512) {
95 LOGE("Unable to read device partition table (%d, %s)",
96 rc, strerror(errno));
97 goto out;
98 }
99
100 /*
101 * If we're a disk, then process the partition table. Otherwise we're
102 * a partition so get the partition type
103 */
104
105 if (blk->type == blkdev_disk) {
106 blk->nr_parts = 0;
107
108 if ((block[0x1fe] != 0x55) || (block[0x1ff] != 0xAA)) {
109 LOG_VOL("Disk %d:%d does not contain a partition table",
110 blk->major, blk->minor);
111 goto out;
112 }
113
114 for (i = 0; i < 4; i++) {
115 struct dos_partition part;
116
117 dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
118 if (part.dp_flag != 0 && part.dp_flag != 0x80) {
119 struct fat_boot_sector *fb = (struct fat_boot_sector *) &block[0];
120
121 if (!i && fb->reserved && fb->fats && fat_valid_media(fb->media)) {
122 LOG_VOL("Detected FAT filesystem in partition table");
123 break;
124 } else {
125 LOG_VOL("Partition table looks corrupt");
126 break;
127 }
128 }
129 if (part.dp_size != 0 && part.dp_typ != 0)
130 blk->nr_parts++;
131 }
132 } else if (blk->type == blkdev_partition) {
133 struct dos_partition part;
134 int part_no = blk->minor -1;
135
136 dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
137 blk->part_type = part.dp_typ;
138 }
139
140 out:
141
142 if (block)
143 free(block);
144
145 char tmp[255];
146 char tmp2[32];
147 sprintf(tmp, "%s (blkdev %d:%d), %u secs (%u MB)",
148 (blk->type == blkdev_disk ? "Disk" : "Partition"),
149 blk->major, blk->minor,
150 blk->nr_sec,
151 ((blk->nr_sec * 512) / 1024) / 1024);
152
153 if (blk->type == blkdev_disk)
154 sprintf(tmp2, " %d partitions", blk->nr_parts);
155 else
156 sprintf(tmp2, " type 0x%x", blk->part_type);
157
158 strcat(tmp, tmp2);
159 LOG_VOL(tmp);
160
161 close(fd);
162
163 return 0;
164 }
165
166 blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type)
167 {
168 return _blkdev_create(disk, devpath, major, minor, type, media);
169 }
170
171 static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
172 int minor, char *type, struct media *media)
173 {
174 blkdev_t *new;
175 struct blkdev_list *list_entry;
176
177 if (disk && disk->type != blkdev_disk) {
178 LOGE("Non disk parent specified for blkdev!");
179 return NULL;
180 }
181
182 if (!(new = malloc(sizeof(blkdev_t))))
183 return NULL;
184
185 memset(new, 0, sizeof(blkdev_t));
186
187 if (!(list_entry = malloc(sizeof(struct blkdev_list)))) {
188 free (new);
189 return NULL;
190 }
191 list_entry->dev = new;
192 list_entry->next = NULL;
193
194 if (!list_root)
195 list_root = list_entry;
196 else {
197 struct blkdev_list *list_scan = list_root;
198 while (list_scan->next)
199 list_scan = list_scan->next;
200 list_scan->next = list_entry;
201 }
202
203 if (devpath)
204 new->devpath = strdup(devpath);
205 new->major = major;
206 new->minor = minor;
207 new->media = media;
208 new->nr_sec = 0xffffffff;
209
210 if (disk)
211 new->disk = disk;
212 else
213 new->disk = new; // Note the self disk pointer
214
215 /* Create device nodes */
216 char nodepath[255];
217 mode_t mode = 0666 | S_IFBLK;
218 dev_t dev = (major << 8) | minor;
219
220 sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor);
221 if (mknod(nodepath, mode, dev) < 0) {
222 LOGE("Error making device nodes for '%s' (%s)",
223 nodepath, strerror(errno));
224 }
225
226 if (!strcmp(type, "disk"))
227 new->type = blkdev_disk;
228 else if (!strcmp(type, "partition"))
229 new->type = blkdev_partition;
230 else {
231 LOGE("Unknown block device type '%s'", type);
232 new->type = blkdev_unknown;
233 }
234
235 return new;
236 }
237
238 void blkdev_destroy(blkdev_t *blkdev)
239 {
240 struct blkdev_list *list_next;
241
242 if (list_root->dev == blkdev) {
243 list_next = list_root->next;
244 free (list_root);
245 list_root = list_next;
246 } else {
247 struct blkdev_list *list_scan = list_root;
248 while (list_scan->next->dev != blkdev)
249 list_scan = list_scan -> next;
250 list_next = list_scan->next->next;
251 free(list_scan->next);
252 list_scan->next = list_next;
253 }
254
255 if (blkdev->devpath)
256 free(blkdev->devpath);
257
258 char nodepath[255];
259 sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor);
260 unlink(nodepath);
261
262 free(blkdev);
263 }
264
265 blkdev_t *blkdev_lookup_by_path(char *devpath)
266 {
267 struct blkdev_list *list_scan = list_root;
268
269 while (list_scan) {
270 if (!strcmp(list_scan->dev->devpath, devpath))
271 return list_scan->dev;
272 list_scan = list_scan->next;
273 }
274 return NULL;
275 }
276
277 blkdev_t *blkdev_lookup_by_devno(int maj, int min)
278 {
279 struct blkdev_list *list_scan = list_root;
280
281 while (list_scan) {
282 if ((list_scan->dev->major == maj) &&
283 (list_scan->dev->minor == min))
284 return list_scan->dev;
285 list_scan = list_scan->next;
286 }
287 return NULL;
288 }
289
290 /*
291 * Given a disk device, return the number of partitions which
292 * have yet to be processed.
293 */
294 int blkdev_get_num_pending_partitions(blkdev_t *blk)
295 {
296 struct blkdev_list *list_scan = list_root;
297 int num = blk->nr_parts;
298
299 if (blk->type != blkdev_disk)
300 return -EINVAL;
301
302 while (list_scan) {
303 if (list_scan->dev->type != blkdev_partition)
304 goto next;
305
306 if (list_scan->dev->major != blk->major)
307 goto next;
308
309 if (list_scan->dev->nr_sec != 0xffffffff &&
310 list_scan->dev->devpath) {
311 num--;
312 }
313 next:
314 list_scan = list_scan->next;
315 }
316 return num;
317 }
318
+0
-64
vold/blkdev.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _BLKDEV_H
18 #define _BLKDEV_H
19
20 #include <sys/types.h>
21
22 struct media;
23
24 enum blk_type { blkdev_unknown, blkdev_disk, blkdev_partition };
25
26 struct blkdev {
27 char *devpath;
28 enum blk_type type;
29 struct media *media;
30
31 // If type == blkdev_disk then nr_parts = number of partitions
32 int nr_parts;
33
34 // If type == blkdev_partition then part_type = partition type
35 uint8_t part_type;
36 // If type == blkdev_partition
37 struct blkdev *disk;
38
39 unsigned int nr_sec;
40
41 int major;
42 int minor;
43 };
44
45 struct blkdev_list {
46 struct blkdev *dev;
47 struct blkdev_list *next;
48 };
49
50 typedef struct blkdev blkdev_t;
51 typedef struct blkdev_list blkdev_list_t;
52
53 blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type);
54 blkdev_t *blkdev_create_pending_partition(blkdev_t *disk, char *dev_fspath, int major, int minor, struct media *media);
55 blkdev_t *blkdev_lookup_by_path(char *devpath);
56 blkdev_t *blkdev_lookup_by_devno(int maj, int min);
57 char *blkdev_get_devpath(blkdev_t *blk);
58
59 void blkdev_destroy(blkdev_t *blk);
60
61 int blkdev_get_num_pending_partitions(blkdev_t *blk);
62 int blkdev_refresh(blkdev_t *blk);
63 #endif
+0
-115
vold/cmd_dispatch.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <unistd.h>
18 #include <errno.h>
19
20 #include "vold.h"
21 #include "cmd_dispatch.h"
22 #include "ums.h"
23 #include "volmgr.h"
24
25 struct cmd_dispatch {
26 char *cmd;
27 int (* dispatch) (char *);
28 };
29
30 static void dispatch_cmd(char *cmd);
31 static int do_send_ums_status(char *cmd);
32 static int do_set_ums_enable(char *cmd);
33 static int do_mount_volume(char *cmd);
34 static int do_eject_media(char *cmd);
35 static int do_format_media(char *cmd);
36
37 static struct cmd_dispatch dispatch_table[] = {
38 { VOLD_CMD_ENABLE_UMS, do_set_ums_enable },
39 { VOLD_CMD_DISABLE_UMS, do_set_ums_enable },
40 { VOLD_CMD_SEND_UMS_STATUS, do_send_ums_status },
41 { VOLD_CMD_MOUNT_VOLUME, do_mount_volume },
42 { VOLD_CMD_EJECT_MEDIA, do_eject_media },
43 { VOLD_CMD_FORMAT_MEDIA, do_format_media },
44 { NULL, NULL }
45 };
46
47 int process_framework_command(int socket)
48 {
49 int rc;
50 char buffer[101];
51
52 if ((rc = read(socket, buffer, sizeof(buffer) -1)) < 0) {
53 LOGE("Unable to read framework command (%s)", strerror(errno));
54 return -errno;
55 } else if (!rc)
56 return -ECONNRESET;
57
58 int start = 0;
59 int i;
60
61 buffer[rc] = 0;
62
63 for (i = 0; i < rc; i++) {
64 if (buffer[i] == 0) {
65 dispatch_cmd(buffer + start);
66 start = i + 1;
67 }
68 }
69 return 0;
70 }
71
72 static void dispatch_cmd(char *cmd)
73 {
74 struct cmd_dispatch *c;
75
76 LOG_VOL("dispatch_cmd(%s):", cmd);
77
78 for (c = dispatch_table; c->cmd != NULL; c++) {
79 if (!strncmp(c->cmd, cmd, strlen(c->cmd))) {
80 c->dispatch(cmd);
81 return;
82 }
83 }
84
85 LOGE("No cmd handlers defined for '%s'", cmd);
86 }
87
88 static int do_send_ums_status(char *cmd)
89 {
90 return ums_send_status();
91 }
92
93 static int do_set_ums_enable(char *cmd)
94 {
95 if (!strcmp(cmd, VOLD_CMD_ENABLE_UMS))
96 return volmgr_enable_ums(true);
97
98 return volmgr_enable_ums(false);
99 }
100
101 static int do_mount_volume(char *cmd)
102 {
103 return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]);
104 }
105
106 static int do_format_media(char *cmd)
107 {
108 return volmgr_format_volume(&cmd[strlen("format_media:")]);
109 }
110
111 static int do_eject_media(char *cmd)
112 {
113 return volmgr_stop_volume_by_mountpoint(&cmd[strlen("eject_media:")]);
114 }
+0
-31
vold/cmd_dispatch.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _CMD_DISPATCH_H
18 #define _CMD_DISPATCH_H
19
20 // These must match the strings in java/android/android/os/UsbListener.java
21 #define VOLD_CMD_ENABLE_UMS "enable_ums"
22 #define VOLD_CMD_DISABLE_UMS "disable_ums"
23 #define VOLD_CMD_SEND_UMS_STATUS "send_ums_status"
24
25 // these commands should contain a volume mount point after the colon
26 #define VOLD_CMD_MOUNT_VOLUME "mount_volume:"
27 #define VOLD_CMD_EJECT_MEDIA "eject_media:"
28 #define VOLD_CMD_FORMAT_MEDIA "format_media:"
29
30 #endif
+0
-463
vold/devmapper.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <dirent.h>
21 #include <unistd.h>
22 #include <sched.h>
23 #include <fcntl.h>
24
25 #include <sys/mount.h>
26
27 #include <linux/loop.h>
28 #include <linux/dm-ioctl.h>
29
30 #include <cutils/config_utils.h>
31 #include <cutils/properties.h>
32
33 #include "vold.h"
34 #include "devmapper.h"
35
36 #define DEBUG_DEVMAPPER 1
37
38 static void *_align(void *ptr, unsigned int a)
39 {
40 register unsigned long agn = --a;
41
42 return (void *) (((unsigned long) ptr + agn) & ~agn);
43 }
44
45 static struct dm_ioctl *_dm_ioctl_setup(struct devmapping *dm, int flags)
46 {
47 void *buffer;
48 void *p;
49 const size_t min_size = 16 * 1024;
50 size_t len = sizeof(struct dm_ioctl);
51 struct dm_ioctl *io;
52 struct dm_target_spec *tgt;
53 int i;
54 char params[1024];
55 char key[80];
56
57 key[0] = '\0';
58 for (i = 0; i < (int) sizeof(dm->key); i++) {
59 char tmp[8];
60
61 sprintf(tmp, "%02x", dm->key[i]);
62 strcat(key, tmp);
63 }
64
65 char srcdev[128];
66
67 // XXX: Handle non crypt targets and non twofish (use param)
68 if (dm->src_type == dmsrc_loopback)
69 strcpy(srcdev, dm->type_data.loop.loop_dev);
70 else if (dm->src_type == dmsrc_partition)
71 strcpy(srcdev, dm->type_data.part.part_dev);
72
73 sprintf(params, "twofish %s 0 %s 0", key, srcdev);
74
75 LOG_VOL("Params = '%s'", params);
76
77 if (len < min_size)
78 len = min_size;
79
80 if (!(buffer = malloc(len))) {
81 LOGE("out of memory");
82 return NULL;
83 }
84
85 memset(buffer, 0, len);
86 io = buffer;
87 tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
88
89 io->version[0] = 4;
90 io->version[1] = 0;
91 io->version[2] = 0;
92
93 io->data_size = len;
94 io->data_start = sizeof(struct dm_ioctl);
95
96 io->flags = flags;
97 io->dev = 0;
98
99 io->target_count = 1;
100 io->event_nr = 1;
101 strncpy(io->name, dm->target, sizeof(io->name));
102
103 tgt->status = 0;
104 tgt->sector_start = 0;
105 tgt->length = (dm->size_mb * (1024 * 1024)) / 512;
106 strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
107
108 p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
109 strcpy((char *) p, params);
110 p+= strlen(params) + 1;
111
112 p = _align(p, 8);
113 tgt->next = p - buffer;
114
115 return io;
116 }
117
118 static int get_next_available_dm()
119 {
120 int i;
121
122 for (i = 0; i < 8; i++) {
123 char path[255];
124 sprintf(path, "/dev/block/dm-%d", i);
125 if ((access(path, F_OK) < 0) && (errno == ENOENT))
126 return i;
127 }
128
129 LOGE("Out of device mapper numbers");
130 return -1;
131 }
132
133 static int create_devmapping(struct devmapping *dm)
134 {
135 struct dm_ioctl *io;
136 int rc, fd;
137
138 #if DEBUG_DEVMAPPER
139 LOG_VOL("create_devmapping():");
140 #endif
141
142 if (dm->dm_no < 0) {
143 LOGE("Invalid dm_no set");
144 return -EINVAL;
145 }
146
147 if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
148 LOGE("Error opening device mapper (%d)", errno);
149 return -errno;
150 }
151
152 if (!(io = _dm_ioctl_setup(dm, 0))) {
153 LOGE("Unable to setup ioctl (out of memory)");
154 close(fd);
155 return -ENOMEM;
156 }
157
158 if ((rc = ioctl(fd, DM_DEV_CREATE, io)) < 0) {
159 LOGE("device-mapper create ioctl failed (%d)", errno);
160 rc = -errno;
161 goto out_free;
162 }
163
164 free(io);
165
166 if (!(io = _dm_ioctl_setup(dm, DM_STATUS_TABLE_FLAG))) {
167 LOGE("Unable to setup ioctl (out of memory)");
168 rc = -ENOMEM;
169 goto out_nofree;
170 }
171
172 if ((rc = ioctl(fd, DM_TABLE_LOAD, io)) < 0) {
173 LOGE("device-mapper load ioctl failed (%d)", errno);
174 rc = -errno;
175 goto out_free;
176 }
177
178 free(io);
179
180 if (!(io = _dm_ioctl_setup(dm, 0))) {
181 LOGE("Unable to setup ioctl (out of memory)");
182 rc = -ENOMEM;
183 goto out_nofree;
184 }
185
186 if ((rc = ioctl(fd, DM_DEV_SUSPEND, io)) < 0) {
187 LOGE("device-mapper resume ioctl failed (%d)", errno);
188 rc = -errno;
189 goto out_free;
190 }
191
192 out_free:
193 free (io);
194 out_nofree:
195 close (fd);
196 return rc;
197 }
198
199 static int loopback_start(struct devmapping *dm)
200 {
201 int i;
202 int fd;
203 char filename[255];
204 int rc;
205
206 #if DEBUG_DEVMAPPER
207 LOG_VOL("loopback_start(%s):", dm->type_data.loop.loop_src);
208 #endif
209
210 for (i = 0; i < MAX_LOOP; i++) {
211 struct loop_info info;
212
213 sprintf(filename, "/dev/block/loop%d", i);
214
215 if ((fd = open(filename, O_RDWR)) < 0) {
216 LOGE("Unable to open %s (%s)", filename, strerror(errno));
217 return -errno;
218 }
219
220 rc = ioctl(fd, LOOP_GET_STATUS, &info);
221 if (rc < 0 && errno == ENXIO)
222 break;
223
224 close(fd);
225
226 if (rc < 0) {
227 LOGE("Unable to get loop status for %s (%s)", filename,
228 strerror(errno));
229 return -errno;
230 }
231 }
232
233 if (i == MAX_LOOP) {
234 LOGE("Out of loop devices");
235 return -ENOSPC;
236 }
237
238 int file_fd;
239
240 if ((file_fd = open(dm->type_data.loop.loop_src, O_RDWR)) < 0) {
241 LOGE("Unable to open %s (%s)", dm->type_data.loop.loop_src,
242 strerror(errno));
243 return -errno;
244 }
245
246 if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) {
247 LOGE("Error setting up loopback interface (%s)", strerror(errno));
248 return -errno;
249 }
250
251 dm->type_data.loop.loop_dev = strdup(filename);
252 dm->type_data.loop.loop_no = i;
253
254 close(fd);
255 close(file_fd);
256
257 #if DEBUG_DEVMAPPER
258 LOG_VOL("Loop setup on %s for %s", dm->type_data.loop.loop_dev,
259 dm->type_data.loop.loop_src);
260 #endif
261
262 return 0;
263 }
264
265 int devmapper_start(struct devmapping *dm)
266 {
267 int rc;
268 char src_blkdev_path[255];
269
270 #if DEBUG_DEVMAPPER
271 LOG_VOL("devmapper_start()");
272 #endif
273
274 if (dm->src_type == dmsrc_loopback) {
275 if ((rc = loopback_start(dm)) < 0)
276 return rc;
277 } else if (dm->src_type == dmsrc_partition) {
278 LOGE("partition maps not yet supported");
279 return -ENOSYS;
280 } else {
281 LOGE("devmapper_start(): Unsupported source type '%d'", dm->src_type);
282 return -ENOENT;
283 }
284
285 /*
286 * Configure the device mapper
287 */
288 if ((rc = create_devmapping(dm)) < 0) {
289 LOGE("Failed to create devmapping (%d)", rc);
290 // XXX: if loopback then tear down
291 return rc;
292 }
293
294 return 0;
295 }
296
297 struct devmapping *devmapper_init(char *src, char *src_type, uint32_t size_mb,
298 char *target, char *params, char *tgt_fs, char *mediapath)
299 {
300 struct devmapping *dm;
301
302 if (!(dm = malloc(sizeof(struct devmapping)))) {
303 LOGE("devmapper_init(): out of memory");
304 return NULL;
305 }
306
307 memset(dm, 0, sizeof(struct devmapping));
308
309 if (!strcmp(src_type, "loopback_file")) {
310 dm->src_type = dmsrc_loopback;
311 dm->type_data.loop.loop_src = strdup(src);
312 } else if (!strncmp(src_type, "partition ", strlen("partition "))) {
313 dm->src_type = dmsrc_partition;
314 char *p = strtok(src_type, " ");
315 if (!p) {
316 LOGE("Invalid partition specifier");
317 goto out_free;
318 }
319 dm->type_data.part.part_type = strtoul(p, NULL, 0);
320 } else {
321 LOGE("Invalid src_type defined (%s)", src_type);
322 goto out_free;
323 }
324
325 // XXX: Validate these
326 dm->size_mb = size_mb;
327 dm->target = strdup(target);
328 dm->params = strdup(params);
329 dm->tgt_fs = strdup(tgt_fs);
330
331 if ((dm->dm_no = get_next_available_dm()) < 0)
332 goto out_free;
333
334 sprintf(mediapath, "/devices/virtual/block/dm-%d", dm->dm_no);
335
336 if (!(dm->media = media_create(mediapath,
337 "unknown",
338 "unknown",
339 media_devmapper))) {
340 LOGE("Unable to create media");
341 goto out_free;
342 }
343
344 return dm;
345 out_free:
346 if (dm->target)
347 free(dm->target);
348 if (dm->params)
349 free(dm->params);
350 if (dm->tgt_fs)
351 free(dm->tgt_fs);
352
353 free(dm);
354 return NULL;
355 }
356
357 int devmapper_genesis(struct devmapping *dm)
358 {
359
360 if (dm->src_type == dmsrc_loopback) {
361 int fd;
362
363 LOG_VOL("devmapper_genesis(): Working on %s",
364 dm->type_data.loop.loop_src);
365
366 unlink(dm->type_data.loop.loop_src);
367
368 LOG_VOL("devmapper_genesis(): Creating imagefile (%u MB)",
369 dm->size_mb);
370
371 if ((fd = creat(dm->type_data.loop.loop_src, 0600)) < 0) {
372 LOGE("Error creating imagefile (%s)", strerror(errno));
373 return -errno;
374 }
375
376 if (ftruncate(fd, (dm->size_mb * (1024 * 1024))) < 0) {
377 LOGE("Error truncating imagefile (%s)", strerror(errno));
378 close(fd);
379 return -errno;
380 }
381 close(fd);
382 } else if (dm->src_type == dmsrc_partition) {
383 LOGE("partition maps not yet supported");
384 return -ENOSYS;
385 }
386
387 return devmapper_start(dm);
388 }
389
390 static int destroy_devmapping(struct devmapping *dm)
391 {
392 struct dm_ioctl *io;
393 int dmFd;
394 int rc = 0;
395
396 LOG_VOL("destroy_devmapping():");
397
398 if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
399 LOGE("Error opening device mapper (%d)", errno);
400 return -errno;
401 }
402
403 if (!(io = _dm_ioctl_setup(dm, DM_PERSISTENT_DEV_FLAG))) {
404 LOGE("Unable to setup ioctl (out of memory)");
405 rc = -ENOMEM;
406 goto out_nofree;
407 }
408
409 if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
410 LOGE("device-mapper remove ioctl failed (%d)", errno);
411 rc = -errno;
412 goto out_free;
413 }
414
415 out_free:
416 free (io);
417 out_nofree:
418 close (dmFd);
419 return rc;
420 }
421
422 static int loopback_stop(struct devmapping *dm)
423 {
424 char devname[255];
425 int device_fd;
426 int rc = 0;
427
428 LOG_VOL("loopback_stop():");
429
430 device_fd = open(dm->type_data.loop.loop_dev, O_RDONLY);
431 if (device_fd < 0) {
432 LOG_ERROR("Failed to open loop (%d)", errno);
433 return -errno;
434 }
435
436 if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
437 LOG_ERROR("Failed to destroy loop (%d)", errno);
438 rc = -errno;
439 }
440
441 close(device_fd);
442 return rc;
443 }
444
445 int devmapper_stop(struct devmapping *dm)
446 {
447 int rc;
448
449 LOG_VOL("devmapper_stop():");
450
451 if ((rc = destroy_devmapping(dm)))
452 return rc;
453
454 if (dm->src_type == dmsrc_loopback) {
455 if ((rc = loopback_stop(dm)))
456 return rc;
457 } else if (dm->src_type == dmsrc_partition) {
458 LOGE("partition maps not yet supported");
459 return -ENOSYS;
460 }
461 return 0;
462 }
+0
-70
vold/devmapper.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _DEVMAPPER_H
18 #define _DEVMAPPER_H
19
20 #include <pthread.h>
21
22 #include "vold.h"
23 #include "blkdev.h"
24 #include "media.h"
25
26 #define MAX_LOOP 8
27
28 enum dm_src_type {
29 dmsrc_unknown,
30 dmsrc_loopback,
31 dmsrc_partition,
32 };
33
34 struct loop_data {
35 char *loop_src;
36
37 char *loop_dev;
38 int loop_no;
39 };
40
41 struct part_data {
42 char part_type;
43
44 char *part_dev;
45 };
46
47 struct devmapping {
48 enum dm_src_type src_type;
49 union {
50 struct loop_data loop;
51 struct part_data part;
52 } type_data;
53
54 uint32_t size_mb;
55 char *target;
56 char *params;
57 char *tgt_fs;
58
59 unsigned char key[16];
60 int dm_no;
61
62 media_t *media;
63 };
64
65 struct devmapping *devmapper_init(char *, char *, unsigned int, char *, char *, char *, char *);
66 int devmapper_start(struct devmapping *);
67 int devmapper_stop(struct devmapping *);
68 int devmapper_genesis(struct devmapping *);
69 #endif
+0
-75
vold/diskmbr.h less more
0 /*-
1 * Copyright (c) 1987, 1988, 1993
2 * The Regents of the University of California. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 4. Neither the name of the University nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * @(#)disklabel.h 8.2 (Berkeley) 7/10/94
29 * $FreeBSD: src/sys/sys/diskmbr.h,v 1.99.2.1 2005/01/31 23:26:56 imp Exp $
30 */
31
32 #ifndef _SYS_DISKMBR_H_
33 #define _SYS_DISKMBR_H_
34
35 #define DOSBBSECTOR 0 /* DOS boot block relative sector number */
36 #define DOSPARTOFF 446
37 #define DOSPARTSIZE 16
38 #define NDOSPART 4
39 #define NEXTDOSPART 32
40 #define DOSMAGICOFFSET 510
41 #define DOSMAGIC 0xAA55
42
43 #define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */
44 #define DOSPTYP_LINSWP 0x82 /* Linux swap partition */
45 #define DOSPTYP_LINUX 0x83 /* Linux partition */
46 #define DOSPTYP_PMBR 0xee /* GPT Protective MBR */
47 #define DOSPTYP_EXT 5 /* DOS extended partition */
48 #define DOSPTYP_EXTLBA 15 /* DOS extended partition */
49
50 struct dos_partition {
51 unsigned char dp_flag; /* bootstrap flags */
52 unsigned char dp_shd; /* starting head */
53 unsigned char dp_ssect; /* starting sector */
54 unsigned char dp_scyl; /* starting cylinder */
55 unsigned char dp_typ; /* partition type */
56 unsigned char dp_ehd; /* end head */
57 unsigned char dp_esect; /* end sector */
58 unsigned char dp_ecyl; /* end cylinder */
59 u_int32_t dp_start; /* absolute starting sector number */
60 u_int32_t dp_size; /* partition size in sectors */
61 };
62 #ifdef CTASSERT
63 CTASSERT(sizeof (struct dos_partition) == DOSPARTSIZE);
64 #endif
65
66 void dos_partition_dec(void const *pp, struct dos_partition *d);
67 void dos_partition_enc(void *pp, struct dos_partition *d);
68
69 #define DPSECT(s) ((s) & 0x3f) /* isolate relevant bits of sector */
70 #define DPCYL(c, s) ((c) + (((s) & 0xc0)<<2)) /* and those that are cylinder */
71
72 #define DIOCSMBR _IOW('M', 129, u_char[512])
73
74 #endif /* !_SYS_DISKMBR_H_ */
+0
-113
vold/format.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #include <linux/fs.h>
21
22 #include "vold.h"
23 #include "blkdev.h"
24 #include "format.h"
25 #include "diskmbr.h"
26 #include "logwrapper.h"
27
28 static char MKDOSFS_PATH[] = "/system/bin/mkdosfs";
29 static char MKE2FS_PATH[] = "/system/bin/mke2fs";
30
31 int format_partition(blkdev_t *part, char *type)
32 {
33 char *devpath;
34 int rc = -EINVAL;
35
36 devpath = blkdev_get_devpath(part);
37
38 if (!strcmp(type, FORMAT_TYPE_FAT32)) {
39 char *args[7];
40 args[0] = MKDOSFS_PATH;
41 args[1] = "-F 32";
42 args[2] = "-c 32";
43 args[3] = "-n 2";
44 args[4] = "-O android";
45 args[5] = devpath;
46 args[6] = NULL;
47 rc = logwrap(6, args);
48 } else {
49 char *args[7];
50 args[0] = MKE2FS_PATH;
51 args[1] = "-b 4096";
52 args[2] = "-m 1";
53 args[3] = "-L android";
54 args[4] = "-v";
55 args[5] = devpath;
56 args[6] = NULL;
57 rc = logwrap(6, args);
58 }
59
60 free(devpath);
61
62 if (rc == 0) {
63 LOG_VOL("Filesystem formatted OK");
64 return 0;
65 } else {
66 LOGE("Format failed (unknokwn exit code %d)", rc);
67 return -EIO;
68 }
69 return 0;
70 }
71
72 int initialize_mbr(blkdev_t *disk)
73 {
74 int fd, rc;
75 unsigned char block[512];
76 struct dos_partition part;
77 char *devpath;
78
79 devpath = blkdev_get_devpath(disk);
80
81 memset(&part, 0, sizeof(part));
82 part.dp_flag = 0x80;
83 part.dp_typ = 0xc;
84 part.dp_start = ((1024 * 64) / 512) + 1;
85 part.dp_size = disk->nr_sec - part.dp_start;
86
87 memset(block, 0, sizeof(block));
88 block[0x1fe] = 0x55;
89 block[0x1ff] = 0xaa;
90
91 dos_partition_enc(block + DOSPARTOFF, &part);
92
93 if ((fd = open(devpath, O_RDWR)) < 0) {
94 LOGE("Error opening disk file (%s)", strerror(errno));
95 return -errno;
96 }
97 free(devpath);
98
99 if (write(fd, block, sizeof(block)) < 0) {
100 LOGE("Error writing MBR (%s)", strerror(errno));
101 close(fd);
102 return -errno;
103 }
104
105 if (ioctl(fd, BLKRRPART, NULL) < 0) {
106 LOGE("Error re-reading partition table (%s)", strerror(errno));
107 close(fd);
108 return -errno;
109 }
110 close(fd);
111 return 0;
112 }
+0
-26
vold/format.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _FORMAT_H
18 #define _FORMAT_H
19
20 #define FORMAT_TYPE_EXT2 "ext2"
21 #define FORMAT_TYPE_FAT32 "fat32"
22
23 int format_partition(blkdev_t *part, char *type);
24 int initialize_mbr(blkdev_t *disk);
25 #endif
+0
-90
vold/geom_mbr_enc.c less more
0 /*-
1 * Copyright (c) 2003 Poul-Henning Kamp
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 /* Functions to encode or decode struct dos_partition into a bytestream
27 * of correct endianess and packing. These functions do no validation
28 * or sanity checking, they only pack/unpack the fields correctly.
29 *
30 * NB! This file must be usable both in kernel and userland.
31 */
32
33 #include <sys/types.h>
34 #include <sys/endian.h>
35
36 #include "diskmbr.h"
37
38 static __inline uint32_t __unused
39 le32dec(const void *buf)
40 {
41 const uint8_t *p = (const uint8_t *)buf;
42
43 return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
44 }
45
46 static __inline void
47 le32enc(void *pp, uint32_t u)
48 {
49 unsigned char *p = (unsigned char *)pp;
50
51 p[0] = u & 0xff;
52 p[1] = (u >> 8) & 0xff;
53 p[2] = (u >> 16) & 0xff;
54 p[3] = (u >> 24) & 0xff;
55 }
56
57 void
58 dos_partition_dec(void const *pp, struct dos_partition *d)
59 {
60 unsigned char const *p = pp;
61
62 d->dp_flag = p[0];
63 d->dp_shd = p[1];
64 d->dp_ssect = p[2];
65 d->dp_scyl = p[3];
66 d->dp_typ = p[4];
67 d->dp_ehd = p[5];
68 d->dp_esect = p[6];
69 d->dp_ecyl = p[7];
70 d->dp_start = le32dec(p + 8);
71 d->dp_size = le32dec(p + 12);
72 }
73
74 void
75 dos_partition_enc(void *pp, struct dos_partition *d)
76 {
77 unsigned char *p = pp;
78
79 p[0] = d->dp_flag;
80 p[1] = d->dp_shd;
81 p[2] = d->dp_ssect;
82 p[3] = d->dp_scyl;
83 p[4] = d->dp_typ;
84 p[5] = d->dp_ehd;
85 p[6] = d->dp_esect;
86 p[7] = d->dp_ecyl;
87 le32enc(p + 8, d->dp_start);
88 le32enc(p + 12, d->dp_size);
89 }
+0
-147
vold/logwrapper.c less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <fcntl.h>
24
25 #include "private/android_filesystem_config.h"
26 #include "cutils/log.h"
27
28 int parent(const char *tag, int parent_read) {
29 int status;
30 char buffer[4096];
31
32 int a = 0; // start index of unprocessed data
33 int b = 0; // end index of unprocessed data
34 int sz;
35 while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
36
37 sz += b;
38 // Log one line at a time
39 for (b = 0; b < sz; b++) {
40 if (buffer[b] == '\r') {
41 buffer[b] = '\0';
42 } else if (buffer[b] == '\n') {
43 buffer[b] = '\0';
44 LOG(LOG_INFO, tag, &buffer[a]);
45 a = b + 1;
46 }
47 }
48
49 if (a == 0 && b == sizeof(buffer) - 1) {
50 // buffer is full, flush
51 buffer[b] = '\0';
52 LOG(LOG_INFO, tag, &buffer[a]);
53 b = 0;
54 } else if (a != b) {
55 // Keep left-overs
56 b -= a;
57 memmove(buffer, &buffer[a], b);
58 a = 0;
59 } else {
60 a = 0;
61 b = 0;
62 }
63
64 }
65 // Flush remaining data
66 if (a != b) {
67 buffer[b] = '\0';
68 LOG(LOG_INFO, tag, &buffer[a]);
69 }
70 status = 0xAAAA;
71 if (wait(&status) != -1) { // Wait for child
72 if (WIFEXITED(status)) {
73 LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
74 WEXITSTATUS(status));
75 return WEXITSTATUS(status);
76 } else if (WIFSIGNALED(status))
77 LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
78 WTERMSIG(status));
79 else if (WIFSTOPPED(status))
80 LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
81 WSTOPSIG(status));
82 } else
83 LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
84 strerror(errno), errno);
85 return -EAGAIN;
86 }
87
88 void child(int argc, char* argv[]) {
89 // create null terminated argv_child array
90 char* argv_child[argc + 1];
91 memcpy(argv_child, argv, argc * sizeof(char *));
92 argv_child[argc] = NULL;
93
94 // XXX: PROTECT FROM VIKING KILLER
95 if (execvp(argv_child[0], argv_child)) {
96 LOG(LOG_ERROR, "logwrapper",
97 "executing %s failed: %s", argv_child[0], strerror(errno));
98 exit(-1);
99 }
100 }
101
102 int logwrap(int argc, char* argv[], pid_t *childPid)
103 {
104 pid_t pid;
105
106 int parent_ptty;
107 int child_ptty;
108 char *child_devname = NULL;
109
110 /* Use ptty instead of socketpair so that STDOUT is not buffered */
111 parent_ptty = open("/dev/ptmx", O_RDWR);
112 if (parent_ptty < 0) {
113 LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
114 return -errno;
115 }
116
117 if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
118 ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
119 LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
120 return -1;
121 }
122
123 pid = fork();
124 if (pid < 0) {
125 LOG(LOG_ERROR, "logwrapper", "Failed to fork");
126 return -errno;
127 } else if (pid == 0) {
128 child_ptty = open(child_devname, O_RDWR);
129 if (child_ptty < 0) {
130 LOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
131 return -errno;
132 }
133
134 // redirect stdout and stderr
135 close(parent_ptty);
136 dup2(child_ptty, 1);
137 dup2(child_ptty, 2);
138 close(child_ptty);
139
140 child(argc, argv);
141 } else {
142 return parent(argv[0], parent_ptty);
143 }
144
145 return 0;
146 }
+0
-23
vold/logwrapper.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _LOGWRAPPER_H
18 #define _LOGWRAPPER_H
19
20 #include <stdlib.h>
21 int logwrap(int argc, char* argv[]);
22 #endif
+0
-165
vold/media.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <errno.h>
21
22 #include <sys/types.h>
23
24 #include "vold.h"
25 #include "media.h"
26
27 static media_list_t *list_root = NULL;
28
29 media_t *media_create(char *devpath, char *name, char *serial, media_type_t type)
30 {
31 media_list_t *list_entry;
32 media_t *new;
33
34 if (!(new = malloc(sizeof(media_t))))
35 return NULL;
36
37 memset(new, 0, sizeof(media_t));
38
39 if (!(list_entry = malloc(sizeof(media_list_t)))) {
40 free(new);
41 return NULL;
42 }
43 list_entry->media = new;
44 list_entry->next = NULL;
45
46 if (!list_root)
47 list_root = list_entry;
48 else {
49 media_list_t *list_scan = list_root;
50 while(list_scan->next)
51 list_scan = list_scan->next;
52 list_scan->next = list_entry;
53 }
54
55 new->devpath = strdup(devpath);
56 new->name = strdup(name);
57 if (!serial)
58 new->serial = 0;
59 else
60 new->serial = strtoul(serial, NULL, 0);
61
62 new->media_type = type;
63
64 return new;
65 }
66
67 void media_destroy(media_t *media)
68 {
69 media_list_t *list_next;
70
71 if (list_root->media == media) {
72 list_next = list_root->next;
73 free(list_root);
74 list_root = list_next;
75 } else {
76 media_list_t *list_scan = list_root;
77 while (list_scan->next->media != media)
78 list_scan = list_scan -> next;
79 list_next = list_scan->next->next;
80 free(list_scan->next);
81 list_scan->next = list_next;
82 }
83
84 free(media->devpath);
85 free(media->name);
86
87 while(media->devs)
88 media_remove_blkdev(media, media->devs->dev);
89 free(media);
90 }
91
92 media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match)
93 {
94 media_list_t *list_scan = list_root;
95
96 while (list_scan) {
97 if (fuzzy_match) {
98 if (!strncmp(list_scan->media->devpath, devpath, strlen(devpath)))
99 return list_scan->media;
100 } else {
101 if (!strcmp(list_scan->media->devpath, devpath))
102 return list_scan->media;
103 }
104 list_scan = list_scan->next;
105 }
106 #if DEBUG_MEDIA
107 LOG_VOL("media_lookup_by_path(): No media found @ %s", devpath);
108 #endif
109 return NULL;
110 }
111
112 int media_add_blkdev(media_t *card, blkdev_t *dev)
113 {
114 blkdev_list_t *list_entry;
115
116 if (!(list_entry = malloc(sizeof(blkdev_list_t)))) {
117 LOGE("Out of memory");
118 return -ENOMEM;
119 }
120
121 list_entry->next = NULL;
122 list_entry->dev = dev;
123 if (!card->devs)
124 card->devs = list_entry;
125 else {
126 blkdev_list_t *scan = card->devs;
127
128 while(scan->next)
129 scan = scan->next;
130
131 scan->next = list_entry;
132 }
133 return 0;
134 }
135
136 void media_remove_blkdev(media_t *card, blkdev_t *dev)
137 {
138 if (card->devs->dev == dev)
139 card->devs = card->devs->next;
140 else {
141 blkdev_list_t *scan = card->devs;
142 while (scan->next->dev != dev)
143 scan = scan -> next;
144 blkdev_list_t *next = scan->next->next;
145 free(scan->next);
146 scan->next = next;
147 }
148 }
149
150 media_t *media_lookup_by_dev(blkdev_t *dev)
151 {
152 media_list_t *media_scan = list_root;
153
154 while (media_scan) {
155 blkdev_list_t *blk_scan = media_scan->media->devs;
156 while (blk_scan) {
157 if (blk_scan->dev == dev)
158 return media_scan->media;
159 blk_scan = blk_scan->next;
160 }
161 media_scan = media_scan->next;
162 }
163 return NULL;
164 }
+0
-51
vold/media.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _MEDIA_H
18 #define _MEDIA_H
19
20 #include <sys/types.h>
21
22 #include "blkdev.h"
23
24 typedef enum media_type {
25 media_unknown,
26 media_mmc,
27 media_devmapper,
28 } media_type_t;
29
30 typedef struct media {
31 char *devpath;
32 char *name;
33 uint32_t serial;
34 media_type_t media_type;
35
36 blkdev_list_t *devs;
37 } media_t;
38
39 typedef struct media_list {
40 media_t *media;
41 struct media_list *next;
42 } media_list_t;
43
44 media_t *media_create(char *devpath, char *name, char *serial, enum media_type);
45 media_t *media_lookup_by_path(char *devpath, boolean fuzzy_match);
46 media_t *media_lookup_by_dev(blkdev_t *dev);
47 void media_destroy(media_t *media);
48 int media_add_blkdev(media_t *media, blkdev_t *dev);
49 void media_remove_blkdev(media_t *media, blkdev_t *dev);
50 #endif
+0
-91
vold/misc.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <malloc.h>
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 void *read_file(char *filename, ssize_t *_size)
28 {
29 int ret, fd;
30 struct stat sb;
31 ssize_t size;
32 void *buffer = NULL;
33
34 /* open the file */
35 fd = open(filename, O_RDONLY);
36 if (fd < 0)
37 return NULL;
38
39 /* find out how big it is */
40 if (fstat(fd, &sb) < 0)
41 goto bail;
42 size = sb.st_size;
43
44 /* allocate memory for it to be read into */
45 buffer = malloc(size);
46 if (!buffer)
47 goto bail;
48
49 /* slurp it into our buffer */
50 ret = read(fd, buffer, size);
51 if (ret != size)
52 goto bail;
53
54 /* let the caller know how big it is */
55 *_size = size;
56
57 bail:
58 close(fd);
59 return buffer;
60 }
61 char *truncate_sysfs_path(char *path, int num_elements_to_remove, char *buffer)
62 {
63 int i;
64
65 strcpy(buffer, path);
66
67 for (i = 0; i < num_elements_to_remove; i++) {
68 char *p = &buffer[strlen(buffer)-1];
69
70 for (p = &buffer[strlen(buffer) -1]; *p != '/'; p--);
71 *p = '\0';
72 }
73
74 return buffer;
75 }
76
77 char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var)
78 {
79 char filename[255];
80 char *p;
81 ssize_t sz;
82
83 sprintf(filename, "/sys%s/%s", devpath, var);
84 p = read_file(filename, &sz);
85 p[(strlen(p) - 1)] = '\0';
86 strncpy(buffer, p, maxlen);
87 free(p);
88 return buffer;
89 }
90
+0
-293
vold/mmc.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <errno.h>
21
22 #include <sys/types.h>
23
24 #include "vold.h"
25 #include "mmc.h"
26 #include "media.h"
27
28 #define DEBUG_BOOTSTRAP 0
29
30 static int mmc_bootstrap_controller(char *sysfs_path);
31 static int mmc_bootstrap_card(char *sysfs_path);
32 static int mmc_bootstrap_block(char *devpath);
33 static int mmc_bootstrap_mmcblk(char *devpath);
34 static int mmc_bootstrap_mmcblk_partition(char *devpath);
35
36 /*
37 * Bootstrap our mmc information.
38 */
39 int mmc_bootstrap()
40 {
41 DIR *d;
42 struct dirent *de;
43
44 if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) {
45 LOG_ERROR("Unable to open '%s' (%m)", SYSFS_CLASS_MMC_PATH);
46 return -errno;
47 }
48
49 while ((de = readdir(d))) {
50 char tmp[255];
51
52 if (de->d_name[0] == '.')
53 continue;
54
55 sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name);
56 if (mmc_bootstrap_controller(tmp))
57 LOG_ERROR("Error bootstrapping controller '%s' (%m)", tmp);
58 }
59
60 closedir(d);
61
62 return 0;
63 }
64
65 static int mmc_bootstrap_controller(char *sysfs_path)
66 {
67 DIR *d;
68 struct dirent *de;
69
70 #if DEBUG_BOOTSTRAP
71 LOG_VOL("bootstrap_controller(%s):", sysfs_path);
72 #endif
73 if (!(d = opendir(sysfs_path))) {
74 LOG_ERROR("Unable to open '%s' (%m)", sysfs_path);
75 return -errno;
76 }
77
78 while ((de = readdir(d))) {
79 char tmp[255];
80
81 if (de->d_name[0] == '.')
82 continue;
83
84 if ((!strcmp(de->d_name, "uevent")) ||
85 (!strcmp(de->d_name, "subsystem")) ||
86 (!strcmp(de->d_name, "device")) ||
87 (!strcmp(de->d_name, "power"))) {
88 continue;
89 }
90
91 sprintf(tmp, "%s/%s", sysfs_path, de->d_name);
92
93 if (mmc_bootstrap_card(tmp) < 0)
94 LOG_ERROR("Error bootstrapping card '%s' (%m)", tmp);
95 } // while
96
97 closedir(d);
98 return 0;
99 }
100
101 static int mmc_bootstrap_card(char *sysfs_path)
102 {
103 char saved_cwd[255];
104 char new_cwd[255];
105 char *devpath;
106 char *uevent_params[4];
107 char *p;
108 char filename[255];
109 char tmp[255];
110 ssize_t sz;
111
112 #if DEBUG_BOOTSTRAP
113 LOG_VOL("bootstrap_card(%s):", sysfs_path);
114 #endif
115
116 /*
117 * sysfs_path is based on /sys/class, but we want the actual device class
118 */
119 if (!getcwd(saved_cwd, sizeof(saved_cwd))) {
120 LOGE("Error getting working dir path");
121 return -errno;
122 }
123
124 if (chdir(sysfs_path) < 0) {
125 LOGE("Unable to chdir to %s (%m)", sysfs_path);
126 return -errno;
127 }
128
129 if (!getcwd(new_cwd, sizeof(new_cwd))) {
130 LOGE("Buffer too small for device path");
131 return -errno;
132 }
133
134 if (chdir(saved_cwd) < 0) {
135 LOGE("Unable to restore working dir");
136 return -errno;
137 }
138
139 devpath = &new_cwd[4]; // Skip over '/sys'
140
141 /*
142 * Collect parameters so we can simulate a UEVENT
143 */
144 sprintf(tmp, "DEVPATH=%s", devpath);
145 uevent_params[0] = (char *) strdup(tmp);
146
147 sprintf(filename, "/sys%s/type", devpath);
148 p = read_file(filename, &sz);
149 p[strlen(p) - 1] = '\0';
150 sprintf(tmp, "MMC_TYPE=%s", p);
151 free(p);
152 uevent_params[1] = (char *) strdup(tmp);
153
154 sprintf(filename, "/sys%s/name", devpath);
155 p = read_file(filename, &sz);
156 p[strlen(p) - 1] = '\0';
157 sprintf(tmp, "MMC_NAME=%s", p);
158 free(p);
159 uevent_params[2] = (char *) strdup(tmp);
160
161 uevent_params[3] = (char *) NULL;
162
163 if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) {
164 LOGE("Error simulating uevent (%m)");
165 return -errno;
166 }
167
168 /*
169 * Check for block drivers
170 */
171 char block_devpath[255];
172 sprintf(tmp, "%s/block", devpath);
173 sprintf(filename, "/sys%s/block", devpath);
174 if (!access(filename, F_OK)) {
175 if (mmc_bootstrap_block(tmp)) {
176 LOGE("Error bootstrapping block @ %s", tmp);
177 }
178 }
179
180 return 0;
181 }
182
183 static int mmc_bootstrap_block(char *devpath)
184 {
185 char blockdir_path[255];
186 DIR *d;
187 struct dirent *de;
188
189 #if DEBUG_BOOTSTRAP
190 LOG_VOL("mmc_bootstrap_block(%s):", devpath);
191 #endif
192
193 sprintf(blockdir_path, "/sys%s", devpath);
194
195 if (!(d = opendir(blockdir_path))) {
196 LOGE("Failed to opendir %s", devpath);
197 return -errno;
198 }
199
200 while ((de = readdir(d))) {
201 char tmp[255];
202
203 if (de->d_name[0] == '.')
204 continue;
205 sprintf(tmp, "%s/%s", devpath, de->d_name);
206 if (mmc_bootstrap_mmcblk(tmp))
207 LOGE("Error bootstraping mmcblk @ %s", tmp);
208 }
209 closedir(d);
210 return 0;
211 }
212
213 static int mmc_bootstrap_mmcblk(char *devpath)
214 {
215 char *mmcblk_devname;
216 int part_no;
217 int rc;
218
219 #if DEBUG_BOOTSTRAP
220 LOG_VOL("mmc_bootstrap_mmcblk(%s):", devpath);
221 #endif
222
223 if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) {
224 LOGE("Error bootstrapping mmcblk partition '%s'", devpath);
225 return rc;
226 }
227
228 for (mmcblk_devname = &devpath[strlen(devpath)];
229 *mmcblk_devname != '/'; mmcblk_devname--);
230 mmcblk_devname++;
231
232 for (part_no = 0; part_no < 4; part_no++) {
233 char part_file[255];
234 sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
235 if (!access(part_file, F_OK)) {
236 char part_devpath[255];
237
238 sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no);
239 if (mmc_bootstrap_mmcblk_partition(part_devpath))
240 LOGE("Error bootstrapping mmcblk partition '%s'", part_devpath);
241 }
242 }
243
244 return 0;
245 }
246
247 static int mmc_bootstrap_mmcblk_partition(char *devpath)
248 {
249 char filename[255];
250 char *uevent_buffer;
251 ssize_t sz;
252 char *uevent_params[4];
253 char tmp[255];
254 FILE *fp;
255 char line[255];
256
257 #if DEBUG_BOOTSTRAP
258 LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):", devpath);
259 #endif
260
261 sprintf(tmp, "DEVPATH=%s", devpath);
262 uevent_params[0] = strdup(tmp);
263
264 sprintf(filename, "/sys%s/uevent", devpath);
265 if (!(fp = fopen(filename, "r"))) {
266 LOGE("Unable to open '%s' (%m)", filename);
267 return -errno;
268 }
269
270 while (fgets(line, sizeof(line), fp)) {
271 line[strlen(line)-1] = 0;
272 if (!strncmp(line, "DEVTYPE=", 8))
273 uevent_params[1] = strdup(line);
274 else if (!strncmp(line, "MAJOR=",6))
275 uevent_params[2] = strdup(line);
276 else if (!strncmp(line, "MINOR=",6))
277 uevent_params[3] = strdup(line);
278 }
279 fclose(fp);
280
281 if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) {
282 LOGE("mmcblk uevent missing required params");
283 return -1;
284 }
285 uevent_params[4] = '\0';
286
287 if (simulate_uevent("block", devpath, "add", uevent_params) < 0) {
288 LOGE("Error simulating uevent (%m)");
289 return -errno;
290 }
291 return 0;
292 }
+0
-23
vold/mmc.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _MMC_H
18 #define _MMC_H
19
20 #define SYSFS_CLASS_MMC_PATH "/sys/class/mmc_host"
21
22 #endif
+0
-121
vold/switch.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <errno.h>
21
22 #include <sys/types.h>
23
24 #include "vold.h"
25 #include "switch.h"
26
27 #define DEBUG_BOOTSTRAP 0
28
29 static int mmc_bootstrap_switch(char *sysfs_path);
30
31 int switch_bootstrap()
32 {
33 DIR *d;
34 struct dirent *de;
35
36 if (!(d = opendir(SYSFS_CLASS_SWITCH_PATH))) {
37 LOG_ERROR("Unable to open '%s' (%m)", SYSFS_CLASS_SWITCH_PATH);
38 return -errno;
39 }
40
41 while ((de = readdir(d))) {
42 char tmp[255];
43
44 if (de->d_name[0] == '.')
45 continue;
46
47 sprintf(tmp, "%s/%s", SYSFS_CLASS_SWITCH_PATH, de->d_name);
48 if (mmc_bootstrap_switch(tmp))
49 LOG_ERROR("Error bootstrapping switch '%s' (%m)", tmp);
50 }
51
52 closedir(d);
53
54 return 0;
55 }
56
57 static int mmc_bootstrap_switch(char *sysfs_path)
58 {
59 #if DEBUG_BOOTSTRAP
60 LOG_VOL("bootstrap_switch(%s):", sysfs_path);
61 #endif
62
63 char filename[255];
64 char name[255];
65 char state[255];
66 char tmp[255];
67 char *uevent_params[3];
68 char devpath[255];
69 FILE *fp;
70
71 /*
72 * Read switch name
73 */
74 sprintf(filename, "%s/name", sysfs_path);
75 if (!(fp = fopen(filename, "r"))) {
76 LOGE("Error opening switch name path '%s' (%s)",
77 sysfs_path, strerror(errno));
78 return -errno;
79 }
80 if (!fgets(name, sizeof(name), fp)) {
81 LOGE("Unable to read switch name");
82 fclose(fp);
83 return -EIO;
84 }
85 fclose(fp);
86
87 name[strlen(name) -1] = '\0';
88 sprintf(devpath, "/devices/virtual/switch/%s", name);
89 sprintf(tmp, "SWITCH_NAME=%s", name);
90 uevent_params[0] = (char *) strdup(tmp);
91
92 /*
93 * Read switch state
94 */
95 sprintf(filename, "%s/state", sysfs_path);
96 if (!(fp = fopen(filename, "r"))) {
97 LOGE("Error opening switch state path '%s' (%s)",
98 sysfs_path, strerror(errno));
99 return -errno;
100 }
101 if (!fgets(state, sizeof(state), fp)) {
102 LOGE("Unable to read switch state");
103 fclose(fp);
104 return -EIO;
105 }
106 fclose(fp);
107
108 state[strlen(state) -1] = '\0';
109 sprintf(tmp, "SWITCH_STATE=%s", state);
110 uevent_params[1] = (char *) strdup(tmp);
111
112 uevent_params[2] = (char *) NULL;
113
114 if (simulate_uevent("switch", devpath, "add", uevent_params) < 0) {
115 LOGE("Error simulating uevent (%s)", strerror(errno));
116 return -errno;
117 }
118
119 return 0;
120 }
+0
-25
vold/switch.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _SWITCH_H
18 #define _SWITCH_H
19
20 #include "vold.h"
21
22 #define SYSFS_CLASS_SWITCH_PATH "/sys/class/switch"
23
24 #endif
+0
-443
vold/uevent.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20
21 #include <sys/types.h>
22 #include <sys/socket.h>
23
24 #include "vold.h"
25 #include "uevent.h"
26 #include "mmc.h"
27 #include "blkdev.h"
28 #include "volmgr.h"
29 #include "media.h"
30
31 #define DEBUG_UEVENT 0
32
33 #define UEVENT_PARAMS_MAX 32
34
35 enum uevent_action { action_add, action_remove, action_change };
36
37 struct uevent {
38 char *path;
39 enum uevent_action action;
40 char *subsystem;
41 char *param[UEVENT_PARAMS_MAX];
42 unsigned int seqnum;
43 };
44
45 struct uevent_dispatch {
46 char *subsystem;
47 int (* dispatch) (struct uevent *);
48 };
49
50 static void dump_uevent(struct uevent *);
51 static int dispatch_uevent(struct uevent *event);
52 static void free_uevent(struct uevent *event);
53 static char *get_uevent_param(struct uevent *event, char *param_name);
54
55 static int handle_powersupply_event(struct uevent *event);
56 static int handle_switch_event(struct uevent *);
57 static int handle_battery_event(struct uevent *);
58 static int handle_mmc_event(struct uevent *);
59 static int handle_block_event(struct uevent *);
60 static int handle_bdi_event(struct uevent *);
61 static void _cb_blkdev_ok_to_destroy(blkdev_t *dev);
62
63 static struct uevent_dispatch dispatch_table[] = {
64 { "switch", handle_switch_event },
65 { "battery", handle_battery_event },
66 { "mmc", handle_mmc_event },
67 { "block", handle_block_event },
68 { "bdi", handle_bdi_event },
69 { "power_supply", handle_powersupply_event },
70 { NULL, NULL }
71 };
72
73 static boolean low_batt = false;
74 static boolean door_open = true;
75
76 int process_uevent_message(int socket)
77 {
78 char buffer[64 * 1024]; // Thank god we're not in the kernel :)
79 int count;
80 char *s = buffer;
81 char *end;
82 struct uevent *event;
83 int param_idx = 0;
84 int i;
85 int first = 1;
86 int rc = 0;
87
88 if ((count = recv(socket, buffer, sizeof(buffer), 0)) < 0) {
89 LOGE("Error receiving uevent (%s)", strerror(errno));
90 return -errno;
91 }
92
93 if (!(event = malloc(sizeof(struct uevent)))) {
94 LOGE("Error allocating memory (%s)", strerror(errno));
95 return -errno;
96 }
97
98 memset(event, 0, sizeof(struct uevent));
99
100 end = s + count;
101 while (s < end) {
102 if (first) {
103 char *p;
104 for (p = s; *p != '@'; p++);
105 p++;
106 event->path = strdup(p);
107 first = 0;
108 } else {
109 if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
110 char *a = s + strlen("ACTION=");
111
112 if (!strcmp(a, "add"))
113 event->action = action_add;
114 else if (!strcmp(a, "change"))
115 event->action = action_change;
116 else if (!strcmp(a, "remove"))
117 event->action = action_remove;
118 } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
119 event->seqnum = atoi(s + strlen("SEQNUM="));
120 else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
121 event->subsystem = strdup(s + strlen("SUBSYSTEM="));
122 else
123 event->param[param_idx++] = strdup(s);
124 }
125 s+= strlen(s) + 1;
126 }
127
128 rc = dispatch_uevent(event);
129
130 free_uevent(event);
131 return rc;
132 }
133
134 int simulate_uevent(char *subsys, char *path, char *action, char **params)
135 {
136 struct uevent *event;
137 char tmp[255];
138 int i, rc;
139
140 if (!(event = malloc(sizeof(struct uevent)))) {
141 LOGE("Error allocating memory (%s)", strerror(errno));
142 return -errno;
143 }
144
145 memset(event, 0, sizeof(struct uevent));
146
147 event->subsystem = strdup(subsys);
148
149 if (!strcmp(action, "add"))
150 event->action = action_add;
151 else if (!strcmp(action, "change"))
152 event->action = action_change;
153 else if (!strcmp(action, "remove"))
154 event->action = action_remove;
155 else {
156 LOGE("Invalid action '%s'", action);
157 return -1;
158 }
159
160 event->path = strdup(path);
161
162 for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
163 if (!params[i])
164 break;
165 event->param[i] = strdup(params[i]);
166 }
167
168 rc = dispatch_uevent(event);
169 free_uevent(event);
170 return rc;
171 }
172
173 static int dispatch_uevent(struct uevent *event)
174 {
175 int i;
176
177 #if DEBUG_UEVENT
178 dump_uevent(event);
179 #endif
180 for (i = 0; dispatch_table[i].subsystem != NULL; i++) {
181 if (!strcmp(dispatch_table[i].subsystem, event->subsystem))
182 return dispatch_table[i].dispatch(event);
183 }
184
185 #if DEBUG_UEVENT
186 LOG_VOL("No uevent handlers registered for '%s' subsystem", event->subsystem);
187 #endif
188 return 0;
189 }
190
191 static void dump_uevent(struct uevent *event)
192 {
193 int i;
194
195 LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s",
196 event->seqnum, event->subsystem, event->action, event->path);
197 for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
198 if (!event->param[i])
199 break;
200 LOG_VOL("%s", event->param[i]);
201 }
202 }
203
204 static void free_uevent(struct uevent *event)
205 {
206 int i;
207 free(event->path);
208 free(event->subsystem);
209 for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
210 if (!event->param[i])
211 break;
212 free(event->param[i]);
213 }
214 free(event);
215 }
216
217 static char *get_uevent_param(struct uevent *event, char *param_name)
218 {
219 int i;
220
221 for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
222 if (!event->param[i])
223 break;
224 if (!strncmp(event->param[i], param_name, strlen(param_name)))
225 return &event->param[i][strlen(param_name) + 1];
226 }
227
228 LOGE("get_uevent_param(): No parameter '%s' found", param_name);
229 return NULL;
230 }
231
232 /*
233 * ---------------
234 * Uevent Handlers
235 * ---------------
236 */
237
238 static int handle_powersupply_event(struct uevent *event)
239 {
240 char *ps_type = get_uevent_param(event, "POWER_SUPPLY_TYPE");
241 char *ps_cap = get_uevent_param(event, "POWER_SUPPLY_CAPACITY");
242
243 if (!strcasecmp(ps_type, "battery")) {
244 int capacity = atoi(ps_cap);
245
246 if (capacity < 5)
247 low_batt = true;
248 else
249 low_batt = false;
250 LOG_VOL("handle_powersupply_event(): low_batt = %d, door_open = %d", low_batt, door_open);
251 volmgr_safe_mode(low_batt || door_open);
252 }
253 return 0;
254 }
255
256 static int handle_switch_event(struct uevent *event)
257 {
258 char *name = get_uevent_param(event, "SWITCH_NAME");
259 char *state = get_uevent_param(event, "SWITCH_STATE");
260
261
262 if (!strcmp(name, "usb_mass_storage")) {
263 if (!strcmp(state, "online")) {
264 ums_hostconnected_set(true);
265 } else {
266 ums_hostconnected_set(false);
267 volmgr_enable_ums(false);
268 }
269 } else if (!strcmp(name, "sd-door")) {
270 if (!strcmp(state, "open"))
271 door_open = true;
272 else
273 door_open = false;
274 LOG_VOL("handle_powersupply_event(): low_batt = %d, door_open = %d", low_batt, door_open);
275 volmgr_safe_mode(low_batt || door_open);
276 } else
277 LOG_VOL("handle_switch_event(): Ignoring switch '%s'", name);
278
279 return 0;
280 }
281
282 static int handle_battery_event(struct uevent *event)
283 {
284 return 0;
285 }
286
287 static int handle_block_event(struct uevent *event)
288 {
289 char mediapath[255];
290 media_t *media;
291 int n;
292 int maj, min;
293 blkdev_t *blkdev;
294
295 /*
296 * Look for backing media for this block device
297 */
298 if (!strncmp(get_uevent_param(event, "DEVPATH"),
299 "/devices/virtual/",
300 strlen("/devices/virtual/"))) {
301 n = 0;
302 } else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "disk"))
303 n = 2;
304 else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "partition"))
305 n = 3;
306 else {
307 LOGE("Bad blockdev type '%s'", get_uevent_param(event, "DEVTYPE"));
308 return -EINVAL;
309 }
310
311 truncate_sysfs_path(event->path, n, mediapath);
312
313 if (!(media = media_lookup_by_path(mediapath, false))) {
314 #if DEBUG_UEVENT
315 LOG_VOL("No backend media found @ device path '%s'", mediapath);
316 #endif
317 return 0;
318 }
319
320 maj = atoi(get_uevent_param(event, "MAJOR"));
321 min = atoi(get_uevent_param(event, "MINOR"));
322
323 if (event->action == action_add) {
324 blkdev_t *disk;
325
326 /*
327 * If there isn't a disk already its because *we*
328 * are the disk
329 */
330 disk = blkdev_lookup_by_devno(maj, 0);
331
332 if (!(blkdev = blkdev_create(disk,
333 event->path,
334 maj,
335 min,
336 media,
337 get_uevent_param(event, "DEVTYPE")))) {
338 LOGE("Unable to allocate new blkdev (%m)");
339 return -1;
340 }
341
342 blkdev_refresh(blkdev);
343
344 /*
345 * Add the blkdev to media
346 */
347 int rc;
348 if ((rc = media_add_blkdev(media, blkdev)) < 0) {
349 LOGE("Unable to add blkdev to card (%d)", rc);
350 return rc;
351 }
352
353 LOG_VOL("New blkdev %d.%d on media %s, media path %s, Dpp %d",
354 blkdev->major, blkdev->minor, media->name, mediapath,
355 blkdev_get_num_pending_partitions(blkdev->disk));
356
357 if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
358 if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
359 LOGE("Volmgr failed to handle device (%d)", rc);
360 return rc;
361 }
362 }
363 } else if (event->action == action_remove) {
364 if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
365 return 0;
366
367 LOG_VOL("Destroying blkdev %d.%d @ %s on media %s", blkdev->major,
368 blkdev->minor, blkdev->devpath, media->name);
369 volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy);
370
371 } else if (event->action == action_change) {
372 if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
373 return 0;
374
375 LOG_VOL("Modified blkdev %d.%d @ %s on media %s", blkdev->major,
376 blkdev->minor, blkdev->devpath, media->name);
377
378 blkdev_refresh(blkdev);
379 } else {
380 #if DEBUG_UEVENT
381 LOG_VOL("No handler implemented for action %d", event->action);
382 #endif
383 }
384 return 0;
385 }
386
387 static void _cb_blkdev_ok_to_destroy(blkdev_t *dev)
388 {
389 media_t *media = media_lookup_by_dev(dev);
390 if (media)
391 media_remove_blkdev(media, dev);
392 blkdev_destroy(dev);
393 }
394
395 static int handle_bdi_event(struct uevent *event)
396 {
397 return 0;
398 }
399
400 static int handle_mmc_event(struct uevent *event)
401 {
402 if (event->action == action_add) {
403 media_t *media;
404 char serial[80];
405 char *type;
406
407 /*
408 * Pull card information from sysfs
409 */
410 type = get_uevent_param(event, "MMC_TYPE");
411 if (strcmp(type, "SD") && strcmp(type, "MMC"))
412 return 0;
413
414 read_sysfs_var(serial, sizeof(serial), event->path, "serial");
415 if (!(media = media_create(event->path,
416 get_uevent_param(event, "MMC_NAME"),
417 serial,
418 media_mmc))) {
419 LOGE("Unable to allocate new media (%m)");
420 return -1;
421 }
422 LOG_VOL("New MMC card '%s' (serial %u) added @ %s", media->name,
423 media->serial, media->devpath);
424 } else if (event->action == action_remove) {
425 media_t *media;
426
427 if (!(media = media_lookup_by_path(event->path, false))) {
428 LOGE("Unable to lookup media '%s'", event->path);
429 return -1;
430 }
431
432 LOG_VOL("MMC card '%s' (serial %u) @ %s removed", media->name,
433 media->serial, media->devpath);
434 media_destroy(media);
435 } else {
436 #if DEBUG_UEVENT
437 LOG_VOL("No handler implemented for action %d", event->action);
438 #endif
439 }
440
441 return 0;
442 }
+0
-21
vold/uevent.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _UEVENT_MSG_H
18 #define _UEVENT_MSG_H
19
20 #endif
+0
-129
vold/ums.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #include "vold.h"
21 #include "ums.h"
22
23 #define DEBUG_UMS 0
24
25 static boolean host_connected = false;
26 static boolean ums_enabled = false;
27
28 int ums_bootstrap(void)
29 {
30 return 0;
31 }
32
33 void ums_enabled_set(boolean enabled)
34 {
35 ums_enabled = enabled;
36 send_msg(enabled ? VOLD_EVT_UMS_ENABLED : VOLD_EVT_UMS_DISABLED);
37 }
38
39 boolean ums_enabled_get()
40 {
41 return ums_enabled;
42 }
43
44 void ums_hostconnected_set(boolean connected)
45 {
46 #if DEBUG_UMS
47 LOG_VOL("ums_hostconnected_set(%d):", connected);
48 #endif
49 host_connected = connected;
50
51 if (!connected)
52 ums_enabled_set(false);
53 send_msg(connected ? VOLD_EVT_UMS_CONNECTED : VOLD_EVT_UMS_DISCONNECTED);
54 }
55
56 int ums_enable(char *dev_fspath, char *lun_syspath)
57 {
58 LOG_VOL("ums_enable(%s, %s):", dev_fspath, lun_syspath);
59
60 int fd;
61 char filename[255];
62
63 sprintf(filename, "/sys/%s/file", lun_syspath);
64 if ((fd = open(filename, O_WRONLY)) < 0) {
65 LOGE("Unable to open '%s' (%s)", filename, strerror(errno));
66 return -errno;
67 }
68
69 if (write(fd, dev_fspath, strlen(dev_fspath)) < 0) {
70 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
71 close(fd);
72 return -errno;
73 }
74
75 close(fd);
76 return 0;
77 }
78
79 int ums_disable(char *lun_syspath)
80 {
81 #if DEBUG_UMS
82 LOG_VOL("ums_disable(%s):", lun_syspath);
83 #endif
84
85 int fd;
86 char filename[255];
87
88 sprintf(filename, "/sys/%s/file", lun_syspath);
89 if ((fd = open(filename, O_WRONLY)) < 0) {
90 LOGE("Unable to open '%s' (%s)", filename, strerror(errno));
91 return -errno;
92 }
93
94 char ch = 0;
95
96 if (write(fd, &ch, 1) < 0) {
97 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
98 close(fd);
99 return -errno;
100 }
101
102 close(fd);
103 return 0;
104 }
105
106 boolean ums_hostconnected_get(void)
107 {
108 return host_connected;
109 }
110
111 int ums_send_status(void)
112 {
113 int rc;
114
115 #if DEBUG_UMS
116 LOG_VOL("ums_send_status():");
117 #endif
118
119 rc = send_msg(ums_enabled_get() ? VOLD_EVT_UMS_ENABLED :
120 VOLD_EVT_UMS_DISABLED);
121 if (rc < 0)
122 return rc;
123
124 rc = send_msg(ums_hostconnected_get() ? VOLD_EVT_UMS_CONNECTED :
125 VOLD_EVT_UMS_DISCONNECTED);
126
127 return rc;
128 }
+0
-31
vold/ums.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _UMS_H
18 #define _UMS_H
19
20 // these must match the corresponding strings in java/android/android/os/UsbListener.java
21 #define VOLD_EVT_UMS_ENABLED "ums_enabled"
22 #define VOLD_EVT_UMS_DISABLED "ums_disabled"
23 #define VOLD_EVT_UMS_CONNECTED "ums_connected"
24 #define VOLD_EVT_UMS_DISCONNECTED "ums_disconnected"
25
26
27 int ums_send_status(void);
28 int ums_enable(char *device_file, char *lun_syspath);
29 int ums_disable(char *lun_syspath);
30 #endif
+0
-234
vold/vold.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <pthread.h>
24
25 #include <sys/socket.h>
26 #include <sys/select.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30
31 #include <cutils/config_utils.h>
32 #include <cutils/cpu_info.h>
33 #include <cutils/properties.h>
34 #include <cutils/sockets.h>
35
36 #include <linux/netlink.h>
37
38 #include <private/android_filesystem_config.h>
39
40 #include "vold.h"
41 #include "volmgr.h"
42
43
44 #define VOLD_SOCKET "vold"
45
46 /*
47 * Globals
48 */
49
50 static int ver_major = 2;
51 static int ver_minor = 0;
52 static pthread_mutex_t write_mutex = PTHREAD_MUTEX_INITIALIZER;
53 static int fw_sock = -1;
54
55 int main(int argc, char **argv)
56 {
57 int door_sock = -1;
58 int uevent_sock = -1;
59 struct sockaddr_nl nladdr;
60 int uevent_sz = 64 * 1024;
61
62 LOG_VOL("Android Volume Daemon version %d.%d", ver_major, ver_minor);
63
64 /*
65 * Create all the various sockets we'll need
66 */
67
68 // Socket to listen on for incomming framework connections
69 if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) {
70 LOGE("Obtaining file descriptor socket '%s' failed: %s",
71 VOLD_SOCKET, strerror(errno));
72 exit(1);
73 }
74
75 if (listen(door_sock, 4) < 0) {
76 LOGE("Unable to listen on fd '%d' for socket '%s': %s",
77 door_sock, VOLD_SOCKET, strerror(errno));
78 exit(1);
79 }
80
81 mkdir("/dev/block/vold", 0755);
82
83 // Socket to listen on for uevent changes
84 memset(&nladdr, 0, sizeof(nladdr));
85 nladdr.nl_family = AF_NETLINK;
86 nladdr.nl_pid = getpid();
87 nladdr.nl_groups = 0xffffffff;
88
89 if ((uevent_sock = socket(PF_NETLINK,
90 SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
91 LOGE("Unable to create uevent socket: %s", strerror(errno));
92 exit(1);
93 }
94
95 if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz,
96 sizeof(uevent_sz)) < 0) {
97 LOGE("Unable to set uevent socket options: %s", strerror(errno));
98 exit(1);
99 }
100
101 if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
102 LOGE("Unable to bind uevent socket: %s", strerror(errno));
103 exit(1);
104 }
105
106 /*
107 * Bootstrap
108 */
109
110 // Volume Manager
111 volmgr_bootstrap();
112
113 // SD Card system
114 mmc_bootstrap();
115
116 // USB Mass Storage
117 ums_bootstrap();
118
119 // Switch
120 switch_bootstrap();
121
122 /*
123 * Main loop
124 */
125 LOG_VOL("Bootstrapping complete");
126 while(1) {
127 fd_set read_fds;
128 struct timeval to;
129 int max = 0;
130 int rc = 0;
131
132 to.tv_sec = (60 * 60);
133 to.tv_usec = 0;
134
135 FD_ZERO(&read_fds);
136 FD_SET(door_sock, &read_fds);
137 if (door_sock > max)
138 max = door_sock;
139 FD_SET(uevent_sock, &read_fds);
140 if (uevent_sock > max)
141 max = uevent_sock;
142
143 if (fw_sock != -1) {
144 FD_SET(fw_sock, &read_fds);
145 if (fw_sock > max)
146 max = fw_sock;
147 }
148
149 if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {
150 LOGE("select() failed (%s)", strerror(errno));
151 sleep(1);
152 continue;
153 }
154
155 if (!rc) {
156 continue;
157 }
158
159 if (FD_ISSET(door_sock, &read_fds)) {
160 struct sockaddr addr;
161 socklen_t alen;
162
163 alen = sizeof(addr);
164
165 if (fw_sock != -1) {
166 LOGE("Dropping duplicate framework connection");
167 int tmp = accept(door_sock, &addr, &alen);
168 close(tmp);
169 continue;
170 }
171
172 if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {
173 LOGE("Unable to accept framework connection (%s)",
174 strerror(errno));
175 }
176 LOG_VOL("Accepted connection from framework");
177 if ((rc = volmgr_send_states()) < 0) {
178 LOGE("Unable to send volmgr status to framework (%d)", rc);
179 }
180 }
181
182 if (FD_ISSET(fw_sock, &read_fds)) {
183 if ((rc = process_framework_command(fw_sock)) < 0) {
184 if (rc == -ECONNRESET) {
185 LOGE("Framework disconnected");
186 close(fw_sock);
187 fw_sock = -1;
188 } else {
189 LOGE("Error processing framework command (%s)",
190 strerror(errno));
191 }
192 }
193 }
194
195 if (FD_ISSET(uevent_sock, &read_fds)) {
196 if ((rc = process_uevent_message(uevent_sock)) < 0) {
197 LOGE("Error processing uevent msg (%s)", strerror(errno));
198 }
199 }
200 } // while
201
202 }
203
204 int send_msg(char* message)
205 {
206 int result = -1;
207
208 pthread_mutex_lock(&write_mutex);
209
210 LOG_VOL("send_msg(%s):", message);
211
212 if (fw_sock >= 0)
213 result = write(fw_sock, message, strlen(message) + 1);
214
215 pthread_mutex_unlock(&write_mutex);
216
217 return result;
218 }
219
220 int send_msg_with_data(char *message, char *data)
221 {
222 int result = -1;
223
224 char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
225 if (!buffer) {
226 LOGE("alloca failed in send_msg_with_data");
227 return -1;
228 }
229
230 strcpy(buffer, message);
231 strcat(buffer, data);
232 return send_msg(buffer);
233 }
+0
-100
vold/vold.h less more
0 /*
1 * Copyright (C) 2008 The Android Open Source Project
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef VOLD_H__
17 #define VOLD_H__
18
19 #define LOG_TAG "vold"
20 #include "cutils/log.h"
21
22 typedef int boolean;
23 enum {
24 false = 0,
25 true = 1
26 };
27
28 #define DEVPATH "/dev/block/"
29 #define DEVPATHLENGTH 11
30
31 #define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
32
33 // Set this for logging error messages
34 #define ENABLE_LOG_ERROR
35
36 // set this to log vold events
37 #define ENABLE_LOG_VOL
38
39 #ifdef ENABLE_LOG_ERROR
40 #define LOG_ERROR(fmt, args...) \
41 { LOGE(fmt , ## args); }
42 #else
43 #define LOG_ERROR(fmt, args...) \
44 do { } while (0)
45 #endif /* ENABLE_LOG_ERROR */
46
47 #ifdef ENABLE_LOG_VOL
48 #define LOG_VOL(fmt, args...) \
49 { LOGD(fmt , ## args); }
50 #else
51 #define LOG_VOL(fmt, args...) \
52 do { } while (0)
53 #endif /* ENABLE_LOG_VOL */
54
55 #ifdef ENABLE_LOG_SERVER
56 #define LOG_SERVER(fmt, args...) \
57 { LOGD(fmt , ## args); }
58 #else
59 #define LOG_SERVER(fmt, args...) \
60 do { } while (0)
61 #endif /* ENABLE_LOG_SERVER */
62
63 #ifdef ENABLE_LOG_ASEC
64 #define LOG_ASEC(fmt, args...) \
65 { LOGD(fmt , ## args); }
66 #else
67 #define LOG_ASEC(fmt, args...) \
68 do { } while (0)
69 #endif /* ENABLE_LOG_ASEC */
70
71 /*
72 * Prototypes
73 */
74
75 int process_framework_command(int socket);
76
77 int process_inotify_event(int fd);
78 int inotify_bootstrap(void);
79
80 int process_uevent_message(int socket);
81 int simulate_uevent(char *subsystem, char *path, char *action, char **params);
82
83 int mmc_bootstrap(void);
84 int ums_bootstrap(void);
85
86 int volmgr_bootstrap(void);
87
88 int switch_bootstrap(void);
89
90 void *read_file(char *filename, ssize_t *_size);
91 char *truncate_sysfs_path(char *path, int num_elements_to_remove, char *buffer);
92 char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var);
93
94 void ums_hostconnected_set(boolean connected);
95 boolean ums_hostconnected_get(void);
96
97 int send_msg(char *msg);
98 int send_msg_with_data(char *msg, char *data);
99 #endif
+0
-1229
vold/volmgr.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <dirent.h>
21 #include <unistd.h>
22 #include <sched.h>
23
24 #include <sys/mount.h>
25
26 #include <cutils/config_utils.h>
27 #include <cutils/properties.h>
28
29 #include "vold.h"
30 #include "volmgr.h"
31 #include "blkdev.h"
32 #include "ums.h"
33 #include "format.h"
34 #include "devmapper.h"
35
36 #include "volmgr_ext3.h"
37 #include "volmgr_vfat.h"
38
39 #define DEBUG_VOLMGR 0
40
41 static volume_t *vol_root = NULL;
42 static boolean safe_mode = true;
43
44 static struct volmgr_fstable_entry fs_table[] = {
45 { "ext3", ext_identify, ext_check, ext_mount , true },
46 { "vfat", vfat_identify, vfat_check, vfat_mount , false },
47 { NULL, NULL, NULL, NULL , false}
48 };
49
50 struct _volume_state_event_map {
51 volume_state_t state;
52 char *event;
53 char *property_val;
54 };
55
56 static struct _volume_state_event_map volume_state_strings[] = {
57 { volstate_unknown, "volstate_unknown:", "unknown" },
58 { volstate_nomedia, VOLD_EVT_NOMEDIA, VOLD_ES_PVAL_NOMEDIA },
59 { volstate_unmounted, VOLD_EVT_UNMOUNTED, VOLD_ES_PVAL_UNMOUNTED },
60 { volstate_checking, VOLD_EVT_CHECKING, VOLD_ES_PVAL_CHECKING },
61 { volstate_mounted, VOLD_EVT_MOUNTED, VOLD_ES_PVAL_MOUNTED },
62 { volstate_mounted_ro, VOLD_EVT_MOUNTED_RO, VOLD_ES_PVAL_MOUNTED_RO },
63 { volstate_badremoval, VOLD_EVT_BADREMOVAL, VOLD_ES_PVAL_BADREMOVAL },
64 { volstate_damaged, VOLD_EVT_DAMAGED, VOLD_ES_PVAL_DAMAGED },
65 { volstate_nofs, VOLD_EVT_NOFS, VOLD_ES_PVAL_NOFS },
66 { volstate_ums, VOLD_EVT_UMS, VOLD_ES_PVAL_UMS },
67 { 0, NULL, NULL }
68 };
69
70
71 static int volmgr_readconfig(char *cfg_path);
72 static int volmgr_config_volume(cnode *node);
73 static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy);
74 static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev);
75 static int _volmgr_start(volume_t *vol, blkdev_t *dev);
76 static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev);
77 static void *volmgr_start_fs_thread(void *arg);
78 static void volmgr_start_fs_thread_sighandler(int signo);
79 static void volume_setstate(volume_t *vol, volume_state_t state);
80 static char *conv_volstate_to_eventstr(volume_state_t state);
81 static char *conv_volstate_to_propstr(volume_state_t state);
82 static int volume_send_state(volume_t *vol);
83 static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg);
84 static int _volmgr_enable_ums(volume_t *);
85 static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *arg), boolean emit_statechange);
86 static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange);
87 static void _cb_volume_stopped_for_eject(volume_t *v, void *arg);
88 static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg);
89 static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev);
90 static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg);
91 static void volmgr_reaper_thread_sighandler(int signo);
92 static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path);
93 static int volmgr_send_eject_request(volume_t *v);
94 static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked);
95
96 static boolean _mountpoint_mounted(char *mp)
97 {
98 char device[256];
99 char mount_path[256];
100 char rest[256];
101 FILE *fp;
102 char line[1024];
103
104 if (!(fp = fopen("/proc/mounts", "r"))) {
105 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
106 return false;
107 }
108
109 while(fgets(line, sizeof(line), fp)) {
110 line[strlen(line)-1] = '\0';
111 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
112 if (!strcmp(mount_path, mp)) {
113 fclose(fp);
114 return true;
115 }
116
117 }
118
119 fclose(fp);
120 return false;
121 }
122
123 /*
124 * Public functions
125 */
126
127 int volmgr_set_volume_key(char *mount_point, unsigned char *key)
128 {
129 volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
130
131 if (!v)
132 return -ENOENT;
133
134 if (v->media_type != media_devmapper) {
135 LOGE("Cannot set key on a non devmapper volume");
136 pthread_mutex_unlock(&v->lock);
137 return -EINVAL;
138 }
139
140 memcpy(v->dm->key, key, sizeof(v->dm->key));
141 pthread_mutex_unlock(&v->lock);
142 return 0;
143 }
144
145 int volmgr_format_volume(char *mount_point)
146 {
147 int rc;
148 volume_t *v;
149
150 LOG_VOL("volmgr_format_volume(%s):", mount_point);
151
152 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
153
154 if (!v)
155 return -ENOENT;
156
157 if (v->state == volstate_mounted ||
158 v->state == volstate_mounted_ro ||
159 v->state == volstate_ums ||
160 v->state == volstate_checking) {
161 LOGE("Can't format '%s', currently in state %d", mount_point, v->state);
162 pthread_mutex_unlock(&v->lock);
163 return -EBUSY;
164 } else if (v->state == volstate_nomedia &&
165 v->media_type != media_devmapper) {
166 LOGE("Can't format '%s', (no media)", mount_point);
167 pthread_mutex_unlock(&v->lock);
168 return -ENOMEDIUM;
169 }
170
171 // XXX:Reject if the underlying source media is not present
172
173 if (v->media_type == media_devmapper) {
174 if ((rc = devmapper_genesis(v->dm)) < 0) {
175 LOGE("devmapper genesis failed for %s (%d)", mount_point, rc);
176 pthread_mutex_unlock(&v->lock);
177 return rc;
178 }
179 } else {
180 if ((rc = initialize_mbr(v->dev->disk)) < 0) {
181 LOGE("MBR init failed for %s (%d)", mount_point, rc);
182 pthread_mutex_unlock(&v->lock);
183 return rc;
184 }
185 }
186
187 volume_setstate(v, volstate_formatting);
188 pthread_mutex_unlock(&v->lock);
189 return rc;
190 }
191
192 int volmgr_bootstrap(void)
193 {
194 int rc;
195
196 if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {
197 LOGE("Unable to process config");
198 return rc;
199 }
200
201 /*
202 * Check to see if any of our volumes is mounted
203 */
204 volume_t *v = vol_root;
205 while (v) {
206 if (_mountpoint_mounted(v->mount_point)) {
207 LOG_VOL("Volume '%s' already mounted at startup", v->mount_point);
208 v->state = volstate_mounted;
209 }
210 v = v->next;
211 }
212
213 return 0;
214 }
215
216 int volmgr_safe_mode(boolean enable)
217 {
218 if (enable == safe_mode)
219 return 0;
220
221 safe_mode = enable;
222
223 volume_t *v = vol_root;
224 int rc;
225
226 while (v) {
227 pthread_mutex_lock(&v->lock);
228 if (v->state == volstate_mounted && v->fs) {
229 rc = v->fs->mount_fn(v->dev, v, safe_mode);
230 if (!rc) {
231 LOG_VOL("Safe mode %s on %s", (enable ? "enabled" : "disabled"), v->mount_point);
232 } else {
233 LOGE("Failed to %s safe-mode on %s (%s)",
234 (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc));
235 }
236 }
237
238 pthread_mutex_unlock(&v->lock);
239 v = v->next;
240 }
241
242 return 0;
243 }
244
245 int volmgr_send_states(void)
246 {
247 volume_t *vol_scan = vol_root;
248 int rc;
249
250 while (vol_scan) {
251 pthread_mutex_lock(&vol_scan->lock);
252 if ((rc = volume_send_state(vol_scan)) < 0) {
253 LOGE("Error sending state to framework (%d)", rc);
254 }
255 pthread_mutex_unlock(&vol_scan->lock);
256 vol_scan = vol_scan->next;
257 break; // XXX:
258 }
259
260 return 0;
261 }
262
263 /*
264 * Called when a block device is ready to be
265 * evaluated by the volume manager.
266 */
267 int volmgr_consider_disk(blkdev_t *dev)
268 {
269 volume_t *vol;
270
271 if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true)))
272 return 0;
273
274 pthread_mutex_lock(&vol->lock);
275
276 if (vol->state == volstate_mounted) {
277 LOGE("Volume %s already mounted (did we just crash?)", vol->mount_point);
278 pthread_mutex_unlock(&vol->lock);
279 return 0;
280 }
281
282 int rc = _volmgr_consider_disk_and_vol(vol, dev);
283 pthread_mutex_unlock(&vol->lock);
284 return rc;
285 }
286
287 int volmgr_start_volume_by_mountpoint(char *mount_point)
288 {
289 volume_t *v;
290
291 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
292 if (!v)
293 return -ENOENT;
294
295 if (v->media_type == media_devmapper) {
296 if (devmapper_start(v->dm) < 0) {
297 LOGE("volmgr failed to start devmapper volume '%s'",
298 v->mount_point);
299 }
300 } else if (v->media_type == media_mmc) {
301 if (!v->dev) {
302 LOGE("Cannot start volume '%s' (volume is not bound)", mount_point);
303 pthread_mutex_unlock(&v->lock);
304 return -ENOENT;
305 }
306
307 if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) {
308 LOGE("volmgr failed to start volume '%s'", v->mount_point);
309 }
310 }
311
312 pthread_mutex_unlock(&v->lock);
313 return 0;
314 }
315
316 static void _cb_volstopped_for_devmapper_teardown(volume_t *v, void *arg)
317 {
318 devmapper_stop(v->dm);
319 volume_setstate(v, volstate_nomedia);
320 pthread_mutex_unlock(&v->lock);
321 }
322
323 int volmgr_stop_volume_by_mountpoint(char *mount_point)
324 {
325 int rc;
326 volume_t *v;
327
328 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
329 if (!v)
330 return -ENOENT;
331
332 if (v->state == volstate_mounted)
333 volmgr_send_eject_request(v);
334
335 if (v->media_type == media_devmapper)
336 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_devmapper_teardown, false);
337 else
338 rc = volmgr_shutdown_volume(v, NULL, true);
339
340 /*
341 * If shutdown returns -EINPROGRESS,
342 * do *not* release the lock as
343 * it is now owned by the reaper thread
344 */
345 if (rc != -EINPROGRESS) {
346 if (rc)
347 LOGE("unable to shutdown volume '%s'", v->mount_point);
348 pthread_mutex_unlock(&v->lock);
349 }
350 return 0;
351 }
352
353 int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *))
354 {
355 LOG_VOL("Volmgr notified of %d:%d eject", dev->major, dev->minor);
356
357 volume_t *v;
358 int rc;
359
360 // XXX: Partitioning support is going to need us to stop *all*
361 // devices in this volume
362 if (!(v = volmgr_lookup_volume_by_dev(dev))) {
363 if (cb)
364 cb(dev);
365 return 0;
366 }
367
368 pthread_mutex_lock(&v->lock);
369
370 volume_state_t old_state = v->state;
371
372 if (v->state == volstate_mounted ||
373 v->state == volstate_ums ||
374 v->state == volstate_checking) {
375
376 volume_setstate(v, volstate_badremoval);
377
378 /*
379 * Stop any devmapper volumes which
380 * are using us as a source
381 * XXX: We may need to enforce stricter
382 * order here
383 */
384 volume_t *dmvol = vol_root;
385 while (dmvol) {
386 if ((dmvol->media_type == media_devmapper) &&
387 (dmvol->dm->src_type == dmsrc_loopback) &&
388 (!strncmp(dmvol->dm->type_data.loop.loop_src,
389 v->mount_point, strlen(v->mount_point)))) {
390
391 pthread_mutex_lock(&dmvol->lock);
392 if (dmvol->state != volstate_nomedia) {
393 rc = volmgr_shutdown_volume(dmvol, _cb_volstopped_for_devmapper_teardown, false);
394 if (rc != -EINPROGRESS) {
395 if (rc)
396 LOGE("unable to shutdown volume '%s'", v->mount_point);
397 pthread_mutex_unlock(&dmvol->lock);
398 }
399 } else
400 pthread_mutex_unlock(&dmvol->lock);
401 }
402 dmvol = dmvol->next;
403 }
404
405 } else if (v->state == volstate_formatting) {
406 /*
407 * The device is being ejected due to
408 * kernel disk revalidation.
409 */
410 LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)",
411 dev->major, dev->minor);
412 if (cb)
413 cb(dev);
414 pthread_mutex_unlock(&v->lock);
415 return 0;
416 } else
417 volume_setstate(v, volstate_nomedia);
418
419 if (old_state == volstate_ums) {
420 ums_disable(v->ums_path);
421 pthread_mutex_unlock(&v->lock);
422 } else {
423 int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
424 if (rc != -EINPROGRESS) {
425 if (rc)
426 LOGE("unable to shutdown volume '%s'", v->mount_point);
427 pthread_mutex_unlock(&v->lock);
428 }
429 }
430 return 0;
431 }
432
433 static void _cb_volume_stopped_for_eject(volume_t *v, void *arg)
434 {
435 void (* eject_cb) (blkdev_t *) = arg;
436
437 #if DEBUG_VOLMGR
438 LOG_VOL("Volume %s has been stopped for eject", v->mount_point);
439 #endif
440
441 if (eject_cb)
442 eject_cb(v->dev);
443 v->dev = NULL; // Clear dev because its being ejected
444 }
445
446 /*
447 * Instructs the volume manager to enable or disable USB mass storage
448 * on any volumes configured to use it.
449 */
450 int volmgr_enable_ums(boolean enable)
451 {
452 volume_t *v = vol_root;
453
454 while(v) {
455 if (v->ums_path) {
456 int rc;
457
458 if (enable) {
459 pthread_mutex_lock(&v->lock);
460 if (v->state == volstate_mounted)
461 volmgr_send_eject_request(v);
462 else if (v->state == volstate_ums) {
463 pthread_mutex_unlock(&v->lock);
464 goto next_vol;
465 }
466
467 // Stop the volume, and enable UMS in the callback
468 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);
469 if (rc != -EINPROGRESS) {
470 if (rc)
471 LOGE("unable to shutdown volume '%s'", v->mount_point);
472 pthread_mutex_unlock(&v->lock);
473 }
474 } else {
475 // Disable UMS
476 pthread_mutex_lock(&v->lock);
477 if (v->state != volstate_ums) {
478 pthread_mutex_unlock(&v->lock);
479 goto next_vol;
480 }
481
482 if ((rc = ums_disable(v->ums_path)) < 0) {
483 LOGE("unable to disable ums on '%s'", v->mount_point);
484 pthread_mutex_unlock(&v->lock);
485 continue;
486 }
487
488 LOG_VOL("Kick-starting volume %d:%d after UMS disable",
489 v->dev->disk->major, v->dev->disk->minor);
490 // Start volume
491 if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) {
492 LOGE("volmgr failed to consider disk %d:%d",
493 v->dev->disk->major, v->dev->disk->minor);
494 }
495 pthread_mutex_unlock(&v->lock);
496 }
497 }
498 next_vol:
499 v = v->next;
500 }
501 return 0;
502 }
503
504 /*
505 * Static functions
506 */
507
508 static int volmgr_send_eject_request(volume_t *v)
509 {
510 return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point);
511 }
512
513 // vol->lock must be held!
514 static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)
515 {
516 int rc = 0;
517
518 #if DEBUG_VOLMGR
519 LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):", vol->mount_point,
520 dev->major, dev->minor);
521 #endif
522
523 if (vol->state == volstate_unknown ||
524 vol->state == volstate_mounted ||
525 vol->state == volstate_mounted_ro ||
526 vol->state == volstate_damaged) {
527 LOGE("Cannot consider volume '%s' because it is in state '%d",
528 vol->mount_point, vol->state);
529 return -EADDRINUSE;
530 }
531
532 if (vol->state == volstate_formatting) {
533 LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'",
534 dev->devpath, vol->mount_point);
535 /*
536 * Since we only support creating 1 partition (right now),
537 * we can just lookup the target by devno
538 */
539 blkdev_t *part = blkdev_lookup_by_devno(dev->major, 1);
540 if (!part) {
541 part = blkdev_lookup_by_devno(dev->major, 0);
542 if (!part) {
543 LOGE("Unable to find device to format");
544 return -ENODEV;
545 }
546 }
547
548 if ((rc = format_partition(part,
549 vol->media_type == media_devmapper ?
550 FORMAT_TYPE_EXT2 : FORMAT_TYPE_FAT32)) < 0) {
551 LOGE("format failed (%d)", rc);
552 return rc;
553 }
554
555 }
556
557 LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'",
558 dev->devpath, vol->mount_point);
559
560 if (dev->nr_parts == 0) {
561 rc = _volmgr_start(vol, dev);
562 #if DEBUG_VOLMGR
563 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", vol->mount_point,
564 dev->major, dev->minor, rc);
565 #endif
566 } else {
567 /*
568 * Device has multiple partitions
569 * This is where interesting partition policies could be implemented.
570 * For now just try them in sequence until one succeeds
571 */
572
573 rc = -ENODEV;
574 int i;
575 for (i = 0; i < dev->nr_parts; i++) {
576 blkdev_t *part = blkdev_lookup_by_devno(dev->major, (i+1));
577 if (!part) {
578 LOGE("Error - unable to lookup partition for blkdev %d:%d", dev->major, (i+1));
579 continue;
580 }
581 rc = _volmgr_start(vol, part);
582 #if DEBUG_VOLMGR
583 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d",
584 vol->mount_point, part->major, part->minor, rc);
585 #endif
586 if (!rc)
587 break;
588 }
589
590 if (rc == -ENODEV) {
591 // Assert to make sure each partition had a backing blkdev
592 LOGE("Internal consistency error");
593 return 0;
594 }
595 }
596
597 if (rc == -ENODATA) {
598 LOGE("Device %d:%d contains no usable filesystems",
599 dev->major, dev->minor);
600 rc = 0;
601 }
602
603 return rc;
604 }
605
606 static void volmgr_reaper_thread_sighandler(int signo)
607 {
608 LOGE("Volume reaper thread got signal %d", signo);
609 }
610
611 static void __reaper_cleanup(void *arg)
612 {
613 volume_t *vol = (volume_t *) arg;
614
615 if (vol->worker_args.reaper_args.cb)
616 vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg);
617
618 vol->worker_running = false;
619
620 // Wake up anyone that was waiting on this thread
621 pthread_mutex_unlock(&vol->worker_sem);
622
623 // Unlock the volume
624 pthread_mutex_unlock(&vol->lock);
625 }
626
627 static void *volmgr_reaper_thread(void *arg)
628 {
629 volume_t *vol = (volume_t *) arg;
630
631 pthread_cleanup_push(__reaper_cleanup, arg);
632
633 vol->worker_running = true;
634 vol->worker_pid = getpid();
635
636 struct sigaction actions;
637
638 memset(&actions, 0, sizeof(actions));
639 sigemptyset(&actions.sa_mask);
640 actions.sa_flags = 0;
641 actions.sa_handler = volmgr_reaper_thread_sighandler;
642 sigaction(SIGUSR1, &actions, NULL);
643
644 LOG_VOL("Reaper here - working on %s", vol->mount_point);
645
646 boolean send_sig_kill = false;
647 int i, rc;
648
649 for (i = 0; i < 10; i++) {
650 errno = 0;
651 rc = umount(vol->mount_point);
652 LOG_VOL("volmngr reaper umount(%s) attempt %d (%s)",
653 vol->mount_point, i + 1, strerror(errno));
654 if (!rc)
655 break;
656 if (rc && (errno == EINVAL || errno == ENOENT)) {
657 rc = 0;
658 break;
659 }
660 sleep(1);
661 if (i >= 4) {
662 KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
663 if (!send_sig_kill)
664 send_sig_kill = true;
665 }
666 }
667
668 if (!rc) {
669 LOG_VOL("Reaper sucessfully unmounted %s", vol->mount_point);
670 vol->fs = NULL;
671 volume_setstate(vol, volstate_unmounted);
672 } else {
673 LOGE("Unable to unmount!! (%d)", rc);
674 }
675
676 out:
677 pthread_cleanup_pop(1);
678 pthread_exit(NULL);
679 return NULL;
680 }
681
682 // vol->lock must be held!
683 static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg)
684 {
685
686 if (vol->worker_running) {
687 LOGE("Worker thread is currently running.. waiting..");
688 pthread_mutex_lock(&vol->worker_sem);
689 LOG_VOL("Worker thread now available");
690 }
691
692 vol->worker_args.reaper_args.cb = cb;
693 vol->worker_args.reaper_args.cb_arg = arg;
694
695 pthread_attr_t attr;
696 pthread_attr_init(&attr);
697 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
698
699 pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol);
700 }
701
702 static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange)
703 {
704 int i, rc;
705
706 if (v->state == volstate_mounted || v->state == volstate_badremoval) {
707 // Try to unmount right away (5 retries)
708 for (i = 0; i < 5; i++) {
709 rc = umount(v->mount_point);
710 if (!rc)
711 break;
712
713 if (rc && (errno == EINVAL || errno == ENOENT)) {
714 rc = 0;
715 break;
716 }
717
718 LOG_VOL("volmngr quick stop umount(%s) attempt %d (%s)",
719 v->mount_point, i + 1, strerror(errno));
720
721 if (i == 0)
722 usleep(1000 * 250); // First failure, sleep for 250 ms
723 else
724 sched_yield();
725 }
726
727 if (!rc) {
728 LOG_VOL("volmgr_stop_volume(%s): Volume unmounted sucessfully",
729 v->mount_point);
730 if (emit_statechange)
731 volume_setstate(v, volstate_unmounted);
732 v->fs = NULL;
733 goto out_cb_immed;
734 }
735
736 /*
737 * Since the volume is still in use, dispatch the stopping to
738 * a thread
739 */
740 LOG_VOL("Volume %s is busy (%d) - uncaging the reaper", v->mount_point, rc);
741 volmgr_uncage_reaper(v, cb, arg);
742 return -EINPROGRESS;
743 } else if (v->state == volstate_checking) {
744 volume_setstate(v, volstate_unmounted);
745 if (v->worker_running) {
746 LOG_VOL("Cancelling worker thread");
747 pthread_kill(v->worker_thread, SIGUSR1);
748 } else
749 LOGE("Strange... we were in checking state but worker thread wasn't running..");
750 goto out_cb_immed;
751 }
752
753 out_cb_immed:
754 if (cb)
755 cb(v, arg);
756 return 0;
757 }
758
759
760 /*
761 * Gracefully stop a volume
762 * v->lock must be held!
763 * if we return -EINPROGRESS, do NOT release the lock as the reaper
764 * is using the volume
765 */
766 static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *), boolean emit_statechange)
767 {
768 return volmgr_stop_volume(v, cb, NULL, emit_statechange);
769 }
770
771 static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg)
772 {
773 void (* shutdown_cb) (volume_t *) = arg;
774
775 #if DEBUG_VOLMGR
776 LOG_VOL("Volume %s has been stopped for shutdown", v->mount_point);
777 #endif
778 shutdown_cb(v);
779 }
780
781
782 /*
783 * Called when a volume is sucessfully unmounted for UMS enable
784 */
785 static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)
786 {
787 int rc;
788 char *devdir_path;
789
790 #if DEBUG_VOLMGR
791 LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point);
792 #endif
793 devdir_path = blkdev_get_devpath(v->dev->disk);
794
795 if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) {
796 free(devdir_path);
797 LOGE("Error enabling ums (%d)", rc);
798 return;
799 }
800 free(devdir_path);
801 volume_setstate(v, volstate_ums);
802 pthread_mutex_unlock(&v->lock);
803 }
804
805 static int volmgr_readconfig(char *cfg_path)
806 {
807 cnode *root = config_node("", "");
808 cnode *node;
809
810 config_load_file(root, cfg_path);
811 node = root->first_child;
812
813 while (node) {
814 if (!strncmp(node->name, "volume_", 7))
815 volmgr_config_volume(node);
816 else
817 LOGE("Skipping unknown configuration node '%s'", node->name);
818 node = node->next;
819 }
820 return 0;
821 }
822
823 static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path)
824 {
825 int i;
826
827 #if DEBUG_VOLMGR
828 LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):", v, media_path);
829 #endif
830 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
831 if (!v->media_paths[i]) {
832 v->media_paths[i] = strdup(media_path);
833 return;
834 }
835 }
836 LOGE("Unable to add media path '%s' to volume (out of media slots)", media_path);
837 }
838
839 static int volmgr_config_volume(cnode *node)
840 {
841 volume_t *new;
842 int rc = 0, i;
843
844 char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs;
845 uint32_t dm_size_mb = 0;
846
847 dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL;
848 #if DEBUG_VOLMGR
849 LOG_VOL("volmgr_configure_volume(%s):", node->name);
850 #endif
851 if (!(new = malloc(sizeof(volume_t))))
852 return -ENOMEM;
853 memset(new, 0, sizeof(volume_t));
854
855 new->state = volstate_nomedia;
856 pthread_mutex_init(&new->lock, NULL);
857 pthread_mutex_init(&new->worker_sem, NULL);
858
859 cnode *child = node->first_child;
860
861 while (child) {
862 if (!strcmp(child->name, "media_path"))
863 volmgr_add_mediapath_to_volume(new, child->value);
864 else if (!strcmp(child->name, "emu_media_path"))
865 volmgr_add_mediapath_to_volume(new, child->value);
866 else if (!strcmp(child->name, "media_type")) {
867 if (!strcmp(child->value, "mmc"))
868 new->media_type = media_mmc;
869 else if (!strcmp(child->value, "devmapper"))
870 new->media_type = media_devmapper;
871 else {
872 LOGE("Invalid media type '%s'", child->value);
873 rc = -EINVAL;
874 goto out_free;
875 }
876 } else if (!strcmp(child->name, "mount_point"))
877 new->mount_point = strdup(child->value);
878 else if (!strcmp(child->name, "ums_path"))
879 new->ums_path = strdup(child->value);
880 else if (!strcmp(child->name, "dm_src"))
881 dm_src = strdup(child->value);
882 else if (!strcmp(child->name, "dm_src_type"))
883 dm_src_type = strdup(child->value);
884 else if (!strcmp(child->name, "dm_src_size_mb"))
885 dm_size_mb = atoi(child->value);
886 else if (!strcmp(child->name, "dm_target"))
887 dm_tgt = strdup(child->value);
888 else if (!strcmp(child->name, "dm_target_params"))
889 dm_param = strdup(child->value);
890 else if (!strcmp(child->name, "dm_target_fs"))
891 dm_tgtfs = strdup(child->value);
892 else
893 LOGE("Ignoring unknown config entry '%s'", child->name);
894 child = child->next;
895 }
896
897 if (new->media_type == media_mmc) {
898 if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) {
899 LOGE("Required configuration parameter missing for mmc volume");
900 rc = -EINVAL;
901 goto out_free;
902 }
903 } else if (new->media_type == media_devmapper) {
904 if (!dm_src || !dm_src_type || !dm_tgt ||
905 !dm_param || !dm_tgtfs || !dm_size_mb) {
906 LOGE("Required configuration parameter missing for devmapper volume");
907 rc = -EINVAL;
908 goto out_free;
909 }
910
911 char dm_mediapath[255];
912 if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb,
913 dm_tgt, dm_param, dm_tgtfs, dm_mediapath))) {
914 LOGE("Unable to initialize devmapping");
915 goto out_free;
916 }
917 LOG_VOL("media path for devmapper volume = '%s'", dm_mediapath);
918 volmgr_add_mediapath_to_volume(new, dm_mediapath);
919 }
920
921 if (!vol_root)
922 vol_root = new;
923 else {
924 volume_t *scan = vol_root;
925 while (scan->next)
926 scan = scan->next;
927 scan->next = new;
928 }
929
930 if (dm_src)
931 free(dm_src);
932 if (dm_src_type)
933 free(dm_src_type);
934 if (dm_tgt)
935 free(dm_tgt);
936 if (dm_param)
937 free(dm_param);
938 if (dm_tgtfs)
939 free(dm_tgtfs);
940
941 return rc;
942
943 out_free:
944
945 if (dm_src)
946 free(dm_src);
947 if (dm_src_type)
948 free(dm_src_type);
949 if (dm_tgt)
950 free(dm_tgt);
951 if (dm_param)
952 free(dm_param);
953 if (dm_tgtfs)
954 free(dm_tgtfs);
955
956
957 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
958 if (new->media_paths[i])
959 free(new->media_paths[i]);
960 }
961 if (new->mount_point)
962 free(new->mount_point);
963 if (new->ums_path)
964 free(new->ums_path);
965 return rc;
966 }
967
968 static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev)
969 {
970 volume_t *scan = vol_root;
971 while(scan) {
972 if (scan->dev == dev)
973 return scan;
974 scan = scan->next;
975 }
976 return NULL;
977 }
978
979 static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked)
980 {
981 volume_t *v = vol_root;
982
983 while(v) {
984 pthread_mutex_lock(&v->lock);
985 if (!strcmp(v->mount_point, mount_point)) {
986 if (!leave_locked)
987 pthread_mutex_unlock(&v->lock);
988 return v;
989 }
990 pthread_mutex_unlock(&v->lock);
991 v = v->next;
992 }
993 return NULL;
994 }
995
996 static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
997 {
998 volume_t *scan = vol_root;
999 int i;
1000
1001 while (scan) {
1002
1003 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
1004 if (!scan->media_paths[i])
1005 continue;
1006
1007 if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i])))
1008 return scan;
1009 else if (!fuzzy && !strcmp(media_path, scan->media_paths[i]))
1010 return scan;
1011 }
1012
1013 scan = scan->next;
1014 }
1015 return NULL;
1016 }
1017
1018 /*
1019 * Attempt to bring a volume online
1020 * Returns: 0 on success, errno on failure, with the following exceptions:
1021 * - ENODATA - Unsupported filesystem type / blank
1022 * vol->lock MUST be held!
1023 */
1024 static int _volmgr_start(volume_t *vol, blkdev_t *dev)
1025 {
1026 struct volmgr_fstable_entry *fs;
1027 int rc = ENODATA;
1028
1029 #if DEBUG_VOLMGR
1030 LOG_VOL("_volmgr_start(%s, %d:%d):", vol->mount_point,
1031 dev->major, dev->minor);
1032 #endif
1033
1034 if (vol->state == volstate_mounted) {
1035 LOGE("Unable to start volume '%s' (already mounted)", vol->mount_point);
1036 return -EBUSY;
1037 }
1038
1039 for (fs = fs_table; fs->name; fs++) {
1040 if (!fs->identify_fn(dev))
1041 break;
1042 }
1043
1044 if (!fs) {
1045 LOGE("No supported filesystems on %d:%d", dev->major, dev->minor);
1046 volume_setstate(vol, volstate_nofs);
1047 return -ENODATA;
1048 }
1049
1050 return volmgr_start_fs(fs, vol, dev);
1051 }
1052
1053 // vol->lock MUST be held!
1054 static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)
1055 {
1056 /*
1057 * Spawn a thread to do the actual checking / mounting in
1058 */
1059
1060 if (vol->worker_running) {
1061 LOGE("Worker thread is currently running.. waiting..");
1062 pthread_mutex_lock(&vol->worker_sem);
1063 LOG_VOL("Worker thread now available");
1064 }
1065
1066 vol->dev = dev;
1067
1068 vol->worker_args.start_args.fs = fs;
1069 vol->worker_args.start_args.dev = dev;
1070
1071 pthread_attr_t attr;
1072 pthread_attr_init(&attr);
1073 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1074
1075 pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);
1076
1077 return 0;
1078 }
1079
1080 static void __start_fs_thread_lock_cleanup(void *arg)
1081 {
1082 volume_t *vol = (volume_t *) arg;
1083
1084 #if DEBUG_VOLMGR
1085 LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point);
1086 #endif
1087
1088 vol->worker_running = false;
1089
1090 // Wake up anyone that was waiting on this thread
1091 pthread_mutex_unlock(&vol->worker_sem);
1092
1093 // Unlock the volume
1094 pthread_mutex_unlock(&vol->lock);
1095 }
1096
1097 static void *volmgr_start_fs_thread(void *arg)
1098 {
1099 volume_t *vol = (volume_t *) arg;
1100
1101 pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg);
1102 pthread_mutex_lock(&vol->lock);
1103
1104 vol->worker_running = true;
1105 vol->worker_pid = getpid();
1106
1107 struct sigaction actions;
1108
1109 memset(&actions, 0, sizeof(actions));
1110 sigemptyset(&actions.sa_mask);
1111 actions.sa_flags = 0;
1112 actions.sa_handler = volmgr_start_fs_thread_sighandler;
1113 sigaction(SIGUSR1, &actions, NULL);
1114
1115 struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs;
1116 blkdev_t *dev = vol->worker_args.start_args.dev;
1117 int rc;
1118
1119 #if DEBUG_VOLMGR
1120 LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s", getpid(),
1121 fs->name, dev->major, dev->minor, vol->mount_point);
1122 #endif
1123
1124 if (fs->check_fn) {
1125 #if DEBUG_VOLMGR
1126 LOG_VOL("Starting %s filesystem check on %d:%d", fs->name,
1127 dev->major, dev->minor);
1128 #endif
1129 volume_setstate(vol, volstate_checking);
1130 pthread_mutex_unlock(&vol->lock);
1131 rc = fs->check_fn(dev);
1132 pthread_mutex_lock(&vol->lock);
1133 if (vol->state != volstate_checking) {
1134 LOG_VOL("filesystem check aborted");
1135 goto out;
1136 }
1137
1138 if (rc < 0) {
1139 LOGE("%s filesystem check failed on %d:%d (%s)", fs->name,
1140 dev->major, dev->minor, strerror(-rc));
1141 if (rc == -ENODATA) {
1142 volume_setstate(vol, volstate_nofs);
1143 goto out;
1144 }
1145 goto out_unmountable;
1146 }
1147 #if DEBUG_VOLMGR
1148 LOG_VOL("%s filesystem check of %d:%d OK", fs->name,
1149 dev->major, dev->minor);
1150 #endif
1151 }
1152
1153 rc = fs->mount_fn(dev, vol, safe_mode);
1154 if (!rc) {
1155 LOG_VOL("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)",
1156 fs->name, dev->major, dev->minor, vol->mount_point,
1157 (safe_mode ? "on" : "off"));
1158 vol->fs = fs;
1159 volume_setstate(vol, volstate_mounted);
1160 goto out;
1161 }
1162
1163 LOGE("%s filesystem mount of %d:%d failed (%d)", fs->name, dev->major,
1164 dev->minor, rc);
1165
1166 out_unmountable:
1167 volume_setstate(vol, volstate_damaged);
1168 out:
1169 pthread_cleanup_pop(1);
1170 pthread_exit(NULL);
1171 return NULL;
1172 }
1173
1174 static void volmgr_start_fs_thread_sighandler(int signo)
1175 {
1176 LOGE("Volume startup thread got signal %d", signo);
1177 }
1178
1179 static void volume_setstate(volume_t *vol, volume_state_t state)
1180 {
1181 if (state == vol->state)
1182 return;
1183
1184 #if DEBUG_VOLMGR
1185 LOG_VOL("Volume %s state change from %d -> %d", vol->mount_point, vol->state, state);
1186 #endif
1187
1188 vol->state = state;
1189
1190 char *prop_val = conv_volstate_to_propstr(vol->state);
1191
1192 if (prop_val) {
1193 property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
1194 volume_send_state(vol);
1195 }
1196 }
1197
1198 static int volume_send_state(volume_t *vol)
1199 {
1200 char *event = conv_volstate_to_eventstr(vol->state);
1201
1202 return send_msg_with_data(event, vol->mount_point);
1203 }
1204
1205 static char *conv_volstate_to_eventstr(volume_state_t state)
1206 {
1207 int i;
1208
1209 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1210 if (volume_state_strings[i].state == state)
1211 break;
1212 }
1213
1214 return volume_state_strings[i].event;
1215 }
1216
1217 static char *conv_volstate_to_propstr(volume_state_t state)
1218 {
1219 int i;
1220
1221 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1222 if (volume_state_strings[i].state == state)
1223 break;
1224 }
1225
1226 return volume_state_strings[i].property_val;
1227 }
1228
+0
-135
vold/volmgr.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _VOLMGR_H
18 #define _VOLMGR_H
19
20 #include <pthread.h>
21
22 #include "vold.h"
23 #include "blkdev.h"
24 #include "media.h"
25 #include "devmapper.h"
26
27 #define PROP_EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
28
29 // these must match the corresponding states in the MediaState enum.
30 // A path to the volume mount point follows the colon
31 typedef enum volume_state {
32 volstate_unknown,
33
34 volstate_nomedia,
35 #define VOLD_EVT_NOMEDIA "volume_nomedia:"
36 #define VOLD_ES_PVAL_NOMEDIA "removed"
37
38 volstate_unmounted,
39 #define VOLD_EVT_UNMOUNTED "volume_unmounted:"
40 #define VOLD_ES_PVAL_UNMOUNTED "unmounted"
41
42 volstate_checking,
43 #define VOLD_EVT_CHECKING "volume_checking:"
44 #define VOLD_ES_PVAL_CHECKING "checking"
45
46 volstate_mounted,
47 #define VOLD_EVT_MOUNTED "volume_mounted:"
48 #define VOLD_ES_PVAL_MOUNTED "mounted"
49
50 volstate_mounted_ro,
51 #define VOLD_EVT_MOUNTED_RO "volume_mounted_ro:"
52 #define VOLD_ES_PVAL_MOUNTED_RO "mounted_ro"
53
54 volstate_badremoval,
55 #define VOLD_EVT_BADREMOVAL "volume_badremoval:"
56 #define VOLD_ES_PVAL_BADREMOVAL "bad_removal"
57
58 volstate_damaged,
59 #define VOLD_EVT_DAMAGED "volume_damaged:"
60 #define VOLD_ES_PVAL_DAMAGED "unmountable"
61
62 volstate_nofs,
63 #define VOLD_EVT_NOFS "volume_nofs:"
64 #define VOLD_ES_PVAL_NOFS "nofs"
65
66 volstate_ums,
67 #define VOLD_EVT_UMS "volume_ums:"
68 #define VOLD_ES_PVAL_UMS "shared"
69
70 volstate_ejecting,
71 #define VOLD_EVT_EJECTING "volume_ejecting:"
72 #define VOLD_ES_PVAL_EJECTING "ejecting"
73
74 volstate_formatting,
75 } volume_state_t;
76
77 struct volume;
78
79 struct volmgr_fstable_entry {
80 char *name;
81 int (*identify_fn) (blkdev_t *dev);
82 int (*check_fn) (blkdev_t *dev);
83 int (*mount_fn) (blkdev_t *dev, struct volume *vol, boolean safe_mode);
84 boolean case_sensitive_paths;
85 };
86
87 struct volmgr_start_args {
88 struct volmgr_fstable_entry *fs;
89 blkdev_t *dev;
90 };
91
92 struct volmgr_reaper_args {
93 void (*cb) (struct volume *, void *);
94 void *cb_arg;
95 };
96
97 #define VOLMGR_MAX_MEDIAPATHS_PER_VOLUME 8
98
99 typedef struct volume {
100 char *media_paths[VOLMGR_MAX_MEDIAPATHS_PER_VOLUME];
101
102 media_type_t media_type;
103 char *mount_point;
104 char *ums_path;
105 struct devmapping *dm;
106
107 pthread_mutex_t lock;
108 volume_state_t state;
109 blkdev_t *dev;
110 pid_t worker_pid;
111 pthread_t worker_thread;
112 union {
113 struct volmgr_start_args start_args;
114 struct volmgr_reaper_args reaper_args;
115 } worker_args;
116 boolean worker_running;
117 pthread_mutex_t worker_sem;
118
119 struct volmgr_fstable_entry *fs;
120
121 struct volume *next;
122 } volume_t;
123
124 int volmgr_consider_disk(blkdev_t *dev);
125 int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *));
126 int volmgr_send_states(void);
127 int volmgr_enable_ums(boolean enable);
128 int volmgr_stop_volume_by_mountpoint(char *mount_point);
129 int volmgr_start_volume_by_mountpoint(char *mount_point);
130 int volmgr_safe_mode(boolean enable);
131 int volmgr_format_volume(char *mount_point);
132 int volmgr_set_volume_key(char *mount_point, unsigned char *key);
133 void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded);
134 #endif
+0
-184
vold/volmgr_ext3.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fcntl.h>
18 #include <errno.h>
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/mount.h>
23
24 #include <linux/ext2_fs.h>
25 #include <linux/ext3_fs.h>
26
27 #include "vold.h"
28 #include "volmgr.h"
29 #include "volmgr_ext3.h"
30 #include "logwrapper.h"
31
32
33 #define EXT_DEBUG 0
34
35 static char E2FSCK_PATH[] = "/system/bin/e2fsck";
36
37 int ext_identify(blkdev_t *dev)
38 {
39 int rc = -1;
40 int fd;
41 struct ext3_super_block sb;
42 char *devpath;
43
44 #if EXT_DEBUG
45 LOG_VOL("ext_identify(%d:%d):", dev-major, dev->minor);
46 #endif
47
48 devpath = blkdev_get_devpath(dev);
49
50 if ((fd = open(devpath, O_RDWR)) < 0) {
51 LOGE("Unable to open device '%s' (%s)", devpath,
52 strerror(errno));
53 free(devpath);
54 return -errno;
55 }
56
57 if (lseek(fd, 1024, SEEK_SET) < 0) {
58 LOGE("Unable to lseek to get superblock (%s)", strerror(errno));
59 rc = -errno;
60 goto out;
61 }
62
63 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
64 LOGE("Unable to read superblock (%s)", strerror(errno));
65 rc = -errno;
66 goto out;
67 }
68
69 if (sb.s_magic == EXT2_SUPER_MAGIC ||
70 sb.s_magic == EXT3_SUPER_MAGIC)
71 rc = 0;
72 else
73 rc = -ENODATA;
74
75 out:
76 #if EXT_DEBUG
77 LOG_VOL("ext_identify(%s): rc = %d", devpath, rc);
78 #endif
79 free(devpath);
80 close(fd);
81 return rc;
82 }
83
84 int ext_check(blkdev_t *dev)
85 {
86 char *devpath;
87
88 #if EXT_DEBUG
89 LOG_VOL("ext_check(%s):", dev->dev_fspath);
90 #endif
91
92 devpath = blkdev_get_devpath(dev);
93
94 if (access(E2FSCK_PATH, X_OK)) {
95 LOGE("ext_check(%s): %s not found (skipping checks)",
96 devpath, E2FSCK_PATH);
97 free(devpath);
98 return 0;
99 }
100
101 char *args[5];
102
103 args[0] = E2FSCK_PATH;
104 args[1] = "-v";
105 args[2] = "-p";
106 args[3] = devpath;
107 args[4] = NULL;
108
109 int rc = logwrap(4, args);
110
111 if (rc == 0) {
112 LOG_VOL("filesystem '%s' had no errors", devpath);
113 } else if (rc == 1) {
114 LOG_VOL("filesystem '%s' had corrected errors", devpath);
115 rc = 0;
116 } else if (rc == 2) {
117 LOGE("VOL volume '%s' had corrected errors (system should be rebooted)", devpath);
118 rc = -EIO;
119 } else if (rc == 4) {
120 LOGE("VOL volume '%s' had uncorrectable errors", devpath);
121 rc = -EIO;
122 } else if (rc == 8) {
123 LOGE("Operational error while checking volume '%s'", devpath);
124 rc = -EIO;
125 } else {
126 LOGE("Unknown e2fsck exit code (%d)", rc);
127 rc = -EIO;
128 }
129 free(devpath);
130 return rc;
131 }
132
133 int ext_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode)
134 {
135 #if EXT_DEBUG
136 LOG_VOL("ext_mount(%s, %s, %d):", dev->dev_fspath, vol->mount_point, safe_mode);
137 #endif
138
139 char *fs[] = { "ext3", "ext2", NULL };
140 char *devpath;
141
142 devpath = blkdev_get_devpath(dev);
143
144 int flags, rc = 0;
145
146 flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
147
148 if (safe_mode)
149 flags |= MS_SYNCHRONOUS;
150
151 if (vol->state == volstate_mounted) {
152 LOG_VOL("Remounting %s on %s, safe mode %d", devpath,
153 vol->mount_point, safe_mode);
154 flags |= MS_REMOUNT;
155 }
156
157 char **f;
158 for (f = fs; *f != NULL; f++) {
159 rc = mount(devpath, vol->mount_point, *f, flags, NULL);
160 if (rc && errno == EROFS) {
161 LOGE("ext_mount(%s, %s): Read only filesystem - retrying mount RO",
162 devpath, vol->mount_point);
163 flags |= MS_RDONLY;
164 rc = mount(devpath, vol->mount_point, *f, flags, NULL);
165 }
166 #if EXT_DEBUG
167 LOG_VOL("ext_mount(%s, %s): %s mount rc = %d", devpath, *f,
168 vol->mount_point, rc);
169 #endif
170 if (!rc)
171 break;
172 }
173 free(devpath);
174
175 // Chmod the mount point so that its a free-for-all.
176 // (required for consistency with VFAT.. sigh)
177 if (chmod(vol->mount_point, 0777) < 0) {
178 LOGE("Failed to chmod %s (%s)", vol->mount_point, strerror(errno));
179 return -errno;
180 }
181
182 return rc;
183 }
+0
-27
vold/volmgr_ext3.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _VOLMGR_EXT3_H
18 #define _VOLMGR_EXT3_H
19
20 #include "volmgr.h"
21 #include "blkdev.h"
22
23 int ext_identify(blkdev_t *blkdev);
24 int ext_check(blkdev_t *blkdev);
25 int ext_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode);
26 #endif
+0
-135
vold/volmgr_vfat.c less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18
19 #include <sys/mount.h>
20
21 #include "vold.h"
22 #include "volmgr.h"
23 #include "volmgr_vfat.h"
24 #include "logwrapper.h"
25
26 #define VFAT_DEBUG 0
27
28 static char FSCK_MSDOS_PATH[] = "/system/bin/dosfsck";
29
30 int vfat_identify(blkdev_t *dev)
31 {
32 #if VFAT_DEBUG
33 LOG_VOL("vfat_identify(%d:%d):", dev->major, dev->minor);
34 #endif
35 return 0; // XXX: Implement
36 }
37
38 int vfat_check(blkdev_t *dev)
39 {
40 int rc;
41
42 #if VFAT_DEBUG
43 LOG_VOL("vfat_check(%d:%d):", dev->major, dev->minor);
44 #endif
45
46 if (access(FSCK_MSDOS_PATH, X_OK)) {
47 LOGE("vfat_check(%d:%d): %s not found (skipping checks)",
48 dev->major, dev->minor, FSCK_MSDOS_PATH);
49 return 0;
50 }
51
52 #ifdef VERIFY_PASS
53 char *args[7];
54 args[0] = FSCK_MSDOS_PATH;
55 args[1] = "-v";
56 args[2] = "-V";
57 args[3] = "-w";
58 args[4] = "-p";
59 args[5] = blkdev_get_devpath(dev);
60 args[6] = NULL;
61 rc = logwrap(6, args);
62 free(args[5]);
63 #else
64 char *args[6];
65 args[0] = FSCK_MSDOS_PATH;
66 args[1] = "-v";
67 args[2] = "-w";
68 args[3] = "-p";
69 args[4] = blkdev_get_devpath(dev);
70 args[5] = NULL;
71 rc = logwrap(5, args);
72 free(args[4]);
73 #endif
74
75 if (rc == 0) {
76 LOG_VOL("Filesystem check completed OK");
77 return 0;
78 } else if (rc == 1) {
79 LOG_VOL("Filesystem check failed (general failure)");
80 return -EINVAL;
81 } else if (rc == 2) {
82 LOG_VOL("Filesystem check failed (invalid usage)");
83 return -EIO;
84 } else if (rc == 4) {
85 LOG_VOL("Filesystem check completed (errors fixed)");
86 } else if (rc == 8) {
87 LOG_VOL("Filesystem check failed (not a FAT filesystem)");
88 return -ENODATA;
89 } else {
90 LOG_VOL("Filesystem check failed (unknown exit code %d)", rc);
91 return -EIO;
92 }
93 return 0;
94 }
95
96 int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode)
97 {
98 int flags, rc;
99 char *devpath;
100
101 devpath = blkdev_get_devpath(dev);
102
103 #if VFAT_DEBUG
104 LOG_VOL("vfat_mount(%d:%d, %s, %d):", dev->major, dev->minor, vol->mount_point, safe_mode);
105 #endif
106
107 flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
108
109 if (safe_mode)
110 flags |= MS_SYNCHRONOUS;
111 if (vol->state == volstate_mounted) {
112 LOG_VOL("Remounting %d:%d on %s, safe mode %d", dev->major,
113 dev->minor, vol->mount_point, safe_mode);
114 flags |= MS_REMOUNT;
115 }
116
117 rc = mount(devpath, vol->mount_point, "vfat", flags,
118 "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
119
120 if (rc && errno == EROFS) {
121 LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO",
122 dev->major, dev->minor, vol->mount_point);
123 flags |= MS_RDONLY;
124 rc = mount(devpath, vol->mount_point, "vfat", flags,
125 "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
126 }
127
128 #if VFAT_DEBUG
129 LOG_VOL("vfat_mount(%s, %d:%d): mount rc = %d", dev->major,k dev->minor,
130 vol->mount_point, rc);
131 #endif
132 free (devpath);
133 return rc;
134 }
+0
-29
vold/volmgr_vfat.h less more
0
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _VOLMGR_VFAT_H
18 #define _VOLMGR_VFAT_H
19
20 #include "volmgr.h"
21 #include "blkdev.h"
22
23
24
25 int vfat_identify(blkdev_t *blkdev);
26 int vfat_check(blkdev_t *blkdev);
27 int vfat_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode);
28 #endif