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,
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
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
137 tar_putdir(char *name, tlm_acls_t *tlm_acls,
138 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
240 * output the TAR header record for extended attributes
241 */
242 static int
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,
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) +
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);
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
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 *
602 get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
603 tlm_cmd_t *lc)
627
628
629 /*
630 * tlm_output_xattr
631 *
632 * Put this file into the output buffers.
633 */
634 /*ARGSUSED*/
635 longlong_t
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;
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);
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);
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) {
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);
|
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 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
40
41 #include <syslog.h>
42 #include <stdio.h>
43 #include <limits.h>
44 #include <time.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <dirent.h>
48 #include <pthread.h>
49 #include <archives.h>
50 #include <tlm.h>
51 #include <sys/fs/zfs.h>
52 #include <sys/mkdev.h>
53 #include <libzfs.h>
54 #include <libcmdutils.h>
55 #include <pwd.h>
56 #include <grp.h>
57 #include "tlm_proto.h"
58
59
60 static char *get_write_buffer(long size,
61 long *actual_size,
101 mem += rec_size;
102 len -= rec_size;
103 }
104 }
105
106 /*
107 * tlm_output_dir
108 *
109 * Put the directory information into the output buffers.
110 */
111 int
112 tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
113 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
114 {
115 u_longlong_t pos;
116
117 /*
118 * Send the node or path history of the directory itself.
119 */
120 pos = tlm_get_data_offset(local_commands);
121 (void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
122 (void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
123 /* fhdir_cb is handled in ndmpd_tar3.c */
124
125 (void) output_acl_header(&tlm_acls->acl_info,
126 local_commands);
127 (void) output_file_header(name, "", tlm_acls, 0,
128 local_commands);
129
130 return (0);
131 }
132
133 /*
134 * tar_putdir
135 *
136 * Main dir backup function for tar
137 */
138 int
139 tar_putdir(char *name, tlm_acls_t *tlm_acls,
140 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
242 * output the TAR header record for extended attributes
243 */
244 static int
245 output_xattr_header(char *fname, char *aname, int fd,
246 tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
247 {
248 struct stat64 *attr = &tlm_acls->acl_attr;
249 struct xattr_hdr *xhdr;
250 struct xattr_buf *xbuf;
251 tlm_tar_hdr_t *tar_hdr;
252 long actual_size;
253 char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
254 int hsize;
255 int comlen;
256 int namesz;
257
258 if (section_name == NULL)
259 return (-TLM_NO_SCRATCH_SPACE);
260
261 if (fstat64(fd, attr) == -1) {
262 syslog(LOG_ERR, "output_file_header stat failed.");
263 free(section_name);
264 return (-TLM_OPEN_ERR);
265 }
266
267 /*
268 * if the file has to go out in sections,
269 * we must mung the name.
270 */
271 if (section == 0) {
272 (void) snprintf(section_name, TLM_MAX_PATH_NAME,
273 "/dev/null/%s.hdr", aname);
274 } else {
275 (void) snprintf(section_name,
276 TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
277 }
278 namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
279 hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
280 comlen = namesz + sizeof (struct xattr_buf);
281
282 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
285 free(section_name);
286 return (0);
287 }
288
289 (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
290
291 tar_hdr->th_linkflag = LF_XATTR;
292 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
293 hsize);
294 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
295 attr->st_mode & 07777);
296 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
297 attr->st_uid);
298 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
299 attr->st_gid);
300 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
301 attr->st_mtime);
302 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
303 sizeof (tar_hdr->th_magic));
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) +
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 if (long_link) {
491 (void) snprintf(tar_hdr->th_linkname,
492 sizeof (tar_hdr->th_name),
493 "%s%08qd.slk",
494 LONGNAME_PREFIX,
495 file_count++);
496 } else {
497 (void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
498 }
499 switch (attr->st_mode & S_IFMT) {
500 case S_IFDIR:
501 tar_hdr->th_linkflag = LF_DIR;
502 break;
503 case S_IFIFO:
504 tar_hdr->th_linkflag = LF_FIFO;
505 break;
506 case S_IFBLK:
507 case S_IFCHR:
508 if (S_ISBLK(attr->st_mode))
509 tar_hdr->th_linkflag = LF_BLK;
510 else
511 tar_hdr->th_linkflag = LF_CHR;
512 (void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
513 sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
514 major(attr->st_rdev));
515 (void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
516 sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
517 minor(attr->st_rdev));
518 break;
519 default:
520 if (attr->st_nlink > 1) {
521 /* mark file with hardlink LF_LINK */
522 tar_hdr->th_linkflag = LF_LINK;
523 (void) snprintf(tar_hdr->th_shared.th_hlink_ino,
524 sizeof (tar_hdr->th_shared.th_hlink_ino),
525 "%011llo ", attr->st_ino);
526 } else {
527 tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
528 LF_SYMLINK;
529 }
530 }
531 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
532 (long)attr->st_size);
533 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
534 attr->st_mode & 07777);
535 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
536 uid);
537 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
538 gid);
539 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
540 uname);
541 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
542 gname);
543 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
544 attr->st_mtime);
545 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
546 sizeof (tar_hdr->th_magic));
547
548 tlm_build_header_checksum(tar_hdr);
557
558
559 /*
560 * tlm_readlink
561 *
562 * Read where the softlink points to. Read the link in the checkpointed
563 * path if the backup is being done on a checkpointed file system.
564 */
565 static int
566 tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
567 {
568 int len;
569
570 if ((len = readlink(snap, buf, bufsize)) >= 0) {
571 /*
572 * realink(2) doesn't null terminate the link name. We must
573 * do it here.
574 */
575 buf[len] = '\0';
576 } else {
577 syslog(LOG_ERR, "Error %d reading softlink of [%s]",
578 errno, nm);
579 buf[0] = '\0';
580
581 /* Backup the link if the destination missing */
582 if (errno == ENOENT)
583 return (0);
584
585 }
586
587 return (len);
588 }
589
590 /*
591 * Read the system attribute file in a single buffer to write
592 * it as a single write. A partial write to system attribute would
593 * cause an EINVAL on write.
594 */
595 static char *
596 get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
597 tlm_cmd_t *lc)
621
622
623 /*
624 * tlm_output_xattr
625 *
626 * Put this file into the output buffers.
627 */
628 /*ARGSUSED*/
629 longlong_t
630 tlm_output_xattr(char *dir, char *name, char *chkdir,
631 tlm_acls_t *tlm_acls, tlm_commands_t *commands,
632 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
633 {
634 char *fullname; /* directory + name */
635 char *snapname; /* snapshot name */
636 int section; /* section of a huge file */
637 int fd;
638 int afd = 0;
639 longlong_t seek_spot = 0; /* location in the file */
640 /* for Multi Volume record */
641 DIR *dp;
642 struct dirent *dtp;
643 char *attrname;
644 char *fnamep;
645 int rv = 0;
646
647 if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
648 return (TLM_NO_SOURCE_FILE);
649 }
650
651 fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
652 if (fullname == NULL) {
653 free(fullname);
654 return (-TLM_NO_SCRATCH_SPACE);
655 }
656
657 if (!tlm_cat_path(fullname, dir, name)) {
658 syslog(LOG_ERR, "Path too long.");
659 free(fullname);
660 return (-TLM_NO_SCRATCH_SPACE);
661 }
662
663 if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
664 sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
665 free(fullname);
666 return (0);
667 }
668
669 attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
670 snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
671 if (attrname == NULL || snapname == NULL) {
672 rv = -TLM_NO_SCRATCH_SPACE;
673 goto err_out;
674 }
675
676 if (!tlm_cat_path(snapname, chkdir, name)) {
677 syslog(LOG_ERR, "Path too long.");
678 rv = -TLM_NO_SCRATCH_SPACE;
679 goto err_out;
680 }
681
682 fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
683
684 /*
685 * Open the file for reading.
686 */
687 fd = attropen(fnamep, ".", O_RDONLY);
688 if (fd == -1) {
689 syslog(LOG_ERR, "BACKUP> Can't open file [%s][%s]",
690 fullname, fnamep);
691 rv = TLM_NO_SOURCE_FILE;
692 goto err_out;
693 }
694
695 section = 0;
696
697 dp = (DIR *)fdopendir(fd);
698 if (dp == NULL) {
699 syslog(LOG_ERR, "BACKUP> Can't open file [%s]", fullname);
700 (void) close(fd);
701 rv = TLM_NO_SOURCE_FILE;
702 goto err_out;
703 }
704
705 while ((dtp = readdir(dp)) != NULL) {
706 int section_size;
707
708 if (*dtp->d_name == '.')
709 continue;
710
711 if (sysattr_rdonly(dtp->d_name))
712 continue;
713
714 afd = attropen(fnamep, dtp->d_name, O_RDONLY);
715 if (afd == -1) {
716 syslog(LOG_ERR,
717 "problem(%d) opening xattr file [%s][%s]", errno,
718 fullname, fnamep);
719 goto tear_down;
720 }
721
722 (void) output_xattr_header(fullname, dtp->d_name, afd,
723 tlm_acls, section, local_commands);
724 (void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
725 dtp->d_name);
726 (void) output_file_header(attrname, "", tlm_acls, 0,
727 local_commands);
728
729 section_size = (long)llmin(tlm_acls->acl_attr.st_size,
730 (longlong_t)TLM_MAX_TAR_IMAGE);
731
732 /* We only can read upto one section extended attribute */
733 while (section_size > 0) {
734 char *buf;
735 long actual_size;
736 int read_size;
737 int sysattr_read = 0;
738 char *rec = NULL;
739 int size = 0;
740
741 /*
742 * check for Abort commands
743 */
744 if (commands->tcs_reader != TLM_BACKUP_RUN) {
745 local_commands->tc_writer = TLM_ABORT;
746 goto tear_down;
747 }
748
749 local_commands->tc_buffers->tbs_buffer[
750 local_commands->tc_buffers->tbs_buffer_in].
751 tb_file_size = section_size;
752 local_commands->tc_buffers->tbs_buffer[
753 local_commands->tc_buffers->tbs_buffer_in].
754 tb_seek_spot = seek_spot;
755
756 buf = get_write_buffer(section_size,
757 &actual_size, FALSE, local_commands);
758 if (!buf)
759 goto tear_down;
778 }
779
780 read_size = min(section_size, actual_size);
781 if ((actual_size = read(afd, buf, read_size)) < 0)
782 break;
783
784 if (sysattr_read) {
785 if (get_write_one_buf(buf, rec, read_size,
786 size, local_commands) == 0) {
787 free(buf);
788 goto tear_down;
789 }
790 free(buf);
791 }
792
793
794 NS_ADD(rdisk, actual_size);
795 NS_INC(rfile);
796
797 if (actual_size == -1) {
798 syslog(LOG_ERR,
799 "problem(%d) reading file [%s][%s]",
800 errno, fullname, snapname);
801 goto tear_down;
802 }
803 seek_spot += actual_size;
804 section_size -= actual_size;
805 }
806 (void) close(afd);
807 afd = -1;
808 }
809
810 tear_down:
811 local_commands->tc_buffers->tbs_buffer[
812 local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
813
814 if (afd > 0)
815 (void) close(afd);
816
817 /* closedir closes fd too */
818 (void) closedir(dp);
840 char *linkname; /* where this file points */
841 int section = 0; /* section of a huge file */
842 int fd;
843 longlong_t real_size; /* the origional file size */
844 longlong_t file_size; /* real size of this file */
845 longlong_t seek_spot = 0; /* location in the file */
846 /* for Multi Volume record */
847 u_longlong_t pos;
848 char *fnamep;
849
850 /* Indicate whether a file with the same inode has been backed up. */
851 int hardlink_done = 0;
852
853 /*
854 * If a file with the same inode has been backed up, hardlink_pos holds
855 * the tape offset of the data record.
856 */
857 u_longlong_t hardlink_pos = 0;
858
859 if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
860 syslog(LOG_ERR, "Path too long [%s][%s]", dir, name);
861 return (-TLM_NO_SCRATCH_SPACE);
862 }
863
864 fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
865 linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
866 snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
867 if (fullname == NULL || linkname == NULL || snapname == NULL) {
868 real_size = -TLM_NO_SCRATCH_SPACE;
869 goto err_out;
870 }
871 if (!tlm_cat_path(fullname, dir, name) ||
872 !tlm_cat_path(snapname, chkdir, name)) {
873 syslog(LOG_ERR, "Path too long.");
874 real_size = -TLM_NO_SCRATCH_SPACE;
875 goto err_out;
876 }
877
878 pos = tlm_get_data_offset(local_commands);
879
880 if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
881 if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
882 file_size = tlm_readlink(fullname, snapname, linkname,
883 TLM_MAX_PATH_NAME-1);
884 if (file_size < 0) {
885 real_size = -ENOENT;
886 goto err_out;
887 }
888 }
889
890 /*
891 * Since soft links can not be read(2), we should only
892 * backup the file header.
893 */
894 (void) output_file_header(fullname,
895 linkname,
896 tlm_acls,
897 section,
898 local_commands);
908 return (0);
909 }
910
911 fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
912
913 /*
914 * For hardlink, only read the data if no other link
915 * belonging to the same inode has been backed up.
916 */
917 if (tlm_acls->acl_attr.st_nlink > 1) {
918 hardlink_done = !hardlink_q_get(hardlink_q,
919 tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
920 }
921
922 if (!hardlink_done) {
923 /*
924 * Open the file for reading.
925 */
926 fd = open(fnamep, O_RDONLY);
927 if (fd == -1) {
928 syslog(LOG_ERR,
929 "BACKUP> Can't open file [%s][%s] err(%d)",
930 fullname, fnamep, errno);
931 real_size = -TLM_NO_SOURCE_FILE;
932 goto err_out;
933 }
934 } else {
935 syslog(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
936 tlm_acls->acl_attr.st_ino, hardlink_pos);
937
938 fd = -1;
939 }
940
941 linkname[0] = 0;
942
943 real_size = tlm_acls->acl_attr.st_size;
944 (void) output_acl_header(&tlm_acls->acl_info,
945 local_commands);
946
947 /*
948 * section = 0: file is small enough for TAR
949 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
950 * and the file name gets munged
951 */
952 file_size = real_size;
953 if (file_size > TLM_MAX_TAR_IMAGE) {
954 if (output_humongus_header(fullname, file_size,
955 local_commands) < 0) {
1019 if (!buf)
1020 goto tear_down;
1021
1022 /*
1023 * check for Abort commands
1024 */
1025 if (commands->tcs_reader != TLM_BACKUP_RUN) {
1026 local_commands->tc_writer = TLM_ABORT;
1027 goto tear_down;
1028 }
1029
1030 read_size = min(section_size, actual_size);
1031 actual_size = read(fd, buf, read_size);
1032 NS_ADD(rdisk, actual_size);
1033 NS_INC(rfile);
1034
1035 if (actual_size == 0)
1036 break;
1037
1038 if (actual_size == -1) {
1039 syslog(LOG_ERR,
1040 "problem(%d) reading file [%s][%s]",
1041 errno, fullname, snapname);
1042 goto tear_down;
1043 }
1044 seek_spot += actual_size;
1045 file_size -= actual_size;
1046 section_size -= actual_size;
1047 }
1048 section++;
1049 }
1050
1051 /*
1052 * If data belonging to this hardlink has been backed up, add the link
1053 * to hardlink queue.
1054 */
1055 if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
1056 (void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
1057 pos, NULL, 0);
1058 syslog(LOG_DEBUG,
1059 "backed up hardlink file %s, inode = %llu, pos = %llu ",
1060 fullname, tlm_acls->acl_attr.st_ino, pos);
1061 }
1062
1063 /*
1064 * For hardlink, if other link belonging to the same inode has been
1065 * backed up, no add_node entry should be sent for this link.
1066 */
1067 if (hardlink_done) {
1068 syslog(LOG_DEBUG,
1069 "backed up hardlink link %s, inode = %llu, pos = %llu ",
1070 fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
1071 } else {
1072 (void) tlm_log_fhnode(job_stats, dir, name,
1073 &tlm_acls->acl_attr, pos);
1074 }
1075
1076 (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
1077 pos);
1078
1079 tear_down:
1080 local_commands->tc_buffers->tbs_buffer[
1081 local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
1082
1083 (void) close(fd);
1084
1085 err_out:
1086 free(fullname);
1087 free(linkname);
1088 free(snapname);
|