1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Status packet definition that is used in both the SD and FD. It
21 * permits Win32 to call output_status() and get the output back
22 * at the callback address line by line, and for Linux code,
23 * the output can be sent directly to a BSOCK.
24 *
25 * Kern Sibbald, March MMVII
26 *
27 */
28
29 #ifndef __STATUS_H_
30 #define __STATUS_H_
31
32 #ifdef HAVE_GETRLIMIT
33 #include <sys/time.h>
34 #include <sys/resource.h>
35 #endif
36
37 /*
38 * Packet to send to output_status()
39 */
40 class STATUS_PKT {
41 public:
42 BSOCK *bs; /* used on Unix machines */
43 void *context; /* Win32 */
44 void (*callback)(const char *msg, int len, void *context); /* Win32 */
45 char api_opts[MAX_NAME_LENGTH];
46 int api; /* set if we want API output, with api level */
47
48 /* Methods */
STATUS_PKT()49 STATUS_PKT() { memset(this, 0, sizeof(STATUS_PKT)); };
~STATUS_PKT()50 ~STATUS_PKT() { };
51 };
52
53 extern void output_status(STATUS_PKT *sp);
54
55 /*
56 * Send to bsock (Director or Console)
57 */
sendit(const char * msg,int len,STATUS_PKT * sp)58 static void sendit(const char *msg, int len, STATUS_PKT *sp)
59 {
60 if (sp->bs) {
61 BSOCK *user = sp->bs;
62 user->msg = check_pool_memory_size(user->msg, len+1);
63 memcpy(user->msg, msg, len+1);
64 user->msglen = len+1;
65 user->send();
66 } else {
67 sp->callback(msg, len, sp->context);
68 }
69 }
70
71 #ifndef STATUS_FUNCTIONS
72 #define STATUS_FUNCTIONS
73
74 /* common to SD/FD */
list_terminated_jobs(STATUS_PKT * sp)75 static void list_terminated_jobs(STATUS_PKT *sp)
76 {
77 OutputWriter ow(sp->api_opts);
78 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
79 char level[10];
80 struct s_last_job *je;
81 const char *msg;
82 char *p;
83
84 msg = _("\nTerminated Jobs:\n");
85 if (!sp->api) sendit(msg, strlen(msg), sp);
86 if (last_jobs->size() == 0) {
87 if (!sp->api) sendit("====\n", 5, sp);
88 return;
89 }
90 lock_last_jobs_list();
91 msg = _(" JobId Level Files Bytes Status Finished Name \n");
92 if (!sp->api) sendit(msg, strlen(msg), sp);
93 msg = _("===================================================================\n");
94 if (!sp->api) sendit(msg, strlen(msg), sp);
95 if (sp->api > 1) {
96 p = ow.start_group("terminated");
97 sendit(p, strlen(p), sp);
98 }
99 foreach_dlist(je, last_jobs) {
100 char JobName[MAX_NAME_LENGTH];
101 const char *termstat;
102 char buf[1000];
103
104 bstrftime_nc(dt, sizeof(dt), je->end_time);
105 switch (je->JobType) {
106 case JT_ADMIN:
107 bstrncpy(level, "Admn", sizeof(level));
108 break;
109 case JT_RESTORE:
110 bstrncpy(level, "Rest", sizeof(level));
111 break;
112 default:
113 bstrncpy(level, job_level_to_str(je->JobLevel), sizeof(level));
114 level[4] = 0;
115 break;
116 }
117 switch (je->JobStatus) {
118 case JS_Created:
119 termstat = _("Created");
120 break;
121 case JS_FatalError:
122 case JS_ErrorTerminated:
123 termstat = _("Error");
124 break;
125 case JS_Differences:
126 termstat = _("Diffs");
127 break;
128 case JS_Canceled:
129 termstat = _("Cancel");
130 break;
131 case JS_Terminated:
132 termstat = _("OK");
133 break;
134 case JS_Warnings:
135 termstat = _("OK -- with warnings");
136 break;
137 case JS_Incomplete:
138 termstat = _("Incomplete");
139 break;
140 default:
141 termstat = _("Other");
142 break;
143 }
144 bstrncpy(JobName, je->Job, sizeof(JobName));
145 /* There are three periods after the Job name */
146 char *p;
147 for (int i=0; i<3; i++) {
148 if ((p=strrchr(JobName, '.')) != NULL) {
149 *p = 0;
150 }
151 }
152 if (sp->api == 1) {
153 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
154 je->JobId,
155 level,
156 edit_uint64_with_commas(je->JobFiles, b1),
157 edit_uint64_with_suffix(je->JobBytes, b2),
158 termstat,
159 dt, JobName);
160
161 } else if (sp->api > 1) {
162 p = ow.get_output(OT_CLEAR,
163 OT_START_OBJ,
164 OT_INT, "jobid", je->JobId,
165 OT_JOBLEVEL,"level", je->JobLevel,
166 OT_JOBTYPE, "type", je->JobType,
167 OT_JOBSTATUS,"status", je->JobStatus,
168 OT_STRING, "status_desc",termstat,
169 OT_SIZE, "jobbytes", je->JobBytes,
170 OT_INT32, "jobfiles", je->JobFiles,
171 OT_STRING, "job", je->Job,
172 OT_STRING, "name", JobName,
173 OT_UTIME, "starttime", je->start_time,
174 OT_UTIME, "endtime", je->end_time,
175 OT_INT, "errors", je->Errors,
176 OT_END_OBJ,
177 OT_END);
178 sendit(p, strlen(p), sp);
179
180
181 } else {
182 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
183 je->JobId,
184 level,
185 edit_uint64_with_commas(je->JobFiles, b1),
186 edit_uint64_with_suffix(je->JobBytes, b2),
187 termstat,
188 dt, JobName);
189 }
190 sendit(buf, strlen(buf), sp);
191 }
192 unlock_last_jobs_list();
193 if (!sp->api) {
194 sendit("====\n", 5, sp);
195 } else if (sp->api > 1) {
196 p = ow.end_group(false);
197 sendit(p, strlen(p), sp);
198 }
199 }
200
201 /* common to SD/FD/DIR */
list_resource_limits(STATUS_PKT * sp,int64_t l_nofile,int64_t l_memlock)202 static void list_resource_limits(STATUS_PKT *sp, int64_t l_nofile, int64_t l_memlock)
203 {
204 #ifdef HAVE_GETRLIMIT
205 OutputWriter ow(sp->api_opts);
206 POOL_MEM msg(PM_MESSAGE), msg_status(PM_MESSAGE);
207 struct rlimit rlim;
208 int64_t nofile=-1, memlock=-1;
209 char nofile_s[128], memlock_s[128];
210 *nofile_s = *memlock_s = '\0';
211
212 msg_status.strcpy("");
213 #ifdef RLIMIT_NOFILE
214 if (getrlimit(RLIMIT_NOFILE, &rlim)==0) {
215 if (rlim.rlim_cur == RLIM_INFINITY) {
216 nofile=-1;
217 bstrncpy(nofile_s, "unlimited", sizeof(nofile_s));
218 } else {
219 nofile=rlim.rlim_cur;
220 edit_int64(nofile, nofile_s);
221 if (l_nofile > 0 && nofile<l_nofile) {
222 msg_status.strcat("nofile ");
223 }
224 }
225 }
226 #endif
227 #ifdef RLIMIT_MEMLOCK
228 if (getrlimit(RLIMIT_MEMLOCK, &rlim)==0) {
229 if (rlim.rlim_cur == RLIM_INFINITY) {
230 memlock=-1;
231 bstrncpy(memlock_s, "unlimited", sizeof(memlock_s));
232 } else {
233 memlock=rlim.rlim_cur;
234 edit_int64(memlock, memlock_s);
235 if (l_memlock > 0 && memlock<l_memlock) {
236 msg_status.strcat("memlock ");
237 }
238 }
239 }
240 #endif
241
242 if (strlen(msg_status.c_str())>0) {
243 strip_trailing_junk(msg_status.c_str());
244 } else {
245 msg_status.strcpy("ok");
246 }
247
248 if (sp->api > 1) {
249 OutputWriter ow(sp->api_opts);
250 char *p;
251 ow.start_group("ulimit");
252 ow.get_output( OT_START_OBJ,
253 OT_INT64, "nofile", nofile,
254 OT_INT64, "memlock", memlock,
255 OT_STRING, "status", msg_status.c_str(),
256 OT_END_OBJ,
257 OT_END);
258 p = ow.end_group(); // dedupengine
259 sendit(p, strlen(p), sp);
260 } else {
261 int len = Mmsg(msg, _(" Ulimits: nofile=%s memlock=%s status=%s\n"),
262 nofile_s, memlock_s, msg_status.c_str());
263 sendit(msg.c_str(), len, sp);
264 }
265 #endif
266 }
267
268 #if defined(HAVE_WIN32)
269 int bacstat = 0;
270
271 #ifdef FILE_DAEMON
272 # define BAC_COMPONENT "Client"
273 #else
274 # define BAC_COMPONENT "Storage"
275 #endif
276
277 /* Return a one line status for the tray monitor */
bac_status(char * buf,int buf_len)278 char *bac_status(char *buf, int buf_len)
279 {
280 JCR *njcr;
281 const char *termstat = _("Bacula " BAC_COMPONENT ": Idle");
282 struct s_last_job *job;
283 int stat = 0; /* Idle */
284
285 if (!last_jobs) {
286 goto done;
287 }
288 Dmsg0(1000, "Begin bac_status jcr loop.\n");
289 foreach_jcr(njcr) {
290 if (njcr->JobId != 0) {
291 stat = JS_Running;
292 termstat = _("Bacula " BAC_COMPONENT ": Running");
293 break;
294 }
295 }
296 endeach_jcr(njcr);
297
298 if (stat != 0) {
299 goto done;
300 }
301 if (last_jobs->size() > 0) {
302 job = (struct s_last_job *)last_jobs->last();
303 stat = job->JobStatus;
304 switch (job->JobStatus) {
305 case JS_Canceled:
306 termstat = _("Bacula " BAC_COMPONENT ": Last Job Canceled");
307 break;
308 case JS_ErrorTerminated:
309 case JS_FatalError:
310 termstat = _("Bacula " BAC_COMPONENT ": Last Job Failed");
311 break;
312 default:
313 if (job->Errors) {
314 termstat = _("Bacula " BAC_COMPONENT ": Last Job had Warnings");
315 }
316 break;
317 }
318 }
319 Dmsg0(1000, "End bac_status jcr loop.\n");
320 done:
321 bacstat = stat;
322 if (buf) {
323 bstrncpy(buf, termstat, buf_len);
324 }
325 return buf;
326 }
327
328 #endif /* HAVE_WIN32 */
329
330 #endif /* ! STATUS_FUNCTIONS */
331
332 #endif
333