12654012fSReza Sabdar /* 2f3012b59SReza Sabdar * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 3*40a5c998SMatthew 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 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 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 * 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 * 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 * 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 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 * 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 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 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 */ 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 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 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 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 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 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 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 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 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 * 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 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*40a5c998SMatthew 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 9582654012fSReza Sabdar ndmpd_put_dumptime(char *path, int level, time_t ddate) 9592654012fSReza Sabdar { 960*40a5c998SMatthew 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 9952654012fSReza Sabdar ndmpd_append_dumptime(char *fname, char *path, int level, time_t ddate) 9962654012fSReza Sabdar { 997*40a5c998SMatthew 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