2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2018 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
26 #include "fd_plugins.h"
27 #include "lib/mem_pool.h"
30 extern int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc,
31 char **argk, char **argv, int max_args);
32 #define Dmsg(context, level, message, ...) bfuncs->DebugMessage(context, __FILE__, __LINE__, level, message, ##__VA_ARGS__)
38 #define PLUGIN_LICENSE "Bacula"
39 #define PLUGIN_AUTHOR "Eric Bollengier"
40 #define PLUGIN_DATE "Oct 2013"
41 #define PLUGIN_VERSION "1.2"
42 #define PLUGIN_DESCRIPTION "Select all local drives"
44 /* Forward referenced functions */
45 static bRC newPlugin(bpContext *ctx);
46 static bRC freePlugin(bpContext *ctx);
47 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
48 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
49 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
50 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
51 static bRC endBackupFile(bpContext *ctx);
52 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
53 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
54 static bRC endRestoreFile(bpContext *ctx);
55 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
56 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
59 /* Pointers to Bacula functions */
60 static bFuncs *bfuncs = NULL;
61 static bInfo *binfo = NULL;
63 static pInfo pluginInfo = {
65 FD_PLUGIN_INTERFACE_VERSION,
74 static pFuncs pluginFuncs = {
76 FD_PLUGIN_INTERFACE_VERSION,
78 /* Entry points into plugin */
79 newPlugin, /* new plugin instance */
80 freePlugin, /* free plugin instance */
91 NULL, /* No checkFiles */
92 NULL /* No ACL/XATTR */
96 * Plugin called here when it is first loaded
99 loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
101 bfuncs = lbfuncs; /* set Bacula funct pointers */
104 *pinfo = &pluginInfo; /* return pointer to our info */
105 *pfuncs = &pluginFuncs; /* return pointer to our functions */
111 * Plugin called here when it is unloaded, normally when
112 * Bacula is going to exit.
120 #define get_self(ctx) ((barg *)ctx->pContext)
126 char *argk[MAX_CMD_ARGS]; /* Argument keywords */
127 char *argv[MAX_CMD_ARGS]; /* Argument values */
136 snapshot_only = false;
140 free_and_null_pool_memory(args);
141 free_and_null_pool_memory(cmd);
145 * Given a single keyword, find it in the argument list, but
146 * it must have a value
147 * Returns: -1 if not found or no value
148 * list index (base 0) on success
150 int find_arg_with_value(const char *keyword)
152 for (int i=0; i<argc; i++) {
153 if (strcasecmp(keyword, argk[i]) == 0) {
164 /* parse command line
165 * search for exclude="A,B,C,D"
166 * populate this->exclude with simple string "ABCD"
168 void parse(char *command) {
171 if ((p = strchr(command, ':')) == NULL) {
172 Dmsg(NULL, 10, "No options\n");
176 args = get_pool_memory(PM_FNAME);
177 cmd = get_pool_memory(PM_FNAME);
179 pm_strcpy(cmd, ++p); /* copy string after : */
180 parse_args(cmd, &args, &argc, argk, argv, MAX_CMD_ARGS);
182 for (int i=0; i < argc ; i++) {
183 if (strcmp(argk[i], "exclude") == 0) {
184 /* a,B,C d => ABCD */
185 q = p = exclude = argv[i];
187 if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) {
193 Dmsg(NULL, 50, "%s => %s\n", command, exclude);
195 } else if (strcmp(argk[i], "snapshot") == 0) {
196 Dmsg(NULL, 50, "Doing only snapshot\n");
197 snapshot_only = true;
200 Dmsg(NULL, 10, "Unknown keyword %s\n", argk[i]);
207 * Called here to make a new instance of the plugin -- i.e. when
208 * a new Job is started. There can be multiple instances of
209 * each plugin that are running at the same time. Your
210 * plugin instance must be thread safe and keep its own
213 static bRC newPlugin(bpContext *ctx)
215 barg *self = new barg();
216 ctx->pContext = (void *)self; /* set our context pointer */
221 * Release everything concerning a particular instance of a
222 * plugin. Normally called when the Job terminates.
224 static bRC freePlugin(bpContext *ctx)
226 barg *self = get_self(ctx);
234 * Called by core code to get a variable from the plugin.
235 * Not currently used.
237 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value)
239 // printf("plugin: getPluginValue var=%d\n", var);
244 * Called by core code to set a plugin variable.
245 * Not currently used.
247 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
249 // printf("plugin: setPluginValue var=%d\n", var);
253 /* TODO: use findlib/drivetype instead */
254 static bool drivetype(const char *fname, char *dt, int dtlen)
259 /* Copy Drive Letter, colon, and backslash to rootpath */
260 bstrncpy(rootpath, fname, 3);
263 type = GetDriveType(rootpath);
266 case DRIVE_REMOVABLE: bstrncpy(dt, "removable", dtlen); return true;
267 case DRIVE_FIXED: bstrncpy(dt, "fixed", dtlen); return true;
268 case DRIVE_REMOTE: bstrncpy(dt, "remote", dtlen); return true;
269 case DRIVE_CDROM: bstrncpy(dt, "cdrom", dtlen); return true;
270 case DRIVE_RAMDISK: bstrncpy(dt, "ramdisk", dtlen); return true;
272 case DRIVE_NO_ROOT_DIR:
278 static void add_drives(bpContext *ctx, char *cmd)
283 barg *arg = get_self(ctx);
286 if (arg->snapshot_only) {
290 for (drive = 'A'; drive <= 'Z'; drive++) {
291 if (arg->exclude && strchr(arg->exclude, drive)) {
292 Dmsg(ctx, 10, "%c is in exclude list\n", drive);
295 snprintf(buf, sizeof(buf), "%c:/", drive);
296 if (drivetype(buf, dt, sizeof(dt))) {
297 if (strcmp(dt, "fixed") == 0) {
298 Dmsg(ctx, 10, "Adding %c to include list\n", drive);
299 bfuncs->AddInclude(ctx, buf);
300 snprintf(buf, sizeof(buf), "%c:/pagefile.sys", drive);
301 bfuncs->AddExclude(ctx, buf);
302 snprintf(buf, sizeof(buf), "%c:/System Volume Information", drive);
303 bfuncs->AddExclude(ctx, buf);
305 Dmsg(ctx, 10, "Discarding %c from include list\n", drive);
311 static void add_snapshot(bpContext *ctx, char *ret)
317 barg *arg = get_self(ctx);
319 /* Start from blank */
322 if (!arg->snapshot_only) {
326 for (drive = 'A'; drive <= 'Z'; drive++) {
327 if (arg->exclude && strchr(arg->exclude, drive)) {
328 Dmsg(ctx, 10, "%c is in exclude list\n", drive);
332 snprintf(buf, sizeof(buf), "%c:/", drive);
334 if (drivetype(buf, dt, sizeof(dt))) {
335 if (strcmp(dt, "fixed") == 0) {
336 Dmsg(ctx, 10, "Adding %c to snapshot list\n", drive);
339 Dmsg(ctx, 10, "Discarding %c from snapshot list\n", drive);
344 Dmsg(ctx, 10, "ret = %s\n", ret);
348 * Called by Bacula when there are certain events that the
349 * plugin might want to know. The value depends on the
352 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
356 switch (event->eventType) {
357 case bEventPluginCommand:
358 add_drives(ctx, (char *)value); /* command line */
361 case bEventVssPrepareSnapshot:
362 add_snapshot(ctx, (char *)value); /* snapshot list */
372 * Called when starting to backup a file. Here the plugin must
373 * return the "stat" packet for the directory/file and provide
374 * certain information so that Bacula knows what the file is.
375 * The plugin can create "Virtual" files by giving them a
376 * name that is not normally found on the file system.
378 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
384 * Done backing up a file.
386 static bRC endBackupFile(bpContext *ctx)
392 * Do actual I/O. Bacula calls this after startBackupFile
393 * or after startRestoreFile to do the actual file
396 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
403 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
408 static bRC endRestoreFile(bpContext *ctx)
414 * Called here to give the plugin the information needed to
415 * re-create the file on a restore. It basically gets the
416 * stat packet that was created during the backup phase.
417 * This data is what is needed to create the file, but does
418 * not contain actual file data.
420 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
426 * Called after the file has been restored. This can be used to
427 * set directory permissions, ...
429 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)