diff options
author | Erik Andersen <andersen@codepoet.org> | 2000-04-05 01:00:52 +0000 |
---|---|---|
committer | Erik Andersen <andersen@codepoet.org> | 2000-04-05 01:00:52 +0000 |
commit | 5661fe078eed752780b11f3f4fdd33bbd76a6c5e (patch) | |
tree | 901159af2b1e62084f258d893949fd9b2fd2d689 | |
parent | cbb0a4b40d32a653957d2c9ecb6fe1a70b30d907 (diff) | |
download | busybox-w32-5661fe078eed752780b11f3f4fdd33bbd76a6c5e.tar.gz busybox-w32-5661fe078eed752780b11f3f4fdd33bbd76a6c5e.tar.bz2 busybox-w32-5661fe078eed752780b11f3f4fdd33bbd76a6c5e.zip |
Tar now works perfectly. It behaves much better now then it
used to. Only thing left to do is add in exclude (-X) option.
-Erik
-rw-r--r-- | TODO | 53 | ||||
-rw-r--r-- | applets/busybox.c | 4 | ||||
-rw-r--r-- | archival/tar.c | 179 | ||||
-rw-r--r-- | busybox.c | 4 | ||||
-rw-r--r-- | kill.c | 2 | ||||
-rw-r--r-- | procps/kill.c | 2 | ||||
-rw-r--r-- | tar.c | 179 | ||||
-rw-r--r-- | utility.c | 4 |
8 files changed, 247 insertions, 180 deletions
@@ -15,15 +15,12 @@ around to it some time. If you have any good ideas, please let me know. | |||
15 | 15 | ||
16 | ----------- | 16 | ----------- |
17 | 17 | ||
18 | * Allow tar to create archives with sockets, devices, and other special files | ||
19 | * Make insmod actually work | 18 | * Make insmod actually work |
20 | * dnsdomainname | 19 | * dnsdomainname |
21 | * traceroute/netstat | 20 | * traceroute/netstat |
22 | * rdate | 21 | * rdate |
23 | * hwclock | 22 | * hwclock |
24 | * killall | ||
25 | * stty | 23 | * stty |
26 | * tr | ||
27 | * cut | 24 | * cut |
28 | * expr (maybe?) (ash builtin?) | 25 | * expr (maybe?) (ash builtin?) |
29 | 26 | ||
@@ -40,58 +37,17 @@ and then start with the biggest things and make them smaller... | |||
40 | 37 | ||
41 | busybox.defs.h is too big and hard to follow. | 38 | busybox.defs.h is too big and hard to follow. |
42 | 39 | ||
43 | I either need to add a better build system (like the Linux kernel?) | 40 | Perhaps I need to add a better build system (like the Linux kernel?) |
44 | or I need to split up busybox.defs.h into coherent chunks (i.e. | ||
45 | busybox.defs.h just has a bunch of: | ||
46 | |||
47 | #include "fileutils.h" | ||
48 | #include "shellutils.h" | ||
49 | |||
50 | which would then have smaller sets of #defines... | ||
51 | Hmm. Needs to be carefully thought out. | ||
52 | 41 | ||
53 | ----------------------- | 42 | ----------------------- |
54 | 43 | ||
55 | 44 | ||
56 | -rw-r--r-- 1000/1000 4398 2000-01-06 21:55 uniq.c | ||
57 | -rw-r--r-- 1000/1000 1568 1999-10-20 18:08 update.c | ||
58 | -rw-r----- 0/1000 1168 2000-01-29 21:03 update.o | ||
59 | -rw-r--r-- 1000/1000 22820 2000-01-05 11:36 utility.c | ||
60 | -rw-r----- 0/1000 7372 2000-01-29 21:03 utility.o | ||
61 | tar: Skipping to next file header | ||
62 | tar: Skipping to next file header | ||
63 | tar: Archive - EOF not on block boundary | ||
64 | tar: Error is not recoverable: exiting now | ||
65 | |||
66 | |||
67 | #1 You are storing by id instead of name like normal tar. Did you realize this? | ||
68 | (or am I missing some compile option? )ctar did not do this, and I don't think | ||
69 | it's a good idea for LRP. | ||
70 | |||
71 | #2 | ||
72 | ctar did not produce the EOF error like your tar does. I believe you need to | ||
73 | pad the end of the archive with at least 2 tarsized (512byte) blocks. (I | ||
74 | think???) | ||
75 | |||
76 | #3 | ||
77 | There is no exclude file(s) option to tar. LRP's packaging system can not | 45 | There is no exclude file(s) option to tar. LRP's packaging system can not |
78 | function without this. Will you have the time to add this soon? | 46 | function without this. Will you have the time to add this soon? |
79 | 47 | ||
80 | 48 | ||
81 | ----------------------- | 49 | ----------------------- |
82 | 50 | ||
83 | cd /mnt | ||
84 | mkdir BACKUP | ||
85 | mv * BACKUP | ||
86 | |||
87 | Today, "mv" behaved as a cp -a and my disk becomed full. It does not | ||
88 | work properly either when renaming a directory into something else | ||
89 | (it produces a lot of disk activity when doing this). | ||
90 | |||
91 | |||
92 | ----------------------- | ||
93 | |||
94 | |||
95 | Feature request: | 51 | Feature request: |
96 | 52 | ||
97 | /bin/busybox --install -s which makes all links to commands that it | 53 | /bin/busybox --install -s which makes all links to commands that it |
@@ -114,13 +70,6 @@ I'll add this to the TODO list, | |||
114 | ----------------------- | 70 | ----------------------- |
115 | 71 | ||
116 | 72 | ||
117 | In utility.c:copyFile: It uses followLinks for both source and | ||
118 | destination files... is that right for `mv'? Will need to revisit | ||
119 | the GNU, freeBSD, and MINIX versions for this... Should read the | ||
120 | Unix98 and POSIX specs also. | ||
121 | |||
122 | ----------------------- | ||
123 | |||
124 | I think that the add_inode &c in utility.c needs to also stow the | 73 | I think that the add_inode &c in utility.c needs to also stow the |
125 | st_dev field, and that du.c should NOT call `reset_inode_list' | 74 | st_dev field, and that du.c should NOT call `reset_inode_list' |
126 | because there can be hard links from inside one argv/ to inside | 75 | because there can be hard links from inside one argv/ to inside |
diff --git a/applets/busybox.c b/applets/busybox.c index c2477a537..9a48f4961 100644 --- a/applets/busybox.c +++ b/applets/busybox.c | |||
@@ -382,8 +382,8 @@ int busybox_main(int argc, char **argv) | |||
382 | fprintf(stderr, "Usage: busybox [function] [arguments]...\n"); | 382 | fprintf(stderr, "Usage: busybox [function] [arguments]...\n"); |
383 | fprintf(stderr, " or: [function] [arguments]...\n\n"); | 383 | fprintf(stderr, " or: [function] [arguments]...\n\n"); |
384 | fprintf(stderr, | 384 | fprintf(stderr, |
385 | "\tMost people will create a link to busybox for each\n" | 385 | "\tMost people will create a link to busybox for each function\n" |
386 | "\tfunction name, and busybox will act like whatever you invoke it as.\n"); | 386 | "\tname, and busybox will act like whatever you invoke it as.\n"); |
387 | fprintf(stderr, "\nCurrently defined functions:\n"); | 387 | fprintf(stderr, "\nCurrently defined functions:\n"); |
388 | 388 | ||
389 | while (a->name != 0) { | 389 | while (a->name != 0) { |
diff --git a/archival/tar.c b/archival/tar.c index f9b3e1813..979821ec0 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -56,7 +56,8 @@ | |||
56 | 56 | ||
57 | static const char tar_usage[] = | 57 | static const char tar_usage[] = |
58 | "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n" | 58 | "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n" |
59 | "Create, extract, or list files from a tar file.\n\n" | 59 | "Create, extract, or list files from a tar file. Note that\n" |
60 | "this version of tar packs hard links as separate files.\n\n" | ||
60 | "Options:\n" | 61 | "Options:\n" |
61 | 62 | ||
62 | "\tc=create, x=extract, t=list contents, v=verbose,\n" | 63 | "\tc=create, x=extract, t=list contents, v=verbose,\n" |
@@ -110,10 +111,10 @@ typedef struct TarHeader TarHeader; | |||
110 | 111 | ||
111 | /* A few useful constants */ | 112 | /* A few useful constants */ |
112 | #define TAR_MAGIC "ustar" /* ustar and a null */ | 113 | #define TAR_MAGIC "ustar" /* ustar and a null */ |
113 | #define TAR_VERSION "00" /* 00 and no null */ | 114 | //#define TAR_VERSION "00" /* 00 and no null */ |
115 | #define TAR_VERSION " " /* Be compatable with old GNU format */ | ||
114 | #define TAR_MAGIC_LEN 6 | 116 | #define TAR_MAGIC_LEN 6 |
115 | #define TAR_VERSION_LEN 2 | 117 | #define TAR_VERSION_LEN 2 |
116 | #define TAR_NAME_LEN 100 | ||
117 | #define TAR_BLOCK_SIZE 512 | 118 | #define TAR_BLOCK_SIZE 512 |
118 | 119 | ||
119 | /* A nice enum with all the possible tar file content types */ | 120 | /* A nice enum with all the possible tar file content types */ |
@@ -366,7 +367,8 @@ tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag) | |||
366 | return; | 367 | return; |
367 | 368 | ||
368 | if (link(header->linkname, header->name) < 0) { | 369 | if (link(header->linkname, header->name) < 0) { |
369 | errorMsg("Error creating hard link '%s': %s\n", header->linkname, strerror(errno)); | 370 | errorMsg("Error creating hard link '%s' to '%s': %s\n", |
371 | header->name, header->linkname, strerror(errno)); | ||
370 | return; | 372 | return; |
371 | } | 373 | } |
372 | 374 | ||
@@ -382,7 +384,8 @@ tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag) | |||
382 | 384 | ||
383 | #ifdef S_ISLNK | 385 | #ifdef S_ISLNK |
384 | if (symlink(header->linkname, header->name) < 0) { | 386 | if (symlink(header->linkname, header->name) < 0) { |
385 | errorMsg("Error creating symlink '%s': %s\n", header->linkname, strerror(errno)); | 387 | errorMsg("Error creating symlink '%s' to '%s': %s\n", |
388 | header->name, header->linkname, strerror(errno)); | ||
386 | return; | 389 | return; |
387 | } | 390 | } |
388 | /* Try to change ownership of the symlink. | 391 | /* Try to change ownership of the symlink. |
@@ -644,18 +647,15 @@ typedef struct TarBallInfo TarBallInfo; | |||
644 | static int putOctal (char *cp, int len, long value) | 647 | static int putOctal (char *cp, int len, long value) |
645 | { | 648 | { |
646 | int tempLength; | 649 | int tempLength; |
647 | char *tempString; | ||
648 | char tempBuffer[32]; | 650 | char tempBuffer[32]; |
651 | char *tempString = tempBuffer; | ||
649 | 652 | ||
650 | /* Create a string of the specified length with an initial space, | 653 | /* Create a string of the specified length with an initial space, |
651 | * leading zeroes and the octal number, and a trailing null. */ | 654 | * leading zeroes and the octal number, and a trailing null. */ |
652 | tempString = tempBuffer; | 655 | sprintf (tempString, "%0*lo", len - 1, value); |
653 | |||
654 | sprintf (tempString, " %0*lo", len - 2, value); | ||
655 | |||
656 | tempLength = strlen (tempString) + 1; | ||
657 | 656 | ||
658 | /* If the string is too large, suppress the leading space. */ | 657 | /* If the string is too large, suppress the leading space. */ |
658 | tempLength = strlen (tempString) + 1; | ||
659 | if (tempLength > len) { | 659 | if (tempLength > len) { |
660 | tempLength--; | 660 | tempLength--; |
661 | tempString++; | 661 | tempString++; |
@@ -677,10 +677,14 @@ static int putOctal (char *cp, int len, long value) | |||
677 | 677 | ||
678 | /* Write out a tar header for the specified file/directory/whatever */ | 678 | /* Write out a tar header for the specified file/directory/whatever */ |
679 | static int | 679 | static int |
680 | writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf) | 680 | writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *statbuf) |
681 | { | 681 | { |
682 | //int i; | 682 | long chksum=0; |
683 | //long chksum, sum; | 683 | struct TarHeader header; |
684 | const unsigned char *cp = (const unsigned char *) &header; | ||
685 | ssize_t size = sizeof(struct TarHeader); | ||
686 | |||
687 | memset( &header, 0, size); | ||
684 | 688 | ||
685 | if (*fileName=='/') { | 689 | if (*fileName=='/') { |
686 | static int alreadyWarned=FALSE; | 690 | static int alreadyWarned=FALSE; |
@@ -688,66 +692,88 @@ writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *stat | |||
688 | errorMsg("tar: Removing leading '/' from member names\n"); | 692 | errorMsg("tar: Removing leading '/' from member names\n"); |
689 | alreadyWarned=TRUE; | 693 | alreadyWarned=TRUE; |
690 | } | 694 | } |
691 | strcpy(header->name, fileName+1); | 695 | strcpy(header.name, fileName+1); |
692 | } | 696 | } |
693 | else { | 697 | else { |
694 | strcpy(header->name, fileName); | 698 | strcpy(header.name, fileName); |
695 | } | 699 | } |
696 | putOctal(header->mode, sizeof(header->mode), statbuf->st_mode & 0777); | 700 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); |
697 | putOctal(header->uid, sizeof(header->uid), statbuf->st_uid); | 701 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); |
698 | putOctal(header->gid, sizeof(header->gid), statbuf->st_gid); | 702 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); |
699 | putOctal(header->size, sizeof(header->size), statbuf->st_size); | 703 | putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ |
700 | putOctal(header->mtime, sizeof(header->mtime), statbuf->st_mtime); | 704 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); |
701 | 705 | strncpy(header.magic, TAR_MAGIC TAR_VERSION, | |
706 | TAR_MAGIC_LEN + TAR_VERSION_LEN ); | ||
707 | |||
708 | my_getpwuid(header.uname, statbuf->st_uid); | ||
709 | /* Put some sort of sane fallback in place... */ | ||
710 | if (! *header.uname) | ||
711 | strncpy(header.uname, "root", 5); | ||
712 | my_getgrgid(header.gname, statbuf->st_gid); | ||
713 | if (! *header.uname) | ||
714 | strncpy(header.uname, "root", 5); | ||
715 | |||
716 | // FIXME: (or most likely not) I break Hard Links | ||
702 | if (S_ISLNK(statbuf->st_mode)) { | 717 | if (S_ISLNK(statbuf->st_mode)) { |
703 | header->typeflag = LNKTYPE; | 718 | char buffer[BUFSIZ]; |
704 | // TODO -- Handle SYMTYPE | 719 | header.typeflag = SYMTYPE; |
720 | if ( readlink(fileName, buffer, sizeof(buffer) - 1) < 0) { | ||
721 | errorMsg("Error reading symlink '%s': %s\n", header.name, strerror(errno)); | ||
722 | return ( FALSE); | ||
723 | } | ||
724 | strncpy(header.linkname, buffer, sizeof(header.linkname)); | ||
705 | } else if (S_ISDIR(statbuf->st_mode)) { | 725 | } else if (S_ISDIR(statbuf->st_mode)) { |
706 | header->typeflag = DIRTYPE; | 726 | header.typeflag = DIRTYPE; |
707 | strncat(header->name, "/", sizeof(header->name)); | 727 | strncat(header.name, "/", sizeof(header.name)); |
708 | } else if (S_ISCHR(statbuf->st_mode)) { | 728 | } else if (S_ISCHR(statbuf->st_mode)) { |
709 | header->typeflag = CHRTYPE; | 729 | header.typeflag = CHRTYPE; |
710 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); | 730 | putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); |
711 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); | 731 | putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); |
712 | } else if (S_ISBLK(statbuf->st_mode)) { | 732 | } else if (S_ISBLK(statbuf->st_mode)) { |
713 | header->typeflag = BLKTYPE; | 733 | header.typeflag = BLKTYPE; |
714 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); | 734 | putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); |
715 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); | 735 | putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); |
716 | } else if (S_ISFIFO(statbuf->st_mode)) { | 736 | } else if (S_ISFIFO(statbuf->st_mode)) { |
717 | header->typeflag = FIFOTYPE; | 737 | header.typeflag = FIFOTYPE; |
718 | } else if (S_ISLNK(statbuf->st_mode)) { | 738 | } else if (S_ISREG(statbuf->st_mode)) { |
719 | header->typeflag = LNKTYPE; | 739 | header.typeflag = REGTYPE; |
720 | } else if (S_ISLNK(statbuf->st_mode)) { | 740 | putOctal(header.size, sizeof(header.size), statbuf->st_size); |
721 | header->typeflag = REGTYPE; | ||
722 | } else { | 741 | } else { |
742 | errorMsg("tar: %s: Unknown file type\n", fileName); | ||
723 | return ( FALSE); | 743 | return ( FALSE); |
724 | } | 744 | } |
725 | return ( TRUE); | ||
726 | |||
727 | #if 0 | ||
728 | header->linkname = rawHeader->linkname; | ||
729 | header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor)); | ||
730 | header->devminor = getOctal(rawHeader->devminor, sizeof(rawHeader->devminor)); | ||
731 | 745 | ||
732 | /* Write out the checksum */ | 746 | /* Calculate and store the checksum (i.e. the sum of all of the bytes of |
733 | chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum)); | 747 | * the header). The checksum field must be filled with blanks for the |
748 | * calculation. The checksum field is formatted differently from the | ||
749 | * other fields: it has [6] digits, a null, then a space -- rather than | ||
750 | * digits, followed by a null like the other fields... */ | ||
751 | memset(header.chksum, ' ', sizeof(header.chksum)); | ||
752 | cp = (const unsigned char *) &header; | ||
753 | while (size-- > 0) | ||
754 | chksum += *cp++; | ||
755 | putOctal(header.chksum, 7, chksum); | ||
756 | |||
757 | /* Now write the header out to disk */ | ||
758 | if ((size=fullWrite(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) { | ||
759 | errorMsg(io_error, fileName, strerror(errno)); | ||
760 | return ( FALSE); | ||
761 | } | ||
762 | /* Pad the header up to the tar block size */ | ||
763 | for (; size<TAR_BLOCK_SIZE; size++) { | ||
764 | write(tbInfo->tarFd, "\0", 1); | ||
765 | } | ||
766 | /* Now do the verbose thing (or not) */ | ||
767 | if (tbInfo->verboseFlag==TRUE) | ||
768 | fprintf(stdout, "%s\n", header.name); | ||
734 | 769 | ||
735 | return ( TRUE); | 770 | return ( TRUE); |
736 | #endif | ||
737 | } | 771 | } |
738 | 772 | ||
739 | 773 | ||
740 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) | 774 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) |
741 | { | 775 | { |
742 | int inputFileFd; | ||
743 | struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; | 776 | struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; |
744 | char header[sizeof(struct TarHeader)]; | ||
745 | |||
746 | /* First open the file we want to archive, and make sure all is well */ | ||
747 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
748 | errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno)); | ||
749 | return( TRUE); | ||
750 | } | ||
751 | 777 | ||
752 | /* It is against the rules to archive a socket */ | 778 | /* It is against the rules to archive a socket */ |
753 | if (S_ISSOCK(statbuf->st_mode)) { | 779 | if (S_ISSOCK(statbuf->st_mode)) { |
@@ -764,13 +790,41 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* | |||
764 | return( TRUE); | 790 | return( TRUE); |
765 | } | 791 | } |
766 | 792 | ||
767 | memset( header, 0, sizeof(struct TarHeader)); | 793 | if (writeTarHeader(tbInfo, fileName, statbuf)==FALSE) { |
768 | if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) { | 794 | return( FALSE); |
769 | dprintf(tbInfo->tarFd, "%s", header); | ||
770 | } | 795 | } |
771 | /* Now do the verbose thing (or not) */ | 796 | |
772 | if (tbInfo->verboseFlag==TRUE) | 797 | /* Now, if the file is a regular file, copy it out to the tarball */ |
773 | fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name); | 798 | if (S_ISREG(statbuf->st_mode)) { |
799 | int inputFileFd; | ||
800 | char buffer[BUFSIZ]; | ||
801 | ssize_t size=0, readSize=0; | ||
802 | |||
803 | /* open the file we want to archive, and make sure all is well */ | ||
804 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
805 | errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno)); | ||
806 | return( FALSE); | ||
807 | } | ||
808 | |||
809 | /* write the file to the archive */ | ||
810 | while ( (size = fullRead(inputFileFd, buffer, sizeof(buffer))) > 0 ) { | ||
811 | if (fullWrite(tbInfo->tarFd, buffer, size) != size ) { | ||
812 | /* Output file seems to have a problem */ | ||
813 | errorMsg(io_error, fileName, strerror(errno)); | ||
814 | return( FALSE); | ||
815 | } | ||
816 | readSize+=size; | ||
817 | } | ||
818 | if (size == -1) { | ||
819 | errorMsg(io_error, fileName, strerror(errno)); | ||
820 | return( FALSE); | ||
821 | } | ||
822 | /* Pad the file up to the tar block size */ | ||
823 | for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) { | ||
824 | write(tbInfo->tarFd, "\0", 1); | ||
825 | } | ||
826 | close( inputFileFd); | ||
827 | } | ||
774 | 828 | ||
775 | return( TRUE); | 829 | return( TRUE); |
776 | } | 830 | } |
@@ -780,6 +834,7 @@ static int writeTarFile(const char* tarName, int tostdoutFlag, | |||
780 | { | 834 | { |
781 | int tarFd=-1; | 835 | int tarFd=-1; |
782 | int errorFlag=FALSE; | 836 | int errorFlag=FALSE; |
837 | ssize_t size; | ||
783 | //int skipFileFlag=FALSE; | 838 | //int skipFileFlag=FALSE; |
784 | struct TarBallInfo tbInfo; | 839 | struct TarBallInfo tbInfo; |
785 | tbInfo.verboseFlag = verboseFlag; | 840 | tbInfo.verboseFlag = verboseFlag; |
@@ -814,6 +869,10 @@ static int writeTarFile(const char* tarName, int tostdoutFlag, | |||
814 | errorFlag = TRUE; | 869 | errorFlag = TRUE; |
815 | } | 870 | } |
816 | } | 871 | } |
872 | /* Write two empty blocks to the end of the archive */ | ||
873 | for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { | ||
874 | write(tbInfo.tarFd, "\0", 1); | ||
875 | } | ||
817 | /* Hang up the tools, close up shop, head home */ | 876 | /* Hang up the tools, close up shop, head home */ |
818 | close(tarFd); | 877 | close(tarFd); |
819 | if (errorFlag == TRUE) { | 878 | if (errorFlag == TRUE) { |
@@ -382,8 +382,8 @@ int busybox_main(int argc, char **argv) | |||
382 | fprintf(stderr, "Usage: busybox [function] [arguments]...\n"); | 382 | fprintf(stderr, "Usage: busybox [function] [arguments]...\n"); |
383 | fprintf(stderr, " or: [function] [arguments]...\n\n"); | 383 | fprintf(stderr, " or: [function] [arguments]...\n\n"); |
384 | fprintf(stderr, | 384 | fprintf(stderr, |
385 | "\tMost people will create a link to busybox for each\n" | 385 | "\tMost people will create a link to busybox for each function\n" |
386 | "\tfunction name, and busybox will act like whatever you invoke it as.\n"); | 386 | "\tname, and busybox will act like whatever you invoke it as.\n"); |
387 | fprintf(stderr, "\nCurrently defined functions:\n"); | 387 | fprintf(stderr, "\nCurrently defined functions:\n"); |
388 | 388 | ||
389 | while (a->name != 0) { | 389 | while (a->name != 0) { |
@@ -1,6 +1,6 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini kill implementation for busybox | 3 | * Mini kill/killall implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. | 5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. |
6 | * | 6 | * |
diff --git a/procps/kill.c b/procps/kill.c index 10343a150..260f4a074 100644 --- a/procps/kill.c +++ b/procps/kill.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini kill implementation for busybox | 3 | * Mini kill/killall implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. | 5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. |
6 | * | 6 | * |
@@ -56,7 +56,8 @@ | |||
56 | 56 | ||
57 | static const char tar_usage[] = | 57 | static const char tar_usage[] = |
58 | "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n" | 58 | "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n" |
59 | "Create, extract, or list files from a tar file.\n\n" | 59 | "Create, extract, or list files from a tar file. Note that\n" |
60 | "this version of tar packs hard links as separate files.\n\n" | ||
60 | "Options:\n" | 61 | "Options:\n" |
61 | 62 | ||
62 | "\tc=create, x=extract, t=list contents, v=verbose,\n" | 63 | "\tc=create, x=extract, t=list contents, v=verbose,\n" |
@@ -110,10 +111,10 @@ typedef struct TarHeader TarHeader; | |||
110 | 111 | ||
111 | /* A few useful constants */ | 112 | /* A few useful constants */ |
112 | #define TAR_MAGIC "ustar" /* ustar and a null */ | 113 | #define TAR_MAGIC "ustar" /* ustar and a null */ |
113 | #define TAR_VERSION "00" /* 00 and no null */ | 114 | //#define TAR_VERSION "00" /* 00 and no null */ |
115 | #define TAR_VERSION " " /* Be compatable with old GNU format */ | ||
114 | #define TAR_MAGIC_LEN 6 | 116 | #define TAR_MAGIC_LEN 6 |
115 | #define TAR_VERSION_LEN 2 | 117 | #define TAR_VERSION_LEN 2 |
116 | #define TAR_NAME_LEN 100 | ||
117 | #define TAR_BLOCK_SIZE 512 | 118 | #define TAR_BLOCK_SIZE 512 |
118 | 119 | ||
119 | /* A nice enum with all the possible tar file content types */ | 120 | /* A nice enum with all the possible tar file content types */ |
@@ -366,7 +367,8 @@ tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag) | |||
366 | return; | 367 | return; |
367 | 368 | ||
368 | if (link(header->linkname, header->name) < 0) { | 369 | if (link(header->linkname, header->name) < 0) { |
369 | errorMsg("Error creating hard link '%s': %s\n", header->linkname, strerror(errno)); | 370 | errorMsg("Error creating hard link '%s' to '%s': %s\n", |
371 | header->name, header->linkname, strerror(errno)); | ||
370 | return; | 372 | return; |
371 | } | 373 | } |
372 | 374 | ||
@@ -382,7 +384,8 @@ tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag) | |||
382 | 384 | ||
383 | #ifdef S_ISLNK | 385 | #ifdef S_ISLNK |
384 | if (symlink(header->linkname, header->name) < 0) { | 386 | if (symlink(header->linkname, header->name) < 0) { |
385 | errorMsg("Error creating symlink '%s': %s\n", header->linkname, strerror(errno)); | 387 | errorMsg("Error creating symlink '%s' to '%s': %s\n", |
388 | header->name, header->linkname, strerror(errno)); | ||
386 | return; | 389 | return; |
387 | } | 390 | } |
388 | /* Try to change ownership of the symlink. | 391 | /* Try to change ownership of the symlink. |
@@ -644,18 +647,15 @@ typedef struct TarBallInfo TarBallInfo; | |||
644 | static int putOctal (char *cp, int len, long value) | 647 | static int putOctal (char *cp, int len, long value) |
645 | { | 648 | { |
646 | int tempLength; | 649 | int tempLength; |
647 | char *tempString; | ||
648 | char tempBuffer[32]; | 650 | char tempBuffer[32]; |
651 | char *tempString = tempBuffer; | ||
649 | 652 | ||
650 | /* Create a string of the specified length with an initial space, | 653 | /* Create a string of the specified length with an initial space, |
651 | * leading zeroes and the octal number, and a trailing null. */ | 654 | * leading zeroes and the octal number, and a trailing null. */ |
652 | tempString = tempBuffer; | 655 | sprintf (tempString, "%0*lo", len - 1, value); |
653 | |||
654 | sprintf (tempString, " %0*lo", len - 2, value); | ||
655 | |||
656 | tempLength = strlen (tempString) + 1; | ||
657 | 656 | ||
658 | /* If the string is too large, suppress the leading space. */ | 657 | /* If the string is too large, suppress the leading space. */ |
658 | tempLength = strlen (tempString) + 1; | ||
659 | if (tempLength > len) { | 659 | if (tempLength > len) { |
660 | tempLength--; | 660 | tempLength--; |
661 | tempString++; | 661 | tempString++; |
@@ -677,10 +677,14 @@ static int putOctal (char *cp, int len, long value) | |||
677 | 677 | ||
678 | /* Write out a tar header for the specified file/directory/whatever */ | 678 | /* Write out a tar header for the specified file/directory/whatever */ |
679 | static int | 679 | static int |
680 | writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf) | 680 | writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *statbuf) |
681 | { | 681 | { |
682 | //int i; | 682 | long chksum=0; |
683 | //long chksum, sum; | 683 | struct TarHeader header; |
684 | const unsigned char *cp = (const unsigned char *) &header; | ||
685 | ssize_t size = sizeof(struct TarHeader); | ||
686 | |||
687 | memset( &header, 0, size); | ||
684 | 688 | ||
685 | if (*fileName=='/') { | 689 | if (*fileName=='/') { |
686 | static int alreadyWarned=FALSE; | 690 | static int alreadyWarned=FALSE; |
@@ -688,66 +692,88 @@ writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *stat | |||
688 | errorMsg("tar: Removing leading '/' from member names\n"); | 692 | errorMsg("tar: Removing leading '/' from member names\n"); |
689 | alreadyWarned=TRUE; | 693 | alreadyWarned=TRUE; |
690 | } | 694 | } |
691 | strcpy(header->name, fileName+1); | 695 | strcpy(header.name, fileName+1); |
692 | } | 696 | } |
693 | else { | 697 | else { |
694 | strcpy(header->name, fileName); | 698 | strcpy(header.name, fileName); |
695 | } | 699 | } |
696 | putOctal(header->mode, sizeof(header->mode), statbuf->st_mode & 0777); | 700 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); |
697 | putOctal(header->uid, sizeof(header->uid), statbuf->st_uid); | 701 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); |
698 | putOctal(header->gid, sizeof(header->gid), statbuf->st_gid); | 702 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); |
699 | putOctal(header->size, sizeof(header->size), statbuf->st_size); | 703 | putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ |
700 | putOctal(header->mtime, sizeof(header->mtime), statbuf->st_mtime); | 704 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); |
701 | 705 | strncpy(header.magic, TAR_MAGIC TAR_VERSION, | |
706 | TAR_MAGIC_LEN + TAR_VERSION_LEN ); | ||
707 | |||
708 | my_getpwuid(header.uname, statbuf->st_uid); | ||
709 | /* Put some sort of sane fallback in place... */ | ||
710 | if (! *header.uname) | ||
711 | strncpy(header.uname, "root", 5); | ||
712 | my_getgrgid(header.gname, statbuf->st_gid); | ||
713 | if (! *header.uname) | ||
714 | strncpy(header.uname, "root", 5); | ||
715 | |||
716 | // FIXME: (or most likely not) I break Hard Links | ||
702 | if (S_ISLNK(statbuf->st_mode)) { | 717 | if (S_ISLNK(statbuf->st_mode)) { |
703 | header->typeflag = LNKTYPE; | 718 | char buffer[BUFSIZ]; |
704 | // TODO -- Handle SYMTYPE | 719 | header.typeflag = SYMTYPE; |
720 | if ( readlink(fileName, buffer, sizeof(buffer) - 1) < 0) { | ||
721 | errorMsg("Error reading symlink '%s': %s\n", header.name, strerror(errno)); | ||
722 | return ( FALSE); | ||
723 | } | ||
724 | strncpy(header.linkname, buffer, sizeof(header.linkname)); | ||
705 | } else if (S_ISDIR(statbuf->st_mode)) { | 725 | } else if (S_ISDIR(statbuf->st_mode)) { |
706 | header->typeflag = DIRTYPE; | 726 | header.typeflag = DIRTYPE; |
707 | strncat(header->name, "/", sizeof(header->name)); | 727 | strncat(header.name, "/", sizeof(header.name)); |
708 | } else if (S_ISCHR(statbuf->st_mode)) { | 728 | } else if (S_ISCHR(statbuf->st_mode)) { |
709 | header->typeflag = CHRTYPE; | 729 | header.typeflag = CHRTYPE; |
710 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); | 730 | putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); |
711 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); | 731 | putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); |
712 | } else if (S_ISBLK(statbuf->st_mode)) { | 732 | } else if (S_ISBLK(statbuf->st_mode)) { |
713 | header->typeflag = BLKTYPE; | 733 | header.typeflag = BLKTYPE; |
714 | putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev)); | 734 | putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); |
715 | putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev)); | 735 | putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); |
716 | } else if (S_ISFIFO(statbuf->st_mode)) { | 736 | } else if (S_ISFIFO(statbuf->st_mode)) { |
717 | header->typeflag = FIFOTYPE; | 737 | header.typeflag = FIFOTYPE; |
718 | } else if (S_ISLNK(statbuf->st_mode)) { | 738 | } else if (S_ISREG(statbuf->st_mode)) { |
719 | header->typeflag = LNKTYPE; | 739 | header.typeflag = REGTYPE; |
720 | } else if (S_ISLNK(statbuf->st_mode)) { | 740 | putOctal(header.size, sizeof(header.size), statbuf->st_size); |
721 | header->typeflag = REGTYPE; | ||
722 | } else { | 741 | } else { |
742 | errorMsg("tar: %s: Unknown file type\n", fileName); | ||
723 | return ( FALSE); | 743 | return ( FALSE); |
724 | } | 744 | } |
725 | return ( TRUE); | ||
726 | |||
727 | #if 0 | ||
728 | header->linkname = rawHeader->linkname; | ||
729 | header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor)); | ||
730 | header->devminor = getOctal(rawHeader->devminor, sizeof(rawHeader->devminor)); | ||
731 | 745 | ||
732 | /* Write out the checksum */ | 746 | /* Calculate and store the checksum (i.e. the sum of all of the bytes of |
733 | chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum)); | 747 | * the header). The checksum field must be filled with blanks for the |
748 | * calculation. The checksum field is formatted differently from the | ||
749 | * other fields: it has [6] digits, a null, then a space -- rather than | ||
750 | * digits, followed by a null like the other fields... */ | ||
751 | memset(header.chksum, ' ', sizeof(header.chksum)); | ||
752 | cp = (const unsigned char *) &header; | ||
753 | while (size-- > 0) | ||
754 | chksum += *cp++; | ||
755 | putOctal(header.chksum, 7, chksum); | ||
756 | |||
757 | /* Now write the header out to disk */ | ||
758 | if ((size=fullWrite(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) { | ||
759 | errorMsg(io_error, fileName, strerror(errno)); | ||
760 | return ( FALSE); | ||
761 | } | ||
762 | /* Pad the header up to the tar block size */ | ||
763 | for (; size<TAR_BLOCK_SIZE; size++) { | ||
764 | write(tbInfo->tarFd, "\0", 1); | ||
765 | } | ||
766 | /* Now do the verbose thing (or not) */ | ||
767 | if (tbInfo->verboseFlag==TRUE) | ||
768 | fprintf(stdout, "%s\n", header.name); | ||
734 | 769 | ||
735 | return ( TRUE); | 770 | return ( TRUE); |
736 | #endif | ||
737 | } | 771 | } |
738 | 772 | ||
739 | 773 | ||
740 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) | 774 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) |
741 | { | 775 | { |
742 | int inputFileFd; | ||
743 | struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; | 776 | struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; |
744 | char header[sizeof(struct TarHeader)]; | ||
745 | |||
746 | /* First open the file we want to archive, and make sure all is well */ | ||
747 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
748 | errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno)); | ||
749 | return( TRUE); | ||
750 | } | ||
751 | 777 | ||
752 | /* It is against the rules to archive a socket */ | 778 | /* It is against the rules to archive a socket */ |
753 | if (S_ISSOCK(statbuf->st_mode)) { | 779 | if (S_ISSOCK(statbuf->st_mode)) { |
@@ -764,13 +790,41 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* | |||
764 | return( TRUE); | 790 | return( TRUE); |
765 | } | 791 | } |
766 | 792 | ||
767 | memset( header, 0, sizeof(struct TarHeader)); | 793 | if (writeTarHeader(tbInfo, fileName, statbuf)==FALSE) { |
768 | if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) { | 794 | return( FALSE); |
769 | dprintf(tbInfo->tarFd, "%s", header); | ||
770 | } | 795 | } |
771 | /* Now do the verbose thing (or not) */ | 796 | |
772 | if (tbInfo->verboseFlag==TRUE) | 797 | /* Now, if the file is a regular file, copy it out to the tarball */ |
773 | fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name); | 798 | if (S_ISREG(statbuf->st_mode)) { |
799 | int inputFileFd; | ||
800 | char buffer[BUFSIZ]; | ||
801 | ssize_t size=0, readSize=0; | ||
802 | |||
803 | /* open the file we want to archive, and make sure all is well */ | ||
804 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
805 | errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno)); | ||
806 | return( FALSE); | ||
807 | } | ||
808 | |||
809 | /* write the file to the archive */ | ||
810 | while ( (size = fullRead(inputFileFd, buffer, sizeof(buffer))) > 0 ) { | ||
811 | if (fullWrite(tbInfo->tarFd, buffer, size) != size ) { | ||
812 | /* Output file seems to have a problem */ | ||
813 | errorMsg(io_error, fileName, strerror(errno)); | ||
814 | return( FALSE); | ||
815 | } | ||
816 | readSize+=size; | ||
817 | } | ||
818 | if (size == -1) { | ||
819 | errorMsg(io_error, fileName, strerror(errno)); | ||
820 | return( FALSE); | ||
821 | } | ||
822 | /* Pad the file up to the tar block size */ | ||
823 | for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) { | ||
824 | write(tbInfo->tarFd, "\0", 1); | ||
825 | } | ||
826 | close( inputFileFd); | ||
827 | } | ||
774 | 828 | ||
775 | return( TRUE); | 829 | return( TRUE); |
776 | } | 830 | } |
@@ -780,6 +834,7 @@ static int writeTarFile(const char* tarName, int tostdoutFlag, | |||
780 | { | 834 | { |
781 | int tarFd=-1; | 835 | int tarFd=-1; |
782 | int errorFlag=FALSE; | 836 | int errorFlag=FALSE; |
837 | ssize_t size; | ||
783 | //int skipFileFlag=FALSE; | 838 | //int skipFileFlag=FALSE; |
784 | struct TarBallInfo tbInfo; | 839 | struct TarBallInfo tbInfo; |
785 | tbInfo.verboseFlag = verboseFlag; | 840 | tbInfo.verboseFlag = verboseFlag; |
@@ -814,6 +869,10 @@ static int writeTarFile(const char* tarName, int tostdoutFlag, | |||
814 | errorFlag = TRUE; | 869 | errorFlag = TRUE; |
815 | } | 870 | } |
816 | } | 871 | } |
872 | /* Write two empty blocks to the end of the archive */ | ||
873 | for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { | ||
874 | write(tbInfo.tarFd, "\0", 1); | ||
875 | } | ||
817 | /* Hang up the tools, close up shop, head home */ | 876 | /* Hang up the tools, close up shop, head home */ |
818 | close(tarFd); | 877 | close(tarFd); |
819 | if (errorFlag == TRUE) { | 878 | if (errorFlag == TRUE) { |
@@ -783,7 +783,7 @@ extern int parse_mode(const char *s, mode_t * theMode) | |||
783 | 783 | ||
784 | 784 | ||
785 | 785 | ||
786 | #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS) | 786 | #if defined BB_CHMOD_CHOWN_CHGRP || defined BB_PS || defined BB_LS || defined BB_TAR |
787 | 787 | ||
788 | /* Use this to avoid needing the glibc NSS stuff | 788 | /* Use this to avoid needing the glibc NSS stuff |
789 | * This uses storage buf to hold things. | 789 | * This uses storage buf to hold things. |
@@ -858,7 +858,7 @@ void my_getgrgid(char *group, gid_t gid) | |||
858 | } | 858 | } |
859 | 859 | ||
860 | 860 | ||
861 | #endif /* BB_CHMOD_CHOWN_CHGRP || BB_PS */ | 861 | #endif /* BB_CHMOD_CHOWN_CHGRP || BB_PS || BB_LS || BB_TAR */ |
862 | 862 | ||
863 | 863 | ||
864 | 864 | ||