Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame^] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | /* |
| 6 | * metrics_library.cc |
| 7 | * |
| 8 | * Created on: Dec 1, 2009 |
| 9 | * Author: sosa |
| 10 | */ |
| 11 | |
| 12 | #include "metrics_library.h" |
| 13 | |
| 14 | #include <errno.h> |
| 15 | #include <sys/file.h> |
| 16 | #include <string.h> |
| 17 | #include <stdio.h> |
| 18 | |
| 19 | #define READ_WRITE_ALL_FILE_FLAGS \ |
| 20 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) |
| 21 | |
| 22 | static const char kAutotestPath[] = "/tmp/.chromeos-metrics-autotest"; |
| 23 | static const char kChromePath[] = "/tmp/.chromeos-metrics"; |
| 24 | static const int kBufferSize = 4096; |
| 25 | |
| 26 | using namespace std; |
| 27 | |
| 28 | // TODO(sosa@chromium.org) - use Chromium logger instead of stderr |
| 29 | void MetricsLibrary::PrintError(const char *message, const char *file, |
| 30 | int code) { |
| 31 | const char *kProgramName = "metrics_library"; |
| 32 | if (code == 0) { |
| 33 | fprintf(stderr, "%s: %s\n", kProgramName, message); |
| 34 | } else if (file == NULL) { |
| 35 | fprintf(stderr, "%s: ", kProgramName); |
| 36 | perror(message); |
| 37 | } else { |
| 38 | fprintf(stderr, "%s: %s: ", kProgramName, file); |
| 39 | perror(message); |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | void MetricsLibrary::SendToAutotest(string name, string value) { |
| 44 | FILE *autotest_file = fopen(kAutotestPath, "a+"); |
| 45 | if (autotest_file == NULL) { |
| 46 | PrintError("fopen", kAutotestPath, errno); |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | fprintf(autotest_file, "%s=%s\n", name.c_str(), value.c_str()); |
| 51 | fclose(autotest_file); |
| 52 | } |
| 53 | |
| 54 | void MetricsLibrary::SendToChrome(string name, string value) { |
| 55 | int chrome_fd = open(kChromePath, |
| 56 | O_WRONLY | O_APPEND | O_CREAT, |
| 57 | READ_WRITE_ALL_FILE_FLAGS); |
| 58 | // If we failed to open it, return |
| 59 | if (chrome_fd < 0) { |
| 60 | PrintError("open", kChromePath, errno); |
| 61 | return; |
| 62 | } |
| 63 | |
| 64 | // Need to chmod because open flags are anded with umask. |
| 65 | if (fchmod(chrome_fd, READ_WRITE_ALL_FILE_FLAGS) < 0) { |
| 66 | PrintError("fchmod", kChromePath, errno); |
| 67 | close(chrome_fd); |
| 68 | return; |
| 69 | } |
| 70 | |
| 71 | // Grab an exclusive lock to protect Chrome from truncating underneath us |
| 72 | if (flock(chrome_fd, LOCK_EX) < 0) { |
| 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 | } |