diff --git a/.gitignore b/.gitignore index 42815d8..de62e8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -SOURCES/coreutils-8.30.tar.xz -/coreutils-8.30.tar.xz +/coreutils-[0-9.]*.tar.xz diff --git a/STAGE1-coreutils b/STAGE1-coreutils new file mode 100644 index 0000000..bfe73b5 --- /dev/null +++ b/STAGE1-coreutils @@ -0,0 +1,7 @@ +srpm coreutils +mcd $BUILDDIR/$1 +(cd $SRC/${1}-*/ ; autoreconf -vif) +$SRC/${1}-*/configure $TCONFIGARGS --disable-pam +notparallel +make $J man1_MANS= V=1 +make $J man1_MANS= install DESTDIR=${ROOTFS} diff --git a/coreutils-8.30.tar.xz.sig b/coreutils-8.30.tar.xz.sig new file mode 100644 index 0000000..34681ce --- /dev/null +++ b/coreutils-8.30.tar.xz.sig @@ -0,0 +1,17 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2 + +iQIcBAABCAAGBQJbOYLXAAoJEN9v2XEwYDfZFRwP/1xKMtXTqCOnP3ECRze+bYnX +GB5Mm57kcP2NXwzo62+9C+FToEfkRTALtlU95edIRlsjLGBoDvv12fsOKdsyO/c5 +7paI3NoaUFyJxby9w91mNOcgN6eR5WZ/LHm2VbTs5VFpsNcSVyHSvhiqgPXtRrVp +ZrnUKbg9iWjn8jcJHIS7qrIO4GsoFzfhn9gVh8Xxp4AYx0btn3BwPTWCxg53Ie0p +OgrMmMnOe3wrpwrlJOgfvpk5na7yKRt7GYsyGMaKB7OxbHlVg4UCx4LuRBnaUPZr +QmlX37sIR/sEJne0zR4iMorPi5IsErMT39VaBDLnsAjyccbmYQ/RmFYASiM5Zijw +d94fk+TocyDBrOMsO5fzKUID5Uf4c5vJlhCXBsPBykNiKsQTb3M7fZ+gjYrMJmoS +4DDgAMryoB5yc2i9HcNj8WMNHy4RGIrRWxOAUZf5j2zEEVwKaRcoNosFoycUotEA +yoWdRIwyCkVwlemVhx0zQTm8WbtFl0kkAFKTqu7uHGUGOKSS4dzTi000cJ4qHSyY +ODrouvKgqKwB+Q7IfpQ72i6DLpTzNjLKNMipBPsSkSW+RaWC67+smo1vL9V5ZlfX +ypzjMF++r3cRuIWG9IwAwedl/sH7iqjHwdMf4y+8sGxRzW5Oeyvx20TvqxMqRLGD +nU0Y2GCLW7C2Idw+I5QM +=pibq +-----END PGP SIGNATURE----- diff --git a/coreutils-8.5-dircolors.patch b/coreutils-8.5-dircolors.patch new file mode 100644 index 0000000..8707c0a --- /dev/null +++ b/coreutils-8.5-dircolors.patch @@ -0,0 +1,13 @@ +diff -urNp coreutils-8.5-orig/src/dircolors.hin coreutils-8.5/src/dircolors.hin +--- coreutils-8.5-orig/src/dircolors.hin 2010-04-20 21:52:04.000000000 +0200 ++++ coreutils-8.5/src/dircolors.hin 2010-07-22 16:18:41.978036926 +0200 +@@ -127,6 +127,9 @@ EXEC 01;32 + .deb 01;31 + .rpm 01;31 + .jar 01;31 ++.war 01;31 ++.ear 01;31 ++.sar 01;31 + .rar 01;31 + .ace 01;31 + .zoo 01;31 diff --git a/coreutils-colorls.csh b/coreutils-colorls.csh old mode 100755 new mode 100644 diff --git a/coreutils-colorls.sh b/coreutils-colorls.sh old mode 100755 new mode 100644 diff --git a/coreutils-i18n-cut.patch b/coreutils-i18n-cut.patch new file mode 100644 index 0000000..f4015d1 --- /dev/null +++ b/coreutils-i18n-cut.patch @@ -0,0 +1,587 @@ +(sb) lin18nux/lsb compliance - cut - not stable enough, not applied + +--- coreutils-8.24/src/cut.c 2015-06-26 19:05:22.000000000 +0200 ++++ cut.c 2016-01-15 10:15:04.863804121 +0100 +@@ -28,6 +28,11 @@ + #include + #include + #include ++ ++#include ++#include ++#include ++ + #include "system.h" + + #include "error.h" +@@ -61,25 +66,16 @@ + CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ + static struct field_range_pair *current_rp; + +-/* This buffer is used to support the semantics of the -s option +- (or lack of same) when the specified field list includes (does +- not include) the first field. In both of those cases, the entire +- first field must be read into this buffer to determine whether it +- is followed by a delimiter or a newline before any of it may be +- output. Otherwise, cut_fields can do the job without using this +- buffer. */ +-static char *field_1_buffer; +- +-/* The number of bytes allocated for FIELD_1_BUFFER. */ +-static size_t field_1_bufsize; +- + enum operating_mode + { + undefined_mode, + +- /* Output characters that are in the given bytes. */ ++ /* Output the given bytes. */ + byte_mode, + ++ /* Output characters that are in the given positions . */ ++ char_mode, ++ + /* Output the given delimiter-separated fields. */ + field_mode + }; +@@ -91,12 +87,16 @@ static enum operating_mode operating_mode; + with field mode. */ + static bool suppress_non_delimited; + ++/* Unless true, we do not recognize multibyte characters in byte-splitting ++ mode. */ ++static bool no_break_mb_chars; ++ + /* If true, print all bytes, characters, or fields _except_ + those that were specified. */ + static bool complement; + + /* The delimiter character for field mode. */ +-static unsigned char delim; ++static mbf_char_t delim; + + /* The delimiter for each line/record. */ + static unsigned char line_delim = '\n'; +@@ -109,7 +109,7 @@ static size_t output_delimiter_length; + + /* The output field separator string. Defaults to the 1-character + string consisting of the input delimiter. */ +-static char *output_delimiter_string; ++static char const *output_delimiter_string; + + /* True if we have ever read standard input. */ + static bool have_read_stdin; +@@ -164,7 +164,7 @@ Print selected parts of lines from each FILE to standard output.\n\ + -f, --fields=LIST select only these fields; also print any line\n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ +- -n (ignored)\n\ ++ -n with -b, don't split multibyte characters\n\ + "), stdout); + fputs (_("\ + --complement complement the set of selected bytes, characters\n\ +@@ -211,6 +211,12 @@ next_item (size_t *item_idx) + current_rp++; + } + ++static inline void ++next_item_n (size_t *item_idx, size_t n) ++{ ++ while (n-- > 0) ++ next_item (item_idx); ++} + /* Return nonzero if the K'th field or byte is printable. */ + + static inline bool +@@ -219,6 +225,15 @@ print_kth (size_t k) + return current_rp->lo <= k; + } + ++/* The lo and hi params should be used for the current characters byte position ++ * and byte size, respectively. */ ++static inline bool ++rp_intersect (size_t lo, size_t hi) ++{ ++ return ((current_rp->lo <= lo && current_rp->hi >= lo) ++ || (current_rp->lo <= hi && current_rp->hi >= hi)); ++} ++ + /* Return nonzero if K'th byte is the beginning of a range. */ + + static inline bool +@@ -281,23 +296,215 @@ cut_bytes (FILE *stream) + } + + /* Read from stream STREAM, printing to standard output any selected fields. */ ++extern ssize_t ++mb_getndelim2 (mbf_char_t **lineptr, size_t *linesize, size_t nmax, ++ mbf_char_t delim1, mbf_char_t delim2, mb_file_t *stream) ++{ ++/* The maximum value that getndelim2 can return without suffering from ++ overflow problems, either internally (because of pointer ++ subtraction overflow) or due to the API (because of ssize_t). */ ++#define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX) ++ ++/* Try to add at least this many bytes when extending the buffer. ++ MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */ ++#define MIN_CHUNK 64 ++ size_t nchars_avail; /* Allocated but unused chars in *LINEPTR. */ ++ mbf_char_t *read_pos; /* Where we're reading into *LINEPTR. */ ++ ssize_t chars_stored = -1; ++ mbf_char_t *ptr = *lineptr; ++ size_t size = *linesize; ++ bool found_delimiter; ++ ++ if (!ptr) ++ { ++ size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK; ++ ptr = malloc (size * sizeof (mbf_char_t)); ++ if (!ptr) ++ return -1; ++ } ++ ++ if (size < 0) ++ goto done; ++ ++ nchars_avail = size; ++ read_pos = ptr; ++ ++ if (nchars_avail == 0 && nmax <= size) ++ goto done; ++ ++ /* Normalize delimiters, since memchr2 doesn't handle EOF. */ ++ if (mb_iseof (delim1)) ++ mb_copy (&delim1, &delim2); ++ else if (mb_iseof (delim2)) ++ mb_copy (&delim2, &delim1); ++ ++ flockfile (stream); ++ ++ found_delimiter = false; ++ do ++ { ++ /* Here always ptr + size == read_pos + nchars_avail. ++ Also nchars_avail > 0 || size < nmax. */ ++ ++ mbf_char_t c IF_LINT (= 0); ++ { ++ mbf_getc (c, *stream); ++ if (mb_iseof (c)) ++ { ++ /* Return partial line, if any. */ ++ if (read_pos == ptr) ++ goto unlock_done; ++ else ++ break; ++ } ++ if (mb_equal (c, delim1) || mb_equal (c, delim2)) ++ found_delimiter = true; ++ } ++ ++ /* We always want at least one byte left in the buffer, since we ++ always (unless we get an error while reading the first byte) ++ NUL-terminate the line buffer. */ ++ ++ if (!nchars_avail) ++ { ++ /* Grow size proportionally, not linearly, to avoid O(n^2) ++ running time. */ ++ size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size; ++ mbf_char_t *newptr; ++ ++ /* Respect nmax. This handles possible integer overflow. */ ++ if (! (size < newsize && newsize <= nmax)) ++ newsize = nmax; ++ ++ if (GETNDELIM2_MAXIMUM < newsize) ++ { ++ size_t newsizemax = GETNDELIM2_MAXIMUM + 1; ++ if (size == newsizemax) ++ goto unlock_done; ++ newsize = newsizemax; ++ } ++ nchars_avail = newsize - (read_pos - ptr); ++ newptr = realloc (ptr, newsize * sizeof (mbf_char_t)); ++ if (!newptr) ++ goto unlock_done; ++ ptr = newptr; ++ size = newsize; ++ read_pos = size - nchars_avail + ptr; ++ } ++ ++ /* Here, if size < nmax, nchars_avail >= buffer_len + 1. ++ If size == nmax, nchars_avail > 0. */ ++ ++ if (1 < nchars_avail--) ++ { ++ mb_copy(read_pos++, &c); ++ } ++ ++ } ++ while (!found_delimiter); ++ ++ chars_stored = (read_pos - ptr); ++ ++ unlock_done: ++ funlockfile (stream); ++ ++ done: ++ *lineptr = ptr; ++ *linesize = size; ++ return chars_stored; ++} ++ ++static void ++cut_chars (FILE *stream) ++{ ++ size_t char_idx; /* Number of chars in the line so far. */ ++ bool print_delimiter; ++ mbf_char_t c; ++ mb_file_t mbf; ++ ++ print_delimiter = false; ++ char_idx = 0; ++ current_rp = frp; ++ ++ mbf_init (mbf, stream); ++ while (true) ++ { ++ mbf_getc (c, mbf); ++ ++ if (mb_iseq (c, line_delim)) ++ { ++ putc (line_delim, stdout); ++ char_idx = 0; ++ print_delimiter = false; ++ current_rp = frp; ++ } ++ else if (mb_iseof (c)) ++ { ++ if (char_idx > 0) ++ putc (line_delim, stdout); ++ break; ++ } ++ else ++ { ++ /* Forward by one byte. */ ++ next_item (&char_idx); ++ ++ /* Check if the current characters byte range is within ++ * the argument list. */ ++ if (rp_intersect (char_idx, char_idx + mb_len (c) - 1)) ++ { ++ if (output_delimiter_specified) ++ { ++ if (print_delimiter && is_range_start_index (char_idx)) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ print_delimiter = true; ++ } ++ mb_putc (c, stdout); ++ } ++ ++ /* Byte mode with multibyte characters uncut (-b -n). */ ++ if (no_break_mb_chars) ++ /* Forward by an additional byte_length (c) - 1. */ ++ next_item_n (&char_idx, mb_len (c) - 1); ++ } ++ } ++} + + static void + cut_fields (FILE *stream) + { +- int c; ++ ++ /* This buffer is used to support the semantics of the -s option ++ (or lack of same) when the specified field list includes (does ++ not include) the first field. In both of those cases, the entire ++ first field must be read into this buffer to determine whether it ++ is followed by a delimiter or a newline before any of it may be ++ output. Otherwise, cut_fields can do the job without using this ++ buffer. */ ++ mbf_char_t *field_1_buffer = 0; ++ /* The number of bytes allocated for FIELD_1_BUFFER. */ ++ size_t field_1_bufsize; ++ ++ ++ mbf_char_t c, d; ++ mb_file_t mbf; + size_t field_idx = 1; + bool found_any_selected_field = false; + bool buffer_first_field; + + current_rp = frp; + +- c = getc (stream); +- if (c == EOF) ++ mbf_init (mbf, stream); ++ mbf_getc (c, mbf); ++ if (mb_iseof (c)) + return; + +- ungetc (c, stream); +- c = 0; ++ mbf_ungetc (c, mbf); ++ mb_setascii (&c, 0); ++ mb_copy (&d, &delim); + + /* To support the semantics of the -s flag, we may have to buffer + all of the first field to determine whether it is 'delimited.' +@@ -312,10 +519,14 @@ cut_fields (FILE *stream) + if (field_idx == 1 && buffer_first_field) + { + ssize_t len; +- size_t n_bytes; ++ size_t n_chars; ++ mbf_char_t nl; ++ mb_setascii (&nl, line_delim); ++ ++ len = mb_getndelim2 (&field_1_buffer, &field_1_bufsize, ++ GETNLINE_NO_LIMIT, d, nl, &mbf); ++ + +- len = getndelim2 (&field_1_buffer, &field_1_bufsize, 0, +- GETNLINE_NO_LIMIT, delim, line_delim, stream); + if (len < 0) + { + free (field_1_buffer); +@@ -325,15 +536,15 @@ cut_fields (FILE *stream) + xalloc_die (); + } + +- n_bytes = len; +- assert (n_bytes != 0); ++ n_chars = len; ++ //assert (n_chars != 0); + +- c = 0; ++ mb_setascii (&c, 0); + + /* If the first field extends to the end of line (it is not + delimited) and we are printing all non-delimited lines, + print this one. */ +- if (to_uchar (field_1_buffer[n_bytes - 1]) != delim) ++ if (!mb_equal (field_1_buffer[n_chars - 1], d)) + { + if (suppress_non_delimited) + { +@@ -341,26 +552,30 @@ cut_fields (FILE *stream) + } + else + { +- fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); ++ for (int i = 0; i < n_chars; ++i) ++ mb_putc (field_1_buffer[i], stdout); ++ + /* Make sure the output line is newline terminated. */ +- if (field_1_buffer[n_bytes - 1] != line_delim) ++ if (!mb_iseq (field_1_buffer[n_chars - 1], line_delim)) + putchar (line_delim); +- c = line_delim; ++ mb_setascii (&c, line_delim); + } + continue; + } + if (print_kth (1)) + { + /* Print the field, but not the trailing delimiter. */ +- fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); ++ for (int i = 0; i < n_chars - 1; ++i) ++ mb_putc (field_1_buffer[i], stdout); + + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ +- if (delim == line_delim) ++ if (mb_iseq (d, line_delim)) + { +- int last_c = getc (stream); +- if (last_c != EOF) ++ mbf_char_t last_c; ++ mbf_getc (last_c, mbf); ++ if (!mb_iseof (last_c)) + { +- ungetc (last_c, stream); ++ mbf_ungetc (last_c, mbf); + found_any_selected_field = true; + } + } +@@ -370,7 +585,8 @@ cut_fields (FILE *stream) + next_item (&field_idx); + } + +- int prev_c = c; ++ mbf_char_t prev_c; ++ mb_copy (&prev_c, &c); + + if (print_kth (field_idx)) + { +@@ -381,42 +597,46 @@ cut_fields (FILE *stream) + } + found_any_selected_field = true; + +- while ((c = getc (stream)) != delim && c != line_delim && c != EOF) ++ mbf_getc (c, mbf); ++ while (!mb_equal (c, d) && !mb_iseq (c, line_delim) && !mb_iseof (c)) + { +- putchar (c); +- prev_c = c; ++ mb_putc (c, stdout); ++ mb_copy (&prev_c, &c); ++ mbf_getc (c, mbf); + } + } + else + { +- while ((c = getc (stream)) != delim && c != line_delim && c != EOF) ++ mbf_getc (c, mbf); ++ while (!mb_equal (c, d) && !mb_iseq (c, line_delim) && !mb_iseof (c)) + { +- prev_c = c; ++ mb_copy (&prev_c, &c); ++ mbf_getc (c, mbf); + } + } + + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ +- if (delim == line_delim && c == delim) ++ if (mb_iseq (d, line_delim) && mb_equal (c, d)) + { +- int last_c = getc (stream); +- if (last_c != EOF) +- ungetc (last_c, stream); ++ mbf_char_t last_c; ++ mbf_getc (last_c, mbf); ++ if (!mb_iseof (last_c)) ++ mbf_ungetc (last_c, mbf); + else +- c = last_c; ++ mb_copy (&c, &last_c); + } + +- if (c == delim) ++ if (mb_equal (c, d)) + next_item (&field_idx); +- else if (c == line_delim || c == EOF) ++ else if (mb_iseq (c, line_delim) || mb_iseof (c)) + { + if (found_any_selected_field + || !(suppress_non_delimited && field_idx == 1)) + { +- if (c == line_delim || prev_c != line_delim +- || delim == line_delim) ++ if (mb_iseq (c, line_delim) || !mb_iseq (prev_c, line_delim) || mb_iseq (d, line_delim)) + putchar (line_delim); + } +- if (c == EOF) ++ if (mb_iseof (c)) + break; + field_idx = 1; + current_rp = frp; +@@ -429,7 +649,14 @@ static void + cut_stream (FILE *stream) + { + if (operating_mode == byte_mode) +- cut_bytes (stream); ++ { ++ if (no_break_mb_chars) ++ cut_chars (stream); ++ else ++ cut_bytes (stream); ++ } ++ else if (operating_mode == char_mode) ++ cut_chars (stream); + else + cut_fields (stream); + } +@@ -483,6 +710,7 @@ main (int argc, char **argv) + bool ok; + bool delim_specified = false; + char *spec_list_string IF_LINT ( = NULL); ++ mbi_iterator_t iter; + + initialize_main (&argc, &argv); + set_program_name (argv[0]); +@@ -496,8 +724,10 @@ main (int argc, char **argv) + + /* By default, all non-delimited lines are printed. */ + suppress_non_delimited = false; ++ /* Default behaviour for -b, unless -n is also specified. */ ++ no_break_mb_chars = false; + +- delim = '\0'; ++ mb_setascii (&delim, '\0'); + have_read_stdin = false; + + while ((optc = getopt_long (argc, argv, "b:c:d:f:nsz", longopts, NULL)) != -1) +@@ -505,7 +735,6 @@ main (int argc, char **argv) + switch (optc) + { + case 'b': +- case 'c': + /* Build the byte list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); +@@ -513,6 +742,14 @@ main (int argc, char **argv) + spec_list_string = optarg; + break; + ++ case 'c': ++ /* Build the char list. */ ++ if (operating_mode != undefined_mode) ++ FATAL_ERROR (_("only one type of list may be specified")); ++ operating_mode = char_mode; ++ spec_list_string = optarg; ++ break; ++ + case 'f': + /* Build the field list. */ + if (operating_mode != undefined_mode) +@@ -524,9 +761,17 @@ main (int argc, char **argv) + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ +- if (optarg[0] != '\0' && optarg[1] != '\0') ++ mbi_init (iter, optarg, strlen (optarg)); ++ if (!mbi_avail (iter)) ++ mb_setascii (&delim, '\0'); ++ else ++ { ++ mb_copy (&delim, &mbi_cur (iter)); ++ ++ mbi_advance (iter); ++ if (mbi_avail (iter)) + FATAL_ERROR (_("the delimiter must be a single character")); +- delim = optarg[0]; ++ } + delim_specified = true; + break; + +@@ -540,6 +785,7 @@ main (int argc, char **argv) + break; + + case 'n': ++ no_break_mb_chars = true; + break; + + case 's': +@@ -579,15 +825,12 @@ main (int argc, char **argv) + | (complement ? SETFLD_COMPLEMENT : 0) ); + + if (!delim_specified) +- delim = '\t'; ++ mb_setascii (&delim, '\t'); + + if (output_delimiter_string == NULL) + { +- static char dummy[2]; +- dummy[0] = delim; +- dummy[1] = '\0'; +- output_delimiter_string = dummy; +- output_delimiter_length = 1; ++ output_delimiter_string = mb_ptr (delim); ++ output_delimiter_length = mb_len (delim); + } + + if (optind == argc) diff --git a/rh_i18n_wip.tar.gz b/rh_i18n_wip.tar.gz new file mode 100644 index 0000000..24b7cdc Binary files /dev/null and b/rh_i18n_wip.tar.gz differ diff --git a/tests/readlink-cannot-handle-recursive-symlinks/Makefile b/tests/readlink-cannot-handle-recursive-symlinks/Makefile new file mode 100644 index 0000000..49d37a7 --- /dev/null +++ b/tests/readlink-cannot-handle-recursive-symlinks/Makefile @@ -0,0 +1,63 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/coreutils/readlink-cannot-handle-recursive-symlink s +# Description: Test for readlink cannot handle recursive symlinks +# Author: Jan Scotka +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2010 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/coreutils/readlink-cannot-handle-recursive-symlinks +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Jan Scotka " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Test for readlink cannot handle recursive symlinks" >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RunFor: coreutils" >> $(METADATA) + @echo "Requires: coreutils" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/readlink-cannot-handle-recursive-symlinks/PURPOSE b/tests/readlink-cannot-handle-recursive-symlinks/PURPOSE new file mode 100644 index 0000000..b9fd740 --- /dev/null +++ b/tests/readlink-cannot-handle-recursive-symlinks/PURPOSE @@ -0,0 +1,54 @@ +PURPOSE of /CoreOS/coreutils/readlink-cannot-handle-recursive-symlinks +Description: Test for readlink cannot handle recursive symlinks +Author: Jan Scotka +Bug summary: readlink cannot handle recursive symlinks + +Description: + +Description of problem: +The readlink command fails with an error "Too many levels of symbolic links", even if there are only 2 levels. + +The readlink command from RHEL 3 and RHEL 4 and from Fedora 11 all work fine. + +Among other changes between RHEL 4 and RHEL 5, RHEL 5's coreutils added calls to cycle_check() in lib/canonicalize.c, but in upstream canonicalize.c (now in gnulib instead of coreutils), we see the comment: + /* Detect loops. We cannot use the cycle-check module here, + since it's actually possible to encounter the same symlink + more than once in a given traversal. However, encountering + the same symlink,NAME pair twice does indicate a loop. */ + +http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/canonicalize.c;h=4f348398fd69ae516396313d18ac294a4ca3dde3;hb=b653eda3ac4864de205419d9f41eec267cb89eeb#l262 + +The latest canonicalize.c uses seen_triple() instead of cycle_check(). + + +Version-Release number of selected component (if applicable): +coreutils-5.97-19.el5 + +How reproducible: +every time + +Steps to Reproduce: +1. Create a directory with a symlink to itself + mkdir /tmp/dir + cd /tmp/dir + ln -s ../dir dirlink + +2. Run readlink using the 'dirlink' symlink recursively + readlink -v -f dirlink + readlink -v -f dirlink/dirlink + readlink -v -f dirlink/dirlink/dirlink + +Actual results: +The first readlink command on just dirlink succeeds, but the 2nd and 3rd commands fail with + readlink: dirlink/dirlink: Too many levels of symbolic links + +Expected results: +$ readlink -v -f dirlink +/tmp/dir +$ readlink -v -f dirlink/dirlink +/tmp/dir +$ readlink -v -f dirlink/dirlink/dirlink +/tmp/dir + + +Additional info: diff --git a/tests/readlink-cannot-handle-recursive-symlinks/runtest.sh b/tests/readlink-cannot-handle-recursive-symlinks/runtest.sh new file mode 100755 index 0000000..6ee251f --- /dev/null +++ b/tests/readlink-cannot-handle-recursive-symlinks/runtest.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/coreutils/readlink-cannot-handle-recursive-symlinks +# Description: Test for readlink cannot handle recursive symlinks +# Author: Jan Scotka +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2010 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include rhts environment +. /usr/bin/rhts-environment.sh +. /usr/lib/beakerlib/beakerlib.sh + +PACKAGE="coreutils" + +rlJournalStart + rlPhaseStartSetup + rlAssertRpm $PACKAGE + rlRun "TmpDir=\`mktemp -d\`" 0 "Creating tmp directory" + rlRun "pushd $TmpDir" + rlRun "mkdir link" 0 "Creating test directory" + rlRun "cd link" 0 "cd to this dir" + rlRun "ln -s ../link link" 0 "creating symlink to ../link -> link" + rlPhaseEnd + + rlPhaseStartTest + rlLog "Test of readlink up to 20 iteration" + export TMPVAR="link" + for foo in `seq 20` + do echo $TMPVAR + rlRun "readlink -v -f $TMPVAR" 0 "readlink of $TMPVAR" + TMPVAR="$TMPVAR/link" + done + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "popd" + rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + rlPhaseEnd +rlJournalPrintText +rlJournalEnd diff --git a/tests/test-basics b/tests/test-basics new file mode 100755 index 0000000..7324553 --- /dev/null +++ b/tests/test-basics @@ -0,0 +1,39 @@ +#!/bin/sh + +# Checks that touch ls rm and foo work +# https://www.mankier.com/1/beakerlib#Examples +. /usr/share/beakerlib/beakerlib.sh + +# Set the full test name +TEST="/examples/beakerlib/Sanity/phases" + +# Package being tested +PACKAGE="coreutils" + +rlJournalStart + # Setup phase: Prepare test directory + rlPhaseStartSetup + rlAssertRpm $PACKAGE + rlRun 'TmpDir=$(mktemp -d)' 0 'Creating tmp directory' # no-reboot + rlRun "pushd $TmpDir" + rlPhaseEnd + + # Test phase: Testing touch, ls and rm commands + rlPhaseStartTest + rlRun "touch foo" 0 "Creating the foo test file" + rlAssertExists "foo" + rlRun "ls -l foo" 0 "Listing the foo test file" + rlRun "rm foo" 0 "Removing the foo test file" + rlAssertNotExists "foo" + rlRun "ls -l foo" 2 "Listing foo should now report an error" + rlPhaseEnd + + # Cleanup phase: Remove test directory + rlPhaseStartCleanup + rlRun "popd" + rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + rlPhaseEnd +rlJournalEnd + +# Print the test report +rlJournalPrintText diff --git a/tests/test_basics.yml b/tests/test_basics.yml new file mode 100644 index 0000000..d5727cf --- /dev/null +++ b/tests/test_basics.yml @@ -0,0 +1,9 @@ +--- +# This first play always runs on the local staging system +- hosts: localhost + tags: + - atomic + - classic + - container + roles: + - { role: standard-test-beakerlib, tests: [ test-basics, readlink-cannot-handle-recursive-symlinks ] } diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..529263d --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,2 @@ +# Fedora Continuous Integration: https://fedoraproject.org/wiki/CI +- include: test_basics.yml diff --git a/upstream-key.gpg b/upstream-key.gpg new file mode 100644 index 0000000..dc6dc1d --- /dev/null +++ b/upstream-key.gpg @@ -0,0 +1,123 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.6 (GNU/Linux) + +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 +Ke4= +=zRdO +-----END PGP PUBLIC KEY BLOCK-----