1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2019-2019 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 
24 #include "include/bareos.h"
25 #include "include/jcr.h"
26 #include "lib/recent_job_results_list.h"
27 #include "lib/dlist.h"
28 #include "lib/berrno.h"
29 
30 #include <vector>
31 #include <mutex>
32 #include <fstream>
33 
34 static std::vector<RecentJobResultsList::JobResult> recent_job_results_list;
35 static const int max_count_recent_job_results = 10;
36 static std::mutex mutex;
37 
Cleanup()38 void RecentJobResultsList::Cleanup()
39 {
40   std::lock_guard<std::mutex> lg(mutex);
41   if (!recent_job_results_list.empty()) { recent_job_results_list.clear(); }
42 }
43 
ImportFromFile(std::ifstream & file)44 bool RecentJobResultsList::ImportFromFile(std::ifstream& file)
45 {
46 #if defined HAVE_IS_TRIVIALLY_COPYABLE
47   static_assert(
48       std::is_trivially_copyable<RecentJobResultsList::JobResult>::value,
49       "RecentJobResultsList::JobResult must be trivially copyable");
50 #endif
51 
52   uint32_t num;
53 
54   try {
55     file.read(reinterpret_cast<char*>(&num), sizeof(num));
56 
57     Dmsg1(100, "Read num_items=%d\n", num);
58     if (num > 4 * max_count_recent_job_results) { /* sanity check */
59       return false;
60     }
61 
62     std::lock_guard<std::mutex> m(mutex);
63 
64     for (; num; num--) {
65       RecentJobResultsList::JobResult job;
66       file.read(reinterpret_cast<char*>(&job), sizeof(job));
67       if (job.JobId > 0) {
68         recent_job_results_list.push_back(job);
69         if (recent_job_results_list.size() > max_count_recent_job_results) {
70           recent_job_results_list.erase(recent_job_results_list.begin());
71         }
72       }
73     }
74   } catch (const std::system_error& e) {
75     BErrNo be;
76     Dmsg3(010, "Could not open or read state file. ERR=%s - %s\n",
77           be.bstrerror(), e.code().message().c_str());
78     return false;
79   } catch (const std::exception& e) {
80     Dmsg0(100, "Could not open or read file. Some error occurred: %s\n",
81           e.what());
82     return false;
83   }
84   return true;
85 }
86 
ExportToFile(std::ofstream & file)87 bool RecentJobResultsList::ExportToFile(std::ofstream& file)
88 {
89   if (!recent_job_results_list.empty()) {
90     std::lock_guard<std::mutex> m(mutex);
91     uint32_t num
92         = recent_job_results_list.size();  // always first entry in the file
93 
94 #if defined HAVE_IS_TRIVIALLY_COPYABLE
95     static_assert(
96         std::is_trivially_copyable<RecentJobResultsList::JobResult>::value,
97         "RecentJobResultsList::JobResult must be trivially copyable");
98 #endif
99 
100     try {
101       file.write(reinterpret_cast<char*>(&num), sizeof(num));
102 
103       for (const auto& je : recent_job_results_list) {
104         file.write(reinterpret_cast<const char*>(&je),
105                    sizeof(struct RecentJobResultsList::JobResult));
106       }
107     } catch (const std::system_error& e) {
108       BErrNo be;
109       Dmsg3(010, "Could not write state file. ERR=%s - %s\n", be.bstrerror(),
110             e.code().message().c_str());
111       return false;
112     } catch (const std::exception& e) {
113       Dmsg0(100, "Could not write file. Some error occurred: %s\n", e.what());
114       return false;
115     }
116   }
117   return true;
118 }
119 
Append(JobControlRecord * jcr)120 void RecentJobResultsList::Append(JobControlRecord* jcr)
121 {
122   RecentJobResultsList::JobResult je;
123   je.Errors = jcr->JobErrors;
124   je.JobType = jcr->getJobType();
125   je.JobId = jcr->JobId;
126   je.VolSessionId = jcr->VolSessionId;
127   je.VolSessionTime = jcr->VolSessionTime;
128   bstrncpy(je.Job, jcr->Job, sizeof(je.Job));
129   je.JobFiles = jcr->JobFiles;
130   je.JobBytes = jcr->JobBytes;
131   je.JobStatus = jcr->JobStatus;
132   je.JobLevel = jcr->getJobLevel();
133   je.start_time = jcr->start_time;
134   je.end_time = time(nullptr);
135 
136   std::lock_guard<std::mutex> lg(mutex);
137   recent_job_results_list.push_back(je);
138   if (recent_job_results_list.size() > max_count_recent_job_results) {
139     recent_job_results_list.erase(recent_job_results_list.begin());
140   }
141 }
142 
Get()143 std::vector<RecentJobResultsList::JobResult> RecentJobResultsList::Get()
144 {
145   std::lock_guard<std::mutex> lg(mutex);
146   return recent_job_results_list;
147 }
148 
Count()149 std::size_t RecentJobResultsList::Count()
150 {
151   std::lock_guard<std::mutex> lg(mutex);
152   return recent_job_results_list.size();
153 }
154 
IsEmpty()155 bool RecentJobResultsList::IsEmpty()
156 {
157   std::lock_guard<std::mutex> lg(mutex);
158   return recent_job_results_list.empty();
159 }
160 
161 
GetMostRecentJobResult()162 RecentJobResultsList::JobResult RecentJobResultsList::GetMostRecentJobResult()
163 {
164   std::lock_guard<std::mutex> lg(mutex);
165   if (recent_job_results_list.size()) {
166     return recent_job_results_list.front();
167   }
168   return RecentJobResultsList::JobResult{};
169 }
170