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 *
21 * Routines for getting and displaying tape alerts
22 *
23 * Written by Kern Sibbald, October MMXVI
24 *
25 */
26
27 #include "bacula.h" /* pull in global headers */
28 #include "stored.h" /* pull in Storage Deamon headers */
29
30 #include "tape_alert_msgs.h"
31
32 static const int dbglvl = 120;
33
34 #define MAX_MSG 54 /* Maximum alert message number */
35
alert_callback(void * ctx,const char * short_msg,const char * long_msg,char * Volume,int severity,int flags,int alertno,utime_t alert_time)36 void alert_callback(void *ctx, const char *short_msg, const char *long_msg,
37 char *Volume, int severity, int flags, int alertno, utime_t alert_time)
38 {
39 DCR *dcr = (DCR *)ctx;
40 JCR *jcr = dcr->jcr;
41 DEVICE *dev = dcr->dev;
42 int type = M_INFO;
43
44 switch (severity) {
45 case 'C':
46 type = M_FATAL;
47 break;
48 case 'W':
49 type = M_WARNING;
50 break;
51 case 'I':
52 type = M_INFO;
53 break;
54 }
55 if (flags & TA_DISABLE_DRIVE) {
56 dev->enabled = false;
57 Jmsg(jcr, M_WARNING, 0, _("Disabled Device %s due to tape alert=%d.\n"),
58 dev->print_name(), alertno);
59 Tmsg2(dbglvl, _("Disabled Device %s due to tape alert=%d.\n"),
60 dev->print_name(), alertno);
61 }
62 if (flags & TA_DISABLE_VOLUME) {
63 dev->setVolCatStatus("Disabled");
64 dev->VolCatInfo.VolEnabled = false;
65 dir_update_volume_info(dcr, false, true);
66 Jmsg(jcr, M_WARNING, 0, _("Disabled Volume \"%s\" due to tape alert=%d.\n"),
67 Volume, alertno);
68 Tmsg2(dbglvl, _("Disabled Volume \"%s\" due to tape alert=%d.\n"),
69 Volume, alertno);
70 }
71 Jmsg(jcr, type, (utime_t)alert_time, _("Alert: Volume=\"%s\" alert=%d: ERR=%s\n"),
72 Volume, alertno, long_msg);
73 }
74
get_tape_alerts(DCR * dcr)75 bool tape_dev::get_tape_alerts(DCR *dcr)
76 {
77 JCR *jcr = dcr->jcr;
78 if (job_canceled(jcr)) {
79 return false;
80 }
81 if (dcr->device->alert_command && dcr->device->control_name) {
82 POOLMEM *alertcmd;
83 int status = 1;
84 int nalerts = 0;
85 BPIPE *bpipe;
86 ALERT *alert, *rmalert;
87 char line[MAXSTRING];
88 const char *fmt = "TapeAlert[%d]";
89
90 struct stat statp;
91 if (stat(dcr->device->control_name, &statp) < 0) {
92 berrno be;
93 Jmsg2(jcr, M_ERROR, 0, _("Unable to stat ControlDevice %s: ERR=%s\n"),
94 dcr->device->control_name, be.bstrerror());
95 return false;
96 }
97
98 if (!alert_list) {
99 alert_list = New(alist(10));
100 }
101 alertcmd = get_pool_memory(PM_FNAME);
102 alertcmd = edit_device_codes(dcr, alertcmd, dcr->device->alert_command, "");
103 /* Wait maximum 5 minutes */
104 bpipe = open_bpipe(alertcmd, 60 * 5, "r");
105 if (bpipe) {
106 int alertno;
107 alert = (ALERT *)malloc(sizeof(ALERT));
108 memset(alert->alerts, 0, sizeof(alert->alerts));
109 alert->Volume = bstrdup(getVolCatName());
110 alert->alert_time = (utime_t)time(NULL);
111 while (fgets(line, (int)sizeof(line), bpipe->rfd)) {
112 alertno = 0;
113 if (bsscanf(line, fmt, &alertno) == 1) {
114 if (alertno > 0) {
115 if (nalerts+1 > (int)sizeof(alert->alerts)) {
116 break;
117 } else {
118 alert->alerts[nalerts++] = alertno;
119 }
120 }
121 }
122 }
123 status = close_bpipe(bpipe);
124 if (nalerts > 0) {
125 /* Maintain First in, last out list */
126 if (alert_list->size() > 8) {
127 rmalert = (ALERT *)alert_list->last();
128 free(rmalert->Volume);
129 alert_list->pop();
130 free(rmalert);
131 }
132 alert_list->prepend(alert);
133 } else {
134 free(alert->Volume);
135 free(alert);
136 }
137 free_pool_memory(alertcmd);
138 return true;
139 } else {
140 status = errno;
141 }
142 if (status != 0) {
143 berrno be;
144 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
145 alertcmd, be.bstrerror(status));
146 Tmsg2(10, _("3997 Bad alert command: %s: ERR=%s.\n"),
147 alertcmd, be.bstrerror(status));
148 }
149
150 Dmsg1(400, "alert status=%d\n", status);
151 free_pool_memory(alertcmd);
152 } else {
153 if (!dcr->device->alert_command) {
154 Dmsg1(dbglvl, "Cannot do tape alerts: no Alert Command specified for device %s\n",
155 print_name());
156 Tmsg1(dbglvl, "Cannot do tape alerts: no Alert Command specified for device %s\n",
157 print_name());
158
159 }
160 if (!dcr->device->control_name) {
161 Dmsg1(dbglvl, "Cannot do tape alerts: no Control Device specified for device %s\n",
162 print_name());
163 Tmsg1(dbglvl, "Cannot do tape alerts: no Control Device specified for device %s\n",
164 print_name());
165 }
166 }
167 return false;
168 }
169
170
171 /*
172 * Print desired tape alert messages
173 */
show_tape_alerts(DCR * dcr,alert_list_type list_type,alert_list_which which,alert_cb alert_callback)174 void tape_dev::show_tape_alerts(DCR *dcr, alert_list_type list_type,
175 alert_list_which which, alert_cb alert_callback)
176 {
177 int i;
178 ALERT *alert;
179 int code;
180
181 if (!alert_list) {
182 return;
183 }
184 Dmsg1(dbglvl, "There are %d alerts.\n", alert_list->size());
185 switch (list_type) {
186 case list_codes:
187 foreach_alist(alert, alert_list) {
188 for (i=0; i<(int)sizeof(alert->alerts) && alert->alerts[i]; i++) {
189 code = alert->alerts[i];
190 Dmsg4(dbglvl, "Volume=%s alert=%d severity=%c flags=0x%x\n", alert->Volume, code,
191 ta_errors[code].severity, (int)ta_errors[code].flags);
192 alert_callback(dcr, ta_errors[code].short_msg, long_msg[code],
193 alert->Volume, ta_errors[code].severity,
194 ta_errors[code].flags, code, (utime_t)alert->alert_time);
195 }
196 if (which == list_last) {
197 break;
198 }
199 }
200 break;
201 default:
202 foreach_alist(alert, alert_list) {
203 for (i=0; i<(int)sizeof(alert->alerts) && alert->alerts[i]; i++) {
204 code = alert->alerts[i];
205 Dmsg4(dbglvl, "Volume=%s severity=%c flags=0x%x alert=%s\n", alert->Volume,
206 ta_errors[code].severity, (int)ta_errors[code].flags,
207 ta_errors[code].short_msg);
208 alert_callback(dcr, ta_errors[code].short_msg, long_msg[code],
209 alert->Volume, ta_errors[code].severity,
210 ta_errors[code].flags, code, (utime_t)alert->alert_time);
211 }
212 if (which == list_last) {
213 break;
214 }
215 }
216 break;
217 }
218 return;
219 }
220
221 /*
222 * Delete alert list returning number deleted
223 */
delete_alerts()224 int tape_dev::delete_alerts()
225 {
226 ALERT *alert;
227 int deleted = 0;
228
229 if (alert_list) {
230 foreach_alist(alert, alert_list) {
231 free(alert->Volume);
232 deleted++;
233 }
234 alert_list->destroy();
235 free(alert_list);
236 alert_list = NULL;
237 }
238 return deleted;
239 }
240