• Re: DEP 17: Improve support for directory aliasing in dpkg

    From Guillem Jover@21:1/5 to Helmut Grohne on Sat Apr 8 04:40:01 2023
    Hi!

    On Mon, 2023-04-03 at 14:02:13 +0200, Helmut Grohne wrote:
    I have been looking into the aliasing problems in dpkg on behalf of Freexian's Debian funding. To that end I proposed a possible way forward
    last year (https://lists.debian.org/debian-dpkg/2022/11/msg00007.html),
    but the feedback I got was not particularly helpful in determining
    consensus.

    I thought my reply was rather clear, and that we had further clarified
    that privately, that at the time I thought there was no other answer
    required as (AFAIR) you stated you'd be digging further on it. And I
    mentioned I'd try to reply to the list, but it didn't feel urgent given
    the clarifications given, neither the timing during the freeze?

    A little later, Simon Richter also looked into the problem (https://lists.debian.org/debian-dpkg/2022/12/msg00023.html), but
    remained silent after the initial post. Little happened since then. Now Raphael Hertzog proposed to use the DEP process to get this thing
    unstuck

    Sigh, a DEP(!?), for a dpkg change? It feels more like a way to exhort
    pressure over this than anything else TBH…

    and with the help of Emilio Pozuelo Monfort I created a draft
    for discussion. I allocate number 17 via debian-project@l.d.o. What
    follows is the draft text. Please consider it to be a piece of best intentions at reconciling feedback wherever I could.

    I'm unlikely to discuss this topic on debian-devel, given previous
    nastiness and abuse.

    The text includes most (but not all) of what I've been saying publicly,
    and what I've tried to further clarify to you and Emilio in private.
    But I think ignores the essence of what I've been repeating all along.

    Introduction
    ============

    At its core, `dpkg` assumes that every filename uniquely refers to a
    file on disk. The situation where two distinct filenames refer to the
    same file on disk is referred to as aliasing.

    (To be precise, I think this describes hardlinks. Aliasing occurs when different pathnames where their last component is not a symlink, all
    refer to the same filename on the same directory. But I don't think this matters much.)

    Proposal
    ========

    In order to handle aliasing efficiently, `dpkg` gains new options `--add-alias <symlink>`, `--remove-alias <symlink>` and
    `--list-aliases`. When creating symbolic links that cause aliasing
    effects, the creating entity is supposed to inform `dpkg` using an appropriate invocation. Doing so records the aliasing information in a
    new mapping inside its administrative directory. No existing
    administrative files are modified as a result of this operation. When
    `dpkg` operates on paths, it can compute a canonicalized version using a
    pure function without the need to `stat()` files on disk thus greatly improving performance. Canonicalized paths are only needed when
    determining whether a file conflict exists. In all other cases,
    original paths continue to be used as symbolic links will be followed by filesystem operations. The `--add-alias` operation records the target
    of the symbolic link that must exist prior to invocation. The `--remove-alias` operation fails if any files are still installed in the aliased location.

    I already mentioned this in my reply for the thread you reference. So,
    let me repeat and possibly expand to avoid any future doubt. I already considered and discarded something like this (except for using a config
    option instead of a new command, but that does not really change the
    substance of the problems).

    Let's also get back to the very basics. dpkg manages objects shipped
    in binary packages, on the filesystem. It assumes this managing role in exclusivity, it will for example overwrite unmanaged files. It preserves
    admin changes with interfaces specifically provided for that (diversions, statoverrides, conffile changes) or the unfortunate symlink redirects.
    These shipped objects define the filesystem layout (not the other way
    around). Due to the missing fsys metadata, where it does not have all
    such metadata at hand when necessary (it might only have the one for
    the currently unpacked .deb), it might use heuristics or check the
    filesystem for such metadata, because it does not have anything else,
    but that should not be taken to mean that the filesystem is the source
    of truth, as most of those will be unnecessary once it has such
    metadata at hand.

    So the reason this proposal is still conceptually wrong is manifold:

    * dpkg cannot safely and atomically perform such switches (and I don't
    see it ever being able to portably do so, so I don't see ever
    supporting that).
    * No packages ships those symlinks (and none should! as that would
    currently imply having the same pathname contain different file types
    on the same system, introducing ordering issues and file type
    conflicts).
    * This introduces a series of commands to let dpkg know that a
    filesystem change that was not shipped in any .deb (even though that
    should have been the way to do it), has been done, which:
    - Switches the source of truth from the .deb to the fsys.
    - Confuses admin initiated changes from distro initiated ones.
    * Wants to be a generic change but it is really targeted to this
    specific mess. We have been doing similar aliasing transitions for
    many doc dirs, by stopping shipping files within, shipping that
    pathname as a symlink and then switching the directories to symlinks
    to match (via the dpkg-maintscript-helper hack because we miss fsys
    metadata). This means we'd need to then register all these directories
    too? Meh.
    * This information can get out of sync with reality, as it adds an
    additional and unconnected with anything source of truth, that dpkg
    cannot do anything about if it diverges (in contrast to diversions
    or statoverrides f.ex.). This can never happen when that information
    comes from the real source of truth (the fsys metadata via the .deb).
    * This also adds undue complexity, by supporting those as admin aliases.
    The admin generated redirecting symlinks are already annoying, I'd rather
    not add further to that pile. I don't really want to support admins doing
    this (dpkg-divert does not even support diverting a directory).

    [ As an aside, I think ideally eventually nothing distro provided should
    be allowed to be installed within an aliased dir, and dpkg should
    eventually just error out in those cases, which eventually would get
    rid of the aliasing problems and any such complexity (I'm not sure how
    or when that would be feasible though, but obviously in Debian at
    least not until nothing ships files there). ]

    So this still looks like a terrible interface, like it did at the time
    it was discarded; founded on a hack, an interface that seems wants to
    be kind of a file-type override but it cannot be, and cannot even
    properly act as record tracker, etc…

    Rejected proposals
    ==================

    Hardcoding aliases into dpkg
    ----------------------------

    It was suggested to include a static aliasing mapping into the `dpkg`
    source code. Since `dpkg` is used by multiple projects in different
    ways (not necessarily Debian-derivatives), this approach would break
    other consumers. Also note that Debian's `dpkg` can be used to operate
    on an installation using different aliases via the `--root` flag. As
    such the alias mapping needs to be a property of the installation.

    Yes.

    Modifying package lists in place
    --------------------------------

    `dpkg` could rewrite the extracted `.list` files from `control.tar` and
    store paths in canonicalized form. Canonicalization would happen as
    when a `control.tar` is extracted. It would also happen either as a
    one-time conversion during the upgrade of `dpkg` or whenever a `.list`
    file is read. Given canonicalized list files, string comparison on
    files would support conflict detection. Other pieces to be updated in a similar way include `alternatives`, `diversions`, `statoverride`, and `triggers`.

    This would affect the output of `dpkg -S`, which would then output canonicalized paths. Packages generated by `dpkg-repack` would have
    their contents canonicalized as well.

    This is an interface breaking change, as it introduces
    change-at-a-distance for packages themselves, and reproducibility
    issues that depend on the system at hand. As it is based on a foundation
    of an invented filesystem view, as those remapped packages never shipped
    those pathnames.

    Managing the aliasing mapping using a control file --------------------------------------------------

    It was suggested that the mapping could be managed via a special control
    file `canonical`. Given that aliasing is not a common operation, the
    benefit of handling it declaratively is minor. Beyond that, aliasing
    can also happen as an customization issued by an administrator.
    Therefore, a command line based approach is preferred.

    As long as the package does not provide the symlinks, shipping this
    type of information declaratively would also be conceptually wrong.
    And it is just a distraction from the fsys metadata stuff, with all
    the drawbacks of the CLI commands.

    Having dpkg move files and create symbolic links ------------------------------------------------

    When instructed with `--add-alias`, `dpkg` could also create the corresponding symbolic links and move the affected files to their new location. While that would be convenient, doing so is non-trivial in an atomic way. Sometimes, the underlying filesystem does not fully conform
    to POSIX (e.g. `overlayfs`) and such corner cases need to be managed individually. Since such an implementation already exists outside
    `dpkg` and its complexity is non-trivial, the moving of files shall
    remain external. In case aliases are setup in a bootstrap setting, no
    moves are necessary.

    dpkg expects several requirements for filesystems semantics, if they do
    not provide them, then those filesystems are not supported for dpkg to
    manage objects on them.

    dpkg cannot guarantee atomicity and safety for this kind of aliasing
    switch, and I don't see it will ever be able to support performing such
    switch, as that can break the system.

    Implement aliasing after metadata tracking ------------------------------------------

    The [metadata tracking](https://wiki.debian.org/Teams/Dpkg/Spec/MetadataTracking)
    feature enhances `dpkg` with knowledge about filesystem metadata for installed files. This includes knowledge of symbolic links, which would
    help with tracking aliasing. Unfortunately, progress on this is fairly
    slow and we think that aliasing support is more urgent.

    I thought it would be clear that if there is stuff that depends on
    any of this kind of changes to dpkg, relying on those changes in
    Debian would not be possible until after trixie+1. Of course there is
    always the route to further pile up over the Jenga tower of hacks,
    by for example adding huge amounts of Pre-Depends…

    So given the above, I don't see why the apparent rush here. And as I've mentioned many times now, I'm planning to continue working on the fsys
    metadata stuff for 1.22.x, probably at the cost of database duplication
    if necessary, if current blockers have not adapted by then. But as I've mentioned before, that might not guarantee this support is sufficient to support fixing this mess. But all other proposed changes I've seen
    flying around for changes to dpkg are just conceptually wrong in one way
    or another.

    Regards,
    Guillem

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Grohne@21:1/5 to Guillem Jover on Sat Apr 22 13:00:01 2023
    Hi Guillem,

    On Sat, Apr 08, 2023 at 04:35:25AM +0200, Guillem Jover wrote:
    I thought my reply was rather clear, and that we had further clarified
    that privately, that at the time I thought there was no other answer
    required as (AFAIR) you stated you'd be digging further on it. And I mentioned I'd try to reply to the list, but it didn't feel urgent given
    the clarifications given, neither the timing during the freeze?

    I'm sorry for the misunderstanding. Thank you for replying here as it
    helps clarify the relevant matters in various areas. The freeze timing
    arises because we ideally merge intrusive changes early in a release
    cycle.

    Sigh, a DEP(!?), for a dpkg change? It feels more like a way to exhort pressure over this than anything else TBH…

    I'm sorry if you perceive it as such. The intention was to capture
    consensus around a change that is necessary in some sense and
    controversial in another.

    I'm unlikely to discuss this topic on debian-devel, given previous
    nastiness and abuse.

    I see. I would have appreciated a Cc in that case as I am not subscribed
    to debian-dpkg.

    The text includes most (but not all) of what I've been saying publicly,
    and what I've tried to further clarify to you and Emilio in private.
    But I think ignores the essence of what I've been repeating all along.

    It's good to see that I captured many of your arguments. That essence
    however probably is the sticking point where we fundamentally disagree.
    I'll reference this "fundamental disagreement" a few more times and
    circle back to it later.

    I already mentioned this in my reply for the thread you reference. So,
    let me repeat and possibly expand to avoid any future doubt. I already considered and discarded something like this (except for using a config option instead of a new command, but that does not really change the substance of the problems).

    Thank you for repeating it in such clarity.

    Let's also get back to the very basics. dpkg manages objects shipped
    in binary packages, on the filesystem. It assumes this managing role in exclusivity, it will for example overwrite unmanaged files. It preserves admin changes with interfaces specifically provided for that (diversions, statoverrides, conffile changes) or the unfortunate symlink redirects.
    These shipped objects define the filesystem layout (not the other way around). Due to the missing fsys metadata, where it does not have all
    such metadata at hand when necessary (it might only have the one for
    the currently unpacked .deb), it might use heuristics or check the
    filesystem for such metadata, because it does not have anything else,
    but that should not be taken to mean that the filesystem is the source
    of truth, as most of those will be unnecessary once it has such
    metadata at hand.

    This captures an insight I previously didn't have in that clarity and
    that I find agreeable conceptually.

    So the reason this proposal is still conceptually wrong is manifold:

    * dpkg cannot safely and atomically perform such switches (and I don't
    see it ever being able to portably do so, so I don't see ever
    supporting that).

    I agree, but the proposal also does not ask dpkg to perform such
    switches, so I kinda fail to see how this is a relevant argument.

    * No packages ships those symlinks (and none should! as that would
    currently imply having the same pathname contain different file types
    on the same system, introducing ordering issues and file type
    conflicts).

    I disagree with this argument on two levels. For one thing, I think that
    the transition only is complete once these symlinks are shipped in a
    package. In particular, that notion of complete likely encompasses that
    no aliasing occurs anymore as all aliased files have been moved to their canonical location somehow (<- and this likely will be a quite difficult
    thing to do). For another, no package actually ships those symlinks now.
    They are created behind dpkg's back in some postinst. This is
    unfortunate and I agree with Simon Richter that this kinda is a policy violation, but at this time, it is an aspect we have to deal with
    whether we want to or not.

    I suspect that you disagree with the notion the we have to deal with
    this situation, which I consider to be our fundamental disagreement.

    * This introduces a series of commands to let dpkg know that a
    filesystem change that was not shipped in any .deb (even though that
    should have been the way to do it), has been done, which:
    - Switches the source of truth from the .deb to the fsys.

    While this is correct on some level, the aim of this change is to put
    that truth back into dpkg of course.

    - Confuses admin initiated changes from distro initiated ones.

    I think we already do this with dpkg-divert, dpkg-statoverride and other
    tools. While this may not be nice, it certain has prior art and is
    consistent with how we have been doing things in the past.

    * Wants to be a generic change but it is really targeted to this
    specific mess. We have been doing similar aliasing transitions for
    many doc dirs, by stopping shipping files within, shipping that
    pathname as a symlink and then switching the directories to symlinks
    to match (via the dpkg-maintscript-helper hack because we miss fsys
    metadata). This means we'd need to then register all these directories
    too? Meh.

    I would love to agree with this, but I believe that this ship has
    sailed. This likely is part of our fundamental disagreement.

    * This information can get out of sync with reality, as it adds an
    additional and unconnected with anything source of truth, that dpkg
    cannot do anything about if it diverges (in contrast to diversions
    or statoverrides f.ex.). This can never happen when that information
    comes from the real source of truth (the fsys metadata via the .deb).

    I have difficulties accurately capturing the argument. The problem of information getting out of sync with reality should affect every aspect
    of dpkg and indeed, that kinda is the status quo where upgrades can
    loose files, because dpkg has an incomplete picture of reality. The aim
    of this change is to allow us to re-sync the status quo into dpkg. My
    view is that dpkg's information presently is out of sync with reality
    and the proposed change partially fixes that.

    * This also adds undue complexity, by supporting those as admin aliases.
    The admin generated redirecting symlinks are already annoying, I'd rather
    not add further to that pile. I don't really want to support admins doing
    this (dpkg-divert does not even support diverting a directory).

    I have to agree with this one. This and the fact that this feature is
    probably impossible to remove later is my main problem with the proposed change. I have been proposing it anyway, because my impression is that
    it is the least bad option available. The notion of "least bad" quite
    obviously is somewhat subjective and is where we need to get consensus.

    [ As an aside, I think ideally eventually nothing distro provided should
    be allowed to be installed within an aliased dir, and dpkg should
    eventually just error out in those cases, which eventually would get
    rid of the aliasing problems and any such complexity (I'm not sure how
    or when that would be feasible though, but obviously in Debian at
    least not until nothing ships files there). ]

    It seems to me that this is something everyone agrees on. So our
    disagreement resides in the way to get there rather than where to get
    to.

    So this still looks like a terrible interface, like it did at the time
    it was discarded; founded on a hack, an interface that seems wants to
    be kind of a file-type override but it cannot be, and cannot even
    properly act as record tracker, etc…

    I agree that in a perfect world, we would not need this. Let me circle
    back to our fundamental disagreement.

    My impression is that at this time basically everyone except you agrees
    that we have to deal with the aliasing problems that have been rolled
    out to users and will be forced in bookworm. I believe that this is the
    state that we have to consider as starting point and that we cannot
    magically turn this transition back to perform it in a better way. And
    indeed, I believe that there would have been a better way[1] that no
    longer is available to us.

    On the other hand, my impression is that you continue to see the
    transition as fundamentally broken and in a state that we cannot work
    from. You appear to believe that if we want to do it, we must start over
    in a better way. That better way must not cause aliasing problems to
    dpkg.

    And sure enough, DEP 17 is a result of having first created these
    aliases and now trying to move the files. If we had opted for first
    moving the files and then creating the aliases, much of the bad effects
    would never have affected anyone and we wouldn't be discussing this
    change as it would not be necessary. With DEP 17 (or any similar change
    to dpkg), we will be able to actually move files to their canonical
    location and thus resolve the aliasing at which point DEP 17 will become unused.

    Did I accurately describe your view on this matter?

    I thought it would be clear that if there is stuff that depends on
    any of this kind of changes to dpkg, relying on those changes in
    Debian would not be possible until after trixie+1. Of course there is
    always the route to further pile up over the Jenga tower of hacks,
    by for example adding huge amounts of Pre-Depends…

    I agree that we probably will deal with this until at least trixie+1.
    This is precisely why I would like to have a plan to finish it sooner
    rather than later.

    So given the above, I don't see why the apparent rush here. And as I've mentioned many times now, I'm planning to continue working on the fsys metadata stuff for 1.22.x, probably at the cost of database duplication
    if necessary, if current blockers have not adapted by then. But as I've mentioned before, that might not guarantee this support is sufficient to support fixing this mess. But all other proposed changes I've seen
    flying around for changes to dpkg are just conceptually wrong in one way
    or another.

    As I see it, the fsys metadata work may help with the aliasing problems
    only if the respective symlinks are actually shipped in a data.tar of a
    .deb, which is not the way we currently do things. For that reason, I
    fail to see how the fsys metadata work is part of the solution for the
    problems we currently experience. I'd appreciate if you could elaborate
    on how you see it helping to fix the file loss on upgrade problem
    affecting current installations if you have sufficient energy to do so.

    Helmut

    [1] What follows is to be considered a time travel fix and is purely
    academic. Imagine we never had never done the usrmerge and would be
    introducing it again in a usrmerge package that works quite
    differently. Rather than create those aliases upfront, it would
    declare a trigger interest in affected locations (i.e. both /bin and
    /usr/bin and so on). It would practically trigger on every package
    operation. Whenever triggered, it would scan the non-/usr location
    for files. If any are found, it would populate both the /usr
    location and the non-/usr location with symlinks to the actual
    files. However when the non-/usr location becomes empty, it would
    remove the hierarchy and place the symlink directly. In that
    approach, we'd end up at the same layout that we currently have, but
    use symlink farms until we reach the point that all files have been
    moved. There are a number of aspects where this approach is
    problematic as well, but I think it is no longer useful to discuss
    it as switching to this approach is not an available option anymore.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Grohne@21:1/5 to Simon Richter on Sat Apr 22 13:00:01 2023
    Hi Simon,

    On Sat, Apr 08, 2023 at 04:06:54PM +0200, Simon Richter wrote:
    Yes, I am quite busy, but it's not forgotten. I keep adding new test cases.

    Thank you for taking the time to follow up. I discarded many of your
    arguments in this reply due to agreement.

    Dpkg already has defined behaviour for directory vs symlink: the directory wins. In principle a future version of dpkg could change that, but /lib/ld-linux.so.2 is just too special, we'd never want to have a package that actually moves it.

    Your argument of the dynamic linker being too special is interesting. I certainly agree that we must take great care at moving it, but on the
    flip side I do not consider the transition complete until we reach the
    point where we have moved it.

    Do you actually see us coping with some aliases (e.g. the /lib one)
    eternally?

    That's why I went with "this needs to be a separate mechanism."

    Or do you want to say that we need a new mechanism to be able to move
    such important files?

    The reason to use a control file instead of a tool would be to install the alias from an Essential package, so the old-school "unpack essential packages, then overwrite with dpkg" approach to system installation would work again without special-casing usrmerge in debootstrap&co.

    I did not have this goal in mind, but now that you mention it, it seems important to me. It is not clear to me though how that control file
    actually gets us there. In your picture, which component is in charge of actually creating the symbolic links on the filesystem? Can you go into
    detail as to how you imagine that bootstrap without special-casing?

    It was suggested that the mapping could be managed via a special control file `canonical`. Given that aliasing is not a common operation, the benefit of handling it declaratively is minor. Beyond that, aliasing
    can also happen as an customization issued by an administrator. Therefore, a command line based approach is preferred.

    The advantage is that it works for Essential packages, like the one shipping /lib/ld-linux.so.2.

    In the --add-alias variant, I think we would still move the dynamic
    linker to /usr and ship the /lib symlink in base-files eventually. I
    admit that it is not entirely clear how such a move could be performed
    safely, but that seems like a solvable problem to me. In that way, I
    fail to see the control file being an advantage.

    Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Guillem Jover@21:1/5 to Helmut Grohne on Wed Jun 21 13:40:01 2023
    Hi!

    On Sat, 2023-04-22 at 10:27:26 +0200, Helmut Grohne wrote:
    On Sat, Apr 08, 2023 at 04:35:25AM +0200, Guillem Jover wrote:
    Let's also get back to the very basics. dpkg manages objects shipped
    in binary packages, on the filesystem. It assumes this managing role in exclusivity, it will for example overwrite unmanaged files. It preserves admin changes with interfaces specifically provided for that (diversions, statoverrides, conffile changes) or the unfortunate symlink redirects. These shipped objects define the filesystem layout (not the other way around). Due to the missing fsys metadata, where it does not have all
    such metadata at hand when necessary (it might only have the one for
    the currently unpacked .deb), it might use heuristics or check the filesystem for such metadata, because it does not have anything else,
    but that should not be taken to mean that the filesystem is the source
    of truth, as most of those will be unnecessary once it has such
    metadata at hand.

    This captures an insight I previously didn't have in that clarity and
    that I find agreeable conceptually.

    So the reason this proposal is still conceptually wrong is manifold:

    * dpkg cannot safely and atomically perform such switches (and I don't
    see it ever being able to portably do so, so I don't see ever
    supporting that).

    I agree, but the proposal also does not ask dpkg to perform such
    switches, so I kinda fail to see how this is a relevant argument.

    It is relevant because it affects the end state, and what solutions
    are going to be appropriate then. See below.

    This might perhaps also have been a source of misunderstanding, my
    thinking is not focused solely on this particular instance but how
    this interacts with other current or long term behavior and upcoming
    features, and how this all would look like in the end.

    * No packages ships those symlinks (and none should! as that would
    currently imply having the same pathname contain different file types
    on the same system, introducing ordering issues and file type
    conflicts).

    I disagree with this argument on two levels. For one thing, I think that
    the transition only is complete once these symlinks are shipped in a
    package. In particular, that notion of complete likely encompasses that
    no aliasing occurs anymore as all aliased files have been moved to their canonical location somehow (<- and this likely will be a quite difficult thing to do). For another, no package actually ships those symlinks now.
    They are created behind dpkg's back in some postinst. This is
    unfortunate and I agree with Simon Richter that this kinda is a policy violation, but at this time, it is an aspect we have to deal with
    whether we want to or not.

    I suspect that you disagree with the notion the we have to deal with
    this situation, which I consider to be our fundamental disagreement.

    I don't think we disagree (?), I probably didn't express myself clearly.
    The fact that no package ships those symlinks *is* and *has* been a
    problem, and what I've been saying all along, this will be the only
    correct way to let dpkg know whether there will be aliasing in play.
    At the same time what I was trying to say is that we cannot ship those
    symlinks because even though dpkg does not yet track fsys metadata
    (even though it should and is one requirement to be able to be
    aliasing-aware), it would be an implicit file type conflict, where
    dpkg (currently) would not know or be able to do anything meaningful
    with it, and might make unpacks fail in the future (depending on the
    ordering or packages being unpacked).

    Coming now back to the atomic and safe switches, and the ordering,
    as I think I've mentioned elsewhere, dpkg should eventually be made aliasing-aware, in that it should know about all fsys file types and
    be able to detect these cases during unpack (once these symlinks are
    properly shipped in a package). But given these mentioned constraints
    it cannot be made to support (as in accept) unpacking files inside
    aliased directories (it should be able to unpack the symlinks creating
    those aliased directories though!).

    There are several reasons for that:

    * One is that the expected behavior for file types tracked by dpkg
    is to switch their file type if this is data.tar initiated and the
    operation can be done when the dirs are empty (so to get rid of
    these dpkg-maintscript-helper parts) otherwise abort, applying the
    symlink←→dir preservation behavior should only be done (if at all)
    for admin initiated changes on the fsys.
    * Another is that dpkg would need to allow those pathnames to have at
    the same time two sets of metadata attributes (mode, perms, xattrs,
    file type, one a symlink target), which is a terrible interface.
    * But more importantly this causes ordering issues and unpredictability.
    If there is a package A shipping a directory and package B shipping
    an aliasing symlink on the same pathname, and package C shipping also
    contents within that directory, and we have established that dpkg
    cannot always safely perform such file type switch, then depending on
    the unpack order and whether the "directory" is empty or not, dpkg
    would be able to perform the file type switch or not, and you might
    end up with files appearing in two "directories" and with an
    aliased directory or not. This is also terrible behavior. And that's
    why I say dpkg should simply refuse that, and something that should
    not be supported.

    * This introduces a series of commands to let dpkg know that a
    filesystem change that was not shipped in any .deb (even though that
    should have been the way to do it), has been done, which:
    - Switches the source of truth from the .deb to the fsys.

    While this is correct on some level, the aim of this change is to put
    that truth back into dpkg of course.

    Sure, the problem is the price that will need to be paid to get there,
    in terms of problematic interfaces or behavior and what kind of
    workarounds or hacks that will entail, and for how long.

    - Confuses admin initiated changes from distro initiated ones.

    I think we already do this with dpkg-divert, dpkg-statoverride and other tools. While this may not be nice, it certain has prior art and is
    consistent with how we have been doing things in the past.

    dpkg-divert distinguishes between local and package level changes, it
    is true that dpkg-statoverride does not have (currently) that
    distinction, although it is primarily an admin tool where I don't
    think it makes much sense to support something like declarative
    package statoverrides TBH once we can ship fsys metadata (perhaps
    conditional one though).

    * Wants to be a generic change but it is really targeted to this
    specific mess. We have been doing similar aliasing transitions for
    many doc dirs, by stopping shipping files within, shipping that
    pathname as a symlink and then switching the directories to symlinks
    to match (via the dpkg-maintscript-helper hack because we miss fsys
    metadata). This means we'd need to then register all these directories
    too? Meh.

    I would love to agree with this, but I believe that this ship has
    sailed. This likely is part of our fundamental disagreement.

    The comment was not focused on how this could have been done, but in
    that this is a common operation we do, and would need to get the same treatment, which seems bad.

    * This information can get out of sync with reality, as it adds an
    additional and unconnected with anything source of truth, that dpkg
    cannot do anything about if it diverges (in contrast to diversions
    or statoverrides f.ex.). This can never happen when that information
    comes from the real source of truth (the fsys metadata via the .deb).

    I have difficulties accurately capturing the argument. The problem of information getting out of sync with reality should affect every aspect
    of dpkg and indeed, that kinda is the status quo where upgrades can
    loose files, because dpkg has an incomplete picture of reality. The aim
    of this change is to allow us to re-sync the status quo into dpkg. My
    view is that dpkg's information presently is out of sync with reality
    and the proposed change partially fixes that.

    The current problem stems from both dpkg lacking fsys metadata and
    Debian holding dpkg wrong in an unsupported way, but where ideally
    both of these will eventually go away (?). My objection was that the
    proposal introduces a mechanism which makes things worse because it
    adds more information sources that can/will get out of sync.

    [ As an aside, I think ideally eventually nothing distro provided should
    be allowed to be installed within an aliased dir, and dpkg should
    eventually just error out in those cases, which eventually would get
    rid of the aliasing problems and any such complexity (I'm not sure how
    or when that would be feasible though, but obviously in Debian at
    least not until nothing ships files there). ]

    It seems to me that this is something everyone agrees on. So our
    disagreement resides in the way to get there rather than where to get
    to.

    If that's the case, then great. My impression though is that some
    people expect dpkg will be able to unpack content within aliased
    directories (?), which I don't see happening for the reasons I
    mentioned above. This will imply that you cannot install any old
    package that ships content there, which might be unexpected, but I
    don't see any other sane way to handle this. :/

    So this still looks like a terrible interface, like it did at the time
    it was discarded; founded on a hack, an interface that seems wants to
    be kind of a file-type override but it cannot be, and cannot even
    properly act as record tracker, etc…

    I agree that in a perfect world, we would not need this. Let me circle
    back to our fundamental disagreement.

    My impression is that at this time basically everyone except you agrees
    that we have to deal with the aliasing problems that have been rolled
    out to users and will be forced in bookworm. I believe that this is the
    state that we have to consider as starting point and that we cannot
    magically turn this transition back to perform it in a better way. And indeed, I believe that there would have been a better way[1] that no
    longer is available to us.

    I think I've mentioned before multiple times, that dpkg should
    eventually be able to be aliasing-aware. I think I've also mentioned
    that to get there we need to move all files out of aliased directories, otherwise several of the changes required for that "support" might not
    be even able to be deployed.

    On the other hand, my impression is that you continue to see the
    transition as fundamentally broken and in a state that we cannot work
    from. You appear to believe that if we want to do it, we must start over
    in a better way. That better way must not cause aliasing problems to
    dpkg.

    Well, it should be obvious by now this somewhat called transition is fundamentally broken, and I also see that there is no magic simple and
    clean way to get out of it. And every way out, is through further
    complexity, workarounds or badness. Of course given the corner Debian
    has painted itself into, there needs to be a way out, my objection is
    what kind of price to pay for that.

    I thought it would be clear that if there is stuff that depends on
    any of this kind of changes to dpkg, relying on those changes in
    Debian would not be possible until after trixie+1. Of course there is always the route to further pile up over the Jenga tower of hacks,
    by for example adding huge amounts of Pre-Depends…

    I agree that we probably will deal with this until at least trixie+1.
    This is precisely why I would like to have a plan to finish it sooner
    rather than later.

    Also, to note, that even if the way out was through some dpkg
    workaround, which would even get backported to bookworm, AIUI upgrades
    are never guaranteed to start from the last point release, so that
    would not seem to help much anyway.


    So coming back to workarounds and hacks, I'm finding the diversions
    stuff to be rather bad, as it requires to bypass an explicit dpkg
    refusal to deal with diverted directories, so it's going into further unsupported territory. :/ My other concern is that this might end up
    leaving unsupported directory diversions around which could break dpkg
    if it starts refusing to work on them during unpack, not just during
    diversion additions.

    I did a PoC (untested) implementation for the partial upgrade deletion prevention workaround to see how bad that might look like, and in
    comparison to the diverted stuff it is bad but not as bad. As I
    mentioned on our talks, this needs to imply emitting a warning,
    because otherwise this might end up as relied on behavior that should
    not be supported, and it would be a temporary hack for Debian and
    derivatives until things have moved out.

    https://git.hadrons.org/git/debian/dpkg/dpkg.git/log/?h=pu/aliasing-workaround

    Also, in case there is any confusion, this is a _partial_ workaround
    that does not cover many of the other badness, such as file overwrites
    and disappearances in other stages of the package life-cycle nor in
    other tools from the dpkg suite, from local packages, or from admin
    initiated changes via supported interfaces.

    I still think all the proposed workarounds are pretty terrible, TBH.

    Thanks,
    Guillem

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Richter@21:1/5 to Guillem Jover on Wed Jun 21 16:30:01 2023
    Hi,

    On 6/21/23 20:33, Guillem Jover wrote:

    I don't think we disagree (?), I probably didn't express myself clearly.
    The fact that no package ships those symlinks *is* and *has* been a
    problem, and what I've been saying all along, this will be the only
    correct way to let dpkg know whether there will be aliasing in play.

    I've looked into building a dpkg-alias tool that would work similar to dpkg-divert, and currently that looks like it might be a viable solution.

    Rules:

    - some package will need to register the alias in its preinst and
    remove it in its postrm (to make piuparts happy and provide symmetry).

    My favourite for that would be systemd-sysv, because that is literally
    the package that brings in the requirement, but there might be problems
    with that approach for containers, so I suspect that's not a good choice.

    - unpacking a symlink over a registered alias is fine if the symlink
    and the alias match.

    This way, we can ship the symlink in a package for bootstrapping. Terms
    and conditions apply.

    - dpkg keeps track of the name of files in the .tar.gz, but also
    recognizes aliased names as referring to the same file

    This can be done inside dpkg's file database -- whenever an entry is
    created, additional entries for aliases are also generated along it, so
    the file can be looked up using any aliased path

    - circular aliases are not allowed

    This would break the requirement that it is possible to generate an
    exhaustive set of all names a file may be found under.

    - the newly created dpkg-alias tool is responsible for moving files,
    if necessary

    This is a separate tool, so we don't need to extend the unpacking logic,
    and we can build an algorithm here that includes error recovery.

    - if an alias is registered for a symlink that already exists, that is
    not an error

    This way, we accept the status quo silently.

    - registering an existing alias or unregistering a nonexistant alias
    is not an error

    This allows future releases to change the list of aliases without
    requiring complex logic in maintainer scripts.

    - Files remain in the same place during the trixie cycle

    We only shift responsibility for moving files and creating the symlinks
    during this cycle, but bootstrapping will have to go through an unmerged
    phase in the beginning, and files are then moved into merged paths from
    the preinst of the key package, after the initial unpack.

    Whether bootstrapping tools prefer to create the symlinks themselves
    does not really matter at this point -- ideally they wouldn't, because
    we'd need to keep track of any symlinks typically created by bootstrap
    tools and explicitly remove these if the actual system should not have
    them (e.g. if an architecture specific symlink is created on an arch
    that doesn't have it).

    - Symlinks cannot yet be shipped in data.tar during the trixie cycle

    Because the unpack phase during bootstrap creates an unmerged file
    system, the symlinks cannot be unpacked here.

    - In trixie+1, the symlinks are then created from data.tar, and files
    can then be moved.

    This allows bootstrap to create merged filesystems directly during the
    unpack phase.

    - dpkg-alias can fail if there is a conflict during alias registration

    This should not actually happen, but protects people who may have local packages that use unmerged paths.

    - dpkg-divert and dpkg-statoverride act on the normalized path
    - dpkg-divert and dpkg-statoverride are registered with un-normalized
    paths
    - it is an error to register a diversion or statoverride with
    non-matching data

    This should allow most of the handover scenarios. For a diversion, it is sufficient if the normalized destinations match, so we can have a
    handover that registers /usr/lib/x -> /usr/lib/y from the preinst of a
    new package and then unregisters /lib/x -> /lib/y from the postrm of an
    older one.

    The package would need to unregister on upgrade in the postrm though,
    but that is standard for removed diversions.

    - dpkg-query returns the package name if any aliased name matches

    There should also be a flag whether to report the file name from the
    data.tar as well, defaulting to "no", because that's what scripts expect.

    But given these mentioned constraints
    it cannot be made to support (as in accept) unpacking files inside
    aliased directories (it should be able to unpack the symlinks creating
    those aliased directories though!).

    I think that can be done. I have already successfully made it report a
    conflict between /bin/testfile and /usr/bin/testfile, with a meaningful
    error message, and runtime overhead isn't too bad -- a factor of
    log_{262144} 2 on the lookup time for a single path, but inserts got a
    bit more expensive because these now have prefix comparisons on the
    path. The latter could probably be improved with another hash on the
    first N bytes of the path.

    dpkg-divert distinguishes between local and package level changes, it
    is true that dpkg-statoverride does not have (currently) that
    distinction, although it is primarily an admin tool where I don't
    think it makes much sense to support something like declarative
    package statoverrides TBH once we can ship fsys metadata (perhaps
    conditional one though).

    This interface could be provided independent from the implementation, by essentially pretending that maintainer scripts contain calls to dpkg-statoverrides if a specific control file is present (and the same
    would work for dpkg-divert and dpkg-alias). The change for that would be
    fairly localized, around the maintainer script calls.

    This can then be optimized later, keeping the same interface, if needed.

    I'd like to see a mechanism that ensures that dpkg understands those
    control files, though -- like a "critical" flag.

    I suspect that for trixie, this will have to be an archive side check
    that any package using one of the declarative interfaces depends on an appropriate version of dpkg, and/or its use disallowed until trixie+1
    for the convenience of backporters.

    Simon

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Guillem Jover@21:1/5 to Simon Richter on Mon Jul 10 11:30:01 2023
    Hi!

    On Wed, 2023-06-21 at 23:24:53 +0900, Simon Richter wrote:
    On 6/21/23 20:33, Guillem Jover wrote:
    I don't think we disagree (?), I probably didn't express myself clearly. The fact that no package ships those symlinks *is* and *has* been a problem, and what I've been saying all along, this will be the only
    correct way to let dpkg know whether there will be aliasing in play.

    I've looked into building a dpkg-alias tool that would work similar to dpkg-divert, and currently that looks like it might be a viable solution.

    Hmm, I get the impression the bulk of the mail this is replying to
    (and other previous ones), got ignored here.

    The package would need to unregister on upgrade in the postrm though, but that is standard for removed diversions.

    - dpkg-query returns the package name if any aliased name matches

    There should also be a flag whether to report the file name from the
    data.tar as well, defaulting to "no", because that's what scripts expect.

    That completely breaks the interface. This is one of the things that
    this change-at-a-distance breaks. The packages expect to be able to
    find their own files under their shipped names, not something the
    system might have done under their feet. So this new behavior can
    never be the default.

    But given these mentioned constraints
    it cannot be made to support (as in accept) unpacking files inside
    aliased directories (it should be able to unpack the symlinks creating those aliased directories though!).

    I think that can be done. I have already successfully made it report a conflict between /bin/testfile and /usr/bin/testfile, with a meaningful
    error message, and runtime overhead isn't too bad -- a factor of
    log_{262144} 2 on the lookup time for a single path, but inserts got a bit more expensive because these now have prefix comparisons on the path. The latter could probably be improved with another hash on the first N bytes of the path.

    I think this comment does not take into account the "mentioned
    constraints". A directory cannot be replaced atomically, even less so
    if it is non-empty. If it is empty and only owned this package, then
    it is still non-atomic, and replacing its file-type seems like
    safe-ish thing to do, as it does not suddenly disappear entire
    hierarchies that would stop being accessible through the old pathname.
    But moving entire hierarchies is simply not possible to do in an
    atomic and crash resistant way. This is one of the reasons dpkg-divert
    refuses to operate on directories.

    This also seems to ignore for example the ordering issue I mentioned
    before.

    I have no doubt that the "db aliasing" could be "done", although that
    also breaks a bunch of interfaces, but that's not the point, the
    problem comes from its consequences on unpacking and on the disk, and
    on having to sync the world views for these with the contents in the
    db on an ongoing basis.

    I'd like to see a mechanism that ensures that dpkg understands those control files, though -- like a "critical" flag.

    I don't think this is possible in a quick or non-nasty way (currently),
    given that such mechanism does not exist today, and we'd need to wait a
    release cycle to be able to use it anyway. In general things get
    introduced into dpkg, and then depending on the interface they can be
    used right away or one needs to wait until it can be used; if it's an independent tool that does not require any support from the running dpkg
    then that just requires dependencies, if it is part of dpkg then you
    need to wait, or if it's an optional feature you might be able to use
    «dpkg --assert-*» to check for availability, or just to bail out if
    it's a hard requirement.

    (Using a different .deb member that comes before the expected ones
    would be an option, which seems like the nasty but only existing
    mechanism for what this would involve, given the requirement to
    update all .deb consumers, and because it would be taking over the
    role of the control.tar member.)

    But for the future, perhaps it's worth considering, yes.

    I suspect that for trixie, this will have to be an archive side check that any package using one of the declarative interfaces depends on an
    appropriate version of dpkg, and/or its use disallowed until trixie+1 for
    the convenience of backporters.

    If we can manage to move files to their canonical locations, then the
    bulk of the aliasing disappears, and then as I've mentioned before
    then dpkg only needs to eventually become aliasing aware (in the fsys
    db sense from the fsys metadata) and simply get to an eventual point
    where it can (once it has a complete fsys metadata view) reject any
    potential attempt to perform a similar migration that would otherwise
    be unsafe and non-atomic. Any such migration would require to first
    move contents into their destination and then switch the dir to a
    symlink (which will be possible automatically once dpkg has the fsys
    metadata and can then replace the matching logic in
    dpkg-maintscript-helper), like we have been doing for /usr/share/doc/
    for ages for example.

    Thanks,
    Guillem

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)