1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 	- Redistributions of source code must retain the above copyright
15 *	  notice, this list of conditions and the following disclaimer.
16 *
17 * 	- Redistributions in binary form must reproduce the above copyright
18 *	  notice, this list of conditions and the following disclaimer in
19 *	  the documentation and/or other materials provided with the
20 *	  distribution.
21 *
22 *	- Neither the name of The Storage Networking Industry Association (SNIA)
23 *	  nor the names of its contributors may be used to endorse or promote
24 *	  products derived from this software without specific prior written
25 *	  permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <cstack.h>
42#include <ctype.h>
43#include <dirent.h>
44#include <errno.h>
45#include "ndmpd.h"
46#include <bitmap.h>
47#include <traverse.h>
48#include <limits.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <time.h>
53#include "tlm_buffers.h"
54
55
56/*
57 * Parameter passed to traverse for marking inodes
58 * when traversing backup hierarchy in V2.  It
59 * includes:
60 *    mp_bmd: the bitmap describptor.
61 *    mp_ddate: backup date.
62 *    mp_session: pointer to the session structure.
63 *    mp_nlp: pointer to the nlp.
64 *    mp_tacl: pointer to the acl.
65 */
66typedef struct mark_param {
67	int mp_bmd;
68	time_t mp_ddate;
69	ndmpd_session_t *mp_session;
70	ndmp_lbr_params_t *mp_nlp;
71	tlm_acls_t *mp_tacl;
72} mark_param_t;
73
74
75/*
76 * Set this variable to non-zero to print the inodes
77 * marked after traversing file system.
78 */
79static int ndmpd_print_inodes = 0;
80
81
82/*
83 * Flag passed to traverse_post.
84 */
85static int ndmpd_mark_flags = 0;
86
87
88/*
89 * Verbose traversing prints the file/dir path names
90 * if they are being marked.
91 */
92static int ndmpd_verbose_traverse = 0;
93
94
95/*
96 * Set this flag to count the number of inodes marked
97 * after traversing backup hierarchy.
98 */
99static int ndmpd_mark_count_flag = 0;
100
101
102/*
103 * Set this variable to non-zero value to force traversing
104 * backup hierarchy for tar format.
105 */
106static int ndmp_tar_force_traverse = 0;
107
108
109/*
110 * Set this variable to non-zero value to skip processing
111 * directories both for tar and dump.
112 */
113static int ndmp_skip_traverse = 0;
114
115
116/*
117 * count_bits_cb
118 *
119 * Call back for counting the set bits in the dbitmap.
120 *
121 * Parameters:
122 *   bmd (input) - bitmap descriptor
123 *   bn (input) - the bit number
124 *   arg (input) - pointer to the argument
125 *
126 * Returns:
127 *   0: always
128 */
129static int
130count_bits_cb(int bmd, u_longlong_t bn, void *arg)
131{
132	if (dbm_getone(bmd, bn)) {
133		(*(u_longlong_t *)arg)++;
134		if (ndmpd_print_inodes)
135			NDMP_LOG(LOG_DEBUG, "%llu", bn);
136	}
137
138	return (0);
139}
140
141
142/*
143 * count_set_bits
144 *
145 * Count bits set in the bitmap.
146 *
147 * Parameters:
148 *   path (input) - the backup path
149 *   bmd (input) - bitmap descriptor
150 *
151 * Returns:
152 *   void
153 */
154void
155count_set_bits(char *path, int bmd)
156{
157	u_longlong_t cnt;
158
159	if (!ndmpd_mark_count_flag)
160		return;
161
162	cnt = 0;
163	(void) dbm_apply_ifset(bmd, count_bits_cb, &cnt);
164	NDMP_LOG(LOG_DEBUG, "%s %llu inodes marked", path, cnt);
165}
166
167
168/*
169 * traverse
170 *
171 * Starts the post-traverse the backup hierarchy.  Checks
172 * for exceptional cases, like aborting operation and if
173 * asked, report detailed information after traversing.
174 *
175 * Parameters:
176 *   session (input) - pointer to the session
177 *   nlp (input) - pointer to the nlp structure
178 *   ftp (input) - pointer to the traverse parameters
179 *
180 * Returns:
181 *   0: on success
182 *   != 0: otherwise
183 */
184int
185traverse(ndmpd_session_t *session, ndmp_lbr_params_t *nlp,
186    fs_traverse_t *ftp)
187{
188	int rv;
189	time_t s, e;
190
191	if (!session || !nlp || !ftp) {
192		NDMP_LOG(LOG_DEBUG, "Invalid argument");
193		return (-1);
194	}
195	NDMP_LOG(LOG_DEBUG, "Processing directories of \"%s\"",
196	    nlp->nlp_backup_path);
197
198	(void) time(&s);
199	if (traverse_post(ftp) != 0) {
200		rv = -1;
201		if (!session->ns_data.dd_abort && !NLP_ISSET(nlp,
202		    NLPF_ABORTED)) {
203			NDMP_LOG(LOG_DEBUG,
204			    "Traversing backup path hierarchy \"%s\"",
205			    nlp->nlp_backup_path);
206		}
207	} else {
208		(void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
209		rv = 0;
210		(void) time(&e);
211		NDMP_LOG(LOG_DEBUG,
212		    "\"%s\" traversed in %u sec", nlp->nlp_backup_path,
213		    (uint_t)(e-s));
214
215		count_set_bits(nlp->nlp_backup_path, nlp->nlp_bkmap);
216	}
217
218	return (rv);
219}
220
221
222/*
223 * mark_cb
224 *
225 * The callback function, called by traverse_post to mark bits
226 * in the bitmap.
227 *
228 * Set the bit of the entry if it's been modified (obviously
229 * should be backed up) plus its parent directory.
230 *
231 * If the entry is a directory and is not modified itself,
232 * but it's marked, then there is something below it that
233 * is being backed up.  It shows the the path, leads to
234 * an object that will be backed up. So the path should
235 * be marked too.
236 *
237 * The backup path itself is always marked.
238 *
239 * Parameters:
240 *   arg (input) - pointer to the mark parameter
241 *   pnp (input) - pointer to the path node
242 *   enp (input) - pointer to the entry node
243 *
244 * Returns:
245 *   0: as long as traversing should continue
246 *   != 0: if traversing should stop
247 */
248int
249mark_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
250{
251	int bmd;
252	int rv;
253	u_longlong_t bl;
254	time_t ddate;
255	fs_fhandle_t *pfhp, *efhp;
256	struct stat64 *pstp, *estp;
257	mark_param_t *mpp;
258	ndmp_lbr_params_t *nlp;
259	tlm_acls_t *tacl;
260
261	rv = 0;
262	mpp = (mark_param_t *)arg;
263	tacl = mpp->mp_tacl;
264	nlp = ndmp_get_nlp(mpp->mp_session);
265	if (!mpp) {
266		NDMP_LOG(LOG_DEBUG, "NULL argument passed");
267		rv = -1;
268	} else if (mpp->mp_session->ns_eof) {
269		NDMP_LOG(LOG_INFO, "Connection to the client is closed");
270		rv = -1;
271	} else if (mpp->mp_session->ns_data.dd_abort ||
272	    (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
273		NDMP_LOG(LOG_INFO, "Processing directories aborted.");
274		rv = -1;
275	}
276
277	if (rv != 0)
278		return (rv);
279
280	ddate = mpp->mp_ddate;
281	bmd = mpp->mp_bmd;
282	bl = dbm_getlen(bmd);
283
284	pfhp = pnp->tn_fh;
285	pstp = pnp->tn_st;
286
287	/* sanity check on fh and stat of the path passed */
288	if (pstp->st_ino > bl) {
289		NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
290		    (uint_t)pstp->st_ino);
291		return (-1);
292	}
293	if (pstp->st_ino != pfhp->fh_fid) {
294		NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
295		    (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
296		return (-1);
297	}
298
299	/*
300	 * Always mark the backup path inode number.
301	 */
302	if (!enp->tn_path) {
303		(void) dbm_setone(bmd, pstp->st_ino);
304		return (0);
305	}
306
307	efhp = enp->tn_fh;
308	estp = enp->tn_st;
309
310	/* sanity check on fh and stat of the entry passed */
311	if (estp->st_ino > bl) {
312		NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
313		    (uint_t)estp->st_ino);
314		return (-1);
315	}
316	if (estp->st_ino != efhp->fh_fid) {
317		NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
318		    (uint_t)pfhp->fh_fid);
319		return (-1);
320	}
321
322	/* check the dates and mark the bitmap inode */
323	if (ddate == 0) {
324		/* base backup */
325		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
326		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
327		if (ndmpd_verbose_traverse) {
328			NDMP_LOG(LOG_DEBUG, "Base Backup");
329			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
330			    pnp->tn_path, enp->tn_path);
331		}
332
333	} else if (estp->st_mtime > ddate) {
334		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
335		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
336		if (ndmpd_verbose_traverse) {
337			NDMP_LOG(LOG_DEBUG,
338			    "m(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
339			    (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
340			    (uint_t)ddate);
341			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
342			    pnp->tn_path, enp->tn_path);
343		}
344	} else if (iscreated(nlp, NULL, tacl, ddate)) {
345		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
346		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
347		if (ndmpd_verbose_traverse) {
348			NDMP_LOG(LOG_DEBUG,
349			    "cr(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
350			    (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
351			    (uint_t)ddate);
352			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
353			    pnp->tn_path, enp->tn_path);
354		}
355	} else if (estp->st_ctime > ddate) {
356		if (!NLP_IGNCTIME(nlp)) {
357			(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
358			(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
359		}
360		if (ndmpd_verbose_traverse) {
361			if (NLP_IGNCTIME(nlp)) {
362				NDMP_LOG(LOG_DEBUG,
363				    "ign c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
364				    (uint_t)estp->st_ino,
365				    (uint_t)estp->st_ctime, (uint_t)ddate);
366			} else {
367				NDMP_LOG(LOG_DEBUG,
368				    "c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
369				    (uint_t)estp->st_ino,
370				    (uint_t)estp->st_ctime, (uint_t)ddate);
371			}
372			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
373			    pnp->tn_path, enp->tn_path);
374		}
375	} else if (S_ISDIR(estp->st_mode) &&
376	    dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
377		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
378		if (ndmpd_verbose_traverse) {
379			NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
380			    (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
381			NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
382			    pnp->tn_path, enp->tn_path);
383		}
384	}
385
386	return (0);
387}
388
389
390/*
391 * mark_inodes_v2
392 *
393 * Traverse the file system in post-order and mark
394 * all the modified objects and also directories leading
395 * to them.
396 *
397 * Parameters:
398 *   session (input) - pointer to the session
399 *   nlp (input) - pointer to the nlp structure
400 *   path (input) - the physical path to traverse
401 *
402 * Returns:
403 *   0: on success.
404 *   != 0: on error.
405 */
406int
407mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
408{
409	fs_traverse_t ft;
410	mark_param_t mp;
411
412	if (!session || !nlp || !path || !*path) {
413		NDMP_LOG(LOG_DEBUG, "Invalid argument");
414		return (-1);
415	}
416
417	NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);
418
419	mp.mp_bmd = nlp->nlp_bkmap;
420	mp.mp_ddate = nlp->nlp_ldate;
421	mp.mp_session = session;
422	mp.mp_nlp = nlp;
423
424	ft.ft_path = path;
425	ft.ft_lpath = nlp->nlp_backup_path;
426	ft.ft_callbk = mark_cb;
427	ft.ft_arg = &mp;
428	ft.ft_logfp = (ft_log_t)ndmp_log;
429	ft.ft_flags = ndmpd_mark_flags;
430
431	return (traverse(session, nlp, &ft));
432}
433
434
435/*
436 * create_bitmap
437 *
438 * Create a dbitmap and return its descriptor.
439 *
440 * Parameters:
441 *   path (input) - path for which the bitmap should be created
442 *   value (input) - the initial value for the bitmap
443 *
444 * Returns:
445 *   the dbitmap descriptor
446 */
447static int
448create_bitmap(char *path, int value)
449{
450	char bm_fname[PATH_MAX];
451	char buf[TLM_MAX_PATH_NAME];
452	char *livepath;
453	ulong_t ninode;
454
455	NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);
456
457	if (fs_is_chkpntvol(path))
458		livepath = (char *)tlm_remove_checkpoint(path, buf);
459	else
460		livepath = path;
461	ninode = 1024 * 1024 * 1024;
462	if (ninode == 0)
463		return (-1);
464	(void) ndmpd_mk_temp(bm_fname);
465
466	NDMP_LOG(LOG_DEBUG, "path \"%s\"ninode %u bm_fname \"%s\"",
467	    livepath, ninode, bm_fname);
468
469	return (dbm_alloc(bm_fname, (u_longlong_t)ninode, value));
470}
471
472
473/*
474 * create_allset_bitmap
475 *
476 * A helper function to create a bitmap with all the
477 * values set to 1.
478 *
479 * Parameters:
480 *   nlp (input) - pointer to the nlp structure
481 *
482 * Returns:
483 *   the dbitmap descriptor
484 */
485static int
486create_allset_bitmap(ndmp_lbr_params_t *nlp)
487{
488	int rv;
489
490	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 1);
491	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
492
493	if (nlp->nlp_bkmap < 0) {
494		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
495		rv = -1;
496	} else
497		rv = 0;
498
499	return (rv);
500}
501
502
503/*
504 * mark_common_v2
505 *
506 * Create the inode bitmap.  If last date of the the
507 * backup is epoch, then all the objects should be backed
508 * up; there is no need to traverse the backup hierarchy
509 * and mark the inodes.  All the bits should be marked.
510 *
511 * Otherwise, the backup hierarchy should be traversed and
512 * the objects should be marked.
513 *
514 * Parameters:
515 *   session (input) - pointer to the session
516 *   nlp (input) - pointer to the nlp structure
517 *
518 * Returns:
519 *   0: on success.
520 *   != 0: on error.
521 */
522static int
523mark_common_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
524{
525	char buf[TLM_MAX_PATH_NAME], *chkpath;
526	int rv;
527
528	/*
529	 * Everything is needed for full backup.
530	 */
531	if (nlp->nlp_ldate == (time_t)0)
532		return (create_allset_bitmap(nlp));
533
534	rv = 0;
535	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
536	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
537
538	if (nlp->nlp_bkmap < 0) {
539		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
540		rv = -1;
541	} else {
542		if (fs_is_chkpntvol(nlp->nlp_backup_path))
543			chkpath = nlp->nlp_backup_path;
544		else
545			chkpath = tlm_build_snapshot_name(
546			    nlp->nlp_backup_path, buf,
547			    nlp->nlp_jstat->js_job_name);
548		rv = mark_inodes_v2(session, nlp, chkpath);
549		(void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
550	}
551
552	return (rv);
553}
554
555
556/*
557 * mark_tar_inodes_v2
558 *
559 * Create the bitmap for tar backup format.
560 *
561 * Parameters:
562 *   session (input) - pointer to the session
563 *   nlp (input) - pointer to the nlp structure
564 *
565 * Returns:
566 *   0: on success.
567 *   != 0: on error.
568 */
569static int
570mark_tar_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
571{
572	int rv;
573
574	if (ndmp_tar_force_traverse)
575		rv = mark_common_v2(session, nlp);
576	else
577		rv = create_allset_bitmap(nlp);
578
579	return (rv);
580}
581
582
583/*
584 * mark_dump_inodes_v2
585 *
586 * Create the bitmap for dump backup format.
587 *
588 * Parameters:
589 *   session (input) - pointer to the session
590 *   nlp (input) - pointer to the nlp structure
591 *
592 * Returns:
593 *   0: on success.
594 *   != 0: on error.
595 */
596static int
597mark_dump_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
598{
599	return (mark_common_v2(session, nlp));
600}
601
602
603/*
604 * ndmpd_mark_inodes_v2
605 *
606 * Mark the inodes of the backup hierarchy if necessary.
607 *
608 * Parameters:
609 *   session (input) - pointer to the session
610 *   nlp (input) - pointer to the nlp structure
611 *
612 * Returns:
613 *   0: on success.
614 *   != 0: on error.
615 */
616int
617ndmpd_mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
618{
619	int rv;
620
621	if (ndmp_skip_traverse) {
622		NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
623		    nlp->nlp_backup_path);
624		rv = create_allset_bitmap(nlp);
625	} else {
626		if (NLP_ISTAR(nlp))
627			rv = mark_tar_inodes_v2(session, nlp);
628		else if (NLP_ISDUMP(nlp))
629			rv = mark_dump_inodes_v2(session, nlp);
630		else {
631			NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
632			    nlp->nlp_backup_path);
633			rv = -1;
634		}
635	}
636
637	return (rv);
638}
639
640
641/*
642 * ndmpd_abort_making_v2
643 *
644 * Abort the process of marking inodes.
645 *
646 * Parameters:
647 *   session (input) - pointer to the session
648 *
649 * Returns:
650 *   void
651 */
652void
653ndmpd_abort_marking_v2(ndmpd_session_t *session)
654{
655	ndmp_lbr_params_t *nlp;
656
657	nlp = ndmp_get_nlp(session);
658	if (nlp)
659		NLP_SET(nlp, NLPF_ABORTED);
660}
661
662
663/*
664 * mark_tokv3
665 *
666 * Traverse the backup hierarchy and mark the bits for the
667 * modified objects of directories leading to a modified
668 * object for the token-based backup.
669 *
670 * Parameters:
671 *   session (input) - pointer to the session
672 *   nlp (input) - pointer to the nlp structure
673 *   path (input) - the physical path to traverse
674 *
675 * Returns:
676 *   0: on success
677 *   != 0: otherwise
678 */
679int
680mark_tokv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
681{
682	fs_traverse_t ft;
683	mark_param_t mp;
684
685	if (!session || !nlp || !path || !*path) {
686		NDMP_LOG(LOG_DEBUG, "Invalid argument");
687		return (-1);
688	}
689	if (nlp->nlp_tokdate == (time_t)0)
690		return (create_allset_bitmap(nlp));
691
692	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
693	if (nlp->nlp_bkmap < 0) {
694		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
695		return (-1);
696	}
697	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
698
699	mp.mp_bmd = nlp->nlp_bkmap;
700	mp.mp_ddate = nlp->nlp_tokdate;
701	mp.mp_session = session;
702	mp.mp_nlp = nlp;
703
704	ft.ft_path = path;
705	ft.ft_lpath = nlp->nlp_backup_path;
706	ft.ft_callbk = mark_cb;
707	ft.ft_arg = &mp;
708	ft.ft_logfp = (ft_log_t)ndmp_log;
709	ft.ft_flags = ndmpd_mark_flags;
710
711	return (traverse(session, nlp, &ft));
712}
713
714
715/*
716 * marklbrv3_cb
717 *
718 * The callback function, called by traverse_post to mark
719 * bits in the bitmap.
720 *
721 * It's so much like mark_cb for time-based (token-based
722 * and level-type) backup types, except that it looks at
723 * the archive bit of the objects instead of their timestamp.
724 *
725 * Parameters:
726 *   arg (input) - pointer to the mark parameter
727 *   pnp (input) - pointer to the path node
728 *   enp (input) - pointer to the entry node
729 *
730 * Returns:
731 *   0: as long as traversing should continue
732 *   != 0: if traversing should stop
733 */
734int
735marklbrv3_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
736{
737	int bmd;
738	u_longlong_t bl;
739	fs_fhandle_t *pfhp, *efhp;
740	struct stat64 *pstp, *estp;
741	mark_param_t *mpp;
742	ndmp_lbr_params_t *nlp;
743
744	mpp = (mark_param_t *)arg;
745	if (!mpp) {
746		NDMP_LOG(LOG_DEBUG, "NULL argument passed");
747		return (-1);
748	}
749	nlp = ndmp_get_nlp(mpp->mp_session);
750	if (mpp->mp_session->ns_data.dd_abort ||
751	    (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
752		NDMP_LOG(LOG_INFO, "Processing directories aborted.");
753		return (-1);
754	}
755
756	bmd = mpp->mp_bmd;
757	bl = dbm_getlen(bmd);
758
759	pfhp = pnp->tn_fh;
760	pstp = pnp->tn_st;
761
762	/* sanity check on fh and stat of the path passed */
763	if (pstp->st_ino > bl) {
764		NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
765		    (uint_t)pstp->st_ino);
766		return (-1);
767	}
768	if (pstp->st_ino != pfhp->fh_fid) {
769		NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
770		    (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
771		return (-1);
772	}
773
774	/*
775	 * Always mark the backup path inode number.
776	 */
777	if (!enp->tn_path) {
778		(void) dbm_setone(bmd, pstp->st_ino);
779		if (ndmpd_verbose_traverse) {
780			NDMP_LOG(LOG_DEBUG, "d(%u)", (uint_t)pstp->st_ino);
781			NDMP_LOG(LOG_DEBUG, "\"%s\"", pnp->tn_path);
782		}
783		return (0);
784	}
785
786	efhp = enp->tn_fh;
787	estp = enp->tn_st;
788
789	/* sanity check on fh and stat of the entry passed */
790	if (estp->st_ino > bl) {
791		NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
792		    (uint_t)estp->st_ino);
793		return (-1);
794	}
795	if (estp->st_ino != efhp->fh_fid) {
796		NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
797		    (uint_t)pfhp->fh_fid);
798		return (-1);
799	}
800
801	if (S_ISDIR(estp->st_mode) &&
802	    dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
803		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
804		if (ndmpd_verbose_traverse) {
805			NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
806			    (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
807			NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
808			    pnp->tn_path, enp->tn_path);
809		}
810	}
811
812	return (0);
813}
814
815
816/*
817 * mark_lbrv3
818 *
819 * Traverse the backup hierarchy and mark the bits for the
820 * modified objects of directories leading to a modified
821 * object for the LBR-type backup.
822 *
823 * Parameters:
824 *   session (input) - pointer to the session
825 *   nlp (input) - pointer to the nlp structure
826 *   path (input) - the physical path to traverse
827 *
828 * Returns:
829 *   0: on success
830 *   != 0: otherwise
831 */
832int
833mark_lbrv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
834{
835	char c;
836	fs_traverse_t ft;
837	mark_param_t mp;
838
839	if (!session || !nlp || !path || !*path) {
840		NDMP_LOG(LOG_DEBUG, "Invalid argument");
841		return (-1);
842	}
843	/* full and archive backups backup everything */
844	c = toupper(nlp->nlp_clevel);
845	if (c == 'F' || c == 'A')
846		return (create_allset_bitmap(nlp));
847
848	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
849	if (nlp->nlp_bkmap < 0) {
850		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
851		return (-1);
852	}
853	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
854
855	mp.mp_bmd = nlp->nlp_bkmap;
856	mp.mp_ddate = 0;
857	mp.mp_session = session;
858	mp.mp_nlp = nlp;
859
860	ft.ft_path = path;
861	ft.ft_lpath = nlp->nlp_backup_path;
862	ft.ft_callbk = marklbrv3_cb;
863	ft.ft_arg = &mp;
864	ft.ft_logfp = (ft_log_t)ndmp_log;
865	ft.ft_flags = ndmpd_mark_flags;
866
867	return (traverse(session, nlp, &ft));
868}
869
870
871/*
872 * mark_levelv3
873 *
874 * Traverse the backup hierarchy and mark the bits for the
875 * modified objects of directories leading to a modified
876 * object for the level-type backup.
877 *
878 * Parameters:
879 *   session (input) - pointer to the session
880 *   nlp (input) - pointer to the nlp structure
881 *   path (input) - the physical path to traverse
882 *
883 * Returns:
884 *   0: on success
885 *   != 0: otherwise
886 */
887int
888mark_levelv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
889{
890	fs_traverse_t ft;
891	mark_param_t mp;
892	tlm_acls_t traverse_acl;
893
894	if (!session || !nlp || !path || !*path) {
895		NDMP_LOG(LOG_DEBUG, "Invalid argument");
896		return (-1);
897	}
898	if (nlp->nlp_ldate == (time_t)0)
899		return (create_allset_bitmap(nlp));
900
901	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
902	if (nlp->nlp_bkmap < 0) {
903		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
904		return (-1);
905	}
906	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
907
908	/*
909	 * We do not want to allocate memory for acl every time we
910	 * process a file.
911	 */
912	(void) memset(&traverse_acl, 0, sizeof (traverse_acl));
913	mp.mp_tacl = &traverse_acl;
914
915	mp.mp_bmd = nlp->nlp_bkmap;
916	mp.mp_ddate = nlp->nlp_ldate;
917	mp.mp_session = session;
918	mp.mp_nlp = nlp;
919
920	ft.ft_path = path;
921	ft.ft_lpath = nlp->nlp_backup_path;
922	ft.ft_callbk = mark_cb;
923	ft.ft_arg = &mp;
924	ft.ft_logfp = (ft_log_t)ndmp_log;
925	ft.ft_flags = ndmpd_mark_flags;
926
927	return (traverse(session, nlp, &ft));
928}
929
930
931/*
932 * mark_commonv3
933 *
934 * Create the inode bitmap.  If last date of the the
935 * backup is epoch, then all the objects should be backed
936 * up; there is no need to traverse the backup hierarchy
937 * and mark the inodes.  All the bits should be marked.
938 *
939 * Otherwise, the backup hierarchy should be traversed and
940 * the objects should be marked.
941 *
942 * Parameters:
943 *   session (input) - pointer to the session
944 *   nlp (input) - pointer to the nlp structure
945 *
946 * Returns:
947 *   0: on success.
948 *   != 0: on error.
949 */
950int
951mark_commonv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
952{
953	char buf[TLM_MAX_PATH_NAME], *chkpath;
954	int rv;
955
956	if (NLP_ISCHKPNTED(nlp))
957		chkpath = nlp->nlp_backup_path;
958	else
959		chkpath = tlm_build_snapshot_name(nlp->nlp_backup_path, buf,
960		    nlp->nlp_jstat->js_job_name);
961
962	if (NLP_ISSET(nlp, NLPF_TOKENBK))
963		rv = mark_tokv3(session, nlp, chkpath);
964	else if (NLP_ISSET(nlp, NLPF_LBRBK))
965		rv = mark_lbrv3(session, nlp, chkpath);
966	else if (NLP_ISSET(nlp, NLPF_LEVELBK)) {
967		rv = mark_levelv3(session, nlp, chkpath);
968	} else {
969		rv = -1;
970		NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
971		    nlp->nlp_backup_path);
972	}
973
974	return (rv);
975}
976
977
978/*
979 * mark_tar_inodesv3
980 *
981 * Mark bits for tar backup format of V3.  Normally, the
982 * backup hierarchy is not traversed for tar format
983 * unless it's forced by setting the ndmp_tar_force_traverse
984 * to a non-zero value.
985 *
986 * Parameters:
987 *   session (input) - pointer to the session
988 *   nlp (input) - pointer to the nlp structure
989 *
990 * Returns:
991 *   0: on success
992 *   != 0: otherwise
993 */
994int
995mark_tar_inodesv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
996{
997	int rv;
998
999	if (ndmp_tar_force_traverse)
1000		rv = mark_commonv3(session, nlp);
1001	else
1002		rv = create_allset_bitmap(nlp);
1003
1004	return (rv);
1005}
1006
1007
1008/*
1009 * ndmpd_mark_inodes_v3
1010 *
1011 * Mark the inodes of the backup hierarchy if necessary.
1012 *
1013 * Parameters:
1014 *   session (input) - pointer to the session
1015 *   nlp (input) - pointer to the nlp structure
1016 *
1017 * Returns:
1018 *   0: on success.
1019 *   != 0: on error.
1020 */
1021int
1022ndmpd_mark_inodes_v3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
1023{
1024	int rv;
1025
1026	if (ndmp_skip_traverse) {
1027		NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
1028		    nlp->nlp_backup_path);
1029		rv = create_allset_bitmap(nlp);
1030	} else {
1031		if (NLP_ISTAR(nlp))
1032			rv = mark_tar_inodesv3(session, nlp);
1033		else if (NLP_ISDUMP(nlp)) {
1034			rv = mark_commonv3(session, nlp);
1035		} else {
1036			NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
1037			    nlp->nlp_backup_path);
1038			rv = -1;
1039		}
1040	}
1041
1042	return (rv);
1043}
1044