1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 #include <time.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <errno.h>
20 
21 #include "Log.h"
22 #include "Settings.h"
23 #include "StringUtil.h"
24 #include "FileUtil.h"
25 
26 
27 // This class is used by Log. So we cannot use LOG? macros here.
28 #define _LOGD_(x...) do { fprintf(stderr, x); fprintf(stderr, "\n"); } while(0)
29 
30 // reported generated under reports/YYYY_MM_DD_HH_MM_SS dir
31 const char reportTopDir[] = "reports";
32 android::String8 FileUtil::mDirPath;
33 
prepare(android::String8 & dirPath)34 bool FileUtil::prepare(android::String8& dirPath)
35 {
36     if (mDirPath.length() != 0) {
37         dirPath = mDirPath;
38         _LOGD_("mDirPath %s", mDirPath.string());
39         return true;
40     }
41 
42     time_t timeNow = time(NULL);
43     if (timeNow == ((time_t)-1)) {
44         _LOGD_("time error");
45        return false;
46     }
47     // tm is allocated in static buffer, and should not be freed.
48     struct tm* tm = localtime(&timeNow);
49     if (tm == NULL) {
50         _LOGD_("localtime error");
51         return false;
52     }
53     int result = mkdir(reportTopDir, S_IRWXU);
54     if ((result == -1) && (errno != EEXIST)) {
55         _LOGD_("mkdir of topdir failed, error %d", errno);
56         return false;
57     }
58     android::String8 reportTime;
59     if (reportTime.appendFormat("%04d_%02d_%02d_%02d_%02d_%02d", tm->tm_year + 1900,
60                 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) != 0) {
61             return false;
62     }
63     Settings::Instance()->addSetting(Settings::EREPORT_TIME, reportTime);
64     android::String8 path;
65     if (path.appendFormat("%s/%s", reportTopDir, reportTime.string()) != 0) {
66         return false;
67     }
68     result = mkdir(path.string(), S_IRWXU);
69     if ((result == -1) && (errno != EEXIST)) {
70         _LOGD_("mkdir of report dir failed, error %d", errno);
71         return false;
72     }
73     mDirPath = path;
74     dirPath = path;
75 
76     return true;
77 }
78 
FileUtil()79 FileUtil::FileUtil()
80 {
81     mBuffer = new char[DEFAULT_BUFFER_SIZE];
82     if (mBuffer == NULL) {
83         // cannot use ASSERT here, just crash
84         abort();
85     }
86     mBufferSize = DEFAULT_BUFFER_SIZE;
87 }
88 
~FileUtil()89 FileUtil::~FileUtil()
90 {
91     if (mFile.is_open()) {
92         mFile.close();
93     }
94     delete[] mBuffer;
95 }
96 
init(const char * fileName)97 bool FileUtil::init(const char* fileName)
98 {
99     if (fileName == NULL) {
100         return true;
101     }
102 
103     mFile.open(fileName, std::ios::out | std::ios::trunc);
104     if (!mFile.is_open()) {
105             return false;
106         }
107     return true;
108 }
109 
doVprintf(bool fileOnly,int logLevel,const char * fmt,va_list ap)110 bool FileUtil::doVprintf(bool fileOnly, int logLevel, const char *fmt, va_list ap)
111 {
112     // prevent messed up log in multi-thread env. Still multi-line logs can be messed up.
113     android::Mutex::Autolock lock(mWriteLock);
114     while (1) {
115         int start = 0;
116         if (logLevel != -1) {
117             mBuffer[0] = '0' + logLevel;
118             mBuffer[1] = '>';
119             start = 2;
120         }
121         int size;
122         size = vsnprintf(mBuffer + start, mBufferSize - start - 2, fmt, ap); // 2 for \n\0
123         if (size < 0) {
124             fprintf(stderr, "FileUtil::vprintf failed");
125             return false;
126         }
127         if ((size + start + 2) > mBufferSize) {
128             //default buffer does not fit, increase buffer size and retry
129             delete[] mBuffer;
130             mBuffer = new char[2 * size];
131             if (mBuffer == NULL) {
132                 // cannot use ASSERT here, just crash
133                 abort();
134             }
135             mBufferSize = 2 * size;
136             // re-try
137             continue;
138         }
139         size += start;
140         mBuffer[size] = '\n';
141         size++;
142         mBuffer[size] = 0;
143 
144         if (!fileOnly) {
145             fprintf(stdout, "%s", mBuffer);
146         }
147         if (mFile.is_open()) {
148             mFile<<mBuffer;
149         }
150         return true;
151     }
152 }
153 
doPrintf(const char * fmt,...)154 bool FileUtil::doPrintf(const char* fmt, ...)
155 {
156     va_list ap;
157     va_start(ap, fmt);
158     bool result = doVprintf(false, -1, fmt, ap);
159     va_end(ap);
160     return result;
161 }
162