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