From daa1604b7ce33652ec583dcd2efc69d31a837cd9 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sun, 29 Feb 2004 22:17:45 +0000 Subject: [PATCH] Tweak Makefiles + add logrotate to autostart install + start bacula service on WinXP/NT/2K + add gui command and reload commands git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1099 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/platforms/redhat/Makefile.in | 17 +- bacula/src/cats/cats.h | 412 +++++++++++++------------- bacula/src/cats/sql.c | 8 +- bacula/src/cats/sql_list.c | 20 +- bacula/src/console/Makefile.in | 6 +- bacula/src/dird/backup.c | 2 +- bacula/src/dird/dird.c | 81 +++-- bacula/src/dird/job.c | 2 +- bacula/src/dird/protos.h | 2 +- bacula/src/dird/ua_cmds.c | 18 +- bacula/src/dird/ua_label.c | 6 +- bacula/src/dird/ua_output.c | 27 +- bacula/src/dird/ua_server.c | 8 +- bacula/src/filed/win32/winmain.cpp | 93 +++--- bacula/src/filed/win32/winservice.cpp | 14 +- bacula/src/filed/win32/wintray.cpp | 359 +++++++++++----------- bacula/src/gnome2-console/Makefile.in | 4 +- bacula/src/jcr.h | 1 + bacula/src/lib/jcr.c | 1 + bacula/src/lib/signal.c | 13 +- 20 files changed, 575 insertions(+), 519 deletions(-) diff --git a/bacula/platforms/redhat/Makefile.in b/bacula/platforms/redhat/Makefile.in index e46588fd1b..9e329a7471 100644 --- a/bacula/platforms/redhat/Makefile.in +++ b/bacula/platforms/redhat/Makefile.in @@ -8,20 +8,22 @@ # INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_PROGRAM = "@INSTALL_PROGRAM@ -m 754" nothing: install: install-autostart -install-autostart: install-autostart-fd install-autostart-sd install-autostart-dir +install-autostart: install-autostart-fd install-autostart-sd install-autostart-dir install-logrotate +install_logrotate: + @$(INSTALL_PROGRAM) ../../scripts/logrotate $(DESTDIR)/etc/logrotate.d/bacula install-autostart-fd: @if test x$(DESTDIR) = x -a -f /etc/rc.d/init.d/bacula-fd; then \ /sbin/chkconfig --del bacula-fd; \ fi - @$(INSTALL_PROGRAM) -m 744 bacula-fd $(DESTDIR)/etc/rc.d/init.d/bacula-fd + @$(INSTALL_PROGRAM) bacula-fd $(DESTDIR)/etc/rc.d/init.d/bacula-fd # set symlinks for script at startup and shutdown @if test x$(DESTDIR) = x ; then \ /sbin/chkconfig --add bacula-fd; \ @@ -32,7 +34,7 @@ install-autostart-sd: @if test x$(DESTDIR) = x -a -f /etc/rc.d/init.d/bacula-sd; then \ /sbin/chkconfig --del bacula-sd; \ fi - @$(INSTALL_PROGRAM) -m 744 bacula-sd $(DESTDIR)/etc/rc.d/init.d/bacula-sd + @$(INSTALL_PROGRAM) bacula-sd $(DESTDIR)/etc/rc.d/init.d/bacula-sd # set symlinks for script at startup and shutdown @if test x$(DESTDIR) = x ; then \ /sbin/chkconfig --add bacula-sd; \ @@ -43,7 +45,7 @@ install-autostart-dir: @if test x$(DESTDIR) = x -a -f /etc/rc.d/init.d/bacula-dir; then \ /sbin/chkconfig --del bacula-dir; \ fi - @$(INSTALL_PROGRAM) -m 744 bacula-dir $(DESTDIR)/etc/rc.d/init.d/bacula-dir + @$(INSTALL_PROGRAM) bacula-dir $(DESTDIR)/etc/rc.d/init.d/bacula-dir # set symlinks for script at startup and shutdown @if test x$(DESTDIR) = x ; then \ /sbin/chkconfig --add bacula-dir; \ @@ -52,7 +54,10 @@ install-autostart-dir: uninstall: uninstall-autostart -uninstall-autostart: uninstall-autostart-fd uninstall-autostart-sd uninstall-autostart-dir +uninstall-autostart: uninstall-autostart-fd uninstall-autostart-sd uninstall-autostart-dir uninstall-logrotate + +uninstall-logrotate: + @rm -f $(DESTDIR)/etc/logrotate.d/bacula uninstall-autostart-fd: @if test x$(DESTDIR) = x -a -f /etc/rc.d/init.d/bacula-fd; then \ diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 10fd0c5f45..2e4dafd3fb 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -57,71 +57,71 @@ struct sqlite { char dummy; }; -#define IS_NUM(x) ((x) == 1) -#define IS_NOT_NULL(x) ((x) == 1) +#define IS_NUM(x) ((x) == 1) +#define IS_NOT_NULL(x) ((x) == 1) typedef struct s_sql_field { - char *name; /* name of column */ - int length; /* length */ - int max_length; /* max length */ - uint32_t type; /* type */ - uint32_t flags; /* flags */ + char *name; /* name of column */ + int length; /* length */ + int max_length; /* max length */ + uint32_t type; /* type */ + uint32_t flags; /* flags */ } SQL_FIELD; /* * This is the "real" definition that should only be * used inside sql.c and associated database interface * subroutines. - * S Q L I T E + * S Q L I T E */ typedef struct s_db { - BQUEUE bq; /* queue control */ - brwlock_t lock; /* transaction lock */ + BQUEUE bq; /* queue control */ + brwlock_t lock; /* transaction lock */ struct sqlite *db; char **result; int status; - int nrow; /* nrow returned from sqlite */ - int ncolumn; /* ncolum returned from sqlite */ - int num_rows; /* used by code */ - int row; /* seek row */ - int have_insert_id; /* do not have insert id */ - int fields_defined; /* set when fields defined */ - int field; /* seek field */ - SQL_FIELD **fields; /* defined fields */ + int nrow; /* nrow returned from sqlite */ + int ncolumn; /* ncolum returned from sqlite */ + int num_rows; /* used by code */ + int row; /* seek row */ + int have_insert_id; /* do not have insert id */ + int fields_defined; /* set when fields defined */ + int field; /* seek field */ + SQL_FIELD **fields; /* defined fields */ int ref_count; char *db_name; char *db_user; - char *db_address; /* host name address */ - char *db_socket; /* socket for local access */ + char *db_address; /* host name address */ + char *db_socket; /* socket for local access */ char *db_password; - int db_port; /* port for host name address */ - int connected; - char *sqlite_errmsg; /* error message returned by sqlite */ - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* SQL command string */ - POOLMEM *cached_path; /* cached path name */ - int cached_path_len; /* length of cached path */ - uint32_t cached_path_id; /* cached path id */ - int transaction; /* transaction started */ - int changes; /* changes during transaction */ - POOLMEM *fname; /* Filename only */ - POOLMEM *path; /* Path only */ - POOLMEM *esc_name; /* Escaped file/path name */ - int fnl; /* file name length */ - int pnl; /* path name length */ + int db_port; /* port for host name address */ + bool connected; /* connection made to db */ + char *sqlite_errmsg; /* error message returned by sqlite */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ + POOLMEM *cached_path; /* cached path name */ + int cached_path_len; /* length of cached path */ + uint32_t cached_path_id; /* cached path id */ + int transaction; /* transaction started */ + int changes; /* changes during transaction */ + POOLMEM *fname; /* Filename only */ + POOLMEM *path; /* Path only */ + POOLMEM *esc_name; /* Escaped file/path name */ + int fnl; /* file name length */ + int pnl; /* path name length */ } B_DB; /* * "Generic" names for easier conversion * - * S Q L I T E + * S Q L I T E */ #define sql_store_result(x) (x)->result #define sql_free_result(x) my_sqlite_free_table(x) #define sql_fetch_row(x) my_sqlite_fetch_row(x) #define sql_query(x, y) my_sqlite_query((x), (y)) -#define sql_close(x) sqlite_close((x)->db) +#define sql_close(x) sqlite_close((x)->db) #define sql_strerror(x) (x)->sqlite_errmsg?(x)->sqlite_errmsg:"unknown" #define sql_num_rows(x) (x)->nrow #define sql_data_seek(x, i) (x)->row = (i) @@ -130,15 +130,15 @@ typedef struct s_db { #define sql_field_seek(x, y) my_sqlite_field_seek((x), (y)) #define sql_fetch_field(x) my_sqlite_fetch_field(x) #define sql_num_fields(x) ((x)->ncolumn) -#define SQL_ROW char** +#define SQL_ROW char** /* In cats/sqlite.c */ -void my_sqlite_free_table(B_DB *mdb); +void my_sqlite_free_table(B_DB *mdb); SQL_ROW my_sqlite_fetch_row(B_DB *mdb); -int my_sqlite_query(B_DB *mdb, char *cmd); -void my_sqlite_field_seek(B_DB *mdb, int field); +int my_sqlite_query(B_DB *mdb, char *cmd); +void my_sqlite_field_seek(B_DB *mdb, int field); SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb); @@ -155,11 +155,11 @@ SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb); * used inside sql.c and associated database interface * subroutines. * - * M Y S Q L + * M Y S Q L */ typedef struct s_db { - BQUEUE bq; /* queue control */ - brwlock_t lock; /* transaction lock */ + BQUEUE bq; /* queue control */ + brwlock_t lock; /* transaction lock */ MYSQL mysql; MYSQL *db; MYSQL_RES *result; @@ -169,22 +169,22 @@ typedef struct s_db { char *db_name; char *db_user; char *db_password; - char *db_address; /* host address */ - char *db_socket; /* socket for local access */ - int db_port; /* port of host address */ - int have_insert_id; /* do have insert_id() */ - int connected; - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* SQL command string */ + char *db_address; /* host address */ + char *db_socket; /* socket for local access */ + int db_port; /* port of host address */ + int have_insert_id; /* do have insert_id() */ + bool connected; + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ POOLMEM *cached_path; - int cached_path_len; /* length of cached path */ + int cached_path_len; /* length of cached path */ uint32_t cached_path_id; - int changes; /* changes made to db */ - POOLMEM *fname; /* Filename only */ - POOLMEM *path; /* Path only */ - POOLMEM *esc_name; /* Escaped file/path name */ - int fnl; /* file name length */ - int pnl; /* path name length */ + int changes; /* changes made to db */ + POOLMEM *fname; /* Filename only */ + POOLMEM *path; /* Path only */ + POOLMEM *esc_name; /* Escaped file/path name */ + int fnl; /* file name length */ + int pnl; /* path name length */ } B_DB; #define DB_STATUS int @@ -194,7 +194,7 @@ typedef struct s_db { #define sql_free_result(x) mysql_free_result((x)->result) #define sql_fetch_row(x) mysql_fetch_row((x)->result) #define sql_query(x, y) mysql_query((x)->db, (y)) -#define sql_close(x) mysql_close((x)->db) +#define sql_close(x) mysql_close((x)->db) #define sql_strerror(x) mysql_error((x)->db) #define sql_num_rows(x) mysql_num_rows((x)->result) #define sql_data_seek(x, i) mysql_data_seek((x)->result, (i)) @@ -203,8 +203,8 @@ typedef struct s_db { #define sql_field_seek(x, y) mysql_field_seek((x)->result, (y)) #define sql_fetch_field(x) mysql_fetch_field((x)->result) #define sql_num_fields(x) (int)mysql_num_fields((x)->result) -#define SQL_ROW MYSQL_ROW -#define SQL_FIELD MYSQL_FIELD +#define SQL_ROW MYSQL_ROW +#define SQL_FIELD MYSQL_FIELD #else @@ -215,15 +215,15 @@ typedef struct s_db { #include /* TEMP: the following is taken from select OID, typname from pg_type; */ -#define IS_NUM(x) ((x) == 20 || (x) == 21 || (x) == 23 || (x) == 700 || (x) == 701) -#define IS_NOT_NULL(x) ((x) == 1) +#define IS_NUM(x) ((x) == 20 || (x) == 21 || (x) == 23 || (x) == 700 || (x) == 701) +#define IS_NOT_NULL(x) ((x) == 1) typedef char **POSTGRESQL_ROW; typedef struct pg_field { - char *name; - int max_length; - unsigned int type; - unsigned int flags; // 1 == not null + char *name; + int max_length; + unsigned int type; + unsigned int flags; // 1 == not null } POSTGRESQL_FIELD; @@ -232,11 +232,11 @@ typedef struct pg_field { * used inside sql.c and associated database interface * subroutines. * - * P O S T G R E S Q L + * P O S T G R E S Q L */ typedef struct s_db { - BQUEUE bq; /* queue control */ - brwlock_t lock; /* transaction lock */ + BQUEUE bq; /* queue control */ + brwlock_t lock; /* transaction lock */ PGconn *db; PGresult *result; int status; @@ -244,36 +244,36 @@ typedef struct s_db { POSTGRESQL_FIELD *fields; int num_rows; int num_fields; - int row_number; /* what row number did we get via my_postgresql_data_seek? */ - int field_number; /* what field number did we get via my_postgresql_field_seek? */ + int row_number; /* what row number did we get via my_postgresql_data_seek? */ + int field_number; /* what field number did we get via my_postgresql_field_seek? */ int ref_count; char *db_name; char *db_user; char *db_password; - char *db_address; /* host address */ - char *db_socket; /* socket for local access */ - int db_port; /* port of host address */ - int have_insert_id; /* do have insert_id() */ - int connected; - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* SQL command string */ + char *db_address; /* host address */ + char *db_socket; /* socket for local access */ + int db_port; /* port of host address */ + int have_insert_id; /* do have insert_id() */ + bool connected; + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ POOLMEM *cached_path; - int cached_path_len; /* length of cached path */ + int cached_path_len; /* length of cached path */ uint32_t cached_path_id; - int changes; /* changes made to db */ - POOLMEM *fname; /* Filename only */ - POOLMEM *path; /* Path only */ - POOLMEM *esc_name; /* Escaped file/path name */ - int fnl; /* file name length */ - int pnl; /* path name length */ + int changes; /* changes made to db */ + POOLMEM *fname; /* Filename only */ + POOLMEM *path; /* Path only */ + POOLMEM *esc_name; /* Escaped file/path name */ + int fnl; /* file name length */ + int pnl; /* path name length */ } B_DB; -void my_postgresql_free_result(B_DB *mdb); -POSTGRESQL_ROW my_postgresql_fetch_row (B_DB *mdb); -int my_postgresql_query (B_DB *mdb, char *query); -void my_postgresql_data_seek (B_DB *mdb, int row); -int my_postgresql_currval (B_DB *mdb, char *table_name); -void my_postgresql_field_seek (B_DB *mdb, int row); +void my_postgresql_free_result(B_DB *mdb); +POSTGRESQL_ROW my_postgresql_fetch_row (B_DB *mdb); +int my_postgresql_query (B_DB *mdb, char *query); +void my_postgresql_data_seek (B_DB *mdb, int row); +int my_postgresql_currval (B_DB *mdb, char *table_name); +void my_postgresql_field_seek (B_DB *mdb, int row); POSTGRESQL_FIELD * my_postgresql_fetch_field(B_DB *mdb); @@ -282,7 +282,7 @@ POSTGRESQL_FIELD * my_postgresql_fetch_field(B_DB *mdb); #define sql_free_result(x) my_postgresql_free_result(x) #define sql_fetch_row(x) my_postgresql_fetch_row(x) #define sql_query(x, y) my_postgresql_query((x), (y)) -#define sql_close(x) PQfinish((x)->db) +#define sql_close(x) PQfinish((x)->db) #define sql_strerror(x) PQresultErrorMessage((x)->result) #define sql_num_rows(x) ((unsigned) PQntuples((x)->result)) #define sql_data_seek(x, i) my_postgresql_data_seek((x), (i)) @@ -291,8 +291,8 @@ POSTGRESQL_FIELD * my_postgresql_fetch_field(B_DB *mdb); #define sql_field_seek(x, y) my_postgresql_field_seek((x), (y)) #define sql_fetch_field(x) my_postgresql_fetch_field(x) #define sql_num_fields(x) ((x)->num_fields) -#define SQL_ROW POSTGRESQL_ROW -#define SQL_FIELD POSTGRESQL_FIELD +#define SQL_ROW POSTGRESQL_ROW +#define SQL_FIELD POSTGRESQL_FIELD #else /* USE BACULA DB routines */ @@ -301,17 +301,17 @@ POSTGRESQL_FIELD * my_postgresql_fetch_field(B_DB *mdb); /* Change this each time there is some incompatible * file format change!!!! */ -#define BDB_VERSION 12 /* file version number */ +#define BDB_VERSION 12 /* file version number */ struct s_control { - int bdb_version; /* Version number */ - uint32_t JobId; /* next Job Id */ - uint32_t PoolId; /* next Pool Id */ - uint32_t MediaId; /* next Media Id */ - uint32_t JobMediaId; /* next JobMedia Id */ - uint32_t ClientId; /* next Client Id */ - uint32_t FileSetId; /* nest FileSet Id */ - time_t time; /* time file written */ + int bdb_version; /* Version number */ + uint32_t JobId; /* next Job Id */ + uint32_t PoolId; /* next Pool Id */ + uint32_t MediaId; /* next Media Id */ + uint32_t JobMediaId; /* next JobMedia Id */ + uint32_t ClientId; /* next Client Id */ + uint32_t FileSetId; /* nest FileSet Id */ + time_t time; /* time file written */ }; @@ -319,23 +319,23 @@ struct s_control { * Bacula internal DB */ typedef struct s_db { - BQUEUE bq; /* queue control */ -/* pthread_mutex_t mutex; */ /* single thread lock */ - brwlock_t lock; /* transaction lock */ - int ref_count; /* number of times opened */ - struct s_control control; /* control file structure */ - int cfd; /* control file device */ - FILE *jobfd; /* Jobs records file descriptor */ - FILE *poolfd; /* Pool records fd */ - FILE *mediafd; /* Media records fd */ - FILE *jobmediafd; /* JobMedia records fd */ - FILE *clientfd; /* Client records fd */ - FILE *filesetfd; /* FileSet records fd */ - char *db_name; /* name of database */ - POOLMEM *errmsg; /* nicely edited error message */ - POOLMEM *cmd; /* Command string */ + BQUEUE bq; /* queue control */ +/* pthread_mutex_t mutex; */ /* single thread lock */ + brwlock_t lock; /* transaction lock */ + int ref_count; /* number of times opened */ + struct s_control control; /* control file structure */ + int cfd; /* control file device */ + FILE *jobfd; /* Jobs records file descriptor */ + FILE *poolfd; /* Pool records fd */ + FILE *mediafd; /* Media records fd */ + FILE *jobmediafd; /* JobMedia records fd */ + FILE *clientfd; /* Client records fd */ + FILE *filesetfd; /* FileSet records fd */ + char *db_name; /* name of database */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* Command string */ POOLMEM *cached_path; - int cached_path_len; /* length of cached path */ + int cached_path_len; /* length of cached path */ uint32_t cached_path_id; } B_DB; @@ -350,12 +350,12 @@ typedef struct s_db { #define DELETE_DB(jcr, db, cmd) DeleteDB(__FILE__, __LINE__, jcr, db, cmd) -#else /* not __SQL_C */ +#else /* not __SQL_C */ /* This is a "dummy" definition for use outside of sql.c */ -typedef struct s_db { - int dummy; /* for SunOS compiler */ +typedef struct s_db { + int dummy; /* for SunOS compiler */ } B_DB; #endif /* __SQL_C */ @@ -366,7 +366,7 @@ extern uint32_t bacula_db_version; * but at the current time, this breaks MySQL. */ typedef uint32_t FileId_t; -typedef uint32_t DBId_t; /* general DB id type */ +typedef uint32_t DBId_t; /* general DB id type */ typedef uint32_t JobId_t; #define faddr_t long @@ -380,18 +380,18 @@ typedef uint32_t JobId_t; /* Job record */ struct JOB_DBR { JobId_t JobId; - char Job[MAX_NAME_LENGTH]; /* Job unique name */ - char Name[MAX_NAME_LENGTH]; /* Job base name */ - int Type; /* actually char(1) */ - int Level; /* actually char(1) */ - int JobStatus; /* actually char(1) */ - uint32_t ClientId; /* Id of client */ - uint32_t PoolId; /* Id of pool */ - uint32_t FileSetId; /* Id of FileSet */ - time_t SchedTime; /* Time job scheduled */ - time_t StartTime; /* Job start time */ - time_t EndTime; /* Job termination time */ - utime_t JobTDate; /* Backup time/date in seconds */ + char Job[MAX_NAME_LENGTH]; /* Job unique name */ + char Name[MAX_NAME_LENGTH]; /* Job base name */ + int Type; /* actually char(1) */ + int Level; /* actually char(1) */ + int JobStatus; /* actually char(1) */ + uint32_t ClientId; /* Id of client */ + uint32_t PoolId; /* Id of pool */ + uint32_t FileSetId; /* Id of FileSet */ + time_t SchedTime; /* Time job scheduled */ + time_t StartTime; /* Job start time */ + time_t EndTime; /* Job termination time */ + utime_t JobTDate; /* Backup time/date in seconds */ uint32_t VolSessionId; uint32_t VolSessionTime; uint32_t JobFiles; @@ -402,8 +402,8 @@ struct JOB_DBR { /* Note, FirstIndex, LastIndex, Start/End File and Block * are only used in the JobMedia record. */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ uint32_t StartFile; uint32_t EndFile; uint32_t StartBlock; @@ -421,28 +421,28 @@ struct JOB_DBR { */ /* JobMedia record */ struct JOBMEDIA_DBR { - uint32_t JobMediaId; /* record id */ - JobId_t JobId; /* JobId */ - uint32_t MediaId; /* MediaId */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ - uint32_t StartFile; /* File for start of data */ - uint32_t EndFile; /* End file on Volume */ - uint32_t StartBlock; /* start block on tape */ - uint32_t EndBlock; /* last block */ + uint32_t JobMediaId; /* record id */ + JobId_t JobId; /* JobId */ + uint32_t MediaId; /* MediaId */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ + uint32_t StartFile; /* File for start of data */ + uint32_t EndFile; /* End file on Volume */ + uint32_t StartBlock; /* start block on tape */ + uint32_t EndBlock; /* last block */ }; /* Volume Parameter structure */ struct VOL_PARAMS { char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ - uint32_t VolIndex; /* Volume seqence no. */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ - uint32_t StartFile; /* File for start of data */ - uint32_t EndFile; /* End file on Volume */ - uint32_t StartBlock; /* start block on tape */ - uint32_t EndBlock; /* last block */ + uint32_t VolIndex; /* Volume seqence no. */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ + uint32_t StartFile; /* File for start of data */ + uint32_t EndFile; /* End file on Volume */ + uint32_t StartBlock; /* start block on tape */ + uint32_t EndBlock; /* last block */ }; @@ -451,9 +451,9 @@ struct VOL_PARAMS { * records (e.g. pathname, filename, fileattributes). */ struct ATTR_DBR { - char *fname; /* full path & filename */ - char *link; /* link if any */ - char *attr; /* attributes statp */ + char *fname; /* full path & filename */ + char *link; /* link if any */ + char *attr; /* attributes statp */ uint32_t FileIndex; uint32_t Stream; JobId_t JobId; @@ -475,26 +475,26 @@ struct FILE_DBR { char LStat[256]; /* int Status; */ char SIG[50]; - int SigType; /* NO_SIG/MD5_SIG/SHA1_SIG */ + int SigType; /* NO_SIG/MD5_SIG/SHA1_SIG */ }; /* Pool record -- same format as database */ struct POOL_DBR { uint32_t PoolId; - char Name[MAX_NAME_LENGTH]; /* Pool name */ - uint32_t NumVols; /* total number of volumes */ - uint32_t MaxVols; /* max allowed volumes */ - int32_t UseOnce; /* set to use once only */ - int32_t UseCatalog; /* set to use catalog */ - int32_t AcceptAnyVolume; /* set to accept any volume sequence */ - int32_t AutoPrune; /* set to prune automatically */ - int32_t Recycle; /* default Vol recycle flag */ - utime_t VolRetention; /* retention period in seconds */ - utime_t VolUseDuration; /* time in secs volume can be used */ - uint32_t MaxVolJobs; /* Max Jobs on Volume */ - uint32_t MaxVolFiles; /* Max files on Volume */ - uint64_t MaxVolBytes; /* Max bytes on Volume */ - char PoolType[MAX_NAME_LENGTH]; + char Name[MAX_NAME_LENGTH]; /* Pool name */ + uint32_t NumVols; /* total number of volumes */ + uint32_t MaxVols; /* max allowed volumes */ + int32_t UseOnce; /* set to use once only */ + int32_t UseCatalog; /* set to use catalog */ + int32_t AcceptAnyVolume; /* set to accept any volume sequence */ + int32_t AutoPrune; /* set to prune automatically */ + int32_t Recycle; /* default Vol recycle flag */ + utime_t VolRetention; /* retention period in seconds */ + utime_t VolUseDuration; /* time in secs volume can be used */ + uint32_t MaxVolJobs; /* Max Jobs on Volume */ + uint32_t MaxVolFiles; /* Max files on Volume */ + uint64_t MaxVolBytes; /* Max bytes on Volume */ + char PoolType[MAX_NAME_LENGTH]; char LabelFormat[MAX_NAME_LENGTH]; /* Extra stuff not in DB */ faddr_t rec_addr; @@ -502,37 +502,37 @@ struct POOL_DBR { /* Media record -- same as the database */ struct MEDIA_DBR { - uint32_t MediaId; /* Unique volume id */ + uint32_t MediaId; /* Unique volume id */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char MediaType[MAX_NAME_LENGTH]; /* Media type */ - uint32_t PoolId; /* Pool id */ - time_t FirstWritten; /* Time Volume first written */ - time_t LastWritten; /* Time Volume last written */ - time_t LabelDate; /* Date/Time Volume labeled */ - uint32_t VolJobs; /* number of jobs on this medium */ - uint32_t VolFiles; /* Number of files */ - uint32_t VolBlocks; /* Number of blocks */ - uint32_t VolMounts; /* Number of times mounted */ - uint32_t VolErrors; /* Number of read/write errors */ - uint32_t VolWrites; /* Number of writes */ - uint32_t VolReads; /* Number of reads */ - uint64_t VolBytes; /* Number of bytes written */ - uint64_t MaxVolBytes; /* Max bytes to write to Volume */ - uint64_t VolCapacityBytes; /* capacity estimate */ - uint64_t VolReadTime; /* time spent reading volume */ - uint64_t VolWriteTime; /* time spent writing volume */ - utime_t VolRetention; /* Volume retention in seconds */ - utime_t VolUseDuration; /* time in secs volume can be used */ - uint32_t MaxVolJobs; /* Max Jobs on Volume */ - uint32_t MaxVolFiles; /* Max files on Volume */ - int32_t Recycle; /* recycle yes/no */ - int32_t Slot; /* slot in changer */ - int32_t InChanger; /* Volume currently in changer */ - char VolStatus[20]; /* Volume status */ + uint32_t PoolId; /* Pool id */ + time_t FirstWritten; /* Time Volume first written */ + time_t LastWritten; /* Time Volume last written */ + time_t LabelDate; /* Date/Time Volume labeled */ + uint32_t VolJobs; /* number of jobs on this medium */ + uint32_t VolFiles; /* Number of files */ + uint32_t VolBlocks; /* Number of blocks */ + uint32_t VolMounts; /* Number of times mounted */ + uint32_t VolErrors; /* Number of read/write errors */ + uint32_t VolWrites; /* Number of writes */ + uint32_t VolReads; /* Number of reads */ + uint64_t VolBytes; /* Number of bytes written */ + uint64_t MaxVolBytes; /* Max bytes to write to Volume */ + uint64_t VolCapacityBytes; /* capacity estimate */ + uint64_t VolReadTime; /* time spent reading volume */ + uint64_t VolWriteTime; /* time spent writing volume */ + utime_t VolRetention; /* Volume retention in seconds */ + utime_t VolUseDuration; /* time in secs volume can be used */ + uint32_t MaxVolJobs; /* Max Jobs on Volume */ + uint32_t MaxVolFiles; /* Max files on Volume */ + int32_t Recycle; /* recycle yes/no */ + int32_t Slot; /* slot in changer */ + int32_t InChanger; /* Volume currently in changer */ + char VolStatus[20]; /* Volume status */ /* Extra stuff not in DB */ - faddr_t rec_addr; /* found record address */ + faddr_t rec_addr; /* found record address */ /* Since the database returns times as strings, this is how we pass - * them back. + * them back. */ char cFirstWritten[MAX_TIME_LENGTH]; /* FirstWritten returned from DB */ char cLastWritten[MAX_TIME_LENGTH]; /* LastWritten returned from DB */ @@ -541,12 +541,12 @@ struct MEDIA_DBR { /* Client record -- same as the database */ struct CLIENT_DBR { - uint32_t ClientId; /* Unique Client id */ + uint32_t ClientId; /* Unique Client id */ int AutoPrune; utime_t FileRetention; utime_t JobRetention; - char Name[MAX_NAME_LENGTH]; /* Client name */ - char Uname[256]; /* Uname for client */ + char Name[MAX_NAME_LENGTH]; /* Client name */ + char Uname[256]; /* Uname for client */ }; /* Counter record as in database */ @@ -561,16 +561,16 @@ struct COUNTER_DBR { /* FileSet record -- same as the database */ struct FILESET_DBR { - uint32_t FileSetId; /* Unique FileSet id */ + uint32_t FileSetId; /* Unique FileSet id */ char FileSet[MAX_NAME_LENGTH]; /* FileSet name */ - char MD5[50]; /* MD5 signature of include/exclude */ - time_t CreateTime; /* date created */ + char MD5[50]; /* MD5 signature of include/exclude */ + time_t CreateTime; /* date created */ /* * This is where we return CreateTime */ char cCreateTime[MAX_TIME_LENGTH]; /* CreateTime as returned from DB */ /* Not in DB but returned by db_create_fileset() */ - bool created; /* set when record newly created */ + bool created; /* set when record newly created */ }; diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index 51b09347a4..79dc10c5d9 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -351,7 +351,7 @@ void split_path_and_filename(JCR *jcr, B_DB *mdb, char *fname) } /* - * List dashs as part of header for listing SQL results in a table + * List dashes as part of header for listing SQL results in a table */ void list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx) @@ -376,7 +376,7 @@ list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx) * list on one line horizontally. */ void -list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) +list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) { SQL_FIELD *field; SQL_ROW row; @@ -440,7 +440,7 @@ list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) field = sql_fetch_field(mdb); if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %-*s |", (int)field->max_length, "NULL"); - } else if (IS_NUM(field->type)) { + } else if (IS_NUM(field->type) && !jcr->gui) { bsnprintf(buf, sizeof(buf), " %*s |", (int)field->max_length, add_commas(row[i], ewc)); } else { @@ -462,7 +462,7 @@ vertical_list: field = sql_fetch_field(mdb); if (row[i] == NULL) { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, "NULL"); - } else if (IS_NUM(field->type)) { + } else if (IS_NUM(field->type) && !jcr->gui) { bsnprintf(buf, sizeof(buf), " %*s: %s\n", max_len, field->name, add_commas(row[i], ewc)); } else { diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index 428e4ae8fd..3f56ca248f 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -44,7 +44,7 @@ */ /* Imported subroutines */ -extern void list_result(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); +extern void list_result(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type); extern int QueryDB(char *file, int line, JCR *jcr, B_DB *db, char *select_cmd); @@ -67,7 +67,7 @@ int db_list_sql_query(JCR *jcr, B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, mdb->result = sql_store_result(mdb); if (mdb->result) { - list_result(mdb, sendit, ctx, type); + list_result(jcr, mdb, sendit, ctx, type); sql_free_result(mdb); } db_unlock(mdb); @@ -93,7 +93,7 @@ db_list_pool_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_ return; } - list_result(mdb, sendit, ctx, type); + list_result(jcr, mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -117,7 +117,7 @@ db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, return; } - list_result(mdb, sendit, ctx, type); + list_result(jcr, mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -166,7 +166,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, return; } - list_result(mdb, sendit, ctx, type); + list_result(jcr, mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -203,7 +203,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, return; } - list_result(mdb, sendit, ctx, type); + list_result(jcr, mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -258,7 +258,7 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, db_unlock(mdb); return; } - list_result(mdb, sendit, ctx, type); + list_result(jcr, mdb, sendit, ctx, type); sql_free_result(mdb); db_unlock(mdb); @@ -282,7 +282,7 @@ db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo return; } - list_result(mdb, sendit, ctx, HORZ_LIST); + list_result(jcr, mdb, sendit, ctx, HORZ_LIST); sql_free_result(mdb); @@ -295,7 +295,7 @@ AS Files,sum(JobBytes) As Bytes FROM Job"); return; } - list_result(mdb, sendit, ctx, HORZ_LIST); + list_result(jcr, mdb, sendit, ctx, HORZ_LIST); sql_free_result(mdb); db_unlock(mdb); @@ -325,7 +325,7 @@ db_list_files_for_job(JCR *jcr, B_DB *mdb, uint32_t jobid, DB_LIST_HANDLER *send return; } - list_result(mdb, sendit, ctx, HORZ_LIST); + list_result(jcr, mdb, sendit, ctx, HORZ_LIST); sql_free_result(mdb); db_unlock(mdb); diff --git a/bacula/src/console/Makefile.in b/bacula/src/console/Makefile.in index b49b953a02..d4695efda9 100644 --- a/bacula/src/console/Makefile.in +++ b/bacula/src/console/Makefile.in @@ -69,7 +69,7 @@ distclean: realclean (cd $(srcdir); $(RMF) Makefile; $(RMF) -r CVS) install: all - $(INSTALL_SCRIPT) bconsole $(DESTDIR)$(sbindir)/bconsole + $(INSTALL_PROGRAM) bconsole $(DESTDIR)$(sbindir)/bconsole @srcconf=bconsole.conf; \ if test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \ destconf=$$srcconf.new; \ @@ -80,11 +80,11 @@ install: all echo "${INSTALL_CONFIG} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \ ${INSTALL_CONFIG} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf if test -f static-bconsole; then \ - $(INSTALL_SCRIPT) static-bconsole $(DESTDIR)$(sbindir)/static-bconsole; \ + $(INSTALL_PROGRAM) static-bconsole $(DESTDIR)$(sbindir)/static-bconsole; \ fi uninstall: - (cd $(DESTDIR)$(sbindir); $(RMF) bconsole) + (cd $(DESTDIR)$(sbindir); $(RMF) bconsole static-bconsole) (cd $(DESTDIR)$(sysconfdir); $(RMF) bconsole.conf bconsole.conf.new) diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 9e3d2354ea..a2773826e2 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -456,7 +456,7 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg)); -// bmicrosleep(40, 0); /* for debugging SIGHUP */ +// bmicrosleep(15, 0); /* for debugging SIGHUP */ Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\ JobId: %d\n\ diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 479c9d1ebd..c09721b6b0 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -32,9 +32,9 @@ /* Forward referenced subroutines */ static void terminate_dird(int sig); static int check_resources(); -static void reload_config(int sig); /* Exported subroutines */ +void reload_config(int sig); /* Imported subroutines */ @@ -61,6 +61,7 @@ int SDConnectTimeout; /* Globals Imported */ extern int r_first, r_last; /* first and last resources */ +extern RES_TABLE resources[]; extern RES_ITEM job_items[]; extern URES res_all; @@ -290,6 +291,19 @@ static void init_reload(void) } } +static void free_saved_resources(int table) +{ + int num = r_last - r_first + 1; + RES **res_tab = reload_table[table].res_table; + Dmsg1(000, "Freeing resources for table %d\n", table); + for (int j=0; jreload_id - 1; - RES **res_tab; Dmsg1(000, "reload job_end JobId=%d\n", jcr->JobId); + lock_jcr_chain(); + LockRes(); if (--reload_table[i].job_count <= 0) { - int num = r_last - r_first + 1; - res_tab = reload_table[i].res_table; - Dmsg0(000, "Freeing resources\n"); - for (int j=0; j die */ @@ -336,12 +357,7 @@ static void reload_config(int sig) lock_jcr_chain(); LockRes(); - for (int i=0; i < max_reloads; i++) { - if (reload_table[i].res_table == NULL) { - table = i; - break; - } - } + table = find_free_table(); if (table < 0) { Jmsg(NULL, M_ERROR, 0, _("Too many reload requests.\n")); goto bail_out; @@ -352,8 +368,7 @@ static void reload_config(int sig) * reload_id == 0 */ foreach_jcr(jcr) { - /* JobId==0 => console */ - if (jcr->JobId != 0 && jcr->reload_id == 0) { + if (jcr->reload_id == 0) { reload_table[table].job_count++; jcr->reload_id = table + 1; job_end_push(jcr, reload_job_end_cb); @@ -362,19 +377,28 @@ static void reload_config(int sig) free_locked_jcr(jcr); } Dmsg1(000, "Reload_config njobs=%d\n", njobs); - if (njobs > 0) { - reload_table[table].res_table = save_config_resources(); - Dmsg1(000, "Saved old config in table %d\n", table); - } else { - free_config_resources(); - } + reload_table[table].res_table = save_config_resources(); + Dmsg1(000, "Saved old config in table %d\n", table); Dmsg0(000, "Calling parse config\n"); parse_config(configfile); Dmsg0(000, "Reloaded config file\n"); if (!check_resources()) { - Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile); + rtable = find_free_table(); /* save new, bad table */ + if (rtable < 0) { + Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile); + } else { + Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile); + } + reload_table[rtable].res_table = save_config_resources(); + /* Now restore old resoure values */ + int num = r_last - r_first + 1; + RES **res_tab = reload_table[table].res_table; + for (int i=0; iFDConnectTimeout; SDConnectTimeout = director->SDConnectTimeout; Dmsg0(0, "Director's configuration file reread.\n"); + + /* Now release saved resources */ + free_saved_resources(table); bail_out: UnlockRes(); diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 55788a11a6..9cc4c25f88 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -66,7 +66,7 @@ void init_job_server(int max_workers) wd->destructor = job_monitor_destructor; wd->one_shot = false; wd->interval = 60; - wd->data = create_control_jcr("*JobMonitor*", JT_SYSTEM); + wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM); register_watchdog(wd); return; diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index cbfe5b7fee..b217a678ac 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -142,7 +142,7 @@ RUN *find_next_run(RUN *run, JOB *job, time_t &runtime); /* ua_server.c */ void bsendmsg(void *sock, char *fmt, ...); UAContext *new_ua_context(JCR *jcr); -JCR *create_control_jcr(char *base_name, int job_type); +JCR *new_control_jcr(char *base_name, int job_type); void free_ua_context(UAContext *ua); /* ua_select.c */ diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 063127981d..2f4473eb45 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -47,7 +47,8 @@ extern int list_cmd(UAContext *ua, char *cmd); extern int llist_cmd(UAContext *ua, char *cmd); extern int show_cmd(UAContext *ua, char *cmd); extern int messagescmd(UAContext *ua, char *cmd); -extern int autodisplaycmd(UAContext *ua, char *cmd); +extern int autodisplay_cmd(UAContext *ua, char *cmd); +extern int gui_cmd(UAContext *ua, char *cmd); extern int sqlquerycmd(UAContext *ua, char *cmd); extern int querycmd(UAContext *ua, char *cmd); extern int run_cmd(UAContext *ua, char *cmd); @@ -71,6 +72,7 @@ static int delete_cmd(UAContext *ua, char *cmd); static int use_cmd(UAContext *ua, char *cmd), unmount_cmd(UAContext *ua, char *cmd); static int version_cmd(UAContext *ua, char *cmd), automount_cmd(UAContext *ua, char *cmd); static int time_cmd(UAContext *ua, char *cmd); +static int reload_cmd(UAContext *ua, char *cmd); static int update_volume(UAContext *ua); static int update_pool(UAContext *ua); static int delete_volume(UAContext *ua); @@ -88,13 +90,14 @@ int quit_cmd(UAContext *ua, char *cmd); struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; }; static struct cmdstruct commands[] = { { N_("add"), add_cmd, _("add media to a pool")}, - { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")}, + { N_("autodisplay"), autodisplay_cmd, _("autodisplay [on/off] -- console messages")}, { N_("automount"), automount_cmd, _("automount [on/off] -- after label")}, { N_("cancel"), cancel_cmd, _("cancel job=nnn -- cancel a job")}, { N_("create"), create_cmd, _("create DB Pool from resource")}, { N_("delete"), delete_cmd, _("delete [pool= | media volume=]")}, { N_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing")}, { N_("exit"), quit_cmd, _("exit = quit")}, + { N_("gui"), gui_cmd, _("gui [on/off] -- non-interactive gui mode")}, { N_("help"), help_cmd, _("print this command")}, { N_("list"), list_cmd, _("list [pools | jobs | jobtotals | media | files jobid=]; from catalog")}, { N_("label"), label_cmd, _("label a tape")}, @@ -108,6 +111,7 @@ static struct cmdstruct commands[] = { { N_("restore"), restore_cmd, _("restore files")}, { N_("relabel"), relabel_cmd, _("relabel a tape")}, { N_("release"), release_cmd, _("release ")}, + { N_("reload"), reload_cmd, _("reload conf file")}, { N_("run"), run_cmd, _("run ")}, { N_("status"), status_cmd, _("status [storage | client]=")}, { N_("setdebug"), setdebug_cmd, _("sets debug level")}, @@ -1447,6 +1451,16 @@ static int time_cmd(UAContext *ua, char *cmd) return 1; } +/* + * reload the conf file + */ +extern void reload_config(int sig); + +static int reload_cmd(UAContext *ua, char *cmd) +{ + reload_config(1); +} + /* diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c index c79cef291f..09cffcfdc9 100644 --- a/bacula/src/dird/ua_label.c +++ b/bacula/src/dird/ua_label.c @@ -294,10 +294,10 @@ static int do_label(UAContext *ua, char *cmd, int relabel) return 1; } - /* Require Volume to be Purged */ + /* Require Volume to be Purged or Recycled */ checkVol: - if (strcmp(omr.VolStatus, "Purged") != 0) { - bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"), + if (strcmp(omr.VolStatus, "Purged") != 0 || strcmp(omr.VolStatus, "Recycle") != 0) { + bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"), omr.VolumeName, omr.VolStatus); return 1; } diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index f0f1eca586..27ac035772 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -50,7 +50,7 @@ static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist); /* * Turn auto display of console messages on/off */ -int autodisplaycmd(UAContext *ua, char *cmd) +int autodisplay_cmd(UAContext *ua, char *cmd) { static char *kw[] = { N_("on"), @@ -71,6 +71,31 @@ int autodisplaycmd(UAContext *ua, char *cmd) return 1; } +/* + * Turn gui processing on/off + */ +int gui_cmd(UAContext *ua, char *cmd) +{ + static char *kw[] = { + N_("on"), + N_("off"), + NULL}; + + switch (find_arg_keyword(ua, kw)) { + case 0: + ua->jcr->gui = true; + break; + case 1: + ua->jcr->gui = false; + break; + default: + bsendmsg(ua, _("ON or OFF keyword missing.\n")); + break; + } + return 1; +} + + struct showstruct {char *res_name; int type;}; static struct showstruct reses[] = { diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c index f89db83b81..d32a9f6982 100644 --- a/bacula/src/dird/ua_server.c +++ b/bacula/src/dird/ua_server.c @@ -95,7 +95,7 @@ static void *connect_thread(void *arg) * Create a Job Control Record for a control "job", * filling in all the appropriate fields. */ -JCR *create_control_jcr(char *base_name, int job_type) +JCR *new_control_jcr(char *base_name, int job_type) { JCR *jcr; jcr = new_jcr(sizeof(JCR), dird_free_jcr); @@ -105,7 +105,9 @@ JCR *create_control_jcr(char *base_name, int job_type) jcr->JobType = job_type; jcr->JobLevel = L_FULL; jcr->JobStatus = JS_Running; - /* None of these are really defined for control JCRs, so we + jcr->JobId = 0; + /* + * None of these are really defined for control JCRs, so we * simply take the first of each one. This ensures that there * will be no null pointer references. */ @@ -134,7 +136,7 @@ static void *handle_UA_client_request(void *arg) pthread_detach(pthread_self()); - jcr = create_control_jcr("*Console*", JT_CONSOLE); + jcr = new_control_jcr("*Console*", JT_CONSOLE); ua = new_ua_context(jcr); ua->UA_sock = UA_sock; diff --git a/bacula/src/filed/win32/winmain.cpp b/bacula/src/filed/win32/winmain.cpp index 1b50502c3a..d1967905f4 100755 --- a/bacula/src/filed/win32/winmain.cpp +++ b/bacula/src/filed/win32/winmain.cpp @@ -149,7 +149,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, szCmdLine[i] = tolower(szCmdLine[i]); } - BOOL argfound = FALSE; + bool argfound = false; for (i = 0; i < (int)strlen(szCmdLine); i++) { if (szCmdLine[i] <= ' ') { continue; @@ -162,94 +162,74 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, continue; } - argfound = TRUE; + argfound = true; - // Now check for command-line arguments + /* Now check for command-line arguments */ - // /servicehelper - // Used on NT to connect to Bacula - if (strncmp(&szCmdLine[i], BaculaRunServiceHelper, strlen(BaculaRunServiceHelper)) == 0) { - // NB : This flag MUST be parsed BEFORE "-service", otherwise it will match - // the wrong option! (This code should really be replaced with a simple - // parser machine and parse-table...) - - // Run the Bacula Service Helper app - bacService::PostUserHelperMessage(); - return 0; - } - // /service + /* /service start service */ if (strncmp(&szCmdLine[i], BaculaRunService, strlen(BaculaRunService)) == 0) { - // Run Bacula as a service + /* Run Bacula as a service */ return bacService::BaculaServiceMain(); } - // /run (this is the default if no command line arguments) + /* /run (this is the default if no command line arguments) */ if (strncmp(&szCmdLine[i], BaculaRunAsUserApp, strlen(BaculaRunAsUserApp)) == 0) { - // Bacula is being run as a user-level program + /* Bacula is being run as a user-level program */ return BaculaAppMain(); } - // /install + /* /install */ if (strncmp(&szCmdLine[i], BaculaInstallService, strlen(BaculaInstallService)) == 0) { - // Install Bacula as a service + /* Install Bacula as a service */ bacService::InstallService(); - i+=strlen(BaculaInstallService); + i += strlen(BaculaInstallService); continue; } - // /remove + /* /remove */ if (strncmp(&szCmdLine[i], BaculaRemoveService, strlen(BaculaRemoveService)) == 0) { - // Remove the Bacula service + /* Remove the Bacula service */ bacService::RemoveService(); - i+=strlen(BaculaRemoveService); + i += strlen(BaculaRemoveService); continue; } - // /about + /* /about */ if (strncmp(&szCmdLine[i], BaculaShowAbout, strlen(BaculaShowAbout)) == 0) { - // Show the About dialog of an existing instance of Bacula + /* Show Bacula's about box */ bacService::ShowAboutBox(); - i+=strlen(BaculaShowAbout); + i += strlen(BaculaShowAbout); continue; } - // /status + /* /status */ if (strncmp(&szCmdLine[i], BaculaShowStatus, strlen(BaculaShowStatus)) == 0) { - // Show the Status dialog of an existing instance of Bacula + /* Show Bacula's status box */ bacService::ShowStatus(); - i+=strlen(BaculaShowStatus); - continue; - } - - // /events - if (strncmp(&szCmdLine[i], BaculaShowEvents, strlen(BaculaShowEvents)) == 0) { - // Show the Events dialog of an existing instance of Bacula - bacService::ShowEvents(); - i+=strlen(BaculaShowEvents); + i += strlen(BaculaShowStatus); continue; } - - // /kill + /* /kill */ if (strncmp(&szCmdLine[i], BaculaKillRunningCopy, strlen(BaculaKillRunningCopy)) == 0) { - // Kill any already running copy of Bacula + /* Kill running copy of Bacula */ bacService::KillRunningCopy(); - i+=strlen(BaculaKillRunningCopy); + i += strlen(BaculaKillRunningCopy); continue; } - // /help + /* /help */ if (strncmp(&szCmdLine[i], BaculaShowHelp, strlen(BaculaShowHelp)) == 0) { - MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION); - i+=strlen(BaculaShowHelp); + MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK|MB_ICONINFORMATION); + i += strlen(BaculaShowHelp); continue; } MessageBox(NULL, szCmdLine, "Bad Command Line Options", MB_OK); - // Show the usage dialog + /* Show the usage dialog */ MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION); break; } - // If no arguments were given then just run + /* If no arguments were given then just run */ if (!argfound) { BaculaAppMain(); } @@ -275,7 +255,7 @@ void *Main_Msg_Loop(LPVOID lpwThreadParam) */ g_servicethread = GetCurrentThreadId(); - // Create tray icon & menu if we're running as an app + /* Create tray icon & menu if we're running as an app */ bacMenu *menu = new bacMenu(); if (menu == NULL) { // log_error_message("Could not create sys tray menu"); @@ -283,7 +263,7 @@ void *Main_Msg_Loop(LPVOID lpwThreadParam) } - // Now enter the Windows message handling loop until told to quit! + /* Now enter the Windows message handling loop until told to quit! */ MSG msg; while (GetMessage(&msg, NULL, 0,0) ) { TranslateMessage(&msg); @@ -295,12 +275,13 @@ void *Main_Msg_Loop(LPVOID lpwThreadParam) } if (old_servicethread != 0) { /* started as NT service */ - // Mark that we're no longer running + /* Mark that we're no longer running */ g_servicethread = 0; - // Tell the service manager that we've stopped. + /* Tell the service manager that we've stopped. */ ReportStatus(SERVICE_STOPPED, g_error, 0); } + /* Tell main program to go away */ terminate_filed(0); /* Should not get here */ @@ -319,7 +300,7 @@ void *Main_Msg_Loop(LPVOID lpwThreadParam) */ int BaculaAppMain() { -// DWORD dwThreadID; +/* DWORD dwThreadID; */ pthread_t tid; #ifdef HAVE_WIN32 WSA_Init(); @@ -355,23 +336,23 @@ int BaculaAppMain() p_BackupWrite = NULL; } - // Set this process to be the last application to be shut down. + /* Set this process to be the last application to be shut down. */ if (p_SetProcessShutdownParameters) { p_SetProcessShutdownParameters(0x100, 0); } HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL); if (hservwnd != NULL) { - // We don't allow multiple instances! + /* We don't allow multiple instances! */ MessageBox(NULL, "Another instance of Bacula is already running", szAppName, MB_OK); _exit(0); } - // Create a thread to handle the Windows messages + /* Create a thread to handle the Windows messages */ // (void)CreateThread(NULL, 0, Main_Msg_Loop, NULL, 0, &dwThreadID); pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0); - // Call the "real" Bacula + /* Call the "real" Bacula */ BaculaMain(num_command_args, command_args); PostQuitMessage(0); _exit(0); diff --git a/bacula/src/filed/win32/winservice.cpp b/bacula/src/filed/win32/winservice.cpp index 3492da70e6..2bac945a27 100755 --- a/bacula/src/filed/win32/winservice.cpp +++ b/bacula/src/filed/win32/winservice.cpp @@ -54,7 +54,6 @@ void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService, bacService init; DWORD g_platform_id; -BOOL g_impersonating_user = 0; bacService::bacService() { @@ -67,14 +66,6 @@ bacService::bacService() } else { g_platform_id = osversioninfo.dwPlatformId; } -#ifdef xxx - /* Rewritten to lookup entry point */ - if (osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && - osversioninfo.dwMinorVersion == 0) { - /* Running Win95 so no GetFileAttributesEx available */ - NoGetFileAttributesEx = 1; - } -#endif } @@ -156,6 +147,7 @@ bacService::ShowStatus() return TRUE; } +#ifdef xxx_needed // Static routine to show the Events dialog for a currently-running // copy of Bacula, (usually a servicified version.) @@ -185,6 +177,7 @@ bacService::PostAddNewClient(unsigned long ipaddress) return TRUE; } +#endif // SERVICE-MODE ROUTINES @@ -237,6 +230,7 @@ bacService::KillRunningCopy() return TRUE; } +#ifdef xxx_needed // ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING Bacula, IN ORDER // THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER @@ -267,6 +261,8 @@ bacService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam) { return TRUE; } +#endif + // SERVICE MAIN ROUTINE int bacService::BaculaServiceMain() diff --git a/bacula/src/filed/win32/wintray.cpp b/bacula/src/filed/win32/wintray.cpp index c8842da97e..933e613573 100755 --- a/bacula/src/filed/win32/wintray.cpp +++ b/bacula/src/filed/win32/wintray.cpp @@ -54,6 +54,7 @@ const UINT MENU_SERVICEHELPER_MSG = RegisterWindowMessage("Bacula.ServiceHelper. const UINT MENU_ADD_CLIENT_MSG = RegisterWindowMessage("Bacula.AddClient.Message"); const char *MENU_CLASS_NAME = "Bacula Tray Icon"; +extern void terminate_filed(int sig); extern char *bac_status(int stat); extern int bacstat; @@ -187,182 +188,186 @@ bacMenu::SendTrayMsg(DWORD msg, int bacstat) // Process window messages LRESULT CALLBACK bacMenu::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { - // This is a static method, so we don't know which instantiation we're - // dealing with. We use Allen Hadden's (ahadden@taratec.com) suggestion - // from a newsgroup to get the pseudo-this. - bacMenu *_this = (bacMenu *) GetWindowLong(hwnd, GWL_USERDATA); - - switch (iMsg) - { - - // Every five seconds, a timer message causes the icon to update - case WM_TIMER: - // *** HACK for running servicified - if (bacService::RunningAsService()) { - // Attempt to add the icon if it's not already there - _this->AddTrayIcon(); - // Trigger a check of the current user - PostMessage(hwnd, WM_USERCHANGED, 0, 0); - } - - // Update the icon - _this->UpdateTrayIcon(bacstat); - break; - - // DEAL WITH NOTIFICATIONS FROM THE SERVER: - case WM_SRV_CLIENT_AUTHENTICATED: - case WM_SRV_CLIENT_DISCONNECT: - // Adjust the icon accordingly - _this->UpdateTrayIcon(bacstat); - return 0; - - // STANDARD MESSAGE HANDLING - case WM_CREATE: - return 0; - - case WM_COMMAND: - // User has clicked an item on the tray menu - switch (LOWORD(wParam)) - { - case ID_STATUS: - // Show the status dialog - _this->m_status.Show(TRUE); - _this->UpdateTrayIcon(bacstat); - break; - - case ID_EVENTS: - // Show the Events dialog - _this->m_events.Show(TRUE); - _this->UpdateTrayIcon(bacstat); - break; - - - case ID_KILLCLIENTS: - // Disconnect all currently connected clients - break; - - case ID_ABOUT: - // Show the About box - _this->m_about.Show(TRUE); - break; - - case ID_CLOSE: - // User selected Close from the tray menu - PostMessage(hwnd, WM_CLOSE, 0, 0); - break; - - } - return 0; - - case WM_TRAYNOTIFY: - // User has clicked on the tray icon or the menu - { - // Get the submenu to use as a pop-up menu - HMENU submenu = GetSubMenu(_this->m_hmenu, 0); - - // What event are we responding to, RMB click? - if (lParam==WM_RBUTTONUP) { - if (submenu == NULL) { - return 0; - } - - // Make the first menu item the default (bold font) - SetMenuDefaultItem(submenu, 0, TRUE); - - // Get the current cursor position, to display the menu at - POINT mouse; - GetCursorPos(&mouse); - - // There's a "bug" - // (Microsoft calls it a feature) in Windows 95 that requires calling - // SetForegroundWindow. To find out more, search for Q135788 in MSDN. - // - SetForegroundWindow(_this->m_nid.hWnd); - - // Display the menu at the desired position - TrackPopupMenu(submenu, - 0, mouse.x, mouse.y, 0, - _this->m_nid.hWnd, NULL); - - return 0; - } - - // Or was there a LMB double click? - if (lParam==WM_LBUTTONDBLCLK) { - // double click: execute first menu item - SendMessage(_this->m_nid.hWnd, - WM_COMMAND, - GetMenuItemID(submenu, 0), - 0); - } - - return 0; - } - - case WM_CLOSE: - break; - - case WM_DESTROY: - // The user wants Bacula to quit cleanly... - PostQuitMessage(0); - return 0; - - case WM_QUERYENDSESSION: - // Are we running as a system service? - // Or is the system shutting down (in which case we should check anyway!) - if ((!bacService::RunningAsService()) || (lParam == 0)) { - // No, so we are about to be killed - - // If there are remote connections then we should verify - // that the user is happy about killing them. - - // Finally, post a quit message, just in case - PostQuitMessage(0); - return TRUE; - } - - // Tell the OS that we've handled it anyway -// PostQuitMessage(0); - return TRUE; + // This is a static method, so we don't know which instantiation we're + // dealing with. We use Allen Hadden's (ahadden@taratec.com) suggestion + // from a newsgroup to get the pseudo-this. + bacMenu *_this = (bacMenu *) GetWindowLong(hwnd, GWL_USERDATA); + + switch (iMsg) { + + // Every five seconds, a timer message causes the icon to update + case WM_TIMER: + // *** HACK for running servicified + if (bacService::RunningAsService()) { + // Attempt to add the icon if it's not already there + _this->AddTrayIcon(); + // Trigger a check of the current user +// PostMessage(hwnd, WM_USERCHANGED, 0, 0); + } - - default: - if (iMsg == MENU_ABOUTBOX_SHOW) { - // External request to show our About dialog - PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_ABOUT, 0), 0); - return 0; - } - if (iMsg == MENU_STATUS_SHOW) { - // External request to show our status - PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_STATUS, 0), 0); - return 0; - } - - if (iMsg == MENU_EVENTS_SHOW) { - // External request to show our Events dialogue - PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_EVENTS, 0), 0); - return 0; - } - - if (iMsg == MENU_SERVICEHELPER_MSG) { - // External ServiceHelper message. - // This message holds a process id which we can use to - // impersonate a specific user. In doing so, we can load their - // preferences correctly - bacService::ProcessUserHelperMessage(wParam, lParam); - - // - Trigger a check of the current user - PostMessage(hwnd, WM_USERCHANGED, 0, 0); - return 0; - } - if (iMsg == MENU_ADD_CLIENT_MSG) { - // Add Client message. This message includes an IP address - // of a listening client, to which we should connect. - - return 0; - } - } - - // Message not recognised - return DefWindowProc(hwnd, iMsg, wParam, lParam); + // Update the icon + _this->UpdateTrayIcon(bacstat); + break; + +#ifdef xxx_needed + + // DEAL WITH NOTIFICATIONS FROM THE SERVER: + case WM_SRV_CLIENT_AUTHENTICATED: + case WM_SRV_CLIENT_DISCONNECT: + // Adjust the icon accordingly + _this->UpdateTrayIcon(bacstat); + return 0; +#endif + + // STANDARD MESSAGE HANDLING + case WM_CREATE: + return 0; + + case WM_COMMAND: + // User has clicked an item on the tray menu + switch (LOWORD(wParam)) { + case ID_STATUS: + // Show the status dialog + _this->m_status.Show(TRUE); + _this->UpdateTrayIcon(bacstat); + break; + + case ID_EVENTS: + // Show the Events dialog + _this->m_events.Show(TRUE); + _this->UpdateTrayIcon(bacstat); + break; + + + case ID_KILLCLIENTS: + // Disconnect all currently connected clients + break; + + case ID_ABOUT: + // Show the About box + _this->m_about.Show(TRUE); + break; + + case ID_CLOSE: + // User selected Close from the tray menu + PostMessage(hwnd, WM_CLOSE, 0, 0); + break; + + } + return 0; + + case WM_TRAYNOTIFY: + // User has clicked on the tray icon or the menu + { + // Get the submenu to use as a pop-up menu + HMENU submenu = GetSubMenu(_this->m_hmenu, 0); + + // What event are we responding to, RMB click? + if (lParam==WM_RBUTTONUP) { + if (submenu == NULL) { + return 0; + } + + // Make the first menu item the default (bold font) + SetMenuDefaultItem(submenu, 0, TRUE); + + // Get the current cursor position, to display the menu at + POINT mouse; + GetCursorPos(&mouse); + + // There's a "bug" + // (Microsoft calls it a feature) in Windows 95 that requires calling + // SetForegroundWindow. To find out more, search for Q135788 in MSDN. + // + SetForegroundWindow(_this->m_nid.hWnd); + + // Display the menu at the desired position + TrackPopupMenu(submenu, + 0, mouse.x, mouse.y, 0, + _this->m_nid.hWnd, NULL); + + return 0; + } + + // Or was there a LMB double click? + if (lParam==WM_LBUTTONDBLCLK) { + // double click: execute first menu item + SendMessage(_this->m_nid.hWnd, + WM_COMMAND, + GetMenuItemID(submenu, 0), + 0); + } + + return 0; + } + + case WM_CLOSE: + terminate_filed(0); + break; + + case WM_DESTROY: + // The user wants Bacula to quit cleanly... + PostQuitMessage(0); + return 0; + + case WM_QUERYENDSESSION: + // Are we running as a system service? + // Or is the system shutting down (in which case we should check anyway!) + if ((!bacService::RunningAsService()) || (lParam == 0)) { + // No, so we are about to be killed + + // If there are remote connections then we should verify + // that the user is happy about killing them. + + // Finally, post a quit message, just in case + PostQuitMessage(0); + return TRUE; + } + + // Tell the OS that we've handled it anyway +// PostQuitMessage(0); + return TRUE; + + + default: + if (iMsg == MENU_ABOUTBOX_SHOW) { + // External request to show our About dialog + PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_ABOUT, 0), 0); + return 0; + } + if (iMsg == MENU_STATUS_SHOW) { + // External request to show our status + PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_STATUS, 0), 0); + return 0; + } + +#ifdef xxx_needed + if (iMsg == MENU_EVENTS_SHOW) { + // External request to show our Events dialogue + PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_EVENTS, 0), 0); + return 0; + } + + if (iMsg == MENU_SERVICEHELPER_MSG) { + // External ServiceHelper message. + // This message holds a process id which we can use to + // impersonate a specific user. In doing so, we can load their + // preferences correctly + bacService::ProcessUserHelperMessage(wParam, lParam); + + // - Trigger a check of the current user + PostMessage(hwnd, WM_USERCHANGED, 0, 0); + return 0; + } + if (iMsg == MENU_ADD_CLIENT_MSG) { + // Add Client message. This message includes an IP address + // of a listening client, to which we should connect. + + return 0; + } +#endif + } + + // Message not recognised + return DefWindowProc(hwnd, iMsg, wParam, lParam); } diff --git a/bacula/src/gnome2-console/Makefile.in b/bacula/src/gnome2-console/Makefile.in index 1977f1cc18..1cb408db63 100644 --- a/bacula/src/gnome2-console/Makefile.in +++ b/bacula/src/gnome2-console/Makefile.in @@ -87,7 +87,7 @@ distclean: realclean (cd $(srcdir); $(RMF) Makefile; $(RMF) -r CVS) install: all - $(INSTALL_SCRIPT) gnome-console $(DESTDIR)$(sbindir)/gnome-console + $(INSTALL_PROGRAM) gnome-console $(DESTDIR)$(sbindir)/gnome-console @srcconf=gnome-console.conf; \ if test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \ destconf=$$srcconf.new; \ @@ -98,7 +98,7 @@ install: all echo "${INSTALL_CONFIG} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \ ${INSTALL_CONFIG} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf if test -f static-gnome-console; then \ - $(INSTALL_SCRIPT) static-gnome-console $(DESTDIR)$(sbindir)/static-gnome-console; \ + $(INSTALL_PROGRAM) static-gnome-console $(DESTDIR)$(sbindir)/static-gnome-console; \ fi uninstall: diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 185f461015..a9641222f3 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -132,6 +132,7 @@ struct JCR { uint32_t ClientId; /* Client associated with Job */ char *where; /* prefix to restore files to */ bool prefix_links; /* Prefix links with Where path */ + bool gui; /* set if gui using console */ int cached_pnl; /* cached path length */ POOLMEM *cached_path; /* cached path */ diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c index 62d2f6c131..93dc42108a 100755 --- a/bacula/src/lib/jcr.c +++ b/bacula/src/lib/jcr.c @@ -197,6 +197,7 @@ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr) jcr->errmsg = get_pool_memory(PM_MESSAGE); jcr->errmsg[0] = 0; strcpy(jcr->Job, "*Console*"); /* default */ + jcr->JobId = UINT32_MAX; /* temp non-zero JobId */ sigtimer.sa_flags = 0; sigtimer.sa_handler = timeout_handler; diff --git a/bacula/src/lib/signal.c b/bacula/src/lib/signal.c index 3d7d2d1f2b..aba1640035 100644 --- a/bacula/src/lib/signal.c +++ b/bacula/src/lib/signal.c @@ -95,16 +95,15 @@ static void signal_handler(int sig) exename, my_name, sig); if (exelen + 12 > (int)sizeof(btpath)) { - strcpy(btpath, "btraceback"); + bstrncpy(btpath, "btraceback", sizeof(btpath)); } else { - strcpy(btpath, exepath); - if (btpath[exelen-1] != '/') { - strcat(btpath, "/btraceback"); - } else { - strcat(btpath, "btraceback"); + bstrncpy(btpath, exepath, sizeof(btpath)); + if (btpath[exelen-1] == '/') { + btpath[exelen-1] = 0; } + bstrncat(btpath, "/btraceback", sizeof(btpath)); } - if (btpath[exelen-1] != '/') { + if (exepath[exelen-1] != '/') { strcat(exepath, "/"); } strcat(exepath, exename); -- 2.39.5