/*
*/
/*
* BSD 3 Clause License
*
* Copyright (c) 2007, The Storage Networking Industry Association.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* - Neither the name of The Storage Networking Industry Association (SNIA)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Copyright (c) 2007, The Storage Networking Industry Association. */
/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
/* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
#include <ctype.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>
/*
* Maximum length of the string-representation of u_longlong_t type.
*/
/* Is Y=yes or T=true */
/* Is F=file format (vs D=node-dir format) */
/*
* If path is defined.
*/
/*
* Component boundary means end of path or on a '/'. At this
* point both paths should be on component boundary.
*/
typedef struct bk_param_v3 {
int bp_opr;
char *bp_tmp;
char *bp_chkpnm;
char **bp_excls;
char *bp_unchkpnm;
/*
* Multiple destination restore mode
*/
int multiple_dest_restore = 0;
/*
* Plug-in module ops
*/
/*
* NDMP exclusion list
*/
/*
* split_env
*
* Splits the string into list of sections separated by the
* sep character.
*
* Parameters:
* envp (input) - the environment variable that should be broken
* sep (input) - the separator character
*
* Returns:
* Array of character pointers: On success. The array is allocated
* as well as all its entries. They all should be freed by the
* caller.
* NULL: on error
*/
static char **
{
char *save;
char **cpp;
int n;
if (!envp)
return (NULL);
envp++;
if (!*envp)
return (NULL);
if (!bp)
return (NULL);
/*
* Since the env variable is not empty, it contains at least one
* component
*/
n = 1;
n++;
}
n++; /* for the terminating NULL pointer */
cpp = ndmp_malloc(sizeof (char *) * n);
if (!cpp) {
return (NULL);
}
n = 0;
while (*cp)
*ep = '\0';
if (!cpp[n++]) {
break;
}
}
} else if (*cp == '\\') {
++cp;
*ep++ = '\n';
cp++;
*ep++ = '\t';
cp++;
} else
} else
*ep = '\0';
if (cpp) {
if (!cpp[n++]) {
} else
}
}
}
return (cpp);
}
/*
* prl
*
* Print the array of character pointers passed to it. This is
* used for debugging purpose.
*
* Parameters:
* lpp (input) - pointer to the array of strings
*
* Returns:
* void
*/
static void
{
if (!lpp) {
return;
}
while (*lpp)
}
/*
* inlist
*
* Looks through all the strings of the array to see if the ent
* matches any of the strings. The strings are patterns.
*
* Parameters:
* lpp (input) - pointer to the array of strings
* ent (input) - the entry to be matched
*
* Returns:
* TRUE: if there is a match
* FALSE: invalid argument or no match
*/
static boolean_t
{
return (FALSE);
}
while (*lpp) {
/*
* Fixing the sync_sort NDMPV3 problem, it sends the inclusion
* like "./" which we should skip the "./"
*/
pattern += 2;
return (TRUE);
}
lpp++;
}
return (FALSE);
}
/*
* inexl
*
* Checks if the entry is in the list. This is used for exclusion
* list. If the exclusion list is empty, FALSE should be returned
* showing that nothing should be excluded by default.
*
* Parameters:
* lpp (input) - pointer to the array of strings
* ent (input) - the entry to be matched
*
* Returns:
* TRUE: if there is a match
* FALSE: invalid argument or no match
*
*/
static boolean_t
{
return (FALSE);
}
/*
* ininc
*
* Checks if the entry is in the list. This is used for inclusion
* list. If the inclusion list is empty, TRUE should be returned
* showing that everything should be included by default.
*
* Parameters:
* lpp (input) - pointer to the array of strings
* ent (input) - the entry to be matched
*
* Returns:
* TRUE: if there is a match or the list is empty
* FALSE: no match
*/
static boolean_t
{
return (TRUE);
}
/*
* setupsels
*
* Set up the selection list for Local B/R functions. A new array of
* "char *" is created and the pointers point to the original paths of
* the Nlist.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
* index(input) - If not zero is the DAR entry position
*
* Returns:
* list pointer: on success
* NULL: on error
*/
/*ARGSUSED*/
char **
{
int i, n;
int len;
if (!lpp) {
return (NULL);
}
if (index) { /* DAR, just one entry */
/*
* We have to setup a list of strings that will not match any
* file. One DAR entry will be added in the right position later
* in this function.
* When the match is called from tar_getdir the
* location of the selection that matches the entry is
* important
*/
for (i = 0; i < n; ++i)
*(lpp+i) = " ";
n = 1;
} else {
start = 0;
end = n;
}
if (!ep)
continue;
/*
* Check for clients that send original path as "."(like
* CA products). In this situation opath is something like
* "/v1/." and we should change it to "/v1/"
*/
"nm3_opath changed from %s. to %s",
}
}
/* list termination indicator is a null pointer */
return (save);
}
/*
* mkrsp
*
* Make Restore Path.
* It gets a path, a selection (with which the path has matched) a new
* name and makes a new name for the path.
* All the components of the path and the selection are skipped as long
* as they are the same. If either of the path or selection are not on
* a component boundary, the match was reported falsefully and no new name
* is generated(Except the situation in which both path and selection
* end with trailing '/' and selection is the prefix of the path).
* Otherwise, the remaining of the path is appended to the
* new name. The result is saved in the buffer passed.
*
* Parameters:
* bp (output) - pointer to the result buffer
* pp (input) - pointer to the path
* sp (input) - pointer to the selection
* np (input) - pointer to the new name
*
* Returns:
* pointer to the bp: on success
* NULL: otherwise
*/
char *
{
return (NULL);
if (sp) {
/* skip as much as match */
sp++;
pp++;
}
/* An exception to the boundary rule */
/* (!(!*sp && (*(pp - 1)) == '/')) */
return (NULL);
/* if pp shorter than sp, it should not be restored */
return (NULL);
}
}
if (np)
else
np = "";
return (NULL);
}
return (bp);
}
/*
* mknewname
*
* This is used as callback for creating the restore path. This function
* can handle both single destination and multiple restore paths.
*
* based on nm3_opath and nm3_dpath. path should have matched nm3_opath
* in some way.
*/
char *
{
char *rv;
if (!buf) {
} else if (!path) {
} else if (!nlp->nlp_params) {
} else
if (!ndmp_full_restore_path) {
"Invalid idx %d range (0, %d)",
"nlist entry %d is NULL", idx);
} else {
"idx %d org \"%s\" dst \"%s\"",
if (rv) {
} else {
"path \"%s\": NULL", path);
}
}
} else {
} else {
}
}
return (rv);
}
/*
* chopslash
*
* Remove the slash from the end of the given path
*/
static void
{
int ln;
return;
*cp-- = '\0';
ln--;
}
}
/*
* joinpath
*
* Join two given paths
*/
static char *
{
else
} else {
else
}
return (bp);
}
/*
* voliswr
*
* Is the volume writable?
*/
static int
{
int rv;
if (!path)
return (0);
return (rv);
}
/*
* is_valid_backup_dir_v3
*
* Checks the validity of the backup path. Backup path should
* have the following characteristics to be valid:
* 1) It should be an absolute path.
* 2) It should be a directory.
* 3) It should not be checkpoint root directory
* 4) If the file system is read-only, the backup path
* should be a checkpointed path. Checkpoint cannot
* be created on a read-only file system.
*
* Parameters:
* params (input) - pointer to the parameters structure.
* bkpath (input) - the backup path
*
* Returns:
* TRUE: if everything's OK
* FALSE: otherwise.
*/
static boolean_t
{
char *msg;
if (*bkpath != '/') {
"Relative backup path not allowed \"%s\".\n", bkpath);
return (FALSE);
}
return (FALSE);
}
/* only directories can be specified as the backup path */
"\"%s\" is not a directory.\n", bkpath);
return (FALSE);
}
/* it is not a chkpnted path */
"\"%s\" is not a checkpointed path.\n", bkpath);
return (FALSE);
}
return (TRUE);
}
/*
* log_date_token_v3
*
* Log the token sequence number and also the date of the
* last backup for token-based backup in the system log
* and also send them as normal log to the client.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
nlp->nlp_tokseq);
}
}
/*
* log_lbr_bk_v3
*
* Log the backup level and data of the backup for LBR-type
* backup in the system log and also send them as normal log
* to the client.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
}
}
/*
* log_level_v3
*
* Log the backup level and date of the last and the current
* backup for level-type backup in the system log and also
* send them as normal log to the client.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
}
/*
* log_bk_params_v3
*
* Dispatcher function which calls the appropriate function
* for logging the backup date and level in the system log
* and also send them as normal log message to the client.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
"Tape record size: %d.\n",
else {
"Internal error: backup level not defined for \"%s\".\n",
}
}
/*
* get_update_env_v3
*
* Is the UPDATE environment variable specified? If it is
* the corresponding flag is set in the flags field of the
* nlp structure, otherwise the flag is cleared.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
char *envp;
if (!envp) {
"env(UPDATE) not defined, default to TRUE");
} else {
else
}
}
/*
* get_hist_env_v3
*
* Is backup history requested? If it is, the corresponding
* flag is set in the flags field of the nlp structure, otherwise
* the flag is cleared.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
char *envp;
if (!envp) {
} else {
else
/* Force file format if specified */
}
}
}
/*
* get_exc_env_v3
*
* Gets the EXCLUDE environment variable and breaks it
* into strings. The separator of the EXCLUDE environment
* variable is the ',' character.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
char *envp;
if (!envp) {
} else {
}
}
/*
* get_inc_env_v3
*
* Gets the FILES environment variable that shows which files
* should be backed up, and breaks it into strings. The
* separator of the FILES environment variable is the space
* character.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
char *envp;
if (!envp) {
} else {
}
}
/*
* get_direct_env_v3
*
* Gets the DIRECT environment variable that shows if the fh_info should
* be sent to the client or not.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
char *envp;
/*
* We should send the fh_info to the DMA, unless it is specified
* in the request that we should not send fh_info.
* At the moment we do not support DAR on directories, so if the user
* needs to restore a directory they should disable the DAR.
*/
"DAR is disabled. Running Restore without DAR");
return;
}
/*
* Regardless of whether DIRECT is defined at backup time we send
* back the fh_info, for some clients do not use get_backup_attrs.
* If operation is restore we have to unset the DIRECT, for
* some clients do not set the MOVER window.
*/
} else {
if (!envp) {
} else {
"Direct Access Restore Enabled");
} else {
"Direct Access Restore Disabled");
}
}
}
"Direct Access Restore information is supported");
else
"Running Restore with Direct Access Restore");
} else {
"Direct Access Restore is not supported");
else
"Running Restore without Direct Access Restore");
}
}
/*
* get_date_token_v3
*
* Parse the token passed as the argument. Evaluate it and
* issue any warning or error if needed. Save the date and
* token sequence in the nlp structure fields. The sequence
* number in the token should be less than hard-limit. If
* it's between soft and hard limit, a warning is issued.
* There is a configurable limit which should be less than
* the soft-limit saved in ndmp_max_tok_seq variable.
*
* The NLPF_TOKENBK flag is set in the nlp flags field to
* show that the backup type is token-based.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
* basedate (input) - the value of the BASE_DATE environment
* variable.
*
* Returns:
* NDMP_NO_ERR: on success
* != NDMP_NO_ERR: Otherwise
*
*/
static ndmp_error
char *basedate)
{
char *endp;
return (NDMP_ILLEGAL_ARGS_ERR);
"Both BASE_DATE and LEVEL environment variables "
"defined.\n");
"BASE_DATE is being used for this backup.\n");
}
"Invalid BASE_DATE environment variable: \"%s\".\n",
basedate);
return (NDMP_ILLEGAL_ARGS_ERR);
}
if ((int)seq > ndmp_get_max_tok_seq()) {
"The sequence counter of the token exceeds the "
"maximum permitted value.\n");
"Token sequence: %u, maxiumum value: %u.\n",
seq, ndmp_get_max_tok_seq());
} else if (seq >= NDMP_TOKSEQ_HLIMIT) {
"The sequence counter the of token exceeds the "
"hard-limit.\n");
"Token sequence: %u, hard-limit: %u.\n",
} else {
rv = NDMP_NO_ERR;
/*
* Issue a warning if the seq is equal to the maximum
* permitted seq number or equal to the soft-limit.
*/
if (seq == NDMP_TOKSEQ_SLIMIT) {
"The sequence counter of the token has reached "
"the soft-limit.\n");
"Token sequence: %u, soft-limit: %u.\n",
} else if ((int)seq == ndmp_get_max_tok_seq()) {
"The sequence counter of the token has reached "
"the maximum permitted value.\n");
"Token sequence: %u, maxiumum value: %u.\n",
seq, ndmp_get_max_tok_seq());
}
/*
* The current seq is equal to the seq field of the
* token. It will be increased after successful backup
* before setting the DUMP_DATE environment variable.
*/
/*
* The value of nlp_cdate will be set to the checkpoint
* creation time after it is created.
*/
}
return (rv);
}
/*
* get_lbr_bk_v3
*
* Sets the level fields of the nlp structures for
* LBR-type backup. The NLPF_LBRBK flag of the
* nlp flags is also set to show the backup type.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
* type (input) - the backup level: 'F', 'A', 'I', 'D' or
* their lower-case values.
*
* Returns:
* NDMP_NO_ERR: on success
* != NDMP_NO_ERR: Otherwise
*/
static ndmp_error
{
return (NDMP_ILLEGAL_ARGS_ERR);
return (NDMP_NO_ERR);
}
/*
* get_backup_level_v3
*
* Gets the backup level from the environment variables. If
* BASE_DATE is specified, it will be used, otherwise LEVEL
* will be used. If neither is specified, LEVEL = '0' is
* assumed.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* NDMP_NO_ERR: on success
* != NDMP_NO_ERR: Otherwise
*/
static ndmp_error
{
char *envp;
/*
* If the BASE_DATE env variable is specified use it, otherwise
* look to see if LEVEL is specified. If LEVEL is not
* specified either, backup level '0' must be made. Level backup
* does not clear the archive bit.
*
* If LEVEL environment varaible is specified, values for
* 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
* 'Incremental', and 'Archive' is checked first. Then
* level '0' to '9' will be checked.
*
* LEVEL environment variable can hold only one character.
* If its length is longer than 1, an error is returned.
*/
if (envp)
if (!envp) {
nlp->nlp_llevel = 0;
nlp->nlp_clevel = 0;
/*
* The value of nlp_cdate will be set to the checkpoint
* creation time after it is created.
*/
return (NDMP_NO_ERR);
}
"Invalid backup level \"%s\".\n", envp);
return (NDMP_ILLEGAL_ARGS_ERR);
}
if (IS_LBR_BKTYPE(*envp))
"Invalid backup level \"%s\".\n", envp);
return (NDMP_ILLEGAL_ARGS_ERR);
}
/*
* The value of nlp_cdate will be set to the checkpoint
* creation time after it is created.
*/
"Getting dumpdates for %s level '%c'.\n",
return (NDMP_NO_MEM_ERR);
} else {
rv = NDMP_NO_ERR;
}
return (rv);
}
/*
* save_date_token_v3
*
* Make the value of DUMP_DATE env variable and append the values
* of the current backup in the file specified with the DMP_NAME
* env variable if any file is specified. The file will be
* relative name in the backup directory path.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
return;
nlp->nlp_tokseq++;
"Could not set DUMP_DATE to %s", val);
"Saving backup date for \"%s\" in \"%s\".\n",
}
}
/*
* save_lbr_bk_v3
*
* Append the backup type and date in the DMP_NAME file for
* LBR-type backup if any file is specified.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
return;
"Saving backup date for \"%s\" in \"%s\".\n",
}
}
/*
* save_level_v3
*
* Save the date and level of the current backup in the dumpdates
* file.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
return;
if (!NLP_SHOULD_UPDATE(nlp)) {
}
}
/*
* save_backup_date_v3
*
* A dispatcher function to call the corresponding save function
* based on the backup type.
*
* Parameters:
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* void
*/
static void
{
return;
else {
"Internal error: lost backup level type for \"%s\".\n",
}
}
/*
* backup_alloc_structs_v3
*
* Create the structures for V3 backup. This includes:
* Job stats
* Reader writer IPC
* File history callback structure
*
* Parameters:
* session (input) - pointer to the session
* jname (input) - name assigned to the current backup for
* job stats strucure
*
* Returns:
* 0: on success
* -1: otherwise
*/
static int
{
int n;
long xfer_size;
if (!nlp) {
return (-1);
}
return (-1);
}
/*
* Read multiple of mover_record_size near to 512K. This
* will prevent the data being copied in the mover buffer
* when we write the data.
*/
if (n <= 0)
n = 1;
xfer_size *= n;
}
if (!cmds->tcs_command) {
return (-1);
}
if (!nlp->nlp_logcallbacks) {
return (-1);
}
return (0);
}
/*
* restore_alloc_structs_v3
*
* Create the structures for V3 Restore. This includes:
* Job stats
* Reader writer IPC
* File recovery callback structure
*
* Parameters:
* session (input) - pointer to the session
* jname (input) - name assigned to the current backup for
* job stats strucure
*
* Returns:
* 0: on success
* -1: otherwise
*/
int
{
long xfer_size;
if (!nlp) {
return (-1);
}
/* this is used in ndmpd_path_restored_v3() */
return (-1);
}
if (!cmds->tcs_command) {
return (-1);
}
if (!nlp->nlp_logcallbacks) {
return (-1);
}
return (-1);
}
return (0);
}
/*
* free_structs_v3
*
* Release the resources allocated by backup_alloc_structs_v3
* function.
*
* Parameters:
* session (input) - pointer to the session
* jname (input) - name assigned to the current backup for
* job stats strucure
*
* Returns:
* void
*/
/*ARGSUSED*/
static void
{
if (!nlp) {
return;
}
if (!cmds) {
return;
}
if (nlp->nlp_logcallbacks) {
} else
if (cmds->tcs_command) {
else
} else
}
} else {
}
}
}
/*
* backup_dirv3
*
* Backup a directory and update the bytes processed field of the
* data server.
*
* Parameters:
* bpp (input) - pointer to the backup parameters structure
* pnp (input) - pointer to the path node
* enp (input) - pointer to the entry node
*
* Returns:
* 0: on success
* != 0: otherwise
*/
static int
{
char *acltp;
char *p;
return (-1);
}
return (0);
return (-1);
}
} else {
}
if (*p == '/')
bpp->bp_unchkpnm, p);
else
bpp->bp_unchkpnm, p);
return (0);
}
/*
* backup_filev3
*
* Backup a file and update the bytes processed field of the
* data server.
*
* Parameters:
* bpp (input) - pointer to the backup parameters structure
* pnp (input) - pointer to the path node
* enp (input) - pointer to the entry node
*
* Returns:
* 0: on success
* != 0: otherwise
*/
static int
{
char *ent;
char *acltp;
char *p;
return (-1);
}
return (0);
return (-1);
}
if (aclp &&
} else {
}
}
if (*p == '/')
bpp->bp_unchkpnm, p);
else
bpp->bp_unchkpnm, p);
}
/*
* check_bk_args
*
* Check the argument of the bpp. This is shared function between
* timebk_v3 and lbrbk_v3 functions. The checks include:
* - The bpp itself.
* - If the session pointer of the bpp is valid.
* - If the session connection to the DMA is closed.
* - If the nlp pointer of the bpp is valid.
* - If the backup is aborted.
*
* Parameters:
* bpp (input) - pointer to the backup parameters structure
*
* Returns:
* 0: if everything's OK
* != 0: otherwise
*/
static int
{
int rv;
if (!bpp) {
rv = -1;
} else if (!bpp->bp_session) {
rv = -1;
rv = -1;
"Connection client is closed for backup \"%s\"",
return (-1);
rv = -1;
} else
rv = 0;
return (rv);
}
/*
* shouldskip
*
* Determines if the current entry should be skipped or it
* should be backed up.
*
* Parameters:
* bpp (input) - pointer to the backup parameters structure
* pnp (input) - pointer to the path node
* enp (input) - pointer to the entry node
* errp (output) - pointer to the error value that should be
* returned by the caller
*
* Returns:
* TRUE: if the entry should not be backed up
* FALSE: otherwise
*/
static boolean_t
{
char *ent;
return (TRUE);
}
ent = "";
} else {
}
/*
* When excluding or skipping entries, FST_SKIP should be
* returned, otherwise, 0 should be returned to
* get other entries in the directory of this entry.
*/
*errp = 0;
} else
return (rv);
}
/*
* ischngd
*
* Check if the object specified should be backed up or not.
* If stp belongs to a directory and if it is marked in the
* bitmap vector, it shows that either the directory itself is
* modified or there is something below it that will be backed
* up.
*
* By setting ndmp_force_bk_dirs global variable to a non-zero
* value, directories are backed up anyways.
*
* Backing up the directories unconditionally helps
* restoring the metadata of directories as well, when one
* of the objects below them are being restored.
*
* For non-directory objects, if the modification or change
* time of the object is after the date specified by the
* bk_selector_t, the the object must be backed up.
*/
static boolean_t
{
if (!stp) {
} else if (!nlp) {
} else if (t == 0) {
/*
* if we are doing base backup then we do not need to
* check the time, for we should backup everything.
*/
/*
* If the object is a directory and it leads to a modified
* object (that should be backed up) and for that type of
* backup the path nodes should be backed up, then return
* TRUE.
*
* This is required by some DMAs like Backup Express, which
* needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
* for the intermediate directories of a modified object.
* Other DMAs, like net_backup and net_worker, do not have such
* requirement. This requirement makes sense for dump format
* but for 'tar' format, it does not. In provision to the
* NDMP-v4 spec, for 'tar' format the intermediate directories
* need not to be reported.
*/
if (NLP_IGNCTIME(nlp)) {
(uint_t)t);
} else {
(uint_t)t);
}
} else {
}
return (rv);
}
/*
* iscreated
*
* This function is used to check last mtime (currently inside the ACL
* structure) instead of ctime for checking if the file is to be backed up
* or not. See option "inc.lmtime" for more details
*/
/*ARGSUSED*/
time_t t)
{
int ret;
char *acltp;
return (0);
if (ret != 0) {
"Error getting the acl information: err %d", ret);
return (0);
}
}
/* Need to add support for last mtime */
return (0);
}
/*
* size_cb
*
* The callback function for calculating the size of
* the backup path. This is used to get an estimate
* of the progress of backup during NDMP backup
*/
static int
{
return (0);
}
/*
* timebk_v3
*
* The callback function for backing up objects based on
* their time stamp. This is shared between token-based
* and level-based backup, which look at the time stamps
* of the objects to determine if they should be backed
* up.
*
* Parameters:
* arg (input) - pointer to the backup parameters structure
* pnp (input) - pointer to the path node
* enp (input) - pointer to the entry node
*
* Returns:
* 0: if backup should continue
* -1: if the backup should be stopped
* FST_SKIP: if backing up the current directory is enough
*/
static int
{
char *ent;
int rv;
time_t t;
if (rv != 0)
return (rv);
return (rv);
} else {
ent = "";
}
return (FST_SKIP);
}
} else {
return (-1);
}
sizeof (struct stat64));
}
} else {
rv = 0;
sizeof (struct stat64));
}
}
return (rv);
}
/*
* lbrbk_v3
*
* The callback function for backing up objects based on
* their archive directory bit. This is used in LBR-type
* backup. In which the objects are backed up if their
* archive bit is set.
*
* Parameters:
* arg (input) - pointer to the backup parameters structure
* pnp (input) - pointer to the path node
* enp (input) - pointer to the entry node
*
* Returns:
* 0: if backup should continue
* -1: if the backup should be stopped
* FST_SKIP: if backing up the current directory is enough
*/
static int
{
char *ent;
int rv;
if (rv != 0)
return (rv);
return (rv);
} else {
ent = "";
}
return (FST_SKIP);
}
return (-1);
}
if (SHOULD_LBRBK(bpp)) {
}
} else if (SHOULD_LBRBK(bpp)) {
rv = 0;
}
return (rv);
}
/*
* backup_reader_v3
*
* The reader thread for the backup. It sets up the callback
* parameters and traverses the backup hierarchy in level-order
* way.
*
* Parameters:
* jname (input) - name assigned to the current backup for
* job stats strucure
* nlp (input) - pointer to the nlp structure
* cmds (input) - pointer to the tlm_commands_t structure
*
* Returns:
* 0: on success
* != 0: otherwise
*/
static int
{
int rv;
char *jname;
if (!argp)
return (-1);
rv = 0;
cmds->tcs_reader_count++;
/* NDMP parameters */
/* LBR-related parameters */
/* release the parent thread, after referencing the job stats */
return (-1);
/*
* Make the checkpointed paths for traversing the
* backup hierarchy, if we make the checkpoint.
*/
if (!NLP_ISCHKPNTED(nlp)) {
return (-1);
}
} else {
}
/* set traversing arguments */
} else {
rv = -1;
"Unknow backup type.\n");
}
/* take into account the header written to the stream so far */
n = tlm_get_data_offset(lcmd);
if (rv == 0) {
/* start traversing the hierarchy and actual backup */
if (rv == 0) {
/* write the trailer and update the bytes processed */
(void) write_tar_eof(lcmd);
nlp->nlp_session->
} else {
"Filesystem traverse error.\n");
}
}
if (!NLP_ISCHKPNTED(nlp))
cmds->tcs_reader_count--;
return (rv);
}
/*
* tar_backup_v3
*
* Traverse the backup hierarchy if needed and make the bitmap.
* Then launch reader and writer threads to do the actual backup.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
* jname (input) - job name
*
* Returns:
* 0: on success
* != 0: otherwise
*/
static int
{
int result;
int err;
if (ndmp_get_bk_dir_ino(nlp))
return (-1);
/* exit as if there was an internal error */
return (-1);
return (-1);
}
}
return (-1);
}
return (-1);
}
/* Plug-in module */
nlp->nlp_backup_path)) != 0) {
goto backup_out;
}
}
(void *)&arg);
if (err == 0) {
} else {
return (-1);
}
"Runtime [%s] %llu bytes (%llu): %d seconds\n",
/* exit as if there was an internal error */
err = -1;
}
}
}
err = -1;
} else {
/* Plug-in module */
return (-1);
}
}
return (err);
}
/*
* get_backup_size
*
* Find the estimate of backup size. This is used to get an estimate
* of the progress of backup during NDMP backup.
*/
void
{
int rv;
bk_size = 0;
} else {
}
bk_size = 0;
} else {
}
}
/*
* get_rs_path_v3
*
* Find the restore path
*/
{
char *dp;
int i, nm_cnt;
*mdest_buf = 0;
*nm_dpath_list = "";
if (!ep) {
return (NDMP_ILLEGAL_ARGS_ERR);
}
}
if (ISDEFINED(nm_dpath_list[i]))
dp = nm_dpath_list[i];
else
/* the default destination path is backup directory */
/* check the destination directory exists and is writable */
if (!fs_volexist(dp)) {
"Invalid destination path volume \"%s\".\n", dp);
"The destination path volume"
" is not writable \"%s\".\n", dp);
} else {
rv = NDMP_NO_ERR;
sizeof (mdest_buf));
}
/*
* Exit if there is an error or it is not a multiple
* destination restore mode
*/
break;
if (i < nm_cnt)
sizeof (mdest_buf));
}
return (rv);
}
/*
* fix_nlist_v3
*
* Check if the recovery list is valid and fix it if there are some
* unspecified entries in it. It checks for original, destination
* and new path for all NDMP names provided inside the list.
*
* V3: dpath is the destination directory. If newnm is not NULL, the
* dpath/opath_last_node, where opath_last_node is the last node in opath.
*
* V4: If newnm is not NULL, dpath is the destination directory, and
* the destination path (opath is not involved in forming destination path).
*/
{
int i, n;
int iswrbk;
int bvexists;
char *dp;
char *nm;
int existsvol;
int isrwdst;
if (!buf) {
return (NDMP_NO_MEM_ERR);
}
rv = NDMP_NO_ERR;
for (i = 0; i < n; i++) {
if (!ep)
continue;
/* chop off the trailing slashes */
/* existing and non-empty destination path */
} else {
/* the default destination path is backup directory */
}
/* check the destination directory exists and is writable */
if (!existsvol) {
"Invalid destination path volume "
"\"%s\".\n", dp);
break;
}
if (!isrwdst) {
"The destination path volume is not "
"writable \"%s\".\n", dp);
break;
}
/*
* If new name is not specified, the default new name is
* the last component of the original path, if any
* (except in V4).
*/
} else {
char *p, *q;
/*
* Find the last component of nm3_opath.
* nm3_opath has no trailing '/'.
*/
/*
* In DDAR the last component could
* be repeated in nm3_dpath
*/
}
if (!bp) {
/*
* Note: What should be done with this entry?
* We leave it untouched for now, hence no path in
* the backup image matches with this entry and will
* be reported as not found.
*/
continue;
}
if (!cp) {
"Insufficient memory.\n");
break;
}
if (!bp) {
/*
* Note: The same problem of above with long path.
*/
"Path too long(%s/%s)",
continue;
}
if (!cp) {
"Insufficient memory.\n");
break;
}
} else {
}
}
return (rv);
}
/*
* allvalidfh
*
* Run a sanity check on the file history info. The file history
* info is the offset of the record starting the entry on the tape
* and is used in DAR (direct access restore mode).
*/
static boolean_t
{
int i, n;
for (i = 0; i < n; i++) {
if (!ep)
continue;
/*
* The fh_info's sent from the client are multiples
* of RECORDSIZE which is 512 bytes.
*
* All our fh_info's are at the RECORDSIZE boundary. If there
* is any fh_info that is less than RECORDSIZE (this covers 0
* and -1 values too), then the result is that DAR cannot be
* done.
*/
break;
}
}
return (rv);
}
/*
* log_rs_params_v3
*
* Log a copy of all values of the restore parameters
*/
void
{
"Tape record size: %d.\n",
"Tape server: remote at %s:%d.\n",
else
"Unknown tape server address type.\n");
"Direct Access Restore.\n");
}
/*
* send_unrecovered_list_v3
*
* Create the list of files that were in restore list but
* not recovered due to some errors.
*/
int
{
int i, rv;
int err;
if (!params) {
return (-1);
}
if (!nlp) {
return (-1);
}
else
err = 0;
}
rv = 0;
for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
if (rv < 0)
break;
}
}
return (rv);
}
/*
* restore_dar_alloc_structs_v3
*
* Allocates the necessary structures for running DAR restore.
* It just creates the reader writer IPC.
* This function is called for each entry in the restore entry list.
*
* Parameters:
* session (input) - pointer to the session
* jname (input) - Job name
*
* Returns:
* 0: on success
* -1: on error
*/
int
{
long xfer_size;
if (!nlp) {
return (-1);
}
if (!cmds->tcs_command) {
return (-1);
}
return (0);
}
/*
* free_dar_structs_v3
*
* To free the structures were created by restore_dar_alloc_structs_v3.
* This funnction is called for each entry in restore entry list.
*
* Parameters:
* session (input) - pointer to the session
* jname (input) - job name
*
* Returns:
* NONE
*/
/*ARGSUSED*/
static void
{
if (!nlp) {
return;
}
if (!cmds) {
return;
}
if (cmds->tcs_command) {
else
} else
}
/*
* ndmp_dar_tar_init_v3
*
* Constructor for the DAR restore. Creates job name, allocates structures
* needed for keeping the statistics, and reports the start of restore action.
* It is called once for each DAR restore request.
*
* Parameters:
* session (input) - pointer to the session
* nlp (input) - pointer to the nlp structure
*
* Returns:
* char pointer: on success
* NULL: on error
*/
{
char *jname;
if (!jname)
return (NULL);
(void) ndmp_new_job_name(jname);
if (!nlp) {
return (NULL);
}
return (NULL);
}
if (!nlp->nlp_logcallbacks) {
return (NULL);
}
return (NULL);
}
/* this is used in ndmpd_path_restored_v3() */
return (jname);
}
/*
* ndmpd_dar_tar_end_v3
*
* Deconstructor for the DAR restore. This function is called once per
* DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
* jname(input) - job name
*
* Returns:
* 0: on success
* -1: on error
*/
{
int err = 0;
/* nothing restored. */
} else {
}
if (nlp->nlp_logcallbacks) {
} else {
}
} else {
"NULL", err);
}
} else {
}
}
return (err);
}
/*
* ndmpd_dar_tar_v3
*
* This function is called for each entry in DAR entry list. The window
* is already located and we should be in the right position to read
* the data from the tape.
* For each entry we setup selection list; so that, if the file name from
* tape is not as the name client asked for, error be returned.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
* jname (input) - job name
* dar_index(input) - Index of this entry in the restore list
*
* Returns:
* 0: on success
* -1: on error
*/
static int
{
char *excl;
char **sels;
int flags;
int err;
err = 0;
/*
* We have to allocate and deallocate buffers every time we
* run the restore, for we need to flush the buffers.
*/
return (-1);
if (!sels) {
return (-1);
}
(void *)&arg);
if (err == 0) {
} else {
return (-1);
}
cmds->tcs_writer_count++;
/* Plug-in module */
dar_index - 1);
!= 0) {
goto restore_out;
}
}
/*
* If the fatal error from tm_getdir looks like an
* errno code, we send the error description to DMA.
*/
sizeof (errbuf)) == 0) {
"Fatal error during the restore: %s\n",
errbuf);
}
}
cmds->tcs_writer_count--;
/*
* If this is the last DAR entry and it is a three-way
* restore then we should close the connection.
*/
if ((data_addr_type == NDMP_ADDR_TCP) &&
}
/* exit as if there was an internal error */
err = -1;
/* Plug-in module */
err = -1;
}
}
return (err);
}
/*
* ndmpd_dar_locate_windwos_v3
*
* Locating the right window in which the requested file is backed up.
* We should go through windows to find the exact location, for the
* file can be located in for example 10th window after the current window.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* fh_info (input) - index from the beginning of the backup stream
* len (input) - Length of the mover window
*
* Returns:
* 0: on success
* -1: on error
*/
static int
{
int ret = 0;
for (; ; ) {
if (ret == 0) /* Seek was done successfully */
break;
else if (ret < 0) {
break;
}
/*
* DMA moved to a new window.
* If we are reading the remainig of the file from
* new window, seek is handled by ndmpd_local_read_v3.
* Here we should continue the seek inside the new
* window.
*/
continue;
}
return (ret);
}
/*
* ndmpd_rs_dar_tar_v3
*
* Main DAR function. It calls the constructor, then for each entry it
* calls the locate_window_v3 to find the exact position of the file. Then
* it restores the file.
* When all restore requests are done it calls the deconstructor to clean
* everything up.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* 0: on success
* -1: on error
*/
static int
{
char *jname;
int i, ret = 0;
int result = 0;
if (!jname)
return (-1);
/*
* We set the length = sizeof (tlm_tar_hdr_t)
* This is important for three-way DAR restore, for we should
* read the header first (If we ask for more data then we have
* to read and discard the remaining data in the socket)
*/
len = tlm_tarhdr_size();
for (i = 0; i < n; ++i) {
if (!ep) {
continue;
}
"restoring opath %s, dpath %s, fh_info %lld",
ep->nm3_fh_info);
/*
* We should seek till finding the window in which file
* is located.
*/
if (ret < 0) /* If seek fails, restore should be aborted */
break;
/*
* We are inside the target window.
* for each restore we will use one entry as selection list
*/
!= 0)
}
return (ret);
}
/*
* ndmp_plugin_pre_restore
*
* Wrapper for pre-restore callback with multiple path
*/
static int
int ncount)
{
int err;
int i;
for (i = 0; i < ncount; i++) {
continue;
return (err);
}
return (0);
}
/*
* get_absolute_path
*
* Get resolved path name which does not involve ".", ".." or extra
* "/" or symbolic links.
*
* e.g.
*
*
* Returns:
* Pointer to the new path (allocated)
* NULL if the path doesnt exist
*/
static char *
{
char *pbuf;
char *rv;
return (NULL);
}
return (rv);
}
/*
* Expands the format string and logs the resulting message to the
* remote DMA
*/
void
{
return;
}
/*
* ndmpd_rs_sar_tar_v3
*
* Main non-DAR restore function. It will try to restore all the entries
* that have been backed up.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
* nlp (input) - pointer to the nlp structure
*
* Returns:
* 0: on success
* -1: on error
*/
static int
{
char *excl;
char **sels;
int flags;
int err;
int result;
(void) ndmp_new_job_name(jname);
return (-1);
if (!sels) {
return (-1);
}
(void *)&arg);
if (err == 0) {
} else {
return (-1);
}
} else {
}
/* Plug-in module */
nlp->nlp_nfiles))
!= 0) {
goto restore_out;
}
}
cmds->tcs_writer_count++;
/*
* If the fatal error from tm_getdir looks like an
* errno code, we send the error description to DMA.
*/
sizeof (errbuf)) == 0) {
"Fatal error during the restore: %s\n",
errbuf);
}
}
cmds->tcs_writer_count--;
/* exit as if there was an internal error */
err = -1;
if (err == -1)
}
err = -1;
} else {
err);
/* Plug-in module */
err = -1;
}
}
return (err);
}
/*
* ndmp_backup_get_params_v3
*
* Get the backup parameters from the NDMP env variables
* and log them in the system log and as normal messages
* to the DMA.
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
*
* Returns:
* NDMP_NO_ERR: on success
* != NDMP_NO_ERR: otherwise
*/
{
return (NDMP_ILLEGAL_ARGS_ERR);
if (!nlp) {
"Internal error: NULL nlp.\n");
return (NDMP_ILLEGAL_ARGS_ERR);
} else {
return (NDMP_ILLEGAL_ARGS_ERR);
}
if (!nlp->nlp_backup_path)
return (NDMP_ILLEGAL_ARGS_ERR);
else
/* Should the st_ctime be ignored when backing up? */
if (ndmp_ignore_ctime) {
} else {
}
if (ndmp_include_lmtime == TRUE) {
} else {
}
}
/*
* ndmpd_tar_backup_starter_v3
*
* Create the checkpoint for the backup and do the backup,
* then remove the backup checkpoint if we created it.
* Save the backup time information based on the backup
* type and stop the data server.
*
* Parameters:
* params (input) - pointer to the parameters structure
*
* Returns:
* 0: on success
* != 0: otherwise
*/
int
{
int err;
(void) ndmp_new_job_name(jname);
err = 0;
if (!NLP_ISCHKPNTED(nlp) &&
"Creating checkpoint on \"%s\".\n",
err = -1;
}
if (err == 0) {
/* Get an estimate of the data size */
(void *)&sarg) == 0)
(void) pthread_detach(tid);
if (err != 0) {
} else {
}
}
if (!NLP_ISCHKPNTED(nlp))
if (err == 0)
/* nlp_params is allocated in start_backup_v3() */
return (err);
}
/*
* ndmpd_tar_backup_abort_v3
*
* Abort the backup operation and stop the reader thread.
*
* Parameters:
* module_cookie (input) - pointer to the nlp structure
*
* Returns:
* 0: always
*/
int
{
}
}
return (0);
}
/*
* ndmp_restore_get_params_v3
*
* Get the parameters specified for recovery such as restore path, type
* of restore (DAR, non-DAR) etc
*
* Parameters:
* session (input) - pointer to the session
* params (input) - pointer to the parameters structure
*
* Returns:
* NDMP_NO_ERR: on success
* != NDMP_NO_ERR: otherwise
*/
{
} else {
rv = NDMP_NO_ERR;
/* Currently we dont support DAR on directory */
"Can't have RECURSIVE and DIRECT together");
return (rv);
}
/*
* DAR can be done if all the fh_info's are valid.
*/
} else {
"Cannot do direct access recovery. "
"Some 'fh_info'es are not valid.\n");
}
}
}
return (rv);
}
/*
* ndmpd_tar_restore_starter_v3
*
* The main restore starter function. It will start a DAR or
* non-DAR recovery based on the parameters. (V3 and V4 only)
*
* Parameters:
* params (input) - pointer to the parameters structure
*
* Returns:
* NDMP_NO_ERR: on success
* != NDMP_NO_ERR: otherwise
*/
int
{
int err;
else
/* nlp_params is allocated in start_recover() */
return (err);
}
/*
* ndmp_tar_restore_abort_v3
*
* Restore abort function (V3 and V4 only)
*
* Parameters:
* module_cookie (input) - pointer to nlp
*
* Returns:
* 0
*/
int
{
}
}
return (0);
}