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 |