From 71876a1be437fec90d67bae4d30a4525aa51db4b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 24 Jul 2008 23:22:09 +0200 Subject: [PATCH] mount: add fallback for versionsort() I was trying to build util-linux-ng on uclibc and it failed | lomount.c: In function 'looplist_next': | lomount.c:223: error: 'versionsort' undeclared (first use in this function) | lomount.c:223: error: (Each undeclared identifier is reported only once | lomount.c:223: error: for each function it appears in.) | make[2]: *** [mount-lomount.o] Error 1 | which is understood because versionsort is GNU extension and uclibc does not implement it. Reported-by: Khem Raj Signed-off-by: Karel Zak --- configure.ac | 5 ++ include/strverscmp.h | 7 +++ lib/strverscmp.c | 120 +++++++++++++++++++++++++++++++++++++++++++ mount/Makefile.am | 10 +++- mount/lomount.c | 4 ++ 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 include/strverscmp.h create mode 100644 lib/strverscmp.c diff --git a/configure.ac b/configure.ac index 5b357d18..8f109b1e 100644 --- a/configure.ac +++ b/configure.ac @@ -72,9 +72,14 @@ AC_CHECK_FUNCS( updwtmp \ lchown \ inotify_init \ + versionsort \ rpmatch]) AC_FUNC_FSEEKO +have_versionsort=no +AC_CHECK_FUNC([versionsort], [have_versionsort=yes]) +AM_CONDITIONAL([HAVE_VERSIONSORT], test "x$have_versionsort" = xyes) + dnl Static compilation m4_define([UTIL_STATIC_PROGRAMS], [losetup, mount, umount, fdisk, sfdisk]) diff --git a/include/strverscmp.h b/include/strverscmp.h new file mode 100644 index 00000000..23ec6709 --- /dev/null +++ b/include/strverscmp.h @@ -0,0 +1,7 @@ +#ifndef STRVERSCMP_H +#define STRVERSCMP_H + +extern int strverscmp (const char *s1, const char *s2); +extern int versionsort (const void *a, const void *b); + +#endif diff --git a/lib/strverscmp.c b/lib/strverscmp.c new file mode 100644 index 00000000..7de473bf --- /dev/null +++ b/lib/strverscmp.c @@ -0,0 +1,120 @@ +/* Compare strings while treating digits characters numerically. + Copyright (C) 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jean-François Bignolles , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +/* states: S_N: normal, S_I: comparing integral part, S_F: comparing + fractionnal parts, S_Z: idem but with leading Zeroes only */ +#define S_N 0x0 +#define S_I 0x4 +#define S_F 0x8 +#define S_Z 0xC + +/* result_type: CMP: return diff; LEN: compare using len_diff/diff */ +#define CMP 2 +#define LEN 3 + + +/* Compare S1 and S2 as strings holding indices/version numbers, + returning less than, equal to or greater than zero if S1 is less than, + equal to or greater than S2 (for more info, see the texinfo doc). +*/ + +int +strverscmp (s1, s2) + const char *s1; + const char *s2; +{ + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + int state; + int diff; + + /* Symbol(s) 0 [1-9] others (padding) + Transition (10) 0 (01) d (00) x (11) - */ + static const unsigned int next_state[] = + { + /* state x d 0 - */ + /* S_N */ S_N, S_I, S_Z, S_N, + /* S_I */ S_N, S_I, S_I, S_I, + /* S_F */ S_N, S_F, S_F, S_F, + /* S_Z */ S_N, S_F, S_Z, S_Z + }; + + static const int result_type[] = + { + /* state x/x x/d x/0 x/- d/x d/d d/0 d/- + 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ + + /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP, + +1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, + /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP, + -1, CMP, CMP, CMP + }; + + if (p1 == p2) + return 0; + + c1 = *p1++; + c2 = *p2++; + /* Hint: '0' is a digit too. */ + state = S_N | ((c1 == '0') + (isdigit (c1) != 0)); + + while ((diff = c1 - c2) == 0 && c1 != '\0') + { + state = next_state[state]; + c1 = *p1++; + c2 = *p2++; + state |= (c1 == '0') + (isdigit (c1) != 0); + } + + state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))]; + + switch (state) + { + case CMP: + return diff; + + case LEN: + while (isdigit (*p1++)) + if (!isdigit (*p2++)) + return 1; + + return isdigit (*p2) ? -1 : diff; + + default: + return state; + } +} + + +int +versionsort (const void *a, const void *b) +{ + return strverscmp ((*(const struct dirent **) a)->d_name, + (*(const struct dirent **) b)->d_name); +} diff --git a/mount/Makefile.am b/mount/Makefile.am index a43fcd5d..43b3d6d8 100644 --- a/mount/Makefile.am +++ b/mount/Makefile.am @@ -8,13 +8,18 @@ dist_man_MANS = fstab.5 mount.8 swapoff.8 swapon.8 umount.8 losetup.8 utils_common = sundries.c xmalloc.c realpath.c fsprobe.c +if !HAVE_VERSIONSORT +fallback = ../lib/strverscmp.c +endif + headers_common = fstab.h mount_mntent.h mount_constants.h \ lomount.h fsprobe.h realpath.h xmalloc.h \ getusername.h loop.h sundries.h mount_common = fstab.c mount_mntent.c getusername.c lomount.c \ $(utils_common) $(headers_common) ../lib/env.c ../lib/linux_version.c \ - ../lib/blkdev.c + ../lib/blkdev.c $(fallback) + mount_SOURCES = mount.c $(mount_common) ../lib/setproctitle.c mount_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS) @@ -27,9 +32,10 @@ umount_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS) swapon_SOURCES = swapon.c swap_constants.h $(utils_common) losetup_SOURCES = lomount.c sundries.c xmalloc.c realpath.c \ - loop.h lomount.h xmalloc.h sundries.h realpath.h + loop.h lomount.h xmalloc.h sundries.h realpath.h $(fallback) losetup_CPPFLAGS = -DMAIN $(AM_CPPFLAGS) + mount_LDADD = $(LDADD_common) umount_LDADD = $(LDADD_common) swapon_LDADD = $(LDADD_common) diff --git a/mount/lomount.c b/mount/lomount.c index 79370524..b9a83c6b 100644 --- a/mount/lomount.c +++ b/mount/lomount.c @@ -25,6 +25,10 @@ #include "xmalloc.h" #include "realpath.h" +#ifndef HAVE_VERSIONSORT +# include "strverscmp.h" +#endif + #define SIZE(a) (sizeof(a)/sizeof(a[0])) #ifdef LOOP_SET_FD -- 2.39.5