]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_update.c
Split messages line by line before sending it to syslog() fix #3325
[bacula/bacula] / bacula / src / cats / sql_update.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
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    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    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Bacula Catalog Database Update record interface routines
30  *
31  *    Kern Sibbald, March 2000
32  *
33  *    Version $Id: sql_update.c 8478 2009-02-18 20:11:55Z kerns $
34  */
35
36 #include "bacula.h"
37
38 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
39
40 #include "cats.h"
41 #include "bdb_priv.h"
42 #include "sql_glue.h"
43
44 /* -----------------------------------------------------------------------
45  *
46  *   Generic Routines (or almost generic)
47  *
48  * -----------------------------------------------------------------------
49  */
50
51 /* -----------------------------------------------------------------------
52  *
53  *   Generic Routines (or almost generic)
54  *
55  * -----------------------------------------------------------------------
56  */
57 /* Update the attributes record by adding the file digest */
58 int
59 db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
60                           int type)
61 {
62    int ret;
63    char ed1[50];
64    int len = strlen(digest);
65
66    db_lock(mdb);
67    mdb->esc_name = check_pool_memory_size(mdb->esc_name, len*2+1);
68    mdb->db_escape_string(jcr, mdb->esc_name, digest, len); 
69    Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", mdb->esc_name, 
70         edit_int64(FileId, ed1));
71    ret = UPDATE_DB(jcr, mdb, mdb->cmd);
72    db_unlock(mdb);
73    return ret;
74 }
75
76 /* Mark the file record as being visited during database
77  * verify compare. Stuff JobId into the MarkId field
78  */
79 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId)
80 {
81    int stat;
82    char ed1[50], ed2[50];
83
84    db_lock(mdb);
85    Mmsg(mdb->cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s", 
86       edit_int64(JobId, ed1), edit_int64(FileId, ed2));
87    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
88    db_unlock(mdb);
89    return stat;
90 }
91
92 /*
93  * Update the Job record at start of Job
94  *
95  *  Returns: false on failure
96  *           true  on success
97  */
98 bool
99 db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
100 {
101    char dt[MAX_TIME_LENGTH];
102    time_t stime;
103    struct tm tm;
104    btime_t JobTDate;
105    int stat;
106    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
107
108    stime = jr->StartTime;
109    (void)localtime_r(&stime, &tm);
110    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
111    JobTDate = (btime_t)stime;
112
113    db_lock(mdb);
114    Mmsg(mdb->cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
115 "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s",
116       (char)(jcr->JobStatus),
117       (char)(jr->JobLevel), dt, 
118       edit_int64(jr->ClientId, ed1),
119       edit_uint64(JobTDate, ed2), 
120       edit_int64(jr->PoolId, ed3),
121       edit_int64(jr->FileSetId, ed4),
122       edit_int64(jr->JobId, ed5));
123
124    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
125    mdb->changes = 0;
126    db_unlock(mdb);
127    return stat;
128 }
129
130 /*
131  * Update Long term statistics with all jobs that were run before
132  * age seconds
133  */
134 int
135 db_update_stats(JCR *jcr, B_DB *mdb, utime_t age)
136 {
137    char ed1[30];
138    utime_t now = (utime_t)time(NULL);
139    edit_uint64(now - age, ed1);
140
141    Mmsg(mdb->cmd, fill_jobhisto, ed1);
142    QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
143    return sql_affected_rows(mdb);
144 }
145
146 /*
147  * Update the Job record at end of Job
148  *
149  *  Returns: 0 on failure
150  *           1 on success
151  */
152 int
153 db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
154 {
155    char dt[MAX_TIME_LENGTH];
156    char rdt[MAX_TIME_LENGTH];
157    time_t ttime;
158    struct tm tm;
159    int stat;
160    char ed1[30], ed2[30], ed3[50], ed4[50];
161    btime_t JobTDate;
162    char PriorJobId[50];
163
164    if (jr->PriorJobId) {
165       bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId));
166    } else {
167       bstrncpy(PriorJobId, "0", sizeof(PriorJobId));
168    }
169
170    ttime = jr->EndTime;
171    (void)localtime_r(&ttime, &tm);
172    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
173
174    if (jr->RealEndTime == 0) {
175       jr->RealEndTime = jr->EndTime;
176    }
177    ttime = jr->RealEndTime;
178    (void)localtime_r(&ttime, &tm);
179    strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm);
180
181    JobTDate = ttime;
182
183    db_lock(mdb);
184    Mmsg(mdb->cmd,
185       "UPDATE Job SET JobStatus='%c',EndTime='%s',"
186 "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u,"
187 "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s,"
188 "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s",
189       (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1),
190       edit_uint64(jr->ReadBytes, ed4),
191       jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime,
192       jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2), 
193       rdt, PriorJobId, jr->HasBase, jr->PurgedFiles,
194       edit_int64(jr->JobId, ed3));
195
196    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
197
198    db_unlock(mdb);
199    return stat;
200 }
201
202 /*
203  * Update Client record
204  *   Returns: 0 on failure
205  *            1 on success
206  */
207 int
208 db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
209 {
210    int stat;
211    char ed1[50], ed2[50];
212    char esc_name[MAX_ESCAPE_NAME_LENGTH];
213    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
214    CLIENT_DBR tcr;
215
216    db_lock(mdb);
217    memcpy(&tcr, cr, sizeof(tcr));
218    if (!db_create_client_record(jcr, mdb, &tcr)) {
219       db_unlock(mdb);
220       return 0;
221    }
222
223    mdb->db_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
224    mdb->db_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
225    Mmsg(mdb->cmd,
226 "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
227 "Uname='%s' WHERE Name='%s'",
228       cr->AutoPrune,
229       edit_uint64(cr->FileRetention, ed1),
230       edit_uint64(cr->JobRetention, ed2),
231       esc_uname, esc_name);
232
233    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
234    db_unlock(mdb);
235    return stat;
236 }
237
238
239 /*
240  * Update Counters record
241  *   Returns: 0 on failure
242  *            1 on success
243  */
244 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
245 {
246    char esc[MAX_ESCAPE_NAME_LENGTH];
247    db_lock(mdb);
248    mdb->db_escape_string(jcr, esc, cr->Counter, strlen(cr->Counter));
249    Mmsg(mdb->cmd,
250 "UPDATE Counters SET \"MinValue\"=%d,\"MaxValue\"=%d,CurrentValue=%d,"
251 "WrapCounter='%s' WHERE Counter='%s'",
252       cr->MinValue, cr->MaxValue, cr->CurrentValue,
253       cr->WrapCounter, esc);
254
255    int stat = UPDATE_DB(jcr, mdb, mdb->cmd);
256    db_unlock(mdb);
257    return stat;
258 }
259
260
261 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
262 {
263    int stat;
264    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
265    char esc[MAX_ESCAPE_NAME_LENGTH];
266
267    db_lock(mdb);
268    mdb->db_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat));
269
270    Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s",
271       edit_int64(pr->PoolId, ed4));
272    pr->NumVols = get_sql_record_max(jcr, mdb);
273    Dmsg1(400, "NumVols=%d\n", pr->NumVols);
274
275    Mmsg(mdb->cmd,
276 "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d,"
277 "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s',"
278 "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d,"
279 "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s,"
280 "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s",
281       pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
282       pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1),
283       edit_uint64(pr->VolUseDuration, ed2),
284       pr->MaxVolJobs, pr->MaxVolFiles,
285       edit_uint64(pr->MaxVolBytes, ed3),
286       pr->Recycle, pr->AutoPrune, pr->LabelType,
287       esc, edit_int64(pr->RecyclePoolId,ed5),
288       edit_int64(pr->ScratchPoolId,ed6),
289       pr->ActionOnPurge,
290       ed4);
291    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
292    db_unlock(mdb);
293    return stat;
294 }
295
296 bool
297 db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
298 {
299    int stat;
300    char ed1[50];
301    db_lock(mdb);
302    Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s", 
303       sr->AutoChanger, edit_int64(sr->StorageId, ed1));
304
305    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
306    db_unlock(mdb);
307    return stat;
308 }
309
310
311 /*
312  * Update the Media Record at end of Session
313  *
314  * Returns: 0 on failure
315  *          numrows on success
316  */
317 int
318 db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
319 {
320    char dt[MAX_TIME_LENGTH];
321    time_t ttime;
322    struct tm tm;
323    int stat;
324    char ed1[50], ed2[50],  ed3[50],  ed4[50]; 
325    char ed5[50], ed6[50],  ed7[50],  ed8[50];
326    char ed9[50], ed10[50], ed11[50];
327    char esc_name[MAX_ESCAPE_NAME_LENGTH];
328    char esc_status[MAX_ESCAPE_NAME_LENGTH];
329
330    Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
331    db_lock(mdb);
332    mdb->db_escape_string(jcr, esc_name, mr->VolumeName, strlen(mr->VolumeName));
333    mdb->db_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));
334
335    if (mr->set_first_written) {
336       Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName);
337       ttime = mr->FirstWritten;
338       (void)localtime_r(&ttime, &tm);
339       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
340       Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'"
341            " WHERE VolumeName='%s'", dt, esc_name);
342       stat = UPDATE_DB(jcr, mdb, mdb->cmd);
343       Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten);
344    }
345
346    /* Label just done? */
347    if (mr->set_label_date) {
348       ttime = mr->LabelDate;
349       if (ttime == 0) {
350          ttime = time(NULL);
351       }
352       (void)localtime_r(&ttime, &tm);
353       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
354       Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
355            "WHERE VolumeName='%s'", dt, esc_name);
356       UPDATE_DB(jcr, mdb, mdb->cmd);
357    }
358
359    if (mr->LastWritten != 0) {
360       ttime = mr->LastWritten;
361       (void)localtime_r(&ttime, &tm);
362       strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
363       Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
364            "WHERE VolumeName='%s'", dt, esc_name);
365       UPDATE_DB(jcr, mdb, mdb->cmd);
366    }
367
368    /* sanity checks for #1066 */
369    if (mr->VolReadTime < 0) {
370       mr->VolReadTime = 0;
371    }
372    if (mr->VolWriteTime < 0) {
373       mr->VolWriteTime = 0;
374    }
375
376    Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
377         "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
378         "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
379         "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
380         "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
381         "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
382         "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d"
383         " WHERE VolumeName='%s'",
384         mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
385         mr->VolMounts, mr->VolErrors, mr->VolWrites,
386         edit_uint64(mr->MaxVolBytes, ed2),
387         esc_status, mr->Slot, mr->InChanger,
388         edit_int64(mr->VolReadTime, ed3),
389         edit_int64(mr->VolWriteTime, ed4),
390         mr->VolParts,
391         mr->LabelType,
392         edit_int64(mr->StorageId, ed5),
393         edit_int64(mr->PoolId, ed6),
394         edit_uint64(mr->VolRetention, ed7),
395         edit_uint64(mr->VolUseDuration, ed8),
396         mr->MaxVolJobs, mr->MaxVolFiles,
397         mr->Enabled, edit_uint64(mr->LocationId, ed9),
398         edit_uint64(mr->ScratchPoolId, ed10),
399         edit_uint64(mr->RecyclePoolId, ed11),
400         mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
401         esc_name);
402
403    Dmsg1(400, "%s\n", mdb->cmd);
404
405    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
406
407    /* Make sure InChanger is 0 for any record having the same Slot */
408    db_make_inchanger_unique(jcr, mdb, mr);
409
410    db_unlock(mdb);
411    return stat;
412 }
413
414 /*
415  * Update the Media Record Default values from Pool
416  *
417  * Returns: 0 on failure
418  *          numrows on success
419  */
420 int
421 db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
422 {
423    int stat;
424    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
425    char esc[MAX_ESCAPE_NAME_LENGTH];
426
427    db_lock(mdb);
428    if (mr->VolumeName[0]) {
429       mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
430       Mmsg(mdb->cmd, "UPDATE Media SET "
431            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
432            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
433            " WHERE VolumeName='%s'",
434            mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
435            edit_uint64(mr->VolUseDuration, ed2),
436            mr->MaxVolJobs, mr->MaxVolFiles,
437            edit_uint64(mr->MaxVolBytes, ed3),
438            edit_uint64(mr->RecyclePoolId, ed4),
439            esc);
440    } else {
441       Mmsg(mdb->cmd, "UPDATE Media SET "
442            "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s,"
443            "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s"
444            " WHERE PoolId=%s",
445            mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1),
446            edit_uint64(mr->VolUseDuration, ed2),
447            mr->MaxVolJobs, mr->MaxVolFiles,
448            edit_uint64(mr->MaxVolBytes, ed3),
449            edit_int64(mr->RecyclePoolId, ed4),
450            edit_int64(mr->PoolId, ed5));
451    }
452
453    Dmsg1(400, "%s\n", mdb->cmd);
454
455    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
456
457    db_unlock(mdb);
458    return stat;
459 }
460
461
462 /*
463  * If we have a non-zero InChanger, ensure that no other Media
464  *  record has InChanger set on the same Slot.
465  *
466  * This routine assumes the database is already locked.
467  */
468 void
469 db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
470 {
471    char ed1[50], ed2[50];
472    char esc[MAX_ESCAPE_NAME_LENGTH];
473    if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) {
474
475        if (mr->MediaId != 0) {
476           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
477                "Slot=%d AND StorageId=%s AND MediaId!=%s",
478                mr->Slot, 
479                edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
480
481        } else if (*mr->VolumeName) {
482           mdb->db_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName));
483           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
484                "Slot=%d AND StorageId=%s AND VolumeName!='%s'",
485                mr->Slot, 
486                edit_int64(mr->StorageId, ed1), esc);
487
488        } else {  /* used by ua_label to reset all volume with this slot */
489           Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE "
490                "Slot=%d AND StorageId=%s",
491                mr->Slot, 
492                edit_int64(mr->StorageId, ed1), mr->VolumeName);          
493        }
494        Dmsg1(100, "%s\n", mdb->cmd);
495        UPDATE_DB(jcr, mdb, mdb->cmd);
496    }
497 }
498
499 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */