#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/acl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <cstack.h>
#include "ndmp.h"
#include "ndmpd.h"
#include <bitmap.h>
#include <traverse.h>
#define QUAD_DECIMAL_LEN 20
#define IS_YORT(c) (strchr("YT", toupper(c)))
#define IS_F(c) (toupper(c) == 'F')
#define ISDEFINED(cp) ((cp) && *(cp))
#define SHOULD_LBRBK(bpp) (!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE))
#define COMPBNDRY(p) (!*(p) || (*p) == '/')
typedef struct bk_param_v3 {
ndmpd_session_t *bp_session;
ndmp_lbr_params_t *bp_nlp;
tlm_job_stats_t *bp_js;
tlm_cmd_t *bp_lcmd;
tlm_commands_t *bp_cmds;
tlm_acls_t *bp_tlmacl;
int bp_opr;
char *bp_tmp;
char *bp_chkpnm;
char **bp_excls;
char *bp_unchkpnm;
} bk_param_v3_t;
#define MULTIPLE_DEST_DIRS 128
int multiple_dest_restore = 0;
ndmp_plugin_t *ndmp_pl;
char **ndmp_excl_list = NULL;
static char **
split_env(char *envp, char sep)
{
char *bp, *cp, *ep;
char *save;
char **cpp;
int n;
if (!envp)
return (NULL);
while (isspace(*envp))
envp++;
if (!*envp)
return (NULL);
bp = save = strdup(envp);
if (!bp)
return (NULL);
n = 1;
while ((cp = strchr(bp, sep))) {
if (cp > save && *(cp-1) != '\\')
n++;
bp = cp + 1;
}
n++;
cpp = ndmp_malloc(sizeof (char *) * n);
if (!cpp) {
free(save);
return (NULL);
}
(void) memset(cpp, 0, n * sizeof (char *));
n = 0;
cp = bp = ep = save;
while (*cp)
if (*cp == sep) {
*ep = '\0';
if (strlen(bp) > 0) {
cpp[n] = strdup(bp);
if (!cpp[n++]) {
tlm_release_list(cpp);
cpp = NULL;
break;
}
}
ep = bp = ++cp;
} else if (*cp == '\\') {
++cp;
if (*cp == 'n') {
*ep++ = '\n';
cp++;
} else if (*cp == 't') {
*ep++ = '\t';
cp++;
} else
*ep++ = *cp++;
} else
*ep++ = *cp++;
*ep = '\0';
if (cpp) {
if (strlen(bp) > 0) {
cpp[n] = strdup(bp);
if (!cpp[n++]) {
tlm_release_list(cpp);
cpp = NULL;
} else
cpp[n] = NULL;
}
if (n == 0 && cpp != NULL) {
tlm_release_list(cpp);
cpp = NULL;
}
}
free(save);
return (cpp);
}
static void
prl(char **lpp)
{
if (!lpp) {
NDMP_LOG(LOG_DEBUG, "empty");
return;
}
while (*lpp)
NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++);
}
static boolean_t
inlist(char **lpp, char *ent)
{
if (!lpp || !ent) {
NDMP_LOG(LOG_DEBUG, "empty list");
return (FALSE);
}
while (*lpp) {
char *pattern = *lpp;
if (strncmp(pattern, "./", 2) == 0)
pattern += 2;
NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
if (match(pattern, ent)) {
NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent);
return (TRUE);
}
lpp++;
}
NDMP_LOG(LOG_DEBUG, "no match");
return (FALSE);
}
static boolean_t
inexl(char **lpp, char *ent)
{
if (!lpp || !ent)
return (FALSE);
return (inlist(lpp, ent));
}
static boolean_t
ininc(char **lpp, char *ent)
{
if (!lpp || !ent || !*ent)
return (TRUE);
return (inlist(lpp, ent));
}
char **
setupsels(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp, int index)
{
char **lpp, **save;
int i, n;
int len;
int start, end;
mem_ndmp_name_v3_t *ep;
n = session->ns_data.dd_nlist_len;
save = lpp = ndmp_malloc(sizeof (char *) * (n + 1));
if (!lpp) {
MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
return (NULL);
}
if (index) {
for (i = 0; i < n; ++i)
*(lpp+i) = " ";
n = 1;
start = index-1;
end = start+1;
lpp += start;
} else {
start = 0;
end = n;
}
for (i = start; i < end; i++) {
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
if (!ep)
continue;
len = strlen(ep->nm3_opath);
if (len > 1 && ep->nm3_opath[len-2] == '/' &&
ep->nm3_opath[len-1] == '.') {
ep->nm3_opath[len-1] = '\0';
NDMP_LOG(LOG_DEBUG,
"nm3_opath changed from %s. to %s",
ep->nm3_opath, ep->nm3_opath);
}
*lpp++ = ep->nm3_opath;
}
*lpp = NULL;
return (save);
}
char *
mkrsp(char *bp, char *pp, char *sp, char *np)
{
if (!bp || !pp)
return (NULL);
pp += strspn(pp, "/");
if (sp) {
sp += strspn(sp, "/");
while (*sp && *pp && *sp == *pp) {
sp++;
pp++;
}
if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
if (*sp || (*(pp - 1)) != '/')
return (NULL);
if (!*pp && *sp) {
sp += strspn(sp, "/");
if (strlen(sp) > 0)
return (NULL);
}
}
if (np)
np += strspn(np, "/");
else
np = "";
if (!tlm_cat_path(bp, np, pp)) {
NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp);
return (NULL);
}
return (bp);
}
char *
mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
{
char *rv;
ndmp_lbr_params_t *nlp;
mem_ndmp_name_v3_t *ep;
rv = NULL;
if (!buf) {
NDMP_LOG(LOG_DEBUG, "buf is NULL");
} else if (!path) {
NDMP_LOG(LOG_DEBUG, "path is NULL");
} else if ((nlp = rnp->rn_nlp) == 0) {
NDMP_LOG(LOG_DEBUG, "rnp->rn_nlp is NULL");
} else if (!nlp->nlp_params) {
NDMP_LOG(LOG_DEBUG, "nlp->nlp_params is NULL");
} else
if (!ndmp_full_restore_path) {
if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
NDMP_LOG(LOG_DEBUG,
"Invalid idx %d range (0, %d)",
idx, nlp->nlp_nfiles);
} else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(
nlp->nlp_params, idx))) {
NDMP_LOG(LOG_DEBUG,
"nlist entry %d is NULL", idx);
} else {
rv = mkrsp(buf, path, ep->nm3_opath,
ep->nm3_dpath);
NDMP_LOG(LOG_DEBUG,
"idx %d org \"%s\" dst \"%s\"",
idx, ep->nm3_opath, ep->nm3_dpath);
if (rv) {
NDMP_LOG(LOG_DEBUG,
"path \"%s\": \"%s\"", path, rv);
} else {
NDMP_LOG(LOG_DEBUG,
"path \"%s\": NULL", path);
}
}
} else {
if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) {
NDMP_LOG(LOG_ERR, "Path too long %s/%s.",
nlp->nlp_restore_path, path);
rv = NULL;
} else {
rv = buf;
NDMP_LOG(LOG_DEBUG,
"path \"%s\": \"%s\"", path, rv);
}
}
return (rv);
}
static void
chopslash(char *cp)
{
int ln;
if (!cp || !*cp)
return;
ln = strlen(cp);
cp += ln - 1;
while (ln > 0 && *cp == '/') {
*cp-- = '\0';
ln--;
}
}
static char *
joinpath(char *bp, char *pp, char *np)
{
if (pp && *pp) {
if (np && *np)
(void) tlm_cat_path(bp, pp, np);
else
(void) strlcpy(bp, pp, TLM_MAX_PATH_NAME);
} else {
if (np && *np)
(void) strlcpy(bp, np, TLM_MAX_PATH_NAME);
else
bp = NULL;
}
return (bp);
}
static int
voliswr(char *path)
{
int rv;
if (!path)
return (0);
rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path);
return (rv);
}
static boolean_t
is_valid_backup_dir_v3(ndmpd_module_params_t *params, char *bkpath)
{
char *msg;
struct stat64 st;
if (*bkpath != '/') {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Relative backup path not allowed \"%s\".\n", bkpath);
return (FALSE);
}
if (stat64(bkpath, &st) < 0) {
msg = strerror(errno);
MOD_LOGV3(params, NDMP_LOG_ERROR, "\"%s\" %s.\n",
bkpath, msg);
return (FALSE);
}
if (!S_ISDIR(st.st_mode)) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"\"%s\" is not a directory.\n", bkpath);
return (FALSE);
}
if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
fs_is_chkpnt_enabled(bkpath)) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"\"%s\" is not a checkpointed path.\n", bkpath);
return (FALSE);
}
return (TRUE);
}
static void
log_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
MOD_LOGV3(params, NDMP_LOG_NORMAL, "Token sequence counter: %d.\n",
nlp->nlp_tokseq);
MOD_LOGV3(params, NDMP_LOG_NORMAL, "Date of the last backup: %s.\n",
cctime(&nlp->nlp_tokdate));
if (nlp->nlp_dmpnm) {
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
}
}
static void
log_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Date of this level '%c': %s.\n", nlp->nlp_clevel,
cctime(&nlp->nlp_cdate));
if (nlp->nlp_dmpnm) {
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
}
}
static void
log_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Date of the last level '%u': %s.\n", nlp->nlp_llevel,
cctime(&nlp->nlp_ldate));
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Date of this level '%u': %s.\n", nlp->nlp_clevel,
cctime(&nlp->nlp_cdate));
MOD_LOGV3(params, NDMP_LOG_NORMAL, "Update: %s.\n",
NDMP_TORF(NLP_ISSET(nlp, NLPF_UPDATE)));
}
static void
log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp)
{
MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
nlp->nlp_backup_path);
if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Tape record size: %d.\n",
session->ns_mover.md_record_size);
MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
if (NLP_ISSET(nlp, NLPF_TOKENBK))
log_date_token_v3(params, nlp);
else if (NLP_ISSET(nlp, NLPF_LBRBK))
log_lbr_bk_v3(params, nlp);
else if (NLP_ISSET(nlp, NLPF_LEVELBK))
log_level_v3(params, nlp);
else {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Internal error: backup level not defined for \"%s\".\n",
nlp->nlp_backup_path);
}
}
static void
get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *envp;
envp = MOD_GETENV(params, "UPDATE");
if (!envp) {
NLP_SET(nlp, NLPF_UPDATE);
NDMP_LOG(LOG_DEBUG,
"env(UPDATE) not defined, default to TRUE");
} else {
NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
if (IS_YORT(*envp))
NLP_SET(nlp, NLPF_UPDATE);
else
NLP_UNSET(nlp, NLPF_UPDATE);
}
}
static void
get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *envp;
envp = MOD_GETENV(params, "HIST");
if (!envp) {
NDMP_LOG(LOG_DEBUG, "env(HIST) not defined");
NLP_UNSET(nlp, NLPF_FH);
} else {
NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", envp);
if (IS_YORT(*envp) || IS_F(*envp))
NLP_SET(nlp, NLPF_FH);
else
NLP_UNSET(nlp, NLPF_FH);
if (IS_F(*envp)) {
params->mp_file_history_path_func =
ndmpd_api_file_history_file_v3;
params->mp_file_history_dir_func = 0;
params->mp_file_history_node_func = 0;
}
}
}
static void
get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *envp;
envp = MOD_GETENV(params, "EXCLUDE");
if (!envp) {
NDMP_LOG(LOG_DEBUG, "env(EXCLUDE) not defined");
nlp->nlp_exl = NULL;
} else {
NDMP_LOG(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
nlp->nlp_exl = split_env(envp, ',');
prl(nlp->nlp_exl);
}
}
static void
get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *envp;
envp = MOD_GETENV(params, "FILES");
if (!envp) {
NDMP_LOG(LOG_DEBUG, "env(FILES) not defined");
nlp->nlp_inc = NULL;
} else {
NDMP_LOG(LOG_DEBUG, "env(FILES): \"%s\"", envp);
nlp->nlp_inc = split_env(envp, ' ');
prl(nlp->nlp_inc);
}
}
static void
get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *envp;
if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
NDMP_LOG(LOG_DEBUG, "Direct Access Restore Disabled");
NLP_UNSET(nlp, NLPF_DIRECT);
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"DAR is disabled. Running Restore without DAR");
return;
}
if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
NDMP_LOG(LOG_DEBUG, "backup default env(DIRECT): YES");
NLP_SET(nlp, NLPF_DIRECT);
} else {
envp = MOD_GETENV(params, "DIRECT");
if (!envp) {
NDMP_LOG(LOG_DEBUG, "env(DIRECT) not defined");
NLP_UNSET(nlp, NLPF_DIRECT);
} else {
NDMP_LOG(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
if (IS_YORT(*envp)) {
NLP_SET(nlp, NLPF_DIRECT);
NDMP_LOG(LOG_DEBUG,
"Direct Access Restore Enabled");
} else {
NLP_UNSET(nlp, NLPF_DIRECT);
NDMP_LOG(LOG_DEBUG,
"Direct Access Restore Disabled");
}
}
}
if (NLP_ISSET(nlp, NLPF_DIRECT)) {
if (params->mp_operation == NDMP_DATA_OP_BACKUP)
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Direct Access Restore information is supported");
else
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Running Restore with Direct Access Restore");
} else {
if (params->mp_operation == NDMP_DATA_OP_BACKUP)
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Direct Access Restore is not supported");
else
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Running Restore without Direct Access Restore");
}
}
static ndmp_error
get_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp,
char *basedate)
{
char *endp;
uint_t seq;
ndmp_error rv;
time_t tstamp;
u_longlong_t tok;
if (!params || !nlp || !basedate || !*basedate)
return (NDMP_ILLEGAL_ARGS_ERR);
if (MOD_GETENV(params, "LEVEL")) {
MOD_LOGV3(params, NDMP_LOG_WARNING,
"Both BASE_DATE and LEVEL environment variables "
"defined.\n");
MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
"BASE_DATE is being used for this backup.\n");
}
tok = strtoll(basedate, &endp, 10);
if (endp == basedate) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Invalid BASE_DATE environment variable: \"%s\".\n",
basedate);
return (NDMP_ILLEGAL_ARGS_ERR);
}
tstamp = tok & 0xffffffff;
seq = (tok >> 32) & 0xffffffff;
NDMP_LOG(LOG_DEBUG, "basedate \"%s\" %lld seq %u tstamp %u",
basedate, tok, seq, tstamp);
if ((int)seq > ndmp_get_max_tok_seq()) {
rv = NDMP_ILLEGAL_ARGS_ERR;
MOD_LOGV3(params, NDMP_LOG_ERROR,
"The sequence counter of the token exceeds the "
"maximum permitted value.\n");
MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
"Token sequence: %u, maxiumum value: %u.\n",
seq, ndmp_get_max_tok_seq());
} else if (seq >= NDMP_TOKSEQ_HLIMIT) {
rv = NDMP_ILLEGAL_ARGS_ERR;
MOD_LOGV3(params, NDMP_LOG_ERROR,
"The sequence counter the of token exceeds the "
"hard-limit.\n");
MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
"Token sequence: %u, hard-limit: %u.\n",
seq, NDMP_TOKSEQ_HLIMIT);
} else {
rv = NDMP_NO_ERR;
if (seq == NDMP_TOKSEQ_SLIMIT) {
MOD_LOGV3(params, NDMP_LOG_WARNING,
"The sequence counter of the token has reached "
"the soft-limit.\n");
MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
"Token sequence: %u, soft-limit: %u.\n",
seq, NDMP_TOKSEQ_SLIMIT);
} else if ((int)seq == ndmp_get_max_tok_seq()) {
MOD_LOGV3(params, NDMP_LOG_WARNING,
"The sequence counter of the token has reached "
"the maximum permitted value.\n");
MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
"Token sequence: %u, maxiumum value: %u.\n",
seq, ndmp_get_max_tok_seq());
}
nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
NLP_SET(nlp, NLPF_TOKENBK);
NLP_UNSET(nlp, NLPF_LEVELBK);
NLP_UNSET(nlp, NLPF_LBRBK);
nlp->nlp_tokseq = seq;
nlp->nlp_tokdate = tstamp;
}
return (rv);
}
static ndmp_error
get_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *type)
{
if (!params || !nlp || !type || !*type)
return (NDMP_ILLEGAL_ARGS_ERR);
NLP_SET(nlp, NLPF_LBRBK);
NLP_UNSET(nlp, NLPF_TOKENBK);
NLP_UNSET(nlp, NLPF_LEVELBK);
nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
nlp->nlp_llevel = toupper(*type);
nlp->nlp_ldate = (time_t)0;
nlp->nlp_clevel = nlp->nlp_llevel;
(void) time(&nlp->nlp_cdate);
return (NDMP_NO_ERR);
}
static ndmp_error
get_backup_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *envp;
ndmp_error rv;
envp = MOD_GETENV(params, "BASE_DATE");
if (envp)
return (get_date_token_v3(params, nlp, envp));
envp = MOD_GETENV(params, "LEVEL");
if (!envp) {
NDMP_LOG(LOG_DEBUG, "env(LEVEL) not defined, default to 0");
NLP_SET(nlp, NLPF_LEVELBK);
NLP_UNSET(nlp, NLPF_LBRBK);
NLP_UNSET(nlp, NLPF_TOKENBK);
nlp->nlp_llevel = 0;
nlp->nlp_ldate = 0;
nlp->nlp_clevel = 0;
return (NDMP_NO_ERR);
}
if (*(envp+1) != '\0') {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Invalid backup level \"%s\".\n", envp);
return (NDMP_ILLEGAL_ARGS_ERR);
}
if (IS_LBR_BKTYPE(*envp))
return (get_lbr_bk_v3(params, nlp, envp));
if (!isdigit(*envp)) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Invalid backup level \"%s\".\n", envp);
return (NDMP_ILLEGAL_ARGS_ERR);
}
NLP_SET(nlp, NLPF_LEVELBK);
NLP_UNSET(nlp, NLPF_LBRBK);
NLP_UNSET(nlp, NLPF_TOKENBK);
nlp->nlp_llevel = *envp - '0';
nlp->nlp_ldate = 0;
nlp->nlp_clevel = nlp->nlp_llevel;
if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
&nlp->nlp_ldate) < 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Getting dumpdates for %s level '%c'.\n",
nlp->nlp_backup_path, *envp);
return (NDMP_NO_MEM_ERR);
} else {
get_update_env_v3(params, nlp);
rv = NDMP_NO_ERR;
}
return (rv);
}
static void
save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char val[QUAD_DECIMAL_LEN];
u_longlong_t tok;
if (!params || !nlp)
return;
nlp->nlp_tokseq++;
tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
(void) snprintf(val, sizeof (val), "%llu", tok);
NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val);
if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Could not set DUMP_DATE to %s", val);
} else if (!nlp->nlp_dmpnm) {
NDMP_LOG(LOG_DEBUG, "No log file defined");
} else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Saving backup date for \"%s\" in \"%s\".\n",
nlp->nlp_backup_path, nlp->nlp_dmpnm);
}
}
static void
save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
if (!params || !nlp)
return;
if (!nlp->nlp_dmpnm) {
NDMP_LOG(LOG_DEBUG, "No log file defined");
} else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
nlp->nlp_clevel, nlp->nlp_cdate) < 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Saving backup date for \"%s\" in \"%s\".\n",
nlp->nlp_backup_path, nlp->nlp_dmpnm);
}
}
static void
save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
if (!params || !nlp)
return;
if (!NLP_SHOULD_UPDATE(nlp)) {
NDMP_LOG(LOG_DEBUG, "update not requested");
} else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
nlp->nlp_cdate) < 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
}
}
static void
save_backup_date_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
if (!params || !nlp)
return;
if (NLP_ISSET(nlp, NLPF_TOKENBK))
save_date_token_v3(params, nlp);
else if (NLP_ISSET(nlp, NLPF_LBRBK))
save_lbr_bk_v3(params, nlp);
else if (NLP_ISSET(nlp, NLPF_LEVELBK))
save_level_v3(params, nlp);
else {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Internal error: lost backup level type for \"%s\".\n",
nlp->nlp_backup_path);
}
}
static int
backup_alloc_structs_v3(ndmpd_session_t *session, char *jname)
{
int n;
long xfer_size;
ndmp_lbr_params_t *nlp;
tlm_commands_t *cmds;
nlp = ndmp_get_nlp(session);
if (!nlp) {
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return (-1);
}
nlp->nlp_jstat = tlm_new_job_stats(jname);
if (!nlp->nlp_jstat) {
NDMP_LOG(LOG_DEBUG, "Creating job stats");
return (-1);
}
cmds = &nlp->nlp_cmds;
(void) memset(cmds, 0, sizeof (*cmds));
xfer_size = ndmp_buffer_get_size(session);
if (xfer_size < 512*KILOBYTE) {
n = 512 * KILOBYTE / xfer_size;
if (n <= 0)
n = 1;
xfer_size *= n;
NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d",
xfer_size);
}
cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
if (!cmds->tcs_command) {
tlm_un_ref_job_stats(jname);
return (-1);
}
nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb);
if (!nlp->nlp_logcallbacks) {
tlm_release_reader_writer_ipc(cmds->tcs_command);
tlm_un_ref_job_stats(jname);
return (-1);
}
nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
nlp->nlp_restored = NULL;
return (0);
}
int
restore_alloc_structs_v3(ndmpd_session_t *session, char *jname)
{
long xfer_size;
ndmp_lbr_params_t *nlp;
tlm_commands_t *cmds;
nlp = ndmp_get_nlp(session);
if (!nlp) {
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return (-1);
}
nlp->nlp_lastidx = -1;
nlp->nlp_jstat = tlm_new_job_stats(jname);
if (!nlp->nlp_jstat) {
NDMP_LOG(LOG_DEBUG, "Creating job stats");
return (-1);
}
cmds = &nlp->nlp_cmds;
(void) memset(cmds, 0, sizeof (*cmds));
xfer_size = ndmp_buffer_get_size(session);
cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
if (!cmds->tcs_command) {
tlm_un_ref_job_stats(jname);
return (-1);
}
nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
ndmpd_path_restored_v3, NULL, NULL);
if (!nlp->nlp_logcallbacks) {
tlm_release_reader_writer_ipc(cmds->tcs_command);
tlm_un_ref_job_stats(jname);
return (-1);
}
nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
if (nlp->nlp_rsbm < 0) {
NDMP_LOG(LOG_ERR, "Out of memory.");
lbrlog_callbacks_done(nlp->nlp_logcallbacks);
tlm_release_reader_writer_ipc(cmds->tcs_command);
tlm_un_ref_job_stats(jname);
return (-1);
}
return (0);
}
static void
free_structs_v3(ndmpd_session_t *session, char *jname)
{
ndmp_lbr_params_t *nlp;
tlm_commands_t *cmds;
nlp = ndmp_get_nlp(session);
if (!nlp) {
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return;
}
cmds = &nlp->nlp_cmds;
if (!cmds) {
NDMP_LOG(LOG_DEBUG, "cmds == NULL");
return;
}
if (nlp->nlp_logcallbacks) {
lbrlog_callbacks_done(nlp->nlp_logcallbacks);
nlp->nlp_logcallbacks = NULL;
} else
NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
if (cmds->tcs_command) {
if (cmds->tcs_command->tc_buffers != NULL)
tlm_release_reader_writer_ipc(cmds->tcs_command);
else
NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
cmds->tcs_command = NULL;
} else
NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
if (nlp->nlp_bkmap >= 0) {
(void) dbm_free(nlp->nlp_bkmap);
nlp->nlp_bkmap = -1;
}
if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
if (nlp->nlp_rsbm < 0) {
NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
} else {
(void) bm_free(nlp->nlp_rsbm);
nlp->nlp_rsbm = -1;
}
}
}
static int
backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
fst_node_t *enp)
{
longlong_t apos, bpos;
acl_t *aclp = NULL;
char *acltp;
struct stat64 st;
char fullpath[TLM_MAX_PATH_NAME];
char *p;
if (!bpp || !pnp || !enp) {
NDMP_LOG(LOG_DEBUG, "Invalid argument");
return (-1);
}
NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp);
if (lstat64(bpp->bp_tmp, &st) != 0)
return (0);
if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
NDMP_LOG(LOG_DEBUG, "acl_get error errno=%d", errno);
return (-1);
}
if (aclp && (acltp = acl_totext(aclp,
ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
(void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
acltp, TLM_MAX_ACL_TXT);
acl_free(aclp);
free(acltp);
} else {
*bpp->bp_tlmacl->acl_info.attr_info = '\0';
}
bpos = tlm_get_data_offset(bpp->bp_lcmd);
p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
if (*p == '/')
(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
bpp->bp_unchkpnm, p);
else
(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
bpp->bp_unchkpnm, p);
if (tm_tar_ops.tm_putdir != NULL)
(void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl,
bpp->bp_lcmd, bpp->bp_js);
apos = tlm_get_data_offset(bpp->bp_lcmd);
bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
apos - bpos;
return (0);
}
static int
backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
fst_node_t *enp)
{
char *ent;
longlong_t rv;
longlong_t apos, bpos;
acl_t *aclp = NULL;
char *acltp;
struct stat64 st;
char fullpath[TLM_MAX_PATH_NAME];
char *p;
if (!bpp || !pnp || !enp) {
NDMP_LOG(LOG_DEBUG, "Invalid argument");
return (-1);
}
NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp);
if (lstat64(bpp->bp_tmp, &st) != 0)
return (0);
if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
NDMP_LOG(LOG_DEBUG, "acl_get error");
return (-1);
}
if (aclp &&
(acltp = acl_totext(aclp,
ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
(void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
acltp, TLM_MAX_ACL_TXT);
acl_free(aclp);
free(acltp);
} else {
*bpp->bp_tlmacl->acl_info.attr_info = '\0';
}
}
bpos = tlm_get_data_offset(bpp->bp_lcmd);
ent = enp->tn_path ? enp->tn_path : "";
p = pnp->tn_path + strlen(bpp->bp_chkpnm);
if (*p == '/')
(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
bpp->bp_unchkpnm, p);
else
(void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
bpp->bp_unchkpnm, p);
if (tm_tar_ops.tm_putfile != NULL)
rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path,
bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js,
bpp->bp_session->hardlink_q);
apos = tlm_get_data_offset(bpp->bp_lcmd);
bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
apos - bpos;
return (rv < 0 ? rv : 0);
}
static int
check_bk_args(bk_param_v3_t *bpp)
{
int rv;
if (!bpp) {
rv = -1;
NDMP_LOG(LOG_DEBUG, "Lost bpp");
} else if (!bpp->bp_session) {
rv = -1;
NDMP_LOG(LOG_DEBUG, "Session is NULL");
} else if (bpp->bp_session->ns_eof) {
rv = -1;
NDMP_LOG(LOG_INFO,
"Connection client is closed for backup \"%s\"",
bpp->bp_nlp->nlp_backup_path);
} else if (!bpp->bp_nlp) {
NDMP_LOG(LOG_DEBUG, "Lost nlp");
return (-1);
} else if (bpp->bp_session->ns_data.dd_abort) {
rv = -1;
NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"",
bpp->bp_nlp->nlp_backup_path);
} else
rv = 0;
return (rv);
}
static boolean_t
shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
fst_node_t *enp, int *errp)
{
char *ent;
boolean_t rv;
struct stat64 *estp;
if (!bpp || !pnp || !enp || !errp) {
NDMP_LOG(LOG_DEBUG, "Invalid argument");
return (TRUE);
}
if (!enp->tn_path) {
ent = "";
estp = pnp->tn_st;
} else {
ent = enp->tn_path;
estp = enp->tn_st;
}
if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
rv = TRUE;
*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
NDMP_LOG(LOG_DEBUG, "Skipping %d %s/%s",
*errp, pnp->tn_path, ent);
} else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) {
rv = TRUE;
*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
NDMP_LOG(LOG_DEBUG, "excl %d \"%s/%s\"",
*errp, pnp->tn_path, ent);
} else if (inexl(bpp->bp_nlp->nlp_exl, ent)) {
rv = TRUE;
*errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
NDMP_LOG(LOG_DEBUG, "out %d \"%s/%s\"",
*errp, pnp->tn_path, ent);
} else if (!S_ISDIR(estp->st_mode) &&
!ininc(bpp->bp_nlp->nlp_inc, ent)) {
rv = TRUE;
*errp = 0;
NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent);
} else
rv = FALSE;
return (rv);
}
static boolean_t
ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
{
boolean_t rv;
if (!stp) {
rv = FALSE;
NDMP_LOG(LOG_DEBUG, "stp is NULL");
} else if (!nlp) {
rv = FALSE;
NDMP_LOG(LOG_DEBUG, "nlp is NULL");
} else if (t == 0) {
rv = TRUE;
NDMP_LOG(LOG_DEBUG, "Base Backup");
} else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
rv = TRUE;
NDMP_LOG(LOG_DEBUG, "d(%lu)", (uint_t)stp->st_ino);
} else if (S_ISDIR(stp->st_mode) &&
dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) &&
((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
(NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
rv = TRUE;
NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino);
} else if (stp->st_mtime > t) {
rv = TRUE;
NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
(uint_t)stp->st_ino, (uint_t)stp->st_mtime, (uint_t)t);
} else if (stp->st_ctime > t) {
if (NLP_IGNCTIME(nlp)) {
rv = FALSE;
NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
(uint_t)stp->st_ino, (uint_t)stp->st_ctime,
(uint_t)t);
} else {
rv = TRUE;
NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
(uint_t)stp->st_ino, (uint_t)stp->st_ctime,
(uint_t)t);
}
} else {
rv = FALSE;
NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
(uint_t)stp->st_ino, (uint_t)stp->st_mtime,
(uint_t)stp->st_ctime, (uint_t)t);
}
return (rv);
}
int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
time_t t)
{
int ret;
acl_t *aclp = NULL;
char *acltp;
NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
if (NLP_INCLMTIME(nlp) == FALSE)
return (0);
ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
if (ret != 0) {
NDMP_LOG(LOG_DEBUG,
"Error getting the acl information: err %d", ret);
return (0);
}
if (aclp && (acltp = acl_totext(aclp,
ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
(void) strlcpy(tacl->acl_info.attr_info, acltp,
TLM_MAX_ACL_TXT);
acl_free(aclp);
free(acltp);
}
return (0);
}
static int
size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
{
struct stat64 *stp;
stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
*((u_longlong_t *)arg) += stp->st_size;
return (0);
}
static int
timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
{
char *ent;
int rv;
time_t t;
bk_param_v3_t *bpp;
struct stat64 *stp;
fs_fhandle_t *fhp;
bpp = (bk_param_v3_t *)arg;
rv = check_bk_args(bpp);
if (rv != 0)
return (rv);
stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
if (shouldskip(bpp, pnp, enp, &rv))
return (rv);
if (enp->tn_path) {
ent = enp->tn_path;
stp = enp->tn_st;
fhp = enp->tn_fh;
} else {
ent = "";
stp = pnp->tn_st;
fhp = pnp->tn_fh;
}
if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
return (FST_SKIP);
}
if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK))
t = bpp->bp_nlp->nlp_tokdate;
else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) {
t = bpp->bp_nlp->nlp_ldate;
} else {
NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"",
pnp->tn_path, ent);
return (-1);
}
if (S_ISDIR(stp->st_mode)) {
bpp->bp_tlmacl->acl_dir_fh = *fhp;
(void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
bpp->bp_tmp, stp);
if (ischngd(stp, t, bpp->bp_nlp)) {
(void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
sizeof (struct stat64));
rv = backup_dirv3(bpp, pnp, enp);
}
} else {
if (ischngd(stp, t, bpp->bp_nlp) ||
iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
rv = 0;
(void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
sizeof (struct stat64));
bpp->bp_tlmacl->acl_fil_fh = *fhp;
(void) backup_filev3(bpp, pnp, enp);
}
}
return (rv);
}
static int
lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
{
char *ent;
int rv;
bk_param_v3_t *bpp;
struct stat64 *stp;
fs_fhandle_t *fhp;
bpp = (bk_param_v3_t *)arg;
rv = check_bk_args(bpp);
if (rv != 0)
return (rv);
stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
if (shouldskip(bpp, pnp, enp, &rv))
return (rv);
if (enp->tn_path) {
ent = enp->tn_path;
stp = enp->tn_st;
fhp = enp->tn_fh;
} else {
ent = "";
stp = pnp->tn_st;
fhp = pnp->tn_fh;
}
if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
return (FST_SKIP);
}
if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK");
return (-1);
}
if (S_ISDIR(stp->st_mode)) {
bpp->bp_tlmacl->acl_dir_fh = *fhp;
(void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
bpp->bp_tmp, stp);
if (SHOULD_LBRBK(bpp)) {
bpp->bp_tlmacl->acl_attr = *stp;
rv = backup_dirv3(bpp, pnp, enp);
}
} else if (SHOULD_LBRBK(bpp)) {
rv = 0;
bpp->bp_tlmacl->acl_attr = *stp;
bpp->bp_tlmacl->acl_fil_fh = *fhp;
(void) backup_filev3(bpp, pnp, enp);
}
return (rv);
}
static void *
backup_reader_v3(void *ptr)
{
int rv;
tlm_cmd_t *lcmd;
tlm_acls_t tlm_acls;
longlong_t bpos, n;
bk_param_v3_t bp;
fs_traverse_t ft;
char *jname;
ndmp_lbr_params_t *nlp;
tlm_commands_t *cmds;
backup_reader_arg_t *argp = ptr;
if (!argp)
return ((void *)(uintptr_t)-1);
jname = argp->br_jname;
nlp = argp->br_nlp;
cmds = argp->br_cmds;
rv = 0;
lcmd = cmds->tcs_command;
lcmd->tc_ref++;
cmds->tcs_reader_count++;
(void) memset(&tlm_acls, 0, sizeof (tlm_acls));
bp.bp_session = nlp->nlp_session;
bp.bp_nlp = nlp;
bp.bp_js = tlm_ref_job_stats(jname);
bp.bp_cmds = cmds;
bp.bp_lcmd = lcmd;
bp.bp_tlmacl = &tlm_acls;
bp.bp_opr = 0;
(void) pthread_barrier_wait(&argp->br_barrier);
bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
if (!bp.bp_tmp)
return ((void *)(uintptr_t)-1);
bp.bp_unchkpnm = nlp->nlp_backup_path;
if (!NLP_ISCHKPNTED(nlp)) {
tlm_acls.acl_checkpointed = TRUE;
bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
if (!bp.bp_chkpnm) {
NDMP_FREE(bp.bp_tmp);
return ((void *)(uintptr_t)-1);
}
(void) tlm_build_snapshot_name(nlp->nlp_backup_path,
bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
} else {
tlm_acls.acl_checkpointed = FALSE;
bp.bp_chkpnm = nlp->nlp_backup_path;
}
bp.bp_excls = ndmpd_make_exc_list();
ft.ft_path = nlp->nlp_backup_path;
ft.ft_lpath = bp.bp_chkpnm;
NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath);
if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
ft.ft_callbk = timebk_v3;
tlm_acls.acl_clear_archive = FALSE;
} else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
ft.ft_callbk = lbrbk_v3;
tlm_acls.acl_clear_archive = FALSE;
NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
} else {
rv = -1;
MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
"Unknow backup type.\n");
}
ft.ft_arg = &bp;
ft.ft_logfp = (ft_log_t)ndmp_log;
ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
n = tlm_get_data_offset(lcmd);
nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
if (rv == 0) {
rv = traverse_level(&ft);
if (rv == 0) {
bpos = tlm_get_data_offset(lcmd);
(void) write_tar_eof(lcmd);
n = tlm_get_data_offset(lcmd) - bpos;
nlp->nlp_session->
ns_data.dd_module.dm_stats.ms_bytes_processed += n;
} else {
MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
"Filesystem traverse error.\n");
ndmpd_data_error(nlp->nlp_session,
NDMP_DATA_HALT_INTERNAL_ERROR);
}
}
if (!NLP_ISCHKPNTED(nlp))
NDMP_FREE(bp.bp_chkpnm);
NDMP_FREE(bp.bp_tmp);
NDMP_FREE(bp.bp_excls);
cmds->tcs_reader_count--;
lcmd->tc_writer = TLM_STOP;
tlm_release_reader_writer_ipc(lcmd);
tlm_un_ref_job_stats(jname);
return ((void *)(uintptr_t)rv);
}
static int
tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp, char *jname)
{
tlm_commands_t *cmds;
backup_reader_arg_t arg;
pthread_t rdtp;
char info[256];
int result;
ndmp_context_t nctx;
int err;
if (ndmp_get_bk_dir_ino(nlp))
return (-1);
result = err = 0;
if (session->ns_eof)
return (-1);
if (!session->ns_data.dd_abort) {
if (backup_alloc_structs_v3(session, jname) < 0) {
nlp->nlp_bkmap = -1;
return (-1);
}
if (ndmpd_mark_inodes_v3(session, nlp) != 0) {
if (nlp->nlp_bkmap != -1) {
(void) dbm_free(nlp->nlp_bkmap);
nlp->nlp_bkmap = -1;
}
free_structs_v3(session, jname);
return (-1);
}
nlp->nlp_jstat->js_start_ltime = time(NULL);
nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
cmds = &nlp->nlp_cmds;
cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
free_structs_v3(session, jname);
return (-1);
}
NDMP_LOG(LOG_DEBUG,
"Backing up \"%s\" started.", nlp->nlp_backup_path);
if (ndmp_pl != NULL &&
ndmp_pl->np_pre_backup != NULL) {
(void) memset(&nctx, 0, sizeof (ndmp_context_t));
nctx.nc_plversion = ndmp_pl->np_plversion;
nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
nctx.nc_cmds = cmds;
nctx.nc_params = params;
nctx.nc_ddata = (void *) session;
if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
nlp->nlp_backup_path)) != 0) {
NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m");
goto backup_out;
}
}
(void) memset(&arg, 0, sizeof (backup_reader_arg_t));
arg.br_jname = jname;
arg.br_nlp = nlp;
arg.br_cmds = cmds;
(void) pthread_barrier_init(&arg.br_barrier, 0, 2);
err = pthread_create(&rdtp, NULL, backup_reader_v3, &arg);
if (err == 0) {
(void) pthread_barrier_wait(&arg.br_barrier);
(void) pthread_barrier_destroy(&arg.br_barrier);
} else {
(void) pthread_barrier_destroy(&arg.br_barrier);
free_structs_v3(session, jname);
NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m");
return (-1);
}
if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
result = EIO;
nlp->nlp_jstat->js_stop_time = time(NULL);
(void) snprintf(info, sizeof (info),
"Runtime [%s] %llu bytes (%llu): %d seconds\n",
nlp->nlp_backup_path,
session->ns_data.dd_module.dm_stats.ms_bytes_processed,
session->ns_data.dd_module.dm_stats.ms_bytes_processed,
nlp->nlp_jstat->js_stop_time -
nlp->nlp_jstat->js_start_ltime);
MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
ndmp_wait_for_reader(cmds);
(void) pthread_join(rdtp, NULL);
if (session->ns_eof) {
result = EPIPE;
err = -1;
}
if (!session->ns_data.dd_abort) {
ndmpd_audit_backup(session->ns_connection,
nlp->nlp_backup_path,
session->ns_data.dd_data_addr.addr_type,
session->ns_tape.td_adapter_name, result);
NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.",
nlp->nlp_backup_path);
}
}
if (session->ns_data.dd_abort) {
ndmpd_audit_backup(session->ns_connection,
nlp->nlp_backup_path,
session->ns_data.dd_data_addr.addr_type,
session->ns_tape.td_adapter_name, EINTR);
NDMP_LOG(LOG_DEBUG,
"Backing up \"%s\" aborted.", nlp->nlp_backup_path);
err = -1;
} else {
backup_out:
if (ndmp_pl != NULL &&
ndmp_pl->np_post_backup != NULL &&
ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) {
NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
return (-1);
}
}
free_structs_v3(session, jname);
return (err);
}
void *
get_backup_size(void *ptr)
{
ndmp_bkup_size_arg_t *sarg = ptr;
fs_traverse_t ft;
u_longlong_t bk_size;
char spath[PATH_MAX];
int rv;
bk_size = 0;
if (fs_is_chkpntvol(sarg->bs_path)) {
ft.ft_path = sarg->bs_path;
} else {
(void) tlm_build_snapshot_name(sarg->bs_path,
spath, sarg->bs_jname);
ft.ft_path = spath;
}
ft.ft_lpath = ft.ft_path;
ft.ft_callbk = size_cb;
ft.ft_arg = &bk_size;
ft.ft_logfp = (ft_log_t)ndmp_log;
ft.ft_flags = FST_VERBOSE;
if ((rv = traverse_level(&ft)) != 0) {
NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv);
bk_size = 0;
} else {
NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n",
bk_size, bk_size / 1024, bk_size /(1024 * 1024));
}
sarg->bs_session->ns_data.dd_data_size = bk_size;
return (NULL);
}
ndmp_error
get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
char *dp;
ndmp_error rv;
mem_ndmp_name_v3_t *ep;
int i, nm_cnt;
char *nm_dpath_list[MULTIPLE_DEST_DIRS];
static char mdest_buf[256];
*mdest_buf = 0;
*nm_dpath_list = "";
for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) {
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
if (!ep) {
NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i);
return (NDMP_ILLEGAL_ARGS_ERR);
}
if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
nm_cnt < MULTIPLE_DEST_DIRS - 1)
nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
}
multiple_dest_restore = (nm_cnt > 1);
nlp->nlp_restore_path = mdest_buf;
for (i = 1; i < nm_cnt + 1; i++) {
if (ISDEFINED(nm_dpath_list[i]))
dp = nm_dpath_list[i];
else
dp = nlp->nlp_backup_path;
if (!fs_volexist(dp)) {
rv = NDMP_ILLEGAL_ARGS_ERR;
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Invalid destination path volume \"%s\".\n", dp);
} else if (!voliswr(dp)) {
rv = NDMP_ILLEGAL_ARGS_ERR;
MOD_LOGV3(params, NDMP_LOG_ERROR,
"The destination path volume"
" is not writable \"%s\".\n", dp);
} else {
rv = NDMP_NO_ERR;
(void) strlcat(nlp->nlp_restore_path, dp,
sizeof (mdest_buf));
NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp);
}
if (rv != NDMP_NO_ERR || !multiple_dest_restore)
break;
if (i < nm_cnt)
(void) strlcat(nlp->nlp_restore_path, ", ",
sizeof (mdest_buf));
}
return (rv);
}
ndmp_error
fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp)
{
char *cp, *buf, *bp;
int i, n;
int iswrbk;
int bvexists;
ndmp_error rv;
mem_ndmp_name_v3_t *ep;
char *dp;
char *nm;
int existsvol;
int isrwdst;
buf = ndmp_malloc(TLM_MAX_PATH_NAME);
if (!buf) {
MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
return (NDMP_NO_MEM_ERR);
}
bvexists = fs_volexist(nlp->nlp_backup_path);
iswrbk = voliswr(nlp->nlp_backup_path);
rv = NDMP_NO_ERR;
n = session->ns_data.dd_nlist_len;
for (i = 0; i < n; i++) {
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
if (!ep)
continue;
chopslash(ep->nm3_opath);
chopslash(ep->nm3_dpath);
chopslash(ep->nm3_newnm);
if (ISDEFINED(ep->nm3_dpath)) {
dp = ep->nm3_dpath;
existsvol = fs_volexist(dp);
isrwdst = voliswr(dp);
} else {
dp = nlp->nlp_backup_path;
existsvol = bvexists;
isrwdst = iswrbk;
}
if (!existsvol) {
rv = NDMP_ILLEGAL_ARGS_ERR;
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Invalid destination path volume "
"\"%s\".\n", dp);
break;
}
if (!isrwdst) {
rv = NDMP_ILLEGAL_ARGS_ERR;
MOD_LOGV3(params, NDMP_LOG_ERROR,
"The destination path volume is not "
"writable \"%s\".\n", dp);
break;
}
if (ISDEFINED(ep->nm3_newnm)) {
nm = ep->nm3_newnm;
} else {
char *p, *q;
p = strrchr(ep->nm3_opath, '/');
nm = p ? p + 1 : ep->nm3_opath;
q = strrchr(ep->nm3_dpath, '/');
q = q ? q + 1 : ep->nm3_dpath;
if (strcmp(nm, q) == 0)
nm = NULL;
}
bp = joinpath(buf, dp, nm);
if (!bp) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Destination path too long(%s/%s)", dp, nm);
continue;
}
cp = strdup(bp);
if (!cp) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Insufficient memory.\n");
rv = NDMP_NO_MEM_ERR;
break;
}
free(ep->nm3_dpath);
ep->nm3_dpath = cp;
NDMP_FREE(ep->nm3_newnm);
bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
if (!bp) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Path too long(%s/%s)",
nlp->nlp_backup_path, ep->nm3_opath);
continue;
}
cp = strdup(bp);
if (!cp) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Insufficient memory.\n");
rv = NDMP_NO_MEM_ERR;
break;
}
NDMP_FREE(ep->nm3_opath);
ep->nm3_opath = cp;
NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
if (ep->nm3_dpath) {
NDMP_LOG(LOG_DEBUG,
"dest[%d]: \"%s\"", i, ep->nm3_dpath);
} else {
NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL");
}
}
free(buf);
return (rv);
}
static boolean_t
allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
{
int i, n;
boolean_t rv;
mem_ndmp_name_v3_t *ep;
rv = TRUE;
n = session->ns_data.dd_nlist_len;
for (i = 0; i < n; i++) {
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
if (!ep)
continue;
if (ep->nm3_fh_info < RECORDSIZE ||
ep->nm3_fh_info % RECORDSIZE != 0) {
rv = FALSE;
break;
}
}
return (rv);
}
void
log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp)
{
MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n",
(nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n");
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Tape record size: %d.\n",
session->ns_mover.md_record_size);
} else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Tape server: remote at %s:%d.\n",
inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
session->ns_data.dd_data_addr.tcp_port_v3);
else
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Unknown tape server address type.\n");
if (NLP_ISSET(nlp, NLPF_DIRECT))
MOD_LOGV3(params, NDMP_LOG_NORMAL,
"Direct Access Restore.\n");
}
int
send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
{
int i, rv;
int err;
if (!params) {
NDMP_LOG(LOG_DEBUG, "params == NULL");
return (-1);
}
if (!nlp) {
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return (-1);
}
if (nlp->nlp_lastidx != -1) {
if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
err = ENOENT;
else
err = 0;
(void) ndmp_send_recovery_stat_v3(params, nlp,
nlp->nlp_lastidx, err);
nlp->nlp_lastidx = -1;
}
rv = 0;
for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
if (rv < 0)
break;
}
}
return (rv);
}
int
restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
{
long xfer_size;
ndmp_lbr_params_t *nlp;
tlm_commands_t *cmds;
nlp = ndmp_get_nlp(session);
if (!nlp) {
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return (-1);
}
cmds = &nlp->nlp_cmds;
(void) memset(cmds, 0, sizeof (*cmds));
xfer_size = ndmp_buffer_get_size(session);
cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
if (!cmds->tcs_command) {
tlm_un_ref_job_stats(jname);
return (-1);
}
return (0);
}
static void
free_dar_structs_v3(ndmpd_session_t *session, char *jname)
{
ndmp_lbr_params_t *nlp;
tlm_commands_t *cmds;
nlp = ndmp_get_nlp(session);
if (!nlp) {
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return;
}
cmds = &nlp->nlp_cmds;
if (!cmds) {
NDMP_LOG(LOG_DEBUG, "cmds == NULL");
return;
}
if (cmds->tcs_command) {
if (cmds->tcs_command->tc_buffers != NULL)
tlm_release_reader_writer_ipc(cmds->tcs_command);
else
NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
cmds->tcs_command = NULL;
} else
NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
}
static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
ndmp_lbr_params_t *nlp)
{
char *jname;
jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
if (!jname)
return (NULL);
(void) ndmp_new_job_name(jname);
if (!nlp) {
free(jname);
NDMP_LOG(LOG_DEBUG, "nlp == NULL");
return (NULL);
}
nlp->nlp_jstat = tlm_new_job_stats(jname);
if (!nlp->nlp_jstat) {
free(jname);
NDMP_LOG(LOG_DEBUG, "Creating job stats");
return (NULL);
}
nlp->nlp_jstat->js_start_ltime = time(NULL);
nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
ndmpd_path_restored_v3, NULL, NULL);
if (!nlp->nlp_logcallbacks) {
tlm_un_ref_job_stats(jname);
free(jname);
return (NULL);
}
nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
if (nlp->nlp_rsbm < 0) {
NDMP_LOG(LOG_ERR, "Out of memory.");
lbrlog_callbacks_done(nlp->nlp_logcallbacks);
tlm_un_ref_job_stats(jname);
free(jname);
return (NULL);
}
nlp->nlp_lastidx = -1;
NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
ndmp_data_get_mover_mode(session));
return (jname);
}
static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
{
int err = 0;
NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
(void) send_unrecovered_list_v3(params, nlp);
if (nlp->nlp_jstat) {
nlp->nlp_bytes_total =
(u_longlong_t)nlp->nlp_jstat->js_bytes_total;
tlm_un_ref_job_stats(jname);
nlp->nlp_jstat = NULL;
} else {
NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
}
if (nlp->nlp_logcallbacks) {
lbrlog_callbacks_done(nlp->nlp_logcallbacks);
nlp->nlp_logcallbacks = NULL;
} else {
NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
}
if (session->ns_data.dd_abort) {
NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
(nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
err = EINTR;
} else {
NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
(nlp->nlp_restore_path) ? nlp->nlp_restore_path :
"NULL", err);
}
if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
if (nlp->nlp_rsbm < 0) {
NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
} else {
(void) bm_free(nlp->nlp_rsbm);
nlp->nlp_rsbm = -1;
}
}
free(jname);
return (err);
}
static int
ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp, char *jname, int dar_index)
{
char *excl;
char **sels;
int flags;
int err;
tlm_commands_t *cmds;
struct rs_name_maker rn;
int data_addr_type = session->ns_data.dd_data_addr.addr_type;
ndmp_tar_reader_arg_t arg;
pthread_t rdtp;
ndmp_context_t nctx;
mem_ndmp_name_v3_t *ep;
err = 0;
if (restore_dar_alloc_structs_v3(session, jname) < 0)
return (-1);
sels = setupsels(session, params, nlp, dar_index);
if (!sels) {
free_dar_structs_v3(session, jname);
return (-1);
}
excl = NULL;
flags = RSFLG_OVR_ALWAYS;
rn.rn_nlp = nlp;
rn.rn_fp = mknewname;
if (!session->ns_data.dd_abort) {
cmds = &nlp->nlp_cmds;
cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
arg.tr_session = session;
arg.tr_mod_params = params;
arg.tr_cmds = cmds;
err = pthread_create(&rdtp, NULL, ndmp_tar_reader, &arg);
if (err == 0) {
tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
} else {
NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m");
return (-1);
}
cmds->tcs_command->tc_ref++;
cmds->tcs_writer_count++;
if (ndmp_pl != NULL &&
ndmp_pl->np_pre_restore != NULL) {
(void) memset(&nctx, 0, sizeof (ndmp_context_t));
nctx.nc_cmds = cmds;
nctx.nc_params = params;
nctx.nc_ddata = (void *) session;
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
dar_index - 1);
if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
ep->nm3_opath, ep->nm3_dpath))
!= 0) {
NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
ndmp_stop_local_reader(session, cmds);
ndmp_wait_for_reader(cmds);
(void) pthread_join(rdtp, NULL);
ndmp_stop_remote_reader(session);
goto restore_out;
}
}
if (tm_tar_ops.tm_getdir != NULL) {
char errbuf[256];
err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
dar_index, nlp->nlp_backup_path,
session->hardlink_q);
if (err > 0 && strerror_r(err, errbuf,
sizeof (errbuf)) == 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Fatal error during the restore: %s\n",
errbuf);
}
}
cmds->tcs_writer_count--;
cmds->tcs_command->tc_ref--;
NDMP_LOG(LOG_DEBUG, "stop local reader.");
ndmp_stop_local_reader(session, cmds);
ndmp_wait_for_reader(cmds);
(void) pthread_join(rdtp, NULL);
if ((data_addr_type == NDMP_ADDR_TCP) &&
(dar_index == (int)session->ns_data.dd_nlist_len)) {
NDMP_LOG(LOG_DEBUG, "stop remote reader.");
ndmp_stop_remote_reader(session);
}
if (session->ns_eof)
err = -1;
restore_out:
if (ndmp_pl != NULL &&
ndmp_pl->np_post_restore != NULL &&
ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
err = -1;
}
}
NDMP_FREE(sels);
free_dar_structs_v3(session, jname);
return (err);
}
static int
ndmpd_dar_locate_window_v3(ndmpd_session_t *session,
ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len)
{
int ret = 0;
for (; ; ) {
ret = (*params->mp_seek_func)(session, fh_info, len);
NDMP_LOG(LOG_DEBUG, "ret %d", ret);
if (ret == 0)
break;
else if (ret < 0) {
NDMP_LOG(LOG_DEBUG, "Seek error");
break;
}
continue;
}
return (ret);
}
static int
ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp)
{
mem_ndmp_name_v3_t *ep;
u_longlong_t len;
char *jname;
int n = session->ns_data.dd_nlist_len;
int i, ret = 0;
int result = 0;
jname = ndmpd_dar_tar_init_v3(session, nlp);
if (!jname)
return (-1);
len = tlm_tarhdr_size();
for (i = 0; i < n; ++i) {
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
if (!ep) {
NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i);
continue;
}
NDMP_LOG(LOG_DEBUG,
"restoring opath %s, dpath %s, fh_info %lld",
ep->nm3_opath ? ep->nm3_opath : "NULL",
ep->nm3_dpath ? ep->nm3_dpath : "NULL",
ep->nm3_fh_info);
ret = ndmpd_dar_locate_window_v3(session, params,
ep->nm3_fh_info, len);
if (ret < 0)
break;
if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1))
!= 0)
result = EIO;
ndmpd_audit_restore(session->ns_connection,
ep->nm3_opath ? ep->nm3_opath : "NULL",
session->ns_data.dd_data_addr.addr_type,
session->ns_tape.td_adapter_name, result);
}
NDMP_LOG(LOG_DEBUG, "End of restore list");
(void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
return (ret);
}
static int
ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
int ncount)
{
mem_ndmp_name_v3_t *ep;
int err;
int i;
for (i = 0; i < ncount; i++) {
if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i)))
continue;
if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp,
ep->nm3_opath, ep->nm3_dpath)) != 0)
return (err);
}
return (0);
}
static char *
get_absolute_path(const char *bkpath)
{
char *pbuf;
char *rv;
if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
return (NULL);
if ((rv = realpath(bkpath, pbuf)) == NULL) {
NDMP_LOG(LOG_DEBUG, "Invalid path [%s] err=%d",
bkpath, errno);
}
return (rv);
}
void
ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
{
va_list ap;
char buf[256];
ndmpd_module_params_t *params;
if (nctx == NULL ||
(params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
return;
va_start(ap, fmt);
(void) vsnprintf(buf, sizeof (buf), fmt, ap);
va_end(ap);
MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf);
}
static int
ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
ndmp_lbr_params_t *nlp)
{
char jname[TLM_MAX_BACKUP_JOB_NAME];
char *excl;
char **sels;
int flags;
int err;
tlm_commands_t *cmds;
struct rs_name_maker rn;
ndmp_tar_reader_arg_t arg;
pthread_t rdtp;
int result;
ndmp_context_t nctx;
result = err = 0;
(void) ndmp_new_job_name(jname);
if (restore_alloc_structs_v3(session, jname) < 0)
return (-1);
sels = setupsels(session, params, nlp, 0);
if (!sels) {
free_structs_v3(session, jname);
return (-1);
}
excl = NULL;
flags = RSFLG_OVR_ALWAYS;
rn.rn_nlp = nlp;
rn.rn_fp = mknewname;
nlp->nlp_jstat->js_start_ltime = time(NULL);
nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
cmds = &nlp->nlp_cmds;
cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.",
(nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
arg.tr_session = session;
arg.tr_mod_params = params;
arg.tr_cmds = cmds;
err = pthread_create(&rdtp, NULL, ndmp_tar_reader, &arg);
if (err == 0) {
tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
} else {
NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
free_structs_v3(session, jname);
return (-1);
}
if (!ndmp_check_utf8magic(cmds->tcs_command)) {
NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
} else {
NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
}
if (ndmp_pl != NULL &&
ndmp_pl->np_pre_restore != NULL) {
(void) memset(&nctx, 0, sizeof (ndmp_context_t));
nctx.nc_cmds = cmds;
nctx.nc_params = params;
nctx.nc_ddata = (void *) session;
if ((err = ndmp_plugin_pre_restore(&nctx, params,
nlp->nlp_nfiles))
!= 0) {
NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
ndmp_stop_local_reader(session, cmds);
ndmp_wait_for_reader(cmds);
(void) pthread_join(rdtp, NULL);
ndmp_stop_remote_reader(session);
goto restore_out;
}
}
cmds->tcs_command->tc_ref++;
cmds->tcs_writer_count++;
if (tm_tar_ops.tm_getdir != NULL) {
char errbuf[256];
err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
nlp->nlp_backup_path, session->hardlink_q);
if (err > 0 && strerror_r(err, errbuf,
sizeof (errbuf)) == 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Fatal error during the restore: %s\n",
errbuf);
}
}
cmds->tcs_writer_count--;
cmds->tcs_command->tc_ref--;
nlp->nlp_jstat->js_stop_time = time(NULL);
(void) send_unrecovered_list_v3(params, nlp);
ndmp_stop_local_reader(session, cmds);
ndmp_wait_for_reader(cmds);
(void) pthread_join(rdtp, NULL);
ndmp_stop_remote_reader(session);
if (session->ns_eof)
err = -1;
if (err == -1)
result = EIO;
}
(void) send_unrecovered_list_v3(params, nlp);
if (session->ns_data.dd_abort) {
NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
(nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
result = EINTR;
ndmpd_audit_restore(session->ns_connection,
nlp->nlp_restore_path,
session->ns_data.dd_data_addr.addr_type,
session->ns_tape.td_adapter_name, result);
err = -1;
} else {
NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
(nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
err);
ndmpd_audit_restore(session->ns_connection,
nlp->nlp_restore_path,
session->ns_data.dd_data_addr.addr_type,
session->ns_tape.td_adapter_name, result);
restore_out:
if (ndmp_pl != NULL &&
ndmp_pl->np_post_restore != NULL &&
ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
err = -1;
}
}
NDMP_FREE(sels);
free_structs_v3(session, jname);
return (err);
}
ndmp_error
ndmp_backup_get_params_v3(ndmpd_session_t *session,
ndmpd_module_params_t *params)
{
ndmp_lbr_params_t *nlp;
if (!session || !params)
return (NDMP_ILLEGAL_ARGS_ERR);
nlp = ndmp_get_nlp(session);
if (!nlp) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Internal error: NULL nlp.\n");
return (NDMP_ILLEGAL_ARGS_ERR);
} else {
if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) ||
!is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
return (NDMP_ILLEGAL_ARGS_ERR);
}
nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
if (!nlp->nlp_backup_path)
return (NDMP_ILLEGAL_ARGS_ERR);
if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
fs_is_rdonly(nlp->nlp_backup_path) ||
!fs_is_chkpnt_enabled(nlp->nlp_backup_path))
NLP_SET(nlp, NLPF_CHKPNTED_PATH);
else
NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
if (ndmp_ignore_ctime) {
NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
NLP_SET(nlp, NLPF_IGNCTIME);
} else {
NLP_UNSET(nlp, NLPF_IGNCTIME);
}
if (ndmp_include_lmtime == TRUE) {
NDMP_LOG(LOG_DEBUG, "including st_lmtime");
NLP_SET(nlp, NLPF_INCLMTIME);
} else {
NLP_UNSET(nlp, NLPF_INCLMTIME);
}
NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
get_hist_env_v3(params, nlp);
get_exc_env_v3(params, nlp);
get_inc_env_v3(params, nlp);
get_direct_env_v3(params, nlp);
return (get_backup_level_v3(params, nlp));
}
void *
ndmpd_tar_backup_starter_v3(void *arg)
{
ndmpd_module_params_t *params = arg;
int err;
ndmpd_session_t *session;
ndmp_lbr_params_t *nlp;
char jname[TLM_MAX_BACKUP_JOB_NAME];
ndmp_bkup_size_arg_t sarg;
pthread_t tid;
session = (ndmpd_session_t *)(params->mp_daemon_cookie);
*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
ndmp_session_ref(session);
(void) ndmp_new_job_name(jname);
err = 0;
if (!NLP_ISCHKPNTED(nlp) &&
ndmp_create_snapshot(nlp->nlp_backup_path, jname) < 0) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Creating checkpoint on \"%s\".\n",
nlp->nlp_backup_path);
err = -1;
}
NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
if (err == 0) {
sarg.bs_session = session;
sarg.bs_jname = jname;
sarg.bs_path = nlp->nlp_backup_path;
if (pthread_create(&tid, NULL, get_backup_size, &sarg) == 0)
(void) pthread_detach(tid);
err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
if (err != 0) {
NDMP_LOG(LOG_DEBUG, "err %d", err);
} else {
log_bk_params_v3(session, params, nlp);
err = tar_backup_v3(session, params, nlp, jname);
}
}
if (!NLP_ISCHKPNTED(nlp))
(void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname);
NDMP_LOG(LOG_DEBUG, "err %d, update %c",
err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
if (err == 0)
save_backup_date_v3(params, nlp);
MOD_DONE(params, err);
NDMP_FREE(nlp->nlp_params);
NDMP_FREE(nlp->nlp_backup_path);
NS_DEC(nbk);
ndmp_session_unref(session);
return ((void *)(uintptr_t)err);
}
int
ndmpd_tar_backup_abort_v3(void *module_cookie)
{
ndmp_lbr_params_t *nlp;
nlp = (ndmp_lbr_params_t *)module_cookie;
if (nlp && nlp->nlp_session) {
if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
NDMP_ADDR_TCP &&
nlp->nlp_session->ns_data.dd_sock != -1) {
(void) close(nlp->nlp_session->ns_data.dd_sock);
nlp->nlp_session->ns_data.dd_sock = -1;
}
ndmp_stop_reader_thread(nlp->nlp_session);
}
return (0);
}
ndmp_error
ndmp_restore_get_params_v3(ndmpd_session_t *session,
ndmpd_module_params_t *params)
{
ndmp_error rv;
ndmp_lbr_params_t *nlp;
if (!(nlp = ndmp_get_nlp(session))) {
NDMP_LOG(LOG_DEBUG, "nlp is NULL");
rv = NDMP_ILLEGAL_ARGS_ERR;
} else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
rv = NDMP_ILLEGAL_ARGS_ERR;
else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
rv = NDMP_ILLEGAL_ARGS_ERR;
} else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
rv = NDMP_ILLEGAL_ARGS_ERR;
} else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
} else {
rv = NDMP_NO_ERR;
get_direct_env_v3(params, nlp);
if (NLP_ISSET(nlp, NLPF_DIRECT)) {
if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
NDMP_LOG(LOG_DEBUG,
"Can't have RECURSIVE and DIRECT together");
rv = NDMP_ILLEGAL_ARGS_ERR;
return (rv);
}
if (allvalidfh(session, params)) {
ndmp_sort_nlist_v3(session);
} else {
MOD_LOGV3(params, NDMP_LOG_WARNING,
"Cannot do direct access recovery. "
"Some 'fh_info'es are not valid.\n");
NLP_UNSET(nlp, NLPF_DIRECT);
}
}
log_rs_params_v3(session, params, nlp);
}
return (rv);
}
void *
ndmpd_tar_restore_starter_v3(void *arg)
{
ndmpd_module_params_t *params = arg;
int err;
ndmpd_session_t *session;
ndmp_lbr_params_t *nlp;
session = (ndmpd_session_t *)(params->mp_daemon_cookie);
*(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
ndmp_session_ref(session);
if (NLP_ISSET(nlp, NLPF_DIRECT))
err = ndmpd_rs_dar_tar_v3(session, params, nlp);
else
err = ndmpd_rs_sar_tar_v3(session, params, nlp);
MOD_DONE(params, err);
NS_DEC(nrs);
NDMP_FREE(nlp->nlp_params);
ndmp_session_unref(session);
return ((void *)(uintptr_t)err);
}
int
ndmpd_tar_restore_abort_v3(void *module_cookie)
{
ndmp_lbr_params_t *nlp;
nlp = (ndmp_lbr_params_t *)module_cookie;
if (nlp != NULL && nlp->nlp_session != NULL) {
if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
NDMP_ADDR_TCP &&
nlp->nlp_session->ns_data.dd_sock != -1) {
(void) close(nlp->nlp_session->ns_data.dd_sock);
nlp->nlp_session->ns_data.dd_sock = -1;
}
ndmp_stop_writer_thread(nlp->nlp_session);
}
return (0);
}