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
79 if (!job_canceled(jcr) && dcr->device->alert_command &&
80 dcr->device->control_name) {
81 POOLMEM *alertcmd;
82 int status = 1;
83 int nalerts = 0;
84 BPIPE *bpipe;
85 ALERT *alert, *rmalert;
86 char line[MAXSTRING];
87 const char *fmt = "TapeAlert[%d]";
88
89 if (!alert_list) {
90 alert_list = New(alist(10));
91 }
92 alertcmd = get_pool_memory(PM_FNAME);
93 alertcmd = edit_device_codes(dcr, alertcmd, dcr->device->alert_command, "");
94 /* Wait maximum 5 minutes */
95 bpipe = open_bpipe(alertcmd, 60 * 5, "r");
96 if (bpipe) {
97 int alertno;
98 alert = (ALERT *)malloc(sizeof(ALERT));
99 memset(alert->alerts, 0, sizeof(alert->alerts));
100 alert->Volume = bstrdup(getVolCatName());
101 alert->alert_time = (utime_t)time(NULL);
102 while (fgets(line, (int)sizeof(line), bpipe->rfd)) {
103 alertno = 0;
104 if (bsscanf(line, fmt, &alertno) == 1) {
105 if (alertno > 0) {
106 if (nalerts+1 > (int)sizeof(alert->alerts)) {
107 break;
108 } else {
109 alert->alerts[nalerts++] = alertno;
110 }
111 }
112 }
113 }
114 status = close_bpipe(bpipe);
115 if (nalerts > 0) {
116 /* Maintain First in, last out list */
117 if (alert_list->size() > 8) {
118 rmalert = (ALERT *)alert_list->last();
119 free(rmalert->Volume);
120 alert_list->pop();
121 free(rmalert);
122 }
123 alert_list->prepend(alert);
124 } else {
125 free(alert->Volume);
126 free(alert);
127 }
128 free_pool_memory(alertcmd);
129 return true;
130 } else {
131 status = errno;
132 }
133 if (status != 0) {
134 berrno be;
135 Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
136 alertcmd, be.bstrerror(status));
137 Tmsg2(10, _("3997 Bad alert command: %s: ERR=%s.\n"),
138 alertcmd, be.bstrerror(status));
139 }
140
141 Dmsg1(400, "alert status=%d\n", status);
142 free_pool_memory(alertcmd);
143 } else {
144 if (!dcr->device->alert_command) {
145 Dmsg1(dbglvl, "Cannot do tape alerts: no Alert Command specified for device %s\n",
146 print_name());
147 Tmsg1(dbglvl, "Cannot do tape alerts: no Alert Command specified for device %s\n",
148 print_name());
149
150 }
151 if (!dcr->device->control_name) {
152 Dmsg1(dbglvl, "Cannot do tape alerts: no Control Device specified for device %s\n",
153 print_name());
154 Tmsg1(dbglvl, "Cannot do tape alerts: no Control Device specified for device %s\n",
155 print_name());
156 }
157 }
158 return false;
159 }
160
161
162 /*
163 * Print desired tape alert messages
164 */
show_tape_alerts(DCR * dcr,alert_list_type list_type,alert_list_which which,alert_cb alert_callback)165 void tape_dev::show_tape_alerts(DCR *dcr, alert_list_type list_type,
166 alert_list_which which, alert_cb alert_callback)
167 {
168 int i;
169 ALERT *alert;
170 int code;
171
172 if (!alert_list) {
173 return;
174 }
175 Dmsg1(dbglvl, "There are %d alerts.\n", alert_list->size());
176 switch (list_type) {
177 case list_codes:
178 foreach_alist(alert, alert_list) {
179 for (i=0; i<(int)sizeof(alert->alerts) && alert->alerts[i]; i++) {
180 code = alert->alerts[i];
181 Dmsg4(dbglvl, "Volume=%s alert=%d severity=%c flags=0x%x\n", alert->Volume, code,
182 ta_errors[code].severity, (int)ta_errors[code].flags);
183 alert_callback(dcr, ta_errors[code].short_msg, long_msg[code],
184 alert->Volume, ta_errors[code].severity,
185 ta_errors[code].flags, code, (utime_t)alert->alert_time);
186 }
187 if (which == list_last) {
188 break;
189 }
190 }
191 break;
192 default:
193 foreach_alist(alert, alert_list) {
194 for (i=0; i<(int)sizeof(alert->alerts) && alert->alerts[i]; i++) {
195 code = alert->alerts[i];
196 Dmsg4(dbglvl, "Volume=%s severity=%c flags=0x%x alert=%s\n", alert->Volume,
197 ta_errors[code].severity, (int)ta_errors[code].flags,
198 ta_errors[code].short_msg);
199 alert_callback(dcr, ta_errors[code].short_msg, long_msg[code],
200 alert->Volume, ta_errors[code].severity,
201 ta_errors[code].flags, code, (utime_t)alert->alert_time);
202 }
203 if (which == list_last) {
204 break;
205 }
206 }
207 break;
208 }
209 return;
210 }
211
212 /*
213 * Delete alert list returning number deleted
214 */
delete_alerts()215 int tape_dev::delete_alerts()
216 {
217 ALERT *alert;
218 int deleted = 0;
219
220 if (alert_list) {
221 foreach_alist(alert, alert_list) {
222 free(alert->Volume);
223 deleted++;
224 }
225 alert_list->destroy();
226 free(alert_list);
227 alert_list = NULL;
228 }
229 return deleted;
230 }
231