1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 #include <stdio.h>
39 #include <limits.h>
40 #include <time.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #include <dirent.h>
44 #include <pthread.h>
45 #include <archives.h>
46 #include <tlm.h>
47 #include <sys/fs/zfs.h>
48 #include <sys/mkdev.h>
49 #include <libzfs.h>
50 #include <libcmdutils.h>
51 #include <pwd.h>
52 #include <grp.h>
53 #include "tlm_proto.h"
54
55
56 static char *get_write_buffer(long size,
57 long *actual_size,
58 boolean_t zero,
59 tlm_cmd_t *);
60 static int output_acl_header(sec_attr_t *,
61 tlm_cmd_t *);
62 static int output_file_header(char *name,
63 char *link,
64 tlm_acls_t *,
65 int section,
66 tlm_cmd_t *);
67 static int output_xattr_header(char *fname,
68 char *aname,
69 int fd,
70 tlm_acls_t *,
71 int section,
72 tlm_cmd_t *);
73
74 extern libzfs_handle_t *zlibh;
75 extern mutex_t zlib_mtx;
76
77 #define S_ISPECIAL(a) (S_ISLNK(a) || S_ISFIFO(a) || S_ISBLK(a) || \
78 S_ISCHR(a))
79
80 /*
81 * output_mem
82 *
83 * Gets a IO write buffer and copies memory to the that.
84 */
85 static void
output_mem(tlm_cmd_t * local_commands,char * mem,int len)86 output_mem(tlm_cmd_t *local_commands, char *mem,
87 int len)
88 {
89 long actual_size, rec_size;
90 char *rec;
91
92 while (len > 0) {
93 rec = get_write_buffer(len, &actual_size,
94 FALSE, local_commands);
95 rec_size = min(actual_size, len);
96 (void) memcpy(rec, mem, rec_size);
97 mem += rec_size;
98 len -= rec_size;
99 }
100 }
101
102 /*
103 * tlm_output_dir
104 *
105 * Put the directory information into the output buffers.
106 */
107 int
tlm_output_dir(char * name,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)108 tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
109 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
110 {
111 u_longlong_t pos;
112
113 /*
114 * Send the node or path history of the directory itself.
115 */
116 pos = tlm_get_data_offset(local_commands);
117 NDMP_LOG(LOG_DEBUG, "pos: %10lld [%s]", pos, name);
118 (void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
119 (void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
120 /* fhdir_cb is handled in ndmpd_tar3.c */
121
122 (void) output_acl_header(&tlm_acls->acl_info,
123 local_commands);
124 (void) output_file_header(name, "", tlm_acls, 0,
125 local_commands);
126
127 return (0);
128 }
129
130 /*
131 * tar_putdir
132 *
133 * Main dir backup function for tar
134 */
135 int
tar_putdir(char * name,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)136 tar_putdir(char *name, tlm_acls_t *tlm_acls,
137 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
138 {
139 int rv;
140
141 rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
142 return (rv < 0 ? rv : 0);
143 }
144
145 /*
146 * output_acl_header
147 *
148 * output the ACL header record and data
149 */
150 static int
output_acl_header(sec_attr_t * acl_info,tlm_cmd_t * local_commands)151 output_acl_header(sec_attr_t *acl_info,
152 tlm_cmd_t *local_commands)
153 {
154 long actual_size;
155 tlm_tar_hdr_t *tar_hdr;
156 long acl_size;
157
158 if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
159 return (0);
160
161 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
162 &actual_size, TRUE, local_commands);
163 if (!tar_hdr)
164 return (0);
165
166 tar_hdr->th_linkflag = LF_ACL;
167 acl_info->attr_type = UFSD_ACL;
168 (void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
169 "%06o", strlen(acl_info->attr_info));
170
171 acl_size = sizeof (*acl_info);
172 (void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
173 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
174 acl_size);
175 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
176 0444);
177 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
178 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
179 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
180 "%011o ", 0);
181 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
182 sizeof (tar_hdr->th_magic));
183
184 tlm_build_header_checksum(tar_hdr);
185
186 (void) output_mem(local_commands, (void *)acl_info, acl_size);
187 return (0);
188 }
189
190 /*
191 * output_humongus_header
192 *
193 * output a special header record for HUGE files
194 * output is: 1) a TAR "HUGE" header redord
195 * 2) a "file" of size, name
196 */
197 static int
output_humongus_header(char * fullname,longlong_t file_size,tlm_cmd_t * local_commands)198 output_humongus_header(char *fullname, longlong_t file_size,
199 tlm_cmd_t *local_commands)
200 {
201 char *buf;
202 int len;
203 long actual_size;
204 tlm_tar_hdr_t *tar_hdr;
205
206 /*
207 * buf will contain: "%llu %s":
208 * - 20 is the maximum length of 'ulong_tlong' decimal notation.
209 * - The first '1' is for the ' ' between the "%llu" and the fullname.
210 * - The last '1' is for the null-terminator of fullname.
211 */
212 len = 20 + 1 + strlen(fullname) + 1;
213
214 if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
215 return (-1);
216
217 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
218 &actual_size, TRUE, local_commands);
219 if (!tar_hdr) {
220 free(buf);
221 return (0);
222 }
223
224 tar_hdr->th_linkflag = LF_HUMONGUS;
225 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
226 len);
227 tlm_build_header_checksum(tar_hdr);
228 (void) snprintf(buf, len, "%lld %s", file_size, fullname);
229 (void) output_mem(local_commands, buf, len);
230
231 free(buf);
232 return (0);
233 }
234
235
236 /*
237 * output_xattr_header
238 *
239 * output the TAR header record for extended attributes
240 */
241 static int
output_xattr_header(char * fname,char * aname,int fd,tlm_acls_t * tlm_acls,int section,tlm_cmd_t * local_commands)242 output_xattr_header(char *fname, char *aname, int fd,
243 tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
244 {
245 struct stat64 *attr = &tlm_acls->acl_attr;
246 struct xattr_hdr *xhdr;
247 struct xattr_buf *xbuf;
248 tlm_tar_hdr_t *tar_hdr;
249 long actual_size;
250 char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
251 int hsize;
252 int comlen;
253 int namesz;
254
255 if (section_name == NULL)
256 return (-TLM_NO_SCRATCH_SPACE);
257
258 if (fstat64(fd, attr) == -1) {
259 NDMP_LOG(LOG_DEBUG, "output_file_header stat failed.");
260 free(section_name);
261 return (-TLM_OPEN_ERR);
262 }
263
264 /*
265 * if the file has to go out in sections,
266 * we must mung the name.
267 */
268 if (section == 0) {
269 (void) snprintf(section_name, TLM_MAX_PATH_NAME,
270 "/dev/null/%s.hdr", aname);
271 } else {
272 (void) snprintf(section_name,
273 TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
274 }
275 namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
276 hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
277 comlen = namesz + sizeof (struct xattr_buf);
278
279 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
280 &actual_size, TRUE, local_commands);
281 if (!tar_hdr) {
282 free(section_name);
283 return (0);
284 }
285
286 (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
287
288 tar_hdr->th_linkflag = LF_XATTR;
289 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
290 hsize);
291 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
292 attr->st_mode & 07777);
293 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
294 attr->st_uid);
295 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
296 attr->st_gid);
297 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
298 attr->st_mtime);
299 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
300 sizeof (tar_hdr->th_magic));
301
302 NDMP_LOG(LOG_DEBUG, "xattr_hdr: %s size %d mode %06o uid %d gid %d",
303 aname, hsize, attr->st_mode & 07777, attr->st_uid, attr->st_gid);
304
305 tlm_build_header_checksum(tar_hdr);
306
307 xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
308 &actual_size, TRUE, local_commands);
309 if (!xhdr) {
310 free(section_name);
311 return (0);
312 }
313
314 (void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
315 XATTR_ARCH_VERS);
316 (void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
317 sizeof (xhdr->h_size) - 1, hsize);
318 (void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
319 "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
320 (void) snprintf(xhdr->h_link_component_len,
321 sizeof (xhdr->h_link_component_len), "%0*d",
322 sizeof (xhdr->h_link_component_len) - 1, 0);
323
324 xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
325 sizeof (struct xattr_hdr));
326 (void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
327 sizeof (xbuf->h_namesz) - 1, namesz);
328
329 /* No support for links in extended attributes */
330 xbuf->h_typeflag = LF_NORMAL;
331
332 (void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
333 (void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
334 TLM_NAME_SIZE);
335
336 free(section_name);
337 return (0);
338 }
339
340
341 /*
342 * output_file_header
343 *
344 * output the TAR header record
345 */
346 static int
output_file_header(char * name,char * link,tlm_acls_t * tlm_acls,int section,tlm_cmd_t * local_commands)347 output_file_header(char *name, char *link,
348 tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
349 {
350 static longlong_t file_count = 0;
351 struct stat64 *attr = &tlm_acls->acl_attr;
352 tlm_tar_hdr_t *tar_hdr;
353 long actual_size;
354 boolean_t long_name = FALSE;
355 boolean_t long_link = FALSE;
356 char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
357 int nmlen, lnklen;
358 uid_t uid;
359 gid_t gid;
360 char *uname = "";
361 char *gname = "";
362 struct passwd *pwd;
363 struct group *grp;
364
365 if (section_name == NULL)
366 return (-TLM_NO_SCRATCH_SPACE);
367
368 /*
369 * if the file has to go out in sections,
370 * we must mung the name.
371 */
372 if (section == 0) {
373 (void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
374 } else {
375 (void) snprintf(section_name,
376 TLM_MAX_PATH_NAME, "%s.%03d", name, section);
377 }
378
379 if ((pwd = getpwuid(attr->st_uid)) != NULL)
380 uname = pwd->pw_name;
381 if ((grp = getgrgid(attr->st_gid)) != NULL)
382 gname = grp->gr_name;
383
384 if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
385 uid = UID_NOBODY;
386 if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
387 gid = GID_NOBODY;
388
389 nmlen = strlen(section_name);
390 if (nmlen >= NAMSIZ) {
391 /*
392 * file name is too big, it must go out
393 * in its own data file
394 */
395 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
396 &actual_size, TRUE, local_commands);
397 if (!tar_hdr) {
398 free(section_name);
399 return (0);
400 }
401 (void) snprintf(tar_hdr->th_name,
402 sizeof (tar_hdr->th_name),
403 "%s%08qd.fil",
404 LONGNAME_PREFIX,
405 file_count++);
406
407 tar_hdr->th_linkflag = LF_LONGNAME;
408 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
409 "%011o ", nmlen);
410 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
411 "%06o ", attr->st_mode & 07777);
412 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
413 "%06o ", uid);
414 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
415 "%06o ", gid);
416 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
417 "%.31s", uname);
418 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
419 "%.31s", gname);
420 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
421 "%011o ", attr->st_mtime);
422 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
423 sizeof (tar_hdr->th_magic));
424
425 tlm_build_header_checksum(tar_hdr);
426
427 (void) output_mem(local_commands,
428 (void *)section_name, nmlen);
429 long_name = TRUE;
430 }
431
432 lnklen = strlen(link);
433 if (lnklen >= NAMSIZ) {
434 /*
435 * link name is too big, it must go out
436 * in its own data file
437 */
438 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
439 &actual_size, TRUE, local_commands);
440 if (!tar_hdr) {
441 free(section_name);
442 return (0);
443 }
444 (void) snprintf(tar_hdr->th_linkname,
445 sizeof (tar_hdr->th_name),
446 "%s%08qd.slk",
447 LONGNAME_PREFIX,
448 file_count++);
449
450 tar_hdr->th_linkflag = LF_LONGLINK;
451 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
452 "%011o ", lnklen);
453 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
454 "%06o ", attr->st_mode & 07777);
455 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
456 "%06o ", uid);
457 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
458 "%06o ", gid);
459 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
460 "%.31s", uname);
461 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
462 "%.31s", gname);
463 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
464 "%011o ", attr->st_mtime);
465 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
466 sizeof (tar_hdr->th_magic));
467
468 tlm_build_header_checksum(tar_hdr);
469
470 (void) output_mem(local_commands, (void *)link,
471 lnklen);
472 long_link = TRUE;
473 }
474 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
475 &actual_size, TRUE, local_commands);
476 if (!tar_hdr) {
477 free(section_name);
478 return (0);
479 }
480 if (long_name) {
481 (void) snprintf(tar_hdr->th_name,
482 sizeof (tar_hdr->th_name),
483 "%s%08qd.fil",
484 LONGNAME_PREFIX,
485 file_count++);
486 } else {
487 (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
488 }
489
490 NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE",
491 link);
492
493 if (long_link) {
494 (void) snprintf(tar_hdr->th_linkname,
495 sizeof (tar_hdr->th_name),
496 "%s%08qd.slk",
497 LONGNAME_PREFIX,
498 file_count++);
499 } else {
500 (void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
501 }
502 switch (attr->st_mode & S_IFMT) {
503 case S_IFDIR:
504 tar_hdr->th_linkflag = LF_DIR;
505 break;
506 case S_IFIFO:
507 tar_hdr->th_linkflag = LF_FIFO;
508 break;
509 case S_IFBLK:
510 case S_IFCHR:
511 if (S_ISBLK(attr->st_mode))
512 tar_hdr->th_linkflag = LF_BLK;
513 else
514 tar_hdr->th_linkflag = LF_CHR;
515 (void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
516 sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
517 major(attr->st_rdev));
518 (void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
519 sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
520 minor(attr->st_rdev));
521 break;
522 default:
523 if (attr->st_nlink > 1) {
524 /* mark file with hardlink LF_LINK */
525 tar_hdr->th_linkflag = LF_LINK;
526 (void) snprintf(tar_hdr->th_shared.th_hlink_ino,
527 sizeof (tar_hdr->th_shared.th_hlink_ino),
528 "%011llo ", attr->st_ino);
529 } else {
530 tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
531 LF_SYMLINK;
532 NDMP_LOG(LOG_DEBUG, "linkflag: '%c'",
533 tar_hdr->th_linkflag);
534 }
535 }
536 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
537 (long)attr->st_size);
538 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
539 attr->st_mode & 07777);
540 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
541 uid);
542 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
543 gid);
544 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
545 uname);
546 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
547 gname);
548 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
549 attr->st_mtime);
550 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
551 sizeof (tar_hdr->th_magic));
552
553 tlm_build_header_checksum(tar_hdr);
554 if (long_name || long_link) {
555 if (file_count > 99999990) {
556 file_count = 0;
557 }
558 }
559 free(section_name);
560 return (0);
561 }
562
563
564 /*
565 * tlm_readlink
566 *
567 * Read where the softlink points to. Read the link in the checkpointed
568 * path if the backup is being done on a checkpointed file system.
569 */
570 static int
tlm_readlink(char * nm,char * snap,char * buf,int bufsize)571 tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
572 {
573 int len;
574
575 if ((len = readlink(snap, buf, bufsize)) >= 0) {
576 /*
577 * realink(2) doesn't null terminate the link name. We must
578 * do it here.
579 */
580 buf[len] = '\0';
581 } else {
582 NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]",
583 errno, nm);
584 buf[0] = '\0';
585
586 /* Backup the link if the destination missing */
587 if (errno == ENOENT)
588 return (0);
589
590 }
591
592 return (len);
593 }
594
595 /*
596 * Read the system attribute file in a single buffer to write
597 * it as a single write. A partial write to system attribute would
598 * cause an EINVAL on write.
599 */
600 static char *
get_write_one_buf(char * buf,char * rec,int buf_size,int rec_size,tlm_cmd_t * lc)601 get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
602 tlm_cmd_t *lc)
603 {
604 int len;
605 long write_size;
606
607 if (rec_size > buf_size)
608 return (rec);
609
610 len = rec_size;
611 (void) memcpy(rec, buf, len);
612 buf += len;
613 while (rec_size < buf_size) {
614 rec = get_write_buffer(buf_size - rec_size,
615 &write_size, FALSE, lc);
616 if (!rec)
617 return (0);
618
619 len = min(buf_size - rec_size, write_size);
620 (void) memcpy(rec, buf, len);
621 rec_size += len;
622 buf += len;
623 }
624 return (rec);
625 }
626
627
628 /*
629 * tlm_output_xattr
630 *
631 * Put this file into the output buffers.
632 */
633 /*ARGSUSED*/
634 longlong_t
tlm_output_xattr(char * dir,char * name,char * chkdir,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)635 tlm_output_xattr(char *dir, char *name, char *chkdir,
636 tlm_acls_t *tlm_acls, tlm_commands_t *commands,
637 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
638 {
639 char *fullname; /* directory + name */
640 char *snapname; /* snapshot name */
641 int section; /* section of a huge file */
642 int fd;
643 int afd = 0;
644 longlong_t seek_spot = 0; /* location in the file */
645 /* for Multi Volume record */
646 u_longlong_t pos;
647 DIR *dp;
648 struct dirent *dtp;
649 char *attrname;
650 char *fnamep;
651 int rv = 0;
652
653 if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
654 return (TLM_NO_SOURCE_FILE);
655 }
656
657 fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
658 if (fullname == NULL) {
659 free(fullname);
660 return (-TLM_NO_SCRATCH_SPACE);
661 }
662
663 if (!tlm_cat_path(fullname, dir, name)) {
664 NDMP_LOG(LOG_DEBUG, "Path too long.");
665 free(fullname);
666 return (-TLM_NO_SCRATCH_SPACE);
667 }
668
669 if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
670 sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
671 free(fullname);
672 return (0);
673 }
674
675 attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
676 snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
677 if (attrname == NULL || snapname == NULL) {
678 rv = -TLM_NO_SCRATCH_SPACE;
679 goto err_out;
680 }
681
682 if (!tlm_cat_path(snapname, chkdir, name)) {
683 NDMP_LOG(LOG_DEBUG, "Path too long.");
684 rv = -TLM_NO_SCRATCH_SPACE;
685 goto err_out;
686 }
687
688 fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
689
690 /*
691 * Open the file for reading.
692 */
693 fd = attropen(fnamep, ".", O_RDONLY);
694 if (fd == -1) {
695 NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]",
696 fullname, fnamep);
697 rv = TLM_NO_SOURCE_FILE;
698 goto err_out;
699 }
700
701 pos = tlm_get_data_offset(local_commands);
702 NDMP_LOG(LOG_DEBUG, "pos: %10lld [%s]", pos, name);
703
704 section = 0;
705
706 dp = (DIR *)fdopendir(fd);
707 if (dp == NULL) {
708 NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
709 (void) close(fd);
710 rv = TLM_NO_SOURCE_FILE;
711 goto err_out;
712 }
713
714 while ((dtp = readdir(dp)) != NULL) {
715 int section_size;
716
717 if (*dtp->d_name == '.')
718 continue;
719
720 if (sysattr_rdonly(dtp->d_name))
721 continue;
722
723 afd = attropen(fnamep, dtp->d_name, O_RDONLY);
724 if (afd == -1) {
725 NDMP_LOG(LOG_DEBUG,
726 "problem(%d) opening xattr file [%s][%s]", errno,
727 fullname, fnamep);
728 goto tear_down;
729 }
730
731 (void) output_xattr_header(fullname, dtp->d_name, afd,
732 tlm_acls, section, local_commands);
733 (void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
734 dtp->d_name);
735 (void) output_file_header(attrname, "", tlm_acls, 0,
736 local_commands);
737
738 section_size = (long)llmin(tlm_acls->acl_attr.st_size,
739 (longlong_t)TLM_MAX_TAR_IMAGE);
740
741 /* We only can read upto one section extended attribute */
742 while (section_size > 0) {
743 char *buf;
744 long actual_size;
745 int read_size;
746 int sysattr_read = 0;
747 char *rec;
748 int size;
749
750 /*
751 * check for Abort commands
752 */
753 if (commands->tcs_reader != TLM_BACKUP_RUN) {
754 local_commands->tc_writer = TLM_ABORT;
755 goto tear_down;
756 }
757
758 local_commands->tc_buffers->tbs_buffer[
759 local_commands->tc_buffers->tbs_buffer_in].
760 tb_file_size = section_size;
761 local_commands->tc_buffers->tbs_buffer[
762 local_commands->tc_buffers->tbs_buffer_in].
763 tb_seek_spot = seek_spot;
764
765 buf = get_write_buffer(section_size,
766 &actual_size, FALSE, local_commands);
767 if (!buf)
768 goto tear_down;
769
770 if ((actual_size < section_size) &&
771 sysattr_rw(dtp->d_name)) {
772 rec = buf;
773 buf = ndmp_malloc(section_size);
774 if (!buf)
775 goto tear_down;
776 size = actual_size;
777 actual_size = section_size;
778 sysattr_read = 1;
779 }
780
781 /*
782 * check for Abort commands
783 */
784 if (commands->tcs_reader != TLM_BACKUP_RUN) {
785 local_commands->tc_writer = TLM_ABORT;
786 goto tear_down;
787 }
788
789 read_size = min(section_size, actual_size);
790 if ((actual_size = read(afd, buf, read_size)) < 0)
791 break;
792
793 if (sysattr_read) {
794 if (get_write_one_buf(buf, rec, read_size,
795 size, local_commands) == 0) {
796 free(buf);
797 goto tear_down;
798 }
799 free(buf);
800 }
801
802
803 NS_ADD(rdisk, actual_size);
804 NS_INC(rfile);
805
806 if (actual_size == -1) {
807 NDMP_LOG(LOG_DEBUG,
808 "problem(%d) reading file [%s][%s]",
809 errno, fullname, snapname);
810 goto tear_down;
811 }
812 seek_spot += actual_size;
813 section_size -= actual_size;
814 }
815 (void) close(afd);
816 afd = -1;
817 }
818
819 tear_down:
820 local_commands->tc_buffers->tbs_buffer[
821 local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
822
823 if (afd > 0)
824 (void) close(afd);
825
826 /* closedir closes fd too */
827 (void) closedir(dp);
828
829 err_out:
830 free(fullname);
831 free(attrname);
832 free(snapname);
833 return (rv);
834 }
835
836
837 /*
838 * tlm_output_file
839 *
840 * Put this file into the output buffers.
841 */
842 longlong_t
tlm_output_file(char * dir,char * name,char * chkdir,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats,struct hardlink_q * hardlink_q)843 tlm_output_file(char *dir, char *name, char *chkdir,
844 tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
845 tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
846 {
847 char *fullname; /* directory + name */
848 char *snapname; /* snapshot name */
849 char *linkname; /* where this file points */
850 int section = 0; /* section of a huge file */
851 int fd;
852 longlong_t real_size; /* the origional file size */
853 longlong_t file_size; /* real size of this file */
854 longlong_t seek_spot = 0; /* location in the file */
855 /* for Multi Volume record */
856 u_longlong_t pos;
857 char *fnamep;
858
859 /* Indicate whether a file with the same inode has been backed up. */
860 int hardlink_done = 0;
861
862 /*
863 * If a file with the same inode has been backed up, hardlink_pos holds
864 * the tape offset of the data record.
865 */
866 u_longlong_t hardlink_pos = 0;
867
868 if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
869 NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
870 return (-TLM_NO_SCRATCH_SPACE);
871 }
872
873 fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
874 linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
875 snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
876 if (fullname == NULL || linkname == NULL || snapname == NULL) {
877 real_size = -TLM_NO_SCRATCH_SPACE;
878 goto err_out;
879 }
880 if (!tlm_cat_path(fullname, dir, name) ||
881 !tlm_cat_path(snapname, chkdir, name)) {
882 NDMP_LOG(LOG_DEBUG, "Path too long.");
883 real_size = -TLM_NO_SCRATCH_SPACE;
884 goto err_out;
885 }
886
887 pos = tlm_get_data_offset(local_commands);
888 NDMP_LOG(LOG_DEBUG, "pos: %10lld [%s]", pos, name);
889
890 if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
891 if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
892 file_size = tlm_readlink(fullname, snapname, linkname,
893 TLM_MAX_PATH_NAME-1);
894 if (file_size < 0) {
895 real_size = -ENOENT;
896 goto err_out;
897 }
898 }
899
900 /*
901 * Since soft links can not be read(2), we should only
902 * backup the file header.
903 */
904 (void) output_file_header(fullname,
905 linkname,
906 tlm_acls,
907 section,
908 local_commands);
909
910 (void) tlm_log_fhnode(job_stats, dir, name,
911 &tlm_acls->acl_attr, pos);
912 (void) tlm_log_fhpath_name(job_stats, fullname,
913 &tlm_acls->acl_attr, pos);
914
915 free(fullname);
916 free(linkname);
917 free(snapname);
918 return (0);
919 }
920
921 fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
922
923 /*
924 * For hardlink, only read the data if no other link
925 * belonging to the same inode has been backed up.
926 */
927 if (tlm_acls->acl_attr.st_nlink > 1) {
928 hardlink_done = !hardlink_q_get(hardlink_q,
929 tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
930 }
931
932 if (!hardlink_done) {
933 /*
934 * Open the file for reading.
935 */
936 fd = open(fnamep, O_RDONLY);
937 if (fd == -1) {
938 NDMP_LOG(LOG_DEBUG,
939 "BACKUP> Can't open file [%s][%s] err(%d)",
940 fullname, fnamep, errno);
941 real_size = -TLM_NO_SOURCE_FILE;
942 goto err_out;
943 }
944 } else {
945 NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
946 tlm_acls->acl_attr.st_ino, hardlink_pos);
947
948 fd = -1;
949 }
950
951 linkname[0] = 0;
952
953 real_size = tlm_acls->acl_attr.st_size;
954 (void) output_acl_header(&tlm_acls->acl_info,
955 local_commands);
956
957 /*
958 * section = 0: file is small enough for TAR
959 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
960 * and the file name gets munged
961 */
962 file_size = real_size;
963 if (file_size > TLM_MAX_TAR_IMAGE) {
964 if (output_humongus_header(fullname, file_size,
965 local_commands) < 0) {
966 (void) close(fd);
967 real_size = -TLM_NO_SCRATCH_SPACE;
968 goto err_out;
969 }
970 section = 1;
971 } else {
972 section = 0;
973 }
974
975 /*
976 * For hardlink, if other link belonging to the same inode
977 * has been backed up, only backup an empty record.
978 */
979 if (hardlink_done)
980 file_size = 0;
981
982 /*
983 * work
984 */
985 if (file_size == 0) {
986 (void) output_file_header(fullname,
987 linkname,
988 tlm_acls,
989 section,
990 local_commands);
991 /*
992 * this can fall right through since zero size files
993 * will be skipped by the WHILE loop anyway
994 */
995 }
996
997 while (file_size > 0) {
998 int section_size = llmin(file_size,
999 (longlong_t)TLM_MAX_TAR_IMAGE);
1000
1001 tlm_acls->acl_attr.st_size = (longlong_t)section_size;
1002 (void) output_file_header(fullname,
1003 linkname,
1004 tlm_acls,
1005 section,
1006 local_commands);
1007 while (section_size > 0) {
1008 char *buf;
1009 long actual_size;
1010 int read_size;
1011
1012 /*
1013 * check for Abort commands
1014 */
1015 if (commands->tcs_reader != TLM_BACKUP_RUN) {
1016 local_commands->tc_writer = TLM_ABORT;
1017 goto tear_down;
1018 }
1019
1020 local_commands->tc_buffers->tbs_buffer[
1021 local_commands->tc_buffers->tbs_buffer_in].
1022 tb_file_size = section_size;
1023 local_commands->tc_buffers->tbs_buffer[
1024 local_commands->tc_buffers->tbs_buffer_in].
1025 tb_seek_spot = seek_spot;
1026
1027 buf = get_write_buffer(section_size,
1028 &actual_size, FALSE, local_commands);
1029 if (!buf)
1030 goto tear_down;
1031
1032 /*
1033 * check for Abort commands
1034 */
1035 if (commands->tcs_reader != TLM_BACKUP_RUN) {
1036 local_commands->tc_writer = TLM_ABORT;
1037 goto tear_down;
1038 }
1039
1040 read_size = min(section_size, actual_size);
1041 actual_size = read(fd, buf, read_size);
1042 NS_ADD(rdisk, actual_size);
1043 NS_INC(rfile);
1044
1045 if (actual_size == 0)
1046 break;
1047
1048 if (actual_size == -1) {
1049 NDMP_LOG(LOG_DEBUG,
1050 "problem(%d) reading file [%s][%s]",
1051 errno, fullname, snapname);
1052 goto tear_down;
1053 }
1054 seek_spot += actual_size;
1055 file_size -= actual_size;
1056 section_size -= actual_size;
1057 }
1058 section++;
1059 }
1060
1061 /*
1062 * If data belonging to this hardlink has been backed up, add the link
1063 * to hardlink queue.
1064 */
1065 if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
1066 (void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
1067 pos, NULL, 0);
1068 NDMP_LOG(LOG_DEBUG,
1069 "backed up hardlink file %s, inode = %llu, pos = %llu ",
1070 fullname, tlm_acls->acl_attr.st_ino, pos);
1071 }
1072
1073 /*
1074 * For hardlink, if other link belonging to the same inode has been
1075 * backed up, no add_node entry should be sent for this link.
1076 */
1077 if (hardlink_done) {
1078 NDMP_LOG(LOG_DEBUG,
1079 "backed up hardlink link %s, inode = %llu, pos = %llu ",
1080 fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
1081 } else {
1082 (void) tlm_log_fhnode(job_stats, dir, name,
1083 &tlm_acls->acl_attr, pos);
1084 }
1085
1086 (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
1087 pos);
1088
1089 tear_down:
1090 local_commands->tc_buffers->tbs_buffer[
1091 local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
1092
1093 (void) close(fd);
1094
1095 err_out:
1096 free(fullname);
1097 free(linkname);
1098 free(snapname);
1099 return (real_size);
1100 }
1101
1102 /*
1103 * tar_putfile
1104 *
1105 * Main file backup function for tar
1106 */
1107 int
tar_putfile(char * dir,char * name,char * chkdir,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats,struct hardlink_q * hardlink_q)1108 tar_putfile(char *dir, char *name, char *chkdir,
1109 tlm_acls_t *tlm_acls, tlm_commands_t *commands,
1110 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
1111 struct hardlink_q *hardlink_q)
1112 {
1113 int rv;
1114
1115 rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
1116 local_commands, job_stats, hardlink_q);
1117 if (rv < 0)
1118 return (rv);
1119
1120 rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
1121 local_commands, job_stats);
1122
1123 return (rv < 0 ? rv : 0);
1124 }
1125
1126 /*
1127 * get_write_buffer
1128 *
1129 * a wrapper to tlm_get_write_buffer so that
1130 * we can cleanly detect ABORT commands
1131 * without involving the TLM library with
1132 * our problems.
1133 */
1134 static char *
get_write_buffer(long size,long * actual_size,boolean_t zero,tlm_cmd_t * local_commands)1135 get_write_buffer(long size, long *actual_size,
1136 boolean_t zero, tlm_cmd_t *local_commands)
1137 {
1138 while (local_commands->tc_reader == TLM_BACKUP_RUN) {
1139 char *rec = tlm_get_write_buffer(size, actual_size,
1140 local_commands->tc_buffers, zero);
1141 if (rec != 0) {
1142 return (rec);
1143 }
1144 }
1145 return (NULL);
1146 }
1147
1148 #define NDMP_MORE_RECORDS 2
1149
1150 /*
1151 * write_tar_eof
1152 *
1153 * This function is initially written for NDMP support. It appends
1154 * two tar headers to the tar file, and also N more empty buffers
1155 * to make sure that the two tar headers will be read as a part of
1156 * a mover record and don't get locked because of EOM on the mover
1157 * side.
1158 */
1159 void
write_tar_eof(tlm_cmd_t * local_commands)1160 write_tar_eof(tlm_cmd_t *local_commands)
1161 {
1162 int i;
1163 long actual_size;
1164 tlm_buffers_t *bufs;
1165
1166 /*
1167 * output 2 zero filled records,
1168 * TAR wants this.
1169 */
1170 (void) get_write_buffer(sizeof (tlm_tar_hdr_t),
1171 &actual_size, TRUE, local_commands);
1172 (void) get_write_buffer(sizeof (tlm_tar_hdr_t),
1173 &actual_size, TRUE, local_commands);
1174
1175 /*
1176 * NDMP: Clear the rest of the buffer and write two more buffers
1177 * to the tape.
1178 */
1179 bufs = local_commands->tc_buffers;
1180 (void) get_write_buffer(bufs->tbs_data_transfer_size,
1181 &actual_size, TRUE, local_commands);
1182
1183 for (i = 0; i < NDMP_MORE_RECORDS &&
1184 local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
1185 /*
1186 * We don't need the return value of get_write_buffer(),
1187 * since it's already zeroed out if the buffer is returned.
1188 */
1189 (void) get_write_buffer(bufs->tbs_data_transfer_size,
1190 &actual_size, TRUE, local_commands);
1191 }
1192
1193 bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
1194 tlm_buffer_release_in_buf(bufs);
1195 }
1196
1197 /*
1198 * Callback to backup each ZFS property
1199 */
1200 static int
zfs_put_prop_cb(int prop,void * pp)1201 zfs_put_prop_cb(int prop, void *pp)
1202 {
1203 ndmp_metadata_handle_t *mhd;
1204 ndmp_metadata_header_ext_t *mhp;
1205 ndmp_metadata_property_ext_t *mpp;
1206 char vbuf[ZFS_MAXPROPLEN];
1207 char sbuf[ZFS_MAXPROPLEN];
1208 zprop_source_t stype;
1209 char *sourcestr;
1210
1211 if (pp == NULL)
1212 return (ZPROP_INVAL);
1213
1214 mhd = (ndmp_metadata_handle_t *)pp;
1215 mhp = mhd->ml_xhdr;
1216 mpp = &mhp->nh_property[mhp->nh_count];
1217
1218 if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
1219 sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
1220 return (ZPROP_INVAL);
1221
1222 if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf),
1223 &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) {
1224 mhp->nh_count++;
1225 return (ZPROP_CONT);
1226 }
1227
1228 (void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), ZFS_MAXNAMELEN);
1229 (void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN);
1230
1231 switch (stype) {
1232 case ZPROP_SRC_NONE:
1233 sourcestr = "none";
1234 break;
1235 case ZPROP_SRC_RECEIVED:
1236 sourcestr = "received";
1237 break;
1238 case ZPROP_SRC_LOCAL:
1239 sourcestr = mhp->nh_dataset;
1240 break;
1241 case ZPROP_SRC_TEMPORARY:
1242 sourcestr = "temporary";
1243 break;
1244 case ZPROP_SRC_DEFAULT:
1245 sourcestr = "default";
1246 break;
1247 default:
1248 sourcestr = sbuf;
1249 break;
1250 }
1251 (void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN);
1252
1253 mhp->nh_count++;
1254 return (ZPROP_CONT);
1255 }
1256
1257 /*
1258 * Callback to backup each ZFS user/group quota
1259 */
1260 static int
zfs_put_quota_cb(void * pp,const char * domain,uid_t rid,uint64_t space)1261 zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
1262 {
1263 ndmp_metadata_handle_t *mhd;
1264 ndmp_metadata_header_ext_t *mhp;
1265 ndmp_metadata_property_ext_t *mpp;
1266 char *typestr;
1267
1268 if (pp == NULL)
1269 return (ZPROP_INVAL);
1270
1271 mhd = (ndmp_metadata_handle_t *)pp;
1272 mhp = mhd->ml_xhdr;
1273 mpp = &mhp->nh_property[mhp->nh_count];
1274
1275 if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
1276 sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
1277 return (ZPROP_INVAL);
1278
1279 if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA)
1280 typestr = "userquota";
1281 else
1282 typestr = "groupquota";
1283
1284 if (domain == NULL || *domain == '\0')
1285 (void) snprintf(mpp->mp_name, ZFS_MAXNAMELEN, "%s@%llu",
1286 typestr, (longlong_t)rid);
1287 else
1288 (void) snprintf(mpp->mp_name, ZFS_MAXNAMELEN, "%s@%s-%llu",
1289 typestr, domain, (longlong_t)rid);
1290 (void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space);
1291 (void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN);
1292
1293 mhp->nh_count++;
1294 return (0);
1295 }
1296
1297 /*
1298 * Callback to count each ZFS property
1299 */
1300 /*ARGSUSED*/
1301 static int
zfs_count_prop_cb(int prop,void * pp)1302 zfs_count_prop_cb(int prop, void *pp)
1303 {
1304 (*(int *)pp)++;
1305 return (ZPROP_CONT);
1306 }
1307
1308 /*
1309 * Callback to count each ZFS user/group quota
1310 */
1311 /*ARGSUSED*/
1312 static int
zfs_count_quota_cb(void * pp,const char * domain,uid_t rid,uint64_t space)1313 zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
1314 {
1315 (*(int *)pp)++;
1316 return (0);
1317 }
1318
1319 /*
1320 * Count the number of ZFS properties and user/group quotas
1321 */
1322 int
zfs_get_prop_counts(zfs_handle_t * zhp)1323 zfs_get_prop_counts(zfs_handle_t *zhp)
1324 {
1325 int count = 0;
1326 nvlist_t *uprops;
1327 nvpair_t *elp;
1328
1329 if (zhp == NULL)
1330 return (0);
1331
1332 (void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE,
1333 ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
1334
1335 (void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb,
1336 &count);
1337 (void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb,
1338 &count);
1339
1340 uprops = zfs_get_user_props(zhp);
1341
1342 elp = nvlist_next_nvpair(uprops, NULL);
1343 for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp))
1344 count++;
1345
1346 return (count);
1347 }
1348
1349 /*
1350 * Notifies ndmpd that the metadata associated with the given ZFS dataset
1351 * should be backed up.
1352 */
1353 int
ndmp_include_zfs(ndmp_context_t * nctx,const char * dataset)1354 ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
1355 {
1356 tlm_commands_t *cmds;
1357 ndmp_metadata_handle_t mhd;
1358 ndmp_metadata_header_ext_t *mhp;
1359 ndmp_metadata_property_ext_t *mpp;
1360 zfs_handle_t *zhp;
1361 tlm_cmd_t *lcmd;
1362 long actual_size;
1363 nvlist_t *uprops, *ulist;
1364 const char *pname;
1365 nvpair_t *elp;
1366 char *sval, *ssrc;
1367 char *wbuf, *pp, *tp;
1368 long size, lsize, sz;
1369 int align = RECORDSIZE - 1;
1370 int pcount;
1371
1372 if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
1373 return (-1);
1374
1375 if ((lcmd = cmds->tcs_command) == NULL ||
1376 lcmd->tc_buffers == NULL)
1377 return (-1);
1378
1379 (void) mutex_lock(&zlib_mtx);
1380 if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) {
1381 (void) mutex_unlock(&zlib_mtx);
1382 return (-1);
1383 }
1384
1385 pcount = zfs_get_prop_counts(zhp);
1386 size = sizeof (ndmp_metadata_header_ext_t) +
1387 pcount * sizeof (ndmp_metadata_property_ext_t);
1388
1389 size += align;
1390 size &= ~align;
1391
1392 if ((mhp = malloc(size)) == NULL) {
1393 zfs_close(zhp);
1394 (void) mutex_unlock(&zlib_mtx);
1395 return (-1);
1396 }
1397
1398 (void) memset(mhp, 0, size);
1399
1400 mhd.ml_handle = zhp;
1401 mhd.ml_xhdr = mhp;
1402 mhp->nh_total_bytes = size;
1403 mhp->nh_major = META_HDR_MAJOR_VERSION;
1404 mhp->nh_minor = META_HDR_MINOR_VERSION;
1405 mhp->nh_plversion = nctx->nc_plversion;
1406
1407 (void) strlcpy(mhp->nh_plname, nctx->nc_plname,
1408 sizeof (mhp->nh_plname));
1409 (void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT,
1410 sizeof (mhp->nh_magic));
1411 (void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
1412
1413 /* Get all the ZFS properties */
1414 (void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE,
1415 ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
1416
1417 /* Get user properties */
1418 uprops = zfs_get_user_props(mhd.ml_handle);
1419
1420 elp = nvlist_next_nvpair(uprops, NULL);
1421
1422 while (elp != NULL) {
1423 mpp = &mhp->nh_property[mhp->nh_count];
1424 if (nvpair_value_nvlist(elp, &ulist) != 0 ||
1425 nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
1426 nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
1427 zfs_close(mhd.ml_handle);
1428 (void) mutex_unlock(&zlib_mtx);
1429 free(mhp);
1430 return (-1);
1431 }
1432 if ((pname = nvpair_name(elp)) != NULL)
1433 (void) strlcpy(mpp->mp_name, pname, ZFS_MAXNAMELEN);
1434
1435 (void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN);
1436 (void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN);
1437 mhp->nh_count++;
1438 elp = nvlist_next_nvpair(uprops, elp);
1439 }
1440
1441 mhd.ml_quota_prop = ZFS_PROP_USERQUOTA;
1442 (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA,
1443 zfs_put_quota_cb, &mhd);
1444 mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA;
1445 (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA,
1446 zfs_put_quota_cb, &mhd);
1447 mhp->nh_count = pcount;
1448
1449 zfs_close(mhd.ml_handle);
1450 (void) mutex_unlock(&zlib_mtx);
1451
1452 if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
1453 lcmd)) != NULL) {
1454 pp = (char *)mhp;
1455
1456 (void) memcpy(wbuf, pp, (actual_size < size) ?
1457 actual_size : size);
1458 pp += (actual_size < size) ? actual_size : size;
1459
1460 sz = actual_size;
1461 while (sz < size &&
1462 ((tp = get_write_buffer(size - sz, &lsize,
1463 TRUE, lcmd))) != NULL) {
1464 (void) memcpy(tp, pp, lsize);
1465 sz += lsize;
1466 pp += lsize;
1467 }
1468 if (sz > size) {
1469 tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
1470 }
1471 }
1472
1473 free(mhp);
1474 return (0);
1475 }
1476