/*
* Copyright (c) 2015 by Delphix. All rights reserved.
*/
/*
* 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.
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libnvpair.h>
#include "ndmpd_log.h"
#include "ndmpd.h"
/*
* The dumpdates file on file system.
*/
/*
* Offsets into the ctime string to various parts.
*/
/*
* The contents of the file dumpdates is maintained on a linked list.
*/
typedef struct dumpdates {
char dd_level;
} dumpdates_t;
/*
* Month names used in ctime string.
*/
/*
* Binary lock for accessing the dumpdates file.
*/
char *zfs_dumpdate_props[] = {
"dumpdates:level0",
"dumpdates:level1",
"dumpdates:level2",
"dumpdates:level3",
"dumpdates:level4",
"dumpdates:level5",
"dumpdates:level6",
"dumpdates:level7",
"dumpdates:level8",
"dumpdates:level9",
};
/*
* lookup
*
* Look up the month (3-character) name and return its number.
*
* Returns -1 if the months name is not valid.
*/
static int
{
if (!str)
return (-1);
return (-1);
}
/*
* unctime
*
* Convert a ctime(3) format string into a system format date.
* Return the date thus calculated.
*
* Return -1 if the string is not in ctime format.
*/
static int
{
if (!str || !t)
return (-1);
return (-1);
"yday %d wday %d %d/%d/%d %02d:%02d:%02d",
return (0);
}
/*
* ddates_pathname
*
* Create the dumpdates file full path name.
*/
static char *
{
}
/*
* getaline
*
* Get a line from the file and handle the continued lines.
*/
static char *
{
char *save;
int len;
return (NULL);
do {
return (NULL);
/* comment line? */
if (*line == '#')
continue;
/* short line */
if (len <= 0)
continue;
if (*line != '\n')
return (NULL);
/* trim the trailing new line */
*line = '\0';
if (--len <= 0)
break;
break;
} while (llen > 0);
return (save);
}
/*
* get_ddname
*
* Get the path name from the buffer passed.
*
* Returns the beginning of the path name. The buffer pointer is moved
* forward to point to where the next field (the dump level) begins.
*/
static char *
{
char *h, *t, *save;
return (NULL);
while (*t) {
if (*t == '\t' || *t == ' ') {
/* consume the '\t' or space character */
t++;
break;
}
if (*t == '\\')
switch (*(t+1)) {
case '\t':
case ' ':
t++; /* skip the '\\' */
default:
break; /* nothing */
}
*h++ = *t++;
}
*bpp = t;
*h++ = '\0';
return (save);
}
/*
* get_ddlevel
*
* Get the dump level from the buffer passed.
*
* Returns the dump level found. The buffer pointer is moved
* forward to point to where the next field (the dump date) begins.
*/
static int
{
char *t, *save;
return (-1);
/*
* For 'F', 'A', 'I', and 'D' return the character itself.
*/
if (IS_LBR_BKTYPE(*t)) {
/*
* Skip the backup type character and null terminate the
* string.
*/
*++t = '\0';
*bpp = ++t;
}
while (isdigit(*t))
t++;
*t++ = '\0';
*bpp = t;
}
/*
* get_ddate
*
* Get the dump date from the buffer passed.
*
* Returns the dump date string. The buffer pointer is moved
* forward. It points to the end of the buffer now.
*/
static char *
{
char *save;
return (NULL);
return (save);
}
/*
* put_ddname
*
* Print the dump path name to the dumpdates file. It escapes the space,
* '\t' and new line characters in the path name. The same characters are
* considered in the get_ddname().
*/
static void
{
if (!nm)
return;
while (*nm)
switch (*nm) {
case ' ':
case '\n':
case '\t':
/* FALLTHROUGH */
default:
}
}
/*
* put_ddlevel
*
* Print the dump level into the dumpdates file.
*/
static void
{
if (!fp)
return;
}
/*
* put_ddate
*
* Print the dump date into the dumpdates file.
*/
time_t t)
{
if (!fp)
return;
/* LINTED variable format specifier */
}
/*
* dd_free
*
* Free the linked list of dumpdates entries.
*/
static void
{
if (!ddheadp)
return;
while (ddheadp) {
}
}
/*
* makedumpdate
*
* Make the dumpdate node based on the string buffer passed to it.
*/
static int
{
int rv;
/*
* While parsing each line, if a line contains one of the
* LBR-type levels, then checking the return value of
* get_ddlevel() against negative values, it OK. Because
* neither of the 'F', 'A', 'I' nor 'D' have negative
* ASCII value.
*/
rv = -1;
rv = -1;
rv = -1;
rv = -1;
rv = -1;
} else {
rv = 0;
}
return (rv);
}
/*
* getrecord
*
* Read a record of dumpdates file and parse it.
* The records that span multiple lines are covered.
*
* Returns:
* 0 on success
* < 0 on error
*/
static int
{
return (-1);
do {
return (-1);
} while (!*tbuf);
(*recno)++;
} else
return (0);
}
/*
* readdumptimes
*
* Read the dumpdates file and make a linked list of its entries.
*
* Returns:
* 0 on success
* < 0 on error
*/
static int
{
int recno;
return (-1);
recno = 1;
for (; ; ) {
if (!ddwalk)
return (-1);
break;
}
}
return (0);
}
/*
* dumprecout
*
* Print a record into the dumpdates file.
*/
static void
{
if (!ddp)
return;
} else
}
/*
* initdumptimes
*
* Open the dumpdates file and read it into memory.
*
* Returns:
* 0 on success
* < 0 on error
*
*/
static int
{
int rv;
if (!ddheadp)
return (-1);
if (!ddates_pathname(fname))
return (-1);
if (!fp) {
return (-1);
}
/*
* Dumpdates does not exist, make an empty one.
*/
"No file `%s', making an empty one", fname);
if (!fp) {
return (-1);
}
if (!fp) {
"Cannot read %s after creating it. %m.", fname);
return (-1);
}
}
return (rv);
}
/*
* putdumptime
*
* Put the record specified by path, level and backup date to the file.
* Update the record if such entry already exists; append if not.
*
* Returns:
* 0 on success
* < 0 on error
*/
static int
{
int found;
int rv;
if (!path)
return (-1);
if (IS_LBR_BKTYPE(level)) {
} else {
}
if (!ddates_pathname(fname)) {
return (-1);
}
if (!rfp) {
if (initdumptimes(&ddhead) < 0) {
return (-1);
}
} else {
if (rv < 0) {
return (-1);
}
}
if (!wfp) {
return (-1);
}
/* try to locate the entry in the file */
found = 0;
continue;
continue;
/* update the record for the entry */
found = 1;
"Updated to: [%s][%d][%u]",
}
/* dump all the read records */
/* append a new record */
if (!found) {
}
return (0);
}
/*
* append_dumptime
*
* Append the record specified by path, level and backup date to the file.
*/
static int
{
return (-1);
"Lbr: [%s][%s][%c][%u]",
} else
fname);
return (-1);
}
/*
* If the file is there and can be opened then make a
* backup copy it.
*/
if (fp) {
return (-1);
}
}
/* open the new copy to append the record to it */
if (!fp) {
return (-1);
}
/* append a new record */
return (0);
}
/*
* find_date
*
* Find the specified date
*/
static dumpdates_t *
{
break;
return (ddp);
}
/*
* Get the dumpdate of the last level backup done on the path.
* The last level normally is (level - 1) in case of NetBackup
* but some DMAs allow that previous level could be anything
* between 0 and the current level.
*
* Returns:
* 0 on success
* < 0 on error
*/
int
{
int i;
return (-1);
if (*level == 0) {
return (0);
}
(void) mutex_lock(&zlib_mtx);
/* Check if this is a ZFS dataset */
*level = 0;
(void) mutex_unlock(&zlib_mtx);
return (0);
}
for (i = *level - 1; i >= 0; i--) {
zfs_dumpdate_props[i], &propval) == 0) {
*level = i;
break;
}
}
&strval) != 0) {
*level = 0;
(void) mutex_unlock(&zlib_mtx);
return (0);
}
(void) mutex_unlock(&zlib_mtx);
return (-1);
}
(void) mutex_unlock(&zlib_mtx);
return (0);
}
(void) mutex_unlock(&zlib_mtx);
if (initdumptimes(&ddhead) < 0) {
return (-1);
}
/*
* Empty dumpdates file means level 0 for all paths.
*/
*level = 0;
*ddate = 0;
return (0);
}
/*
* If it's not level backup, then find the exact record
* type.
*/
"LBR_BKTYPE save 0x%p", save);
} else {
/*
* Go find the entry with the same name for a maximum of a
* lower increment and older date.
*/
for (i = *level - 1; i >= 0; i--) {
if (save) {
break;
}
}
if (!save) {
*level = 0;
}
}
return (0);
}
/*
* Put the date and the level of the back up for the
* specified path in the dumpdates file. If there is a line
* for the same path and the same level, the date is updated.
* Otherwise, a line is appended to the file.
*
* Returns:
* 0 on success
* < 0 on error
*/
int
{
int rv;
ddate);
/* Check if this is a ZFS dataset */
(void) mutex_lock(&zlib_mtx);
(void) mutex_unlock(&zlib_mtx);
return (rv);
}
(void) mutex_unlock(&zlib_mtx);
(void) mutex_lock(&ndmp_dd_lock);
(void) mutex_unlock(&ndmp_dd_lock);
return (rv);
}
/*
* Append a backup date record to the specified file.
*/
int
{
int rv;
/* Check if this is a ZFS dataset */
(void) mutex_lock(&zlib_mtx);
(void) mutex_unlock(&zlib_mtx);
return (rv);
}
(void) mutex_unlock(&zlib_mtx);
(void) mutex_lock(&ndmp_dd_lock);
(void) mutex_unlock(&ndmp_dd_lock);
return (rv);
}