What changes are necessary to make rustup.sh handle sudo itself?


#1

I’d like to change rustup.sh to be more interactive, not require invocation under sudo, and instead run sudo itself when necessary. There are two main reasons:

  1. Security-minded people do not like us telling people to curl a script into a root shell.
  2. rustup.sh has a lot of fiddly shell code, and most of it does not need to run as root. In some scenarios it leaves a ~/.rustup directory around, and I’d rather that be under the user’s account than root.

My worry about making this change is mostly about deciding when to run sudo, since not all installations need to be run as root, not all environments can access the terminal, etc.

So I’ll lay out how it might work. Let me know where the gaps in my thinking are.

After the change we’ll tell people to run curl -s https://static.rust-lang.org/rustup.sh | sh, without an explicit sudo. rustup.sh will itself call sudo to run the installer, but only in certain scenarios.

The first thing rustup.sh will do is print out a concise message explaining what it is going to do and giving the user an opportunity to abort. To avoid interactive mode callers can pass -y or --yes, which also turns off sudo (TODO: ok to conflate these two things?). Since this script is being piped into the shell, we can’t just read input from stdin. So, if in interactive mode, the first step is to open /dev/tty. If that fails, exit. Otherwise print the message and wait for ‘y/n’ user input. This step of checking for an interactive terminal is necessary also for knowing whether we can sudo.

By default, rustup.sh will try to figure out whether it is appropriate to run sudo, and if so will either run sudo or error. To disable the sudo logic, the user can pass --disable-sudo (TODO: similar to -y)

To determine whether sudo is needed, rustup tries to write, then delete, a file in the prefix directory, the prefix bin directory, and the prefix lib directory. If this fails rustup.sh decides it needs to sudo. Either way rustup.sh prints a status message explaining the choice. There may be smarter ways to decide whether to sudo.

I think that’s the extent of the changes.

As an alternative, we might not try to detect when sudo is needed and just run it unconditionally, but say in the opening message, ‘we’re going to run sudo, if you don’t like that call it again with --disable-sudo’.


#2

Ah, another facet here is to have a nice error when sudo doesn’t exist.


#3

What if running sudo was opt-in and rustup suggested adding --sudo when failing to write a test file?


#4

YES PLEASE! This is very much needed and I’m glad you’re working on it!


#5

I don’t think running with -y should turn of sudo-ing. The correct way to do is to require the least needed privileges: So only the installation phase (e.g. copy distributables) should require sudo at all, iff the user does not have write access to the target directories.

A user could be installing Rust into a ~/bin, ~/lib, etc. directory, which should not sudo anything.


#6

Here’s my current patch: https://github.com/rust-lang/rustup/compare/master...brson:next

The default mode is interactive and first explains exactly what’s going to happen. It runs sudo unconditionally and says so in the welcome message.


#7

PR for the above patch


#8

A quick thought on the security-mindedness: if someone is uncomfortable piping curl to a root shell, I think they should or would also be uncomfortable typing their password into a prompt from such a script.

Otherwise, a nice improvement to the install flow!


#9

Why does it need sudo at all?

I mean, shouldn’t rustc be installed by default into /usr/local/… (bin/lib/…) ?

That typically doesn’t require sudo.

(e.g. users of homebrew under MacOS do things this way and it is pretty nice actually)


#10

Changes to that require sudo on my linux computer:

$ touch /usr/local/bin/test
touch: cannot touch ‘/usr/local/bin/test’: Permission denied

#11

I’m pretty sure it’s only Homebrew that uses crazy permissions by default; no self-respecting Unix system would do so :smile: . But avoiding sudo in that case would be nice.


#12

Should the aim not be to obsolete rustup.sh or at least to keep its target-audience minimal, instead of making the script more user-friendly?

My view is that as-soon-as-possible users should be encouraged to use the latest stable release, not nightlies (I thought this is what 1.0 was for anyway). Most Rust developers, too; otherwise we’re going to keep seeing libraries which don’t work with the latest stable release.


#13

rustup.sh is still the recommended (easiest) way to install a stable release when your distribution doesn’t provide a package for it. Also, the plan is to have a new stable release every 6 weeks. If your distribution has versions, you may want to update Rust without waiting for the next distribution version in 6 months or a couple years.


#14

Most of the major distros seem to have some official package management channels for unofficial packages (Fedora Copr, Ubuntu PPA, OpenSUSE build factory, Arch AUR, etc.). Surely those should become the preferred way of installing up-to-date Rust on Linux platforms.

Some other installation method is still needed, but I would rather see instructions of the form:

  1. extract a tarball to your preferred path, e.g. $HOME/rust
  2. update PATH and LD_LIBRARY_PATH in ~/.bashrc

Then it’s clear exactly what’s going on, and should still be simple enough for any dev (non-devs should not, in theory, be installing except via distro’s stable packages anyway).


#15

Updating bashrc would only work for the current user. Using sudo ldconfig to update library links works for all users (at least in my Linux system).

It may be useful to do a sudo ldconfig if the lib prefix starts with /usr, otherwise a LD_LIBRARY_PATH update should suffice?