12654012fSReza Sabdar /*
2f3012b59SReza Sabdar  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3*9adfa60dSMatthew Ahrens  * Copyright (c) 2015 by Delphix. All rights reserved.
42654012fSReza Sabdar  */
52654012fSReza Sabdar 
62654012fSReza Sabdar /*
72654012fSReza Sabdar  * BSD 3 Clause License
82654012fSReza Sabdar  *
92654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
102654012fSReza Sabdar  *
112654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
122654012fSReza Sabdar  * modification, are permitted provided that the following conditions
132654012fSReza Sabdar  * are met:
142654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
152654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
162654012fSReza Sabdar  *
172654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
182654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
192654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
202654012fSReza Sabdar  *	  distribution.
212654012fSReza Sabdar  *
222654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
232654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
242654012fSReza Sabdar  *	  products derived from this software without specific prior written
252654012fSReza Sabdar  *	  permission.
262654012fSReza Sabdar  *
272654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
282654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
292654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
302654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
312654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
322654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
332654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
342654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
352654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
362654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
372654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
382654012fSReza Sabdar  */
392654012fSReza Sabdar 
402654012fSReza Sabdar #include <sys/param.h>
412654012fSReza Sabdar #include <sys/types.h>
422654012fSReza Sabdar #include <ctype.h>
432654012fSReza Sabdar #include <errno.h>
442654012fSReza Sabdar #include <fcntl.h>
452654012fSReza Sabdar #include <limits.h>
462654012fSReza Sabdar #include <stdarg.h>
472654012fSReza Sabdar #include <stdio.h>
482654012fSReza Sabdar #include <stdlib.h>
492654012fSReza Sabdar #include <string.h>
502654012fSReza Sabdar #include <time.h>
512654012fSReza Sabdar #include <unistd.h>
522654012fSReza Sabdar #include <libnvpair.h>
532654012fSReza Sabdar #include "ndmpd_log.h"
542654012fSReza Sabdar #include "ndmpd.h"
552654012fSReza Sabdar 
562654012fSReza Sabdar /*
572654012fSReza Sabdar  * The dumpdates file on file system.
582654012fSReza Sabdar  */
592654012fSReza Sabdar #define	NDMP_DUMPDATES	"dumpdates"
602654012fSReza Sabdar 
612654012fSReza Sabdar 
622654012fSReza Sabdar /*
632654012fSReza Sabdar  * Offsets into the ctime string to various parts.
642654012fSReza Sabdar  */
652654012fSReza Sabdar #define	E_MONTH		4
662654012fSReza Sabdar #define	E_DAY		8
672654012fSReza Sabdar #define	E_HOUR		11
682654012fSReza Sabdar #define	E_MINUTE	14
692654012fSReza Sabdar #define	E_SECOND	17
702654012fSReza Sabdar #define	E_YEAR		20
712654012fSReza Sabdar 
722654012fSReza Sabdar 
732654012fSReza Sabdar /*
742654012fSReza Sabdar  * The contents of the file dumpdates is maintained on a linked list.
752654012fSReza Sabdar  */
762654012fSReza Sabdar typedef struct dumpdates {
772654012fSReza Sabdar 	char dd_name[TLM_MAX_PATH_NAME];
782654012fSReza Sabdar 	char dd_level;
792654012fSReza Sabdar 	time_t dd_ddate;
802654012fSReza Sabdar 	struct dumpdates *dd_next;
812654012fSReza Sabdar } dumpdates_t;
822654012fSReza Sabdar 
832654012fSReza Sabdar 
842654012fSReza Sabdar /*
852654012fSReza Sabdar  * Month names used in ctime string.
862654012fSReza Sabdar  */
872654012fSReza Sabdar static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
882654012fSReza Sabdar 
892654012fSReza Sabdar 
902654012fSReza Sabdar /*
912654012fSReza Sabdar  * Binary lock for accessing the dumpdates file.
922654012fSReza Sabdar  */
932654012fSReza Sabdar mutex_t ndmp_dd_lock = DEFAULTMUTEX;
942654012fSReza Sabdar 
952654012fSReza Sabdar int ndmp_isdst = -1;
962654012fSReza Sabdar 
972654012fSReza Sabdar char *zfs_dumpdate_props[] = {
982654012fSReza Sabdar 	"dumpdates:level0",
992654012fSReza Sabdar 	"dumpdates:level1",
1002654012fSReza Sabdar 	"dumpdates:level2",
1012654012fSReza Sabdar 	"dumpdates:level3",
1022654012fSReza Sabdar 	"dumpdates:level4",
1032654012fSReza Sabdar 	"dumpdates:level5",
1042654012fSReza Sabdar 	"dumpdates:level6",
1052654012fSReza Sabdar 	"dumpdates:level7",
1062654012fSReza Sabdar 	"dumpdates:level8",
1072654012fSReza Sabdar 	"dumpdates:level9",
1082654012fSReza Sabdar };
1092654012fSReza Sabdar 
1102654012fSReza Sabdar 
1112654012fSReza Sabdar /*
1122654012fSReza Sabdar  * lookup
1132654012fSReza Sabdar  *
1142654012fSReza Sabdar  * Look up the month (3-character) name and return its number.
1152654012fSReza Sabdar  *
1162654012fSReza Sabdar  * Returns -1 if the months name is not valid.
1172654012fSReza Sabdar  */
1182654012fSReza Sabdar static int
lookup(char * str)1192654012fSReza Sabdar lookup(char *str)
1202654012fSReza Sabdar {
1212654012fSReza Sabdar 	register char *cp, *cp2;
1222654012fSReza Sabdar 
1232654012fSReza Sabdar 	if (!str)
1242654012fSReza Sabdar 		return (-1);
1252654012fSReza Sabdar 
1262654012fSReza Sabdar 	for (cp = months, cp2 = str; *cp != '\0'; cp += 3)
1272654012fSReza Sabdar 		if (strncmp(cp, cp2, 3) == 0)
1282654012fSReza Sabdar 			return ((cp-months) / 3);
1292654012fSReza Sabdar 	return (-1);
1302654012fSReza Sabdar }
1312654012fSReza Sabdar 
1322654012fSReza Sabdar 
1332654012fSReza Sabdar /*
1342654012fSReza Sabdar  * unctime
1352654012fSReza Sabdar  *
1362654012fSReza Sabdar  * Convert a ctime(3) format string into a system format date.
1372654012fSReza Sabdar  * Return the date thus calculated.
1382654012fSReza Sabdar  *
1392654012fSReza Sabdar  * Return -1 if the string is not in ctime format.
1402654012fSReza Sabdar  */
1412654012fSReza Sabdar static int
unctime(char * str,time_t * t)1422654012fSReza Sabdar unctime(char *str, time_t *t)
1432654012fSReza Sabdar {
1442654012fSReza Sabdar 	struct tm then;
1452654012fSReza Sabdar 	char dbuf[26];
1462654012fSReza Sabdar 
1472654012fSReza Sabdar 	if (!str || !t)
1482654012fSReza Sabdar 		return (-1);
1492654012fSReza Sabdar 
1502654012fSReza Sabdar 	(void) memset(&then, 0, sizeof (then));
1512654012fSReza Sabdar 	(void) strlcpy(dbuf, str, sizeof (dbuf) - 1);
1522654012fSReza Sabdar 	dbuf[sizeof (dbuf) - 1] = '\0';
1532654012fSReza Sabdar 	dbuf[E_MONTH+3] = '\0';
1542654012fSReza Sabdar 	if ((then.tm_mon = lookup(&dbuf[E_MONTH])) < 0)
1552654012fSReza Sabdar 		return (-1);
1562654012fSReza Sabdar 
1572654012fSReza Sabdar 	then.tm_mday = atoi(&dbuf[E_DAY]);
1582654012fSReza Sabdar 	then.tm_hour = atoi(&dbuf[E_HOUR]);
1592654012fSReza Sabdar 	then.tm_min = atoi(&dbuf[E_MINUTE]);
1602654012fSReza Sabdar 	then.tm_sec = atoi(&dbuf[E_SECOND]);
1612654012fSReza Sabdar 	then.tm_year = atoi(&dbuf[E_YEAR]) - 1900;
1622654012fSReza Sabdar 	then.tm_isdst = ndmp_isdst;
1632654012fSReza Sabdar 
1642654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG,
1652654012fSReza Sabdar 	    "yday %d wday %d %d/%d/%d %02d:%02d:%02d",
1662654012fSReza Sabdar 	    then.tm_yday, then.tm_wday, then.tm_year, then.tm_mon,
1672654012fSReza Sabdar 	    then.tm_mday, then.tm_hour, then.tm_min, then.tm_sec);
1682654012fSReza Sabdar 
1692654012fSReza Sabdar 	*t = mktime(&then);
1702654012fSReza Sabdar 
1712654012fSReza Sabdar 	return (0);
1722654012fSReza Sabdar }
1732654012fSReza Sabdar 
1742654012fSReza Sabdar 
1752654012fSReza Sabdar /*
1762654012fSReza Sabdar  * ddates_pathname
1772654012fSReza Sabdar  *
1782654012fSReza Sabdar  * Create the dumpdates file full path name.
1792654012fSReza Sabdar  */
1802654012fSReza Sabdar static char *
ddates_pathname(char * buf)1812654012fSReza Sabdar ddates_pathname(char *buf)
1822654012fSReza Sabdar {
1832654012fSReza Sabdar 	return (ndmpd_make_bk_dir_path(buf, NDMP_DUMPDATES));
1842654012fSReza Sabdar }
1852654012fSReza Sabdar 
1862654012fSReza Sabdar 
1872654012fSReza Sabdar /*
18823a1cceaSRoger A. Faulkner  * getaline
1892654012fSReza Sabdar  *
1902654012fSReza Sabdar  * Get a line from the file and handle the continued lines.
1912654012fSReza Sabdar  */
1922654012fSReza Sabdar static char *
getaline(FILE * fp,char * line,int llen)19323a1cceaSRoger A. Faulkner getaline(FILE *fp, char *line, int llen)
1942654012fSReza Sabdar {
1952654012fSReza Sabdar 	char *save;
1962654012fSReza Sabdar 	int len;
1972654012fSReza Sabdar 
1982654012fSReza Sabdar 	if (!fp || !line)
1992654012fSReza Sabdar 		return (NULL);
2002654012fSReza Sabdar 
2012654012fSReza Sabdar 	*(save = line) = '\0';
2022654012fSReza Sabdar 	do {
2032654012fSReza Sabdar 		if (fgets(line, llen, fp) != line)
2042654012fSReza Sabdar 			return (NULL);
2052654012fSReza Sabdar 
2062654012fSReza Sabdar 		/* comment line? */
2072654012fSReza Sabdar 		if (*line == '#')
2082654012fSReza Sabdar 			continue;
2092654012fSReza Sabdar 
2102654012fSReza Sabdar 		len = strlen(line);
2112654012fSReza Sabdar 		/* short line */
2122654012fSReza Sabdar 		if (len <= 0)
2132654012fSReza Sabdar 			continue;
2142654012fSReza Sabdar 
2152654012fSReza Sabdar 		line += len-1;
2162654012fSReza Sabdar 		if (*line != '\n')
2172654012fSReza Sabdar 			return (NULL);
2182654012fSReza Sabdar 
2192654012fSReza Sabdar 		/* trim the trailing new line */
2202654012fSReza Sabdar 		*line = '\0';
2212654012fSReza Sabdar 		if (--len <= 0)
2222654012fSReza Sabdar 			break;
2232654012fSReza Sabdar 
2242654012fSReza Sabdar 		if (*(line-1) != '\\')
2252654012fSReza Sabdar 			break;
2262654012fSReza Sabdar 
2272654012fSReza Sabdar 		*(line-1) = '\n';
2282654012fSReza Sabdar 		llen -= len;
2292654012fSReza Sabdar 	} while (llen > 0);
2302654012fSReza Sabdar 
2312654012fSReza Sabdar 	return (save);
2322654012fSReza Sabdar }
2332654012fSReza Sabdar 
2342654012fSReza Sabdar 
2352654012fSReza Sabdar /*
2362654012fSReza Sabdar  * get_ddname
2372654012fSReza Sabdar  *
2382654012fSReza Sabdar  * Get the path name from the buffer passed.
2392654012fSReza Sabdar  *
2402654012fSReza Sabdar  * Returns the beginning of the path name.  The buffer pointer is moved
2412654012fSReza Sabdar  * forward to point to where the next field (the dump level) begins.
2422654012fSReza Sabdar  */
2432654012fSReza Sabdar static char *
get_ddname(char ** bpp)2442654012fSReza Sabdar get_ddname(char **bpp)
2452654012fSReza Sabdar {
2462654012fSReza Sabdar 	char *h, *t, *save;
2472654012fSReza Sabdar 
2482654012fSReza Sabdar 	if (!bpp || !*bpp)
2492654012fSReza Sabdar 		return (NULL);
2502654012fSReza Sabdar 
2512654012fSReza Sabdar 	*bpp += strspn(*bpp, "\t ");
2522654012fSReza Sabdar 	save = h = t = *bpp;
2532654012fSReza Sabdar 	while (*t) {
2542654012fSReza Sabdar 		if (*t == '\t' || *t == ' ') {
2552654012fSReza Sabdar 			/* consume the '\t' or space character */
2562654012fSReza Sabdar 			t++;
2572654012fSReza Sabdar 			break;
2582654012fSReza Sabdar 		}
2592654012fSReza Sabdar 
2602654012fSReza Sabdar 		if (*t == '\\')
2612654012fSReza Sabdar 			switch (*(t+1)) {
2622654012fSReza Sabdar 			case '\t':
2632654012fSReza Sabdar 			case ' ':
2642654012fSReza Sabdar 				t++; /* skip the '\\' */
2652654012fSReza Sabdar 			default:
2662654012fSReza Sabdar 				break;	/* nothing */
2672654012fSReza Sabdar 			}
2682654012fSReza Sabdar 
2692654012fSReza Sabdar 		*h++ = *t++;
2702654012fSReza Sabdar 	}
2712654012fSReza Sabdar 
2722654012fSReza Sabdar 	*bpp = t;
2732654012fSReza Sabdar 	*h++ = '\0';
2742654012fSReza Sabdar 	return (save);
2752654012fSReza Sabdar }
2762654012fSReza Sabdar 
2772654012fSReza Sabdar 
2782654012fSReza Sabdar /*
2792654012fSReza Sabdar  * get_ddlevel
2802654012fSReza Sabdar  *
2812654012fSReza Sabdar  * Get the dump level from the buffer passed.
2822654012fSReza Sabdar  *
2832654012fSReza Sabdar  * Returns the dump level found.  The buffer pointer is moved
2842654012fSReza Sabdar  * forward to point to where the next field (the dump date) begins.
2852654012fSReza Sabdar  */
2862654012fSReza Sabdar static int
get_ddlevel(char ** bpp)2872654012fSReza Sabdar get_ddlevel(char **bpp)
2882654012fSReza Sabdar {
2892654012fSReza Sabdar 	char *t, *save;
2902654012fSReza Sabdar 
2912654012fSReza Sabdar 	if (!bpp || !*bpp)
2922654012fSReza Sabdar 		return (-1);
2932654012fSReza Sabdar 
2942654012fSReza Sabdar 	*bpp += strspn(*bpp, "\t ");
2952654012fSReza Sabdar 	save = t = *bpp;
2962654012fSReza Sabdar 
2972654012fSReza Sabdar 	/*
2982654012fSReza Sabdar 	 * For 'F', 'A', 'I', and 'D' return the character itself.
2992654012fSReza Sabdar 	 */
3002654012fSReza Sabdar 	if (IS_LBR_BKTYPE(*t)) {
3012654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Lbr bk type %c", *t);
3022654012fSReza Sabdar 		/*
3032654012fSReza Sabdar 		 * Skip the backup type character and null terminate the
3042654012fSReza Sabdar 		 * string.
3052654012fSReza Sabdar 		 */
3062654012fSReza Sabdar 		*++t = '\0';
3072654012fSReza Sabdar 		*bpp = ++t;
3082654012fSReza Sabdar 		return (toupper(*save));
3092654012fSReza Sabdar 	}
3102654012fSReza Sabdar 
3112654012fSReza Sabdar 	while (isdigit(*t))
3122654012fSReza Sabdar 		t++;
3132654012fSReza Sabdar 
3142654012fSReza Sabdar 	*t++ = '\0';
3152654012fSReza Sabdar 	*bpp = t;
3162654012fSReza Sabdar 	return (atoi(save));
3172654012fSReza Sabdar }
3182654012fSReza Sabdar 
3192654012fSReza Sabdar 
3202654012fSReza Sabdar /*
3212654012fSReza Sabdar  * get_ddate
3222654012fSReza Sabdar  *
3232654012fSReza Sabdar  * Get the dump date from the buffer passed.
3242654012fSReza Sabdar  *
3252654012fSReza Sabdar  * Returns the dump date string. The buffer pointer is moved
3262654012fSReza Sabdar  * forward.  It points to the end of the buffer now.
3272654012fSReza Sabdar  */
3282654012fSReza Sabdar static char *
get_ddate(char ** bpp)3292654012fSReza Sabdar get_ddate(char **bpp)
3302654012fSReza Sabdar {
3312654012fSReza Sabdar 	char *save;
3322654012fSReza Sabdar 
3332654012fSReza Sabdar 	if (!bpp || !*bpp)
3342654012fSReza Sabdar 		return (NULL);
3352654012fSReza Sabdar 
3362654012fSReza Sabdar 	*bpp += strspn(*bpp, "\t ");
3372654012fSReza Sabdar 	save = *bpp;
3382654012fSReza Sabdar 	*bpp += strlen(*bpp);
3392654012fSReza Sabdar 	return (save);
3402654012fSReza Sabdar }
3412654012fSReza Sabdar 
3422654012fSReza Sabdar 
3432654012fSReza Sabdar /*
3442654012fSReza Sabdar  * put_ddname
3452654012fSReza Sabdar  *
3462654012fSReza Sabdar  * Print the dump path name to the dumpdates file.  It escapes the space,
3472654012fSReza Sabdar  * '\t' and new line characters in the path name.  The same characters are
3482654012fSReza Sabdar  * considered in the get_ddname().
3492654012fSReza Sabdar  */
3502654012fSReza Sabdar static void
put_ddname(FILE * fp,char * nm)3512654012fSReza Sabdar put_ddname(FILE *fp, char *nm)
3522654012fSReza Sabdar {
3532654012fSReza Sabdar 	if (!nm)
3542654012fSReza Sabdar 		return;
3552654012fSReza Sabdar 
3562654012fSReza Sabdar 	while (*nm)
3572654012fSReza Sabdar 		switch (*nm) {
3582654012fSReza Sabdar 		case ' ':
3592654012fSReza Sabdar 		case '\n':
3602654012fSReza Sabdar 		case '\t':
3612654012fSReza Sabdar 			(void) fputc('\\', fp);
3622654012fSReza Sabdar 			/* FALLTHROUGH */
3632654012fSReza Sabdar 		default:
3642654012fSReza Sabdar 			(void) fputc(*nm++, fp);
3652654012fSReza Sabdar 		}
3662654012fSReza Sabdar }
3672654012fSReza Sabdar 
3682654012fSReza Sabdar 
3692654012fSReza Sabdar /*
3702654012fSReza Sabdar  * put_ddlevel
3712654012fSReza Sabdar  *
3722654012fSReza Sabdar  * Print the dump level into the dumpdates file.
3732654012fSReza Sabdar  */
3742654012fSReza Sabdar static void
put_ddlevel(FILE * fp,int level)3752654012fSReza Sabdar put_ddlevel(FILE *fp, int level)
3762654012fSReza Sabdar {
3772654012fSReza Sabdar 	if (!fp)
3782654012fSReza Sabdar 		return;
3792654012fSReza Sabdar 
3802654012fSReza Sabdar 	(void) fprintf(fp, IS_LBR_BKTYPE(level) ? "%c" : "%d", level);
3812654012fSReza Sabdar }
3822654012fSReza Sabdar 
3832654012fSReza Sabdar 
3842654012fSReza Sabdar /*
3852654012fSReza Sabdar  * put_ddate
3862654012fSReza Sabdar  *
3872654012fSReza Sabdar  * Print the dump date into the dumpdates file.
3882654012fSReza Sabdar  */
put_ddate(FILE * fp,time_t t)3892654012fSReza Sabdar static void put_ddate(FILE *fp,
3902654012fSReza Sabdar 	time_t t)
3912654012fSReza Sabdar {
3922654012fSReza Sabdar 	char tbuf[64];
3932654012fSReza Sabdar 
3942654012fSReza Sabdar 	if (!fp)
3952654012fSReza Sabdar 		return;
3962654012fSReza Sabdar 
3972654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "[%u]", t);
3982654012fSReza Sabdar 
3992654012fSReza Sabdar 	(void) ctime_r(&t, tbuf, sizeof (tbuf));
4002654012fSReza Sabdar 	/* LINTED variable format specifier */
4012654012fSReza Sabdar 	(void) fprintf(fp, tbuf);
4022654012fSReza Sabdar }
4032654012fSReza Sabdar 
4042654012fSReza Sabdar 
4052654012fSReza Sabdar /*
4062654012fSReza Sabdar  * dd_free
4072654012fSReza Sabdar  *
4082654012fSReza Sabdar  * Free the linked list of dumpdates entries.
4092654012fSReza Sabdar  */
4102654012fSReza Sabdar static void
dd_free(dumpdates_t * ddheadp)4112654012fSReza Sabdar dd_free(dumpdates_t *ddheadp)
4122654012fSReza Sabdar {
4132654012fSReza Sabdar 	dumpdates_t *save;
4142654012fSReza Sabdar 
4152654012fSReza Sabdar 	if (!ddheadp)
4162654012fSReza Sabdar 		return;
4172654012fSReza Sabdar 
4182654012fSReza Sabdar 	ddheadp = ddheadp->dd_next;
4192654012fSReza Sabdar 	while (ddheadp) {
4202654012fSReza Sabdar 		save = ddheadp->dd_next;
4212654012fSReza Sabdar 		free(ddheadp);
4222654012fSReza Sabdar 		ddheadp = save;
4232654012fSReza Sabdar 	}
4242654012fSReza Sabdar }
4252654012fSReza Sabdar 
4262654012fSReza Sabdar 
4272654012fSReza Sabdar /*
4282654012fSReza Sabdar  * makedumpdate
4292654012fSReza Sabdar  *
4302654012fSReza Sabdar  * Make the dumpdate node based on the string buffer passed to it.
4312654012fSReza Sabdar  */
4322654012fSReza Sabdar static int
makedumpdate(dumpdates_t * ddp,char * tbuf)4332654012fSReza Sabdar makedumpdate(dumpdates_t *ddp, char *tbuf)
4342654012fSReza Sabdar {
4352654012fSReza Sabdar 	char *nmp, *un_buf;
4362654012fSReza Sabdar 	int rv;
4372654012fSReza Sabdar 
4382654012fSReza Sabdar 	/*
4392654012fSReza Sabdar 	 * While parsing each line, if a line contains one of the
4402654012fSReza Sabdar 	 * LBR-type levels, then checking the return value of
4412654012fSReza Sabdar 	 * get_ddlevel() against negative values, it OK.  Because
4422654012fSReza Sabdar 	 * neither of the 'F', 'A', 'I' nor 'D' have negative
4432654012fSReza Sabdar 	 * ASCII value.
4442654012fSReza Sabdar 	 */
4452654012fSReza Sabdar 	if (!ddp || !tbuf)
4462654012fSReza Sabdar 		rv = -1;
4472654012fSReza Sabdar 	else if (!(nmp = get_ddname(&tbuf))) {
4482654012fSReza Sabdar 		rv = -1;
4492654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "get_ddname failed 0x%p", nmp);
4502654012fSReza Sabdar 	} else if ((ddp->dd_level = get_ddlevel(&tbuf)) < 0) {
4512654012fSReza Sabdar 		rv = -1;
4522654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "dd_level < 0 %d", ddp->dd_level);
4532654012fSReza Sabdar 	} else if (!(un_buf = get_ddate(&tbuf))) {
4542654012fSReza Sabdar 		rv = -1;
4552654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "get_ddate failed 0x%p", un_buf);
4562654012fSReza Sabdar 	} else if (unctime(un_buf, &ddp->dd_ddate) < 0) {
4572654012fSReza Sabdar 		rv = -1;
4582654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "unctime failed \"%s\"", un_buf);
4592654012fSReza Sabdar 	} else {
4602654012fSReza Sabdar 		(void) strlcpy(ddp->dd_name, nmp, TLM_MAX_PATH_NAME);
4612654012fSReza Sabdar 		rv = 0;
4622654012fSReza Sabdar 	}
4632654012fSReza Sabdar 
4642654012fSReza Sabdar 	return (rv);
4652654012fSReza Sabdar }
4662654012fSReza Sabdar 
4672654012fSReza Sabdar 
4682654012fSReza Sabdar /*
4692654012fSReza Sabdar  * getrecord
4702654012fSReza Sabdar  *
4712654012fSReza Sabdar  * Read a record of dumpdates file and parse it.
4722654012fSReza Sabdar  * The records that span multiple lines are covered.
4732654012fSReza Sabdar  *
4742654012fSReza Sabdar  * Returns:
4752654012fSReza Sabdar  *   0 on success
4762654012fSReza Sabdar  *   < 0 on error
4772654012fSReza Sabdar  */
4782654012fSReza Sabdar static int
getrecord(FILE * fp,dumpdates_t * ddatep,int * recno)4792654012fSReza Sabdar getrecord(FILE *fp, dumpdates_t *ddatep, int *recno)
4802654012fSReza Sabdar {
4812654012fSReza Sabdar 	char tbuf[BUFSIZ];
4822654012fSReza Sabdar 
4832654012fSReza Sabdar 	if (!fp || !ddatep || !recno)
4842654012fSReza Sabdar 		return (-1);
4852654012fSReza Sabdar 
4862654012fSReza Sabdar 	do {
48723a1cceaSRoger A. Faulkner 		if (getaline(fp, tbuf, sizeof (tbuf)) != tbuf)
4882654012fSReza Sabdar 			return (-1);
4892654012fSReza Sabdar 	} while (!*tbuf);
4902654012fSReza Sabdar 
4912654012fSReza Sabdar 	if (makedumpdate(ddatep, tbuf) < 0)
4922654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
4932654012fSReza Sabdar 		    "Unknown intermediate format in %s, line %d", tbuf, *recno);
4942654012fSReza Sabdar 
4952654012fSReza Sabdar 	(*recno)++;
4962654012fSReza Sabdar 
4972654012fSReza Sabdar 	if (IS_LBR_BKTYPE(ddatep->dd_level & 0xff)) {
4982654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Lbr: [%s][%c][%u]",
4992654012fSReza Sabdar 		    ddatep->dd_name, ddatep->dd_level, ddatep->dd_ddate);
5002654012fSReza Sabdar 	} else
5012654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "[%s][%d][%u]",
5022654012fSReza Sabdar 		    ddatep->dd_name, ddatep->dd_level, ddatep->dd_ddate);
5032654012fSReza Sabdar 
5042654012fSReza Sabdar 	return (0);
5052654012fSReza Sabdar }
5062654012fSReza Sabdar 
5072654012fSReza Sabdar 
5082654012fSReza Sabdar /*
5092654012fSReza Sabdar  * readdumptimes
5102654012fSReza Sabdar  *
5112654012fSReza Sabdar  * Read the dumpdates file and make a linked list of its entries.
5122654012fSReza Sabdar  *
5132654012fSReza Sabdar  * Returns:
5142654012fSReza Sabdar  *   0 on success
5152654012fSReza Sabdar  *   < 0 on error
5162654012fSReza Sabdar  */
5172654012fSReza Sabdar static int
readdumptimes(FILE * fp,dumpdates_t * ddheadp)5182654012fSReza Sabdar readdumptimes(FILE *fp, dumpdates_t *ddheadp)
5192654012fSReza Sabdar {
5202654012fSReza Sabdar 	int recno;
5212654012fSReza Sabdar 	register struct	dumpdates *ddwalk;
5222654012fSReza Sabdar 
5232654012fSReza Sabdar 	if (!fp || !ddheadp)
5242654012fSReza Sabdar 		return (-1);
5252654012fSReza Sabdar 
5262654012fSReza Sabdar 	recno = 1;
5272654012fSReza Sabdar 	(void) memset((void *)ddheadp, 0, sizeof (*ddheadp));
5282654012fSReza Sabdar 	for (; ; ) {
5292654012fSReza Sabdar 		ddwalk = ndmp_malloc(sizeof (*ddwalk));
5302654012fSReza Sabdar 		if (!ddwalk)
5312654012fSReza Sabdar 			return (-1);
5322654012fSReza Sabdar 
5332654012fSReza Sabdar 		if (getrecord(fp, ddwalk, &recno) < 0) {
5342654012fSReza Sabdar 			free(ddwalk);
5352654012fSReza Sabdar 			break;
5362654012fSReza Sabdar 		}
5372654012fSReza Sabdar 
5382654012fSReza Sabdar 		ddwalk->dd_next = ddheadp->dd_next;
5392654012fSReza Sabdar 		ddheadp->dd_next = ddwalk;
5402654012fSReza Sabdar 		ddheadp = ddwalk;
5412654012fSReza Sabdar 	}
5422654012fSReza Sabdar 
5432654012fSReza Sabdar 	return (0);
5442654012fSReza Sabdar }
5452654012fSReza Sabdar 
5462654012fSReza Sabdar 
5472654012fSReza Sabdar /*
5482654012fSReza Sabdar  * dumprecout
5492654012fSReza Sabdar  *
5502654012fSReza Sabdar  * Print a record into the dumpdates file.
5512654012fSReza Sabdar  */
5522654012fSReza Sabdar static void
dumprecout(FILE * fp,dumpdates_t * ddp)5532654012fSReza Sabdar dumprecout(FILE *fp, dumpdates_t *ddp)
5542654012fSReza Sabdar {
5552654012fSReza Sabdar 	if (!ddp)
5562654012fSReza Sabdar 		return;
5572654012fSReza Sabdar 
5582654012fSReza Sabdar 	if (IS_LBR_BKTYPE(ddp->dd_level)) {
5592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Lbr: [%s][%c][%u]",
5602654012fSReza Sabdar 		    ddp->dd_name, ddp->dd_level, ddp->dd_ddate);
5612654012fSReza Sabdar 	} else
5622654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "[%s][%d][%u]",
5632654012fSReza Sabdar 		    ddp->dd_name, ddp->dd_level, ddp->dd_ddate);
5642654012fSReza Sabdar 
5652654012fSReza Sabdar 	put_ddname(fp, ddp->dd_name);
5662654012fSReza Sabdar 	(void) fputc('\t', fp);
5672654012fSReza Sabdar 	put_ddlevel(fp, ddp->dd_level);
5682654012fSReza Sabdar 	(void) fputc('\t', fp);
5692654012fSReza Sabdar 	put_ddate(fp, ddp->dd_ddate);
5702654012fSReza Sabdar }
5712654012fSReza Sabdar 
5722654012fSReza Sabdar 
5732654012fSReza Sabdar /*
5742654012fSReza Sabdar  * initdumptimes
5752654012fSReza Sabdar  *
5762654012fSReza Sabdar  * Open the dumpdates file and read it into memory.
5772654012fSReza Sabdar  *
5782654012fSReza Sabdar  * Returns:
5792654012fSReza Sabdar  *   0 on success
5802654012fSReza Sabdar  *   < 0 on error
5812654012fSReza Sabdar  *
5822654012fSReza Sabdar  */
5832654012fSReza Sabdar static int
initdumptimes(dumpdates_t * ddheadp)5842654012fSReza Sabdar initdumptimes(dumpdates_t *ddheadp)
5852654012fSReza Sabdar {
5862654012fSReza Sabdar 	char fname[PATH_MAX];
5872654012fSReza Sabdar 	int rv;
5882654012fSReza Sabdar 	FILE *fp;
5892654012fSReza Sabdar 
5902654012fSReza Sabdar 	if (!ddheadp)
5912654012fSReza Sabdar 		return (-1);
5922654012fSReza Sabdar 
5932654012fSReza Sabdar 	if (!ddates_pathname(fname))
5942654012fSReza Sabdar 		return (-1);
5952654012fSReza Sabdar 
5962654012fSReza Sabdar 	fp = fopen(fname, "r");
5972654012fSReza Sabdar 	if (!fp) {
5982654012fSReza Sabdar 		if (errno != ENOENT) {
5992654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Cannot read %s: %m.", fname);
6002654012fSReza Sabdar 			return (-1);
6012654012fSReza Sabdar 		}
6022654012fSReza Sabdar 		/*
6032654012fSReza Sabdar 		 * Dumpdates does not exist, make an empty one.
6042654012fSReza Sabdar 		 */
6052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
6062654012fSReza Sabdar 		    "No file `%s', making an empty one", fname);
6072654012fSReza Sabdar 
6082654012fSReza Sabdar 		fp = fopen(fname, "w");
6092654012fSReza Sabdar 		if (!fp) {
6102654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Cannot create %s: %m.", fname);
6112654012fSReza Sabdar 			return (-1);
6122654012fSReza Sabdar 		}
6132654012fSReza Sabdar 		(void) fclose(fp);
6142654012fSReza Sabdar 
6152654012fSReza Sabdar 		fp = fopen(fname, "r");
6162654012fSReza Sabdar 		if (!fp) {
6172654012fSReza Sabdar 			NDMP_LOG(LOG_ERR,
6182654012fSReza Sabdar 			    "Cannot read %s after creating it. %m.", fname);
6192654012fSReza Sabdar 			return (-1);
6202654012fSReza Sabdar 		}
6212654012fSReza Sabdar 	}
6222654012fSReza Sabdar 
6232654012fSReza Sabdar 	rv = readdumptimes(fp, ddheadp);
6242654012fSReza Sabdar 	(void) fclose(fp);
6252654012fSReza Sabdar 
6262654012fSReza Sabdar 	return (rv);
6272654012fSReza Sabdar }
6282654012fSReza Sabdar 
6292654012fSReza Sabdar 
6302654012fSReza Sabdar /*
6312654012fSReza Sabdar  * putdumptime
6322654012fSReza Sabdar  *
6332654012fSReza Sabdar  * Put the record specified by path, level and backup date to the file.
6342654012fSReza Sabdar  * Update the record if such entry already exists; append if not.
6352654012fSReza Sabdar  *
6362654012fSReza Sabdar  * Returns:
6372654012fSReza Sabdar  *   0 on success
6382654012fSReza Sabdar  *   < 0 on error
6392654012fSReza Sabdar  */
6402654012fSReza Sabdar static int
putdumptime(char * path,int level,time_t ddate)6412654012fSReza Sabdar putdumptime(char *path, int level, time_t ddate)
6422654012fSReza Sabdar {
6432654012fSReza Sabdar 	int found;
6442654012fSReza Sabdar 	char fname[PATH_MAX], bakfname[PATH_MAX];
6452654012fSReza Sabdar 	FILE *rfp, *wfp;
6462654012fSReza Sabdar 	dumpdates_t ddhead, tmpdd;
6472654012fSReza Sabdar 	register dumpdates_t *ddp;
6482654012fSReza Sabdar 	int rv;
6492654012fSReza Sabdar 
6502654012fSReza Sabdar 	if (!path)
6512654012fSReza Sabdar 		return (-1);
6522654012fSReza Sabdar 
6532654012fSReza Sabdar 	if (IS_LBR_BKTYPE(level)) {
6542654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Lbr: [%s][%c][%u]", path, level, ddate);
6552654012fSReza Sabdar 	} else {
6562654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "[%s][%d][%u]", path, level, ddate);
6572654012fSReza Sabdar 	}
6582654012fSReza Sabdar 
6592654012fSReza Sabdar 	if (!ddates_pathname(fname)) {
6602654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot get dumpdate file path name.");
6612654012fSReza Sabdar 		return (-1);
6622654012fSReza Sabdar 	}
6632654012fSReza Sabdar 
6642654012fSReza Sabdar 	rfp = fopen(fname, "r");
6652654012fSReza Sabdar 	if (!rfp) {
6662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Creating %s.", fname);
6672654012fSReza Sabdar 		(void) memset((void *)&ddhead, 0, sizeof (ddhead));
6682654012fSReza Sabdar 		if (initdumptimes(&ddhead) < 0) {
6692654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Could not initialize %s.",
6702654012fSReza Sabdar 			    NDMP_DUMPDATES);
6712654012fSReza Sabdar 			dd_free(&ddhead);
6722654012fSReza Sabdar 			return (-1);
6732654012fSReza Sabdar 		}
6742654012fSReza Sabdar 	} else {
6752654012fSReza Sabdar 		rv = readdumptimes(rfp, &ddhead);
6762654012fSReza Sabdar 
6772654012fSReza Sabdar 		if (rv < 0) {
6782654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Error reading dumpdates file.");
6792654012fSReza Sabdar 			(void) fclose(rfp);
6802654012fSReza Sabdar 			dd_free(&ddhead);
6812654012fSReza Sabdar 			return (-1);
6822654012fSReza Sabdar 		}
6832654012fSReza Sabdar 		(void) fclose(rfp);
6842654012fSReza Sabdar 	}
6852654012fSReza Sabdar 
6862654012fSReza Sabdar 	(void) snprintf(bakfname, PATH_MAX, "%s.bak", fname);
6872654012fSReza Sabdar 	wfp = fopen(bakfname, "w");
6882654012fSReza Sabdar 	if (!wfp) {
6892654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot open %s: %m.", bakfname);
6902654012fSReza Sabdar 		dd_free(&ddhead);
6912654012fSReza Sabdar 		return (-1);
6922654012fSReza Sabdar 	}
6932654012fSReza Sabdar 
6942654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "[%s][%s]", fname, bakfname);
6952654012fSReza Sabdar 
6962654012fSReza Sabdar 	/* try to locate the entry in the file */
6972654012fSReza Sabdar 	found = 0;
6982654012fSReza Sabdar 	for (ddp = ddhead.dd_next; ddp; ddp = ddp->dd_next) {
6992654012fSReza Sabdar 		if (ddp->dd_level != level)
7002654012fSReza Sabdar 			continue;
7012654012fSReza Sabdar 		if (strcmp(path, ddp->dd_name))
7022654012fSReza Sabdar 			continue;
7032654012fSReza Sabdar 
7042654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Found: [%s][%d][%u]",
7052654012fSReza Sabdar 		    ddp->dd_name, ddp->dd_level, ddp->dd_ddate);
7062654012fSReza Sabdar 
7072654012fSReza Sabdar 		/* update the record for the entry */
7082654012fSReza Sabdar 		found = 1;
7092654012fSReza Sabdar 		ddp->dd_ddate = ddate;
7102654012fSReza Sabdar 
7112654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
7122654012fSReza Sabdar 		    "Updated to: [%s][%d][%u]",
7132654012fSReza Sabdar 		    ddp->dd_name, ddp->dd_level, ddp->dd_ddate);
7142654012fSReza Sabdar 	}
7152654012fSReza Sabdar 
7162654012fSReza Sabdar 	/* dump all the read records */
7172654012fSReza Sabdar 	for (ddp = ddhead.dd_next; ddp; ddp = ddp->dd_next)
7182654012fSReza Sabdar 		dumprecout(wfp, ddp);
7192654012fSReza Sabdar 
7202654012fSReza Sabdar 	dd_free(&ddhead);
7212654012fSReza Sabdar 
7222654012fSReza Sabdar 	/* append a new record */
7232654012fSReza Sabdar 	if (!found) {
7242654012fSReza Sabdar 		(void) strlcpy(tmpdd.dd_name, path, TLM_MAX_PATH_NAME);
7252654012fSReza Sabdar 		tmpdd.dd_level = level;
7262654012fSReza Sabdar 		tmpdd.dd_ddate = ddate;
7272654012fSReza Sabdar 		dumprecout(wfp, &tmpdd);
7282654012fSReza Sabdar 	}
7292654012fSReza Sabdar 
7302654012fSReza Sabdar 	(void) fclose(wfp);
7312654012fSReza Sabdar 	(void) rename(bakfname, fname);
7322654012fSReza Sabdar 
7332654012fSReza Sabdar 	return (0);
7342654012fSReza Sabdar }
7352654012fSReza Sabdar 
7362654012fSReza Sabdar 
7372654012fSReza Sabdar /*
7382654012fSReza Sabdar  * append_dumptime
7392654012fSReza Sabdar  *
7402654012fSReza Sabdar  * Append the record specified by path, level and backup date to the file.
7412654012fSReza Sabdar  */
7422654012fSReza Sabdar static int
append_dumptime(char * fname,char * path,int level,time_t ddate)7432654012fSReza Sabdar append_dumptime(char *fname, char *path, int level, time_t ddate)
7442654012fSReza Sabdar {
7452654012fSReza Sabdar 	char fpath[PATH_MAX], bakfpath[PATH_MAX];
7462654012fSReza Sabdar 	FILE *fp;
7472654012fSReza Sabdar 	dumpdates_t tmpdd;
7482654012fSReza Sabdar 
7492654012fSReza Sabdar 	if (!fname || !*fname || !path || !*path)
7502654012fSReza Sabdar 		return (-1);
7512654012fSReza Sabdar 
7522654012fSReza Sabdar 	if (IS_LBR_BKTYPE(level & 0xff)) {
7532654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
7542654012fSReza Sabdar 		    "Lbr: [%s][%s][%c][%u]",
7552654012fSReza Sabdar 		    fname, path, level, ddate);
7562654012fSReza Sabdar 	} else
7572654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "[%s][%s][%d][%u]",
7582654012fSReza Sabdar 		    fname, path, level, ddate);
7592654012fSReza Sabdar 
7602654012fSReza Sabdar 	if (!ndmpd_make_bk_dir_path(fpath, fname)) {
7612654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot get dumpdate file path name %s.",
7622654012fSReza Sabdar 		    fname);
7632654012fSReza Sabdar 		return (-1);
7642654012fSReza Sabdar 	}
7652654012fSReza Sabdar 
7662654012fSReza Sabdar 	(void) snprintf(bakfpath, PATH_MAX, "%s.bak", fpath);
7672654012fSReza Sabdar 
7682654012fSReza Sabdar 	/*
7692654012fSReza Sabdar 	 * If the file is there and can be opened then make a
7702654012fSReza Sabdar 	 * backup copy it.
7712654012fSReza Sabdar 	 */
7722654012fSReza Sabdar 	fp = fopen(fpath, "r");
7732654012fSReza Sabdar 	if (fp) {
7742654012fSReza Sabdar 		(void) fclose(fp);
7752654012fSReza Sabdar 		if (filecopy(bakfpath, fpath) != 0) {
7762654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Cannot copy %s to %s: %m.",
7772654012fSReza Sabdar 			    fpath, bakfpath);
7782654012fSReza Sabdar 			return (-1);
7792654012fSReza Sabdar 		}
7802654012fSReza Sabdar 	}
7812654012fSReza Sabdar 
7822654012fSReza Sabdar 	/* open the new copy to append the record to it */
7832654012fSReza Sabdar 	fp = fopen(bakfpath, "a");
7842654012fSReza Sabdar 	if (!fp) {
7852654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Cannot open %s: %m.", bakfpath);
7862654012fSReza Sabdar 		return (-1);
7872654012fSReza Sabdar 	}
7882654012fSReza Sabdar 
7892654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "[%s][%s]", fpath, bakfpath);
7902654012fSReza Sabdar 
7912654012fSReza Sabdar 	/* append a new record */
7922654012fSReza Sabdar 	(void) strlcpy(tmpdd.dd_name, path, TLM_MAX_PATH_NAME);
7932654012fSReza Sabdar 	tmpdd.dd_level = level;
7942654012fSReza Sabdar 	tmpdd.dd_ddate = ddate;
7952654012fSReza Sabdar 	dumprecout(fp, &tmpdd);
7962654012fSReza Sabdar 
7972654012fSReza Sabdar 	(void) fclose(fp);
7982654012fSReza Sabdar 	(void) rename(bakfpath, fpath);
7992654012fSReza Sabdar 
8002654012fSReza Sabdar 	return (0);
8012654012fSReza Sabdar }
8022654012fSReza Sabdar 
8032654012fSReza Sabdar 
8042654012fSReza Sabdar /*
8052654012fSReza Sabdar  * find_date
8062654012fSReza Sabdar  *
8072654012fSReza Sabdar  * Find the specified date
8082654012fSReza Sabdar  */
8092654012fSReza Sabdar static dumpdates_t *
find_date(dumpdates_t * ddp,char * path,int level,time_t t)8102654012fSReza Sabdar find_date(dumpdates_t *ddp, char *path, int level, time_t t)
8112654012fSReza Sabdar {
8122654012fSReza Sabdar 	for (; ddp; ddp = ddp->dd_next)
8132654012fSReza Sabdar 		if (ddp->dd_level == level && ddp->dd_ddate > t &&
8142654012fSReza Sabdar 		    strcmp(path, ddp->dd_name) == 0)
8152654012fSReza Sabdar 			break;
8162654012fSReza Sabdar 
8172654012fSReza Sabdar 	return (ddp);
8182654012fSReza Sabdar }
8192654012fSReza Sabdar 
8202654012fSReza Sabdar 
8212654012fSReza Sabdar /*
8222654012fSReza Sabdar  * Get the dumpdate of the last level backup done on the path.
823f3012b59SReza Sabdar  * The last level normally is (level - 1) in case of NetBackup
824f3012b59SReza Sabdar  * but some DMAs allow that previous level could be anything
825f3012b59SReza Sabdar  * between 0 and the current level.
8262654012fSReza Sabdar  *
8272654012fSReza Sabdar  * Returns:
8282654012fSReza Sabdar  *   0 on success
8292654012fSReza Sabdar  *   < 0 on error
8302654012fSReza Sabdar  */
8312654012fSReza Sabdar int
ndmpd_get_dumptime(char * path,int * level,time_t * ddate)8322654012fSReza Sabdar ndmpd_get_dumptime(char *path, int *level, time_t *ddate)
8332654012fSReza Sabdar {
8342654012fSReza Sabdar 	int i;
8352654012fSReza Sabdar 	dumpdates_t ddhead, *ddp, *save;
836*9adfa60dSMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
8372654012fSReza Sabdar 	nvlist_t *userprops;
8382654012fSReza Sabdar 	zfs_handle_t *zhp;
839f3012b59SReza Sabdar 	nvlist_t *propval = NULL;
840f3012b59SReza Sabdar 	char *strval = NULL;
8412654012fSReza Sabdar 
8422654012fSReza Sabdar 	if (!path || !level || !ddate)
8432654012fSReza Sabdar 		return (-1);
8442654012fSReza Sabdar 
8452654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "[%s] level %d",
8462654012fSReza Sabdar 	    path, *level);
8472654012fSReza Sabdar 
8482654012fSReza Sabdar 	if (*level == 0) {
8492654012fSReza Sabdar 		*ddate = (time_t)0;
8502654012fSReza Sabdar 		return (0);
8512654012fSReza Sabdar 	}
8522654012fSReza Sabdar 
8532654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
8542654012fSReza Sabdar 	/* Check if this is a ZFS dataset */
8552654012fSReza Sabdar 	if ((zlibh != NULL) &&
8562654012fSReza Sabdar 	    (get_zfsvolname(vol, sizeof (vol), path) == 0) &&
8572654012fSReza Sabdar 	    ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) != NULL)) {
858f3012b59SReza Sabdar 		if ((userprops = zfs_get_user_props(zhp)) == NULL) {
8592654012fSReza Sabdar 			*level = 0;
8602654012fSReza Sabdar 			*ddate = (time_t)0;
8612654012fSReza Sabdar 			zfs_close(zhp);
8622654012fSReza Sabdar 			(void) mutex_unlock(&zlib_mtx);
8632654012fSReza Sabdar 			return (0);
8642654012fSReza Sabdar 		}
865f3012b59SReza Sabdar 		for (i = *level - 1; i >= 0; i--) {
866f3012b59SReza Sabdar 			if (nvlist_lookup_nvlist(userprops,
867f3012b59SReza Sabdar 			    zfs_dumpdate_props[i], &propval) == 0) {
868f3012b59SReza Sabdar 				*level = i;
869f3012b59SReza Sabdar 				break;
870f3012b59SReza Sabdar 			}
871f3012b59SReza Sabdar 		}
872f3012b59SReza Sabdar 		if (propval == NULL ||
873f3012b59SReza Sabdar 		    nvlist_lookup_string(propval, ZPROP_VALUE,
8742654012fSReza Sabdar 		    &strval) != 0) {
8752654012fSReza Sabdar 			*level = 0;
8762654012fSReza Sabdar 			*ddate = (time_t)0;
8772654012fSReza Sabdar 			zfs_close(zhp);
8782654012fSReza Sabdar 			(void) mutex_unlock(&zlib_mtx);
8792654012fSReza Sabdar 			return (0);
8802654012fSReza Sabdar 		}
881f3012b59SReza Sabdar 		if (unctime(strval, ddate) < 0) {
8822654012fSReza Sabdar 			zfs_close(zhp);
8832654012fSReza Sabdar 			(void) mutex_unlock(&zlib_mtx);
8842654012fSReza Sabdar 			return (-1);
8852654012fSReza Sabdar 		}
8862654012fSReza Sabdar 
8872654012fSReza Sabdar 		zfs_close(zhp);
8882654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
8892654012fSReza Sabdar 		return (0);
8902654012fSReza Sabdar 	}
8912654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
8922654012fSReza Sabdar 
8932654012fSReza Sabdar 	(void) memset((void *)&ddhead, 0, sizeof (ddhead));
8942654012fSReza Sabdar 	if (initdumptimes(&ddhead) < 0) {
8952654012fSReza Sabdar 		dd_free(&ddhead);
8962654012fSReza Sabdar 		return (-1);
8972654012fSReza Sabdar 	}
8982654012fSReza Sabdar 
8992654012fSReza Sabdar 	/*
9002654012fSReza Sabdar 	 * Empty dumpdates file means level 0 for all paths.
9012654012fSReza Sabdar 	 */
9022654012fSReza Sabdar 	if ((ddp = ddhead.dd_next) == 0) {
9032654012fSReza Sabdar 		if (!IS_LBR_BKTYPE(*level & 0xff))
9042654012fSReza Sabdar 			*level = 0;
9052654012fSReza Sabdar 		*ddate = 0;
9062654012fSReza Sabdar 		return (0);
9072654012fSReza Sabdar 	}
9082654012fSReza Sabdar 
9092654012fSReza Sabdar 	/*
9102654012fSReza Sabdar 	 * If it's not level backup, then find the exact record
9112654012fSReza Sabdar 	 * type.
9122654012fSReza Sabdar 	 */
9132654012fSReza Sabdar 	if (IS_LBR_BKTYPE(*level & 0xff)) {
9142654012fSReza Sabdar 		save = find_date(ddp, path, *level, *ddate);
9152654012fSReza Sabdar 
9162654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
9172654012fSReza Sabdar 		    "LBR_BKTYPE save 0x%p", save);
9182654012fSReza Sabdar 
9192654012fSReza Sabdar 		*ddate = save ? save->dd_ddate : (time_t)0;
9202654012fSReza Sabdar 	} else {
9212654012fSReza Sabdar 		/*
9222654012fSReza Sabdar 		 * Go find the entry with the same name for a maximum of a
9232654012fSReza Sabdar 		 * lower increment and older date.
9242654012fSReza Sabdar 		 */
9252654012fSReza Sabdar 		save = NULL;
9262654012fSReza Sabdar 		for (i = *level - 1; i >= 0; i--) {
9272654012fSReza Sabdar 			save = find_date(ddp, path, i, *ddate);
9282654012fSReza Sabdar 			if (save) {
9292654012fSReza Sabdar 				*level = save->dd_level;
9302654012fSReza Sabdar 				*ddate = save->dd_ddate;
9312654012fSReza Sabdar 				break;
9322654012fSReza Sabdar 			}
9332654012fSReza Sabdar 		}
9342654012fSReza Sabdar 
9352654012fSReza Sabdar 		if (!save) {
9362654012fSReza Sabdar 			*level = 0;
9372654012fSReza Sabdar 			*ddate = (time_t)0;
9382654012fSReza Sabdar 		}
9392654012fSReza Sabdar 	}
9402654012fSReza Sabdar 
9412654012fSReza Sabdar 	dd_free(&ddhead);
9422654012fSReza Sabdar 
9432654012fSReza Sabdar 	return (0);
9442654012fSReza Sabdar }
9452654012fSReza Sabdar 
9462654012fSReza Sabdar 
9472654012fSReza Sabdar /*
9482654012fSReza Sabdar  * Put the date and the level of the back up for the
9492654012fSReza Sabdar  * specified path in the dumpdates file.  If there is a line
9502654012fSReza Sabdar  * for the same path and the same level, the date is updated.
9512654012fSReza Sabdar  * Otherwise, a line is appended to the file.
9522654012fSReza Sabdar  *
9532654012fSReza Sabdar  * Returns:
9542654012fSReza Sabdar  *   0 on success
9552654012fSReza Sabdar  *   < 0 on error
9562654012fSReza Sabdar  */
9572654012fSReza Sabdar int
ndmpd_put_dumptime(char * path,int level,time_t ddate)9582654012fSReza Sabdar ndmpd_put_dumptime(char *path, int level, time_t ddate)
9592654012fSReza Sabdar {
960*9adfa60dSMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
9612654012fSReza Sabdar 	zfs_handle_t *zhp;
9622654012fSReza Sabdar 	char tbuf[64];
9632654012fSReza Sabdar 	int rv;
9642654012fSReza Sabdar 
9652654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "[%s][%d][%u]", path, level,
9662654012fSReza Sabdar 	    ddate);
9672654012fSReza Sabdar 
9682654012fSReza Sabdar 	/* Check if this is a ZFS dataset */
9692654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
9702654012fSReza Sabdar 	if ((zlibh != NULL) &&
9712654012fSReza Sabdar 	    (get_zfsvolname(vol, sizeof (vol), path) == 0) &&
9722654012fSReza Sabdar 	    ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) != NULL)) {
9732654012fSReza Sabdar 
9742654012fSReza Sabdar 		(void) ctime_r(&ddate, tbuf, sizeof (tbuf));
9752654012fSReza Sabdar 		rv = zfs_prop_set(zhp, zfs_dumpdate_props[level], tbuf);
9762654012fSReza Sabdar 		zfs_close(zhp);
9772654012fSReza Sabdar 
9782654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
9792654012fSReza Sabdar 		return (rv);
9802654012fSReza Sabdar 	}
9812654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
9822654012fSReza Sabdar 
9832654012fSReza Sabdar 	(void) mutex_lock(&ndmp_dd_lock);
9842654012fSReza Sabdar 	rv = putdumptime(path, level, ddate);
9852654012fSReza Sabdar 	(void) mutex_unlock(&ndmp_dd_lock);
9862654012fSReza Sabdar 
9872654012fSReza Sabdar 	return (rv);
9882654012fSReza Sabdar }
9892654012fSReza Sabdar 
9902654012fSReza Sabdar 
9912654012fSReza Sabdar /*
9922654012fSReza Sabdar  * Append a backup date record to the specified file.
9932654012fSReza Sabdar  */
9942654012fSReza Sabdar int
ndmpd_append_dumptime(char * fname,char * path,int level,time_t ddate)9952654012fSReza Sabdar ndmpd_append_dumptime(char *fname, char *path, int level, time_t ddate)
9962654012fSReza Sabdar {
997*9adfa60dSMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
9982654012fSReza Sabdar 	zfs_handle_t *zhp;
9992654012fSReza Sabdar 	char tbuf[64];
10002654012fSReza Sabdar 	int rv;
10012654012fSReza Sabdar 
10022654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "[%s][%s][%d][%u]", fname,
10032654012fSReza Sabdar 	    path, level, ddate);
10042654012fSReza Sabdar 
10052654012fSReza Sabdar 	/* Check if this is a ZFS dataset */
10062654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
10072654012fSReza Sabdar 	if ((zlibh != NULL) &&
10082654012fSReza Sabdar 	    (get_zfsvolname(vol, sizeof (vol), path) == 0) &&
10092654012fSReza Sabdar 	    ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) != NULL)) {
10102654012fSReza Sabdar 
10112654012fSReza Sabdar 		(void) ctime_r(&ddate, tbuf, sizeof (tbuf));
10122654012fSReza Sabdar 		rv = zfs_prop_set(zhp, zfs_dumpdate_props[level], tbuf);
10132654012fSReza Sabdar 		zfs_close(zhp);
10142654012fSReza Sabdar 
10152654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
10162654012fSReza Sabdar 		return (rv);
10172654012fSReza Sabdar 	}
10182654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
10192654012fSReza Sabdar 
10202654012fSReza Sabdar 	(void) mutex_lock(&ndmp_dd_lock);
10212654012fSReza Sabdar 	rv = append_dumptime(fname, path, level, ddate);
10222654012fSReza Sabdar 	(void) mutex_unlock(&ndmp_dd_lock);
10232654012fSReza Sabdar 
10242654012fSReza Sabdar 	return (rv);
10252654012fSReza Sabdar }
1026