Tomas Cameron
Tullio Andreatta
Ulrich Leodolter
+Vitaliy Kosharskiy
Wolfgang Denk
Yuri Timofeev
Yves Orton
+++ /dev/null
-
- This patch used the jcr stored in the BSOCK packet during callbacks
- to the Director rather than looking them up in the JCR list.
-
- It can be applied to Bacula version 2.4.3 (or earlier) with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-getmsg.patch
- ./configure <your options>
- make
- ...
- make install
-
-
-Index: src/dird/getmsg.c
-===================================================================
---- src/dird/getmsg.c (revision 7970)
-+++ src/dird/getmsg.c (working copy)
-@@ -1,7 +1,7 @@
- /*
- Bacula® - The Network Backup Solution
-
-- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
-+ Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
-
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
-@@ -20,7 +20,7 @@
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-- Bacula® is a registered trademark of John Walker.
-+ Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
-@@ -102,12 +102,12 @@
- char Job[MAX_NAME_LENGTH];
- char MsgType[20];
- int type, level;
-- JCR *jcr;
-+ JCR *jcr = bs->jcr();
- char *msg;
-
- for (;;) {
- n = bs->recv();
-- Dmsg2(100, "bget_dirmsg %d: %s", n, bs->msg);
-+ Dmsg2(300, "bget_dirmsg %d: %s\n", n, bs->msg);
-
- if (is_bnet_stop(bs)) {
- return n; /* error or terminate */
-@@ -142,7 +142,7 @@
- bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1));
- break;
- default:
-- Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
-+ Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
- return n;
- }
- continue;
-@@ -160,21 +160,13 @@
- * Try to fulfill it.
- */
- if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
-- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
-+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- continue;
- }
-- if (strcmp(Job, "*System*") == 0) {
-- jcr = NULL; /* No jcr */
-- } else if (!(jcr=get_jcr_by_full_name(Job))) {
-- Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
-- continue;
-- }
-- Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr);
-
- /* Skip past "Jmsg Job=nnn" */
- if (!(msg=find_msg_start(bs->msg))) {
-- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
-- free_jcr(jcr);
-+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- continue;
- }
-
-@@ -185,8 +177,7 @@
- if (bs->msg[0] == 'J') { /* Job message */
- if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d",
- Job, &type, &level) != 3) {
-- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
-- free_jcr(jcr);
-+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- continue;
- }
- Dmsg1(900, "Got msg: %s\n", bs->msg);
-@@ -199,7 +190,6 @@
- }
- Dmsg1(900, "Dispatch msg: %s", msg);
- dispatch_message(jcr, type, level, msg);
-- free_jcr(jcr);
- continue;
- }
- /*
-@@ -209,21 +199,16 @@
- if (bs->msg[0] == 'C') { /* Catalog request */
- Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
- catalog_request(jcr, bs);
-- Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
-- free_jcr(jcr);
- continue;
- }
- if (bs->msg[0] == 'U') { /* SD sending attributes */
- Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
- catalog_update(jcr, bs);
-- Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
-- free_jcr(jcr);
- continue;
- }
- if (bs->msg[0] == 'M') { /* Mount request */
- Dmsg1(900, "Mount req: %s", bs->msg);
- mount_request(jcr, bs, msg);
-- free_jcr(jcr);
- continue;
- }
- if (bs->msg[0] == 'S') { /* Status change */
-@@ -232,9 +217,8 @@
- if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
- jcr->SDJobStatus = JobStatus; /* current status */
- } else {
-- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
-+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- }
-- free_jcr(jcr);
- continue;
- }
- #ifdef needed
+++ /dev/null
-
- This patch corrects two problems:
- 1. If you start more than 60 jobs within a 1 minute period, the unique
- jobname (critical for the daemons) can be duplicated leading to
- authentication failures and orphaned jobs.
- 2. FD jobs that fail SD authentication were not properly cleaned up.
-
- Apply it to Bacula 2.4.3 (possibly earlier versions)
- with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-jobs.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/dird/job.c
-===================================================================
---- src/dird/job.c (revision 8011)
-+++ src/dird/job.c (working copy)
-@@ -758,17 +758,17 @@
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- static time_t last_start_time = 0;
- static int seq = 0;
-- time_t now;
-+ time_t now = time(NULL);
- struct tm tm;
- char dt[MAX_TIME_LENGTH];
- char name[MAX_NAME_LENGTH];
- char *p;
-+ int len;
-
- /* Guarantee unique start time -- maximum one per second, and
- * thus unique Job Name
- */
- P(mutex); /* lock creation of jobs */
-- now = time(NULL);
- seq++;
- if (seq > 59) { /* wrap as if it is seconds */
- seq = 0;
-@@ -783,9 +783,10 @@
- /* Form Unique JobName */
- (void)localtime_r(&now, &tm);
- /* Use only characters that are permitted in Windows filenames */
-- strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
-+ strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
-+ len = strlen(dt) + 5; /* dt + .%02d EOS */
- bstrncpy(name, base_name, sizeof(name));
-- name[sizeof(name)-22] = 0; /* truncate if too long */
-+ name[sizeof(name)-len] = 0; /* truncate if too long */
- bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
- /* Convert spaces into underscores */
- for (p=jcr->Job; *p; p++) {
-@@ -793,6 +794,7 @@
- *p = '_';
- }
- }
-+ Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
- }
-
- /* Called directly from job rescheduling */
-Index: src/stored/job.c
-===================================================================
---- src/stored/job.c (revision 8011)
-+++ src/stored/job.c (working copy)
-@@ -228,21 +228,25 @@
- if (!(jcr=get_jcr_by_full_name(job_name))) {
- Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
- Dmsg1(3, "**** Job \"%s\" not found\n", job_name);
-+ fd->close();
- return;
- }
-
-- jcr->file_bsock = fd;
-- jcr->file_bsock->set_jcr(jcr);
--
- Dmsg1(110, "Found Job %s\n", job_name);
-
- if (jcr->authenticated) {
- Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
- (uint32_t)jcr->JobId, jcr->Job);
-+ Dmsg2(50, "Hey!!!! JobId %u Job %s already authenticated.\n",
-+ (uint32_t)jcr->JobId, jcr->Job);
-+ fd->close();
- free_jcr(jcr);
- return;
- }
-
-+ jcr->file_bsock = fd;
-+ jcr->file_bsock->set_jcr(jcr);
-+
- /*
- * Authenticate the File daemon
- */
-Index: src/lib/bnet_server.c
-===================================================================
---- src/lib/bnet_server.c (revision 8011)
-+++ src/lib/bnet_server.c (working copy)
-@@ -1,7 +1,7 @@
- /*
- Bacula® - The Network Backup Solution
-
-- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
-+ Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
-
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
-@@ -20,7 +20,7 @@
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-- Bacula® is a registered trademark of John Walker.
-+ Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
-@@ -137,7 +137,7 @@
- be.bstrerror());
- }
- }
-- listen(fd_ptr->fd, 5); /* tell system we are ready */
-+ listen(fd_ptr->fd, 20); /* tell system we are ready */
- sockfds.append(fd_ptr);
- }
- /* Start work queue thread */
+++ /dev/null
-
- This patch should cause all Job Log records to be migrated when the
- Job is migrated. It fixes the second issue reported in bug #1171.
-
- Apply it to Bacula 2.4.3 (possibly earlier versions)
- with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-migrate.patch
- ./configure <your-options>
- make
- ...
- make install
-
-Index: src/dird/migrate.c
-===================================================================
---- src/dird/migrate.c (revision 7926)
-+++ src/dird/migrate.c (working copy)
-@@ -402,14 +402,6 @@
- }
-
- migration_cleanup(jcr, jcr->JobStatus);
-- if (mig_jcr) {
-- char jobid[50];
-- UAContext *ua = new_ua_context(jcr);
-- edit_uint64(jcr->previous_jr.JobId, jobid);
-- /* Purge all old file records, but leave Job record */
-- purge_files_from_jobs(ua, jobid);
-- free_ua_context(ua);
-- }
- return true;
- }
-
-@@ -1087,11 +1079,26 @@
- edit_uint64(mig_jcr->jr.JobId, ec2));
- db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
-
-- /* Now mark the previous job as migrated if it terminated normally */
-- if (jcr->JobStatus == JS_Terminated) {
-+ /*
-+ * If we terminated a migration normally:
-+ * - mark the previous job as migrated
-+ * - move any Log records to the new JobId
-+ * - Purge the File records from the previous job
-+ */
-+ if (jcr->JobType == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
-+ char old_jobid[50], new_jobid[50];
- Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
-- (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
-+ (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, new_jobid));
- db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
-+ UAContext *ua = new_ua_context(jcr);
-+ /* Move JobLog to new JobId */
-+ Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
-+ new_jobid,
-+ edit_uint64(jcr->previous_jr.JobId, old_jobid));
-+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
-+ /* Purge all old file records, but leave Job record */
-+ purge_files_from_jobs(ua, old_jobid);
-+ free_ua_context(ua);
- }
-
- if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
-@@ -1100,7 +1107,6 @@
- set_jcr_job_status(jcr, JS_ErrorTerminated);
- }
-
--
- update_bootstrap_file(mig_jcr);
-
- if (!db_get_job_volume_names(mig_jcr, mig_jcr->db, mig_jcr->jr.JobId, &mig_jcr->VolumeName)) {
+++ /dev/null
-
- This patch should prevent migration jobs from attempting to migrate
- jobs that failed. Apply it to Bacula 2.4.3 (possibly earlier versions)
- with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-migrate.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/dird/migrate.c
-===================================================================
---- src/dird/migrate.c (revision 7757)
-+++ src/dird/migrate.c (working copy)
-@@ -377,7 +377,7 @@
- * to avoid two threads from using the BSOCK structure at
- * the same time.
- */
-- if (!bnet_fsend(sd, "run")) {
-+ if (!sd->fsend("run")) {
- return false;
- }
-
-@@ -520,6 +520,7 @@
- "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool,Client"
- " WHERE Client.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
- " AND Job.ClientId=Client.ClientId AND Job.Type='B'"
-+ " AND Job.JobStatus = 'T'"
- " ORDER by Job.StartTime";
-
- /* Get Volume names in Pool */
-@@ -533,9 +534,9 @@
- "SELECT DISTINCT Job.JobId,Job.StartTime FROM Media,JobMedia,Job"
- " WHERE Media.VolumeName='%s' AND Media.MediaId=JobMedia.MediaId"
- " AND JobMedia.JobId=Job.JobId AND Job.Type='B'"
-+ " AND Job.JobStatus = 'T' AND Media.Enabled=1"
- " ORDER by Job.StartTime";
-
--
- const char *sql_smallest_vol =
- "SELECT Media.MediaId FROM Media,Pool,JobMedia WHERE"
- " Media.MediaId in (SELECT DISTINCT MediaId from JobMedia) AND"
-@@ -570,7 +571,6 @@
- const char *sql_job_bytes =
- "SELECT SUM(JobBytes) FROM Job WHERE JobId IN (%s)";
-
--
- /* Get Media Ids in Pool */
- const char *sql_mediaids =
- "SELECT MediaId FROM Media,Pool WHERE"
+++ /dev/null
-
- This patch should fix two bugs:
- - Bug #1206 -- sql error when there are no files to migrate.
- - Bug #1171 -- Job catalog log is not migrated during migration.
-
- Apply it to a fully patched (requires two previous migration patches)
- 2.4.3 version with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-migrate2.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/dird/migrate.c
-===================================================================
---- src/dird/migrate.c (revision 8152)
-+++ src/dird/migrate.c (working copy)
-@@ -122,6 +122,12 @@
-
- Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
-
-+ if (!get_or_create_fileset_record(jcr)) {
-+ Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
-+ Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
-+ return false;
-+ }
-+
- /* If we find a job or jobs to migrate it is previous_jr.JobId */
- count = get_job_to_migrate(jcr);
- if (count < 0) {
-@@ -139,12 +145,6 @@
- return true; /* no work */
- }
-
-- if (!get_or_create_fileset_record(jcr)) {
-- Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
-- Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
-- return false;
-- }
--
- create_restore_bootstrap_file(jcr);
-
- if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
-@@ -1062,6 +1062,11 @@
- * mig_jcr is jcr of the newly migrated job.
- */
- if (mig_jcr) {
-+ char old_jobid[50], new_jobid[50];
-+
-+ edit_uint64(jcr->previous_jr.JobId, old_jobid);
-+ edit_uint64(mig_jcr->jr.JobId, new_jobid);
-+
- mig_jcr->JobFiles = jcr->JobFiles = jcr->SDJobFiles;
- mig_jcr->JobBytes = jcr->JobBytes = jcr->SDJobBytes;
- mig_jcr->VolSessionId = jcr->VolSessionId;
-@@ -1076,7 +1081,7 @@
- "JobTDate=%s WHERE JobId=%s",
- jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime,
- edit_uint64(jcr->previous_jr.JobTDate, ec1),
-- edit_uint64(mig_jcr->jr.JobId, ec2));
-+ new_jobid);
- db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
-
- /*
-@@ -1086,15 +1091,13 @@
- * - Purge the File records from the previous job
- */
- if (jcr->JobType == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
-- char old_jobid[50], new_jobid[50];
- Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
-- (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, new_jobid));
-+ (char)JT_MIGRATED_JOB, old_jobid);
- db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
- UAContext *ua = new_ua_context(jcr);
- /* Move JobLog to new JobId */
- Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
-- new_jobid,
-- edit_uint64(jcr->previous_jr.JobId, old_jobid));
-+ new_jobid, old_jobid);
- db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
- /* Purge all old file records, but leave Job record */
- purge_files_from_jobs(ua, old_jobid);
+++ /dev/null
-
- This patch fixes a case of orphaned jobs (and possible deadlock)
- during pruning.
- Apply it to Bacula 2.4.3 (possibly earlier versions) with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-orphaned-jobs.patch
- ./configure <your-options>
- make
- ...
- make install
-
-Index: src/dird/ua_prune.c
-===================================================================
---- src/dird/ua_prune.c (revision 7949)
-+++ src/dird/ua_prune.c (working copy)
-@@ -468,6 +468,7 @@
- break;
- }
- }
-+ endeach_jcr(jcr);
- if (skip) {
- continue;
- }
+++ /dev/null
-
- This patch should fix the bug reported on the bacula-users list where
- a retention period of 100 years does immediate prunning.
- Apply it to 2.4.3 (or earlier versions) with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-prune.patch
- ./configure <your-options>
- make
- ...
- make install
-
-Index: src/dird/ua_prune.c
-===================================================================
---- src/dird/ua_prune.c (revision 7757)
-+++ src/dird/ua_prune.c (working copy)
-@@ -202,7 +202,7 @@
- now = (utime_t)time(NULL);
-
- /* Select Jobs -- for counting */
-- Mmsg(query, count_select_job, edit_uint64(now - period, ed1),
-+ Mmsg(query, count_select_job, edit_int64(now - period, ed1),
- edit_int64(cr.ClientId, ed2));
- Dmsg3(050, "select now=%u period=%u sql=%s\n", (uint32_t)now,
- (uint32_t)period, query.c_str());
-@@ -230,7 +230,7 @@
- del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
-
- /* Now process same set but making a delete list */
-- Mmsg(query, select_job, edit_uint64(now - period, ed1),
-+ Mmsg(query, select_job, edit_int64(now - period, ed1),
- edit_int64(cr.ClientId, ed2));
- db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del);
-
-@@ -318,7 +318,7 @@
- * Select all files that are older than the JobRetention period
- * and stuff them into the "DeletionCandidates" table.
- */
-- edit_uint64(now - period, ed1);
-+ edit_int64(now - period, ed1);
- Mmsg(query, insert_delcand, (char)JobType, ed1,
- edit_int64(cr.ClientId, ed2));
- if (!db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL)) {
-@@ -443,10 +443,10 @@
- edit_int64(mr->MediaId, ed1);
- period = mr->VolRetention;
- now = (utime_t)time(NULL);
-- edit_uint64(now-period, ed2);
-+ edit_int64(now-period, ed2);
- Mmsg(query, sel_JobMedia, ed1, ed2);
-- Dmsg3(250, "Now=%d period=%d now-period=%d\n", (int)now, (int)period,
-- (int)(now-period));
-+ Dmsg3(250, "Now=%d period=%d now-period=%s\n", (int)now, (int)period,
-+ ed2);
-
- Dmsg1(050, "Query=%s\n", query.c_str());
- if (!db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)del)) {
+++ /dev/null
-
- This patch corrects appears to fix bug #1188, where a Volume can
- be purged while it is being written.
-
- Apply it to Bacula 2.4.3 (possibly earlier versions)
- with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-purge-bug.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/dird/ua_purge.c
-===================================================================
---- src/dird/ua_purge.c (revision 8054)
-+++ src/dird/ua_purge.c (working copy)
-@@ -463,6 +463,9 @@
- bool purged = false;
- char ed1[50];
-
-+ if (mr->FirstWritten == 0 || mr->LastWritten == 0) {
-+ goto bail_out; /* not written cannot purge */
-+ }
- if (strcmp(mr->VolStatus, "Purged") == 0) {
- purged = true;
- goto bail_out;
+++ /dev/null
-
- This patch fix #1110 about a problem when executing a program with
- Unicode path.
-
- It can be applied to 2.4.3 (and previous versions) with:
-
- cd <bacula-source>
- patch -p0 <2.4.3-win32-runscript-unicode-path.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/win32/compat/compat.cpp
-===================================================================
---- src/win32/compat/compat.cpp (révision 7772)
-+++ src/win32/compat/compat.cpp (copie de travail)
-@@ -1807,6 +1807,97 @@
- }
-
- /**
-+ * Create the process with UTF8 API
-+ */
-+static BOOL
-+CreateChildProcessW(const char *comspec, const char *cmdLine,
-+ PROCESS_INFORMATION *hProcInfo,
-+ HANDLE in, HANDLE out, HANDLE err)
-+{
-+ STARTUPINFOW siStartInfo;
-+ BOOL bFuncRetn = FALSE;
-+
-+ // Set up members of the STARTUPINFO structure.
-+ ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
-+ siStartInfo.cb = sizeof(siStartInfo);
-+ // setup new process to use supplied handles for stdin,stdout,stderr
-+
-+ siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-+ siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
-+
-+ siStartInfo.hStdInput = in;
-+ siStartInfo.hStdOutput = out;
-+ siStartInfo.hStdError = err;
-+
-+ // Convert argument to WCHAR
-+ POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
-+ POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
-+
-+ UTF8_2_wchar(&cmdLine_wchar, cmdLine);
-+ UTF8_2_wchar(&comspec_wchar, comspec);
-+
-+ // Create the child process.
-+ Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
-+
-+ // try to execute program
-+ bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
-+ (WCHAR*)cmdLine_wchar,// command line
-+ NULL, // process security attributes
-+ NULL, // primary thread security attributes
-+ TRUE, // handles are inherited
-+ 0, // creation flags
-+ NULL, // use parent's environment
-+ NULL, // use parent's current directory
-+ &siStartInfo, // STARTUPINFO pointer
-+ hProcInfo); // receives PROCESS_INFORMATION
-+
-+ free_pool_memory(cmdLine_wchar);
-+ free_pool_memory(comspec_wchar);
-+
-+ return bFuncRetn;
-+}
-+
-+
-+/**
-+ * Create the process with ANSI API
-+ */
-+static BOOL
-+CreateChildProcessA(const char *comspec, char *cmdLine,
-+ PROCESS_INFORMATION *hProcInfo,
-+ HANDLE in, HANDLE out, HANDLE err)
-+{
-+ STARTUPINFOA siStartInfo;
-+ BOOL bFuncRetn = FALSE;
-+
-+ // Set up members of the STARTUPINFO structure.
-+ ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
-+ siStartInfo.cb = sizeof(siStartInfo);
-+ // setup new process to use supplied handles for stdin,stdout,stderr
-+ siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-+ siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
-+
-+ siStartInfo.hStdInput = in;
-+ siStartInfo.hStdOutput = out;
-+ siStartInfo.hStdError = err;
-+
-+ // Create the child process.
-+ Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
-+
-+ // try to execute program
-+ bFuncRetn = p_CreateProcessA(comspec,
-+ cmdLine, // command line
-+ NULL, // process security attributes
-+ NULL, // primary thread security attributes
-+ TRUE, // handles are inherited
-+ 0, // creation flags
-+ NULL, // use parent's environment
-+ NULL, // use parent's current directory
-+ &siStartInfo,// STARTUPINFO pointer
-+ hProcInfo);// receives PROCESS_INFORMATION
-+ return bFuncRetn;
-+}
-+
-+/**
- * OK, so it would seem CreateProcess only handles true executables:
- * .com or .exe files. So grab $COMSPEC value and pass command line to it.
- */
-@@ -1815,44 +1906,30 @@
- {
- static const char *comspec = NULL;
- PROCESS_INFORMATION piProcInfo;
-- STARTUPINFOA siStartInfo;
- BOOL bFuncRetn = FALSE;
-
-- if (comspec == NULL) {
-+ if (!p_CreateProcessA || !p_CreateProcessW)
-+ return INVALID_HANDLE_VALUE;
-+
-+ if (comspec == NULL)
- comspec = getenv("COMSPEC");
-- }
- if (comspec == NULL) // should never happen
- return INVALID_HANDLE_VALUE;
-
- // Set up members of the PROCESS_INFORMATION structure.
- ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
-
-- // Set up members of the STARTUPINFO structure.
--
-- ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
-- siStartInfo.cb = sizeof(STARTUPINFO);
-- // setup new process to use supplied handles for stdin,stdout,stderr
- // if supplied handles are not used the send a copy of our STD_HANDLE
- // as appropriate
-- siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-- siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
-+ if (in == INVALID_HANDLE_VALUE)
-+ in = GetStdHandle(STD_INPUT_HANDLE);
-
-- if (in != INVALID_HANDLE_VALUE)
-- siStartInfo.hStdInput = in;
-- else
-- siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
-+ if (out == INVALID_HANDLE_VALUE)
-+ out = GetStdHandle(STD_OUTPUT_HANDLE);
-
-- if (out != INVALID_HANDLE_VALUE)
-- siStartInfo.hStdOutput = out;
-- else
-- siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-- if (err != INVALID_HANDLE_VALUE)
-- siStartInfo.hStdError = err;
-- else
-- siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-+ if (err == INVALID_HANDLE_VALUE)
-+ err = GetStdHandle(STD_ERROR_HANDLE);
-
-- // Create the child process.
--
- char *exeFile;
- const char *argStart;
-
-@@ -1860,43 +1937,32 @@
- return INVALID_HANDLE_VALUE;
- }
-
-- int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
-+ POOL_MEM cmdLine(PM_FNAME);
-+ Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
-
-- char *cmdLine = (char *)alloca(cmdLen);
--
-- snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
--
- free(exeFile);
-
-- Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
-+ if (p_CreateProcessW && p_MultiByteToWideChar) {
-+ bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
-+ in, out, err);
-+ } else {
-+ bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
-+ in, out, err);
-+ }
-
-- // try to execute program
-- bFuncRetn = CreateProcessA(comspec,
-- cmdLine, // command line
-- NULL, // process security attributes
-- NULL, // primary thread security attributes
-- TRUE, // handles are inherited
-- 0, // creation flags
-- NULL, // use parent's environment
-- NULL, // use parent's current directory
-- &siStartInfo, // STARTUPINFO pointer
-- &piProcInfo); // receives PROCESS_INFORMATION
--
- if (bFuncRetn == 0) {
- ErrorExit("CreateProcess failed\n");
- const char *err = errorString();
-- Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
-+ Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
- LocalFree((void *)err);
- return INVALID_HANDLE_VALUE;
- }
- // we don't need a handle on the process primary thread so we close
- // this now.
- CloseHandle(piProcInfo.hThread);
--
- return piProcInfo.hProcess;
- }
-
--
- void
- ErrorExit (LPCSTR lpszMessage)
- {
-Index: src/win32/compat/winapi.c
-===================================================================
---- src/win32/compat/winapi.c (révision 7772)
-+++ src/win32/compat/winapi.c (copie de travail)
-@@ -88,6 +88,9 @@
-
- t_SHGetFolderPath p_SHGetFolderPath = NULL;
-
-+t_CreateProcessA p_CreateProcessA = NULL;
-+t_CreateProcessW p_CreateProcessW = NULL;
-+
- void
- InitWinAPIWrapper()
- {
-@@ -104,6 +107,12 @@
-
- HMODULE hLib = LoadLibraryA("KERNEL32.DLL");
- if (hLib) {
-+ /* create process calls */
-+ p_CreateProcessA = (t_CreateProcessA)
-+ GetProcAddress(hLib, "CreateProcessA");
-+ p_CreateProcessW = (t_CreateProcessW)
-+ GetProcAddress(hLib, "CreateProcessW");
-+
- /* create file calls */
- p_CreateFileA = (t_CreateFileA)
- GetProcAddress(hLib, "CreateFileA");
-Index: src/win32/winapi.h
-===================================================================
---- src/win32/winapi.h (révision 7772)
-+++ src/win32/winapi.h (copie de travail)
-@@ -138,6 +138,32 @@
-
- typedef BOOL (WINAPI * t_AttachConsole) (DWORD);
-
-+typedef BOOL (WINAPI *t_CreateProcessA) (
-+ LPCSTR,
-+ LPSTR,
-+ LPSECURITY_ATTRIBUTES,
-+ LPSECURITY_ATTRIBUTES,
-+ BOOL,
-+ DWORD,
-+ PVOID,
-+ LPCSTR,
-+ LPSTARTUPINFOA,
-+ LPPROCESS_INFORMATION);
-+typedef BOOL (WINAPI *t_CreateProcessW) (
-+ LPCWSTR,
-+ LPWSTR,
-+ LPSECURITY_ATTRIBUTES,
-+ LPSECURITY_ATTRIBUTES,
-+ BOOL,
-+ DWORD,
-+ PVOID,
-+ LPCWSTR,
-+ LPSTARTUPINFOW,
-+ LPPROCESS_INFORMATION);
-+
-+extern t_CreateProcessA DLL_IMP_EXP p_CreateProcessA;
-+extern t_CreateProcessW DLL_IMP_EXP p_CreateProcessW;
-+
- extern t_GetFileAttributesA DLL_IMP_EXP p_GetFileAttributesA;
- extern t_GetFileAttributesW DLL_IMP_EXP p_GetFileAttributesW;
-
+
+ This patch fixes bug #1211 crash during reload with bad dird.conf file.
+
+ Apply it to version 2.4.4 with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.4-reload.patch
+ ./configure <your options>
+ make
+ ...
+ make install
+
+
Index: src/lib/parse_conf.c
===================================================================
--- src/lib/parse_conf.c (revision 8393)
--- /dev/null
+
+ This patch fixes a text sizing problem in the tray-monitor.
+ It fixes bug #1219.
+
+ Apply it to version 2.4.4 with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.4-tray-sizing.patch
+ ./configure <your options>
+ make
+ ...
+ make install
+
+
+Index: src/tray-monitor/tray-monitor.c
+===================================================================
+--- src/tray-monitor/tray-monitor.c (revision 8393)
++++ src/tray-monitor/tray-monitor.c (working copy)
+@@ -1,7 +1,7 @@
+ /*
+ Bacula® - The Network Backup Solution
+
+- Copyright (C) 2004-2007 Free Software Foundation Europe e.V.
++ Copyright (C) 2004-2009 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+@@ -97,6 +97,7 @@
+ static GtkWidget *textview;
+ static GtkTextBuffer *buffer;
+ static GtkWidget *timeoutspinner;
++static GtkWidget *scrolledWindow;
+ char** xpm_generic_var;
+ static gboolean blinkstate = TRUE;
+
+@@ -409,9 +410,13 @@
+ }
+
+ gtk_box_pack_start(GTK_BOX(vbox), daemon_table, FALSE, FALSE, 0);
+-
++
+ textview = gtk_text_view_new();
+
++ scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
++ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
++ gtk_container_add(GTK_CONTAINER (scrolledWindow), textview);
++
+ buffer = gtk_text_buffer_new(NULL);
+
+ gtk_text_buffer_set_text(buffer, "", -1);
+@@ -456,7 +461,7 @@
+
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
+
+- gtk_box_pack_start(GTK_BOX(vbox), textview, TRUE, TRUE, 0);
++ gtk_box_pack_start(GTK_BOX(vbox), scrolledWindow, TRUE, TRUE, 0);
+
+ GtkWidget* hbox = gtk_hbox_new(FALSE, 10);
+
--- /dev/null
+
+ This patch used the jcr stored in the BSOCK packet during callbacks
+ to the Director rather than looking them up in the JCR list.
+
+ It can be applied to Bacula version 2.4.3 (or earlier) with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-getmsg.patch
+ ./configure <your options>
+ make
+ ...
+ make install
+
+
+Index: src/dird/getmsg.c
+===================================================================
+--- src/dird/getmsg.c (revision 7970)
++++ src/dird/getmsg.c (working copy)
+@@ -1,7 +1,7 @@
+ /*
+ Bacula® - The Network Backup Solution
+
+- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
++ Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+@@ -20,7 +20,7 @@
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+- Bacula® is a registered trademark of John Walker.
++ Bacula® is a registered trademark of Kern Sibbald.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+@@ -102,12 +102,12 @@
+ char Job[MAX_NAME_LENGTH];
+ char MsgType[20];
+ int type, level;
+- JCR *jcr;
++ JCR *jcr = bs->jcr();
+ char *msg;
+
+ for (;;) {
+ n = bs->recv();
+- Dmsg2(100, "bget_dirmsg %d: %s", n, bs->msg);
++ Dmsg2(300, "bget_dirmsg %d: %s\n", n, bs->msg);
+
+ if (is_bnet_stop(bs)) {
+ return n; /* error or terminate */
+@@ -142,7 +142,7 @@
+ bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1));
+ break;
+ default:
+- Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
++ Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
+ return n;
+ }
+ continue;
+@@ -160,21 +160,13 @@
+ * Try to fulfill it.
+ */
+ if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
+- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
++ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ continue;
+ }
+- if (strcmp(Job, "*System*") == 0) {
+- jcr = NULL; /* No jcr */
+- } else if (!(jcr=get_jcr_by_full_name(Job))) {
+- Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
+- continue;
+- }
+- Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr);
+
+ /* Skip past "Jmsg Job=nnn" */
+ if (!(msg=find_msg_start(bs->msg))) {
+- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+- free_jcr(jcr);
++ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ continue;
+ }
+
+@@ -185,8 +177,7 @@
+ if (bs->msg[0] == 'J') { /* Job message */
+ if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d",
+ Job, &type, &level) != 3) {
+- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+- free_jcr(jcr);
++ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ continue;
+ }
+ Dmsg1(900, "Got msg: %s\n", bs->msg);
+@@ -199,7 +190,6 @@
+ }
+ Dmsg1(900, "Dispatch msg: %s", msg);
+ dispatch_message(jcr, type, level, msg);
+- free_jcr(jcr);
+ continue;
+ }
+ /*
+@@ -209,21 +199,16 @@
+ if (bs->msg[0] == 'C') { /* Catalog request */
+ Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
+ catalog_request(jcr, bs);
+- Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
+- free_jcr(jcr);
+ continue;
+ }
+ if (bs->msg[0] == 'U') { /* SD sending attributes */
+ Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
+ catalog_update(jcr, bs);
+- Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
+- free_jcr(jcr);
+ continue;
+ }
+ if (bs->msg[0] == 'M') { /* Mount request */
+ Dmsg1(900, "Mount req: %s", bs->msg);
+ mount_request(jcr, bs, msg);
+- free_jcr(jcr);
+ continue;
+ }
+ if (bs->msg[0] == 'S') { /* Status change */
+@@ -232,9 +217,8 @@
+ if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
+ jcr->SDJobStatus = JobStatus; /* current status */
+ } else {
+- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
++ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ }
+- free_jcr(jcr);
+ continue;
+ }
+ #ifdef needed
--- /dev/null
+
+ This patch corrects two problems:
+ 1. If you start more than 60 jobs within a 1 minute period, the unique
+ jobname (critical for the daemons) can be duplicated leading to
+ authentication failures and orphaned jobs.
+ 2. FD jobs that fail SD authentication were not properly cleaned up.
+
+ Apply it to Bacula 2.4.3 (possibly earlier versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-jobs.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/dird/job.c
+===================================================================
+--- src/dird/job.c (revision 8011)
++++ src/dird/job.c (working copy)
+@@ -758,17 +758,17 @@
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ static time_t last_start_time = 0;
+ static int seq = 0;
+- time_t now;
++ time_t now = time(NULL);
+ struct tm tm;
+ char dt[MAX_TIME_LENGTH];
+ char name[MAX_NAME_LENGTH];
+ char *p;
++ int len;
+
+ /* Guarantee unique start time -- maximum one per second, and
+ * thus unique Job Name
+ */
+ P(mutex); /* lock creation of jobs */
+- now = time(NULL);
+ seq++;
+ if (seq > 59) { /* wrap as if it is seconds */
+ seq = 0;
+@@ -783,9 +783,10 @@
+ /* Form Unique JobName */
+ (void)localtime_r(&now, &tm);
+ /* Use only characters that are permitted in Windows filenames */
+- strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
++ strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
++ len = strlen(dt) + 5; /* dt + .%02d EOS */
+ bstrncpy(name, base_name, sizeof(name));
+- name[sizeof(name)-22] = 0; /* truncate if too long */
++ name[sizeof(name)-len] = 0; /* truncate if too long */
+ bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
+ /* Convert spaces into underscores */
+ for (p=jcr->Job; *p; p++) {
+@@ -793,6 +794,7 @@
+ *p = '_';
+ }
+ }
++ Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
+ }
+
+ /* Called directly from job rescheduling */
+Index: src/stored/job.c
+===================================================================
+--- src/stored/job.c (revision 8011)
++++ src/stored/job.c (working copy)
+@@ -228,21 +228,25 @@
+ if (!(jcr=get_jcr_by_full_name(job_name))) {
+ Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
+ Dmsg1(3, "**** Job \"%s\" not found\n", job_name);
++ fd->close();
+ return;
+ }
+
+- jcr->file_bsock = fd;
+- jcr->file_bsock->set_jcr(jcr);
+-
+ Dmsg1(110, "Found Job %s\n", job_name);
+
+ if (jcr->authenticated) {
+ Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
+ (uint32_t)jcr->JobId, jcr->Job);
++ Dmsg2(50, "Hey!!!! JobId %u Job %s already authenticated.\n",
++ (uint32_t)jcr->JobId, jcr->Job);
++ fd->close();
+ free_jcr(jcr);
+ return;
+ }
+
++ jcr->file_bsock = fd;
++ jcr->file_bsock->set_jcr(jcr);
++
+ /*
+ * Authenticate the File daemon
+ */
+Index: src/lib/bnet_server.c
+===================================================================
+--- src/lib/bnet_server.c (revision 8011)
++++ src/lib/bnet_server.c (working copy)
+@@ -1,7 +1,7 @@
+ /*
+ Bacula® - The Network Backup Solution
+
+- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
++ Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+@@ -20,7 +20,7 @@
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+- Bacula® is a registered trademark of John Walker.
++ Bacula® is a registered trademark of Kern Sibbald.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+@@ -137,7 +137,7 @@
+ be.bstrerror());
+ }
+ }
+- listen(fd_ptr->fd, 5); /* tell system we are ready */
++ listen(fd_ptr->fd, 20); /* tell system we are ready */
+ sockfds.append(fd_ptr);
+ }
+ /* Start work queue thread */
--- /dev/null
+
+ This patch should cause all Job Log records to be migrated when the
+ Job is migrated. It fixes the second issue reported in bug #1171.
+
+ Apply it to Bacula 2.4.3 (possibly earlier versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-migrate.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+Index: src/dird/migrate.c
+===================================================================
+--- src/dird/migrate.c (revision 7926)
++++ src/dird/migrate.c (working copy)
+@@ -402,14 +402,6 @@
+ }
+
+ migration_cleanup(jcr, jcr->JobStatus);
+- if (mig_jcr) {
+- char jobid[50];
+- UAContext *ua = new_ua_context(jcr);
+- edit_uint64(jcr->previous_jr.JobId, jobid);
+- /* Purge all old file records, but leave Job record */
+- purge_files_from_jobs(ua, jobid);
+- free_ua_context(ua);
+- }
+ return true;
+ }
+
+@@ -1087,11 +1079,26 @@
+ edit_uint64(mig_jcr->jr.JobId, ec2));
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+
+- /* Now mark the previous job as migrated if it terminated normally */
+- if (jcr->JobStatus == JS_Terminated) {
++ /*
++ * If we terminated a migration normally:
++ * - mark the previous job as migrated
++ * - move any Log records to the new JobId
++ * - Purge the File records from the previous job
++ */
++ if (jcr->JobType == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
++ char old_jobid[50], new_jobid[50];
+ Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
+- (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
++ (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, new_jobid));
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
++ UAContext *ua = new_ua_context(jcr);
++ /* Move JobLog to new JobId */
++ Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
++ new_jobid,
++ edit_uint64(jcr->previous_jr.JobId, old_jobid));
++ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
++ /* Purge all old file records, but leave Job record */
++ purge_files_from_jobs(ua, old_jobid);
++ free_ua_context(ua);
+ }
+
+ if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
+@@ -1100,7 +1107,6 @@
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ }
+
+-
+ update_bootstrap_file(mig_jcr);
+
+ if (!db_get_job_volume_names(mig_jcr, mig_jcr->db, mig_jcr->jr.JobId, &mig_jcr->VolumeName)) {
--- /dev/null
+
+ This patch should prevent migration jobs from attempting to migrate
+ jobs that failed. Apply it to Bacula 2.4.3 (possibly earlier versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-migrate.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/dird/migrate.c
+===================================================================
+--- src/dird/migrate.c (revision 7757)
++++ src/dird/migrate.c (working copy)
+@@ -377,7 +377,7 @@
+ * to avoid two threads from using the BSOCK structure at
+ * the same time.
+ */
+- if (!bnet_fsend(sd, "run")) {
++ if (!sd->fsend("run")) {
+ return false;
+ }
+
+@@ -520,6 +520,7 @@
+ "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool,Client"
+ " WHERE Client.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
+ " AND Job.ClientId=Client.ClientId AND Job.Type='B'"
++ " AND Job.JobStatus = 'T'"
+ " ORDER by Job.StartTime";
+
+ /* Get Volume names in Pool */
+@@ -533,9 +534,9 @@
+ "SELECT DISTINCT Job.JobId,Job.StartTime FROM Media,JobMedia,Job"
+ " WHERE Media.VolumeName='%s' AND Media.MediaId=JobMedia.MediaId"
+ " AND JobMedia.JobId=Job.JobId AND Job.Type='B'"
++ " AND Job.JobStatus = 'T' AND Media.Enabled=1"
+ " ORDER by Job.StartTime";
+
+-
+ const char *sql_smallest_vol =
+ "SELECT Media.MediaId FROM Media,Pool,JobMedia WHERE"
+ " Media.MediaId in (SELECT DISTINCT MediaId from JobMedia) AND"
+@@ -570,7 +571,6 @@
+ const char *sql_job_bytes =
+ "SELECT SUM(JobBytes) FROM Job WHERE JobId IN (%s)";
+
+-
+ /* Get Media Ids in Pool */
+ const char *sql_mediaids =
+ "SELECT MediaId FROM Media,Pool WHERE"
--- /dev/null
+
+ This patch should fix two bugs:
+ - Bug #1206 -- sql error when there are no files to migrate.
+ - Bug #1171 -- Job catalog log is not migrated during migration.
+
+ Apply it to a fully patched (requires two previous migration patches)
+ 2.4.3 version with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-migrate2.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/dird/migrate.c
+===================================================================
+--- src/dird/migrate.c (revision 8152)
++++ src/dird/migrate.c (working copy)
+@@ -122,6 +122,12 @@
+
+ Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
+
++ if (!get_or_create_fileset_record(jcr)) {
++ Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
++ Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
++ return false;
++ }
++
+ /* If we find a job or jobs to migrate it is previous_jr.JobId */
+ count = get_job_to_migrate(jcr);
+ if (count < 0) {
+@@ -139,12 +145,6 @@
+ return true; /* no work */
+ }
+
+- if (!get_or_create_fileset_record(jcr)) {
+- Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
+- Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
+- return false;
+- }
+-
+ create_restore_bootstrap_file(jcr);
+
+ if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
+@@ -1062,6 +1062,11 @@
+ * mig_jcr is jcr of the newly migrated job.
+ */
+ if (mig_jcr) {
++ char old_jobid[50], new_jobid[50];
++
++ edit_uint64(jcr->previous_jr.JobId, old_jobid);
++ edit_uint64(mig_jcr->jr.JobId, new_jobid);
++
+ mig_jcr->JobFiles = jcr->JobFiles = jcr->SDJobFiles;
+ mig_jcr->JobBytes = jcr->JobBytes = jcr->SDJobBytes;
+ mig_jcr->VolSessionId = jcr->VolSessionId;
+@@ -1076,7 +1081,7 @@
+ "JobTDate=%s WHERE JobId=%s",
+ jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime,
+ edit_uint64(jcr->previous_jr.JobTDate, ec1),
+- edit_uint64(mig_jcr->jr.JobId, ec2));
++ new_jobid);
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+
+ /*
+@@ -1086,15 +1091,13 @@
+ * - Purge the File records from the previous job
+ */
+ if (jcr->JobType == JT_MIGRATE && jcr->JobStatus == JS_Terminated) {
+- char old_jobid[50], new_jobid[50];
+ Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
+- (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, new_jobid));
++ (char)JT_MIGRATED_JOB, old_jobid);
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+ UAContext *ua = new_ua_context(jcr);
+ /* Move JobLog to new JobId */
+ Mmsg(query, "UPDATE Log SET JobId=%s WHERE JobId=%s",
+- new_jobid,
+- edit_uint64(jcr->previous_jr.JobId, old_jobid));
++ new_jobid, old_jobid);
+ db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+ /* Purge all old file records, but leave Job record */
+ purge_files_from_jobs(ua, old_jobid);
--- /dev/null
+
+ This patch fixes a case of orphaned jobs (and possible deadlock)
+ during pruning.
+ Apply it to Bacula 2.4.3 (possibly earlier versions) with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-orphaned-jobs.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+Index: src/dird/ua_prune.c
+===================================================================
+--- src/dird/ua_prune.c (revision 7949)
++++ src/dird/ua_prune.c (working copy)
+@@ -468,6 +468,7 @@
+ break;
+ }
+ }
++ endeach_jcr(jcr);
+ if (skip) {
+ continue;
+ }
--- /dev/null
+
+ This patch should fix the bug reported on the bacula-users list where
+ a retention period of 100 years does immediate prunning.
+ Apply it to 2.4.3 (or earlier versions) with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-prune.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+Index: src/dird/ua_prune.c
+===================================================================
+--- src/dird/ua_prune.c (revision 7757)
++++ src/dird/ua_prune.c (working copy)
+@@ -202,7 +202,7 @@
+ now = (utime_t)time(NULL);
+
+ /* Select Jobs -- for counting */
+- Mmsg(query, count_select_job, edit_uint64(now - period, ed1),
++ Mmsg(query, count_select_job, edit_int64(now - period, ed1),
+ edit_int64(cr.ClientId, ed2));
+ Dmsg3(050, "select now=%u period=%u sql=%s\n", (uint32_t)now,
+ (uint32_t)period, query.c_str());
+@@ -230,7 +230,7 @@
+ del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
+
+ /* Now process same set but making a delete list */
+- Mmsg(query, select_job, edit_uint64(now - period, ed1),
++ Mmsg(query, select_job, edit_int64(now - period, ed1),
+ edit_int64(cr.ClientId, ed2));
+ db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del);
+
+@@ -318,7 +318,7 @@
+ * Select all files that are older than the JobRetention period
+ * and stuff them into the "DeletionCandidates" table.
+ */
+- edit_uint64(now - period, ed1);
++ edit_int64(now - period, ed1);
+ Mmsg(query, insert_delcand, (char)JobType, ed1,
+ edit_int64(cr.ClientId, ed2));
+ if (!db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL)) {
+@@ -443,10 +443,10 @@
+ edit_int64(mr->MediaId, ed1);
+ period = mr->VolRetention;
+ now = (utime_t)time(NULL);
+- edit_uint64(now-period, ed2);
++ edit_int64(now-period, ed2);
+ Mmsg(query, sel_JobMedia, ed1, ed2);
+- Dmsg3(250, "Now=%d period=%d now-period=%d\n", (int)now, (int)period,
+- (int)(now-period));
++ Dmsg3(250, "Now=%d period=%d now-period=%s\n", (int)now, (int)period,
++ ed2);
+
+ Dmsg1(050, "Query=%s\n", query.c_str());
+ if (!db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)del)) {
--- /dev/null
+
+ This patch corrects appears to fix bug #1188, where a Volume can
+ be purged while it is being written.
+
+ Apply it to Bacula 2.4.3 (possibly earlier versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-purge-bug.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/dird/ua_purge.c
+===================================================================
+--- src/dird/ua_purge.c (revision 8054)
++++ src/dird/ua_purge.c (working copy)
+@@ -463,6 +463,9 @@
+ bool purged = false;
+ char ed1[50];
+
++ if (mr->FirstWritten == 0 || mr->LastWritten == 0) {
++ goto bail_out; /* not written cannot purge */
++ }
+ if (strcmp(mr->VolStatus, "Purged") == 0) {
+ purged = true;
+ goto bail_out;
--- /dev/null
+
+ This patch fix #1110 about a problem when executing a program with
+ Unicode path.
+
+ It can be applied to 2.4.3 (and previous versions) with:
+
+ cd <bacula-source>
+ patch -p0 <2.4.3-win32-runscript-unicode-path.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/win32/compat/compat.cpp
+===================================================================
+--- src/win32/compat/compat.cpp (révision 7772)
++++ src/win32/compat/compat.cpp (copie de travail)
+@@ -1807,6 +1807,97 @@
+ }
+
+ /**
++ * Create the process with UTF8 API
++ */
++static BOOL
++CreateChildProcessW(const char *comspec, const char *cmdLine,
++ PROCESS_INFORMATION *hProcInfo,
++ HANDLE in, HANDLE out, HANDLE err)
++{
++ STARTUPINFOW siStartInfo;
++ BOOL bFuncRetn = FALSE;
++
++ // Set up members of the STARTUPINFO structure.
++ ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
++ siStartInfo.cb = sizeof(siStartInfo);
++ // setup new process to use supplied handles for stdin,stdout,stderr
++
++ siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
++ siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
++
++ siStartInfo.hStdInput = in;
++ siStartInfo.hStdOutput = out;
++ siStartInfo.hStdError = err;
++
++ // Convert argument to WCHAR
++ POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
++ POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
++
++ UTF8_2_wchar(&cmdLine_wchar, cmdLine);
++ UTF8_2_wchar(&comspec_wchar, comspec);
++
++ // Create the child process.
++ Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
++
++ // try to execute program
++ bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
++ (WCHAR*)cmdLine_wchar,// command line
++ NULL, // process security attributes
++ NULL, // primary thread security attributes
++ TRUE, // handles are inherited
++ 0, // creation flags
++ NULL, // use parent's environment
++ NULL, // use parent's current directory
++ &siStartInfo, // STARTUPINFO pointer
++ hProcInfo); // receives PROCESS_INFORMATION
++
++ free_pool_memory(cmdLine_wchar);
++ free_pool_memory(comspec_wchar);
++
++ return bFuncRetn;
++}
++
++
++/**
++ * Create the process with ANSI API
++ */
++static BOOL
++CreateChildProcessA(const char *comspec, char *cmdLine,
++ PROCESS_INFORMATION *hProcInfo,
++ HANDLE in, HANDLE out, HANDLE err)
++{
++ STARTUPINFOA siStartInfo;
++ BOOL bFuncRetn = FALSE;
++
++ // Set up members of the STARTUPINFO structure.
++ ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
++ siStartInfo.cb = sizeof(siStartInfo);
++ // setup new process to use supplied handles for stdin,stdout,stderr
++ siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
++ siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
++
++ siStartInfo.hStdInput = in;
++ siStartInfo.hStdOutput = out;
++ siStartInfo.hStdError = err;
++
++ // Create the child process.
++ Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
++
++ // try to execute program
++ bFuncRetn = p_CreateProcessA(comspec,
++ cmdLine, // command line
++ NULL, // process security attributes
++ NULL, // primary thread security attributes
++ TRUE, // handles are inherited
++ 0, // creation flags
++ NULL, // use parent's environment
++ NULL, // use parent's current directory
++ &siStartInfo,// STARTUPINFO pointer
++ hProcInfo);// receives PROCESS_INFORMATION
++ return bFuncRetn;
++}
++
++/**
+ * OK, so it would seem CreateProcess only handles true executables:
+ * .com or .exe files. So grab $COMSPEC value and pass command line to it.
+ */
+@@ -1815,44 +1906,30 @@
+ {
+ static const char *comspec = NULL;
+ PROCESS_INFORMATION piProcInfo;
+- STARTUPINFOA siStartInfo;
+ BOOL bFuncRetn = FALSE;
+
+- if (comspec == NULL) {
++ if (!p_CreateProcessA || !p_CreateProcessW)
++ return INVALID_HANDLE_VALUE;
++
++ if (comspec == NULL)
+ comspec = getenv("COMSPEC");
+- }
+ if (comspec == NULL) // should never happen
+ return INVALID_HANDLE_VALUE;
+
+ // Set up members of the PROCESS_INFORMATION structure.
+ ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
+
+- // Set up members of the STARTUPINFO structure.
+-
+- ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
+- siStartInfo.cb = sizeof(STARTUPINFO);
+- // setup new process to use supplied handles for stdin,stdout,stderr
+ // if supplied handles are not used the send a copy of our STD_HANDLE
+ // as appropriate
+- siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+- siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
++ if (in == INVALID_HANDLE_VALUE)
++ in = GetStdHandle(STD_INPUT_HANDLE);
+
+- if (in != INVALID_HANDLE_VALUE)
+- siStartInfo.hStdInput = in;
+- else
+- siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
++ if (out == INVALID_HANDLE_VALUE)
++ out = GetStdHandle(STD_OUTPUT_HANDLE);
+
+- if (out != INVALID_HANDLE_VALUE)
+- siStartInfo.hStdOutput = out;
+- else
+- siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+- if (err != INVALID_HANDLE_VALUE)
+- siStartInfo.hStdError = err;
+- else
+- siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
++ if (err == INVALID_HANDLE_VALUE)
++ err = GetStdHandle(STD_ERROR_HANDLE);
+
+- // Create the child process.
+-
+ char *exeFile;
+ const char *argStart;
+
+@@ -1860,43 +1937,32 @@
+ return INVALID_HANDLE_VALUE;
+ }
+
+- int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
++ POOL_MEM cmdLine(PM_FNAME);
++ Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
+
+- char *cmdLine = (char *)alloca(cmdLen);
+-
+- snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
+-
+ free(exeFile);
+
+- Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
++ if (p_CreateProcessW && p_MultiByteToWideChar) {
++ bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
++ in, out, err);
++ } else {
++ bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
++ in, out, err);
++ }
+
+- // try to execute program
+- bFuncRetn = CreateProcessA(comspec,
+- cmdLine, // command line
+- NULL, // process security attributes
+- NULL, // primary thread security attributes
+- TRUE, // handles are inherited
+- 0, // creation flags
+- NULL, // use parent's environment
+- NULL, // use parent's current directory
+- &siStartInfo, // STARTUPINFO pointer
+- &piProcInfo); // receives PROCESS_INFORMATION
+-
+ if (bFuncRetn == 0) {
+ ErrorExit("CreateProcess failed\n");
+ const char *err = errorString();
+- Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
++ Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
+ LocalFree((void *)err);
+ return INVALID_HANDLE_VALUE;
+ }
+ // we don't need a handle on the process primary thread so we close
+ // this now.
+ CloseHandle(piProcInfo.hThread);
+-
+ return piProcInfo.hProcess;
+ }
+
+-
+ void
+ ErrorExit (LPCSTR lpszMessage)
+ {
+Index: src/win32/compat/winapi.c
+===================================================================
+--- src/win32/compat/winapi.c (révision 7772)
++++ src/win32/compat/winapi.c (copie de travail)
+@@ -88,6 +88,9 @@
+
+ t_SHGetFolderPath p_SHGetFolderPath = NULL;
+
++t_CreateProcessA p_CreateProcessA = NULL;
++t_CreateProcessW p_CreateProcessW = NULL;
++
+ void
+ InitWinAPIWrapper()
+ {
+@@ -104,6 +107,12 @@
+
+ HMODULE hLib = LoadLibraryA("KERNEL32.DLL");
+ if (hLib) {
++ /* create process calls */
++ p_CreateProcessA = (t_CreateProcessA)
++ GetProcAddress(hLib, "CreateProcessA");
++ p_CreateProcessW = (t_CreateProcessW)
++ GetProcAddress(hLib, "CreateProcessW");
++
+ /* create file calls */
+ p_CreateFileA = (t_CreateFileA)
+ GetProcAddress(hLib, "CreateFileA");
+Index: src/win32/winapi.h
+===================================================================
+--- src/win32/winapi.h (révision 7772)
++++ src/win32/winapi.h (copie de travail)
+@@ -138,6 +138,32 @@
+
+ typedef BOOL (WINAPI * t_AttachConsole) (DWORD);
+
++typedef BOOL (WINAPI *t_CreateProcessA) (
++ LPCSTR,
++ LPSTR,
++ LPSECURITY_ATTRIBUTES,
++ LPSECURITY_ATTRIBUTES,
++ BOOL,
++ DWORD,
++ PVOID,
++ LPCSTR,
++ LPSTARTUPINFOA,
++ LPPROCESS_INFORMATION);
++typedef BOOL (WINAPI *t_CreateProcessW) (
++ LPCWSTR,
++ LPWSTR,
++ LPSECURITY_ATTRIBUTES,
++ LPSECURITY_ATTRIBUTES,
++ BOOL,
++ DWORD,
++ PVOID,
++ LPCWSTR,
++ LPSTARTUPINFOW,
++ LPPROCESS_INFORMATION);
++
++extern t_CreateProcessA DLL_IMP_EXP p_CreateProcessA;
++extern t_CreateProcessW DLL_IMP_EXP p_CreateProcessW;
++
+ extern t_GetFileAttributesA DLL_IMP_EXP p_GetFileAttributesA;
+ extern t_GetFileAttributesW DLL_IMP_EXP p_GetFileAttributesW;
+
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2004-2009 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
static GtkWidget *textview;
static GtkTextBuffer *buffer;
static GtkWidget *timeoutspinner;
+static GtkWidget *scrolledWindow;
char** xpm_generic_var;
static gboolean blinkstate = TRUE;
}
gtk_box_pack_start(GTK_BOX(vbox), daemon_table, FALSE, FALSE, 0);
-
+
textview = gtk_text_view_new();
+ scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER (scrolledWindow), textview);
+
buffer = gtk_text_buffer_new(NULL);
gtk_text_buffer_set_text(buffer, "", -1);
gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer);
- gtk_box_pack_start(GTK_BOX(vbox), textview, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), scrolledWindow, TRUE, TRUE, 0);
GtkWidget* hbox = gtk_hbox_new(FALSE, 10);