Bug 258372 - x11-fonts/fontconfig: cannot install as user (into non-default prefix)
Summary: x11-fonts/fontconfig: cannot install as user (into non-default prefix)
Status: New
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-desktop (Team)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-09-08 15:53 UTC by Gerald Pfeifer
Modified: 2023-11-28 01:12 UTC (History)
3 users (show)

See Also:
bugzilla: maintainer-feedback? (desktop)


Attachments
Concept patch (991 bytes, patch)
2023-04-29 11:28 UTC, Gerald Pfeifer
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Gerald Pfeifer freebsd_committer freebsd_triage 2021-09-08 15:53:11 UTC
x11-fonts/fontconfig/pkg-plist has the following entry

  @dir /var/db/fontconfig

This breaks installing into a non-default prefix as a regular user:

Installing fontconfig-2.13.94_1,1...
pkg: Fail to create /var/db/fontconfig:Permission denied
ldconfig: mkstemp(/var/run/ld-elf.so.hints.zLG4s8): Permission denied
ldconfig: mkstemp(/var/run/ld-elf32.so.hints.dOlnQp): Permission denied
Running fc-cache to build fontconfig cache...
/bin/sh: fc-cache: not found
*** Error code 1

When I remove that line things appear fine for my purposes (testing of
ports), though I am not saying this is the general fix.
Comment 1 Adriaan de Groot freebsd_committer freebsd_triage 2022-05-02 16:04:21 UTC
This surely isn't the only port that hard-codes a /var/db path in pkg-plist. There's not *many* others; devel/flyspray, for instance. There are plenty more with a /var/db path hard-coded elsewhere, but that doesn't bother pkg.

Can you check if recent changes to fontconfig have improved matters? (ie. can you remove that @dir line still) The package now uses triggers and understands %%PREFIX%%, rather than whatever was before, so this **might** be an easy-to-fix thing now.
Comment 2 John Hein 2022-11-02 14:34:32 UTC
I just tried 'make -C x11-fonts/fontconfig INSTALL_AS_USER=1 LOCALBASE=/usr/local.user PKG_DBDIR=/usr/local.user/var/db/pkg PORT_DBDIR=/usr/local.user/var/db/ports install' as a non-root user.  This is with pkg-1.18.4.  I did not get 'Fail to create /var/db/fontconfig:Permission denied'.

'deinstall' does produce 'pkg-static: unlinkat(var/db/fontconfig): Permission denied', but that is not fatal - it does remove the installed package and does return a exit code of 0 (indicating alleged success).  That might be considered a bug in pkg.  It seems pkg_delete.c does not treat EPERM as an error.  But in that case (not treating a failed directory removal as an error) could be reported as a separate bug for pkg perhaps.  If 'pkg delete' DID fail when doing deinstall with INSTALL_AS_USER=1 (especially if it failed to fully remove the package), then this current bug could become 'cannot deinstall as user'.  That is a different bug than this one, however.


I did notice that src/fccfg.c still points into a hard-coded /usr/local even if you define LOCALBASE (and/or PREFIX) to something that is not /usr/local.  But that is a separate bug - it should replace /usr/local with %%LOCALBASE%%, and for that matter, files/fontconfig.ucl.in should use %%LOCALBASE%% instead of %%PREFIX%% for the 'path' that looks in share/fonts and etc/fonts/conf.d.


So, it seems to me that the original problem reported here is not a problem now, or at least I could not reproduce the failure.  I don't know what changed between now and when this problem was reported.  In Sep 2021 (the latest pkg was 1.17.1 then), I think pkg did not treat @dir entries any differently than it does now - i.e., @dir is only used when the package is deleted, per pkg-create(8).  Gerald, can you confirm whether or not your failure can be reproduced now?
Comment 3 Gerald Pfeifer freebsd_committer freebsd_triage 2023-01-26 11:45:17 UTC
(In reply to Adriaan de Groot from comment #1)
> Can you check if recent changes to fontconfig have improved matters?
> (ie. can you remove that @dir line still) The package now uses triggers
> and understands %%PREFIX%%, rather than whatever was before, so this
> **might** be an easy-to-fix thing now.

If I install as a regular user (into a non-default prefix) I still get:

  [ref12-amd64.freebsd.org] Installing fontconfig-2.14.0,1...
  pkg: Fail to create /var/db/fontconfig:Permission denied

If I remove the  @dir /var/db/fontconfig  line from pkg-plist it still
installs.

(But maybe I misunderstood your questions, Adriaan?)
Comment 4 Gerald Pfeifer freebsd_committer freebsd_triage 2023-01-26 11:58:11 UTC
(In reply to John Hein from comment #2)
> I just tried 'make -C x11-fonts/fontconfig INSTALL_AS_USER=1
> LOCALBASE=/usr/local.user PKG_DBDIR=/usr/local.user/var/db/pkg
> PORT_DBDIR=/usr/local.user/var/db/ports install' as a non-root user.
> This is with pkg-1.18.4.  I did not get 'Fail to create
> /var/d/fontconfig:Permission denied'.

When I just tried again, and got that error, it was pkg 1.19.0 and
  make INSTALL_AS_USER=1 BATCH=1 NO_DEPENDS=1 install
and PREFIX, LOCALBASE and PKG_DBDIR set to paths in my home directory.

Ahh, maybe I have an idea on why I am still getting this error and you
are not:

  % ll /var/db/fontconfig
  ls: /var/db/fontconfig: No such file or directory

Does /var/db/fontconfig exist on your system? If so, that might explain
why it does not try to generate that directory, whereas it does it in my
case - and fails.
Comment 5 Tatsuki Makino 2023-01-27 06:49:17 UTC
Once this is installed and any fonts are installed, the contents of /usr/ports/Keywords/fc.ucl will be run and /var/db/fontconfig/ will no longer be empty.
I have a feeling that if this is uninstalled in that state, /var/db/fontconfig/ will remain.
Comment 6 John Hein 2023-01-27 13:12:19 UTC
(In reply to Gerald Pfeifer from comment #4)
> Does /var/db/fontconfig exist on your system? If so, that might explain
> why it does not try to generate that directory, whereas it does it in my
> case - and fails.

Yes, /var/db/fontconfig did exist in my previous testing.  When I move it away and re-install ('make -C x11-fonts/fontconfig INSTALL_AS_USER=1 LOCALBASE=/usr/local.user PKG_DBDIR=/usr/local.user/var/db/pkg PORT_DBDIR=/usr/local.user/var/db/ports reinstall'), it fails with 'pkg: Fail to create /var/db/fontconfig:Permission denied' as described in comment 0.

So the pkg-create(8) man page where @dir is described is incomplete (IMO).  It only discusses what happens when the pkg is deleted.  It omits any description about behavior on pkg install.  One could read that the implication of that omission is that nothing is done at install.  But that does not appear to be a correct interpretation of that omission.  To be more clear, the pkg-create(8) man page could describe @dir behavior at install time.

So, given confirmation of that error, what should fontconfig (or other ports per comment 1) do for @dir entries that point explicitly to directories where the user does not have write permission when INSTALL_AS_USER is set?

Some possible courses of action:

  (1) Change the pkg tool. pkg could warn instead of fail for @dir creation (or deletion?) failures if INSTALL_AS_USER is set.  pkg already looks for INSTALL_AS_USER to:

    o Skip chflags
    o Skip chown
    o Skip checks that fail if the pkg db file is not owned by root. Perhaps that check is not needed, or should not trigger an exit at the point of the check anyway.  The pkg tool will not be able to write to the db file if the user does not have the appropriate permissions, so just let pkg fail naturally when it does the write attempt.  The check could remain and just emit a warning (instead of being fatal if the check fails) regardless of INSTALL_AS_USER.

  (2) Modify plist for INSTALL_AS_USER.  Ports that have @dir entries that point to non-user directories, could have a plist that sets a different value for the @dir directory.  Maybe <localbase>/var/db/fontconfig in this case, for instance.  What defines a "non-user" directory is not obvious, however - anything outside PREFIX? anything outside LOCALBASE?  Maybe there could be an INSTALL_AS_USER_ROOT variable where such plist entries would go (instead of the default /) when using INSTALL_AS_USER.

  (3) A variant of (2)... allow currently hard-coded directories in the plist like /var/db/fontconfig to be defined by a make variable (instead of hard-coded).  For example, have the plist entry be something like @dir %%FONTCONFIG_DB%% and define FONTCONFIG_DB in PLIST_SUB.  This would default to /var/db/fontconfig, of course - and maybe it could default to ${LOCALBASE}/var/db/fontconfig if INSTALL_AS_USER is set.

  (4) Continue with existing behavior (but document it).  If INSTALL_AS_USER is set, expect that @dir directories are in a parent directory that is expected to be writable by the install user.  This is effectively what is done now.  But that policy is likely just an implicit or even just accidental policy - it could be explicitly spelled out in the @dir documentation.

(2) and (3) would be per-port modifications (as opposed to a change to the ports framework or the pkg tool).  There could be another variant of (2) or (3) that could be defined by the framework so individual ports affected by this issue would not need to be modified one by one.  For instance, when a hard-coded absolute path is an argument to @dir (or maybe an absolute path that is outside of PREFIX / LOCALBASE?), the plist generation step in bsd.port.mk could be modified to change the @dir entry to, say, '@dir <localbase>/dir' when INSTALL_AS_USER is set.  Or the pkg tool could be modified to do something similar (I don't like that as well, however - pkg should just do what the plist says to do, so the plist should be modified as needed before being passed to pkg).

If we don't want to define a global policy for @dir when INSTALL_AS_USER is set (i.e., modify the framework or pkg tool for these cases), I think I prefer (3) for each affected port at this time.

If we do want to implement something that does not requiring changes for every affected port, I think I prefer (2) - specifically modifying generate-plist in bsd.port.mk to detect absolute path @dir entries that are outside PREFIX or LOCALBASE and prepend ${INSTALL_AS_USER_ROOT} (any potential better name suggestion for that is welcome).
Comment 7 John Hein 2023-01-27 13:36:37 UTC
(In reply to John Hein from comment #6)
Re (4).  The policy for INSTALL_AS_USER IS documented in pkg(8) and pkg-static(8):

    It is expected that the user will ensure that every file
    and directory manipulated by pkg are readable (or
    writable where appropriate) by the user.

So one "fix" for this bug could be no change to anything in the ports tree or the pkg tool - and users should chown /var/db appropriately when doing 'make INSTALL_AS_USER=1 ... install'.
Comment 8 Tatsuki Makino 2023-01-27 21:18:11 UTC
To begin with, isn't /var/db/fontconfig directory that doesn't need to be prepared beforehand?
It was automatically created by the following operation by root.

mv /var/db/fontconfig{,.orig}
fc-cache --force --system-only --verbose

It seems that /var/db/fontconfig is not hard-coded, but just written in /usr/local/etc/fonts/fonts.conf*.
From what I can see of it, it seems to act like it is looking for a place in <cachedir> where it can write from the top.
It should be noted that prefix="xdg" has its own fall down different from glib's (at fontconfig-2.14.0/src/fccfg.c).
Since non-privileged users cannot write to /var/db, the default behavior seems to be to write to ~/.cache/fontconfig if they are able to write to ~/.cache and to ~/.fontconfig otherwise.

Let's see, that means we don't need to create /var/db/fontconfig when we install fontconfig, do we? :)
Comment 9 John Hein 2023-01-29 04:35:10 UTC
(In reply to Tatsuki Makino from comment #8)
> mv /var/db/fontconfig{,.orig}
> fc-cache --force --system-only --verbose
>   .
>   .
> It seems that /var/db/fontconfig is not hard-coded
>   .
>   .
> Let's see, that means we don't need to create /var/db/fontconfig when we install > fontconfig, do we? :)

Tatsuki, this bug is all about how installing fontconfig without being root can fail.  If you do your 'mv /var/db/fontconfig{,.orig}' without your 'fc-cache', then do 'make INSTALL_AS_USER=1 LOCALBASE=... install', then you get the error.

And INSTALL_AS_USER is all about doing builds without having to be root.

/var/db/fontconfig is definitely hard-coded as the '@dir /var/db/fontconfig' line in pkg-plist.

Yes, you could create /var/db/fontconfig ahead of time (either with mkdir or by running fc-cache).  But if you don't, then the install will try to create it (due to the @dir entry).  Assuming /var/db is owned by root (as it is by default), then you get the Permission denied failure as shown in comment 0.

There are various options to work around that error.  One of them is the option you are talking about - namely to create /var/db/fontconfig ahead of time.  That is not a fix for this particular INSTALL_AS_USER problem.  It's a hack.  You won't know about that failure until you try to do the install with INSTALL_AS_USER and hit the error.  'make install INSTALL_AS_USER=1 ...' should work without having to do something else like creating /var/db/fontconfig beforehand.
Comment 10 Tatsuki Makino 2023-01-29 20:47:36 UTC
(In reply to John Hein from comment #9)

Yes, mine is about workarounds limited to fontconfig.
And yours could spread beyond fontconfig.
For example, something in games/*, */linux-* or etc...

/var/db/fontconfig/ is used because it is patched to do so by files/patch-meson.build.
As for the thought of changing it there, it seems to me that pkg is not concerned with file changes, meaning that there is no need to write it in pkg-plist, but what do you think?
Comment 11 John Hein 2023-01-30 10:17:54 UTC
(In reply to Tatsuki Makino from comment #10)
One reason to have '@dir /var/db/fontconfig' in the plist is to have the directory removed when the package is deleted.  So I probably would not remove that entry from the plist.
Comment 12 Tatsuki Makino 2023-01-30 21:20:53 UTC
(In reply to John Hein from comment #11)

Since it is creating that directory in the post-install target, I can see why it needs to be removed when it is deinstalled.

By the way, since x11-fonts/fontconfig now has USES=trigger and files/fontconfig.ucl.in, doesn't that action make that directory impossible to remove?
That trigger executes fc-cache once, so /var/db/fontconfig/CACHEDIR.TAG remains.

These seem to indicate that it would be better to do it with something like files/pkg-install.in....
Or can we include it in the trigger...?
Comment 13 Gerald Pfeifer freebsd_committer freebsd_triage 2023-04-29 10:31:18 UTC
(In reply to John Hein from comment #11)
> One reason to have '@dir /var/db/fontconfig' in the plist is to have
> the directory removed when the package is deleted.  So I probably would
> not remove that entry from the plist.

In the past we could have used @dirrmtry, alas that was removed in 2021.

Now, as long as we keep '@dir /var/db/fontconfig' installing as user fails
hard.
Comment 14 Gerald Pfeifer freebsd_committer freebsd_triage 2023-04-29 11:28:29 UTC
Created attachment 241847 [details]
Concept patch

How about something like this, the heart of which is

  .if defined(INSTALL_AS_USER)
  PLIST_SUB+=             ROOT="@comment "
  .else
  PLIST_SUB+=             ROOT=""
  .endif

(Note: could not fully test this.)