12654012fSReza Sabdar /*
2f3012b59SReza Sabdar * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3*675fc291SMatthew 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*675fc291SMatthew 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*675fc291SMatthew 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*675fc291SMatthew 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