--- old/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c	Mon Aug  5 17:15:17 2019
+++ new/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c	Mon Aug  5 17:15:17 2019
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -40,13 +40,16 @@
 
 #include <errno.h>
 #include <signal.h>
-#include <libgen.h>
 #include <libscf.h>
 #include <libintl.h>
 #include <sys/wait.h>
+#include <syslog.h>
+#include <syslog.h>
 #include <zone.h>
 #include <tsol/label.h>
 #include <dlfcn.h>
+#include <sys/mount.h>
+#include <libzfs.h>
 #include "ndmpd.h"
 #include "ndmpd_common.h"
 
@@ -81,7 +84,7 @@
 		return (0);
 
 	if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) {
-		NDMP_LOG(LOG_ERR, "Error loading the plug-in %s: %s",
+		syslog(LOG_ERR, "Error loading the plug-in %s: %s",
 		    plname, dlerror());
 		return (0);
 	}
@@ -92,7 +95,7 @@
 		return (0);
 	}
 	if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) {
-		NDMP_LOG(LOG_ERR, "Error loading the plug-in %s", plname);
+		syslog(LOG_ERR, "Error loading the plug-in %s", plname);
 		return (-1);
 	}
 	return (0);
@@ -184,6 +187,230 @@
 }
 
 /*
+ * Utility routine to check if a zpool is bootable. For the purposes
+ * of cleaning up ndmp backup clones and snapshots, shouldn't consider
+ * the 'boot' volume.
+ *
+ * Parameters:
+ *   zhp (input) - the zfs handle of the zpool dataset.
+ *
+ * Returns:
+ *   B_TRUE : If the given zpool has a boot record
+ *   B_FALSE: otherwise
+ */
+boolean_t
+ndmp_zpool_is_bootable(zpool_handle_t *zhp)
+{
+	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
+
+	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
+	    sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
+	    sizeof (bootfs)) != 0);
+}
+
+/*
+ * This is the zpool_iter() callback routine specifically for
+ * ZFS_TYPE_SNAPSHOTS and is passed in a zfs handle to each one
+ * it finds during iteration.  If this callback returns zero
+ * the iterator keeps going, if it returns non-sero the
+ * iteration stops.
+ *
+ * Parameters:
+ *   zhp (input) - the zfs handle of the ZFS_TYPE_SNAPSHOTS dataset.
+ *   arg (input) - optional parameter (not used in this case)
+ *
+ * Returns:
+ *   0: on success
+ *  -1: otherwise
+ */
+/*ARGSUSED*/
+int
+ndmp_match_and_destroy_snapshot(zfs_handle_t *zhp, void *arg)
+{
+	int err = 0;
+	char *dataset_name;
+	char *snap_name;
+	char *snap_delim;
+	zfs_handle_t *dszhp;
+
+	dataset_name = strdup(zfs_get_name(zhp));
+	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+		if (strstr(dataset_name, NDMP_RCF_BASENAME) != NULL) {
+			snap_delim = strchr(dataset_name, '@');
+			snap_name = snap_delim + 1;
+			*snap_delim = '\0';
+
+			syslog(LOG_DEBUG,
+			    "Remove snap [%s] from dataset [%s] tag [%s]\n",
+			    snap_name, dataset_name, NDMP_RCF_BASENAME);
+
+			if ((dszhp = zfs_open(zlibh, dataset_name,
+			    ZFS_TYPE_DATASET)) != NULL) {
+				if ((err = zfs_release(dszhp, snap_name,
+				    NDMP_RCF_BASENAME, B_FALSE)) != 0) {
+					if (libzfs_errno(zlibh)
+					    != EZFS_REFTAG_RELE) {
+						syslog(LOG_DEBUG,
+						    "(%d) problem zfs_release "
+						    "error:%s action:"
+						    "%s errno:%d\n",
+						    err,
+						    libzfs_error_description(
+						    zlibh),
+						    libzfs_error_action(
+						    zlibh),
+						    libzfs_errno(
+						    zlibh));
+						zfs_close(dszhp);
+						goto _out;
+					}
+				}
+				if ((err = zfs_destroy(zhp, B_FALSE)) != 0) {
+					syslog(LOG_DEBUG,
+					    "(%d)snapshot: problem zfs_destroy "
+					    "error:%s action:%s errno:%d\n",
+					    err,
+					    libzfs_error_description(zlibh),
+					    libzfs_error_action(zlibh),
+					    libzfs_errno(zlibh));
+				}
+				zfs_close(dszhp);
+			} else {
+				err = -1;
+				goto _out;
+			}
+		}
+	}
+_out:
+	free(dataset_name);
+	zfs_close(zhp);
+	return (err);
+}
+
+/*
+ * This is the zpool_iter() callback routine specifically for
+ * ZFS_TYPE_FILESYSTEM and is passed in a zfs handle to each one
+ * it finds during iteration.  If this callback returns zero
+ * the iterator keeps going, if it returns non-sero the
+ * iteration stops.
+ *
+ * Parameters:
+ *   zhp (input) - the zfs handle of the ZFS_TYPE_FILESYSTEM dataset.
+ *   arg (input) - optional parameter (not used in this case)
+ *
+ * Returns:
+ *   0: on success
+ *  -1: otherwise
+ */
+/*ARGSUSED*/
+int
+ndmp_match_and_destroy_filesystem(zfs_handle_t *zhp, void *arg)
+{
+	int err = 0;
+	char *mntpt = NULL;
+	char *dataset_name;
+
+	dataset_name = strdup(zfs_get_name(zhp));
+	if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)  {
+		if (strstr(dataset_name, NDMP_RCF_BASENAME) != NULL) {
+
+			syslog(LOG_DEBUG,
+			    "Remove filesystem [%s]", dataset_name);
+			if (zfs_is_mounted(zhp, &mntpt)) {
+				syslog(LOG_DEBUG,
+				    "mountpoint for snapshot is [%s]\n", mntpt);
+				if (zfs_unmount(zhp, NULL, MS_FORCE) != 0) {
+					syslog(LOG_DEBUG, "Failed to unmount "
+					    "mount point [%s]", mntpt);
+					err = -1;
+					goto _out;
+				}
+			}
+			if (rmdir(mntpt) != 0) {
+				if (errno != ENOENT) {
+					syslog(LOG_DEBUG, "Failed to remove "
+					    "mount point [%s]", mntpt);
+					err = -1;
+					goto _out;
+				}
+			}
+
+			if ((err = zfs_destroy(zhp, B_FALSE)) != 0) {
+				syslog(LOG_DEBUG,
+				    "(%d)filesystem: problem zfs_destroy "
+				    "error:%s action:%s errno:%d\n",
+				    err, libzfs_error_description(zlibh),
+				    libzfs_error_action(zlibh),
+				    libzfs_errno(zlibh));
+			}
+		}
+	}
+_out:
+	free(dataset_name);
+	zfs_close(zhp);
+	return (err);
+}
+
+/*
+ * This is the zpool iterator callback routine.  For each pool on
+ * the system iterate filesystem dependents first then iterate snapshot
+ * dependents and run the corresponding ndmp_match_and_destroy_XXX()
+ * callback. The 'snapshot' are removed second because 'filesystem'
+ * is dependend on its parent 'snapshot'.  If this callback returns
+ * zero the iterator keeps going, if it returns non-sero the
+ * iteration stops.
+ *
+ * Parameters:
+ *   zhp (input) - the zfs handle of the zpool dataset.
+ *   arg (input) - optional parameter (not used in this case)
+ *
+ * Returns:
+ *   0: on success
+ *  -1: otherwise
+ */
+/*ARGSUSED*/
+int
+ndmp_cleanup_snapshots_inpool(zfs_handle_t *zhp, void *arg)
+{
+	const char *zpool_name;
+	int err = 0;
+	zpool_handle_t *php;
+
+	/*
+	 * Check for pools with bootfs entries and skip them
+	 */
+	zpool_name = zfs_get_name(zhp);
+	if ((php = zpool_open(zlibh, zpool_name)) != NULL) {
+		if (!ndmp_zpool_is_bootable(php)) {
+			syslog(LOG_DEBUG,
+			    "Working on pool [%s]\n", zfs_get_name(zhp));
+
+			err = zfs_iter_dependents(zhp, B_FALSE,
+			    ndmp_match_and_destroy_filesystem, (void *)NULL);
+			if (err) {
+				syslog(LOG_ERR,
+				    "cleanup filesystems error: "
+				    "%d on pool [%s]",
+				    err, zpool_name);
+				goto _out;
+			}
+			err = zfs_iter_dependents(zhp,
+			    B_FALSE, ndmp_match_and_destroy_snapshot,
+			    (void *)NULL);
+			if (err) {
+				syslog(LOG_ERR,
+				    "cleanup snapshots error: %d on pool",
+				    err, zpool_name);
+			}
+		}
+	}
+_out:
+	zpool_close(php);
+	zfs_close(zhp);
+	return (err);
+}
+
+/*
  * main
  *
  * The main NDMP daemon function
@@ -203,7 +430,6 @@
 	char c;
 	void *arg = NULL;
 	boolean_t run_in_foreground = B_FALSE;
-	boolean_t override_debug = B_FALSE;
 
 	/*
 	 * Check for existing ndmpd door server (make sure ndmpd is not already
@@ -237,9 +463,6 @@
 	opterr = 0;
 	while ((c = getopt(argc, argv, "df")) != -1) {
 		switch (c) {
-		case 'd':
-			override_debug = B_TRUE;
-			break;
 		case 'f':
 			run_in_foreground = B_TRUE;
 			break;
@@ -246,7 +469,7 @@
 		default:
 			(void) fprintf(stderr, "%s: Invalid option -%c.\n",
 			    argv[0], optopt);
-			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
+			(void) fprintf(stderr, "Usage: %s [-f]\n", argv[0]);
 			exit(SMF_EXIT_ERR_CONFIG);
 		}
 	}
@@ -271,43 +494,44 @@
 
 	set_privileges();
 	(void) umask(077);
-	openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
+	openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_LOCAL4);
 
-	/*
-	 * Open log file before we detach from terminal in case that open
-	 * fails and error message is printed to stderr.
-	 */
-	if (ndmp_log_open_file(run_in_foreground, override_debug) != 0)
-		exit(SMF_EXIT_ERR_FATAL);
-
 	if (!run_in_foreground)
 		daemonize_init();
 
-	(void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL);
-
 	if (mod_init() != 0) {
-		NDMP_LOG(LOG_ERR, "Failed to load the plugin module.");
+		syslog(LOG_ERR, "Failed to load the plugin module.");
 		exit(SMF_EXIT_ERR_CONFIG);
 	}
 
 	/* libzfs init */
 	if ((zlibh = libzfs_init()) == NULL) {
-		NDMP_LOG(LOG_ERR, "Failed to initialize ZFS library.");
+		syslog(LOG_ERR, "Failed to initialize ZFS library.");
 		exit(SMF_EXIT_ERR_CONFIG);
 	}
 
 	/* initialize and start the door server */
 	if (ndmp_door_init()) {
-		NDMP_LOG(LOG_ERR, "Can not start ndmpd door server.");
+		syslog(LOG_ERR, "Can not start ndmpd door server.");
 		exit(SMF_EXIT_ERR_CONFIG);
 	}
 
 	if (tlm_init() == -1) {
-		NDMP_LOG(LOG_ERR, "Failed to initialize tape manager.");
+		syslog(LOG_ERR, "Failed to initialize tape manager.");
 		exit(SMF_EXIT_ERR_CONFIG);
 	}
 
 	/*
+	 * Use libzfs iterator routine to list through all the pools and
+	 * invoke cleanup callback routine on each.
+	 */
+	if (zfs_iter_root(zlibh,
+	    ndmp_cleanup_snapshots_inpool, (void *)NULL) != 0) {
+		syslog(LOG_ERR, "Failed to cleanup leftover snapshots.");
+		exit(SMF_EXIT_ERR_CONFIG);
+	}
+
+	/*
 	 * Prior to this point, we are single-threaded. We will be
 	 * multi-threaded from this point on.
 	 */
@@ -327,7 +551,7 @@
 		case SIGHUP:
 			/* Refresh SMF properties */
 			if (ndmpd_load_prop())
-				NDMP_LOG(LOG_ERR,
+				syslog(LOG_ERR,
 				    "Service properties initialization "
 				    "failed.");
 			break;
@@ -343,11 +567,10 @@
 		ndmpd.s_sigval = 0;
 	}
 
-	(void) mutex_destroy(&ndmpd_zfs_fd_lock);
 	libzfs_fini(zlibh);
 	mod_fini();
 	ndmp_door_fini();
-	ndmp_log_close_file();
+	closelog();
 
 	return (SMF_EXIT_OK);
 }
