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 * Bacula Catalog Database Create record interface routines
21 *
22 * Written by Kern Sibbald, March 2000
23 *
24 */
25
26 #include "bacula.h"
27
28 static const int dbglevel = 100;
29
30 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
31
32 #include "cats.h"
33
34 /* -----------------------------------------------------------------------
35 *
36 * Generic Routines (or almost generic)
37 *
38 * -----------------------------------------------------------------------
39 */
40
41 /** Create a new record for the Job
42 * Returns: false on failure
43 * true on success
44 */
bdb_create_job_record(JCR * jcr,JOB_DBR * jr)45 bool BDB::bdb_create_job_record(JCR *jcr, JOB_DBR *jr)
46 {
47 POOL_MEM buf;
48 char dt[MAX_TIME_LENGTH], dt2[MAX_TIME_LENGTH];
49 time_t stime, starttime;
50 struct tm tm;
51 bool ok;
52 int len;
53 utime_t JobTDate;
54 char ed1[30],ed2[30];
55 char esc_job[MAX_ESCAPE_NAME_LENGTH];
56 char esc_name[MAX_ESCAPE_NAME_LENGTH];
57
58 bdb_lock();
59
60 stime = jr->SchedTime;
61 starttime = jr->StartTime;
62 ASSERT(stime != 0);
63
64 (void)localtime_r(&stime, &tm);
65 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
66
67 (void)localtime_r(&starttime, &tm);
68 strftime(dt2, sizeof(dt2), "%Y-%m-%d %H:%M:%S", &tm);
69 JobTDate = (utime_t)stime;
70
71 len = strlen(jcr->comment); /* TODO: use jr instead of jcr to get comment */
72 buf.check_size(len*2+1);
73 bdb_escape_string(jcr, buf.c_str(), jcr->comment, len);
74
75 bdb_escape_string(jcr, esc_job, jr->Job, strlen(jr->Job));
76 bdb_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name));
77
78 /* Must create it */
79 Mmsg(cmd,
80 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,StartTime,SchedTime,JobTDate,"
81 "ClientId,Comment) "
82 "VALUES ('%s','%s','%c','%c','%c','%s','%s',%s,%s,'%s')",
83 esc_job, esc_name, (char)(jr->JobType), (char)(jr->JobLevel),
84 (char)(jr->JobStatus), dt2, dt, edit_uint64(JobTDate, ed1),
85 edit_int64(jr->ClientId, ed2), buf.c_str());
86
87 if ((jr->JobId = sql_insert_autokey_record(cmd, NT_("Job"))) == 0) {
88 Mmsg2(&errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
89 cmd, sql_strerror());
90 ok = false;
91 } else {
92 ok = true;
93 }
94 bdb_unlock();
95 return ok;
96 }
97
98
99 /** Create a JobMedia record for medium used this job
100 * Returns: false on failure
101 * true on success
102 */
bdb_create_jobmedia_record(JCR * jcr,JOBMEDIA_DBR * jm)103 bool BDB::bdb_create_jobmedia_record(JCR *jcr, JOBMEDIA_DBR *jm)
104 {
105 bool ok = true;
106 int count;
107 char ed1[50], ed2[50];
108
109 bdb_lock();
110
111 /* Now get count for VolIndex */
112 Mmsg(cmd, "SELECT MAX(VolIndex) from JobMedia WHERE JobId=%s",
113 edit_int64(jm->JobId, ed1));
114 count = get_sql_record_max(jcr, this);
115
116 if (count < 0) {
117 count = 0;
118 }
119 count++;
120
121 Mmsg(cmd,
122 "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
123 "StartFile,EndFile,StartBlock,EndBlock,VolIndex) "
124 "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u)",
125 edit_int64(jm->JobId, ed1),
126 edit_int64(jm->MediaId, ed2),
127 jm->FirstIndex, jm->LastIndex,
128 jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count);
129
130 Dmsg0(300, cmd);
131 if (!InsertDB(jcr, cmd)) {
132 Mmsg2(&errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), cmd,
133 sql_strerror());
134 ok = false;
135 } else {
136 /* Worked, now update the Media record with the EndFile and EndBlock */
137 Mmsg(cmd,
138 "UPDATE Media SET EndFile=%lu, EndBlock=%lu WHERE MediaId=%lu",
139 jm->EndFile, jm->EndBlock, jm->MediaId);
140 if (!UpdateDB(jcr, cmd, false)) {
141 Mmsg2(&errmsg, _("Update Media record %s failed: ERR=%s\n"), cmd,
142 sql_strerror());
143 ok = false;
144 }
145 }
146 bdb_unlock();
147 Dmsg0(300, "Return from JobMedia\n");
148 return ok;
149 }
150
151
152 /** Create a fileMedia record for File index
153 * Returns: false on failure
154 * true on success
155 */
bdb_create_filemedia_record(JCR * jcr,FILEMEDIA_DBR * fm)156 bool BDB::bdb_create_filemedia_record(JCR *jcr, FILEMEDIA_DBR *fm)
157 {
158 bool ok = true;
159 char ed1[50], ed2[50];
160
161 bdb_lock();
162
163 Mmsg(cmd,
164 "INSERT INTO FileMedia (JobId,MediaId,FileIndex,BlockAddress,RecordNo,"
165 "FileOffset) "
166 "VALUES (%s,%s,%u,%lld,%u,%lld)",
167 edit_int64(fm->JobId, ed1),
168 edit_int64(fm->MediaId, ed2),
169 fm->FileIndex, fm->BlockAddress,
170 fm->RecordNo, fm->FileOffset);
171
172 Dmsg0(300, cmd);
173 if (!InsertDB(jcr, cmd)) {
174 Mmsg2(&errmsg, _("Create FileMedia record %s failed: ERR=%s\n"), cmd,
175 sql_strerror());
176 ok = false;
177 }
178 bdb_unlock();
179 return ok;
180 }
181
182 /** Create Unique Pool record
183 * Returns: false on failure
184 * true on success
185 */
bdb_create_pool_record(JCR * jcr,POOL_DBR * pr)186 bool BDB::bdb_create_pool_record(JCR *jcr, POOL_DBR *pr)
187 {
188 bool stat;
189 char ed1[30], ed2[30], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50];
190 char esc_name[MAX_ESCAPE_NAME_LENGTH];
191 char esc_lf[MAX_ESCAPE_NAME_LENGTH];
192 char esc_type[MAX_ESCAPE_NAME_LENGTH];
193
194 /* The pooltype should match the case when we insert it to the catalog
195 * backup -> Backup, BACKUP -> Backup
196 */
197 ucfirst(esc_type, pr->PoolType, sizeof(esc_type));
198
199 Dmsg0(200, "In create pool\n");
200 bdb_lock();
201 bdb_escape_string(jcr, esc_name, pr->Name, strlen(pr->Name));
202 bdb_escape_string(jcr, esc_lf, pr->LabelFormat, strlen(pr->LabelFormat));
203 Mmsg(cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", esc_name);
204 Dmsg1(200, "selectpool: %s\n", cmd);
205
206 if (QueryDB(jcr, cmd)) {
207 if (sql_num_rows() > 0) {
208 Mmsg1(&errmsg, _("pool record %s already exists\n"), pr->Name);
209 sql_free_result();
210 bdb_unlock();
211 Dmsg1(200, "%s", errmsg); /* pool already exists */
212 return false;
213 }
214 sql_free_result();
215 }
216
217 /* Must create it */
218 Mmsg(cmd,
219 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
220 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
221 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat,"
222 "RecyclePoolId,ScratchPoolId,ActionOnPurge,CacheRetention,MaxPoolBytes) "
223 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d,%s,%s)",
224 esc_name,
225 pr->NumVols, pr->MaxVols,
226 pr->UseOnce, pr->UseCatalog,
227 pr->AcceptAnyVolume,
228 pr->AutoPrune, pr->Recycle,
229 edit_uint64(pr->VolRetention, ed1),
230 edit_uint64(pr->VolUseDuration, ed2),
231 pr->MaxVolJobs, pr->MaxVolFiles,
232 edit_uint64(pr->MaxVolBytes, ed3),
233 esc_type, pr->LabelType, esc_lf,
234 edit_int64(pr->RecyclePoolId,ed4),
235 edit_int64(pr->ScratchPoolId,ed5),
236 pr->ActionOnPurge,
237 edit_uint64(pr->CacheRetention, ed6),
238 edit_int64(pr->MaxPoolBytes, ed7)
239 );
240 Dmsg1(200, "Create Pool: %s\n", cmd);
241 if ((pr->PoolId = sql_insert_autokey_record(cmd, NT_("Pool"))) == 0) {
242 Mmsg2(&errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
243 cmd, sql_strerror());
244 stat = false;
245 } else {
246 stat = true;
247 }
248 bdb_unlock();
249 return stat;
250 }
251
252 /**
253 * Create Unique Device record
254 * Returns: false on failure
255 * true on success
256 */
bdb_create_device_record(JCR * jcr,DEVICE_DBR * dr)257 bool BDB::bdb_create_device_record(JCR *jcr, DEVICE_DBR *dr)
258 {
259 bool ok;
260 char ed1[30], ed2[30];
261 char esc[MAX_ESCAPE_NAME_LENGTH];
262
263 Dmsg0(200, "In create Device\n");
264 bdb_lock();
265 bdb_escape_string(jcr, esc, dr->Name, strlen(dr->Name));
266 Mmsg(cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", esc);
267 Dmsg1(200, "selectdevice: %s\n", cmd);
268
269 if (QueryDB(jcr, cmd)) {
270 if (sql_num_rows() > 0) {
271 Mmsg1(&errmsg, _("Device record %s already exists\n"), dr->Name);
272 sql_free_result();
273 bdb_unlock();
274 return false;
275 }
276 sql_free_result();
277 }
278
279 /* Must create it */
280 Mmsg(cmd,
281 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
282 esc,
283 edit_uint64(dr->MediaTypeId, ed1),
284 edit_int64(dr->StorageId, ed2));
285 Dmsg1(200, "Create Device: %s\n", cmd);
286 if ((dr->DeviceId = sql_insert_autokey_record(cmd, NT_("Device"))) == 0) {
287 Mmsg2(&errmsg, _("Create db Device record %s failed: ERR=%s\n"),
288 cmd, sql_strerror());
289 ok = false;
290 } else {
291 ok = true;
292 }
293 bdb_unlock();
294 return ok;
295 }
296
297
298
299 /**
300 * Create a Unique record for Storage -- no duplicates
301 * Returns: false on failure
302 * true on success with id in sr->StorageId
303 */
bdb_create_storage_record(JCR * jcr,STORAGE_DBR * sr)304 bool BDB::bdb_create_storage_record(JCR *jcr, STORAGE_DBR *sr)
305 {
306 SQL_ROW row;
307 bool ok;
308 char esc[MAX_ESCAPE_NAME_LENGTH];
309
310 bdb_lock();
311 bdb_escape_string(jcr, esc, sr->Name, strlen(sr->Name));
312 Mmsg(cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'",esc);
313
314 sr->StorageId = 0;
315 sr->created = false;
316 /* Check if it already exists */
317 if (QueryDB(jcr, cmd)) {
318 /* If more than one, report error, but return first row */
319 if (sql_num_rows() > 1) {
320 Mmsg1(&errmsg, _("More than one Storage record!: %d\n"), sql_num_rows());
321 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
322 }
323 if (sql_num_rows() >= 1) {
324 if ((row = sql_fetch_row()) == NULL) {
325 Mmsg1(&errmsg, _("error fetching Storage row: %s\n"), sql_strerror());
326 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
327 sql_free_result();
328 bdb_unlock();
329 return false;
330 }
331 sr->StorageId = str_to_int64(row[0]);
332 sr->AutoChanger = atoi(row[1]); /* bool */
333 sql_free_result();
334 bdb_unlock();
335 return true;
336 }
337 sql_free_result();
338 }
339
340 /* Must create it */
341 Mmsg(cmd, "INSERT INTO Storage (Name,AutoChanger)"
342 " VALUES ('%s',%d)", esc, sr->AutoChanger);
343
344 if ((sr->StorageId = sql_insert_autokey_record(cmd, NT_("Storage"))) == 0) {
345 Mmsg2(&errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
346 cmd, sql_strerror());
347 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
348 ok = false;
349 } else {
350 sr->created = true;
351 ok = true;
352 }
353 bdb_unlock();
354 return ok;
355 }
356
357
358 /**
359 * Create Unique MediaType record
360 * Returns: false on failure
361 * true on success
362 */
bdb_create_mediatype_record(JCR * jcr,MEDIATYPE_DBR * mr)363 bool BDB::bdb_create_mediatype_record(JCR *jcr, MEDIATYPE_DBR *mr)
364 {
365 bool stat;
366 char esc[MAX_ESCAPE_NAME_LENGTH];
367
368 Dmsg0(200, "In create mediatype\n");
369 bdb_lock();
370 bdb_escape_string(jcr, esc, mr->MediaType, strlen(mr->MediaType));
371 Mmsg(cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", esc);
372 Dmsg1(200, "selectmediatype: %s\n", cmd);
373
374 if (QueryDB(jcr, cmd)) {
375 if (sql_num_rows() > 0) {
376 Mmsg1(&errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
377 sql_free_result();
378 bdb_unlock();
379 return false;
380 }
381 sql_free_result();
382 }
383
384 /* Must create it */
385 Mmsg(cmd,
386 "INSERT INTO MediaType (MediaType,ReadOnly) "
387 "VALUES ('%s',%d)",
388 mr->MediaType,
389 mr->ReadOnly);
390 Dmsg1(200, "Create mediatype: %s\n", cmd);
391 if ((mr->MediaTypeId = sql_insert_autokey_record(cmd, NT_("MediaType"))) == 0) {
392 Mmsg2(&errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
393 cmd, sql_strerror());
394 stat = false;
395 } else {
396 stat = true;
397 }
398 bdb_unlock();
399 return stat;
400 }
401
402
403 /**
404 * Create Media record. VolumeName and non-zero Slot must be unique
405 *
406 * Returns: 0 on failure
407 * 1 on success
408 */
bdb_create_media_record(JCR * jcr,MEDIA_DBR * mr)409 int BDB::bdb_create_media_record(JCR *jcr, MEDIA_DBR *mr)
410 {
411 int stat;
412 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
413 char ed9[50], ed10[50], ed11[50], ed12[50], ed13[50], ed14[50];
414 struct tm tm;
415 char esc_name[MAX_ESCAPE_NAME_LENGTH];
416 char esc_mtype[MAX_ESCAPE_NAME_LENGTH];
417 char esc_status[MAX_ESCAPE_NAME_LENGTH];
418
419
420 bdb_lock();
421 bdb_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
422 bdb_escape_string(jcr, esc_mtype, mr->MediaType, strlen(mr->MediaType));
423 bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
424
425 Mmsg(cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'", esc_name);
426 Dmsg1(500, "selectpool: %s\n", cmd);
427
428 if (QueryDB(jcr, cmd)) {
429 if (sql_num_rows() > 0) {
430 Mmsg1(&errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
431 sql_free_result();
432 bdb_unlock();
433 return 0;
434 }
435 sql_free_result();
436 }
437
438 /* Must create it */
439 Mmsg(cmd,
440 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
441 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
442 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolType,"
443 "VolParts,VolCloudParts,LastPartBytes,"
444 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
445 "ScratchPoolId,RecyclePoolId,Enabled,ActionOnPurge,CacheRetention)"
446 "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,"
447 "%d,%d,'%s',%d,%d,%d,%s,%s,%s,%s,%s,%d,%d,%s)",
448 esc_name,
449 esc_mtype, mr->PoolId,
450 edit_uint64(mr->MaxVolBytes,ed1),
451 edit_uint64(mr->VolCapacityBytes, ed2),
452 mr->Recycle,
453 edit_uint64(mr->VolRetention, ed3),
454 edit_uint64(mr->VolUseDuration, ed4),
455 mr->MaxVolJobs,
456 mr->MaxVolFiles,
457 esc_status,
458 mr->Slot,
459 edit_uint64(mr->VolBytes, ed5),
460 mr->InChanger,
461 edit_int64(mr->VolReadTime, ed6),
462 edit_int64(mr->VolWriteTime, ed7),
463 mr->VolType,
464 mr->VolParts,
465 mr->VolCloudParts,
466 edit_uint64(mr->LastPartBytes, ed8),
467 mr->EndFile,
468 mr->EndBlock,
469 mr->LabelType,
470 edit_int64(mr->StorageId, ed9),
471 edit_int64(mr->DeviceId, ed10),
472 edit_int64(mr->LocationId, ed11),
473 edit_int64(mr->ScratchPoolId, ed12),
474 edit_int64(mr->RecyclePoolId, ed13),
475 mr->Enabled,
476 mr->ActionOnPurge,
477 edit_uint64(mr->CacheRetention, ed14)
478 );
479
480
481 Dmsg1(500, "Create Volume: %s\n", cmd);
482 if ((mr->MediaId = sql_insert_autokey_record(cmd, NT_("Media"))) == 0) {
483 Mmsg2(&errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
484 cmd, sql_strerror());
485 stat = 0;
486 } else {
487 stat = 1;
488 if (mr->set_label_date) {
489 char dt[MAX_TIME_LENGTH];
490 if (mr->LabelDate == 0) {
491 mr->LabelDate = time(NULL);
492 }
493 (void)localtime_r(&mr->LabelDate, &tm);
494 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
495 Mmsg(cmd, "UPDATE Media SET LabelDate='%s' "
496 "WHERE MediaId=%lu", dt, mr->MediaId);
497 stat = UpdateDB(jcr, cmd, false);
498 }
499 /*
500 * Make sure that if InChanger is non-zero any other identical slot
501 * has InChanger zero.
502 */
503 db_make_inchanger_unique(jcr, this, mr);
504 }
505
506 bdb_unlock();
507 return stat;
508 }
509
510 /**
511 * Create a Unique record for the client -- no duplicates
512 * Returns: 0 on failure
513 * 1 on success with id in cr->ClientId
514 */
bdb_create_client_record(JCR * jcr,CLIENT_DBR * cr)515 int BDB::bdb_create_client_record(JCR *jcr, CLIENT_DBR *cr)
516 {
517 SQL_ROW row;
518 int stat;
519 char ed1[50], ed2[50];
520 char esc_name[MAX_ESCAPE_NAME_LENGTH];
521 char esc_uname[MAX_ESCAPE_NAME_LENGTH];
522
523 bdb_lock();
524 bdb_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
525 bdb_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
526 Mmsg(cmd, "SELECT ClientId,Uname,AutoPrune,"
527 "FileRetention,JobRetention FROM Client WHERE Name='%s'",esc_name);
528
529 cr->ClientId = 0;
530 if (QueryDB(jcr, cmd)) {
531 /* If more than one, report error, but return first row */
532 if (sql_num_rows() > 1) {
533 Mmsg1(&errmsg, _("More than one Client!: %d\n"), sql_num_rows());
534 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
535 }
536 if (sql_num_rows() >= 1) {
537 if ((row = sql_fetch_row()) == NULL) {
538 Mmsg1(&errmsg, _("error fetching Client row: %s\n"), sql_strerror());
539 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
540 sql_free_result();
541 bdb_unlock();
542 return 0;
543 }
544 cr->ClientId = str_to_int64(row[0]);
545 if (row[1]) {
546 bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
547 } else {
548 cr->Uname[0] = 0; /* no name */
549 }
550 cr->AutoPrune = str_to_int64(row[2]);
551 cr->FileRetention = str_to_int64(row[3]);
552 cr->JobRetention = str_to_int64(row[4]);
553 sql_free_result();
554 bdb_unlock();
555 return 1;
556 }
557 sql_free_result();
558 }
559
560 /* Must create it */
561 Mmsg(cmd, "INSERT INTO Client (Name,Uname,AutoPrune,"
562 "FileRetention,JobRetention) VALUES "
563 "('%s','%s',%d,%s,%s)", esc_name, esc_uname, cr->AutoPrune,
564 edit_uint64(cr->FileRetention, ed1),
565 edit_uint64(cr->JobRetention, ed2));
566
567 if ((cr->ClientId = sql_insert_autokey_record(cmd, NT_("Client"))) == 0) {
568 Mmsg2(&errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
569 cmd, sql_strerror());
570 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
571 stat = 0;
572 } else {
573 stat = 1;
574 }
575 bdb_unlock();
576 return stat;
577 }
578
579
580 /** Create a Unique record for the Path -- no duplicates */
bdb_create_path_record(JCR * jcr,ATTR_DBR * ar)581 int BDB::bdb_create_path_record(JCR *jcr, ATTR_DBR *ar)
582 {
583 SQL_ROW row;
584 int stat;
585
586 errmsg[0] = 0;
587 esc_name = check_pool_memory_size(esc_name, 2*pnl+2);
588 bdb_escape_string(jcr, esc_name, path, pnl);
589
590 if (cached_path_id != 0 && cached_path_len == pnl &&
591 strcmp(cached_path, path) == 0) {
592 ar->PathId = cached_path_id;
593 return 1;
594 }
595
596 Mmsg(cmd, "SELECT PathId FROM Path WHERE Path='%s'", esc_name);
597
598 if (QueryDB(jcr, cmd)) {
599 if (sql_num_rows() > 1) {
600 char ed1[30];
601 Mmsg2(&errmsg, _("More than one Path!: %s for path: %s\n"),
602 edit_uint64(sql_num_rows(), ed1), path);
603 Jmsg(jcr, M_WARNING, 0, "%s", errmsg);
604 }
605 /* Even if there are multiple paths, take the first one */
606 if (sql_num_rows() >= 1) {
607 if ((row = sql_fetch_row()) == NULL) {
608 Mmsg1(&errmsg, _("error fetching row: %s\n"), sql_strerror());
609 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
610 sql_free_result();
611 ar->PathId = 0;
612 ASSERT2(ar->PathId,
613 "Your Path table is broken. "
614 "Please, use dbcheck to correct it.");
615 return 0;
616 }
617 ar->PathId = str_to_int64(row[0]);
618 sql_free_result();
619 /* Cache path */
620 if (ar->PathId != cached_path_id) {
621 cached_path_id = ar->PathId;
622 cached_path_len = pnl;
623 pm_strcpy(cached_path, path);
624 }
625 ASSERT(ar->PathId);
626 return 1;
627 }
628 sql_free_result();
629 }
630
631 Mmsg(cmd, "INSERT INTO Path (Path) VALUES ('%s')", esc_name);
632
633 if ((ar->PathId = sql_insert_autokey_record(cmd, NT_("Path"))) == 0) {
634 Mmsg2(&errmsg, _("Create db Path record %s failed. ERR=%s\n"),
635 cmd, sql_strerror());
636 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
637 ar->PathId = 0;
638 stat = 0;
639 } else {
640 stat = 1;
641 }
642
643 /* Cache path */
644 if (stat && ar->PathId != cached_path_id) {
645 cached_path_id = ar->PathId;
646 cached_path_len = pnl;
647 pm_strcpy(cached_path, path);
648 }
649 return stat;
650 }
651
652 /**
653 * Create a Unique record for the counter -- no duplicates
654 * Returns: 0 on failure
655 * 1 on success with counter filled in
656 */
bdb_create_counter_record(JCR * jcr,COUNTER_DBR * cr)657 int BDB::bdb_create_counter_record(JCR *jcr, COUNTER_DBR *cr)
658 {
659 char esc[MAX_ESCAPE_NAME_LENGTH];
660 COUNTER_DBR mcr;
661 int stat;
662 bdb_lock();
663 memset(&mcr, 0, sizeof(mcr));
664 bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
665 if (bdb_get_counter_record(jcr, &mcr)) {
666 /* If the counter definition changed, we must update the record
667 */
668 if (mcr.MinValue != cr->MinValue ||
669 mcr.MaxValue != cr->MaxValue ||
670 strcmp(mcr.WrapCounter, cr->WrapCounter) != 0)
671 {
672 /* With the update, the current value can be wrong, we need
673 * to adjust it
674 */
675 if (mcr.CurrentValue > 0) {
676 if (cr->MinValue > mcr.CurrentValue) {
677 cr->CurrentValue = cr->MinValue;
678
679 } else if (cr->MaxValue < mcr.CurrentValue) {
680 cr->CurrentValue = cr->MaxValue;
681
682 } else {
683 cr->CurrentValue = mcr.CurrentValue;
684 }
685 }
686 Dmsg3(dbglevel, "org: MinValue=%ld MaxValue=%ld CurrentValue=%ld\n",
687 mcr.MinValue, mcr.MaxValue, mcr.CurrentValue);
688 Dmsg3(dbglevel, "new: MinValue=%ld MaxValue=%ld CurrentValue=%ld\n",
689 cr->MinValue, cr->MaxValue, cr->CurrentValue);
690 stat = bdb_update_counter_record(jcr, cr);
691
692 } else {
693 memcpy(cr, &mcr, sizeof(COUNTER_DBR));
694 stat = 1;
695 }
696 bdb_unlock();
697 return stat;
698 }
699
700 bdb_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
701
702 /* Must create it */
703 Mmsg(cmd, insert_counter_values[bdb_get_type_index()],
704 esc, cr->MinValue, cr->MaxValue, cr->CurrentValue,
705 cr->WrapCounter);
706
707 if (!InsertDB(jcr, cmd)) {
708 Mmsg2(&errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
709 cmd, sql_strerror());
710 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
711 stat = 0;
712 } else {
713 stat = 1;
714 }
715 bdb_unlock();
716 return stat;
717 }
718
719 /**
720 * Create a FileSet record. This record is unique in the
721 * name and the MD5 signature of the include/exclude sets.
722 * Returns: 0 on failure
723 * 1 on success with FileSetId in record
724 */
bdb_create_fileset_record(JCR * jcr,FILESET_DBR * fsr)725 bool BDB::bdb_create_fileset_record(JCR *jcr, FILESET_DBR *fsr)
726 {
727 SQL_ROW row;
728 bool stat;
729 struct tm tm;
730 char esc_fs[MAX_ESCAPE_NAME_LENGTH];
731 char esc_md5[MAX_ESCAPE_NAME_LENGTH];
732
733 /* TODO: Escape FileSet and MD5 */
734 bdb_lock();
735 fsr->created = false;
736 bdb_escape_string(jcr, esc_fs, fsr->FileSet, strlen(fsr->FileSet));
737 bdb_escape_string(jcr, esc_md5, fsr->MD5, strlen(fsr->MD5));
738 Mmsg(cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
739 "FileSet='%s' AND MD5='%s'", esc_fs, esc_md5);
740
741 fsr->FileSetId = 0;
742 if (QueryDB(jcr, cmd)) {
743 if (sql_num_rows() > 1) {
744 Mmsg1(&errmsg, _("More than one FileSet!: %d\n"), sql_num_rows());
745 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
746 }
747 if (sql_num_rows() >= 1) {
748 if ((row = sql_fetch_row()) == NULL) {
749 Mmsg1(&errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror());
750 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
751 sql_free_result();
752 bdb_unlock();
753 return false;
754 }
755 fsr->FileSetId = str_to_int64(row[0]);
756 if (row[1] == NULL) {
757 fsr->cCreateTime[0] = 0;
758 } else {
759 bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
760 }
761 sql_free_result();
762 bdb_unlock();
763 return true;
764 }
765 sql_free_result();
766 }
767
768 if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
769 fsr->CreateTime = time(NULL);
770 }
771 (void)localtime_r(&fsr->CreateTime, &tm);
772 strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
773
774 /* Must create it */
775 Mmsg(cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
776 "VALUES ('%s','%s','%s')", esc_fs, esc_md5, fsr->cCreateTime);
777
778 if ((fsr->FileSetId = sql_insert_autokey_record(cmd, NT_("FileSet"))) == 0) {
779 Mmsg2(&errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
780 cmd, sql_strerror());
781 Jmsg(jcr, M_ERROR, 0, "%s", errmsg);
782 stat = false;
783 } else {
784 fsr->created = true;
785 stat = true;
786 }
787
788 bdb_unlock();
789 return stat;
790 }
791
792
793 /**
794 * struct stat
795 * {
796 * dev_t st_dev; * device *
797 * ino_t st_ino; * inode *
798 * mode_t st_mode; * protection *
799 * nlink_t st_nlink; * number of hard links *
800 * uid_t st_uid; * user ID of owner *
801 * gid_t st_gid; * group ID of owner *
802 * dev_t st_rdev; * device type (if inode device) *
803 * off_t st_size; * total size, in bytes *
804 * unsigned long st_blksize; * blocksize for filesystem I/O *
805 * unsigned long st_blocks; * number of blocks allocated *
806 * time_t st_atime; * time of last access *
807 * time_t st_mtime; * time of last modification *
808 * time_t st_ctime; * time of last inode change *
809 * };
810 */
811
812 /* For maintenance, we can put batch mode in hold */
813 static bool batch_mode_enabled = true;
814
bdb_disable_batch_insert(bool enabled)815 void bdb_disable_batch_insert(bool enabled)
816 {
817 batch_mode_enabled = enabled;
818 }
819
820 /*
821 * All sql_batch_xx functions are used to do bulk batch
822 * insert in File/Filename/Path tables.
823 *
824 * To sum up :
825 * - bulk load a temp table
826 * - table before that to avoid possible duplicate inserts with concurrent update)
827 * - insert missing paths into path with another single query
828 * - then insert the join between the temp and path tables into file.
829 */
830
831 /*
832 * Returns true if OK
833 * false if failed
834 */
bdb_write_batch_file_records(JCR * jcr)835 bool bdb_write_batch_file_records(JCR *jcr)
836 {
837 bool retval = false;
838 int JobStatus = jcr->JobStatus;
839
840 if (!jcr->batch_started) { /* no files to backup ? */
841 Dmsg0(50,"db_write_batch_file_records: no files\n");
842 return true;
843 }
844
845 if (job_canceled(jcr)) {
846 goto bail_out;
847 }
848
849 jcr->JobStatus = JS_AttrInserting;
850
851 /* Check if batch mode is on hold */
852 while (!batch_mode_enabled) {
853 Dmsg0(50, "batch mode is on hold\n");
854 bmicrosleep(10, 0);
855
856 if (job_canceled(jcr)) {
857 goto bail_out;
858 }
859 }
860
861 Dmsg1(50,"db_write_batch_file_records changes=%u\n",jcr->db_batch->changes);
862
863 if (!jcr->db_batch->sql_batch_end(jcr, NULL)) {
864 Jmsg1(jcr, M_FATAL, 0, "Batch end %s\n", jcr->db_batch->errmsg);
865 goto bail_out;
866 }
867 if (job_canceled(jcr)) {
868 goto bail_out;
869 }
870
871 /* We have to lock tables */
872 if (!jcr->db_batch->bdb_sql_query(batch_lock_path_query[jcr->db_batch->bdb_get_type_index()], NULL, NULL)) {
873 Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", jcr->db_batch->errmsg);
874 goto bail_out;
875 }
876
877 if (!jcr->db_batch->bdb_sql_query(batch_fill_path_query[jcr->db_batch->bdb_get_type_index()], NULL, NULL)) {
878 Jmsg1(jcr, M_FATAL, 0, "Fill Path table %s\n",jcr->db_batch->errmsg);
879 jcr->db_batch->bdb_sql_query(batch_unlock_tables_query[jcr->db_batch->bdb_get_type_index()], NULL, NULL);
880 goto bail_out;
881 }
882
883 if (!jcr->db_batch->bdb_sql_query(batch_unlock_tables_query[jcr->db_batch->bdb_get_type_index()], NULL, NULL)) {
884 Jmsg1(jcr, M_FATAL, 0, "Unlock Path table %s\n", jcr->db_batch->errmsg);
885 goto bail_out;
886 }
887
888 if (!jcr->db_batch->bdb_sql_query(
889 "INSERT INTO File (FileIndex, JobId, PathId, Filename, LStat, MD5, DeltaSeq) "
890 "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
891 "batch.Name, batch.LStat, batch.MD5, batch.DeltaSeq "
892 "FROM batch JOIN Path ON (batch.Path = Path.Path) ", NULL, NULL))
893 {
894 Jmsg1(jcr, M_FATAL, 0, "Fill File table %s\n", jcr->db_batch->errmsg);
895 goto bail_out;
896 }
897
898 jcr->JobStatus = JobStatus; /* reset entry status */
899 retval = true;
900
901 bail_out:
902 jcr->db_batch->bdb_sql_query("DROP TABLE IF EXISTS batch", NULL,NULL);
903 jcr->batch_started = false;
904
905 return retval;
906 }
907
908 /**
909 * Create File record in BDB
910 *
911 * In order to reduce database size, we store the File attributes, the Path
912 * separately. In principle, there is a single Path record, no matter how
913 * many times it occurs. This is this subroutine, we separate the file and
914 * the path and fill temporary tables with this three records.
915 *
916 * Note: all routines that call this expect to be able to call
917 * db_strerror(mdb) to get the error message, so the error message
918 * MUST be edited into errmsg before returning an error status.
919 */
bdb_create_batch_file_attributes_record(JCR * jcr,ATTR_DBR * ar)920 bool BDB::bdb_create_batch_file_attributes_record(JCR *jcr, ATTR_DBR *ar)
921 {
922 ASSERT(ar->FileType != FT_BASE);
923 Dmsg2(dbglevel, "FileIndex=%d Fname=%s\n", ar->FileIndex, ar->fname);
924 Dmsg0(dbglevel, "put_file_into_catalog\n");
925
926 if (jcr->batch_started && jcr->db_batch->changes > 500000) {
927 bdb_write_batch_file_records(jcr);
928 jcr->db_batch->changes = 0;
929 }
930
931 /* Open the dedicated connexion */
932 if (!jcr->batch_started) {
933 if (!bdb_open_batch_connexion(jcr)) {
934 return false; /* error already printed */
935 }
936 if (!jcr->db_batch->sql_batch_start(jcr)) {
937 Mmsg1(&errmsg,
938 "Can't start batch mode: ERR=%s", jcr->db_batch->bdb_strerror());
939 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
940 return false;
941 }
942 jcr->batch_started = true;
943 }
944
945 split_path_and_file(jcr, jcr->db_batch, ar->fname);
946
947 return jcr->db_batch->sql_batch_insert(jcr, ar);
948 }
949
950 /**
951 * Create File record in BDB
952 *
953 * In order to reduce database size, we store the File attributes and the Path
954 * separately. In principle, there is a single Path record, no matter how
955 * many times it occurs. This is this subroutine, we separate the file and
956 * the path and create two database records.
957 */
bdb_create_file_attributes_record(JCR * jcr,ATTR_DBR * ar)958 bool BDB::bdb_create_file_attributes_record(JCR *jcr, ATTR_DBR *ar)
959 {
960 bdb_lock();
961 Dmsg2(dbglevel, "FileIndex=%d Fname=%s\n", ar->FileIndex, ar->fname);
962 Dmsg0(dbglevel, "put_file_into_catalog\n");
963
964 split_path_and_file(jcr, this, ar->fname);
965
966 if (!bdb_create_path_record(jcr, ar)) {
967 goto bail_out;
968 }
969 Dmsg1(dbglevel, "db_create_path_record: %s\n", esc_name);
970
971 esc_name = check_pool_memory_size(esc_name, 2*fnl+2);
972 bdb_escape_string(jcr, esc_name, fname, fnl);
973 ar->Filename = esc_name;
974
975 /* Now create master File record */
976 if (!bdb_create_file_record(jcr, ar)) {
977 goto bail_out;
978 }
979 Dmsg0(dbglevel, "db_create_file_record OK\n");
980
981 Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s Filename=%s\n", path, fname, ar->Filename);
982 bdb_unlock();
983 return true;
984
985 bail_out:
986 bdb_unlock();
987 return false;
988 }
989 /**
990 * This is the master File entry containing the attributes.
991 * The filename and path records have already been created.
992 */
bdb_create_file_record(JCR * jcr,ATTR_DBR * ar)993 int BDB::bdb_create_file_record(JCR *jcr, ATTR_DBR *ar)
994 {
995 int stat;
996 static const char *no_digest = "0";
997 const char *digest;
998
999 ASSERT(ar->JobId);
1000 ASSERT(ar->PathId);
1001 ASSERT(ar->Filename != NULL);
1002
1003 if (ar->Digest == NULL || ar->Digest[0] == 0) {
1004 digest = no_digest;
1005 } else {
1006 digest = ar->Digest;
1007 }
1008
1009 /* Must create it */
1010 Mmsg(cmd,
1011 "INSERT INTO File (FileIndex,JobId,PathId,Filename,"
1012 "LStat,MD5,DeltaSeq) VALUES (%d,%u,%u,'%s','%s','%s',%u)",
1013 ar->FileIndex, ar->JobId, ar->PathId, ar->Filename,
1014 ar->attr, digest, ar->DeltaSeq);
1015
1016 if ((ar->FileId = sql_insert_autokey_record(cmd, NT_("File"))) == 0) {
1017 Mmsg2(&errmsg, _("Create db File record %s failed. ERR=%s"),
1018 cmd, sql_strerror());
1019 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
1020 stat = 0;
1021 } else {
1022 stat = 1;
1023 }
1024 return stat;
1025 }
1026
1027 /**
1028 * Create file attributes record, or base file attributes record
1029 */
bdb_create_attributes_record(JCR * jcr,ATTR_DBR * ar)1030 bool BDB::bdb_create_attributes_record(JCR *jcr, ATTR_DBR *ar)
1031 {
1032 bool ret;
1033
1034 Dmsg2(dbglevel, "FileIndex=%d Fname=%s\n", ar->FileIndex, ar->fname);
1035 errmsg[0] = 0;
1036 /*
1037 * Make sure we have an acceptable attributes record.
1038 */
1039 if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
1040 ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
1041 Mmsg1(&errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
1042 ar->Stream);
1043 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
1044 return false;
1045 }
1046
1047 if (ar->FileType != FT_BASE) {
1048 if (batch_insert_available()) {
1049 ret = bdb_create_batch_file_attributes_record(jcr, ar);
1050 /* Error message already printed */
1051 } else {
1052 ret = bdb_create_file_attributes_record(jcr, ar);
1053 }
1054 } else if (jcr->HasBase) {
1055 ret = bdb_create_base_file_attributes_record(jcr, ar);
1056 } else {
1057 Mmsg0(&errmsg, _("Cannot Copy/Migrate job using BaseJob.\n"));
1058 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
1059 ret = true; /* in copy/migration what do we do ? */
1060 }
1061
1062 return ret;
1063 }
1064
1065 /**
1066 * Create Base File record in BDB
1067 *
1068 */
bdb_create_base_file_attributes_record(JCR * jcr,ATTR_DBR * ar)1069 bool BDB::bdb_create_base_file_attributes_record(JCR *jcr, ATTR_DBR *ar)
1070 {
1071 bool ret;
1072
1073 Dmsg1(dbglevel, "create_base_file Fname=%s\n", ar->fname);
1074 Dmsg0(dbglevel, "put_base_file_into_catalog\n");
1075
1076 bdb_lock();
1077 split_path_and_file(jcr, this, ar->fname);
1078
1079 esc_name = check_pool_memory_size(esc_name, fnl*2+1);
1080 bdb_escape_string(jcr, esc_name, fname, fnl);
1081
1082 esc_path = check_pool_memory_size(esc_path, pnl*2+1);
1083 bdb_escape_string(jcr, esc_path, path, pnl);
1084
1085 Mmsg(cmd, "INSERT INTO basefile%lld (Path, Name) VALUES ('%s','%s')",
1086 (uint64_t)jcr->JobId, esc_path, esc_name);
1087
1088 ret = InsertDB(jcr, cmd);
1089 bdb_unlock();
1090
1091 return ret;
1092 }
1093
1094 /**
1095 * Cleanup the base file temporary tables
1096 */
db_cleanup_base_file(JCR * jcr,BDB * mdb)1097 static void db_cleanup_base_file(JCR *jcr, BDB *mdb)
1098 {
1099 POOL_MEM buf(PM_MESSAGE);
1100 Mmsg(buf, "DROP TABLE IF EXISTS new_basefile%lld", (uint64_t) jcr->JobId);
1101 mdb->bdb_sql_query(buf.c_str(), NULL, NULL);
1102
1103 Mmsg(buf, "DROP TABLE IF EXISTS basefile%lld", (uint64_t) jcr->JobId);
1104 mdb->bdb_sql_query(buf.c_str(), NULL, NULL);
1105 }
1106
1107 /**
1108 * Put all base file seen in the backup to the BaseFile table
1109 * and cleanup temporary tables
1110 */
bdb_commit_base_file_attributes_record(JCR * jcr)1111 bool BDB::bdb_commit_base_file_attributes_record(JCR *jcr)
1112 {
1113 bool ret;
1114 char ed1[50];
1115
1116 bdb_lock();
1117
1118 Mmsg(cmd,
1119 "INSERT INTO BaseFiles (BaseJobId, JobId, FileId, FileIndex) "
1120 "SELECT B.JobId AS BaseJobId, %s AS JobId, "
1121 "B.FileId, B.FileIndex "
1122 "FROM basefile%s AS A, new_basefile%s AS B "
1123 "WHERE A.Path = B.Path "
1124 "AND A.Name = B.Name "
1125 "ORDER BY B.FileId",
1126 edit_uint64(jcr->JobId, ed1), ed1, ed1);
1127 ret = bdb_sql_query(cmd, NULL, NULL);
1128 /*
1129 * Display error now, because the subsequent cleanup destroys the
1130 * error message from the above query.
1131 */
1132 if (!ret) {
1133 Jmsg1(jcr, M_FATAL, 0, "%s", jcr->db->bdb_strerror());
1134 }
1135 jcr->nb_base_files_used = sql_affected_rows();
1136 db_cleanup_base_file(jcr, this);
1137
1138 bdb_unlock();
1139 return ret;
1140 }
1141
1142 /**
1143 * Find the last "accurate" backup state with Base jobs
1144 * 1) Get all files with jobid in list (F subquery)
1145 * 2) Take only the last version of each file (Temp subquery) => accurate list is ok
1146 * 3) Put the result in a temporary table for the end of job
1147 *
1148 */
bdb_create_base_file_list(JCR * jcr,char * jobids)1149 bool BDB::bdb_create_base_file_list(JCR *jcr, char *jobids)
1150 {
1151 POOL_MEM buf;
1152 bool ret = false;
1153
1154 bdb_lock();
1155
1156 if (!*jobids) {
1157 Mmsg(errmsg, _("ERR=JobIds are empty\n"));
1158 goto bail_out;
1159 }
1160
1161 Mmsg(cmd, create_temp_basefile[bdb_get_type_index()], (uint64_t) jcr->JobId);
1162 if (!bdb_sql_query(cmd, NULL, NULL)) {
1163 goto bail_out;
1164 }
1165 Mmsg(buf, select_recent_version[bdb_get_type_index()], jobids, jobids);
1166 Mmsg(cmd, create_temp_new_basefile[bdb_get_type_index()], (uint64_t)jcr->JobId, buf.c_str());
1167
1168 ret = bdb_sql_query(cmd, NULL, NULL);
1169 bail_out:
1170 bdb_unlock();
1171 return ret;
1172 }
1173
1174 /**
1175 * Create Restore Object record in BDB
1176 *
1177 */
bdb_create_restore_object_record(JCR * jcr,ROBJECT_DBR * ro)1178 bool BDB::bdb_create_restore_object_record(JCR *jcr, ROBJECT_DBR *ro)
1179 {
1180 bool stat;
1181 int plug_name_len;
1182 POOLMEM *esc_plug_name = get_pool_memory(PM_MESSAGE);
1183
1184 bdb_lock();
1185
1186 Dmsg1(dbglevel, "Oname=%s\n", ro->object_name);
1187 Dmsg0(dbglevel, "put_object_into_catalog\n");
1188
1189 fnl = strlen(ro->object_name);
1190 esc_name = check_pool_memory_size(esc_name, fnl*2+1);
1191 bdb_escape_string(jcr, esc_name, ro->object_name, fnl);
1192
1193 bdb_escape_object(jcr, ro->object, ro->object_len);
1194
1195 plug_name_len = strlen(ro->plugin_name);
1196 esc_plug_name = check_pool_memory_size(esc_plug_name, plug_name_len*2+1);
1197 bdb_escape_string(jcr, esc_plug_name, ro->plugin_name, plug_name_len);
1198
1199 Mmsg(cmd,
1200 "INSERT INTO RestoreObject (ObjectName,PluginName,RestoreObject,"
1201 "ObjectLength,ObjectFullLength,ObjectIndex,ObjectType,"
1202 "ObjectCompression,FileIndex,JobId) "
1203 "VALUES ('%s','%s','%s',%d,%d,%d,%d,%d,%d,%u)",
1204 esc_name, esc_plug_name, esc_obj,
1205 ro->object_len, ro->object_full_len, ro->object_index,
1206 ro->FileType, ro->object_compression, ro->FileIndex, ro->JobId);
1207
1208 ro->RestoreObjectId = sql_insert_autokey_record(cmd, NT_("RestoreObject"));
1209 if (ro->RestoreObjectId == 0) {
1210 Mmsg2(&errmsg, _("Create db Object record %s failed. ERR=%s"),
1211 cmd, sql_strerror());
1212 Jmsg(jcr, M_FATAL, 0, "%s", errmsg);
1213 stat = false;
1214 } else {
1215 stat = true;
1216 }
1217 bdb_unlock();
1218 free_pool_memory(esc_plug_name);
1219 return stat;
1220 }
1221
bdb_create_snapshot_record(JCR * jcr,SNAPSHOT_DBR * snap)1222 bool BDB::bdb_create_snapshot_record(JCR *jcr, SNAPSHOT_DBR *snap)
1223 {
1224 bool status = false;
1225 char esc_name[MAX_ESCAPE_NAME_LENGTH];
1226 POOLMEM *esc_vol = get_pool_memory(PM_MESSAGE);
1227 POOLMEM *esc_dev = get_pool_memory(PM_MESSAGE);
1228 POOLMEM *esc_type = get_pool_memory(PM_MESSAGE);
1229 POOLMEM *esc_client = get_pool_memory(PM_MESSAGE);
1230 POOLMEM *esc_fs = get_pool_memory(PM_MESSAGE);
1231 char esc_comment[MAX_ESCAPE_NAME_LENGTH];
1232 char dt[MAX_TIME_LENGTH], ed1[50], ed2[50];
1233 time_t stime;
1234 struct tm tm;
1235
1236 bdb_lock();
1237
1238 esc_vol = check_pool_memory_size(esc_vol, strlen(snap->Volume) * 2 + 1);
1239 bdb_escape_string(jcr, esc_vol, snap->Volume, strlen(snap->Volume));
1240
1241 esc_dev = check_pool_memory_size(esc_dev, strlen(snap->Device) * 2 + 1);
1242 bdb_escape_string(jcr, esc_dev, snap->Device, strlen(snap->Device));
1243
1244 esc_type = check_pool_memory_size(esc_type, strlen(snap->Type) * 2 + 1);
1245 bdb_escape_string(jcr, esc_type, snap->Type, strlen(snap->Type));
1246
1247 bdb_escape_string(jcr, esc_comment, snap->Comment, strlen(snap->Comment));
1248
1249 if (*snap->Client) {
1250 bdb_escape_string(jcr, esc_name, snap->Client, strlen(snap->Client));
1251 Mmsg(esc_client, "(SELECT ClientId FROM Client WHERE Name='%s')", esc_name);
1252
1253 } else {
1254 Mmsg(esc_client, "%d", snap->ClientId);
1255 }
1256
1257 if (*snap->FileSet) {
1258 bdb_escape_string(jcr, esc_name, snap->FileSet, strlen(snap->FileSet));
1259 Mmsg(esc_fs, "(SELECT FileSetId FROM FileSet WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1)", esc_name);
1260
1261 } else {
1262 Mmsg(esc_fs, "%d", snap->FileSetId);
1263 }
1264
1265 bdb_escape_string(jcr, esc_name, snap->Name, strlen(snap->Name));
1266
1267 stime = snap->CreateTDate;
1268 (void)localtime_r(&stime, &tm);
1269 strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
1270
1271 Mmsg(cmd, "INSERT INTO Snapshot "
1272 "(Name, JobId, CreateTDate, CreateDate, ClientId, FileSetId, Volume, Device, Type, Retention, Comment) "
1273 "VALUES ('%s', %s, %d, '%s', %s, %s, '%s', '%s', '%s', %s, '%s')",
1274 esc_name, edit_uint64(snap->JobId, ed2), stime, dt, esc_client, esc_fs, esc_vol,
1275 esc_dev, esc_type, edit_int64(snap->Retention, ed1), esc_comment);
1276
1277 if (bdb_sql_query(cmd, NULL, NULL)) {
1278 snap->SnapshotId = sql_insert_autokey_record(cmd, NT_("Snapshot"));
1279 status = true;
1280 }
1281
1282 bdb_unlock();
1283
1284 free_pool_memory(esc_vol);
1285 free_pool_memory(esc_dev);
1286 free_pool_memory(esc_type);
1287 free_pool_memory(esc_client);
1288 free_pool_memory(esc_fs);
1289
1290 return status;
1291 }
1292
bdb_create_events_record(JCR * jcr,EVENTS_DBR * event)1293 int BDB::bdb_create_events_record(JCR *jcr, EVENTS_DBR *event)
1294 {
1295 bool status = false;
1296 int len;
1297 POOL_MEM tmp, type, from, source, time, text;
1298 char dt[MAX_TIME_LENGTH];
1299
1300 bdb_lock();
1301 if (!is_name_valid(event->EventsCode, tmp.handle(), "")) {
1302 Mmsg(errmsg, "Invalid EventsCode %s", tmp.c_str());
1303 goto bail_out;
1304 }
1305
1306 if (!is_name_valid(event->EventsType, tmp.handle(), "")) {
1307 Mmsg(errmsg, "Invalid EventsType %s", tmp.c_str());
1308 goto bail_out;
1309 }
1310 len = strlen(event->EventsType);
1311 type.check_size(len*2+1);
1312 db_escape_string(jcr, this, type.c_str(), event->EventsType, len);
1313
1314 if (!is_name_valid(event->EventsSource, tmp.handle(), "*-.,:")) { /* Add *None* */
1315 Mmsg(errmsg, "Invalid EventsSource %s", tmp.c_str());
1316 goto bail_out;
1317 }
1318 len = strlen(event->EventsSource);
1319 source.check_size(len*2+1);
1320 db_escape_string(jcr, this, source.c_str(), event->EventsSource, len);
1321
1322 if (!is_name_valid(event->EventsDaemon, tmp.handle())) {
1323 Mmsg(errmsg, "Invalid EventsDaemon %s", tmp.c_str());
1324 goto bail_out;
1325 }
1326 len = strlen(event->EventsDaemon);
1327 from.check_size(len*2+1);
1328 db_escape_string(jcr, this, from.c_str(), event->EventsDaemon, len);
1329
1330 len = strlen(event->EventsText);
1331 text.check_size(len*2+1);
1332 db_escape_string(jcr, this, text.c_str(), event->EventsText, len);
1333
1334 bstrutime(dt, sizeof(dt), event->EventsTime);
1335 Mmsg(cmd, "INSERT INTO Events "
1336 "(EventsDaemon, EventsCode, EventsType, EventsSource, EventsRef, EventsTime, EventsText) "
1337 "VALUES ('%s', '%s', '%s', '%s', '0x%p', '%s', '%s')", from.c_str(), event->EventsCode,
1338 type.c_str(), source.c_str(), event->EventsRef, dt, text.c_str());
1339
1340 if (bdb_sql_query(cmd, NULL, NULL)) {
1341 status = true;
1342 }
1343
1344 bail_out:
1345 bdb_unlock();
1346 return status;
1347 }
1348
1349
bdb_create_log_record(JCR * jcr,JobId_t jobid,utime_t mtime,char * msg)1350 bool BDB::bdb_create_log_record(JCR *jcr, JobId_t jobid, utime_t mtime, char *msg)
1351 {
1352 bool ret;
1353 POOLMEM *cmd = get_pool_memory(PM_MESSAGE);
1354 POOLMEM *esc_msg = get_pool_memory(PM_MESSAGE);
1355 char dt[MAX_TIME_LENGTH], ed1[50];
1356 int len = strlen(msg) + 1;
1357
1358 esc_msg = check_pool_memory_size(esc_msg, len*2+1);
1359 bdb_escape_string(jcr, esc_msg, msg, len);
1360 bstrutime(dt, sizeof(dt), mtime);
1361 Mmsg(cmd, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
1362 edit_int64(jcr->JobId, ed1), dt, esc_msg);
1363
1364 ret = bdb_sql_query(cmd, NULL, NULL);
1365
1366 free_pool_memory(cmd);
1367 free_pool_memory(esc_msg);
1368 return ret;
1369 }
1370
1371 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */
1372