Loading logcat/logcat.cpp +71 −54 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <string> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <cutils/sched_policy.h> #include <cutils/sockets.h> Loading Loading @@ -109,29 +110,27 @@ static void rotateLogs() (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0; for (int i = g_maxRotatedLogs ; i > 0 ; i--) { char *file0, *file1; asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); std::string file1 = android::base::StringPrintf( "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); std::string file0; if (i - 1 == 0) { asprintf(&file0, "%s", g_outputFileName); file0 = android::base::StringPrintf("%s", g_outputFileName); } else { asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1); file0 = android::base::StringPrintf( "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1); } if (!file0 || !file1) { if ((file0.length() == 0) || (file1.length() == 0)) { perror("while rotating log files"); break; } err = rename(file0, file1); err = rename(file0.c_str(), file1.c_str()); if (err < 0 && errno != ENOENT) { perror("while rotating log files"); } free(file1); free(file0); } g_outFD = openLogFile(g_outputFileName); Loading Loading @@ -231,13 +230,15 @@ static void maybePrintStart(log_device_t* dev, bool printDividers) { } } static void setupOutput() { static void setupOutputAndSchedulingPolicy(bool blocking) { if (g_outputFileName == NULL) { g_outFD = STDOUT_FILENO; return; } } else { if (blocking) { // Lower priority and set to batch scheduling if we are saving // the logs into files and taking continuous content. if (set_sched_policy(0, SP_BACKGROUND) < 0) { fprintf(stderr, "failed to set background scheduling policy\n"); } Loading @@ -251,6 +252,7 @@ static void setupOutput() if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) { fprintf(stderr, "failed set to priority\n"); } } g_outFD = openLogFile (g_outputFileName); Loading @@ -271,7 +273,6 @@ static void setupOutput() g_outByteCount = statbuf.st_size; } } static void show_help(const char *cmd) { Loading @@ -284,6 +285,8 @@ static void show_help(const char *cmd) " Rotate log every kbytes. Requires -f option\n" " -n <count>, --rotate-count=<count>\n" " Sets max number of rotated logs to <count>, default 4\n" " --id=<id> If the signature id for logging to file changes, then clear\n" " the fileset and continue\n" " -v <format>, --format=<format>\n" " Sets log print format verb and adverbs, where <format> is:\n" " brief long process raw tag thread threadtime time\n" Loading Loading @@ -443,7 +446,7 @@ static char *parseTime(log_time &t, const char *cp) { return t.strptime(cp, "%s.%q"); } // Find last logged line in gestalt of all matching existing output files // Find last logged line in <outputFileName>, or <outputFileName>.1 static log_time lastLogTime(char *outputFileName) { log_time retval(log_time::EPOCH); if (!outputFileName) { Loading @@ -468,24 +471,18 @@ static log_time lastLogTime(char *outputFileName) { return retval; } clockid_t clock_type = android_log_clockid(); log_time now(clock_type); bool monotonic = clock_type == CLOCK_MONOTONIC; log_time now(android_log_clockid()); size_t len = strlen(file); log_time modulo(0, NS_PER_SEC); struct dirent *dp; while ((dp = readdir(dir.get())) != NULL) { if ((dp->d_type != DT_REG) // If we are using realtime, check all files that match the // basename for latest time. If we are using monotonic time // then only check the main file because time cycles on // every reboot. || strncmp(dp->d_name, file, len + monotonic) || (dp->d_name[len] && ((dp->d_name[len] != '.') || !isdigit(dp->d_name[len+1])))) { if ((dp->d_type != DT_REG) || (strncmp(dp->d_name, file, len) != 0) || (dp->d_name[len] && ((dp->d_name[len] != '.') || (strtoll(dp->d_name + 1, NULL, 10) != 1)))) { continue; } Loading Loading @@ -547,6 +544,7 @@ int main(int argc, char **argv) unsigned long setLogSize = 0; int getPruneList = 0; char *setPruneList = NULL; char *setId = NULL; int printStatistics = 0; int mode = ANDROID_LOG_RDONLY; const char *forceFilters = NULL; Loading Loading @@ -574,6 +572,7 @@ int main(int argc, char **argv) int option_index = 0; // list of long-argument only strings for later comparison static const char pid_str[] = "pid"; static const char id_str[] = "id"; static const char wrap_str[] = "wrap"; static const char print_str[] = "print"; static const struct option long_options[] = { Loading @@ -588,6 +587,7 @@ int main(int argc, char **argv) { "grep", required_argument, NULL, 'e' }, // hidden and undocumented reserved alias for --max-count { "head", required_argument, NULL, 'm' }, { id_str, required_argument, NULL, 0 }, { "last", no_argument, NULL, 'L' }, { "max-count", required_argument, NULL, 'm' }, { pid_str, required_argument, NULL, 0 }, Loading @@ -613,7 +613,7 @@ int main(int argc, char **argv) switch (ret) { case 0: // One of the long options // only long options if (long_options[option_index].name == pid_str) { // ToDo: determine runtime PID_MAX? if (!getSizeTArg(optarg, &pid, 1)) { Loading Loading @@ -644,6 +644,10 @@ int main(int argc, char **argv) g_printItAnyways = true; break; } if (long_options[option_index].name == id_str) { setId = optarg && optarg[0] ? optarg : NULL; break; } break; case 's': Loading @@ -657,7 +661,7 @@ int main(int argc, char **argv) break; case 'L': mode |= ANDROID_LOG_PSTORE; mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK; break; case 'd': Loading Loading @@ -968,7 +972,20 @@ int main(int argc, char **argv) logcat_panic(true, "-r requires -f as well\n"); } setupOutput(); if (setId != NULL) { if (g_outputFileName == NULL) { logcat_panic(true, "--id='%s' requires -f as well\n", setId); } std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName); std::string file; bool file_ok = android::base::ReadFileToString(file_name, &file); android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR, getuid(), getgid()); if (!file_ok || (file.compare(setId) == 0)) { setId = NULL; } } if (hasSetLogFormat == 0) { const char* logFormat = getenv("ANDROID_PRINTF_LOG"); Loading Loading @@ -1034,34 +1051,33 @@ int main(int argc, char **argv) continue; } if (clearLog) { if (clearLog || setId) { if (g_outputFileName) { int maxRotationCountDigits = (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0; for (int i = g_maxRotatedLogs ; i >= 0 ; --i) { char *file; std::string file; if (i == 0) { asprintf(&file, "%s", g_outputFileName); file = android::base::StringPrintf("%s", g_outputFileName); } else { asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); file = android::base::StringPrintf("%s.%.*d", g_outputFileName, maxRotationCountDigits, i); } if (!file) { if (file.length() == 0) { perror("while clearing log files"); clearFail = clearFail ?: dev->device; break; } err = unlink(file); err = unlink(file.c_str()); if (err < 0 && errno != ENOENT && clearFail == NULL) { perror("while clearing log files"); clearFail = dev->device; } free(file); } } else if (android_logger_clear(dev->logger)) { clearFail = clearFail ?: dev->device; Loading Loading @@ -1177,7 +1193,6 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } if (getLogSize) { return EXIT_SUCCESS; } Loading @@ -1188,6 +1203,8 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } setupOutputAndSchedulingPolicy((mode & ANDROID_LOG_NONBLOCK) == 0); //LOG_EVENT_INT(10, 12345); //LOG_EVENT_LONG(11, 0x1122334455667788LL); //LOG_EVENT_STRING(0, "whassup, doc?"); Loading logcat/logcatd.rc +2 −2 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ on property:logd.logpersistd.enable=true && property:logd.logpersistd=logcatd # all exec/services are called with umask(077), so no gain beyond 0700 mkdir /data/misc/logd 0700 logd log # logd for write to /data/misc/logd, log group for read from pstore (-L) exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id} start logcatd # stop logcatd service and clear data Loading @@ -56,7 +56,7 @@ on property:logd.logpersistd.enable=false stop logcatd # logcatd service service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id} class late_start disabled # logd for write to /data/misc/logd, log group for read from log daemon Loading logcat/logpersist +7 −5 Original line number Diff line number Diff line Loading @@ -17,8 +17,9 @@ true) ;; ;; esac log_uid=logd log_tag_property=persist.log.tag data=/data/misc/logd data=/data/misc/logd/logcat service=logcatd size_default=256 buffer_default=all Loading Loading @@ -74,11 +75,12 @@ case ${progname} in if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2 fi su logd ls "${data}" | su ${log_uid} ls "${data%/*}" | tr -d '\r' | sort -ru | sed "s#^#${data}/#" | su logd xargs cat sed "s#^#${data%/*}/#" | grep "${data}[.]*[0-9]*\$" | su ${log_uid} xargs cat ;; *.start) current_buffer="`getprop ${property#persist.}.buffer`" Loading Loading @@ -139,7 +141,7 @@ case ${progname} in sleep 1 getprop ${property#persist.} # also generate an error return code if not found running pgrep -u ${data##*/} ${service%d} pgrep -u ${log_uid} ${service%d} ;; *.stop) if [ -n "${size}${buffer}" ]; then Loading logcat/tests/logcat_test.cpp +70 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> Loading Loading @@ -848,6 +849,75 @@ TEST(logcat, logrotate_clear) { EXPECT_FALSE(system(command)); } static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) { static const char log_filename[] = "log.txt"; char command[strlen(tmp_out_dir) + strlen(logcat_cmd) + strlen(log_filename) + 32]; snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); int ret; EXPECT_FALSE((ret = system(command))); if (ret) { return -1; } std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir); EXPECT_NE(nullptr, dir); if (!dir) { return -1; } struct dirent *entry; int count = 0; while ((entry = readdir(dir.get()))) { if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { continue; } ++count; } return count; } TEST(logcat, logrotate_id) { static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 32 -r 1 --id=test"; static const char logcat_short_cmd[] = "logcat -b all -t 10 -f %s/%s -n 32 -r 1 --id=test"; static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; static const char log_filename[] = "log.txt"; char tmp_out_dir[strlen(tmp_out_dir_form) + 1]; ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); EXPECT_EQ(34, logrotate_count_id(logcat_cmd, tmp_out_dir)); EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5]; snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename); if (getuid() != 0) { chmod(id_file, 0); EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); } unlink(id_file); EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); FILE *fp = fopen(id_file, "w"); if (fp) { fprintf(fp, "not_a_test"); fclose(fp); } if (getuid() != 0) { chmod(id_file, 0); // API to preserve content even with signature change ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); chmod(id_file, 0600); } int new_signature; EXPECT_LE(2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir))); EXPECT_GT(34, new_signature); static const char cleanup_cmd[] = "rm -rf %s"; char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)]; snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); EXPECT_FALSE(system(command)); } TEST(logcat, logrotate_nodir) { // expect logcat to error out on writing content and exit(1) for nodir EXPECT_EQ(W_EXITCODE(1, 0), Loading Loading
logcat/logcat.cpp +71 −54 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <string> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <cutils/sched_policy.h> #include <cutils/sockets.h> Loading Loading @@ -109,29 +110,27 @@ static void rotateLogs() (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0; for (int i = g_maxRotatedLogs ; i > 0 ; i--) { char *file0, *file1; asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); std::string file1 = android::base::StringPrintf( "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); std::string file0; if (i - 1 == 0) { asprintf(&file0, "%s", g_outputFileName); file0 = android::base::StringPrintf("%s", g_outputFileName); } else { asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1); file0 = android::base::StringPrintf( "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1); } if (!file0 || !file1) { if ((file0.length() == 0) || (file1.length() == 0)) { perror("while rotating log files"); break; } err = rename(file0, file1); err = rename(file0.c_str(), file1.c_str()); if (err < 0 && errno != ENOENT) { perror("while rotating log files"); } free(file1); free(file0); } g_outFD = openLogFile(g_outputFileName); Loading Loading @@ -231,13 +230,15 @@ static void maybePrintStart(log_device_t* dev, bool printDividers) { } } static void setupOutput() { static void setupOutputAndSchedulingPolicy(bool blocking) { if (g_outputFileName == NULL) { g_outFD = STDOUT_FILENO; return; } } else { if (blocking) { // Lower priority and set to batch scheduling if we are saving // the logs into files and taking continuous content. if (set_sched_policy(0, SP_BACKGROUND) < 0) { fprintf(stderr, "failed to set background scheduling policy\n"); } Loading @@ -251,6 +252,7 @@ static void setupOutput() if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) { fprintf(stderr, "failed set to priority\n"); } } g_outFD = openLogFile (g_outputFileName); Loading @@ -271,7 +273,6 @@ static void setupOutput() g_outByteCount = statbuf.st_size; } } static void show_help(const char *cmd) { Loading @@ -284,6 +285,8 @@ static void show_help(const char *cmd) " Rotate log every kbytes. Requires -f option\n" " -n <count>, --rotate-count=<count>\n" " Sets max number of rotated logs to <count>, default 4\n" " --id=<id> If the signature id for logging to file changes, then clear\n" " the fileset and continue\n" " -v <format>, --format=<format>\n" " Sets log print format verb and adverbs, where <format> is:\n" " brief long process raw tag thread threadtime time\n" Loading Loading @@ -443,7 +446,7 @@ static char *parseTime(log_time &t, const char *cp) { return t.strptime(cp, "%s.%q"); } // Find last logged line in gestalt of all matching existing output files // Find last logged line in <outputFileName>, or <outputFileName>.1 static log_time lastLogTime(char *outputFileName) { log_time retval(log_time::EPOCH); if (!outputFileName) { Loading @@ -468,24 +471,18 @@ static log_time lastLogTime(char *outputFileName) { return retval; } clockid_t clock_type = android_log_clockid(); log_time now(clock_type); bool monotonic = clock_type == CLOCK_MONOTONIC; log_time now(android_log_clockid()); size_t len = strlen(file); log_time modulo(0, NS_PER_SEC); struct dirent *dp; while ((dp = readdir(dir.get())) != NULL) { if ((dp->d_type != DT_REG) // If we are using realtime, check all files that match the // basename for latest time. If we are using monotonic time // then only check the main file because time cycles on // every reboot. || strncmp(dp->d_name, file, len + monotonic) || (dp->d_name[len] && ((dp->d_name[len] != '.') || !isdigit(dp->d_name[len+1])))) { if ((dp->d_type != DT_REG) || (strncmp(dp->d_name, file, len) != 0) || (dp->d_name[len] && ((dp->d_name[len] != '.') || (strtoll(dp->d_name + 1, NULL, 10) != 1)))) { continue; } Loading Loading @@ -547,6 +544,7 @@ int main(int argc, char **argv) unsigned long setLogSize = 0; int getPruneList = 0; char *setPruneList = NULL; char *setId = NULL; int printStatistics = 0; int mode = ANDROID_LOG_RDONLY; const char *forceFilters = NULL; Loading Loading @@ -574,6 +572,7 @@ int main(int argc, char **argv) int option_index = 0; // list of long-argument only strings for later comparison static const char pid_str[] = "pid"; static const char id_str[] = "id"; static const char wrap_str[] = "wrap"; static const char print_str[] = "print"; static const struct option long_options[] = { Loading @@ -588,6 +587,7 @@ int main(int argc, char **argv) { "grep", required_argument, NULL, 'e' }, // hidden and undocumented reserved alias for --max-count { "head", required_argument, NULL, 'm' }, { id_str, required_argument, NULL, 0 }, { "last", no_argument, NULL, 'L' }, { "max-count", required_argument, NULL, 'm' }, { pid_str, required_argument, NULL, 0 }, Loading @@ -613,7 +613,7 @@ int main(int argc, char **argv) switch (ret) { case 0: // One of the long options // only long options if (long_options[option_index].name == pid_str) { // ToDo: determine runtime PID_MAX? if (!getSizeTArg(optarg, &pid, 1)) { Loading Loading @@ -644,6 +644,10 @@ int main(int argc, char **argv) g_printItAnyways = true; break; } if (long_options[option_index].name == id_str) { setId = optarg && optarg[0] ? optarg : NULL; break; } break; case 's': Loading @@ -657,7 +661,7 @@ int main(int argc, char **argv) break; case 'L': mode |= ANDROID_LOG_PSTORE; mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK; break; case 'd': Loading Loading @@ -968,7 +972,20 @@ int main(int argc, char **argv) logcat_panic(true, "-r requires -f as well\n"); } setupOutput(); if (setId != NULL) { if (g_outputFileName == NULL) { logcat_panic(true, "--id='%s' requires -f as well\n", setId); } std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName); std::string file; bool file_ok = android::base::ReadFileToString(file_name, &file); android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR, getuid(), getgid()); if (!file_ok || (file.compare(setId) == 0)) { setId = NULL; } } if (hasSetLogFormat == 0) { const char* logFormat = getenv("ANDROID_PRINTF_LOG"); Loading Loading @@ -1034,34 +1051,33 @@ int main(int argc, char **argv) continue; } if (clearLog) { if (clearLog || setId) { if (g_outputFileName) { int maxRotationCountDigits = (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0; for (int i = g_maxRotatedLogs ; i >= 0 ; --i) { char *file; std::string file; if (i == 0) { asprintf(&file, "%s", g_outputFileName); file = android::base::StringPrintf("%s", g_outputFileName); } else { asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); file = android::base::StringPrintf("%s.%.*d", g_outputFileName, maxRotationCountDigits, i); } if (!file) { if (file.length() == 0) { perror("while clearing log files"); clearFail = clearFail ?: dev->device; break; } err = unlink(file); err = unlink(file.c_str()); if (err < 0 && errno != ENOENT && clearFail == NULL) { perror("while clearing log files"); clearFail = dev->device; } free(file); } } else if (android_logger_clear(dev->logger)) { clearFail = clearFail ?: dev->device; Loading Loading @@ -1177,7 +1193,6 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } if (getLogSize) { return EXIT_SUCCESS; } Loading @@ -1188,6 +1203,8 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } setupOutputAndSchedulingPolicy((mode & ANDROID_LOG_NONBLOCK) == 0); //LOG_EVENT_INT(10, 12345); //LOG_EVENT_LONG(11, 0x1122334455667788LL); //LOG_EVENT_STRING(0, "whassup, doc?"); Loading
logcat/logcatd.rc +2 −2 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ on property:logd.logpersistd.enable=true && property:logd.logpersistd=logcatd # all exec/services are called with umask(077), so no gain beyond 0700 mkdir /data/misc/logd 0700 logd log # logd for write to /data/misc/logd, log group for read from pstore (-L) exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id} start logcatd # stop logcatd service and clear data Loading @@ -56,7 +56,7 @@ on property:logd.logpersistd.enable=false stop logcatd # logcatd service service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id} class late_start disabled # logd for write to /data/misc/logd, log group for read from log daemon Loading
logcat/logpersist +7 −5 Original line number Diff line number Diff line Loading @@ -17,8 +17,9 @@ true) ;; ;; esac log_uid=logd log_tag_property=persist.log.tag data=/data/misc/logd data=/data/misc/logd/logcat service=logcatd size_default=256 buffer_default=all Loading Loading @@ -74,11 +75,12 @@ case ${progname} in if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2 fi su logd ls "${data}" | su ${log_uid} ls "${data%/*}" | tr -d '\r' | sort -ru | sed "s#^#${data}/#" | su logd xargs cat sed "s#^#${data%/*}/#" | grep "${data}[.]*[0-9]*\$" | su ${log_uid} xargs cat ;; *.start) current_buffer="`getprop ${property#persist.}.buffer`" Loading Loading @@ -139,7 +141,7 @@ case ${progname} in sleep 1 getprop ${property#persist.} # also generate an error return code if not found running pgrep -u ${data##*/} ${service%d} pgrep -u ${log_uid} ${service%d} ;; *.stop) if [ -n "${size}${buffer}" ]; then Loading
logcat/tests/logcat_test.cpp +70 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> Loading Loading @@ -848,6 +849,75 @@ TEST(logcat, logrotate_clear) { EXPECT_FALSE(system(command)); } static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) { static const char log_filename[] = "log.txt"; char command[strlen(tmp_out_dir) + strlen(logcat_cmd) + strlen(log_filename) + 32]; snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); int ret; EXPECT_FALSE((ret = system(command))); if (ret) { return -1; } std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir); EXPECT_NE(nullptr, dir); if (!dir) { return -1; } struct dirent *entry; int count = 0; while ((entry = readdir(dir.get()))) { if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) { continue; } ++count; } return count; } TEST(logcat, logrotate_id) { static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 32 -r 1 --id=test"; static const char logcat_short_cmd[] = "logcat -b all -t 10 -f %s/%s -n 32 -r 1 --id=test"; static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX"; static const char log_filename[] = "log.txt"; char tmp_out_dir[strlen(tmp_out_dir_form) + 1]; ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form))); EXPECT_EQ(34, logrotate_count_id(logcat_cmd, tmp_out_dir)); EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5]; snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename); if (getuid() != 0) { chmod(id_file, 0); EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); } unlink(id_file); EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); FILE *fp = fopen(id_file, "w"); if (fp) { fprintf(fp, "not_a_test"); fclose(fp); } if (getuid() != 0) { chmod(id_file, 0); // API to preserve content even with signature change ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir)); chmod(id_file, 0600); } int new_signature; EXPECT_LE(2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir))); EXPECT_GT(34, new_signature); static const char cleanup_cmd[] = "rm -rf %s"; char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)]; snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); EXPECT_FALSE(system(command)); } TEST(logcat, logrotate_nodir) { // expect logcat to error out on writing content and exit(1) for nodir EXPECT_EQ(W_EXITCODE(1, 0), Loading