rstudio / tinytex

A lightweight, cross-platform, portable, and easy-to-maintain LaTeX distribution based on TeX Live
https://yihui.org/tinytex/
Other
988 stars 117 forks source link

Installing TinyTeX globally for all users on Linux server / RStudio Server #415

Open salim-b opened 1 year ago

salim-b commented 1 year ago

Goal

I want to install TinyTeX system-wide to be used by all users of an RStudio Server instance.

So far

To accomplish that goal, I've ran the following steps on a root terminal session on the RStudio Server:

# install TinyTex for the root user
bash -c 'wget -qO- "https://yihui.org/tinytex/install-bin-unix.sh" | sh'

# move TinyTex installation from root home dir to `/opt/tinytex` and update the necessary config and symlinks
tlmgr path remove \
  && mv ~/.TinyTeX /opt/tinytex \
  && /opt/tinytex/bin/*/tlmgr option sys_bin /usr/local/bin \
  && /opt/tinytex/bin/*/tlmgr path add

# change group ownership to `staff` of whole TinyTex dir (all users are members of staff)
chown -R root:staff /opt/tinytex

# make whole TinyTex dir group-writable
chmod -R g+w /opt/tinytex \
  && chmod -R g+wx /opt/tinytex/bin

# set GID bit on all folders of TinyTex dir, cf. https://en.wikipedia.org/wiki/Setuid#When_set_on_a_directory
find /opt/tinytex -type d -exec chmod g+s {} +

# pretend all `texlive*` DEB packages have been installed, cf. https://yihui.org/tinytex/faq/#faq-7
wget "https://travis-bin.yihui.org/texlive-local.deb" \
  && apt-get install ./texlive-local.deb \
  && rm texlive-local.deb

# make `/usr/local/bin` owned by group `staff` and group-writable, so that `tlmgr path add` succeeds without root privileges
# NOTE: as per Debian wiki, this is the intended behaviour: https://wiki.debian.org/SystemGroups#Other_System_Groups
chown :staff /usr/local/bin \
    && chmod g+w /usr/local/bin

With the above, non-root users (which are member of group staff) can read the shared TinyTeX installation as well as generate the necessary symlinks for the TeX executables via tlmgr path add or tinytex::tlmgr_path(action = "add") . Automatically installing additional TeX packages during knitting as well as manual installation via tlmgr install <PKG> or tinytex::tlmgr_install() also works for non-root users, but the latter prints some messages about failed permission changes to /opt/tinytex/tlpkg/texlive.tlpdb like

chmod(420,/opt/tinytex/tlpkg/texlive.tlpdb) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.

The same message is also printed when a non-root user removes a package via tlmgr remove <PKG> or tinytex::tlmgr_remove() (since in both cases the texlive.tlpdb gets updated). The message is a bit cryptic to me since chmod 420 is not what /opt/tinytex/tlpkg/texlive.tlpdb) should have (and also not what it does have after the root user runs the same commands; instead it becomes chmod 644). 420 is the decimal representation of the octal 644 mask, as @norbusan pointed out.

The output of tinytex::tlmgr_conf() after the above is for any user

Output: ``` =========================== version information ========================== tlmgr revision 66798 (2023-04-08 02:15:21 +0200) tlmgr using installation: /opt/tinytex TeX Live (https://tug.org/texlive) version 2023 ==================== executables found by searching PATH ================= PATH: /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/quarto/bin:/usr/lib/rstudio-server/bin/postback dvipdfmx: /usr/local/bin/dvipdfmx dvips: /usr/local/bin/dvips fmtutil: /usr/local/bin/fmtutil kpsewhich: /usr/local/bin/kpsewhich luatex: /usr/local/bin/luatex mktexpk: /usr/local/bin/mktexpk pdftex: /usr/local/bin/pdftex tex: /usr/local/bin/tex tlmgr: /usr/local/bin/tlmgr updmap: /usr/local/bin/updmap xetex: /usr/local/bin/xetex =========================== active config files ========================== config.ps: /opt/tinytex/texmf-dist/dvips/config/config.ps fmtutil.cnf: /opt/tinytex/texmf-dist/web2c/fmtutil.cnf mktex.cnf: /opt/tinytex/texmf-dist/web2c/mktex.cnf pdftexconfig.tex: /opt/tinytex/texmf-dist/tex/generic/tex-ini-files/pdftexconfig.tex texmf.cnf: /opt/tinytex/texmf.cnf texmf.cnf: /opt/tinytex/texmf-dist/web2c/texmf.cnf updmap.cfg: /opt/tinytex/texmf-dist/web2c/updmap.cfg ============================= font map files ============================= kanjix.map: /opt/tinytex/texmf-var/fonts/map/dvipdfmx/updmap/kanjix.map pdftex.map: /opt/tinytex/texmf-var/fonts/map/pdftex/updmap/pdftex.map ps2pk.map: /opt/tinytex/texmf-var/fonts/map/dvips/updmap/ps2pk.map psfonts.map: /opt/tinytex/texmf-var/fonts/map/dvips/updmap/psfonts.map =========================== kpathsea variables =========================== ENCFONTS=.:{{}/opt/tinytex/texmf-config,/opt/tinytex/texmf-var,/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist}/fonts/enc// SYSTEXMF=/opt/tinytex/texmf-var:/opt/tinytex/texmf-local:/opt/tinytex/texmf-dist TEXCONFIG={{}/opt/tinytex/texmf-config,/opt/tinytex/texmf-var,/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist}/dvips// TEXFONTMAPS=.:{{}/opt/tinytex/texmf-config,/opt/tinytex/texmf-var,/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist}/fonts/map/{kpsewhich,pdftex,dvips,}// TEXMF={{}/opt/tinytex/texmf-config,/opt/tinytex/texmf-var,/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist} TEXMFCONFIG=/opt/tinytex/texmf-config TEXMFDBS={!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist} TEXMFDIST=/opt/tinytex/texmf-dist TEXMFHOME=/opt/tinytex/texmf-local TEXMFLOCAL=/opt/tinytex/texmf-local TEXMFMAIN=/opt/tinytex/texmf-dist TEXMFSYSCONFIG=/opt/tinytex/texmf-config TEXMFSYSVAR=/opt/tinytex/texmf-var TEXMFVAR=/opt/tinytex/texmf-var TEXPSHEADERS=.:{{}/opt/tinytex/texmf-config,/opt/tinytex/texmf-var,/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist}/{dvips,fonts/{enc,type1,type42,type3}}// VARTEXFONTS=/opt/tinytex/texmf-var/fonts WEB2C={{}/opt/tinytex/texmf-config,/opt/tinytex/texmf-var,/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-local,!!/opt/tinytex/texmf-config,!!/opt/tinytex/texmf-var,!!/opt/tinytex/texmf-dist}/web2c ==== kpathsea variables from environment only (ok if no output here) ==== ```

Remaining issues

  1. Removing or installing additional TeX packages via the root account changes permissions of file /opt/tinytex/tlpkg/texlive.tlpdb to not be group-writable anymore, rendering it impossible for non-root users to perform tlmgr install or tlmgr remove anymore. This is annoying but can be fixed by a simple chmod g+w /opt/tinytex/tlpkg/texlive.tlpdb. The changed group-write permission is retained when that file is updated during installation of additional packages by non-root users (since the subsequent permission modification to texlive.tlpdb fails in such case, see above) .

  2. Running fmtutil-sys --all (also via tinytex::tlmgr_update(run_fmtutil = TRUE)) the first time as non-root user prints the following (error) messages:

    chmod(420,/opt/tinytex/texmf-var/web2c/pdftex/pdftex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/xetex/xetex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/luatex/luatex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/tex/tex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/luahbtex/luahbtex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/luatex/dviluatex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/metafont/mf.base) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/pdftex/latex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/pdftex/pdflatex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/luahbtex/lualatex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/luatex/dvilualatex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/pdftex/etex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/xetex/xelatex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    chmod(420,/opt/tinytex/texmf-var/web2c/pdftex/pdfetex.fmt) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
    fmtutil [ERROR]: cannot copy format pdftex.fmt to: /opt/tinytex/texmf-var/web2c/pdftex/pdftex.fmt
    fmtutil [ERROR]: cannot copy format xetex.fmt to: /opt/tinytex/texmf-var/web2c/xetex/xetex.fmt
    fmtutil [ERROR]: cannot copy format luatex.fmt to: /opt/tinytex/texmf-var/web2c/luatex/luatex.fmt
    fmtutil [ERROR]: cannot copy format tex.fmt to: /opt/tinytex/texmf-var/web2c/tex/tex.fmt
    fmtutil [ERROR]: cannot copy format luahbtex.fmt to: /opt/tinytex/texmf-var/web2c/luahbtex/luahbtex.fmt
    fmtutil [ERROR]: cannot copy format dviluatex.fmt to: /opt/tinytex/texmf-var/web2c/luatex/dviluatex.fmt
    fmtutil [ERROR]: cannot copy format mf.base to: /opt/tinytex/texmf-var/web2c/metafont/mf.base
    fmtutil [ERROR]: cannot copy format latex.fmt to: /opt/tinytex/texmf-var/web2c/pdftex/latex.fmt
    fmtutil [ERROR]: cannot copy format pdflatex.fmt to: /opt/tinytex/texmf-var/web2c/pdftex/pdflatex.fmt
    fmtutil [ERROR]: cannot copy format lualatex.fmt to: /opt/tinytex/texmf-var/web2c/luahbtex/lualatex.fmt
    fmtutil [ERROR]: cannot copy format dvilualatex.fmt to: /opt/tinytex/texmf-var/web2c/luatex/dvilualatex.fmt
    fmtutil [ERROR]: cannot copy format etex.fmt to: /opt/tinytex/texmf-var/web2c/pdftex/etex.fmt
    fmtutil [ERROR]: cannot copy format xelatex.fmt to: /opt/tinytex/texmf-var/web2c/xetex/xelatex.fmt
    fmtutil [ERROR]: cannot copy format pdfetex.fmt to: /opt/tinytex/texmf-var/web2c/pdftex/pdfetex.fmt

    Subsequent runs don't emit these messages anymore and successfully copy the .fmt files (but they become chmod 644, i.e. not group-writable). I have no clue what exactly is going on here.

Both of these issues seem to lie in the upstream TeX Live perl scripts and not in TinyTeX itself. Any ideas on how to fix them? The issues seem to be somewhat similar to https://github.com/rstudio/tinytex/issues/77 (which has eventually been fixed upstream).

Relevant documentation


By filing an issue to this repo, I promise that

I understand that my issue may be closed if I don't fulfill my promises.

yihui commented 1 year ago

I'm afraid this is beyond my capability and I'll have to ask for help again from @kberry @norbusan. Thanks!

norbusan commented 1 year ago

Hmmm, the above messages are warnings about not being able to chmod, coming from TLUtils::copy:

    $mode = (-x $infile) ? oct("0777") : oct("0666");
    $mode &= ~umask;

    open (OUT, ">$outfile") || die "open(>$outfile) failed: $!";
    binmode OUT;

    chmod ($mode, $outfile) || warn "chmod($mode,$outfile) failed: $!";

That shouldn't be a problem per se, and the copy operation should continue.

The warning message is a bit confusing because it lists 420 which is octal 644 which is the expected permission mask.

Setting the permissions didnt work probably because the directories dont have the write permission for group users.

You could try to give more relaxed permissions to the admin users.

salim-b commented 1 year ago

@norbusan Thanks for your response!

The warning message is a bit confusing because it lists 420 which is octal 644 which is the expected permission mask.

Thanks, that clears things up.

Setting the permissions didnt work probably because the directories dont have the write permission for group users. You could try to give more relaxed permissions to the admin users.

The directories are all group-writable (thanks to chmod -R g+w /opt/tinytex in the setup above). They have also the setgid bit set, so newly created folders inherit the group ownership of their parent directory. Thus, permissions should already be relaxed enough.

The cause of the issue rather seems that the intermediate texlive.tlpdb.main.<HASH> file that gets created during tlmgr install/remove is not group-writable.

Directly after the above setup (i.e. before any non-root user performs a tlmgr action), permissions are as follows:

# ls -1lhd /opt/tinytex
drwxrwsr-x 8 root staff 4.0K May 10 19:22 /opt/tinytex

# ls -1lh /opt/tinytex
total 172K
drwxrwsr-x  3 root staff 4.0K May 10 03:12 bin
-rwxrwxr-x  1 root root  123K Mar 12 17:33 install-tl
-rw-rw-r--  1 root staff 2.1K Sep 28  2006 LICENSE.CTAN
-rw-rw-r--  1 root staff 5.2K Nov 20  2019 LICENSE.TL
-rw-rw-r--  1 root staff  350 Mar 14 00:11 release-texlive.txt
-rw-rw-r--  1 root staff  637 May 10 03:12 texmf.cnf
-rw-rw-r--  1 root staff  728 May 10 03:12 texmfcnf.lua
drwxrwsr-x  2 root staff 4.0K May 10 19:22 texmf-config
drwxrwsr-x 14 root staff 4.0K May 10 19:22 texmf-dist
drwxrwsr-x 10 root staff 4.0K May 10 19:22 texmf-local
drwxrwsr-x  6 root staff 4.0K May 10 19:22 texmf-var
drwxrwsr-x  8 root staff 4.0K May 10 19:22 tlpkg

# ls -1lh /opt/tinytex/tlpkg
total 18M
drwxrwsr-x 2 root staff 4.0K May 10 03:12 backups
drwxrwsr-x 2 root staff 4.0K May 10 03:12 gpg
drwxrwsr-x 5 root staff 4.0K May 10 19:22 installer
drwxrwsr-x 2 root staff 4.0K May 10 03:12 TeXLive
-rw-rw-r-- 1 root staff  845 May 10 03:12 texlive.profile
-rw-rw-r-- 1 root staff 507K May 10 19:22 texlive.tlpdb
-rw-rw-r-- 1 root staff  18M May 10 19:22 texlive.tlpdb.main.257da4516b1137cfe4f33341414fe5c7
drwxrwsr-x 2 root staff 4.0K May 10 19:22 tlpobj
drwxrwsr-x 2 root staff 4.0K May 10 03:12 tlpostcode

After a non-root user runs tlpkg install soul, the permissions become

# ls -1lh /opt/tinytex/tlpkg
total 18M
drwxrwsr-x 2 root  staff 4.0K May 10 03:12 backups
drwxrwsr-x 2 root  staff 4.0K May 10 03:12 gpg
drwxrwsr-x 5 root  staff 4.0K May 10 19:22 installer
drwxrwsr-x 2 root  staff 4.0K May 10 03:12 TeXLive
-rw-rw-r-- 1 root  staff  845 May 10 03:12 texlive.profile
-rw-rw-r-- 1 root  staff 509K May 11 10:54 texlive.tlpdb
-rw-r--r-- 1 salim staff  18M May 11 10:54 texlive.tlpdb.main.b219efc301f2675f5cd4c9cba8c232f3
drwxrwsr-x 2 root  staff 4.0K May 11 10:54 tlpobj
drwxrwsr-x 2 root  staff 4.0K May 10 03:12 tlpostcode

I.e., the newly created file texlive.tlpdb.main.b219efc301f2675f5cd4c9cba8c232f3 is not group-writable.

norbusan commented 1 year ago

I.e., the newly created file texlive.tlpdb.main.b219efc301f2675f5cd4c9cba8c232f3 is not group-writable.

But isn't that then an issue of the umask of the user running it? We (TeX Live) set as default mask 0666/0777 so there is no problem. The restriction is from the umask of the user.

You must force the umask of users to allow group writable to make newly created files group writable.

salim-b commented 1 year ago

Thanks again, @norbusan! You were absolutely right about umask. The whole file mode creation mask subject was a big knowledge gap on my part. But I took the time to fill this gap with a bit of reading, and as it turns out, the corresponding Wikipedia article is pretty illuminating (as they often are).

I must say the whole concept of umask feels very weird as a security tool (being able to set the masks per path instead of globally for a user would appear way more sensible to me; but I guess that's more in the realm of ACLs?), but I'm getting off the point.

On my RStudio Server instance (based on Ubuntu 22.04), the default umask is 022 for all users (seems to be the case for most Linux distros), meaning giving writing permissions to newly created files/dirs is always disallowed (i.e. stripped). Hence I changed that to umask 002 and now the texlive.tlpdb.main.<HASH> files created by tlmgr invocations are also group-writable.

What still remains is the issue about non-root users running fmtutil-sys --all.

And another (minor) issue still remains: When a non-root user runs tlmgr install/remove, now the following message is printed:

chmod(436,/opt/tinytex/tlpkg/texlive.tlpdb) failed: Operation not permitted at /opt/tinytex/tlpkg/TeXLive/TLUtils.pm line 1488.
running mktexlsr ...

436 is 664 octal, so I guess it refers to the diff between TeX Live's umask (666) and the user umask (002) – i.e. giving writing permission to all users (a+w) is disallowed by the user umask. Right?

The weird thing is, this message does not appear when the same command is run by the root user (also having 002 umask).

Switching the RStudio Server config option server-set-umask has no effect on this.

norbusan commented 1 year ago

Well, setting an umask of 002 for all users is somehow dangerous, you don't want all your newly created files to be readable by every other group member in most cases.

So yes, this is a case where classical unix permissions are not optimal, and ACLs should be used. I sm not sure you can achieve what you want to achieve solely with classical unix permissions.

OTOH, I assume you are running on ext4 or some similar standard linux file system, then you can activate extended attributes and use getfacl and setfacl to set proper ACL.

norbusan commented 1 year ago

BTW, if you do and succeed, it would be nice if you could document it somewhere so that we can incorporate it in the documentation, or refer to it. Thanks in advance.

salim-b commented 1 year ago

Well, setting an umask of 002 for all users is somehow dangerous, you don't want all your newly created files to be readable by every other group member in most cases.

Well, readability isn't restricted with umask 022 (Ubuntu's default), either. The last digit would need to be 6 or 7 to harden security in that sense.

But I don't think the change to allow giving write permission to groups by lowering the second digit from 2 to 0 is that much of a security issue either, since a user's primary group is normally exclusive to that user (e.g. group salim for user salim). So creating a file owned by a shared group like staff only happens if explicitly requested, the setgid bit is set to the parent folder, or the application creating the file chooses to do so.

I assume you are running on ext4 or some similar standard linux file system, then you can activate extended attributes and use getfacl and setfacl to set proper ACL.

I might look into that some other day. Currently I'm fine with the setup. Thanks for the hint, though. 🙂

BTW, if you do and succeed, it would be nice if you could document it somewhere so that we can incorporate it in the documentation, or refer to it.

You mean regarding ACLs? I'll post here if I find the time to experiment with that and achieve better results than with standard permissions. My current RStudio Server config (excl. sensitive stuff) is found in this GitLab repo. The TinyTeX installation stuff is found on lines 52–142 of the Dockerfile if anybody's interested.