Remove typedef decl errors
[hiphop-php.git] / hphp / util / cronolog.cpp
blob236d825284fb01fea674577024011119748f92e0
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/util/cronolog.h"
17 #include "hphp/util/user-info.h"
19 #include <boost/filesystem/path.hpp>
21 #ifndef _MSC_VER
22 #include <pwd.h>
23 #endif
25 #include <folly/portability/Fcntl.h>
26 #include <folly/portability/SysStat.h>
28 /* Default permissions for files and directories that are created */
30 #ifndef FILE_MODE
31 #define FILE_MODE ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH )
32 #endif
34 namespace HPHP {
36 ///////////////////////////////////////////////////////////////////////////////
38 using std::string;
39 namespace fs = boost::filesystem;
41 /* Open a new log file: determine the start of the current
42 * period, generate the log file name from the fileTemplate,
43 * determine the end of the period and open the new log file.
45 * Returns the file descriptor of the new log file and also sets the
46 * name of the file and the start time of the next period via pointers
47 * supplied.
49 static FILE *new_log_file(const char *fileTemplate, const char *linkname,
50 mode_t linktype, const char *prevlinkname,
51 PERIODICITY periodicity, int period_multiple,
52 int period_delay, char *pfilename,
53 size_t pfilename_len, time_t time_now,
54 time_t *pnext_period) {
55 time_t start_of_period;
56 struct tm *tm;
57 int log_fd;
59 start_of_period = start_of_this_period(time_now, periodicity,
60 period_multiple);
61 tm = localtime(&start_of_period);
62 strftime(pfilename, pfilename_len, fileTemplate, tm);
63 *pnext_period = start_of_next_period(start_of_period, periodicity,
64 period_multiple) + period_delay;
66 CRONO_DEBUG(("%s (%d): using log file \"%s\" from %s (%d) until %s (%d) "
67 "(for %d secs)\n",
68 timestamp(time_now), time_now, pfilename,
69 timestamp(start_of_period), start_of_period,
70 timestamp(*pnext_period), *pnext_period,
71 *pnext_period - time_now));
73 log_fd = open(pfilename, O_WRONLY|O_CREAT|O_APPEND, FILE_MODE);
75 #ifndef DONT_CREATE_SUBDIRS
76 if ((log_fd < 0) && (errno == ENOENT)) {
77 create_subdirs(pfilename);
78 log_fd = open(pfilename, O_WRONLY|O_CREAT|O_APPEND, FILE_MODE);
80 #endif
82 if (log_fd < 0) {
83 perror(pfilename);
84 return nullptr;
87 #ifndef _MSC_VER
88 if (linkname) {
89 struct stat stat_buf;
90 struct stat stat_buf2;
91 if (fstat(log_fd, &stat_buf) ||
92 stat(linkname, &stat_buf2) ||
93 stat_buf.st_ino != stat_buf2.st_ino ||
94 stat_buf.st_dev != stat_buf2.st_dev) {
96 /* Create a relative symlink to logs under linkname's directory */
97 std::string dir = fs::path(linkname).parent_path().native();
98 if (dir != "/") {
99 dir.append("/");
101 std::string filename;
102 if (!strncmp(pfilename, dir.c_str(), dir.length())) {
103 filename = pfilename + dir.length();
104 } else {
105 filename = pfilename;
108 create_link(filename.c_str(), linkname, linktype, prevlinkname);
111 #endif
112 return fdopen(log_fd, "a");
115 void Cronolog::setPeriodicity() {
116 if (m_periodicity == UNKNOWN) {
117 m_periodicity = determine_periodicity((char *)m_template.c_str());
121 FILE *Cronolog::getOutputFile() {
122 if (m_template.empty()) return m_file;
124 time_t time_now = time(nullptr) + m_timeOffset;
125 /* If the current period has not finished and there is a log file, use it */
126 if ((time_now < m_nextPeriod) && (m_file)) return m_file;
128 /* We need to open a new file under a mutex. */
130 std::lock_guard<std::mutex> lock(m_mutex);
131 if ((time_now >= m_nextPeriod)) {
132 /* the current period has finished */
134 /* We cannot close m_file because there may be other threads still
135 * writing to it. We save m_file in m_prevFile and leave it open for
136 * an entire period. We simply assume that by the end of the delay
137 * no threads should be still referencing m_prevFile and we can safely
138 * close it.
140 if (m_prevFile) fclose(m_prevFile);
141 m_prevFile = m_file;
142 m_file = nullptr;
145 /* If there is no log file open then open a new one. */
146 if (m_file == nullptr) {
147 const char *linkname = m_linkName.empty() ? nullptr : m_linkName.c_str();
148 m_file = new_log_file(m_template.c_str(),
149 #ifdef _MSC_VER
150 "", 0,
151 #else
152 linkname, S_IFLNK,
153 #endif
154 m_prevLinkName, m_periodicity, m_periodMultiple,
155 m_periodDelay, m_fileName, sizeof(m_fileName),
156 time_now, &m_nextPeriod);
159 return m_file;
162 void Cronolog::changeOwner(const string &username, const string &symlink) {
163 #ifdef _MSC_VER
164 return;
165 #else
166 if (username.empty() || symlink.empty()) {
167 return;
170 auto buf = PasswdBuffer{};
171 passwd* pw;
172 if (getpwnam_r(username.c_str(), &buf.ent, buf.data.get(), buf.size, &pw)) {
173 // Failed to obtain the record.
174 return;
177 if (pw == nullptr) {
178 // Invalid user.
179 return;
182 if (lchown(symlink.c_str(), pw->pw_uid, -1) < 0) {
183 fprintf(stderr, "Unable to chown %s\n", symlink.c_str());
186 // using chown() isn't portable if it is a symlink
187 int fd = open(symlink.c_str(), O_RDONLY | O_NONBLOCK | O_NOCTTY);
188 int success = (fd >= 0 ? fchown(fd, pw->pw_uid, -1) : -1);
190 if (fd >= 0) {
191 close(fd);
194 if (success < 0) {
195 fprintf(stderr, "Unable to chown %s\n", symlink.c_str());
197 #endif
200 ///////////////////////////////////////////////////////////////////////////////