diff options
Diffstat (limited to 'liblog')
-rw-r--r-- | liblog/Android.mk | 8 | ||||
-rw-r--r-- | liblog/config_read.c | 62 | ||||
-rw-r--r-- | liblog/config_read.h | 50 | ||||
-rw-r--r-- | liblog/config_write.c | 66 | ||||
-rw-r--r-- | liblog/config_write.h | 50 | ||||
-rw-r--r-- | liblog/event_tag_map.c | 2 | ||||
-rw-r--r-- | liblog/fake_log_device.c | 2 | ||||
-rw-r--r-- | liblog/fake_log_device.h | 2 | ||||
-rw-r--r-- | liblog/fake_writer.c | 82 | ||||
-rw-r--r-- | liblog/log_event_list.c | 2 | ||||
-rw-r--r-- | liblog/log_event_write.c | 2 | ||||
-rw-r--r-- | liblog/log_is_loggable.c | 2 | ||||
-rw-r--r-- | liblog/log_portability.h (renamed from liblog/log_cdefs.h) | 34 | ||||
-rw-r--r-- | liblog/log_read.c | 917 | ||||
-rw-r--r-- | liblog/log_time.cpp | 2 | ||||
-rw-r--r-- | liblog/logd_reader.c | 670 | ||||
-rw-r--r-- | liblog/logd_writer.c | 267 | ||||
-rw-r--r-- | liblog/logger.h | 159 | ||||
-rw-r--r-- | liblog/logger_lock.c | 82 | ||||
-rw-r--r-- | liblog/logger_name.c | 65 | ||||
-rw-r--r-- | liblog/logger_read.c | 474 | ||||
-rw-r--r-- | liblog/logger_write.c (renamed from liblog/logd_write.c) | 415 | ||||
-rw-r--r-- | liblog/logprint.c | 2 | ||||
-rw-r--r-- | liblog/pmsg_reader.c | 255 | ||||
-rw-r--r-- | liblog/pmsg_writer.c | 159 | ||||
-rw-r--r-- | liblog/uio.c | 2 |
26 files changed, 2587 insertions, 1246 deletions
diff --git a/liblog/Android.mk b/liblog/Android.mk index 6d53a4af0..01c8e77b2 100644 --- a/liblog/Android.mk +++ b/liblog/Android.mk | |||
@@ -24,10 +24,14 @@ include $(CLEAR_VARS) | |||
24 | # so make sure we do not regret hard-coding it as follows: | 24 | # so make sure we do not regret hard-coding it as follows: |
25 | liblog_cflags := -DLIBLOG_LOG_TAG=1005 | 25 | liblog_cflags := -DLIBLOG_LOG_TAG=1005 |
26 | 26 | ||
27 | liblog_sources := logd_write.c log_event_list.c log_event_write.c | 27 | liblog_sources := log_event_list.c log_event_write.c logger_write.c |
28 | liblog_sources += config_write.c logger_name.c logger_lock.c | ||
28 | liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags | 29 | liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags |
30 | liblog_host_sources += fake_writer.c | ||
29 | liblog_target_sources := $(liblog_sources) event_tag_map.c | 31 | liblog_target_sources := $(liblog_sources) event_tag_map.c |
30 | liblog_target_sources += log_time.cpp log_is_loggable.c logprint.c log_read.c | 32 | liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c |
33 | liblog_target_sources += pmsg_reader.c pmsg_writer.c | ||
34 | liblog_target_sources += logd_reader.c logd_writer.c logger_read.c | ||
31 | 35 | ||
32 | # Shared and static library for host | 36 | # Shared and static library for host |
33 | # ======================================================== | 37 | # ======================================================== |
diff --git a/liblog/config_read.c b/liblog/config_read.c new file mode 100644 index 000000000..1f54152b0 --- /dev/null +++ b/liblog/config_read.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 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 "config_read.h" | ||
18 | #include "logger.h" | ||
19 | |||
20 | LIBLOG_HIDDEN struct listnode __android_log_transport_read = | ||
21 | { &__android_log_transport_read, &__android_log_transport_read }; | ||
22 | LIBLOG_HIDDEN struct listnode __android_log_persist_read = | ||
23 | { &__android_log_persist_read, &__android_log_persist_read }; | ||
24 | |||
25 | static void __android_log_add_transport( | ||
26 | struct listnode *list, struct android_log_transport_read *transport) { | ||
27 | size_t i; | ||
28 | |||
29 | /* Try to keep one functioning transport for each log buffer id */ | ||
30 | for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) { | ||
31 | struct android_log_transport_read *transp; | ||
32 | |||
33 | if (list_empty(list)) { | ||
34 | if (!transport->available || ((*transport->available)(i) >= 0)) { | ||
35 | list_add_tail(list, &transport->node); | ||
36 | return; | ||
37 | } | ||
38 | } else { | ||
39 | read_transport_for_each(transp, list) { | ||
40 | if (!transp->available) { | ||
41 | return; | ||
42 | } | ||
43 | if (((*transp->available)(i) < 0) && | ||
44 | (!transport->available || | ||
45 | ((*transport->available)(i) >= 0))) { | ||
46 | list_add_tail(list, &transport->node); | ||
47 | return; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | LIBLOG_HIDDEN void __android_log_config_read() { | ||
55 | #if (FAKE_LOG_DEVICE == 0) | ||
56 | extern struct android_log_transport_read logdLoggerRead; | ||
57 | extern struct android_log_transport_read pmsgLoggerRead; | ||
58 | |||
59 | __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead); | ||
60 | __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead); | ||
61 | #endif | ||
62 | } | ||
diff --git a/liblog/config_read.h b/liblog/config_read.h new file mode 100644 index 000000000..67f4c20d0 --- /dev/null +++ b/liblog/config_read.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 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 _LIBLOG_CONFIG_READ_H__ | ||
18 | #define _LIBLOG_CONFIG_READ_H__ | ||
19 | |||
20 | #include <cutils/list.h> | ||
21 | |||
22 | #include "log_portability.h" | ||
23 | |||
24 | __BEGIN_DECLS | ||
25 | |||
26 | extern LIBLOG_HIDDEN struct listnode __android_log_transport_read; | ||
27 | extern LIBLOG_HIDDEN struct listnode __android_log_persist_read; | ||
28 | |||
29 | #define read_transport_for_each(transp, transports) \ | ||
30 | for (transp = node_to_item((transports)->next, \ | ||
31 | struct android_log_transport_read, node); \ | ||
32 | (transp != node_to_item(transports, \ | ||
33 | struct android_log_transport_read, node)); \ | ||
34 | transp = node_to_item(transp->node.next, \ | ||
35 | struct android_log_transport_read, node)) \ | ||
36 | |||
37 | #define read_transport_for_each_safe(transp, n, transports) \ | ||
38 | for (transp = node_to_item((transports)->next, \ | ||
39 | struct android_log_transport_read, node), \ | ||
40 | n = transp->node.next; \ | ||
41 | (transp != node_to_item(transports, \ | ||
42 | struct android_log_transport_read, node)); \ | ||
43 | transp = node_to_item(n, struct android_log_transport_read, node), \ | ||
44 | n = transp->node.next) | ||
45 | |||
46 | LIBLOG_HIDDEN void __android_log_config_read(); | ||
47 | |||
48 | __END_DECLS | ||
49 | |||
50 | #endif /* _LIBLOG_CONFIG_READ_H__ */ | ||
diff --git a/liblog/config_write.c b/liblog/config_write.c new file mode 100644 index 000000000..d689f631b --- /dev/null +++ b/liblog/config_write.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 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 "config_write.h" | ||
18 | #include "logger.h" | ||
19 | |||
20 | LIBLOG_HIDDEN struct listnode __android_log_transport_write = | ||
21 | { &__android_log_transport_write, &__android_log_transport_write }; | ||
22 | LIBLOG_HIDDEN struct listnode __android_log_persist_write = | ||
23 | { &__android_log_persist_write, &__android_log_persist_write}; | ||
24 | |||
25 | static void __android_log_add_transport( | ||
26 | struct listnode *list, struct android_log_transport_write *transport) { | ||
27 | size_t i; | ||
28 | |||
29 | /* Try to keep one functioning transport for each log buffer id */ | ||
30 | for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) { | ||
31 | struct android_log_transport_write *transp; | ||
32 | |||
33 | if (list_empty(list)) { | ||
34 | if (!transport->available || ((*transport->available)(i) >= 0)) { | ||
35 | list_add_tail(list, &transport->node); | ||
36 | return; | ||
37 | } | ||
38 | } else { | ||
39 | write_transport_for_each(transp, list) { | ||
40 | if (!transp->available) { | ||
41 | return; | ||
42 | } | ||
43 | if (((*transp->available)(i) < 0) && | ||
44 | (!transport->available || | ||
45 | ((*transport->available)(i) >= 0))) { | ||
46 | list_add_tail(list, &transport->node); | ||
47 | return; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | LIBLOG_HIDDEN void __android_log_config_write() { | ||
55 | #if (FAKE_LOG_DEVICE == 0) | ||
56 | extern struct android_log_transport_write logdLoggerWrite; | ||
57 | extern struct android_log_transport_write pmsgLoggerWrite; | ||
58 | |||
59 | __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite); | ||
60 | __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite); | ||
61 | #else | ||
62 | extern struct android_log_transport_write fakeLoggerWrite; | ||
63 | |||
64 | __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite); | ||
65 | #endif | ||
66 | } | ||
diff --git a/liblog/config_write.h b/liblog/config_write.h new file mode 100644 index 000000000..3a02a4e79 --- /dev/null +++ b/liblog/config_write.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 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 _LIBLOG_CONFIG_WRITE_H__ | ||
18 | #define _LIBLOG_CONFIG_WRITE_H__ | ||
19 | |||
20 | #include <cutils/list.h> | ||
21 | |||
22 | #include "log_portability.h" | ||
23 | |||
24 | __BEGIN_DECLS | ||
25 | |||
26 | extern LIBLOG_HIDDEN struct listnode __android_log_transport_write; | ||
27 | extern LIBLOG_HIDDEN struct listnode __android_log_persist_write; | ||
28 | |||
29 | #define write_transport_for_each(transp, transports) \ | ||
30 | for (transp = node_to_item((transports)->next, \ | ||
31 | struct android_log_transport_write, node); \ | ||
32 | (transp != node_to_item(transports, \ | ||
33 | struct android_log_transport_write, node)); \ | ||
34 | transp = node_to_item(transp->node.next, \ | ||
35 | struct android_log_transport_write, node)) \ | ||
36 | |||
37 | #define write_transport_for_each_safe(transp, n, transports) \ | ||
38 | for (transp = node_to_item((transports)->next, \ | ||
39 | struct android_log_transport_write, node), \ | ||
40 | n = transp->node.next; \ | ||
41 | (transp != node_to_item(transports, \ | ||
42 | struct android_log_transport_write, node)); \ | ||
43 | transp = node_to_item(n, struct android_log_transport_write, node), \ | ||
44 | n = transp->node.next) | ||
45 | |||
46 | LIBLOG_HIDDEN void __android_log_config_write(); | ||
47 | |||
48 | __END_DECLS | ||
49 | |||
50 | #endif /* _LIBLOG_CONFIG_WRITE_H__ */ | ||
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c index 870c69aa2..64d872a25 100644 --- a/liblog/event_tag_map.c +++ b/liblog/event_tag_map.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <log/event_tag_map.h> | 24 | #include <log/event_tag_map.h> |
25 | #include <log/log.h> | 25 | #include <log/log.h> |
26 | 26 | ||
27 | #include "log_cdefs.h" | 27 | #include "log_portability.h" |
28 | 28 | ||
29 | #define OUT_TAG "EventTagMap" | 29 | #define OUT_TAG "EventTagMap" |
30 | 30 | ||
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c index c73e03e21..cc67f3eba 100644 --- a/liblog/fake_log_device.c +++ b/liblog/fake_log_device.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <log/logd.h> | 31 | #include <log/logd.h> |
32 | 32 | ||
33 | #include "fake_log_device.h" | 33 | #include "fake_log_device.h" |
34 | #include "log_cdefs.h" | 34 | #include "log_portability.h" |
35 | 35 | ||
36 | #define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */ | 36 | #define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */ |
37 | 37 | ||
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h index 672b446f3..4529b5d95 100644 --- a/liblog/fake_log_device.h +++ b/liblog/fake_log_device.h | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include <sys/types.h> | 20 | #include <sys/types.h> |
21 | 21 | ||
22 | #include "log_cdefs.h" | 22 | #include "log_portability.h" |
23 | 23 | ||
24 | struct iovec; | 24 | struct iovec; |
25 | 25 | ||
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c new file mode 100644 index 000000000..dab8bc54e --- /dev/null +++ b/liblog/fake_writer.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2016 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 <fcntl.h> | ||
19 | #include <unistd.h> | ||
20 | |||
21 | #include <log/log.h> | ||
22 | |||
23 | #include "config_write.h" | ||
24 | #include "fake_log_device.h" | ||
25 | #include "log_portability.h" | ||
26 | #include "logger.h" | ||
27 | |||
28 | static int fakeOpen(); | ||
29 | static void fakeClose(); | ||
30 | static int fakeWrite(log_id_t log_id, struct timespec *ts, | ||
31 | struct iovec *vec, size_t nr); | ||
32 | |||
33 | static int logFds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 }; | ||
34 | |||
35 | LIBLOG_HIDDEN struct android_log_transport_write fakeLoggerWrite = { | ||
36 | .node = { &fakeLoggerWrite.node, &fakeLoggerWrite.node }, | ||
37 | .context.private = &logFds, | ||
38 | .name = "fake", | ||
39 | .available = NULL, | ||
40 | .open = fakeOpen, | ||
41 | .close = fakeClose, | ||
42 | .write = fakeWrite, | ||
43 | }; | ||
44 | |||
45 | static int fakeOpen() { | ||
46 | int i; | ||
47 | |||
48 | for (i = 0; i < LOG_ID_MAX; i++) { | ||
49 | char buf[sizeof("/dev/log_security")]; | ||
50 | snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i)); | ||
51 | logFds[i] = fakeLogOpen(buf, O_WRONLY); | ||
52 | } | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static void fakeClose() { | ||
57 | int i; | ||
58 | |||
59 | for (i = 0; i < LOG_ID_MAX; i++) { | ||
60 | fakeLogClose(logFds[i]); | ||
61 | logFds[i] = -1; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | static int fakeWrite(log_id_t log_id, struct timespec *ts __unused, | ||
66 | struct iovec *vec, size_t nr) | ||
67 | { | ||
68 | ssize_t ret; | ||
69 | int logFd; | ||
70 | |||
71 | if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) { | ||
72 | return -EBADF; | ||
73 | } | ||
74 | |||
75 | logFd = logFds[(int)log_id]; | ||
76 | ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr)); | ||
77 | if (ret < 0) { | ||
78 | ret = -errno; | ||
79 | } | ||
80 | |||
81 | return ret; | ||
82 | } | ||
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c index a77c56eb1..64d9024c6 100644 --- a/liblog/log_event_list.c +++ b/liblog/log_event_list.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <log/log.h> | 25 | #include <log/log.h> |
26 | #include <log/logger.h> | 26 | #include <log/logger.h> |
27 | 27 | ||
28 | #include "log_cdefs.h" | 28 | #include "log_portability.h" |
29 | 29 | ||
30 | #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t)) | 30 | #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t)) |
31 | 31 | ||
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c index 3535b94c1..b9827a16d 100644 --- a/liblog/log_event_write.c +++ b/liblog/log_event_write.c | |||
@@ -18,7 +18,7 @@ | |||
18 | 18 | ||
19 | #include <log/log.h> | 19 | #include <log/log.h> |
20 | 20 | ||
21 | #include "log_cdefs.h" | 21 | #include "log_portability.h" |
22 | 22 | ||
23 | #define MAX_SUBTAG_LEN 32 | 23 | #define MAX_SUBTAG_LEN 32 |
24 | 24 | ||
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c index 47fde204e..551fa7684 100644 --- a/liblog/log_is_loggable.c +++ b/liblog/log_is_loggable.c | |||
@@ -23,7 +23,7 @@ | |||
23 | 23 | ||
24 | #include <android/log.h> | 24 | #include <android/log.h> |
25 | 25 | ||
26 | #include "log_cdefs.h" | 26 | #include "log_portability.h" |
27 | 27 | ||
28 | static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER; | 28 | static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER; |
29 | 29 | ||
diff --git a/liblog/log_cdefs.h b/liblog/log_portability.h index 3a526256e..3ad20601e 100644 --- a/liblog/log_cdefs.h +++ b/liblog/log_portability.h | |||
@@ -14,10 +14,13 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #ifndef _LIBLOG_CDEFS_H__ | 17 | #ifndef _LIBLOG_PORTABILITY_H__ |
18 | #define _LIBLOG_CDEFS_H__ | 18 | #define _LIBLOG_PORTABILITY_H__ |
19 | 19 | ||
20 | #include <sys/cdefs.h> | 20 | #include <sys/cdefs.h> |
21 | #include <unistd.h> | ||
22 | |||
23 | /* Helpful private sys/cdefs.h like definitions */ | ||
21 | 24 | ||
22 | /* Declare this library function hidden and internal */ | 25 | /* Declare this library function hidden and internal */ |
23 | #if defined(_WIN32) | 26 | #if defined(_WIN32) |
@@ -46,9 +49,34 @@ | |||
46 | #define LIBLOG_WEAK __attribute__((weak,visibility("default"))) | 49 | #define LIBLOG_WEAK __attribute__((weak,visibility("default"))) |
47 | #endif | 50 | #endif |
48 | 51 | ||
52 | /* possible missing definitions in sys/cdefs.h */ | ||
53 | |||
54 | /* DECLS */ | ||
55 | #ifndef __BEGIN_DECLS | ||
56 | #if defined(__cplusplus) | ||
57 | #define __BEGIN_DECLS extern "C" { | ||
58 | #define __END_DECLS } | ||
59 | #else | ||
60 | #define __BEGIN_DECLS | ||
61 | #define __END_DECLS | ||
62 | #endif | ||
63 | #endif | ||
64 | |||
49 | /* Unused argument. For C code only, remove symbol name for C++ */ | 65 | /* Unused argument. For C code only, remove symbol name for C++ */ |
50 | #ifndef __unused | 66 | #ifndef __unused |
51 | #define __unused __attribute__((__unused__)) | 67 | #define __unused __attribute__((__unused__)) |
52 | #endif | 68 | #endif |
53 | 69 | ||
54 | #endif /* _LIBLOG_CDEFS_H__ */ | 70 | /* possible missing definitions in unistd.h */ |
71 | |||
72 | #ifndef TEMP_FAILURE_RETRY | ||
73 | /* Used to retry syscalls that can return EINTR. */ | ||
74 | #define TEMP_FAILURE_RETRY(exp) ({ \ | ||
75 | __typeof__(exp) _rc; \ | ||
76 | do { \ | ||
77 | _rc = (exp); \ | ||
78 | } while (_rc == -1 && errno == EINTR); \ | ||
79 | _rc; }) | ||
80 | #endif | ||
81 | |||
82 | #endif /* _LIBLOG_PORTABILITY_H__ */ | ||
diff --git a/liblog/log_read.c b/liblog/log_read.c deleted file mode 100644 index 4b839443d..000000000 --- a/liblog/log_read.c +++ /dev/null | |||
@@ -1,917 +0,0 @@ | |||
1 | /* | ||
2 | ** Copyright 2013-2014, 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 <fcntl.h> | ||
19 | #include <inttypes.h> | ||
20 | #include <poll.h> | ||
21 | #include <signal.h> | ||
22 | #include <stdbool.h> | ||
23 | #include <stddef.h> | ||
24 | #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */ | ||
25 | #include <stdlib.h> | ||
26 | #include <string.h> | ||
27 | #include <unistd.h> | ||
28 | |||
29 | #include <cutils/list.h> | ||
30 | #include <cutils/sockets.h> | ||
31 | #include <log/log.h> | ||
32 | #include <log/logger.h> | ||
33 | #include <private/android_filesystem_config.h> | ||
34 | #include <private/android_logger.h> | ||
35 | |||
36 | #include "log_cdefs.h" | ||
37 | |||
38 | /* branchless on many architectures. */ | ||
39 | #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) | ||
40 | |||
41 | /* Private copy of ../libcutils/socket_local_client.c prevent library loops */ | ||
42 | |||
43 | #if defined(_WIN32) | ||
44 | |||
45 | LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type) | ||
46 | { | ||
47 | errno = ENOSYS; | ||
48 | return -ENOSYS; | ||
49 | } | ||
50 | |||
51 | #else /* !_WIN32 */ | ||
52 | |||
53 | #include <sys/socket.h> | ||
54 | #include <sys/un.h> | ||
55 | #include <sys/select.h> | ||
56 | #include <sys/types.h> | ||
57 | |||
58 | /* Private copy of ../libcutils/socket_local.h prevent library loops */ | ||
59 | #define FILESYSTEM_SOCKET_PREFIX "/tmp/" | ||
60 | #define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" | ||
61 | /* End of ../libcutils/socket_local.h */ | ||
62 | |||
63 | #define LISTEN_BACKLOG 4 | ||
64 | |||
65 | /* Documented in header file. */ | ||
66 | LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId, | ||
67 | struct sockaddr_un *p_addr, | ||
68 | socklen_t *alen) | ||
69 | { | ||
70 | memset (p_addr, 0, sizeof (*p_addr)); | ||
71 | size_t namelen; | ||
72 | |||
73 | switch (namespaceId) { | ||
74 | case ANDROID_SOCKET_NAMESPACE_ABSTRACT: | ||
75 | #if defined(__linux__) | ||
76 | namelen = strlen(name); | ||
77 | |||
78 | /* Test with length +1 for the *initial* '\0'. */ | ||
79 | if ((namelen + 1) > sizeof(p_addr->sun_path)) { | ||
80 | goto error; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Note: The path in this case is *not* supposed to be | ||
85 | * '\0'-terminated. ("man 7 unix" for the gory details.) | ||
86 | */ | ||
87 | |||
88 | p_addr->sun_path[0] = 0; | ||
89 | memcpy(p_addr->sun_path + 1, name, namelen); | ||
90 | #else | ||
91 | /* this OS doesn't have the Linux abstract namespace */ | ||
92 | |||
93 | namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); | ||
94 | /* unix_path_max appears to be missing on linux */ | ||
95 | if (namelen > sizeof(*p_addr) | ||
96 | - offsetof(struct sockaddr_un, sun_path) - 1) { | ||
97 | goto error; | ||
98 | } | ||
99 | |||
100 | strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); | ||
101 | strcat(p_addr->sun_path, name); | ||
102 | #endif | ||
103 | break; | ||
104 | |||
105 | case ANDROID_SOCKET_NAMESPACE_RESERVED: | ||
106 | namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); | ||
107 | /* unix_path_max appears to be missing on linux */ | ||
108 | if (namelen > sizeof(*p_addr) | ||
109 | - offsetof(struct sockaddr_un, sun_path) - 1) { | ||
110 | goto error; | ||
111 | } | ||
112 | |||
113 | strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); | ||
114 | strcat(p_addr->sun_path, name); | ||
115 | break; | ||
116 | |||
117 | case ANDROID_SOCKET_NAMESPACE_FILESYSTEM: | ||
118 | namelen = strlen(name); | ||
119 | /* unix_path_max appears to be missing on linux */ | ||
120 | if (namelen > sizeof(*p_addr) | ||
121 | - offsetof(struct sockaddr_un, sun_path) - 1) { | ||
122 | goto error; | ||
123 | } | ||
124 | |||
125 | strcpy(p_addr->sun_path, name); | ||
126 | break; | ||
127 | |||
128 | default: | ||
129 | /* invalid namespace id */ | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | p_addr->sun_family = AF_LOCAL; | ||
134 | *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; | ||
135 | return 0; | ||
136 | error: | ||
137 | return -1; | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * connect to peer named "name" on fd | ||
142 | * returns same fd or -1 on error. | ||
143 | * fd is not closed on error. that's your job. | ||
144 | * | ||
145 | * Used by AndroidSocketImpl | ||
146 | */ | ||
147 | LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name, | ||
148 | int namespaceId, int type __unused) | ||
149 | { | ||
150 | struct sockaddr_un addr; | ||
151 | socklen_t alen; | ||
152 | int err; | ||
153 | |||
154 | err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen); | ||
155 | |||
156 | if (err < 0) { | ||
157 | goto error; | ||
158 | } | ||
159 | |||
160 | if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { | ||
161 | goto error; | ||
162 | } | ||
163 | |||
164 | return fd; | ||
165 | |||
166 | error: | ||
167 | return -1; | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * connect to peer named "name" | ||
172 | * returns fd or -1 on error | ||
173 | */ | ||
174 | LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type) | ||
175 | { | ||
176 | int s; | ||
177 | |||
178 | s = socket(AF_LOCAL, type, 0); | ||
179 | if(s < 0) return -1; | ||
180 | |||
181 | if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) { | ||
182 | close(s); | ||
183 | return -1; | ||
184 | } | ||
185 | |||
186 | return s; | ||
187 | } | ||
188 | |||
189 | #endif /* !_WIN32 */ | ||
190 | /* End of ../libcutils/socket_local_client.c */ | ||
191 | |||
192 | #define logger_for_each(logger, logger_list) \ | ||
193 | for (logger = node_to_item((logger_list)->node.next, struct logger, node); \ | ||
194 | logger != node_to_item(&(logger_list)->node, struct logger, node); \ | ||
195 | logger = node_to_item((logger)->node.next, struct logger, node)) | ||
196 | |||
197 | /* In the future, we would like to make this list extensible */ | ||
198 | static const char *LOG_NAME[LOG_ID_MAX] = { | ||
199 | [LOG_ID_MAIN] = "main", | ||
200 | [LOG_ID_RADIO] = "radio", | ||
201 | [LOG_ID_EVENTS] = "events", | ||
202 | [LOG_ID_SYSTEM] = "system", | ||
203 | [LOG_ID_CRASH] = "crash", | ||
204 | [LOG_ID_SECURITY] = "security", | ||
205 | [LOG_ID_KERNEL] = "kernel", | ||
206 | }; | ||
207 | |||
208 | LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id) | ||
209 | { | ||
210 | if (log_id >= LOG_ID_MAX) { | ||
211 | log_id = LOG_ID_MAIN; | ||
212 | } | ||
213 | return LOG_NAME[log_id]; | ||
214 | } | ||
215 | |||
216 | LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName) | ||
217 | { | ||
218 | const char *b; | ||
219 | int ret; | ||
220 | |||
221 | if (!logName) { | ||
222 | return -1; /* NB: log_id_t is unsigned */ | ||
223 | } | ||
224 | b = strrchr(logName, '/'); | ||
225 | if (!b) { | ||
226 | b = logName; | ||
227 | } else { | ||
228 | ++b; | ||
229 | } | ||
230 | |||
231 | for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) { | ||
232 | const char *l = LOG_NAME[ret]; | ||
233 | if (l && !strcmp(b, l)) { | ||
234 | return ret; | ||
235 | } | ||
236 | } | ||
237 | return -1; /* should never happen */ | ||
238 | } | ||
239 | |||
240 | struct logger_list { | ||
241 | struct listnode node; | ||
242 | int mode; | ||
243 | unsigned int tail; | ||
244 | log_time start; | ||
245 | pid_t pid; | ||
246 | int sock; | ||
247 | }; | ||
248 | |||
249 | struct logger { | ||
250 | struct listnode node; | ||
251 | struct logger_list *top; | ||
252 | log_id_t id; | ||
253 | }; | ||
254 | |||
255 | /* android_logger_alloc unimplemented, no use case */ | ||
256 | /* android_logger_free not exported */ | ||
257 | static void android_logger_free(struct logger *logger) | ||
258 | { | ||
259 | if (!logger) { | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | list_remove(&logger->node); | ||
264 | |||
265 | free(logger); | ||
266 | } | ||
267 | |||
268 | /* android_logger_alloc unimplemented, no use case */ | ||
269 | |||
270 | /* method for getting the associated sublog id */ | ||
271 | LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger) | ||
272 | { | ||
273 | return logger->id; | ||
274 | } | ||
275 | |||
276 | /* worker for sending the command to the logger */ | ||
277 | static ssize_t send_log_msg(struct logger *logger, | ||
278 | const char *msg, char *buf, size_t buf_size) | ||
279 | { | ||
280 | ssize_t ret; | ||
281 | size_t len; | ||
282 | char *cp; | ||
283 | int errno_save = 0; | ||
284 | int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, | ||
285 | SOCK_STREAM); | ||
286 | if (sock < 0) { | ||
287 | return sock; | ||
288 | } | ||
289 | |||
290 | if (msg) { | ||
291 | snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1); | ||
292 | } | ||
293 | |||
294 | len = strlen(buf) + 1; | ||
295 | ret = TEMP_FAILURE_RETRY(write(sock, buf, len)); | ||
296 | if (ret <= 0) { | ||
297 | goto done; | ||
298 | } | ||
299 | |||
300 | len = buf_size; | ||
301 | cp = buf; | ||
302 | while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) { | ||
303 | struct pollfd p; | ||
304 | |||
305 | if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) { | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | len -= ret; | ||
310 | cp += ret; | ||
311 | |||
312 | memset(&p, 0, sizeof(p)); | ||
313 | p.fd = sock; | ||
314 | p.events = POLLIN; | ||
315 | |||
316 | /* Give other side 20ms to refill pipe */ | ||
317 | ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20)); | ||
318 | |||
319 | if (ret <= 0) { | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | if (!(p.revents & POLLIN)) { | ||
324 | ret = 0; | ||
325 | break; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | if (ret >= 0) { | ||
330 | ret += buf_size - len; | ||
331 | } | ||
332 | |||
333 | done: | ||
334 | if ((ret == -1) && errno) { | ||
335 | errno_save = errno; | ||
336 | } | ||
337 | close(sock); | ||
338 | if (errno_save) { | ||
339 | errno = errno_save; | ||
340 | } | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | static int check_log_success(char *buf, ssize_t ret) | ||
345 | { | ||
346 | if (ret < 0) { | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | if (strncmp(buf, "success", 7)) { | ||
351 | errno = EINVAL; | ||
352 | return -1; | ||
353 | } | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | /* Determine the credentials of the caller */ | ||
359 | static bool uid_has_log_permission(uid_t uid) | ||
360 | { | ||
361 | return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT); | ||
362 | } | ||
363 | |||
364 | static uid_t get_best_effective_uid() | ||
365 | { | ||
366 | uid_t euid; | ||
367 | uid_t uid; | ||
368 | gid_t gid; | ||
369 | ssize_t i; | ||
370 | static uid_t last_uid = (uid_t) -1; | ||
371 | |||
372 | if (last_uid != (uid_t) -1) { | ||
373 | return last_uid; | ||
374 | } | ||
375 | uid = getuid(); | ||
376 | if (uid_has_log_permission(uid)) { | ||
377 | return last_uid = uid; | ||
378 | } | ||
379 | euid = geteuid(); | ||
380 | if (uid_has_log_permission(euid)) { | ||
381 | return last_uid = euid; | ||
382 | } | ||
383 | gid = getgid(); | ||
384 | if (uid_has_log_permission(gid)) { | ||
385 | return last_uid = gid; | ||
386 | } | ||
387 | gid = getegid(); | ||
388 | if (uid_has_log_permission(gid)) { | ||
389 | return last_uid = gid; | ||
390 | } | ||
391 | i = getgroups((size_t) 0, NULL); | ||
392 | if (i > 0) { | ||
393 | gid_t list[i]; | ||
394 | |||
395 | getgroups(i, list); | ||
396 | while (--i >= 0) { | ||
397 | if (uid_has_log_permission(list[i])) { | ||
398 | return last_uid = list[i]; | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | return last_uid = uid; | ||
403 | } | ||
404 | |||
405 | LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger) | ||
406 | { | ||
407 | char buf[512]; | ||
408 | |||
409 | if (logger->top->mode & ANDROID_LOG_PSTORE) { | ||
410 | if (uid_has_log_permission(get_best_effective_uid())) { | ||
411 | return unlink("/sys/fs/pstore/pmsg-ramoops-0"); | ||
412 | } | ||
413 | errno = EPERM; | ||
414 | return -1; | ||
415 | } | ||
416 | return check_log_success(buf, | ||
417 | send_log_msg(logger, "clear %d", buf, sizeof(buf))); | ||
418 | } | ||
419 | |||
420 | /* returns the total size of the log's ring buffer */ | ||
421 | LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger) | ||
422 | { | ||
423 | char buf[512]; | ||
424 | |||
425 | ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf)); | ||
426 | if (ret < 0) { | ||
427 | return ret; | ||
428 | } | ||
429 | |||
430 | if ((buf[0] < '0') || ('9' < buf[0])) { | ||
431 | return -1; | ||
432 | } | ||
433 | |||
434 | return atol(buf); | ||
435 | } | ||
436 | |||
437 | LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger, | ||
438 | unsigned long size) | ||
439 | { | ||
440 | char buf[512]; | ||
441 | |||
442 | snprintf(buf, sizeof(buf), "setLogSize %d %lu", | ||
443 | logger ? logger->id : (unsigned) -1, size); | ||
444 | |||
445 | return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf))); | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * returns the readable size of the log's ring buffer (that is, amount of the | ||
450 | * log consumed) | ||
451 | */ | ||
452 | LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size( | ||
453 | struct logger *logger) | ||
454 | { | ||
455 | char buf[512]; | ||
456 | |||
457 | ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf)); | ||
458 | if (ret < 0) { | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | if ((buf[0] < '0') || ('9' < buf[0])) { | ||
463 | return -1; | ||
464 | } | ||
465 | |||
466 | return atol(buf); | ||
467 | } | ||
468 | |||
469 | /* | ||
470 | * returns the logger version | ||
471 | */ | ||
472 | LIBLOG_ABI_PUBLIC int android_logger_get_log_version( | ||
473 | struct logger *logger __unused) | ||
474 | { | ||
475 | return 4; | ||
476 | } | ||
477 | |||
478 | /* | ||
479 | * returns statistics | ||
480 | */ | ||
481 | LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics( | ||
482 | struct logger_list *logger_list, | ||
483 | char *buf, size_t len) | ||
484 | { | ||
485 | struct logger *logger; | ||
486 | char *cp = buf; | ||
487 | size_t remaining = len; | ||
488 | size_t n; | ||
489 | |||
490 | n = snprintf(cp, remaining, "getStatistics"); | ||
491 | n = min(n, remaining); | ||
492 | remaining -= n; | ||
493 | cp += n; | ||
494 | |||
495 | logger_for_each(logger, logger_list) { | ||
496 | n = snprintf(cp, remaining, " %d", logger->id); | ||
497 | n = min(n, remaining); | ||
498 | remaining -= n; | ||
499 | cp += n; | ||
500 | } | ||
501 | |||
502 | if (logger_list->pid) { | ||
503 | snprintf(cp, remaining, " pid=%u", logger_list->pid); | ||
504 | } | ||
505 | |||
506 | return send_log_msg(NULL, NULL, buf, len); | ||
507 | } | ||
508 | |||
509 | LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list( | ||
510 | struct logger_list *logger_list __unused, | ||
511 | char *buf, size_t len) | ||
512 | { | ||
513 | return send_log_msg(NULL, "getPruneList", buf, len); | ||
514 | } | ||
515 | |||
516 | LIBLOG_ABI_PUBLIC int android_logger_set_prune_list( | ||
517 | struct logger_list *logger_list __unused, | ||
518 | char *buf, size_t len) | ||
519 | { | ||
520 | const char cmd[] = "setPruneList "; | ||
521 | const size_t cmdlen = sizeof(cmd) - 1; | ||
522 | |||
523 | if (strlen(buf) > (len - cmdlen)) { | ||
524 | return -ENOMEM; /* KISS */ | ||
525 | } | ||
526 | memmove(buf + cmdlen, buf, len - cmdlen); | ||
527 | buf[len - 1] = '\0'; | ||
528 | memcpy(buf, cmd, cmdlen); | ||
529 | |||
530 | return check_log_success(buf, send_log_msg(NULL, NULL, buf, len)); | ||
531 | } | ||
532 | |||
533 | LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc( | ||
534 | int mode, | ||
535 | unsigned int tail, | ||
536 | pid_t pid) | ||
537 | { | ||
538 | struct logger_list *logger_list; | ||
539 | |||
540 | logger_list = calloc(1, sizeof(*logger_list)); | ||
541 | if (!logger_list) { | ||
542 | return NULL; | ||
543 | } | ||
544 | |||
545 | list_init(&logger_list->node); | ||
546 | logger_list->mode = mode; | ||
547 | logger_list->start.tv_sec = 0; | ||
548 | logger_list->start.tv_nsec = 0; | ||
549 | logger_list->tail = tail; | ||
550 | logger_list->pid = pid; | ||
551 | logger_list->sock = -1; | ||
552 | |||
553 | return logger_list; | ||
554 | } | ||
555 | |||
556 | LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time( | ||
557 | int mode, | ||
558 | log_time start, | ||
559 | pid_t pid) | ||
560 | { | ||
561 | struct logger_list *logger_list; | ||
562 | |||
563 | logger_list = calloc(1, sizeof(*logger_list)); | ||
564 | if (!logger_list) { | ||
565 | return NULL; | ||
566 | } | ||
567 | |||
568 | list_init(&logger_list->node); | ||
569 | logger_list->mode = mode; | ||
570 | logger_list->start = start; | ||
571 | logger_list->tail = 0; | ||
572 | logger_list->pid = pid; | ||
573 | logger_list->sock = -1; | ||
574 | |||
575 | return logger_list; | ||
576 | } | ||
577 | |||
578 | /* android_logger_list_register unimplemented, no use case */ | ||
579 | /* android_logger_list_unregister unimplemented, no use case */ | ||
580 | |||
581 | /* Open the named log and add it to the logger list */ | ||
582 | LIBLOG_ABI_PUBLIC struct logger *android_logger_open( | ||
583 | struct logger_list *logger_list, | ||
584 | log_id_t id) | ||
585 | { | ||
586 | struct logger *logger; | ||
587 | |||
588 | if (!logger_list || (id >= LOG_ID_MAX)) { | ||
589 | goto err; | ||
590 | } | ||
591 | |||
592 | logger_for_each(logger, logger_list) { | ||
593 | if (logger->id == id) { | ||
594 | goto ok; | ||
595 | } | ||
596 | } | ||
597 | |||
598 | logger = calloc(1, sizeof(*logger)); | ||
599 | if (!logger) { | ||
600 | goto err; | ||
601 | } | ||
602 | |||
603 | logger->id = id; | ||
604 | list_add_tail(&logger_list->node, &logger->node); | ||
605 | logger->top = logger_list; | ||
606 | goto ok; | ||
607 | |||
608 | err: | ||
609 | logger = NULL; | ||
610 | ok: | ||
611 | return logger; | ||
612 | } | ||
613 | |||
614 | /* Open the single named log and make it part of a new logger list */ | ||
615 | LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open( | ||
616 | log_id_t id, | ||
617 | int mode, | ||
618 | unsigned int tail, | ||
619 | pid_t pid) | ||
620 | { | ||
621 | struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid); | ||
622 | if (!logger_list) { | ||
623 | return NULL; | ||
624 | } | ||
625 | |||
626 | if (!android_logger_open(logger_list, id)) { | ||
627 | android_logger_list_free(logger_list); | ||
628 | return NULL; | ||
629 | } | ||
630 | |||
631 | return logger_list; | ||
632 | } | ||
633 | |||
634 | static int android_logger_list_read_pstore(struct logger_list *logger_list, | ||
635 | struct log_msg *log_msg) | ||
636 | { | ||
637 | ssize_t ret; | ||
638 | off_t current, next; | ||
639 | uid_t uid; | ||
640 | struct logger *logger; | ||
641 | struct __attribute__((__packed__)) { | ||
642 | android_pmsg_log_header_t p; | ||
643 | android_log_header_t l; | ||
644 | } buf; | ||
645 | static uint8_t preread_count; | ||
646 | bool is_system; | ||
647 | |||
648 | memset(log_msg, 0, sizeof(*log_msg)); | ||
649 | |||
650 | if (logger_list->sock < 0) { | ||
651 | int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); | ||
652 | |||
653 | if (fd < 0) { | ||
654 | return -errno; | ||
655 | } | ||
656 | logger_list->sock = fd; | ||
657 | preread_count = 0; | ||
658 | } | ||
659 | |||
660 | while(1) { | ||
661 | if (preread_count < sizeof(buf)) { | ||
662 | ret = TEMP_FAILURE_RETRY(read(logger_list->sock, | ||
663 | &buf.p.magic + preread_count, | ||
664 | sizeof(buf) - preread_count)); | ||
665 | if (ret < 0) { | ||
666 | return -errno; | ||
667 | } | ||
668 | preread_count += ret; | ||
669 | } | ||
670 | if (preread_count != sizeof(buf)) { | ||
671 | return preread_count ? -EIO : -EAGAIN; | ||
672 | } | ||
673 | if ((buf.p.magic != LOGGER_MAGIC) | ||
674 | || (buf.p.len <= sizeof(buf)) | ||
675 | || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) | ||
676 | || (buf.l.id >= LOG_ID_MAX) | ||
677 | || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) { | ||
678 | do { | ||
679 | memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count); | ||
680 | } while (preread_count && (buf.p.magic != LOGGER_MAGIC)); | ||
681 | continue; | ||
682 | } | ||
683 | preread_count = 0; | ||
684 | |||
685 | logger_for_each(logger, logger_list) { | ||
686 | if (buf.l.id != logger->id) { | ||
687 | continue; | ||
688 | } | ||
689 | |||
690 | if ((logger_list->start.tv_sec || logger_list->start.tv_nsec) | ||
691 | && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec) | ||
692 | || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec) | ||
693 | && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) { | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | if (logger_list->pid && (logger_list->pid != buf.p.pid)) { | ||
698 | break; | ||
699 | } | ||
700 | |||
701 | uid = get_best_effective_uid(); | ||
702 | is_system = uid_has_log_permission(uid); | ||
703 | if (!is_system && (uid != buf.p.uid)) { | ||
704 | break; | ||
705 | } | ||
706 | |||
707 | ret = TEMP_FAILURE_RETRY(read(logger_list->sock, | ||
708 | is_system ? | ||
709 | log_msg->entry_v4.msg : | ||
710 | log_msg->entry_v3.msg, | ||
711 | buf.p.len - sizeof(buf))); | ||
712 | if (ret < 0) { | ||
713 | return -errno; | ||
714 | } | ||
715 | if (ret != (ssize_t)(buf.p.len - sizeof(buf))) { | ||
716 | return -EIO; | ||
717 | } | ||
718 | |||
719 | log_msg->entry_v4.len = buf.p.len - sizeof(buf); | ||
720 | log_msg->entry_v4.hdr_size = is_system ? | ||
721 | sizeof(log_msg->entry_v4) : | ||
722 | sizeof(log_msg->entry_v3); | ||
723 | log_msg->entry_v4.pid = buf.p.pid; | ||
724 | log_msg->entry_v4.tid = buf.l.tid; | ||
725 | log_msg->entry_v4.sec = buf.l.realtime.tv_sec; | ||
726 | log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec; | ||
727 | log_msg->entry_v4.lid = buf.l.id; | ||
728 | if (is_system) { | ||
729 | log_msg->entry_v4.uid = buf.p.uid; | ||
730 | } | ||
731 | |||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | current = TEMP_FAILURE_RETRY(lseek(logger_list->sock, | ||
736 | (off_t)0, SEEK_CUR)); | ||
737 | if (current < 0) { | ||
738 | return -errno; | ||
739 | } | ||
740 | next = TEMP_FAILURE_RETRY(lseek(logger_list->sock, | ||
741 | (off_t)(buf.p.len - sizeof(buf)), | ||
742 | SEEK_CUR)); | ||
743 | if (next < 0) { | ||
744 | return -errno; | ||
745 | } | ||
746 | if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) { | ||
747 | return -EIO; | ||
748 | } | ||
749 | } | ||
750 | } | ||
751 | |||
752 | static void caught_signal(int signum __unused) | ||
753 | { | ||
754 | } | ||
755 | |||
756 | /* Read from the selected logs */ | ||
757 | LIBLOG_ABI_PUBLIC int android_logger_list_read( | ||
758 | struct logger_list *logger_list, | ||
759 | struct log_msg *log_msg) | ||
760 | { | ||
761 | int ret, e; | ||
762 | struct logger *logger; | ||
763 | struct sigaction ignore; | ||
764 | struct sigaction old_sigaction; | ||
765 | unsigned int old_alarm = 0; | ||
766 | |||
767 | if (!logger_list) { | ||
768 | return -EINVAL; | ||
769 | } | ||
770 | |||
771 | if (logger_list->mode & ANDROID_LOG_PSTORE) { | ||
772 | return android_logger_list_read_pstore(logger_list, log_msg); | ||
773 | } | ||
774 | |||
775 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
776 | memset(&ignore, 0, sizeof(ignore)); | ||
777 | ignore.sa_handler = caught_signal; | ||
778 | sigemptyset(&ignore.sa_mask); | ||
779 | } | ||
780 | |||
781 | if (logger_list->sock < 0) { | ||
782 | char buffer[256], *cp, c; | ||
783 | |||
784 | int sock = socket_local_client("logdr", | ||
785 | ANDROID_SOCKET_NAMESPACE_RESERVED, | ||
786 | SOCK_SEQPACKET); | ||
787 | if (sock < 0) { | ||
788 | if ((sock == -1) && errno) { | ||
789 | return -errno; | ||
790 | } | ||
791 | return sock; | ||
792 | } | ||
793 | |||
794 | strcpy(buffer, | ||
795 | (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream"); | ||
796 | cp = buffer + strlen(buffer); | ||
797 | |||
798 | strcpy(cp, " lids"); | ||
799 | cp += 5; | ||
800 | c = '='; | ||
801 | int remaining = sizeof(buffer) - (cp - buffer); | ||
802 | logger_for_each(logger, logger_list) { | ||
803 | ret = snprintf(cp, remaining, "%c%u", c, logger->id); | ||
804 | ret = min(ret, remaining); | ||
805 | remaining -= ret; | ||
806 | cp += ret; | ||
807 | c = ','; | ||
808 | } | ||
809 | |||
810 | if (logger_list->tail) { | ||
811 | ret = snprintf(cp, remaining, " tail=%u", logger_list->tail); | ||
812 | ret = min(ret, remaining); | ||
813 | remaining -= ret; | ||
814 | cp += ret; | ||
815 | } | ||
816 | |||
817 | if (logger_list->start.tv_sec || logger_list->start.tv_nsec) { | ||
818 | if (logger_list->mode & ANDROID_LOG_WRAP) { | ||
819 | // ToDo: alternate API to allow timeout to be adjusted. | ||
820 | ret = snprintf(cp, remaining, " timeout=%u", | ||
821 | ANDROID_LOG_WRAP_DEFAULT_TIMEOUT); | ||
822 | ret = min(ret, remaining); | ||
823 | remaining -= ret; | ||
824 | cp += ret; | ||
825 | } | ||
826 | ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, | ||
827 | logger_list->start.tv_sec, | ||
828 | logger_list->start.tv_nsec); | ||
829 | ret = min(ret, remaining); | ||
830 | remaining -= ret; | ||
831 | cp += ret; | ||
832 | } | ||
833 | |||
834 | if (logger_list->pid) { | ||
835 | ret = snprintf(cp, remaining, " pid=%u", logger_list->pid); | ||
836 | ret = min(ret, remaining); | ||
837 | cp += ret; | ||
838 | } | ||
839 | |||
840 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
841 | /* Deal with an unresponsive logd */ | ||
842 | sigaction(SIGALRM, &ignore, &old_sigaction); | ||
843 | old_alarm = alarm(30); | ||
844 | } | ||
845 | ret = write(sock, buffer, cp - buffer); | ||
846 | e = errno; | ||
847 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
848 | if (e == EINTR) { | ||
849 | e = ETIMEDOUT; | ||
850 | } | ||
851 | alarm(old_alarm); | ||
852 | sigaction(SIGALRM, &old_sigaction, NULL); | ||
853 | } | ||
854 | |||
855 | if (ret <= 0) { | ||
856 | close(sock); | ||
857 | if ((ret == -1) && e) { | ||
858 | return -e; | ||
859 | } | ||
860 | if (ret == 0) { | ||
861 | return -EIO; | ||
862 | } | ||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | logger_list->sock = sock; | ||
867 | } | ||
868 | |||
869 | while(1) { | ||
870 | memset(log_msg, 0, sizeof(*log_msg)); | ||
871 | |||
872 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
873 | /* particularily useful if tombstone is reporting for logd */ | ||
874 | sigaction(SIGALRM, &ignore, &old_sigaction); | ||
875 | old_alarm = alarm(30); | ||
876 | } | ||
877 | /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */ | ||
878 | ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0); | ||
879 | e = errno; | ||
880 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
881 | if ((ret == 0) || (e == EINTR)) { | ||
882 | e = EAGAIN; | ||
883 | ret = -1; | ||
884 | } | ||
885 | alarm(old_alarm); | ||
886 | sigaction(SIGALRM, &old_sigaction, NULL); | ||
887 | } | ||
888 | |||
889 | if ((ret == -1) && e) { | ||
890 | return -e; | ||
891 | } | ||
892 | return ret; | ||
893 | } | ||
894 | /* NOTREACH */ | ||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | /* Close all the logs */ | ||
899 | LIBLOG_ABI_PUBLIC void android_logger_list_free( | ||
900 | struct logger_list *logger_list) | ||
901 | { | ||
902 | if (logger_list == NULL) { | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | while (!list_empty(&logger_list->node)) { | ||
907 | struct listnode *node = list_head(&logger_list->node); | ||
908 | struct logger *logger = node_to_item(node, struct logger, node); | ||
909 | android_logger_free(logger); | ||
910 | } | ||
911 | |||
912 | if (logger_list->sock >= 0) { | ||
913 | close (logger_list->sock); | ||
914 | } | ||
915 | |||
916 | free(logger_list); | ||
917 | } | ||
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp index b6af2221c..d2bf18166 100644 --- a/liblog/log_time.cpp +++ b/liblog/log_time.cpp | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | #include <log/log_read.h> | 22 | #include <log/log_read.h> |
23 | 23 | ||
24 | #include "log_cdefs.h" | 24 | #include "log_portability.h" |
25 | 25 | ||
26 | LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q"; | 26 | LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q"; |
27 | LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 }; | 27 | LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 }; |
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c new file mode 100644 index 000000000..d8441040c --- /dev/null +++ b/liblog/logd_reader.c | |||
@@ -0,0 +1,670 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2016 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 <endian.h> | ||
18 | #include <errno.h> | ||
19 | #include <fcntl.h> | ||
20 | #include <inttypes.h> | ||
21 | #include <poll.h> | ||
22 | #include <stdarg.h> | ||
23 | #include <stdatomic.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <string.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/socket.h> | ||
30 | #include <sys/un.h> | ||
31 | #include <time.h> | ||
32 | #include <unistd.h> | ||
33 | |||
34 | #include <cutils/sockets.h> | ||
35 | #include <log/logd.h> | ||
36 | #include <log/logger.h> | ||
37 | #include <log/log_read.h> | ||
38 | #include <private/android_filesystem_config.h> | ||
39 | #include <private/android_logger.h> | ||
40 | |||
41 | #include "config_read.h" | ||
42 | #include "log_portability.h" | ||
43 | #include "logger.h" | ||
44 | |||
45 | /* branchless on many architectures. */ | ||
46 | #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) | ||
47 | |||
48 | static int logdAvailable(log_id_t LogId); | ||
49 | static int logdVersion(struct android_log_logger *logger, | ||
50 | struct android_log_transport_context *transp); | ||
51 | static int logdRead(struct android_log_logger_list *logger_list, | ||
52 | struct android_log_transport_context *transp, | ||
53 | struct log_msg *log_msg); | ||
54 | static int logdPoll(struct android_log_logger_list *logger_list, | ||
55 | struct android_log_transport_context *transp); | ||
56 | static void logdClose(struct android_log_logger_list *logger_list, | ||
57 | struct android_log_transport_context *transp); | ||
58 | static int logdClear(struct android_log_logger *logger, | ||
59 | struct android_log_transport_context *transp); | ||
60 | static ssize_t logdSetSize(struct android_log_logger *logger, | ||
61 | struct android_log_transport_context *transp, | ||
62 | size_t size); | ||
63 | static ssize_t logdGetSize(struct android_log_logger *logger, | ||
64 | struct android_log_transport_context *transp); | ||
65 | static ssize_t logdGetReadableSize(struct android_log_logger *logger, | ||
66 | struct android_log_transport_context *transp); | ||
67 | static ssize_t logdGetPrune(struct android_log_logger_list *logger, | ||
68 | struct android_log_transport_context *transp, | ||
69 | char *buf, size_t len); | ||
70 | static ssize_t logdSetPrune(struct android_log_logger_list *logger, | ||
71 | struct android_log_transport_context *transp, | ||
72 | char *buf, size_t len); | ||
73 | static ssize_t logdGetStats(struct android_log_logger_list *logger, | ||
74 | struct android_log_transport_context *transp, | ||
75 | char *buf, size_t len); | ||
76 | |||
77 | LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = { | ||
78 | .node = { &logdLoggerRead.node, &logdLoggerRead.node }, | ||
79 | .name = "logd", | ||
80 | .available = logdAvailable, | ||
81 | .version = logdVersion, | ||
82 | .read = logdRead, | ||
83 | .poll = logdPoll, | ||
84 | .close = logdClose, | ||
85 | .clear = logdClear, | ||
86 | .getSize = logdGetSize, | ||
87 | .setSize = logdSetSize, | ||
88 | .getReadableSize = logdGetSize, | ||
89 | .getPrune = logdGetPrune, | ||
90 | .setPrune = logdSetPrune, | ||
91 | .getStats = logdGetStats, | ||
92 | }; | ||
93 | |||
94 | static int logdAvailable(log_id_t logId) | ||
95 | { | ||
96 | if (logId > LOG_ID_KERNEL) { | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | if (logId == LOG_ID_SECURITY) { | ||
100 | uid_t uid = __android_log_uid(); | ||
101 | if (uid != AID_SYSTEM) { | ||
102 | return -EPERM; | ||
103 | } | ||
104 | } | ||
105 | if (access("/dev/socket/logdw", W_OK) == 0) { | ||
106 | return 0; | ||
107 | } | ||
108 | return -EBADF; | ||
109 | } | ||
110 | |||
111 | /* Private copy of ../libcutils/socket_local_client.c prevent library loops */ | ||
112 | |||
113 | #if defined(_WIN32) | ||
114 | |||
115 | LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type) | ||
116 | { | ||
117 | errno = ENOSYS; | ||
118 | return -ENOSYS; | ||
119 | } | ||
120 | |||
121 | #else /* !_WIN32 */ | ||
122 | |||
123 | #include <sys/socket.h> | ||
124 | #include <sys/un.h> | ||
125 | #include <sys/select.h> | ||
126 | #include <sys/types.h> | ||
127 | |||
128 | /* Private copy of ../libcutils/socket_local.h prevent library loops */ | ||
129 | #define FILESYSTEM_SOCKET_PREFIX "/tmp/" | ||
130 | #define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" | ||
131 | /* End of ../libcutils/socket_local.h */ | ||
132 | |||
133 | #define LISTEN_BACKLOG 4 | ||
134 | |||
135 | /* Documented in header file. */ | ||
136 | LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId, | ||
137 | struct sockaddr_un *p_addr, | ||
138 | socklen_t *alen) | ||
139 | { | ||
140 | memset (p_addr, 0, sizeof (*p_addr)); | ||
141 | size_t namelen; | ||
142 | |||
143 | switch (namespaceId) { | ||
144 | case ANDROID_SOCKET_NAMESPACE_ABSTRACT: | ||
145 | #if defined(__linux__) | ||
146 | namelen = strlen(name); | ||
147 | |||
148 | /* Test with length +1 for the *initial* '\0'. */ | ||
149 | if ((namelen + 1) > sizeof(p_addr->sun_path)) { | ||
150 | goto error; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Note: The path in this case is *not* supposed to be | ||
155 | * '\0'-terminated. ("man 7 unix" for the gory details.) | ||
156 | */ | ||
157 | |||
158 | p_addr->sun_path[0] = 0; | ||
159 | memcpy(p_addr->sun_path + 1, name, namelen); | ||
160 | #else | ||
161 | /* this OS doesn't have the Linux abstract namespace */ | ||
162 | |||
163 | namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); | ||
164 | /* unix_path_max appears to be missing on linux */ | ||
165 | if (namelen > sizeof(*p_addr) | ||
166 | - offsetof(struct sockaddr_un, sun_path) - 1) { | ||
167 | goto error; | ||
168 | } | ||
169 | |||
170 | strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); | ||
171 | strcat(p_addr->sun_path, name); | ||
172 | #endif | ||
173 | break; | ||
174 | |||
175 | case ANDROID_SOCKET_NAMESPACE_RESERVED: | ||
176 | namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); | ||
177 | /* unix_path_max appears to be missing on linux */ | ||
178 | if (namelen > sizeof(*p_addr) | ||
179 | - offsetof(struct sockaddr_un, sun_path) - 1) { | ||
180 | goto error; | ||
181 | } | ||
182 | |||
183 | strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); | ||
184 | strcat(p_addr->sun_path, name); | ||
185 | break; | ||
186 | |||
187 | case ANDROID_SOCKET_NAMESPACE_FILESYSTEM: | ||
188 | namelen = strlen(name); | ||
189 | /* unix_path_max appears to be missing on linux */ | ||
190 | if (namelen > sizeof(*p_addr) | ||
191 | - offsetof(struct sockaddr_un, sun_path) - 1) { | ||
192 | goto error; | ||
193 | } | ||
194 | |||
195 | strcpy(p_addr->sun_path, name); | ||
196 | break; | ||
197 | |||
198 | default: | ||
199 | /* invalid namespace id */ | ||
200 | return -1; | ||
201 | } | ||
202 | |||
203 | p_addr->sun_family = AF_LOCAL; | ||
204 | *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; | ||
205 | return 0; | ||
206 | error: | ||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * connect to peer named "name" on fd | ||
212 | * returns same fd or -1 on error. | ||
213 | * fd is not closed on error. that's your job. | ||
214 | * | ||
215 | * Used by AndroidSocketImpl | ||
216 | */ | ||
217 | LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name, | ||
218 | int namespaceId, int type __unused) | ||
219 | { | ||
220 | struct sockaddr_un addr; | ||
221 | socklen_t alen; | ||
222 | int err; | ||
223 | |||
224 | err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen); | ||
225 | |||
226 | if (err < 0) { | ||
227 | goto error; | ||
228 | } | ||
229 | |||
230 | if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { | ||
231 | goto error; | ||
232 | } | ||
233 | |||
234 | return fd; | ||
235 | |||
236 | error: | ||
237 | return -1; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * connect to peer named "name" | ||
242 | * returns fd or -1 on error | ||
243 | */ | ||
244 | LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type) | ||
245 | { | ||
246 | int s; | ||
247 | |||
248 | s = socket(AF_LOCAL, type, 0); | ||
249 | if(s < 0) return -1; | ||
250 | |||
251 | if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) { | ||
252 | close(s); | ||
253 | return -1; | ||
254 | } | ||
255 | |||
256 | return s; | ||
257 | } | ||
258 | |||
259 | #endif /* !_WIN32 */ | ||
260 | /* End of ../libcutils/socket_local_client.c */ | ||
261 | |||
262 | /* worker for sending the command to the logger */ | ||
263 | static ssize_t send_log_msg(struct android_log_logger *logger, | ||
264 | const char *msg, char *buf, size_t buf_size) | ||
265 | { | ||
266 | ssize_t ret; | ||
267 | size_t len; | ||
268 | char *cp; | ||
269 | int errno_save = 0; | ||
270 | int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, | ||
271 | SOCK_STREAM); | ||
272 | if (sock < 0) { | ||
273 | return sock; | ||
274 | } | ||
275 | |||
276 | if (msg) { | ||
277 | snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned) -1); | ||
278 | } | ||
279 | |||
280 | len = strlen(buf) + 1; | ||
281 | ret = TEMP_FAILURE_RETRY(write(sock, buf, len)); | ||
282 | if (ret <= 0) { | ||
283 | goto done; | ||
284 | } | ||
285 | |||
286 | len = buf_size; | ||
287 | cp = buf; | ||
288 | while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) { | ||
289 | struct pollfd p; | ||
290 | |||
291 | if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) { | ||
292 | break; | ||
293 | } | ||
294 | |||
295 | len -= ret; | ||
296 | cp += ret; | ||
297 | |||
298 | memset(&p, 0, sizeof(p)); | ||
299 | p.fd = sock; | ||
300 | p.events = POLLIN; | ||
301 | |||
302 | /* Give other side 20ms to refill pipe */ | ||
303 | ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20)); | ||
304 | |||
305 | if (ret <= 0) { | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | if (!(p.revents & POLLIN)) { | ||
310 | ret = 0; | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | if (ret >= 0) { | ||
316 | ret += buf_size - len; | ||
317 | } | ||
318 | |||
319 | done: | ||
320 | if ((ret == -1) && errno) { | ||
321 | errno_save = errno; | ||
322 | } | ||
323 | close(sock); | ||
324 | if (errno_save) { | ||
325 | errno = errno_save; | ||
326 | } | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int check_log_success(char *buf, ssize_t ret) | ||
331 | { | ||
332 | if (ret < 0) { | ||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | if (strncmp(buf, "success", 7)) { | ||
337 | errno = EINVAL; | ||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int logdClear(struct android_log_logger *logger, | ||
345 | struct android_log_transport_context *transp __unused) | ||
346 | { | ||
347 | char buf[512]; | ||
348 | |||
349 | return check_log_success(buf, | ||
350 | send_log_msg(logger, "clear %d", buf, sizeof(buf))); | ||
351 | } | ||
352 | |||
353 | /* returns the total size of the log's ring buffer */ | ||
354 | static ssize_t logdGetSize(struct android_log_logger *logger, | ||
355 | struct android_log_transport_context *transp __unused) | ||
356 | { | ||
357 | char buf[512]; | ||
358 | |||
359 | ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf)); | ||
360 | if (ret < 0) { | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | if ((buf[0] < '0') || ('9' < buf[0])) { | ||
365 | return -1; | ||
366 | } | ||
367 | |||
368 | return atol(buf); | ||
369 | } | ||
370 | |||
371 | static ssize_t logdSetSize( | ||
372 | struct android_log_logger *logger, | ||
373 | struct android_log_transport_context *transp __unused, | ||
374 | size_t size) | ||
375 | { | ||
376 | char buf[512]; | ||
377 | |||
378 | snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size); | ||
379 | |||
380 | return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf))); | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * returns the readable size of the log's ring buffer (that is, amount of the | ||
385 | * log consumed) | ||
386 | */ | ||
387 | static ssize_t logdGetReadableSize( | ||
388 | struct android_log_logger *logger, | ||
389 | struct android_log_transport_context *transp __unused) | ||
390 | { | ||
391 | char buf[512]; | ||
392 | |||
393 | ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf)); | ||
394 | if (ret < 0) { | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | if ((buf[0] < '0') || ('9' < buf[0])) { | ||
399 | return -1; | ||
400 | } | ||
401 | |||
402 | return atol(buf); | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * returns the logger version | ||
407 | */ | ||
408 | static int logdVersion( | ||
409 | struct android_log_logger *logger __unused, | ||
410 | struct android_log_transport_context *transp __unused) | ||
411 | { | ||
412 | uid_t uid = __android_log_uid(); | ||
413 | return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4; | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * returns statistics | ||
418 | */ | ||
419 | static ssize_t logdGetStats(struct android_log_logger_list *logger_list, | ||
420 | struct android_log_transport_context *transp __unused, | ||
421 | char *buf, size_t len) | ||
422 | { | ||
423 | struct android_log_logger *logger; | ||
424 | char *cp = buf; | ||
425 | size_t remaining = len; | ||
426 | size_t n; | ||
427 | |||
428 | n = snprintf(cp, remaining, "getStatistics"); | ||
429 | n = min(n, remaining); | ||
430 | remaining -= n; | ||
431 | cp += n; | ||
432 | |||
433 | logger_for_each(logger, logger_list) { | ||
434 | n = snprintf(cp, remaining, " %d", logger->logId); | ||
435 | n = min(n, remaining); | ||
436 | remaining -= n; | ||
437 | cp += n; | ||
438 | } | ||
439 | |||
440 | if (logger_list->pid) { | ||
441 | snprintf(cp, remaining, " pid=%u", logger_list->pid); | ||
442 | } | ||
443 | |||
444 | return send_log_msg(NULL, NULL, buf, len); | ||
445 | } | ||
446 | |||
447 | static ssize_t logdGetPrune( | ||
448 | struct android_log_logger_list *logger_list __unused, | ||
449 | struct android_log_transport_context *transp __unused, | ||
450 | char *buf, size_t len) | ||
451 | { | ||
452 | return send_log_msg(NULL, "getPruneList", buf, len); | ||
453 | } | ||
454 | |||
455 | static ssize_t logdSetPrune( | ||
456 | struct android_log_logger_list *logger_list __unused, | ||
457 | struct android_log_transport_context *transp __unused, | ||
458 | char *buf, size_t len) | ||
459 | { | ||
460 | const char cmd[] = "setPruneList "; | ||
461 | const size_t cmdlen = sizeof(cmd) - 1; | ||
462 | |||
463 | if (strlen(buf) > (len - cmdlen)) { | ||
464 | return -ENOMEM; /* KISS */ | ||
465 | } | ||
466 | memmove(buf + cmdlen, buf, len - cmdlen); | ||
467 | buf[len - 1] = '\0'; | ||
468 | memcpy(buf, cmd, cmdlen); | ||
469 | |||
470 | return check_log_success(buf, send_log_msg(NULL, NULL, buf, len)); | ||
471 | } | ||
472 | |||
473 | |||
474 | static void caught_signal(int signum __unused) | ||
475 | { | ||
476 | } | ||
477 | |||
478 | static int logdOpen(struct android_log_logger_list *logger_list, | ||
479 | struct android_log_transport_context *transp) | ||
480 | { | ||
481 | struct android_log_logger *logger; | ||
482 | struct sigaction ignore; | ||
483 | struct sigaction old_sigaction; | ||
484 | unsigned int old_alarm = 0; | ||
485 | char buffer[256], *cp, c; | ||
486 | int e, ret, remaining; | ||
487 | |||
488 | int sock = transp->context.sock; | ||
489 | if (sock > 0) { | ||
490 | return sock; | ||
491 | } | ||
492 | |||
493 | if (!logger_list) { | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | |||
497 | sock = socket_local_client("logdr", | ||
498 | ANDROID_SOCKET_NAMESPACE_RESERVED, | ||
499 | SOCK_SEQPACKET); | ||
500 | if (sock == 0) { | ||
501 | /* Guarantee not file descriptor zero */ | ||
502 | int newsock = socket_local_client("logdr", | ||
503 | ANDROID_SOCKET_NAMESPACE_RESERVED, | ||
504 | SOCK_SEQPACKET); | ||
505 | close(sock); | ||
506 | sock = newsock; | ||
507 | } | ||
508 | if (sock <= 0) { | ||
509 | if ((sock == -1) && errno) { | ||
510 | return -errno; | ||
511 | } | ||
512 | return sock; | ||
513 | } | ||
514 | |||
515 | strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? | ||
516 | "dumpAndClose" : "stream"); | ||
517 | cp = buffer + strlen(buffer); | ||
518 | |||
519 | strcpy(cp, " lids"); | ||
520 | cp += 5; | ||
521 | c = '='; | ||
522 | remaining = sizeof(buffer) - (cp - buffer); | ||
523 | logger_for_each(logger, logger_list) { | ||
524 | ret = snprintf(cp, remaining, "%c%u", c, logger->logId); | ||
525 | ret = min(ret, remaining); | ||
526 | remaining -= ret; | ||
527 | cp += ret; | ||
528 | c = ','; | ||
529 | } | ||
530 | |||
531 | if (logger_list->tail) { | ||
532 | ret = snprintf(cp, remaining, " tail=%u", logger_list->tail); | ||
533 | ret = min(ret, remaining); | ||
534 | remaining -= ret; | ||
535 | cp += ret; | ||
536 | } | ||
537 | |||
538 | if (logger_list->start.tv_sec || logger_list->start.tv_nsec) { | ||
539 | if (logger_list->mode & ANDROID_LOG_WRAP) { | ||
540 | // ToDo: alternate API to allow timeout to be adjusted. | ||
541 | ret = snprintf(cp, remaining, " timeout=%u", | ||
542 | ANDROID_LOG_WRAP_DEFAULT_TIMEOUT); | ||
543 | ret = min(ret, remaining); | ||
544 | remaining -= ret; | ||
545 | cp += ret; | ||
546 | } | ||
547 | ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, | ||
548 | logger_list->start.tv_sec, | ||
549 | logger_list->start.tv_nsec); | ||
550 | ret = min(ret, remaining); | ||
551 | remaining -= ret; | ||
552 | cp += ret; | ||
553 | } | ||
554 | |||
555 | if (logger_list->pid) { | ||
556 | ret = snprintf(cp, remaining, " pid=%u", logger_list->pid); | ||
557 | ret = min(ret, remaining); | ||
558 | cp += ret; | ||
559 | } | ||
560 | |||
561 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
562 | /* Deal with an unresponsive logd */ | ||
563 | memset(&ignore, 0, sizeof(ignore)); | ||
564 | ignore.sa_handler = caught_signal; | ||
565 | sigemptyset(&ignore.sa_mask); | ||
566 | /* particularily useful if tombstone is reporting for logd */ | ||
567 | sigaction(SIGALRM, &ignore, &old_sigaction); | ||
568 | old_alarm = alarm(30); | ||
569 | } | ||
570 | ret = write(sock, buffer, cp - buffer); | ||
571 | e = errno; | ||
572 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
573 | if (e == EINTR) { | ||
574 | e = ETIMEDOUT; | ||
575 | } | ||
576 | alarm(old_alarm); | ||
577 | sigaction(SIGALRM, &old_sigaction, NULL); | ||
578 | } | ||
579 | |||
580 | if (ret <= 0) { | ||
581 | close(sock); | ||
582 | if ((ret == -1) && e) { | ||
583 | return -e; | ||
584 | } | ||
585 | if (ret == 0) { | ||
586 | return -EIO; | ||
587 | } | ||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | return transp->context.sock = sock; | ||
592 | } | ||
593 | |||
594 | /* Read from the selected logs */ | ||
595 | static int logdRead(struct android_log_logger_list *logger_list, | ||
596 | struct android_log_transport_context *transp, | ||
597 | struct log_msg *log_msg) | ||
598 | { | ||
599 | int ret, e; | ||
600 | struct sigaction ignore; | ||
601 | struct sigaction old_sigaction; | ||
602 | unsigned int old_alarm = 0; | ||
603 | |||
604 | ret = logdOpen(logger_list, transp); | ||
605 | if (ret < 0) { | ||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | memset(log_msg, 0, sizeof(*log_msg)); | ||
610 | |||
611 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
612 | memset(&ignore, 0, sizeof(ignore)); | ||
613 | ignore.sa_handler = caught_signal; | ||
614 | sigemptyset(&ignore.sa_mask); | ||
615 | /* particularily useful if tombstone is reporting for logd */ | ||
616 | sigaction(SIGALRM, &ignore, &old_sigaction); | ||
617 | old_alarm = alarm(30); | ||
618 | } | ||
619 | |||
620 | /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */ | ||
621 | ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0); | ||
622 | e = errno; | ||
623 | |||
624 | if (logger_list->mode & ANDROID_LOG_NONBLOCK) { | ||
625 | if ((ret == 0) || (e == EINTR)) { | ||
626 | e = EAGAIN; | ||
627 | ret = -1; | ||
628 | } | ||
629 | alarm(old_alarm); | ||
630 | sigaction(SIGALRM, &old_sigaction, NULL); | ||
631 | } | ||
632 | |||
633 | if ((ret == -1) && e) { | ||
634 | return -e; | ||
635 | } | ||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | static int logdPoll(struct android_log_logger_list *logger_list, | ||
640 | struct android_log_transport_context *transp) | ||
641 | { | ||
642 | struct pollfd p; | ||
643 | |||
644 | int ret = logdOpen(logger_list, transp); | ||
645 | if (ret < 0) { | ||
646 | return ret; | ||
647 | } | ||
648 | |||
649 | memset(&p, 0, sizeof(p)); | ||
650 | p.fd = ret; | ||
651 | p.events = POLLIN; | ||
652 | ret = poll(&p, 1, 20); | ||
653 | if ((ret > 0) && !(p.revents & POLLIN)) { | ||
654 | ret = 0; | ||
655 | } | ||
656 | if ((ret == -1) && errno) { | ||
657 | return -errno; | ||
658 | } | ||
659 | return ret; | ||
660 | } | ||
661 | |||
662 | /* Close all the logs */ | ||
663 | static void logdClose(struct android_log_logger_list *logger_list __unused, | ||
664 | struct android_log_transport_context *transp) | ||
665 | { | ||
666 | if (transp->context.sock > 0) { | ||
667 | close (transp->context.sock); | ||
668 | transp->context.sock = -1; | ||
669 | } | ||
670 | } | ||
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c new file mode 100644 index 000000000..696237d34 --- /dev/null +++ b/liblog/logd_writer.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2016 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 <endian.h> | ||
18 | #include <errno.h> | ||
19 | #include <fcntl.h> | ||
20 | #include <inttypes.h> | ||
21 | #include <poll.h> | ||
22 | #include <stdarg.h> | ||
23 | #include <stdatomic.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <string.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/socket.h> | ||
30 | #include <sys/un.h> | ||
31 | #include <time.h> | ||
32 | #include <unistd.h> | ||
33 | |||
34 | #include <cutils/sockets.h> | ||
35 | #include <log/logd.h> | ||
36 | #include <log/logger.h> | ||
37 | #include <log/log_read.h> | ||
38 | #include <private/android_filesystem_config.h> | ||
39 | #include <private/android_logger.h> | ||
40 | |||
41 | #include "config_write.h" | ||
42 | #include "log_portability.h" | ||
43 | #include "logger.h" | ||
44 | |||
45 | /* branchless on many architectures. */ | ||
46 | #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) | ||
47 | |||
48 | static int logdAvailable(log_id_t LogId); | ||
49 | static int logdOpen(); | ||
50 | static void logdClose(); | ||
51 | static int logdWrite(log_id_t logId, struct timespec *ts, | ||
52 | struct iovec *vec, size_t nr); | ||
53 | |||
54 | LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = { | ||
55 | .node = { &logdLoggerWrite.node, &logdLoggerWrite.node }, | ||
56 | .context.sock = -1, | ||
57 | .name = "logd", | ||
58 | .available = logdAvailable, | ||
59 | .open = logdOpen, | ||
60 | .close = logdClose, | ||
61 | .write = logdWrite, | ||
62 | }; | ||
63 | |||
64 | /* log_init_lock assumed */ | ||
65 | static int logdOpen() | ||
66 | { | ||
67 | int i, ret = 0; | ||
68 | |||
69 | if (logdLoggerWrite.context.sock < 0) { | ||
70 | i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)); | ||
71 | if (i < 0) { | ||
72 | ret = -errno; | ||
73 | } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) { | ||
74 | ret = -errno; | ||
75 | close(i); | ||
76 | } else { | ||
77 | struct sockaddr_un un; | ||
78 | memset(&un, 0, sizeof(struct sockaddr_un)); | ||
79 | un.sun_family = AF_UNIX; | ||
80 | strcpy(un.sun_path, "/dev/socket/logdw"); | ||
81 | |||
82 | if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un, | ||
83 | sizeof(struct sockaddr_un))) < 0) { | ||
84 | ret = -errno; | ||
85 | close(i); | ||
86 | } else { | ||
87 | logdLoggerWrite.context.sock = i; | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static void logdClose() | ||
96 | { | ||
97 | if (logdLoggerWrite.context.sock >= 0) { | ||
98 | close(logdLoggerWrite.context.sock); | ||
99 | logdLoggerWrite.context.sock = -1; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static int logdAvailable(log_id_t logId) | ||
104 | { | ||
105 | if (logId > LOG_ID_SECURITY) { | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | if (logId == LOG_ID_SECURITY) { | ||
109 | uid_t uid = __android_log_uid(); | ||
110 | if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) { | ||
111 | return -EPERM; | ||
112 | } | ||
113 | } | ||
114 | if (logdLoggerWrite.context.sock < 0) { | ||
115 | if (access("/dev/socket/logdw", W_OK) == 0) { | ||
116 | return 0; | ||
117 | } | ||
118 | return -EBADF; | ||
119 | } | ||
120 | return 1; | ||
121 | } | ||
122 | |||
123 | static int logdWrite(log_id_t logId, struct timespec *ts, | ||
124 | struct iovec *vec, size_t nr) | ||
125 | { | ||
126 | ssize_t ret; | ||
127 | static const unsigned headerLength = 1; | ||
128 | struct iovec newVec[nr + headerLength]; | ||
129 | android_log_header_t header; | ||
130 | size_t i, payloadSize; | ||
131 | static atomic_int_fast32_t dropped; | ||
132 | static atomic_int_fast32_t droppedSecurity; | ||
133 | |||
134 | if (logdLoggerWrite.context.sock < 0) { | ||
135 | return -EBADF; | ||
136 | } | ||
137 | |||
138 | /* logd, after initialization and priv drop */ | ||
139 | if (__android_log_uid() == AID_LOGD) { | ||
140 | /* | ||
141 | * ignore log messages we send to ourself (logd). | ||
142 | * Such log messages are often generated by libraries we depend on | ||
143 | * which use standard Android logging. | ||
144 | */ | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * struct { | ||
150 | * // what we provide to socket | ||
151 | * android_log_header_t header; | ||
152 | * // caller provides | ||
153 | * union { | ||
154 | * struct { | ||
155 | * char prio; | ||
156 | * char payload[]; | ||
157 | * } string; | ||
158 | * struct { | ||
159 | * uint32_t tag | ||
160 | * char payload[]; | ||
161 | * } binary; | ||
162 | * }; | ||
163 | * }; | ||
164 | */ | ||
165 | |||
166 | header.tid = gettid(); | ||
167 | header.realtime.tv_sec = ts->tv_sec; | ||
168 | header.realtime.tv_nsec = ts->tv_nsec; | ||
169 | |||
170 | newVec[0].iov_base = (unsigned char *)&header; | ||
171 | newVec[0].iov_len = sizeof(header); | ||
172 | |||
173 | if (logdLoggerWrite.context.sock > 0) { | ||
174 | int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, | ||
175 | memory_order_relaxed); | ||
176 | if (snapshot) { | ||
177 | android_log_event_int_t buffer; | ||
178 | |||
179 | header.id = LOG_ID_SECURITY; | ||
180 | buffer.header.tag = htole32(LIBLOG_LOG_TAG); | ||
181 | buffer.payload.type = EVENT_TYPE_INT; | ||
182 | buffer.payload.data = htole32(snapshot); | ||
183 | |||
184 | newVec[headerLength].iov_base = &buffer; | ||
185 | newVec[headerLength].iov_len = sizeof(buffer); | ||
186 | |||
187 | ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2)); | ||
188 | if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) { | ||
189 | atomic_fetch_add_explicit(&droppedSecurity, snapshot, | ||
190 | memory_order_relaxed); | ||
191 | } | ||
192 | } | ||
193 | snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed); | ||
194 | if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO, | ||
195 | "liblog", | ||
196 | ANDROID_LOG_VERBOSE)) { | ||
197 | android_log_event_int_t buffer; | ||
198 | |||
199 | header.id = LOG_ID_EVENTS; | ||
200 | buffer.header.tag = htole32(LIBLOG_LOG_TAG); | ||
201 | buffer.payload.type = EVENT_TYPE_INT; | ||
202 | buffer.payload.data = htole32(snapshot); | ||
203 | |||
204 | newVec[headerLength].iov_base = &buffer; | ||
205 | newVec[headerLength].iov_len = sizeof(buffer); | ||
206 | |||
207 | ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2)); | ||
208 | if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) { | ||
209 | atomic_fetch_add_explicit(&dropped, snapshot, | ||
210 | memory_order_relaxed); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | header.id = logId; | ||
216 | |||
217 | for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) { | ||
218 | newVec[i].iov_base = vec[i - headerLength].iov_base; | ||
219 | payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len; | ||
220 | |||
221 | if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) { | ||
222 | newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD; | ||
223 | if (newVec[i].iov_len) { | ||
224 | ++i; | ||
225 | } | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * The write below could be lost, but will never block. | ||
232 | * | ||
233 | * ENOTCONN occurs if logd dies. | ||
234 | * EAGAIN occurs if logd is overloaded. | ||
235 | */ | ||
236 | ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i)); | ||
237 | if (ret < 0) { | ||
238 | ret = -errno; | ||
239 | if (ret == -ENOTCONN) { | ||
240 | __android_log_lock(); | ||
241 | logdClose(); | ||
242 | ret = logdOpen(); | ||
243 | __android_log_unlock(); | ||
244 | |||
245 | if (ret < 0) { | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i)); | ||
250 | if (ret < 0) { | ||
251 | ret = -errno; | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if (ret > (ssize_t)sizeof(header)) { | ||
257 | ret -= sizeof(header); | ||
258 | } else if (ret == -EAGAIN) { | ||
259 | atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); | ||
260 | if (logId == LOG_ID_SECURITY) { | ||
261 | atomic_fetch_add_explicit(&droppedSecurity, 1, | ||
262 | memory_order_relaxed); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | return ret; | ||
267 | } | ||
diff --git a/liblog/logger.h b/liblog/logger.h new file mode 100644 index 000000000..61bc3968a --- /dev/null +++ b/liblog/logger.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 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 _LIBLOG_LOGGER_H__ | ||
18 | #define _LIBLOG_LOGGER_H__ | ||
19 | |||
20 | #include <stdbool.h> | ||
21 | #include <log/uio.h> | ||
22 | |||
23 | #include <cutils/list.h> | ||
24 | #include <log/log.h> | ||
25 | #include <log/log_read.h> | ||
26 | #include <log/logger.h> | ||
27 | |||
28 | #include "log_portability.h" | ||
29 | |||
30 | __BEGIN_DECLS | ||
31 | |||
32 | /* Union, sock or fd of zero is not allowed unless static initialized */ | ||
33 | union android_log_context { | ||
34 | void *private; | ||
35 | int sock; | ||
36 | int fd; | ||
37 | struct listnode *node; | ||
38 | }; | ||
39 | |||
40 | struct android_log_transport_write { | ||
41 | struct listnode node; | ||
42 | const char *name; | ||
43 | union android_log_context context; /* Initialized by static allocation */ | ||
44 | |||
45 | int (*available)(log_id_t logId); | ||
46 | int (*open)(); | ||
47 | void (*close)(); | ||
48 | int (*write)(log_id_t logId, struct timespec *ts, struct iovec *vec, size_t nr); | ||
49 | }; | ||
50 | |||
51 | struct android_log_logger_list; | ||
52 | struct android_log_transport_context; | ||
53 | struct android_log_logger; | ||
54 | |||
55 | struct android_log_transport_read { | ||
56 | struct listnode node; | ||
57 | const char *name; | ||
58 | |||
59 | int (*available)(log_id_t logId); | ||
60 | int (*version)(struct android_log_logger *logger, | ||
61 | struct android_log_transport_context *transp); | ||
62 | void (*close)(struct android_log_logger_list *logger_list, | ||
63 | struct android_log_transport_context *transp); | ||
64 | |||
65 | /* | ||
66 | * Expect all to instantiate open on any call, so we do not have | ||
67 | * an expicit open call | ||
68 | */ | ||
69 | int (*read)(struct android_log_logger_list *logger_list, | ||
70 | struct android_log_transport_context *transp, | ||
71 | struct log_msg *log_msg); | ||
72 | /* Assumption is only called if not ANDROID_LOG_NONBLOCK */ | ||
73 | int (*poll)(struct android_log_logger_list *logger_list, | ||
74 | struct android_log_transport_context *transp); | ||
75 | |||
76 | int (*clear)(struct android_log_logger *logger, | ||
77 | struct android_log_transport_context *transp); | ||
78 | ssize_t (*setSize)(struct android_log_logger *logger, | ||
79 | struct android_log_transport_context *transp, | ||
80 | size_t size); | ||
81 | ssize_t (*getSize)(struct android_log_logger *logger, | ||
82 | struct android_log_transport_context *transp); | ||
83 | ssize_t (*getReadableSize)(struct android_log_logger *logger, | ||
84 | struct android_log_transport_context *transp); | ||
85 | |||
86 | ssize_t (*getPrune)(struct android_log_logger_list *logger_list, | ||
87 | struct android_log_transport_context *transp, | ||
88 | char *buf, size_t len); | ||
89 | ssize_t (*setPrune)(struct android_log_logger_list *logger_list, | ||
90 | struct android_log_transport_context *transp, | ||
91 | char *buf, size_t len); | ||
92 | ssize_t (*getStats)(struct android_log_logger_list *logger_list, | ||
93 | struct android_log_transport_context *transp, | ||
94 | char *buf, size_t len); | ||
95 | }; | ||
96 | |||
97 | struct android_log_logger_list { | ||
98 | struct listnode logger; | ||
99 | struct listnode transport; | ||
100 | int mode; | ||
101 | unsigned int tail; | ||
102 | log_time start; | ||
103 | pid_t pid; | ||
104 | }; | ||
105 | |||
106 | struct android_log_logger { | ||
107 | struct listnode node; | ||
108 | struct android_log_logger_list *parent; | ||
109 | |||
110 | log_id_t logId; | ||
111 | }; | ||
112 | |||
113 | struct android_log_transport_context { | ||
114 | struct listnode node; | ||
115 | union android_log_context context; /* zero init per-transport context */ | ||
116 | struct android_log_logger_list *parent; | ||
117 | |||
118 | struct android_log_transport_read *transport; | ||
119 | unsigned logMask; | ||
120 | int ret; | ||
121 | struct log_msg logMsg; /* valid is logMsg.len != 0 */ | ||
122 | }; | ||
123 | |||
124 | /* assumes caller has structures read-locked, single threaded, or fenced */ | ||
125 | #define transport_context_for_each(transp, logger_list) \ | ||
126 | for (transp = node_to_item((logger_list)->transport.next, \ | ||
127 | struct android_log_transport_context, \ | ||
128 | node); \ | ||
129 | (transp != node_to_item(&(logger_list)->transport, \ | ||
130 | struct android_log_transport_context, \ | ||
131 | node)) && \ | ||
132 | (transp->parent == (logger_list)); \ | ||
133 | transp = node_to_item(transp->node.next, \ | ||
134 | struct android_log_transport_context, node)) | ||
135 | |||
136 | #define logger_for_each(logp, logger_list) \ | ||
137 | for (logp = node_to_item((logger_list)->logger.next, \ | ||
138 | struct android_log_logger, node); \ | ||
139 | (logp != node_to_item(&(logger_list)->logger, \ | ||
140 | struct android_log_logger, node)) && \ | ||
141 | (logp->parent == (logger_list)); \ | ||
142 | logp = node_to_item((logp)->node.next, \ | ||
143 | struct android_log_logger, node)) | ||
144 | |||
145 | /* OS specific dribs and drabs */ | ||
146 | |||
147 | #if defined(_WIN32) | ||
148 | typedef uint32_t uid_t; | ||
149 | #endif | ||
150 | |||
151 | LIBLOG_HIDDEN uid_t __android_log_uid(); | ||
152 | LIBLOG_HIDDEN pid_t __android_log_pid(); | ||
153 | LIBLOG_HIDDEN void __android_log_lock(); | ||
154 | LIBLOG_HIDDEN int __android_log_trylock(); | ||
155 | LIBLOG_HIDDEN void __android_log_unlock(); | ||
156 | |||
157 | __END_DECLS | ||
158 | |||
159 | #endif /* _LIBLOG_LOGGER_H__ */ | ||
diff --git a/liblog/logger_lock.c b/liblog/logger_lock.c new file mode 100644 index 000000000..ee979bd5e --- /dev/null +++ b/liblog/logger_lock.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2016 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 | * Some OS specific dribs and drabs (locking etc). | ||
19 | */ | ||
20 | |||
21 | #if !defined(_WIN32) | ||
22 | #include <pthread.h> | ||
23 | #endif | ||
24 | |||
25 | #include <private/android_filesystem_config.h> | ||
26 | |||
27 | #include "logger.h" | ||
28 | |||
29 | LIBLOG_HIDDEN uid_t __android_log_uid() | ||
30 | { | ||
31 | #if defined(_WIN32) | ||
32 | return AID_SYSTEM; | ||
33 | #else | ||
34 | static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */ | ||
35 | |||
36 | if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */ | ||
37 | last_uid = getuid(); | ||
38 | } | ||
39 | return last_uid; | ||
40 | #endif | ||
41 | } | ||
42 | |||
43 | LIBLOG_HIDDEN pid_t __android_log_pid() | ||
44 | { | ||
45 | static pid_t last_pid = (pid_t) -1; | ||
46 | |||
47 | if (last_pid == (pid_t) -1) { | ||
48 | last_pid = getpid(); | ||
49 | } | ||
50 | return last_pid; | ||
51 | } | ||
52 | |||
53 | #if !defined(_WIN32) | ||
54 | static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; | ||
55 | #endif | ||
56 | |||
57 | LIBLOG_HIDDEN void __android_log_lock() | ||
58 | { | ||
59 | #if !defined(_WIN32) | ||
60 | /* | ||
61 | * If we trigger a signal handler in the middle of locked activity and the | ||
62 | * signal handler logs a message, we could get into a deadlock state. | ||
63 | */ | ||
64 | pthread_mutex_lock(&log_init_lock); | ||
65 | #endif | ||
66 | } | ||
67 | |||
68 | LIBLOG_HIDDEN int __android_log_trylock() | ||
69 | { | ||
70 | #if !defined(_WIN32) | ||
71 | return pthread_mutex_trylock(&log_init_lock); | ||
72 | #else | ||
73 | return 0; | ||
74 | #endif | ||
75 | } | ||
76 | |||
77 | LIBLOG_HIDDEN void __android_log_unlock() | ||
78 | { | ||
79 | #if !defined(_WIN32) | ||
80 | pthread_mutex_unlock(&log_init_lock); | ||
81 | #endif | ||
82 | } | ||
diff --git a/liblog/logger_name.c b/liblog/logger_name.c new file mode 100644 index 000000000..b7ccac51f --- /dev/null +++ b/liblog/logger_name.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | ** Copyright 2013-2014, 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 | |||
19 | #include <log/log.h> | ||
20 | #include <log/logger.h> | ||
21 | |||
22 | #include "log_portability.h" | ||
23 | |||
24 | /* In the future, we would like to make this list extensible */ | ||
25 | static const char *LOG_NAME[LOG_ID_MAX] = { | ||
26 | [LOG_ID_MAIN] = "main", | ||
27 | [LOG_ID_RADIO] = "radio", | ||
28 | [LOG_ID_EVENTS] = "events", | ||
29 | [LOG_ID_SYSTEM] = "system", | ||
30 | [LOG_ID_CRASH] = "crash", | ||
31 | [LOG_ID_SECURITY] = "security", | ||
32 | [LOG_ID_KERNEL] = "kernel", | ||
33 | }; | ||
34 | |||
35 | LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id) | ||
36 | { | ||
37 | if (log_id >= LOG_ID_MAX) { | ||
38 | log_id = LOG_ID_MAIN; | ||
39 | } | ||
40 | return LOG_NAME[log_id]; | ||
41 | } | ||
42 | |||
43 | LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName) | ||
44 | { | ||
45 | const char *b; | ||
46 | int ret; | ||
47 | |||
48 | if (!logName) { | ||
49 | return -1; /* NB: log_id_t is unsigned */ | ||
50 | } | ||
51 | b = strrchr(logName, '/'); | ||
52 | if (!b) { | ||
53 | b = logName; | ||
54 | } else { | ||
55 | ++b; | ||
56 | } | ||
57 | |||
58 | for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) { | ||
59 | const char *l = LOG_NAME[ret]; | ||
60 | if (l && !strcmp(b, l)) { | ||
61 | return ret; | ||
62 | } | ||
63 | } | ||
64 | return -1; /* should never happen */ | ||
65 | } | ||
diff --git a/liblog/logger_read.c b/liblog/logger_read.c new file mode 100644 index 000000000..f15c7cd62 --- /dev/null +++ b/liblog/logger_read.c | |||
@@ -0,0 +1,474 @@ | |||
1 | /* | ||
2 | ** Copyright 2013-2014, 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 <fcntl.h> | ||
19 | #include <pthread.h> | ||
20 | #include <sched.h> | ||
21 | #include <stddef.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <cutils/list.h> | ||
27 | #include <log/log.h> | ||
28 | #include <log/logger.h> | ||
29 | |||
30 | #include "config_read.h" | ||
31 | #include "log_portability.h" | ||
32 | #include "logger.h" | ||
33 | |||
34 | /* android_logger_alloc unimplemented, no use case */ | ||
35 | /* android_logger_free not exported */ | ||
36 | static void android_logger_free(struct logger *logger) | ||
37 | { | ||
38 | struct android_log_logger *logger_internal = | ||
39 | (struct android_log_logger *)logger; | ||
40 | |||
41 | if (!logger_internal) { | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | list_remove(&logger_internal->node); | ||
46 | |||
47 | free(logger_internal); | ||
48 | } | ||
49 | |||
50 | /* android_logger_alloc unimplemented, no use case */ | ||
51 | |||
52 | /* method for getting the associated sublog id */ | ||
53 | LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger) | ||
54 | { | ||
55 | return ((struct android_log_logger *)logger)->logId; | ||
56 | } | ||
57 | |||
58 | static int init_transport_context(struct android_log_logger_list *logger_list) | ||
59 | { | ||
60 | struct android_log_transport_read *transport; | ||
61 | struct listnode *node; | ||
62 | |||
63 | if (!logger_list) { | ||
64 | return -EINVAL; | ||
65 | } | ||
66 | |||
67 | if (list_empty(&logger_list->logger)) { | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | if (!list_empty(&logger_list->transport)) { | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | __android_log_lock(); | ||
76 | /* mini __write_to_log_initialize() to populate transports */ | ||
77 | if (list_empty(&__android_log_transport_read) && | ||
78 | list_empty(&__android_log_persist_read)) { | ||
79 | __android_log_config_read(); | ||
80 | } | ||
81 | __android_log_unlock(); | ||
82 | |||
83 | node = (logger_list->mode & ANDROID_LOG_PSTORE) ? | ||
84 | &__android_log_persist_read : &__android_log_transport_read; | ||
85 | |||
86 | read_transport_for_each(transport, node) { | ||
87 | struct android_log_transport_context *transp; | ||
88 | struct android_log_logger *logger; | ||
89 | unsigned logMask = 0; | ||
90 | |||
91 | logger_for_each(logger, logger_list) { | ||
92 | log_id_t logId = logger->logId; | ||
93 | |||
94 | if (transport->read && | ||
95 | (!transport->available || | ||
96 | (transport->available(logId) >= 0))) { | ||
97 | logMask |= 1 << logId; | ||
98 | } | ||
99 | } | ||
100 | if (!logMask) { | ||
101 | continue; | ||
102 | } | ||
103 | transp = calloc(1, sizeof(*transp)); | ||
104 | if (!transp) { | ||
105 | return -ENOMEM; | ||
106 | } | ||
107 | transp->parent = logger_list; | ||
108 | transp->transport = transport; | ||
109 | transp->logMask = logMask; | ||
110 | transp->ret = 1; | ||
111 | list_add_tail(&logger_list->transport, &transp->node); | ||
112 | } | ||
113 | if (list_empty(&logger_list->transport)) { | ||
114 | return -ENODEV; | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | #define LOGGER_FUNCTION(logger, def, func, args...) \ | ||
120 | ssize_t ret = -EINVAL; \ | ||
121 | struct android_log_transport_context *transp; \ | ||
122 | struct android_log_logger *logger_internal = \ | ||
123 | (struct android_log_logger *)logger; \ | ||
124 | \ | ||
125 | if (!logger_internal) { \ | ||
126 | return ret; \ | ||
127 | } \ | ||
128 | ret = init_transport_context(logger_internal->parent); \ | ||
129 | if (ret < 0) { \ | ||
130 | return ret; \ | ||
131 | } \ | ||
132 | \ | ||
133 | ret = (def); \ | ||
134 | transport_context_for_each(transp, logger_internal->parent) { \ | ||
135 | if ((transp->logMask & (1 << logger_internal->logId)) && \ | ||
136 | transp->transport && transp->transport->func) { \ | ||
137 | ssize_t retval = (transp->transport->func)(logger_internal, \ | ||
138 | transp, ## args); \ | ||
139 | if ((ret >= 0) || (ret == (def))) { \ | ||
140 | ret = retval; \ | ||
141 | } \ | ||
142 | } \ | ||
143 | } \ | ||
144 | return ret | ||
145 | |||
146 | LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger) | ||
147 | { | ||
148 | LOGGER_FUNCTION(logger, -ENODEV, clear); | ||
149 | } | ||
150 | |||
151 | /* returns the total size of the log's ring buffer */ | ||
152 | LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger) | ||
153 | { | ||
154 | LOGGER_FUNCTION(logger, -ENODEV, getSize); | ||
155 | } | ||
156 | |||
157 | LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger, | ||
158 | unsigned long size) | ||
159 | { | ||
160 | LOGGER_FUNCTION(logger, -ENODEV, setSize, size); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * returns the readable size of the log's ring buffer (that is, amount of the | ||
165 | * log consumed) | ||
166 | */ | ||
167 | LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size( | ||
168 | struct logger *logger) | ||
169 | { | ||
170 | LOGGER_FUNCTION(logger, -ENODEV, getReadableSize); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * returns the logger version | ||
175 | */ | ||
176 | LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger *logger) | ||
177 | { | ||
178 | LOGGER_FUNCTION(logger, 4, version); | ||
179 | } | ||
180 | |||
181 | #define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \ | ||
182 | struct android_log_transport_context *transp; \ | ||
183 | struct android_log_logger_list *logger_list_internal = \ | ||
184 | (struct android_log_logger_list *)logger_list; \ | ||
185 | \ | ||
186 | ssize_t ret = init_transport_context(logger_list_internal); \ | ||
187 | if (ret < 0) { \ | ||
188 | return ret; \ | ||
189 | } \ | ||
190 | \ | ||
191 | ret = (def); \ | ||
192 | transport_context_for_each(transp, logger_list_internal) { \ | ||
193 | if (transp->transport && (transp->transport->func)) { \ | ||
194 | ssize_t retval = (transp->transport->func)(logger_list_internal, \ | ||
195 | transp, ## args); \ | ||
196 | if ((ret >= 0) || (ret == (def))) { \ | ||
197 | ret = retval; \ | ||
198 | } \ | ||
199 | } \ | ||
200 | } \ | ||
201 | return ret | ||
202 | |||
203 | /* | ||
204 | * returns statistics | ||
205 | */ | ||
206 | LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics( | ||
207 | struct logger_list *logger_list, | ||
208 | char *buf, size_t len) | ||
209 | { | ||
210 | LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len); | ||
211 | } | ||
212 | |||
213 | LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list( | ||
214 | struct logger_list *logger_list, | ||
215 | char *buf, size_t len) | ||
216 | { | ||
217 | LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len); | ||
218 | } | ||
219 | |||
220 | LIBLOG_ABI_PUBLIC int android_logger_set_prune_list( | ||
221 | struct logger_list *logger_list, | ||
222 | char *buf, size_t len) | ||
223 | { | ||
224 | LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len); | ||
225 | } | ||
226 | |||
227 | LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc( | ||
228 | int mode, | ||
229 | unsigned int tail, | ||
230 | pid_t pid) | ||
231 | { | ||
232 | struct android_log_logger_list *logger_list; | ||
233 | |||
234 | logger_list = calloc(1, sizeof(*logger_list)); | ||
235 | if (!logger_list) { | ||
236 | return NULL; | ||
237 | } | ||
238 | |||
239 | list_init(&logger_list->logger); | ||
240 | list_init(&logger_list->transport); | ||
241 | logger_list->mode = mode; | ||
242 | logger_list->tail = tail; | ||
243 | logger_list->pid = pid; | ||
244 | |||
245 | return (struct logger_list *)logger_list; | ||
246 | } | ||
247 | |||
248 | LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time( | ||
249 | int mode, | ||
250 | log_time start, | ||
251 | pid_t pid) | ||
252 | { | ||
253 | struct android_log_logger_list *logger_list; | ||
254 | |||
255 | logger_list = calloc(1, sizeof(*logger_list)); | ||
256 | if (!logger_list) { | ||
257 | return NULL; | ||
258 | } | ||
259 | |||
260 | list_init(&logger_list->logger); | ||
261 | list_init(&logger_list->transport); | ||
262 | logger_list->mode = mode; | ||
263 | logger_list->start = start; | ||
264 | logger_list->pid = pid; | ||
265 | |||
266 | return (struct logger_list *)logger_list; | ||
267 | } | ||
268 | |||
269 | /* android_logger_list_register unimplemented, no use case */ | ||
270 | /* android_logger_list_unregister unimplemented, no use case */ | ||
271 | |||
272 | /* Open the named log and add it to the logger list */ | ||
273 | LIBLOG_ABI_PUBLIC struct logger *android_logger_open( | ||
274 | struct logger_list *logger_list, | ||
275 | log_id_t logId) | ||
276 | { | ||
277 | struct android_log_logger_list *logger_list_internal = | ||
278 | (struct android_log_logger_list *)logger_list; | ||
279 | struct android_log_logger *logger; | ||
280 | |||
281 | if (!logger_list_internal || (logId >= LOG_ID_MAX)) { | ||
282 | goto err; | ||
283 | } | ||
284 | |||
285 | logger_for_each(logger, logger_list_internal) { | ||
286 | if (logger->logId == logId) { | ||
287 | goto ok; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | logger = calloc(1, sizeof(*logger)); | ||
292 | if (!logger) { | ||
293 | goto err; | ||
294 | } | ||
295 | |||
296 | logger->logId = logId; | ||
297 | list_add_tail(&logger_list_internal->logger, &logger->node); | ||
298 | logger->parent = logger_list_internal; | ||
299 | |||
300 | /* Reset known transports to re-evaluate, we just added one */ | ||
301 | while (!list_empty(&logger_list_internal->transport)) { | ||
302 | struct listnode *node = list_head(&logger_list_internal->transport); | ||
303 | struct android_log_transport_context *transp = | ||
304 | node_to_item(node, struct android_log_transport_context, node); | ||
305 | |||
306 | list_remove(&transp->node); | ||
307 | free(transp); | ||
308 | } | ||
309 | goto ok; | ||
310 | |||
311 | err: | ||
312 | logger = NULL; | ||
313 | ok: | ||
314 | return (struct logger *)logger; | ||
315 | } | ||
316 | |||
317 | /* Open the single named log and make it part of a new logger list */ | ||
318 | LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open( | ||
319 | log_id_t logId, | ||
320 | int mode, | ||
321 | unsigned int tail, | ||
322 | pid_t pid) | ||
323 | { | ||
324 | struct logger_list *logger_list = | ||
325 | android_logger_list_alloc(mode, tail, pid); | ||
326 | |||
327 | if (!logger_list) { | ||
328 | return NULL; | ||
329 | } | ||
330 | |||
331 | if (!android_logger_open(logger_list, logId)) { | ||
332 | android_logger_list_free(logger_list); | ||
333 | return NULL; | ||
334 | } | ||
335 | |||
336 | return logger_list; | ||
337 | } | ||
338 | |||
339 | /* Read from the selected logs */ | ||
340 | LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list, | ||
341 | struct log_msg *log_msg) | ||
342 | { | ||
343 | struct android_log_transport_context *transp; | ||
344 | struct android_log_logger_list *logger_list_internal = | ||
345 | (struct android_log_logger_list *)logger_list; | ||
346 | |||
347 | int ret = init_transport_context(logger_list_internal); | ||
348 | if (ret < 0) { | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | /* at least one transport */ | ||
353 | transp = node_to_item(logger_list_internal->transport.next, | ||
354 | struct android_log_transport_context, node); | ||
355 | |||
356 | /* more than one transport? */ | ||
357 | if (transp->node.next != &logger_list_internal->transport) { | ||
358 | /* Poll and merge sort the entries if from multiple transports */ | ||
359 | struct android_log_transport_context *oldest = NULL; | ||
360 | int ret; | ||
361 | int polled = 0; | ||
362 | do { | ||
363 | if (polled) { | ||
364 | sched_yield(); | ||
365 | } | ||
366 | ret = -1000; | ||
367 | polled = 0; | ||
368 | do { | ||
369 | int retval = transp->ret; | ||
370 | if ((retval > 0) && !transp->logMsg.entry.len) { | ||
371 | if (!transp->transport->read) { | ||
372 | retval = transp->ret = 0; | ||
373 | } else if ((logger_list_internal->mode & | ||
374 | ANDROID_LOG_NONBLOCK) || | ||
375 | !transp->transport->poll) { | ||
376 | retval = transp->ret = (*transp->transport->read)( | ||
377 | logger_list_internal, | ||
378 | transp, | ||
379 | &transp->logMsg); | ||
380 | } else { | ||
381 | int pollval = (*transp->transport->poll)( | ||
382 | logger_list_internal, transp); | ||
383 | if (pollval <= 0) { | ||
384 | sched_yield(); | ||
385 | pollval = (*transp->transport->poll)( | ||
386 | logger_list_internal, transp); | ||
387 | } | ||
388 | polled = 1; | ||
389 | if (pollval < 0) { | ||
390 | if ((pollval == -EINTR) || (pollval == -EAGAIN)) { | ||
391 | return -EAGAIN; | ||
392 | } | ||
393 | retval = transp->ret = pollval; | ||
394 | } else if (pollval > 0) { | ||
395 | retval = transp->ret = (*transp->transport->read)( | ||
396 | logger_list_internal, | ||
397 | transp, | ||
398 | &transp->logMsg); | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | if (ret < retval) { | ||
403 | ret = retval; | ||
404 | } | ||
405 | if ((transp->ret > 0) && transp->logMsg.entry.len && | ||
406 | (!oldest || | ||
407 | (oldest->logMsg.entry.sec > | ||
408 | transp->logMsg.entry.sec) || | ||
409 | ((oldest->logMsg.entry.sec == | ||
410 | transp->logMsg.entry.sec) && | ||
411 | (oldest->logMsg.entry.nsec > | ||
412 | transp->logMsg.entry.nsec)))) { | ||
413 | oldest = transp; | ||
414 | } | ||
415 | transp = node_to_item(transp->node.next, | ||
416 | struct android_log_transport_context, | ||
417 | node); | ||
418 | } while (transp != node_to_item( | ||
419 | &logger_list_internal->transport, | ||
420 | struct android_log_transport_context, | ||
421 | node)); | ||
422 | if (!oldest && | ||
423 | (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) { | ||
424 | return (ret < 0) ? ret : -EAGAIN; | ||
425 | } | ||
426 | transp = node_to_item(logger_list_internal->transport.next, | ||
427 | struct android_log_transport_context, node); | ||
428 | } while (!oldest && (ret > 0)); | ||
429 | if (!oldest) { | ||
430 | return ret; | ||
431 | } | ||
432 | memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len + | ||
433 | (oldest->logMsg.entry.hdr_size ? | ||
434 | oldest->logMsg.entry.hdr_size : | ||
435 | sizeof(struct logger_entry))); | ||
436 | oldest->logMsg.entry.len = 0; /* Mark it as copied */ | ||
437 | return oldest->ret; | ||
438 | } | ||
439 | |||
440 | /* if only one, no need to copy into transport_context and merge-sort */ | ||
441 | return (transp->transport->read)(logger_list_internal, transp, log_msg); | ||
442 | } | ||
443 | |||
444 | /* Close all the logs */ | ||
445 | LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list) | ||
446 | { | ||
447 | struct android_log_logger_list *logger_list_internal = | ||
448 | (struct android_log_logger_list *)logger_list; | ||
449 | |||
450 | if (logger_list_internal == NULL) { | ||
451 | return; | ||
452 | } | ||
453 | |||
454 | while (!list_empty(&logger_list_internal->transport)) { | ||
455 | struct listnode *node = list_head(&logger_list_internal->transport); | ||
456 | struct android_log_transport_context *transp = | ||
457 | node_to_item(node, struct android_log_transport_context, node); | ||
458 | |||
459 | if (transp->transport && transp->transport->close) { | ||
460 | (*transp->transport->close)(logger_list_internal, transp); | ||
461 | } | ||
462 | list_remove(&transp->node); | ||
463 | free(transp); | ||
464 | } | ||
465 | |||
466 | while (!list_empty(&logger_list_internal->logger)) { | ||
467 | struct listnode *node = list_head(&logger_list_internal->logger); | ||
468 | struct android_log_logger *logger = | ||
469 | node_to_item(node, struct android_log_logger, node); | ||
470 | android_logger_free((struct logger *)logger); | ||
471 | } | ||
472 | |||
473 | free(logger_list_internal); | ||
474 | } | ||
diff --git a/liblog/logd_write.c b/liblog/logger_write.c index 85a4aab52..a4155e927 100644 --- a/liblog/logd_write.c +++ b/liblog/logger_write.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007-2014 The Android Open Source Project | 2 | * Copyright (C) 2007-2016 The Android Open Source Project |
3 | * | 3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
@@ -13,27 +13,12 @@ | |||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | #if (FAKE_LOG_DEVICE == 0) | 16 | |
17 | #include <endian.h> | ||
18 | #endif | ||
19 | #include <errno.h> | 17 | #include <errno.h> |
20 | #include <fcntl.h> | ||
21 | #if !defined(_WIN32) | ||
22 | #include <pthread.h> | ||
23 | #endif | ||
24 | #include <stdarg.h> | ||
25 | #include <stdatomic.h> | 18 | #include <stdatomic.h> |
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> | 19 | #include <stdlib.h> |
28 | #include <string.h> | 20 | #include <string.h> |
29 | #include <sys/stat.h> | 21 | #include <sys/time.h> |
30 | #include <sys/types.h> | ||
31 | #if (FAKE_LOG_DEVICE == 0) | ||
32 | #include <sys/socket.h> | ||
33 | #include <sys/un.h> | ||
34 | #endif | ||
35 | #include <time.h> | ||
36 | #include <unistd.h> | ||
37 | 22 | ||
38 | #ifdef __BIONIC__ | 23 | #ifdef __BIONIC__ |
39 | #include <android/set_abort_message.h> | 24 | #include <android/set_abort_message.h> |
@@ -46,55 +31,15 @@ | |||
46 | #include <private/android_filesystem_config.h> | 31 | #include <private/android_filesystem_config.h> |
47 | #include <private/android_logger.h> | 32 | #include <private/android_logger.h> |
48 | 33 | ||
49 | #include "log_cdefs.h" | 34 | #include "config_write.h" |
35 | #include "log_portability.h" | ||
36 | #include "logger.h" | ||
50 | 37 | ||
51 | #define LOG_BUF_SIZE 1024 | 38 | #define LOG_BUF_SIZE 1024 |
52 | 39 | ||
53 | #if FAKE_LOG_DEVICE | ||
54 | /* This will be defined when building for the host. */ | ||
55 | #include "fake_log_device.h" | ||
56 | #endif | ||
57 | |||
58 | static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); | 40 | static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); |
59 | static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; | 41 | static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; |
60 | 42 | ||
61 | #if !defined(_WIN32) | ||
62 | static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; | ||
63 | |||
64 | static void lock() | ||
65 | { | ||
66 | /* | ||
67 | * If we trigger a signal handler in the middle of locked activity and the | ||
68 | * signal handler logs a message, we could get into a deadlock state. | ||
69 | */ | ||
70 | pthread_mutex_lock(&log_init_lock); | ||
71 | } | ||
72 | |||
73 | static int trylock() | ||
74 | { | ||
75 | return pthread_mutex_trylock(&log_init_lock); | ||
76 | } | ||
77 | |||
78 | static void unlock() | ||
79 | { | ||
80 | pthread_mutex_unlock(&log_init_lock); | ||
81 | } | ||
82 | |||
83 | #else /* !defined(_WIN32) */ | ||
84 | |||
85 | #define lock() ((void)0) | ||
86 | #define trylock() (0) /* success */ | ||
87 | #define unlock() ((void)0) | ||
88 | |||
89 | #endif /* !defined(_WIN32) */ | ||
90 | |||
91 | #if FAKE_LOG_DEVICE | ||
92 | static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 }; | ||
93 | #else | ||
94 | static int logd_fd = -1; | ||
95 | static int pstore_fd = -1; | ||
96 | #endif | ||
97 | |||
98 | /* | 43 | /* |
99 | * This is used by the C++ code to decide if it should write logs through | 44 | * This is used by the C++ code to decide if it should write logs through |
100 | * the C code. Basically, if /dev/socket/logd is available, we're running in | 45 | * the C code. Basically, if /dev/socket/logd is available, we're running in |
@@ -106,110 +51,101 @@ static enum { | |||
106 | 51 | ||
107 | LIBLOG_ABI_PUBLIC int __android_log_dev_available() | 52 | LIBLOG_ABI_PUBLIC int __android_log_dev_available() |
108 | { | 53 | { |
109 | if (g_log_status == kLogUninitialized) { | 54 | struct android_log_transport_write *node; |
110 | if (access("/dev/socket/logdw", W_OK) == 0) | 55 | size_t i; |
111 | g_log_status = kLogAvailable; | ||
112 | else | ||
113 | g_log_status = kLogNotAvailable; | ||
114 | } | ||
115 | 56 | ||
116 | return (g_log_status == kLogAvailable); | 57 | if (list_empty(&__android_log_transport_write)) { |
58 | return kLogUninitialized; | ||
59 | } | ||
60 | for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) { | ||
61 | write_transport_for_each(node, &__android_log_transport_write) { | ||
62 | if (node->write && | ||
63 | (!node->available || ((*node->available)(i) >= 0))) { | ||
64 | return kLogAvailable; | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | return kLogNotAvailable; | ||
117 | } | 69 | } |
118 | 70 | ||
119 | /* log_init_lock assumed */ | 71 | /* log_init_lock assumed */ |
120 | static int __write_to_log_initialize() | 72 | static int __write_to_log_initialize() |
121 | { | 73 | { |
122 | int i, ret = 0; | 74 | struct android_log_transport_write *transport; |
123 | 75 | struct listnode *n; | |
124 | #if FAKE_LOG_DEVICE | 76 | int i = 0, ret = 0; |
125 | for (i = 0; i < LOG_ID_MAX; i++) { | 77 | |
126 | char buf[sizeof("/dev/log_security")]; | 78 | __android_log_config_write(); |
127 | snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i)); | 79 | write_transport_for_each_safe(transport, n, &__android_log_transport_write) { |
128 | log_fds[i] = fakeLogOpen(buf, O_WRONLY); | 80 | if (!transport->open || ((*transport->open)() < 0)) { |
129 | } | 81 | if (transport->close) { |
130 | #else | 82 | (*transport->close)(); |
131 | if (pstore_fd < 0) { | 83 | } |
132 | pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY)); | 84 | list_remove(&transport->node); |
85 | continue; | ||
86 | } | ||
87 | ++ret; | ||
133 | } | 88 | } |
134 | 89 | write_transport_for_each_safe(transport, n, &__android_log_persist_write) { | |
135 | if (logd_fd < 0) { | 90 | if (!transport->open || ((*transport->open)() < 0)) { |
136 | i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)); | 91 | if (transport->close) { |
137 | if (i < 0) { | 92 | (*transport->close)(); |
138 | ret = -errno; | ||
139 | } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) { | ||
140 | ret = -errno; | ||
141 | close(i); | ||
142 | } else { | ||
143 | struct sockaddr_un un; | ||
144 | memset(&un, 0, sizeof(struct sockaddr_un)); | ||
145 | un.sun_family = AF_UNIX; | ||
146 | strcpy(un.sun_path, "/dev/socket/logdw"); | ||
147 | |||
148 | if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un, | ||
149 | sizeof(struct sockaddr_un))) < 0) { | ||
150 | ret = -errno; | ||
151 | close(i); | ||
152 | } else { | ||
153 | logd_fd = i; | ||
154 | } | 93 | } |
94 | list_remove(&transport->node); | ||
95 | continue; | ||
155 | } | 96 | } |
97 | ++i; | ||
98 | } | ||
99 | if (!ret && !i) { | ||
100 | return -ENODEV; | ||
156 | } | 101 | } |
157 | #endif | ||
158 | 102 | ||
159 | return ret; | 103 | return ret; |
160 | } | 104 | } |
161 | 105 | ||
162 | static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) | 106 | /* |
107 | * Extract a 4-byte value from a byte stream. le32toh open coded | ||
108 | */ | ||
109 | static inline uint32_t get4LE(const uint8_t* src) | ||
163 | { | 110 | { |
164 | ssize_t ret; | 111 | return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); |
165 | #if FAKE_LOG_DEVICE | 112 | } |
166 | int log_fd; | ||
167 | 113 | ||
168 | if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { | 114 | static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) |
169 | log_fd = log_fds[(int)log_id]; | 115 | { |
170 | } else { | 116 | struct android_log_transport_write *node; |
171 | return -EBADF; | 117 | int ret; |
172 | } | ||
173 | do { | ||
174 | ret = fakeLogWritev(log_fd, vec, nr); | ||
175 | if (ret < 0) { | ||
176 | ret = -errno; | ||
177 | } | ||
178 | } while (ret == -EINTR); | ||
179 | #else | ||
180 | static const unsigned header_length = 2; | ||
181 | struct iovec newVec[nr + header_length]; | ||
182 | android_log_header_t header; | ||
183 | android_pmsg_log_header_t pmsg_header; | ||
184 | struct timespec ts; | 118 | struct timespec ts; |
185 | size_t i, payload_size; | 119 | size_t len, i; |
186 | static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */ | ||
187 | static pid_t last_pid = (pid_t) -1; | ||
188 | static atomic_int_fast32_t dropped; | ||
189 | static atomic_int_fast32_t dropped_security; | ||
190 | 120 | ||
191 | if (!nr) { | 121 | for (len = i = 0; i < nr; ++i) { |
122 | len += vec[i].iov_len; | ||
123 | } | ||
124 | if (!len) { | ||
192 | return -EINVAL; | 125 | return -EINVAL; |
193 | } | 126 | } |
194 | 127 | ||
195 | if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */ | 128 | #if defined(__BIONIC__) |
196 | last_uid = getuid(); | ||
197 | } | ||
198 | if (last_pid == (pid_t) -1) { | ||
199 | last_pid = getpid(); | ||
200 | } | ||
201 | if (log_id == LOG_ID_SECURITY) { | 129 | if (log_id == LOG_ID_SECURITY) { |
130 | uid_t uid; | ||
131 | |||
202 | if (vec[0].iov_len < 4) { | 132 | if (vec[0].iov_len < 4) { |
203 | return -EINVAL; | 133 | return -EINVAL; |
204 | } | 134 | } |
135 | |||
136 | uid = __android_log_uid(); | ||
205 | /* Matches clientHasLogCredentials() in logd */ | 137 | /* Matches clientHasLogCredentials() in logd */ |
206 | if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT) && (last_uid != AID_LOG)) { | 138 | if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) { |
207 | uid_t uid = geteuid(); | 139 | uid = geteuid(); |
208 | if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) { | 140 | if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) { |
209 | gid_t gid = getgid(); | 141 | gid_t gid = getgid(); |
210 | if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) { | 142 | if ((gid != AID_SYSTEM) && |
143 | (gid != AID_ROOT) && | ||
144 | (gid != AID_LOG)) { | ||
211 | gid = getegid(); | 145 | gid = getegid(); |
212 | if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) { | 146 | if ((gid != AID_SYSTEM) && |
147 | (gid != AID_ROOT) && | ||
148 | (gid != AID_LOG)) { | ||
213 | int num_groups; | 149 | int num_groups; |
214 | gid_t *groups; | 150 | gid_t *groups; |
215 | 151 | ||
@@ -237,12 +173,11 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) | |||
237 | } | 173 | } |
238 | } | 174 | } |
239 | if (!__android_log_security()) { | 175 | if (!__android_log_security()) { |
240 | atomic_store(&dropped_security, 0); | 176 | /* If only we could reset downstream logd counter */ |
241 | return -EPERM; | 177 | return -EPERM; |
242 | } | 178 | } |
243 | } else if (log_id == LOG_ID_EVENTS) { | 179 | } else if (log_id == LOG_ID_EVENTS) { |
244 | static atomic_uintptr_t map; | 180 | static atomic_uintptr_t map; |
245 | int ret; | ||
246 | const char *tag; | 181 | const char *tag; |
247 | EventTagMap *m, *f; | 182 | EventTagMap *m, *f; |
248 | 183 | ||
@@ -255,7 +190,7 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) | |||
255 | m = (EventTagMap *)atomic_load(&map); | 190 | m = (EventTagMap *)atomic_load(&map); |
256 | 191 | ||
257 | if (!m) { | 192 | if (!m) { |
258 | ret = trylock(); | 193 | ret = __android_log_trylock(); |
259 | m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */ | 194 | m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */ |
260 | if (!m) { | 195 | if (!m) { |
261 | m = android_openEventTagMap(EVENT_TAG_MAP_FILE); | 196 | m = android_openEventTagMap(EVENT_TAG_MAP_FILE); |
@@ -269,13 +204,11 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) | |||
269 | } | 204 | } |
270 | } | 205 | } |
271 | if (!ret) { /* trylock succeeded, unlock */ | 206 | if (!ret) { /* trylock succeeded, unlock */ |
272 | unlock(); | 207 | __android_log_unlock(); |
273 | } | 208 | } |
274 | } | 209 | } |
275 | if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) { | 210 | if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) { |
276 | tag = android_lookupEventTag( | 211 | tag = android_lookupEventTag(m, get4LE(vec[0].iov_base)); |
277 | m, | ||
278 | htole32(((uint32_t *)vec[0].iov_base)[0])); | ||
279 | } | 212 | } |
280 | ret = __android_log_is_loggable(ANDROID_LOG_INFO, | 213 | ret = __android_log_is_loggable(ANDROID_LOG_INFO, |
281 | tag, | 214 | tag, |
@@ -317,203 +250,57 @@ static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr) | |||
317 | } | 250 | } |
318 | } | 251 | } |
319 | 252 | ||
320 | /* | ||
321 | * struct { | ||
322 | * // what we provide to pstore | ||
323 | * android_pmsg_log_header_t pmsg_header; | ||
324 | * // what we provide to socket | ||
325 | * android_log_header_t header; | ||
326 | * // caller provides | ||
327 | * union { | ||
328 | * struct { | ||
329 | * char prio; | ||
330 | * char payload[]; | ||
331 | * } string; | ||
332 | * struct { | ||
333 | * uint32_t tag | ||
334 | * char payload[]; | ||
335 | * } binary; | ||
336 | * }; | ||
337 | * }; | ||
338 | */ | ||
339 | |||
340 | clock_gettime(android_log_clockid(), &ts); | 253 | clock_gettime(android_log_clockid(), &ts); |
341 | 254 | #else | |
342 | pmsg_header.magic = LOGGER_MAGIC; | 255 | /* simulate clock_gettime(CLOCK_REALTIME, &ts); */ |
343 | pmsg_header.len = sizeof(pmsg_header) + sizeof(header); | 256 | { |
344 | pmsg_header.uid = last_uid; | 257 | struct timeval tv; |
345 | pmsg_header.pid = last_pid; | 258 | gettimeofday(&tv, NULL); |
346 | 259 | ts.tv_sec = tv.tv_sec; | |
347 | header.tid = gettid(); | 260 | ts.tv_nsec = tv.tv_usec * 1000; |
348 | header.realtime.tv_sec = ts.tv_sec; | ||
349 | header.realtime.tv_nsec = ts.tv_nsec; | ||
350 | |||
351 | newVec[0].iov_base = (unsigned char *) &pmsg_header; | ||
352 | newVec[0].iov_len = sizeof(pmsg_header); | ||
353 | newVec[1].iov_base = (unsigned char *) &header; | ||
354 | newVec[1].iov_len = sizeof(header); | ||
355 | |||
356 | if (logd_fd > 0) { | ||
357 | int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0, | ||
358 | memory_order_relaxed); | ||
359 | if (snapshot) { | ||
360 | android_log_event_int_t buffer; | ||
361 | |||
362 | header.id = LOG_ID_SECURITY; | ||
363 | buffer.header.tag = htole32(LIBLOG_LOG_TAG); | ||
364 | buffer.payload.type = EVENT_TYPE_INT; | ||
365 | buffer.payload.data = htole32(snapshot); | ||
366 | |||
367 | newVec[2].iov_base = &buffer; | ||
368 | newVec[2].iov_len = sizeof(buffer); | ||
369 | |||
370 | ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2)); | ||
371 | if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) { | ||
372 | atomic_fetch_add_explicit(&dropped_security, snapshot, | ||
373 | memory_order_relaxed); | ||
374 | } | ||
375 | } | ||
376 | snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed); | ||
377 | if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO, | ||
378 | "liblog", | ||
379 | ANDROID_LOG_VERBOSE)) { | ||
380 | android_log_event_int_t buffer; | ||
381 | |||
382 | header.id = LOG_ID_EVENTS; | ||
383 | buffer.header.tag = htole32(LIBLOG_LOG_TAG); | ||
384 | buffer.payload.type = EVENT_TYPE_INT; | ||
385 | buffer.payload.data = htole32(snapshot); | ||
386 | |||
387 | newVec[2].iov_base = &buffer; | ||
388 | newVec[2].iov_len = sizeof(buffer); | ||
389 | |||
390 | ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2)); | ||
391 | if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) { | ||
392 | atomic_fetch_add_explicit(&dropped, snapshot, | ||
393 | memory_order_relaxed); | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | |||
398 | header.id = log_id; | ||
399 | |||
400 | for (payload_size = 0, i = header_length; i < nr + header_length; i++) { | ||
401 | newVec[i].iov_base = vec[i - header_length].iov_base; | ||
402 | payload_size += newVec[i].iov_len = vec[i - header_length].iov_len; | ||
403 | |||
404 | if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) { | ||
405 | newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD; | ||
406 | if (newVec[i].iov_len) { | ||
407 | ++i; | ||
408 | } | ||
409 | payload_size = LOGGER_ENTRY_MAX_PAYLOAD; | ||
410 | break; | ||
411 | } | ||
412 | } | ||
413 | pmsg_header.len += payload_size; | ||
414 | |||
415 | if (pstore_fd >= 0) { | ||
416 | TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i)); | ||
417 | } | ||
418 | |||
419 | if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */ | ||
420 | /* | ||
421 | * ignore log messages we send to ourself (logd). | ||
422 | * Such log messages are often generated by libraries we depend on | ||
423 | * which use standard Android logging. | ||
424 | */ | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | if (logd_fd < 0) { | ||
429 | return -EBADF; | ||
430 | } | 261 | } |
262 | #endif | ||
431 | 263 | ||
432 | /* | 264 | ret = 0; |
433 | * The write below could be lost, but will never block. | 265 | write_transport_for_each(node, &__android_log_transport_write) { |
434 | * | 266 | if (node->write) { |
435 | * To logd, we drop the pmsg_header | 267 | ssize_t retval; |
436 | * | 268 | retval = (*node->write)(log_id, &ts, vec, nr); |
437 | * ENOTCONN occurs if logd dies. | 269 | if (ret >= 0) { |
438 | * EAGAIN occurs if logd is overloaded. | 270 | ret = retval; |
439 | */ | ||
440 | ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1)); | ||
441 | if (ret < 0) { | ||
442 | ret = -errno; | ||
443 | if (ret == -ENOTCONN) { | ||
444 | lock(); | ||
445 | close(logd_fd); | ||
446 | logd_fd = -1; | ||
447 | ret = __write_to_log_initialize(); | ||
448 | unlock(); | ||
449 | |||
450 | if (ret < 0) { | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1)); | ||
455 | if (ret < 0) { | ||
456 | ret = -errno; | ||
457 | } | 271 | } |
458 | } | 272 | } |
459 | } | 273 | } |
460 | 274 | ||
461 | if (ret > (ssize_t)sizeof(header)) { | 275 | write_transport_for_each(node, &__android_log_persist_write) { |
462 | ret -= sizeof(header); | 276 | if (node->write) { |
463 | } else if (ret == -EAGAIN) { | 277 | (void)(*node->write)(log_id, &ts, vec, nr); |
464 | atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); | ||
465 | if (log_id == LOG_ID_SECURITY) { | ||
466 | atomic_fetch_add_explicit(&dropped_security, 1, | ||
467 | memory_order_relaxed); | ||
468 | } | 278 | } |
469 | } | 279 | } |
470 | #endif | ||
471 | 280 | ||
472 | return ret; | 281 | return ret; |
473 | } | 282 | } |
474 | 283 | ||
475 | #if FAKE_LOG_DEVICE | ||
476 | static const char *LOG_NAME[LOG_ID_MAX] = { | ||
477 | [LOG_ID_MAIN] = "main", | ||
478 | [LOG_ID_RADIO] = "radio", | ||
479 | [LOG_ID_EVENTS] = "events", | ||
480 | [LOG_ID_SYSTEM] = "system", | ||
481 | [LOG_ID_CRASH] = "crash", | ||
482 | [LOG_ID_SECURITY] = "security", | ||
483 | [LOG_ID_KERNEL] = "kernel", | ||
484 | }; | ||
485 | |||
486 | LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id) | ||
487 | { | ||
488 | if (log_id >= LOG_ID_MAX) { | ||
489 | log_id = LOG_ID_MAIN; | ||
490 | } | ||
491 | return LOG_NAME[log_id]; | ||
492 | } | ||
493 | #endif | ||
494 | |||
495 | static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) | 284 | static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) |
496 | { | 285 | { |
497 | lock(); | 286 | __android_log_lock(); |
498 | 287 | ||
499 | if (write_to_log == __write_to_log_init) { | 288 | if (write_to_log == __write_to_log_init) { |
500 | int ret; | 289 | int ret; |
501 | 290 | ||
502 | ret = __write_to_log_initialize(); | 291 | ret = __write_to_log_initialize(); |
503 | if (ret < 0) { | 292 | if (ret < 0) { |
504 | unlock(); | 293 | __android_log_unlock(); |
505 | #if (FAKE_LOG_DEVICE == 0) | 294 | if (!list_empty(&__android_log_persist_write)) { |
506 | if (pstore_fd >= 0) { | ||
507 | __write_to_log_daemon(log_id, vec, nr); | 295 | __write_to_log_daemon(log_id, vec, nr); |
508 | } | 296 | } |
509 | #endif | ||
510 | return ret; | 297 | return ret; |
511 | } | 298 | } |
512 | 299 | ||
513 | write_to_log = __write_to_log_daemon; | 300 | write_to_log = __write_to_log_daemon; |
514 | } | 301 | } |
515 | 302 | ||
516 | unlock(); | 303 | __android_log_unlock(); |
517 | 304 | ||
518 | return write_to_log(log_id, vec, nr); | 305 | return write_to_log(log_id, vec, nr); |
519 | } | 306 | } |
@@ -603,10 +390,8 @@ LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio, | |||
603 | return __android_log_buf_write(bufID, prio, tag, buf); | 390 | return __android_log_buf_write(bufID, prio, tag, buf); |
604 | } | 391 | } |
605 | 392 | ||
606 | LIBLOG_ABI_PUBLIC void __android_log_assert( | 393 | LIBLOG_ABI_PUBLIC void __android_log_assert(const char *cond, const char *tag, |
607 | const char *cond, | 394 | const char *fmt, ...) |
608 | const char *tag, | ||
609 | const char *fmt, ...) | ||
610 | { | 395 | { |
611 | char buf[LOG_BUF_SIZE]; | 396 | char buf[LOG_BUF_SIZE]; |
612 | 397 | ||
diff --git a/liblog/logprint.c b/liblog/logprint.c index 02df8ddd6..d7de8648b 100644 --- a/liblog/logprint.c +++ b/liblog/logprint.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <log/logprint.h> | 34 | #include <log/logprint.h> |
35 | #include <private/android_filesystem_config.h> | 35 | #include <private/android_filesystem_config.h> |
36 | 36 | ||
37 | #include "log_cdefs.h" | 37 | #include "log_portability.h" |
38 | 38 | ||
39 | #define MS_PER_NSEC 1000000 | 39 | #define MS_PER_NSEC 1000000 |
40 | #define US_PER_NSEC 1000 | 40 | #define US_PER_NSEC 1000 |
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c new file mode 100644 index 000000000..de435f7ed --- /dev/null +++ b/liblog/pmsg_reader.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2016 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 <fcntl.h> | ||
19 | #include <stdbool.h> | ||
20 | #include <string.h> | ||
21 | #include <sys/types.h> | ||
22 | |||
23 | #include <private/android_filesystem_config.h> | ||
24 | #include <private/android_logger.h> | ||
25 | |||
26 | #include "config_read.h" | ||
27 | #include "logger.h" | ||
28 | |||
29 | static int pmsgAvailable(log_id_t logId); | ||
30 | static int pmsgVersion(struct android_log_logger *logger, | ||
31 | struct android_log_transport_context *transp); | ||
32 | static int pmsgRead(struct android_log_logger_list *logger_list, | ||
33 | struct android_log_transport_context *transp, | ||
34 | struct log_msg *log_msg); | ||
35 | static void pmsgClose(struct android_log_logger_list *logger_list, | ||
36 | struct android_log_transport_context *transp); | ||
37 | static int pmsgClear(struct android_log_logger *logger, | ||
38 | struct android_log_transport_context *transp); | ||
39 | |||
40 | LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = { | ||
41 | .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node }, | ||
42 | .name = "pmsg", | ||
43 | .available = pmsgAvailable, | ||
44 | .version = pmsgVersion, | ||
45 | .read = pmsgRead, | ||
46 | .poll = NULL, | ||
47 | .close = pmsgClose, | ||
48 | .clear = pmsgClear, | ||
49 | .setSize = NULL, | ||
50 | .getSize = NULL, | ||
51 | .getReadableSize = NULL, | ||
52 | .getPrune = NULL, | ||
53 | .setPrune = NULL, | ||
54 | .getStats = NULL, | ||
55 | }; | ||
56 | |||
57 | static int pmsgAvailable(log_id_t logId) | ||
58 | { | ||
59 | if (logId > LOG_ID_SECURITY) { | ||
60 | return -EINVAL; | ||
61 | } | ||
62 | if (access("/dev/pmsg0", W_OK) == 0) { | ||
63 | return 0; | ||
64 | } | ||
65 | return -EBADF; | ||
66 | } | ||
67 | |||
68 | /* Determine the credentials of the caller */ | ||
69 | static bool uid_has_log_permission(uid_t uid) | ||
70 | { | ||
71 | return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT); | ||
72 | } | ||
73 | |||
74 | static uid_t get_best_effective_uid() | ||
75 | { | ||
76 | uid_t euid; | ||
77 | uid_t uid; | ||
78 | gid_t gid; | ||
79 | ssize_t i; | ||
80 | static uid_t last_uid = (uid_t) -1; | ||
81 | |||
82 | if (last_uid != (uid_t) -1) { | ||
83 | return last_uid; | ||
84 | } | ||
85 | uid = __android_log_uid(); | ||
86 | if (uid_has_log_permission(uid)) { | ||
87 | return last_uid = uid; | ||
88 | } | ||
89 | euid = geteuid(); | ||
90 | if (uid_has_log_permission(euid)) { | ||
91 | return last_uid = euid; | ||
92 | } | ||
93 | gid = getgid(); | ||
94 | if (uid_has_log_permission(gid)) { | ||
95 | return last_uid = gid; | ||
96 | } | ||
97 | gid = getegid(); | ||
98 | if (uid_has_log_permission(gid)) { | ||
99 | return last_uid = gid; | ||
100 | } | ||
101 | i = getgroups((size_t) 0, NULL); | ||
102 | if (i > 0) { | ||
103 | gid_t list[i]; | ||
104 | |||
105 | getgroups(i, list); | ||
106 | while (--i >= 0) { | ||
107 | if (uid_has_log_permission(list[i])) { | ||
108 | return last_uid = list[i]; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | return last_uid = uid; | ||
113 | } | ||
114 | |||
115 | static int pmsgClear(struct android_log_logger *logger __unused, | ||
116 | struct android_log_transport_context *transp __unused) | ||
117 | { | ||
118 | if (uid_has_log_permission(get_best_effective_uid())) { | ||
119 | return unlink("/sys/fs/pstore/pmsg-ramoops-0"); | ||
120 | } | ||
121 | errno = EPERM; | ||
122 | return -1; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * returns the logger version | ||
127 | */ | ||
128 | static int pmsgVersion(struct android_log_logger *logger __unused, | ||
129 | struct android_log_transport_context *transp __unused) | ||
130 | { | ||
131 | return 4; | ||
132 | } | ||
133 | |||
134 | static int pmsgRead(struct android_log_logger_list *logger_list, | ||
135 | struct android_log_transport_context *transp, | ||
136 | struct log_msg *log_msg) | ||
137 | { | ||
138 | ssize_t ret; | ||
139 | off_t current, next; | ||
140 | uid_t uid; | ||
141 | struct android_log_logger *logger; | ||
142 | struct __attribute__((__packed__)) { | ||
143 | android_pmsg_log_header_t p; | ||
144 | android_log_header_t l; | ||
145 | } buf; | ||
146 | static uint8_t preread_count; | ||
147 | bool is_system; | ||
148 | |||
149 | memset(log_msg, 0, sizeof(*log_msg)); | ||
150 | |||
151 | if (transp->context.fd <= 0) { | ||
152 | int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); | ||
153 | |||
154 | if (fd < 0) { | ||
155 | return -errno; | ||
156 | } | ||
157 | if (fd == 0) { /* Argggg */ | ||
158 | fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); | ||
159 | close(0); | ||
160 | if (fd < 0) { | ||
161 | return -errno; | ||
162 | } | ||
163 | } | ||
164 | transp->context.fd = fd; | ||
165 | preread_count = 0; | ||
166 | } | ||
167 | |||
168 | while(1) { | ||
169 | if (preread_count < sizeof(buf)) { | ||
170 | ret = TEMP_FAILURE_RETRY(read(transp->context.fd, | ||
171 | &buf.p.magic + preread_count, | ||
172 | sizeof(buf) - preread_count)); | ||
173 | if (ret < 0) { | ||
174 | return -errno; | ||
175 | } | ||
176 | preread_count += ret; | ||
177 | } | ||
178 | if (preread_count != sizeof(buf)) { | ||
179 | return preread_count ? -EIO : -EAGAIN; | ||
180 | } | ||
181 | if ((buf.p.magic != LOGGER_MAGIC) | ||
182 | || (buf.p.len <= sizeof(buf)) | ||
183 | || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) | ||
184 | || (buf.l.id >= LOG_ID_MAX) | ||
185 | || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) { | ||
186 | do { | ||
187 | memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count); | ||
188 | } while (preread_count && (buf.p.magic != LOGGER_MAGIC)); | ||
189 | continue; | ||
190 | } | ||
191 | preread_count = 0; | ||
192 | |||
193 | if ((transp->logMask & (1 << buf.l.id)) && | ||
194 | ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) || | ||
195 | ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) && | ||
196 | ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) || | ||
197 | (logger_list->start.tv_nsec <= | ||
198 | buf.l.realtime.tv_nsec)))) && | ||
199 | (!logger_list->pid || (logger_list->pid == buf.p.pid))) { | ||
200 | uid = get_best_effective_uid(); | ||
201 | is_system = uid_has_log_permission(uid); | ||
202 | if (is_system || (uid == buf.p.uid)) { | ||
203 | ret = TEMP_FAILURE_RETRY(read(transp->context.fd, | ||
204 | is_system ? | ||
205 | log_msg->entry_v4.msg : | ||
206 | log_msg->entry_v3.msg, | ||
207 | buf.p.len - sizeof(buf))); | ||
208 | if (ret < 0) { | ||
209 | return -errno; | ||
210 | } | ||
211 | if (ret != (ssize_t)(buf.p.len - sizeof(buf))) { | ||
212 | return -EIO; | ||
213 | } | ||
214 | |||
215 | log_msg->entry_v4.len = buf.p.len - sizeof(buf); | ||
216 | log_msg->entry_v4.hdr_size = is_system ? | ||
217 | sizeof(log_msg->entry_v4) : | ||
218 | sizeof(log_msg->entry_v3); | ||
219 | log_msg->entry_v4.pid = buf.p.pid; | ||
220 | log_msg->entry_v4.tid = buf.l.tid; | ||
221 | log_msg->entry_v4.sec = buf.l.realtime.tv_sec; | ||
222 | log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec; | ||
223 | log_msg->entry_v4.lid = buf.l.id; | ||
224 | if (is_system) { | ||
225 | log_msg->entry_v4.uid = buf.p.uid; | ||
226 | } | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | current = TEMP_FAILURE_RETRY(lseek(transp->context.fd, | ||
233 | (off_t)0, SEEK_CUR)); | ||
234 | if (current < 0) { | ||
235 | return -errno; | ||
236 | } | ||
237 | next = TEMP_FAILURE_RETRY(lseek(transp->context.fd, | ||
238 | (off_t)(buf.p.len - sizeof(buf)), | ||
239 | SEEK_CUR)); | ||
240 | if (next < 0) { | ||
241 | return -errno; | ||
242 | } | ||
243 | if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) { | ||
244 | return -EIO; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static void pmsgClose(struct android_log_logger_list *logger_list __unused, | ||
250 | struct android_log_transport_context *transp) { | ||
251 | if (transp->context.fd > 0) { | ||
252 | close (transp->context.fd); | ||
253 | } | ||
254 | transp->context.fd = 0; | ||
255 | } | ||
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c new file mode 100644 index 000000000..7a89e5d54 --- /dev/null +++ b/liblog/pmsg_writer.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2016 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 | * pmsg write handler | ||
19 | */ | ||
20 | |||
21 | #include <errno.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <time.h> | ||
27 | |||
28 | #include <log/log.h> | ||
29 | #include <log/logger.h> | ||
30 | |||
31 | #include <private/android_filesystem_config.h> | ||
32 | #include <private/android_logger.h> | ||
33 | |||
34 | #include "config_write.h" | ||
35 | #include "log_portability.h" | ||
36 | #include "logger.h" | ||
37 | |||
38 | static int pmsgOpen(); | ||
39 | static void pmsgClose(); | ||
40 | static int pmsgAvailable(log_id_t logId); | ||
41 | static int pmsgWrite(log_id_t logId, struct timespec *ts, | ||
42 | struct iovec *vec, size_t nr); | ||
43 | |||
44 | LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = { | ||
45 | .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node }, | ||
46 | .context.fd = -1, | ||
47 | .name = "pmsg", | ||
48 | .available = pmsgAvailable, | ||
49 | .open = pmsgOpen, | ||
50 | .close = pmsgClose, | ||
51 | .write = pmsgWrite, | ||
52 | }; | ||
53 | |||
54 | static int pmsgOpen() | ||
55 | { | ||
56 | if (pmsgLoggerWrite.context.fd < 0) { | ||
57 | pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY)); | ||
58 | } | ||
59 | |||
60 | return pmsgLoggerWrite.context.fd; | ||
61 | } | ||
62 | |||
63 | static void pmsgClose() | ||
64 | { | ||
65 | if (pmsgLoggerWrite.context.fd >= 0) { | ||
66 | close(pmsgLoggerWrite.context.fd); | ||
67 | pmsgLoggerWrite.context.fd = -1; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static int pmsgAvailable(log_id_t logId) | ||
72 | { | ||
73 | if (logId > LOG_ID_SECURITY) { | ||
74 | return -EINVAL; | ||
75 | } | ||
76 | if (pmsgLoggerWrite.context.fd < 0) { | ||
77 | if (access("/dev/pmsg0", W_OK) == 0) { | ||
78 | return 0; | ||
79 | } | ||
80 | return -EBADF; | ||
81 | } | ||
82 | return 1; | ||
83 | } | ||
84 | |||
85 | static int pmsgWrite(log_id_t logId, struct timespec *ts, | ||
86 | struct iovec *vec, size_t nr) | ||
87 | { | ||
88 | static const unsigned headerLength = 2; | ||
89 | struct iovec newVec[nr + headerLength]; | ||
90 | android_log_header_t header; | ||
91 | android_pmsg_log_header_t pmsgHeader; | ||
92 | size_t i, payloadSize; | ||
93 | ssize_t ret; | ||
94 | |||
95 | if (pmsgLoggerWrite.context.fd < 0) { | ||
96 | return -EBADF; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * struct { | ||
101 | * // what we provide to pstore | ||
102 | * android_pmsg_log_header_t pmsgHeader; | ||
103 | * // what we provide to file | ||
104 | * android_log_header_t header; | ||
105 | * // caller provides | ||
106 | * union { | ||
107 | * struct { | ||
108 | * char prio; | ||
109 | * char payload[]; | ||
110 | * } string; | ||
111 | * struct { | ||
112 | * uint32_t tag | ||
113 | * char payload[]; | ||
114 | * } binary; | ||
115 | * }; | ||
116 | * }; | ||
117 | */ | ||
118 | |||
119 | pmsgHeader.magic = LOGGER_MAGIC; | ||
120 | pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header); | ||
121 | pmsgHeader.uid = __android_log_uid(); | ||
122 | pmsgHeader.pid = __android_log_pid(); | ||
123 | |||
124 | header.id = logId; | ||
125 | header.tid = gettid(); | ||
126 | header.realtime.tv_sec = ts->tv_sec; | ||
127 | header.realtime.tv_nsec = ts->tv_nsec; | ||
128 | |||
129 | newVec[0].iov_base = (unsigned char *)&pmsgHeader; | ||
130 | newVec[0].iov_len = sizeof(pmsgHeader); | ||
131 | newVec[1].iov_base = (unsigned char *)&header; | ||
132 | newVec[1].iov_len = sizeof(header); | ||
133 | |||
134 | for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) { | ||
135 | newVec[i].iov_base = vec[i - headerLength].iov_base; | ||
136 | payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len; | ||
137 | |||
138 | if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) { | ||
139 | newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD; | ||
140 | if (newVec[i].iov_len) { | ||
141 | ++i; | ||
142 | } | ||
143 | payloadSize = LOGGER_ENTRY_MAX_PAYLOAD; | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | pmsgHeader.len += payloadSize; | ||
148 | |||
149 | ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i)); | ||
150 | if (ret < 0) { | ||
151 | ret = errno ? -errno : -ENOTCONN; | ||
152 | } | ||
153 | |||
154 | if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) { | ||
155 | ret -= sizeof(header) - sizeof(pmsgHeader); | ||
156 | } | ||
157 | |||
158 | return ret; | ||
159 | } | ||
diff --git a/liblog/uio.c b/liblog/uio.c index d0184dc90..ac0558f3f 100644 --- a/liblog/uio.c +++ b/liblog/uio.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | #include <log/uio.h> | 21 | #include <log/uio.h> |
22 | 22 | ||
23 | #include "log_cdefs.h" | 23 | #include "log_portability.h" |
24 | 24 | ||
25 | LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count) | 25 | LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count) |
26 | { | 26 | { |