I knew I'd seen this symlink patch before:

        https://lists.dulug.duke.edu/pipermail/rpm-devel/2006-April/001037.html

I did not like the patch the first time, and I don't like it 5 years later.

I will rework the issue under #if RPM_VENDOR_MANDRIVA across the board.

Note that the rule (already implemented except you've turned it off)
        All symlinks depend on their end-point.
not only covers the special case of ELF libraries (when the symlink is
explicitly "owned" by a package), but all other cases of symlinks to
end-points in other packages. Yes you will need to teach URPMI and other
depsolvers about symlink end-points constructed from RPMTAG_FILELINKTOS
data, very not hard.

The only remaining "feature" is the explicit
        Requires: devel(whatever)
added to metadata. I fully realize the difficulties
of transitive closure in "dependency hell", but hey, lets not
go around in circles all over again.

Note that the rule I've stated requires zero additional metadata,
the linkto dependency is constructed on the install box from the symlink
end-points that are already in metadata (but you're likely choosing to
disable that functionality some 4? 5? years after being implemented).

hth

73 de Jeff

On Apr 10, 2011, at 1:23 AM, Per Øyvind Karlsen wrote:

>  RPM Package Manager, CVS Repository
>  http://rpm5.org/cvs/
>  ____________________________________________________________________________
> 
>  Server: rpm5.org                         Name:   Per Øyvind Karlsen
>  Root:   /v/rpm/cvs                       Email:  pkarl...@rpm5.org
>  Module: rpm                              Date:   10-Apr-2011 07:23:26
>  Branch: HEAD                             Handle: 2011041005232500
> 
>  Modified files:
>    rpm                     CHANGES
>    rpm/lib                 librpm.vers rpmds.c rpmds.h rpmfc.c
> 
>  Log:
>    implement devel(libfoo) symlink dependencies from Mandriva, but with
>    proper ELF SONAME checking
> 
>  Summary:
>    Revision    Changes     Path
>    1.3607      +2  -0      rpm/CHANGES
>    1.78        +1  -0      rpm/lib/librpm.vers
>    2.173       +171 -12    rpm/lib/rpmds.c
>    2.82        +13 -0      rpm/lib/rpmds.h
>    1.80        +17 -1      rpm/lib/rpmfc.c
>  ____________________________________________________________________________
> 
>  patch -p0 <<'@@ .'
>  Index: rpm/CHANGES
>  ============================================================================
>  $ cvs diff -u -r1.3606 -r1.3607 CHANGES
>  --- rpm/CHANGES      8 Apr 2011 16:14:15 -0000       1.3606
>  +++ rpm/CHANGES      10 Apr 2011 05:23:25 -0000      1.3607
>  @@ -1,4 +1,6 @@
>   5.4.0 -> 5.4.1:
>  +    - proyvind: rpmds: implement devel(libfoo) symlink dependencies from
>  +    Mandriva, but with proper ELF SONAME checking.
>       - jbj: mongo: stub-in a /usr/lib/rpm/bin mongo shell wrapper.
>       - jbj: spewage: fix: rework sql/json markup to use the EVRD parser.
>       - jbj: build: fix: resurrect %description -l XY yet again.
>  @@ .
>  patch -p0 <<'@@ .'
>  Index: rpm/lib/librpm.vers
>  ============================================================================
>  $ cvs diff -u -r1.77 -r1.78 librpm.vers
>  --- rpm/lib/librpm.vers      27 Sep 2010 23:12:48 -0000      1.77
>  +++ rpm/lib/librpm.vers      10 Apr 2011 05:23:25 -0000      1.78
>  @@ -125,6 +125,7 @@
>       rpmdsSetRefs;
>       rpmdsSetResult;
>       rpmdsSingle;
>  +    rpmdsSymlink;
>       rpmdsSysinfo;
>       rpmdsTagN;
>       rpmdsThis;
>  @@ .
>  patch -p0 <<'@@ .'
>  Index: rpm/lib/rpmds.c
>  ============================================================================
>  $ cvs diff -u -r2.172 -r2.173 rpmds.c
>  --- rpm/lib/rpmds.c  25 Jan 2011 14:47:14 -0000      2.172
>  +++ rpm/lib/rpmds.c  10 Apr 2011 05:23:25 -0000      2.173
>  @@ -2890,19 +2890,37 @@
>    * @param isElf64   is this an ELF64 symbol?
>    */
>   #if defined(HAVE_GELF_H) && defined(HAVE_LIBELF) && !defined(__FreeBSD__)
>  -static char * sonameDep(/*@returned@*/ char * t, const char * s, int 
> isElf64)
>  +static char * sonameDep(/*@returned@*/ char * t, const char * s, int 
> isElf64, int devel)
>       /*@modifies t @*/
>   {
>  +    char *tmp = t;
>       *t = '\0';
>  +    if (devel) {
>  +    tmp = stpcpy(t, "devel(");
>  +    }
>   #if !defined(__alpha__) && !defined(__sun)
>  -    if (isElf64) {
>  -    if (s[strlen(s)-1] != ')')
>  -    (void) stpcpy( stpcpy(t, s), "()(64bit)");
>  -    else
>  -        (void) stpcpy( stpcpy(t, s), "(64bit)");
>  +    if (!isElf64) {
>  +    /* XXX: eehhk, would've been nice with consistency, mandriva legacy... 
> :| */
>  +    if (!devel && s[strlen(s)-1] != ')')
>  +    (void) stpcpy( stpcpy(tmp, s), "()(64bit)");
>  +    else {
>  +        char *suffix;
>  +        tmp = stpcpy(tmp, s);
>  +        if (devel && (suffix = strstr(t, ".so")))
>  +            tmp = suffix;
>  +        tmp = stpcpy(tmp, "(64bit)");
>  +        }
>       }else
>   #endif
>  -    (void) stpcpy(t, s);
>  +    tmp = stpcpy(tmp, s);
>  +    if (devel) {
>  +    char *suffix;
>  +    tmp = stpcpy(tmp, s);
>  +    if (devel && (suffix = strstr(t, ".so")))
>  +        tmp = suffix;
>  +    (void) stpcpy(tmp, ")");
>  +    }
>  +
>       return t;
>   }
>   #endif
>  @@ -3074,7 +3092,7 @@
> 
>                           /* Add next provide dependency. */
>                           ds = rpmdsSingle(RPMTAG_PROVIDES,
>  -                                    sonameDep(t, buf, isElf64),
>  +                                    sonameDep(t, buf, isElf64, 0),
>                                       "", RPMSENSE_FIND_PROVIDES);
>                           xx = add(context, ds);
>                           (void)rpmdsFree(ds);
>  @@ -3127,7 +3145,7 @@
> 
>                           /* Add next require dependency. */
>                           ds = rpmdsSingle(RPMTAG_REQUIRENAME,
>  -                                    sonameDep(t, buf, isElf64),
>  +                                    sonameDep(t, buf, isElf64, 0),
>                                       "", RPMSENSE_FIND_REQUIRES);
>                           xx = add(context, ds);
>                           (void)rpmdsFree(ds);
>  @@ -3169,7 +3187,7 @@
>   assert(s != NULL);
>                       buf[0] = '\0';
>                       ds = rpmdsSingle(RPMTAG_REQUIRENAME,
>  -                            sonameDep(buf, s, isElf64),
>  +                            sonameDep(buf, s, isElf64, 0),
>                               "", RPMSENSE_FIND_REQUIRES);
>                       xx = add(context, ds);
>                       (void)rpmdsFree(ds);
>  @@ -3184,7 +3202,7 @@
>                       /* Add next provide dependency. */
>                       buf[0] = '\0';
>                       ds = rpmdsSingle(RPMTAG_PROVIDENAME,
>  -                            sonameDep(buf, s, isElf64),
>  +                            sonameDep(buf, s, isElf64, 0),
>                               "", RPMSENSE_FIND_PROVIDES);
>                       xx = add(context, ds);
>                       (void)rpmdsFree(ds);
>  @@ -3220,7 +3238,7 @@
>       /* Add next provide dependency. */
>       buf[0] = '\0';
>       ds = rpmdsSingle(RPMTAG_PROVIDENAME,
>  -            sonameDep(buf, s, isElf64), "", RPMSENSE_FIND_PROVIDES);
>  +            sonameDep(buf, s, isElf64, 0), "", RPMSENSE_FIND_PROVIDES);
>       xx = add(context, ds);
>       (void)rpmdsFree(ds);
>       ds = NULL;
>  @@ -3238,6 +3256,147 @@
>   }
>   /*@=moduncon =noeffectuncon @*/
> 
>  +
>  +int rpmdsSymlink(const char * fn, int flags,
>  +            int (*add) (void * context, rpmds ds), void * context)
>  +{
>  +#if defined(HAVE_GELF_H) && defined(HAVE_LIBELF) && !defined(__FreeBSD__)
>  +    Elf * elf;
>  +    Elf_Scn * scn;
>  +    Elf_Data * data;
>  +    GElf_Ehdr ehdr_mem, * ehdr;
>  +    GElf_Shdr shdr_mem, * shdr;
>  +    GElf_Dyn dyn_mem, * dyn;
>  +    int fdno;
>  +    int cnt;
>  +    int i;
>  +    char buf[BUFSIZ];
>  +    const char * s;
>  +    int is_executable;
>  +    const char * soname = NULL;
>  +    rpmds ds;
>  +    int xx;
>  +    int isElf64;
>  +    int gotSONAME = 0;
>  +    int skipP = (flags & RPMELF_FLAG_SKIPPROVIDES);
>  +    int skipR = (flags & RPMELF_FLAG_SKIPREQUIRES);
>  +    int lnklen;
>  +    char path[MAXPATHLEN];
>  +    ARGV_t deps = NULL;
>  +
>  +    if ((lnklen = readlink(fn, path, MAXPATHLEN - 1)) == -1) {
>  +    warn("%s", fn);
>  +    return RPMRC_FAIL;
>  +    }
>  +    path[lnklen] = '\0';
>  +
>  +/*@-castfcnptr@*/
>  +if (_rpmds_debug < 0)
>  +fprintf(stderr, "*** rpmdsELF(%s, %d, %p, %p)\n", fn, flags, (void *)add, 
> context);
>  +/*@=castfcnptr@*/
>  +
>  +    /* Extract dependencies only from files with executable bit set. */
>  +    {       struct stat sb, * st = &sb;
>  +    if (lstat(fn, st) != 0)
>  +        return -1;
>  +    is_executable = (int)(st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));
>  +    }
>  +
>  +    fdno = open(fn, O_RDONLY);
>  +    if (fdno < 0)
>  +    return fdno;
>  +
>  +    (void) elf_version(EV_CURRENT);
>  +
>  +/*@-evalorder@*/
>  +    elf = NULL;
>  +    if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL
>  +     || elf_kind(elf) != ELF_K_ELF
>  +     || (ehdr = gelf_getehdr(elf, &ehdr_mem)) == NULL
>  +     || !(ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC))
>  +    goto exit;
>  +/*@=evalorder@*/
>  +
>  +    isElf64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
>  +
>  +    /*@-uniondef @*/
>  +    scn = NULL;
>  +    while ((scn = elf_nextscn(elf, scn)) != NULL) {
>  +    shdr = gelf_getshdr(scn, &shdr_mem);
>  +    if (shdr == NULL)
>  +        break;
>  +
>  +    soname = _free(soname);
>  +    switch (shdr->sh_type) {
>  +    default:
>  +        continue;
>  +        /*@notreached@*/ /*@switchbreak@*/ break;
>  +    case SHT_DYNAMIC:
>  +        data = NULL;
>  +        while ((data = elf_getdata (scn, data)) != NULL) {
>  +            for (cnt = 0; cnt < (int)(shdr->sh_size / shdr->sh_entsize); 
> ++cnt) {
>  +                dyn = gelf_getdyn (data, cnt, &dyn_mem);
>  +                if (dyn == NULL)
>  +                    /*@innerbreak@*/ break;
>  +                s = NULL;
>  +                switch (dyn->d_tag) {
>  +                default:
>  +                    /*@innercontinue@*/ continue;
>  +                    /*@notreached@*/ /*@switchbreak@*/ break;
>  +                case DT_NEEDED:
>  +                    /* Only from files with executable bit set. */
>  +                    if (skipR || !is_executable)
>  +                        /*@innercontinue@*/ continue;
>  +                    /* Add next require dependency. */
>  +                    s = elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val);
>  +assert(s != NULL);
>  +                    buf[0] = '\0';
>  +                    argvAdd(&deps, s);
>  +                    /*@switchbreak@*/ break;
>  +                case DT_SONAME:
>  +                    gotSONAME = 1;
>  +                    s = elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val);
>  +assert(s != NULL);
>  +                    /* Add next provide dependency. */
>  +                    buf[0] = '\0';
>  +                    if (!skipP) {
>  +                        ds = rpmdsSingle(RPMTAG_PROVIDENAME,
>  +                                sonameDep(buf, s, isElf64, 1),
>  +                                "", RPMSENSE_FIND_PROVIDES);
>  +                        xx = add(context, ds);
>  +                        (void)rpmdsFree(ds);
>  +                        ds = NULL;
>  +                    }
>  +                    /*@switchbreak@*/ break;
>  +                }
>  +            }
>  +        }
>  +        /*@switchbreak@*/ break;
>  +    }
>  +    }
>  +    /*@=uniondef @*/
>  +
>  +exit:
>  +    if (gotSONAME)
>  +    for (i = 0, cnt = argvCount(deps); i < cnt; i++) {
>  +        ds = rpmdsSingle(RPMTAG_REQUIRENAME,
>  +                sonameDep(buf, deps[i], isElf64, 1),
>  +                "", RPMSENSE_FIND_REQUIRES);
>  +        xx = add(context, ds);
>  +        (void)rpmdsFree(ds);
>  +        ds = NULL;
>  +    }
>  +
>  +    deps = argvFree(deps);
>  +    if (elf) (void) elf_end(elf);
>  +    if (fdno > 0)
>  +    xx = close(fdno);
>  +    return 0;
>  +#else
>  +    return -1;
>  +#endif
>  +}
>  +
>   #define     _SBIN_LDCONFIG_P        "/sbin/ldconfig -p"
>   /*@unchecked@*/ /*@observer@*/ /*@owned@*/ /*@relnull@*/
>   static const char * _ldconfig_cmd = _SBIN_LDCONFIG_P;
>  @@ .
>  patch -p0 <<'@@ .'
>  Index: rpm/lib/rpmds.h
>  ============================================================================
>  $ cvs diff -u -r2.81 -r2.82 rpmds.h
>  --- rpm/lib/rpmds.h  6 Mar 2010 15:31:29 -0000       2.81
>  +++ rpm/lib/rpmds.h  10 Apr 2011 05:23:25 -0000      2.82
>  @@ -616,6 +616,19 @@
>   #define RPMELF_FLAG_SKIPREQUIRES    0x2     /*<! rpmdsELF: skip requires */
> 
>   /** \ingroup rpmds
>  + * Extract dependencies from a symlink.
>  + * @param fn                file name
>  + * @param flags             1: skip provides 2: skip requires
>  + * @param *add              add(arg, ds) saves next provide/require symlink 
> dependency.
>  + * @param context   add() callback context
>  + * @return          0 on success
>  + */
>  +int rpmdsSymlink(const char * fn, int flags,
>  +            int (*add) (void * context, rpmds ds), void * context)
>  +    /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
>  +    /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/;
>  +
>  +/** \ingroup rpmds
>    * Load /etc/ld.so.cache provides into a dependency set.
>    * @todo Add dependency colors, and attach to file.
>    * @retval *PRCO    provides/requires/conflicts/obsoletes depedency set(s)
>  @@ .
>  patch -p0 <<'@@ .'
>  Index: rpm/lib/rpmfc.c
>  ============================================================================
>  $ cvs diff -u -r1.79 -r1.80 rpmfc.c
>  --- rpm/lib/rpmfc.c  1 Apr 2011 12:27:28 -0000       1.79
>  +++ rpm/lib/rpmfc.c  10 Apr 2011 05:23:25 -0000      1.80
>  @@ -987,6 +987,21 @@
>       return rpmdsELF(fn, flags, rpmfcMergePR, fc);
>   }
> 
>  +static int rpmfcSYMLINK(rpmfc fc)
>  +    /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
>  +    /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
>  +{
>  +    const char * fn = fc->fn[fc->ix];
>  +    int flags = 0;
>  +
>  +    if (fc->skipProv)
>  +    flags |= RPMELF_FLAG_SKIPPROVIDES;
>  +    if (fc->skipReq)
>  +    flags |= RPMELF_FLAG_SKIPREQUIRES;
>  +
>  +    return rpmdsSymlink(fn, flags, rpmfcMergePR, fc);
>  +}
>  +
>   typedef struct rpmfcApplyTbl_s {
>       int (*func) (rpmfc fc);
>       int colormask;
>  @@ -999,7 +1014,8 @@
>   /*@unchecked@*/
>   static struct rpmfcApplyTbl_s rpmfcApplyTable[] = {
>       { rpmfcELF,             RPMFC_ELF },
>  -    { rpmfcSCRIPT,  
> (RPMFC_SCRIPT|RPMFC_PERL|RPMFC_PYTHON|RPMFC_LIBTOOL|RPMFC_PKGCONFIG|RPMFC_BOURNE|RPMFC_JAVA|RPMFC_PHP|RPMFC_MONO|RPMFC_RUBY)
>  },
>  +    { rpmfcSCRIPT,  
> (RPMFC_SCRIPT|RPMFC_PERL|RPMFC_PYTHON|RPMFC_LIBTOOL|RPMFC_PKGCONFIG|RPMFC_BOURNE|RPMFC_JAVA|RPMFC_PHP|RPMFC_MONO)
>  },
>  +    { rpmfcSYMLINK, RPMFC_SYMLINK },
>       { NULL, 0 }
>   };
>   /*@=nullassign@*/
>  @@ .
> ______________________________________________________________________
> RPM Package Manager                                    http://rpm5.org
> CVS Sources Repository                                rpm-...@rpm5.org

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to