| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /* | 5 /* |
| 6 * metrics_library.cc | 6 * metrics_library.cc |
| 7 * | 7 * |
| 8 * Created on: Dec 1, 2009 | 8 * Created on: Dec 1, 2009 |
| 9 * Author: sosa | 9 * Author: sosa |
| 10 */ | 10 */ |
| 11 | 11 |
| 12 #include "metrics_library.h" | 12 #include "metrics_library.h" |
| 13 | 13 |
| 14 #include <errno.h> | 14 #include <errno.h> |
| 15 #include <sys/file.h> | 15 #include <sys/file.h> |
| 16 #include <string.h> | 16 |
| 17 #include <stdio.h> | 17 #include <cstdarg> |
| 18 #include <cstdio> |
| 19 #include <cstring> |
| 18 | 20 |
| 19 #define READ_WRITE_ALL_FILE_FLAGS \ | 21 #define READ_WRITE_ALL_FILE_FLAGS \ |
| 20 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) | 22 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) |
| 21 | 23 |
| 22 static const char kAutotestPath[] = "/tmp/.chromeos-metrics-autotest"; | 24 static const char kAutotestPath[] = "/tmp/.chromeos-metrics-autotest"; |
| 23 static const char kChromePath[] = "/tmp/.chromeos-metrics"; | 25 static const char kChromePath[] = "/tmp/.chromeos-metrics"; |
| 24 static const int kBufferSize = 4096; | 26 static const int32_t kBufferSize = 1024; |
| 25 | 27 |
| 26 using namespace std; | 28 using namespace std; |
| 27 | 29 |
| 28 // TODO(sosa@chromium.org) - use Chromium logger instead of stderr | 30 // TODO(sosa@chromium.org) - use Chromium logger instead of stderr |
| 29 void MetricsLibrary::PrintError(const char *message, const char *file, | 31 static void PrintError(const char *message, const char *file, |
| 30 int code) { | 32 int code) { |
| 31 const char *kProgramName = "metrics_library"; | 33 const char *kProgramName = "metrics_library"; |
| 32 if (code == 0) { | 34 if (code == 0) { |
| 33 fprintf(stderr, "%s: %s\n", kProgramName, message); | 35 fprintf(stderr, "%s: %s\n", kProgramName, message); |
| 34 } else if (file == NULL) { | 36 } else if (file == NULL) { |
| 35 fprintf(stderr, "%s: ", kProgramName); | 37 fprintf(stderr, "%s: ", kProgramName); |
| 36 perror(message); | 38 perror(message); |
| 37 } else { | 39 } else { |
| 38 fprintf(stderr, "%s: %s: ", kProgramName, file); | 40 fprintf(stderr, "%s: %s: ", kProgramName, file); |
| 39 perror(message); | 41 perror(message); |
| 40 } | 42 } |
| 41 } | 43 } |
| 42 | 44 |
| 43 void MetricsLibrary::SendToAutotest(string name, string value) { | 45 // Sends message of size length to Chrome and returns true on success. |
| 46 static bool SendMessageToChrome(int32_t length, const char *message) { |
| 47 int chrome_fd = open(kChromePath, |
| 48 O_WRONLY | O_APPEND | O_CREAT, |
| 49 READ_WRITE_ALL_FILE_FLAGS); |
| 50 // If we failed to open it, return. |
| 51 if (chrome_fd < 0) { |
| 52 PrintError("open", kChromePath, errno); |
| 53 return false; |
| 54 } |
| 55 |
| 56 // Need to chmod because open flags are anded with umask. Ignore the |
| 57 // exit code -- a chronos process may fail chmoding because the file |
| 58 // has been created by a root process but that should be OK. |
| 59 fchmod(chrome_fd, READ_WRITE_ALL_FILE_FLAGS); |
| 60 |
| 61 // Grab an exclusive lock to protect Chrome from truncating |
| 62 // underneath us. Keep the file locked as briefly as possible. |
| 63 if (flock(chrome_fd, LOCK_EX) < 0) { |
| 64 PrintError("flock", kChromePath, errno); |
| 65 close(chrome_fd); |
| 66 return false; |
| 67 } |
| 68 |
| 69 bool success = true; |
| 70 if (write(chrome_fd, message, length) != length) { |
| 71 PrintError("write", kChromePath, errno); |
| 72 success = false; |
| 73 } |
| 74 |
| 75 // Release the file lock and close file. |
| 76 if (flock(chrome_fd, LOCK_UN) < 0) { |
| 77 PrintError("unlock", kChromePath, errno); |
| 78 success = false; |
| 79 } |
| 80 close(chrome_fd); |
| 81 return success; |
| 82 } |
| 83 |
| 84 // Formats a name/value message for Chrome in buffer and returns the |
| 85 // length of the message or a negative value on error. |
| 86 // |
| 87 // Message format is: | LENGTH(binary) | NAME | \0 | VALUE | \0 | |
| 88 // |
| 89 // The arbitrary format argument covers the non-LENGTH portion of the |
| 90 // message. The caller is responsible to store the \0 character |
| 91 // between NAME and VALUE (e.g. "%s%c%d", name, '\0', value). |
| 92 static int32_t FormatChromeMessage(int32_t buffer_size, char *buffer, |
| 93 const char *format, ...) { |
| 94 int32_t message_length; |
| 95 size_t len_size = sizeof(message_length); |
| 96 |
| 97 // Format the non-LENGTH contents in the buffer by leaving space for |
| 98 // LENGTH at the start of the buffer. |
| 99 va_list args; |
| 100 va_start(args, format); |
| 101 message_length = vsnprintf(&buffer[len_size], buffer_size - len_size, |
| 102 format, args); |
| 103 va_end(args); |
| 104 |
| 105 if (message_length < 0) { |
| 106 PrintError("chrome message format error", NULL, 0); |
| 107 return -1; |
| 108 } |
| 109 |
| 110 // +1 to account for the trailing \0. |
| 111 message_length += len_size + 1; |
| 112 if (message_length > buffer_size) { |
| 113 PrintError("chrome message too long", NULL, 0); |
| 114 return -1; |
| 115 } |
| 116 |
| 117 // Prepend LENGTH to the message. |
| 118 memcpy(buffer, &message_length, len_size); |
| 119 return message_length; |
| 120 } |
| 121 |
| 122 bool MetricsLibrary::SendToAutotest(string name, int value) { |
| 44 FILE *autotest_file = fopen(kAutotestPath, "a+"); | 123 FILE *autotest_file = fopen(kAutotestPath, "a+"); |
| 45 if (autotest_file == NULL) { | 124 if (autotest_file == NULL) { |
| 46 PrintError("fopen", kAutotestPath, errno); | 125 PrintError("fopen", kAutotestPath, errno); |
| 47 return; | 126 return false; |
| 48 } | 127 } |
| 49 | 128 |
| 50 fprintf(autotest_file, "%s=%s\n", name.c_str(), value.c_str()); | 129 fprintf(autotest_file, "%s=%d\n", name.c_str(), value); |
| 51 fclose(autotest_file); | 130 fclose(autotest_file); |
| 131 return true; |
| 52 } | 132 } |
| 53 | 133 |
| 54 void MetricsLibrary::SendToChrome(string name, string value) { | 134 bool MetricsLibrary::SendToChrome(string name, int value) { |
| 55 int chrome_fd = open(kChromePath, | 135 // Format the message. |
| 56 O_WRONLY | O_APPEND | O_CREAT, | 136 char message[kBufferSize]; |
| 57 READ_WRITE_ALL_FILE_FLAGS); | 137 int32_t message_length = |
| 58 // If we failed to open it, return | 138 FormatChromeMessage(kBufferSize, message, |
| 59 if (chrome_fd < 0) { | 139 "%s%c%d", name.c_str(), '\0', value); |
| 60 PrintError("open", kChromePath, errno); | |
| 61 return; | |
| 62 } | |
| 63 | 140 |
| 64 // Need to chmod because open flags are anded with umask. | 141 if (message_length < 0) |
| 65 if (fchmod(chrome_fd, READ_WRITE_ALL_FILE_FLAGS) < 0) { | 142 return false; |
| 66 PrintError("fchmod", kChromePath, errno); | |
| 67 close(chrome_fd); | |
| 68 return; | |
| 69 } | |
| 70 | 143 |
| 71 // Grab an exclusive lock to protect Chrome from truncating underneath us | 144 // Send the message. |
| 72 if (flock(chrome_fd, LOCK_EX) < 0) { | 145 return SendMessageToChrome(message_length, message); |
| 73 PrintError("flock", kChromePath, errno); | |
| 74 close(chrome_fd); | |
| 75 return; | |
| 76 } | |
| 77 | |
| 78 // Message format is: LENGTH (binary), NAME, VALUE | |
| 79 char message[kBufferSize]; | |
| 80 char *curr_ptr = message; | |
| 81 int32_t message_length = | |
| 82 name.length() + value.length() + 2 + sizeof(message_length); | |
| 83 if (message_length > static_cast<int32_t>(sizeof(message))) | |
| 84 PrintError("name/value too long", NULL, 0); | |
| 85 | |
| 86 // Make sure buffer is blanked | |
| 87 memset(message, 0, sizeof(message)); | |
| 88 memcpy(curr_ptr, &message_length, sizeof(message_length)); | |
| 89 curr_ptr += sizeof(message_length); | |
| 90 strncpy(curr_ptr, name.c_str(), name.length()); | |
| 91 curr_ptr += name.length() + 1; | |
| 92 strncpy(curr_ptr, value.c_str(), value.length()); | |
| 93 if (write(chrome_fd, message, message_length) != message_length) | |
| 94 PrintError("write", kChromePath, errno); | |
| 95 | |
| 96 // Release the file lock and close file | |
| 97 if (flock(chrome_fd, LOCK_UN) < 0) | |
| 98 PrintError("unlock", kChromePath, errno); | |
| 99 close(chrome_fd); | |
| 100 } | 146 } |
| OLD | NEW |