From: Radosław Korzeniewski Date: Thu, 4 Nov 2021 13:59:52 +0000 (+0100) Subject: pluginlib: Metaplugin - add symbolic link support for external STAT command. X-Git-Tag: Beta-15.0.0~778 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e735c7800090e9f5dd84e29e3af265e70c595092;p=thirdparty%2Fbacula.git pluginlib: Metaplugin - add symbolic link support for external STAT command. --- diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin.cpp index 12253ccdb..46ebad105 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin.cpp +++ b/bacula/src/plugins/fd/pluginlib/metaplugin.cpp @@ -897,13 +897,6 @@ bRC METAPLUGIN::send_startjob(bpContext *ctx, const char *command) return bRC_Error; } - // if (!backend.ctx->read_ack(ctx)){ - // strip_trailing_newline(cmd.c_str()); - // DMSG(ctx, DERROR, "Wrong backend response to %s command.\n", cmd.c_str()); - // JMSG(ctx, backend.ctx->jmsg_err_level(), "Wrong backend response to %s command.\n", cmd.c_str()); - // return bRC_Error; - // } - int32_t status; while ((status = backend.ctx->read_command(ctx, cmd)) != 0) { @@ -1765,13 +1758,13 @@ bRC METAPLUGIN::perform_read_metacommands(bpContext *ctx) if (scan_parameter_str(cmd, "CHECK:", fname)) { /* got accurate check query */ - metaplugin::accurate::perform_accurate_check(ctx, backend.ctx, fname, accurate_mode, accurate_mode_err); + metaplugin::accurate::perform_accurate_check(ctx, backend.ctx, fname, lname, accurate_mode, accurate_mode_err); continue; } if (scan_parameter_str(cmd, "CHECKGET:", fname)) { /* got accurate get query */ - metaplugin::accurate::perform_accurate_check_get(ctx, backend.ctx, fname, accurate_mode, accurate_mode_err); + metaplugin::accurate::perform_accurate_check_get(ctx, backend.ctx, fname, lname, accurate_mode, accurate_mode_err); continue; } if (scan_parameter_str(cmd, "ACCEPT:", fname)) @@ -1929,7 +1922,7 @@ bRC METAPLUGIN::perform_accept_file(bpContext *ctx) struct save_pkt sp; memset(&sp, 0, sizeof(sp)); - metaplugin::attributes::Status status = metaplugin::attributes::read_attributes_command(ctx, backend.ctx, cmd, &sp); + metaplugin::attributes::Status status = metaplugin::attributes::read_attributes_command(ctx, backend.ctx, cmd, &sp, lname); switch(status) { case metaplugin::attributes::Invalid_File_Type: @@ -2329,9 +2322,13 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp) while (backend.ctx->read_command(ctx, cmd) > 0) { DMSG(ctx, DINFO, "read_command(2): %s\n", cmd.c_str()); - metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, sp); + + metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, sp, lname); switch (status) { + case metaplugin::attributes::Status_Error: + return bRC_Error; + case metaplugin::attributes::Invalid_File_Type: JMSG2(ctx, M_ERROR, "Invalid file type: %c for %s\n", sp->type, fname.c_str()); return bRC_Error; @@ -2345,12 +2342,15 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp) reqparams--; } continue; + case metaplugin::attributes::Status_Handled: reqparams--; continue; + default: break; } + status = metaplugin::attributes::read_scan_tstamp_command(ctx, cmd, sp); switch (status) { @@ -2359,12 +2359,15 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp) default: break; } - if (scan_parameter_str(cmd, "LSTAT:", lname) == 1) { + + if (scan_parameter_str(cmd, "LSTAT:", lname) == 1) + { sp->link = lname.c_str(); reqparams--; DMSG(ctx, DINFO, "LSTAT:%s\n", lname.c_str()); continue; } + POOL_MEM tmp(PM_FNAME); if (scan_parameter_str(cmd, "PIPE:", tmp)) { /* handle PIPE command */ diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.cpp index 2b7e008df..bf44aa705 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.cpp +++ b/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.cpp @@ -53,7 +53,7 @@ namespace accurate * @param accurate_mode_err when accurate mode error handled * @return bRC bRC_OK when success, bRC_Error if not */ - bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err) + bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err) { if (strlen(fname.c_str()) == 0){ // input variable is not valid @@ -72,7 +72,7 @@ namespace accurate return bRC_Error; } - metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, &sp); + metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, &sp, lname); if (status == metaplugin::attributes::Status_OK) { if (ptcomm->read_command(ctx, cmd) < 0) { // error @@ -137,7 +137,7 @@ namespace accurate * @param accurate_mode_err when accurate mode error handled * @return bRC bRC_OK when success, bRC_Error if not */ - bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err) + bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err) { POOL_MEM cmd(PM_FNAME); diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.h b/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.h index 6399db0c4..81187698c 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.h +++ b/bacula/src/plugins/fd/pluginlib/metaplugin_accurate.h @@ -37,8 +37,8 @@ namespace metaplugin { namespace accurate { - bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err); - bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err); + bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err); + bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err); } // namespace accurate } // namespace metaplugin diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.cpp index a5e4579cb..d19c49544 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.cpp +++ b/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.cpp @@ -51,7 +51,7 @@ namespace attributes * Status_Handled when data managed and TSTAMP command is not required * Not_Command when it was not this command */ - Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp) + Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname) { char type; size_t size; @@ -67,7 +67,7 @@ namespace attributes // handle stat(2) for this file scan_parameter_str(cmd, "STAT:", param); DMSG1(ctx, DDEBUG, "read_scan_stat_command():stat:%s\n", param.c_str()); - int rc = stat(param.c_str(), &sp->statp); + int rc = lstat(param.c_str(), &sp->statp); if (rc < 0) { // error @@ -85,6 +85,23 @@ namespace attributes case S_IFREG: sp->type = FT_REG; break; + case S_IFLNK: + { + sp->type = FT_LNK; + ssize_t rc = readlink(param.c_str(), lname.c_str(), lname.size()); + if (rc < 0) + { + berrno be; + // error reading link value + DMSG2(ctx, DERROR, "Error reading link value. Err=%s (%d)", be.bstrerror(), be.code()); + JMSG3(ctx, M_ERROR, "Error reading link value: %s, Err=%s (%d)", param.c_str(), be.bstrerror(), be.code()); + return Status_Error; + } + lname.c_str()[rc] = '\0'; + sp->link = lname.c_str(); + DMSG1(ctx, DDEBUG, "read_scan_stat_command():readlink:%s\n", sp->link); + } + break; default: DMSG1(ctx, DERROR, "Unsupported file type: %o\n", sp->statp.st_mode & S_IFMT); return Invalid_Stat_Packet; @@ -246,7 +263,7 @@ namespace attributes * @param sp save packet to fill when file attributes handled * @return Status Status_OK when file attributes commands handled, Status_Error on any error, other depends on enum. */ - Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp) + Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname) { DMSG0(ctx, DDEBUG, "read_attributes_command()\n"); @@ -256,7 +273,7 @@ namespace attributes return Status_Error; } - Status status = read_scan_stat_command(ctx, cmd, sp); + Status status = read_scan_stat_command(ctx, cmd, sp, lname); switch(status) { case Status_OK: diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.h b/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.h index a2fc77038..93de0a1d5 100644 --- a/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.h +++ b/bacula/src/plugins/fd/pluginlib/metaplugin_attributes.h @@ -47,11 +47,11 @@ namespace attributes Status_Error, } Status; - Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp); + Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname); Status make_stat_command(bpContext *ctx, POOL_MEM &cmd, const restore_pkt *rp); Status read_scan_tstamp_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp); Status make_tstamp_command(bpContext *ctx, POOL_MEM &cmd, const restore_pkt *rp); - Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp); + Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname); } // attributes } // metaplugin diff --git a/bacula/src/plugins/fd/pluginlib/test_metaplugin_backend.c b/bacula/src/plugins/fd/pluginlib/test_metaplugin_backend.c index 31ebf58d1..a888e150c 100644 --- a/bacula/src/plugins/fd/pluginlib/test_metaplugin_backend.c +++ b/bacula/src/plugins/fd/pluginlib/test_metaplugin_backend.c @@ -54,8 +54,9 @@ extern const char *PLUGINNAME; int logfd; pid_t mypid; -char * buf; -char * buflog; +char *buf; +char *buflog; +char symlink_fname[32]; bool regress_error_plugin_params = false; bool regress_error_start_job = false; @@ -1183,6 +1184,27 @@ void perform_backup() signal_eod(); write_plugin('I', "TEST18Data"); + // now test `STAT:/path/to/file` using symbolic link + snprintf(symlink_fname, 32, "/tmp/passwd.%d", mypid); + symlink("/etc/passwd", symlink_fname); + + // the file with external stat(2) packet + snprintf(buf, BIGBUFLEN, "FNAME:%s/java/%d/stat.symlink\n", PLUGINPREFIX, mypid); + write_plugin('C', buf); + snprintf(buf, BIGBUFLEN, "STAT:%s\n", symlink_fname); + write_plugin('C', buf); + write_plugin('I', "TEST18S"); + signal_eod(); + // here comes a file data contents + write_plugin('C', "DATA\n"); + write_plugin('D', "/* here comes a file data contents */"); + write_plugin('D', "/* here comes another file line */"); + write_plugin('D', "/* here comes another file line */"); + write_plugin('D', "/* here comes another file line */"); + write_plugin('D', "/* here comes another file line */"); + signal_eod(); + write_plugin('I', "TEST18S_Data"); + // this plugin object should be the latest item to backup if (regress_backup_plugin_objects) { @@ -1771,6 +1793,8 @@ int main(int argc, char** argv) { Term: signal_term(); + // LOG("#> Unlink symlink_fname."); + // unlink(symlink_fname); LOG("#> Terminating backend."); close(logfd); free(buf);