hashicorp/vagrant

stdin: is not a tty

Closed this issue ยท 51 comments

Hello

I run Vagrant version 1.2.2 on Mac OS 10.8.3.

When I set up a multi VM environment with lucid64 boxes, which I provision either with shell or puppet, I always get the following error when provisionning

stdin: is not a tty

Example :

dhcp-10-0-89-123:devops-test-deploy geoffroy$ vagrant up test
Bringing machine 'test' up with 'virtualbox' provider...
[test] Importing base box 'precise64'...
[test] Matching MAC address for NAT networking...
[test] Setting the name of the VM...
[test] Clearing any previously set forwarded ports...
[test] Creating shared folders metadata...
[test] Clearing any previously set network interfaces...
[test] Preparing network interfaces based on configuration...
[test] Forwarding ports...
[test] -- 22 => 2250 (adapter 1)
[test] -- 80 => 4567 (adapter 1)
[test] Running any VM customizations...
[test] Booting VM...
[test] Waiting for VM to boot. This can take a few minutes.
[test] VM booted and ready for use!
[test] Setting hostname...
[test] Configuring and enabling network interfaces...
[test] Mounting shared folders...
[test] -- /vagrant
[test] -- /etc/puppet
[test] -- /tmp/vagrant-puppet/manifests
[test] Running provisioner: shell...
[test] Running: /var/folders/6m/twgys53s1cn326fz4tlrchjr0000gn/T/vagrant-shell20130430-3314-ejk9pk
stdin: is not a tty

Thanks

Geoffroy

Yeah this is a known "thing." It is not really a problem because it doesn't really cause a problem. Actually, the reason this error message even appears is due to a bug in Ubuntu not checking whether stdin is a TTY, and just assuming it is.

thanks for your quick reply ! I won't bother then :)

Is there any workaround possible to avoid this warning? For some reason it annoys me unnaturally ๐Ÿ˜„

Yea, along with occasional dpkg-preconfigure: unable to re-open stdin: No such file or directory is making me nervous

Is this also something to not worry about? dpkg-preconfigure: unable to re-open stdin: No such file or directory

For those looking for a fix, see https://bugs.launchpad.net/ubuntu/+source/xen-3.1/+bug/1167281. I recently built my own box using veewee and replaced:

msg n

With:

tty -s && mesg n

In file /root/.profile.

Adding this to a shell provisioner should fix it:
sed -i 's/^mesg n$/tty -s \&\& mesg n/g' /root/.profile

@johnraz , thanks for that ๐Ÿ‘

@johnraz that worked for me too on one host machine but on another host machine I now get:

tty: extra operand 'mesg'

It's really a nasty hack anyway and I only tried it against ubuntu 12.04 ... Guess you will have to adapt it to whatever distro / version you are using.

I did say earlier this bug "annoys me unnaturally".. I decided today I wouldn't stop until I understood why this happens. ๐Ÿ˜„ Unfortunately this entire situation with shells and configuration files (.bashrc/.profile/etc). is really worse than I thought. It's obvious the current situation evolved "organically" and it really sucks to work with.

Vagrant defaults its SSH shell command to bash -l. This command is used for Vagrant's internal SSH communicator (which is used to execute commands in shell provisioners and plugins). The -l flag forces this to be a login shell. For a non-interactive login shell like this one, bash will source /etc/profile, followed by the first existing file out of ~/.bash_profile, ~/.bash_login, and ~/.profile. Since Vagrant runs most of its commands as root, it will source /etc/profile, then /root/.profile.

On Ubuntu, /root/.profile contains the command mesg n. This command is used to prevent other users on the machine writing to your current terminal device -- this is a good thing, it stops other users on the machine from writing to root terminals (I couldn't find much on the security implications, but a discussion of the potential reasons for this is available in [1, pp. 270]). However, this command doesn't even make sense when running commands as Vagrant does, because there is no terminal device at all (which is obvious, once you realise what mesg is for).

So it's true that Ubuntu's default /root/.profile doesn't check whether a terminal device is present before running mesg (as @mitchellh said initially), and that's why this problem is fixed when changing the relevant line to read tty -s && mesg -n as suggested by @andyshinn (it only runs mesg -n if tty reports that stdin is a terminal).

However, I don't think the onus is on Ubuntu to implement this change as @mitchellh suggests. Their /root/.profile assumes that all login shells are interactive -- but that's because they usually are. Login shells are usually started by the login process (or ssh when logging in interactively), and in those instances the shell would also be interactive. It's fairly unusual to have a login shell that's also non-interactive (the condition which triggers this problem).

A better way to fix this would be to avoid using a login shell. I think the only reason Vagrant chooses to use a login shell is so that /etc/profile is sourced before the command is run. On the base Ubuntu boxes provided by Vagrant, that executes /etc/profile.d/vagrantruby.sh, which adds /opt/ruby/bin into $PATH. So if you changed the Vagrant setting config.ssh.shell to bash (without the -l), it would fix this issue, but you would have to give the full path to Ruby because it wouldn't be in the $PATH. So I think to fix this problem "correctly", we need to find another way to get /opt/ruby/bin into the $PATH.

Honestly, I think there are some problems with the way the base box is built, specifically what happens in postinstall.sh. I'd open a pull request with some suggested changes, but I can't find that hosted anywhere official to do so. Here's my recommendations:

  1. Remove the trailing slash from the $PATH (currently /etc/profile.d/vagrantruby.sh contains PATH=$PATH:/opt/ruby/bin/, the trailing slash can cause problems, a trivial example being which ruby giving /opt/ruby/bin//ruby with two slashes).
  2. Actually export the change to $PATH (the current assignment to $PATH won't affect any sub-processes, which can be confusing)
  3. The main problem, however: we need to find another way to get /opt/ruby/bin into the $PATH. I really like the way OS X has /etc/paths.d (that would fix this problem awesomely) but unfortunately nothing like that is in Ubuntu yet. If you really really want to make extra double sure that Ruby is always available, why not chuck it into /etc/environment? This is sourced by login/sshd itself when logging in, no matter how you log in really.

tl;dr: Environment variables and shell configurations are FUBAR. @mitchellh (I believe?) should maybe adjust postinstall.sh used to build the official Vagrant Ubuntu base boxes -- don't use /etc/profile.d/vagrantruby.sh to add /opt/ruby/bin into the $PATH, let's modify /etc/environment instead. Citations. I have no life.

[1] B. Toxen, Real World Linux Security: Intrusion Prevention, Detection, and Recovery. Upper Saddle River, NJ: Prentice Hall, 2003. http://goo.gl/kmKryu

Oh, one more thing: for the time being, I'm fixing this by adding this line to my Vagrantfile:

config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"

This starts bash as a non-login shell, but also tells it to source /etc/profile, which I hypothesised to be the only reason to use a login shell by default. Works for me with the stock precise64 Vagrant box.

Some other ways to fix the issue:

  • Previous suggestions to change mesg n to tty -s && mesg n in /root/.profile
  • Remove the mesg n line from /root/.profile completely, if you don't care about the security/denial of service implications, or will only have trusted users on the virtual machine (passwordless sudo is enabled on the base boxes already anyway...)
  • Put a script named mesg in root's $PATH which only executes the real mesg if stdin is a tty (tested using tty -s or the preferred test -t 0)
  • Disable login shell for the SSH command in your Vagrantfile: config.ssh.shell = 'bash' -- you'll also have to use full paths to binaries in all of your provisioners, as ruby won't be found in $PATH (probably only feasible if only using shell provisioners)

@bradfeehan : Very interesting findings. Thanks for taking the time to dig this and share it with us.

@bradfeehan thank you so much for writing this up! I tried config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'" and it worked :)

@bradfeehan Wow, thanks! This bothered me to no end. I was about to go in for the deep dive to sort this out.

@bradfeehan this worked for me! thanks.

There's a problem with this workaround that means you don't get ~/.bash_profile sourced when logging in interactively via vagrant ssh. I guess this problem really is so complex that there's no right answer.

I'm going to put up with the message, and solve it a different way when it annoys me too much again.

If anybody get this error:

[2014-01-20T08:11:08-05:00] INFO: Chef Run complete in 67.290072613 seconds
[2014-01-20T08:11:08-05:00] INFO: Running report handlers
[2014-01-20T08:11:08-05:00] INFO: Report handlers complete
[2014-01-20T13:10:00+00:00] INFO: Forking chef instance to converge...
[2014-01-20T13:10:00+00:00] DEBUG: Fork successful. Waiting for new chef pid: 5680
[2014-01-20T08:11:08-05:00] DEBUG: Forked instance successfully reaped (pid: 5680)
[2014-01-20T08:11:08-05:00] DEBUG: Exiting

Or their vagrant box runs out of memory, remove the config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'" hack. For me, it was causing problem with the rbenv cookbook (https://github.com/RiotGames/rbenv-cookbook)

@phirschybar I was also getting that error message: " tty: extra operand 'mesg' "
It's because you have to double-escape the ampersands in @andyshinn's command. So the command would look like:

  config.vm.provision :shell,
    :inline => "sed -i 's/^mesg n$/tty -s \\&\\& mesg n/g' /root/.profile"

Note the double-backslashes before the ampersand. If you don't do that, you end up writing unintended text into /root/.profile, leading to that error message in subsequent provisions.

This command is almost perfect, but you still get that 'stdin is not a tty' on your very first provision. To reassure my colleagues when provisioning a box for the first time, I now add the following to my Vagrantfile:

#This next bit fixes the 'stdin is not a tty' error when shell provisioning Ubuntu boxes
  config.vm.provision :shell,
    #if there a line that only consists of 'mesg n' in /root/.profile, replace it with 'tty -s && mesg n'
    :inline => "(grep -q -E '^mesg n$' /root/.profile && sed -i 's/^mesg n$/tty -s \\&\\& mesg n/g' /root/.profile && echo 'Ignore the previous error about stdin not being a tty. Fixing it now...') || exit 0;"

That prints a reassuring green message right after the scary red 'stdin is not a tty' upon the very first provision.

(The only thing I don't like about it is that I used a redundant grep to determine if sed was going to do any work. You can use sed's 'q' command to determine if it did any work, but I'm already in over my Unix head, and couldn't get it to work.)

I have the same problem, and for me it's an actual problem.

Why is there no option to have a TTY during provisioning?

The only answer I could imagine is "But provisioning should not be interactive". However, I always run provisioning on a terminal and watch the output.

There exist commands which require a TTY, even when they do not actually need to interact with the user โ€” in my case, it was "agda-mode setup" from Agda starting Emacs, mostly just to find it (I'm sure you didn't hear of Agda).

Debian package installation also requires a TTY, though that's actually interactive; however, upon finding no TTY, in my setup it still tries to use ncurses and ends up corrupting the terminal settings, requiring to run reset in the host terminal.

I'm working this around by provisioning with vagrant ssh -c /vagrant/myscript.sh, but that seems to half-defeat the point of having provisioning.

@Blaisorblade There is: config.ssh.pty = true (min Vagrant 1.4.0)

Thanks! But shouldn't it be documented under both of
http://docs.vagrantup.com/v2/vagrantfile/ssh_settings.html
http://docs.vagrantup.com/v2/provisioning/shell.html
(so that one can find it from both places), while it isn't documented in either page?

Also, while this setting solves my problem, provisioning does not terminate if I actually use "agda-mode setup", which does use the terminal in strange ways. It's still better, but not perfect. (Also, the same script works fine inside ssh โ€” and enabling keep_color does not help).

In addition, with config.ssh.pty the default shared folder is mounted under logout (meaning /home/vagrant/logout) instead of /vagrant. I guess some command is happy to see a TTY and is producing output which Vagrant doesn't expect, but usually login/logout scripts are supposed to not produce output with non-interactive shells.

I also tried adding :binary => true to the provisioning configuration, but it didn't help.

I experienced the same as @Blaisorblade, seems like a bug to me. Breaks a lot things like provisioning that requires mounted folders in a known /tmp location.

I haven't seen this bit of trivia mentioned yet, so...

I only see "stdin: is not a tty" when running a privileged shell provisioner. If I set "privileged: false", the message doesn't appear.

If you are running Centos/REHL then config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'" wont work. You need to comment out Defaults requiretty in /etc/sudoers.

โ€ผ๏ธ Still running into issues with this on Ubuntu 12.04, using Vagrant docker provisioning and shell inline.

Gist of a --debug stderr/stdout log, with a link to the Vagrantfile in the description available here: https://gist.github.com/momer/270b875f376b44883d1e

Update

I had added DOCKER_OPTS='-H tcp://0.0.0.0:4243 ...' as I was using the command on another VM set up. Removing that opt allowed Vagrant to set up and start Docker correctly.

I am also running into the same issue as @Blaisorblade and @andyshinn when setting
config.ssh.pty = true on precise64.box.

Cheers to @bradfeehan going hard on this. We should reopen this and figure it out ๐Ÿ˜ƒ

@bradfeehan : Thanks from me as well. I agree with your analysis, but for two minor nitpickings:

Remove the trailing slash from the $PATH (currently /etc/profile.d/vagrantruby.sh contains PATH=$PATH:/opt/ruby/bin/, the trailing slash can cause problems, a trivial example being which ruby giving /opt/ruby/bin//ruby with two slashes).

That path is just as valid, and I don't think there can be any "problems" (except if some script does something weird), but I agree that's ugly and should be fixed.

Actually export the change to $PATH (the current assignment to $PATH won't affect any sub-processes, which can be confusing)

Nope: changing a variable doesn't mean you need to reexport it. To be clear, after:

PATH=/bin:/usr/bin
export PATH
PATH=/other/path:$PATH

subprocesses will see the new value of PATH. That's because export (conceptually) sets a flag for the variable name, not for its content.

There is an unexpected and trivial solution on stack overflow : http://serverfault.com/questions/500764/dpkg-reconfigure-unable-to-re-open-stdin-no-file-or-directory

export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
locale-gen en_US.UTF-8
dpkg-reconfigure locales

it just works.

I also received a similar error message (but with a different root cause), and my issue was solved in #5753. I'm posting for search-engine visibility.

hehe :)

heh

In addition, with config.ssh.pty the default shared folder is mounted under logout (meaning /home/vagrant/logout) instead of /vagrant. I guess some command is happy to see a TTY and is producing output which Vagrant doesn't expect, but usually login/logout scripts are supposed to not produce output with non-interactive shells.

Should reproduce that again; my analysis was wrong, because the provisioning shell is indeed interactive (as discussed by others).

Note that the workaround based on overriding the shell breaks vagrant ssh -c COMMAND. I have yet to find a way to quiet the error while keeping this feature.

Im using Ubuntu 14.04.

I found that using

config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"

as @bradfeehan suggests, breaks the vagrant ssh -c COMMAND as @warrenseine mentioned.

But using

config.vm.provision "fix-no-tty", type: "shell" do |s|
    s.privileged = false
    s.inline = "sudo sed -i '/tty/!s/mesg n/tty -s \\&\\& mesg n/' /root/.profile"
end

as @johnraz suggests, works fine.

I didnt test the @Offirmo suggestion, but my box already had the locales set as he suggests:

$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US:
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8

getting this when running vagrant up on a windows 7 pro x64 host ... attempting to generate a ubuntu vm ... suggestions on fix? I have tried updating my vagrantfile many ways, no luck so far...

default:
default: Guest Additions Version: 4.3.10
default: VirtualBox Version: 5.0
==> default: Mounting shared folders...
default: /vagrant => C:/HashiCorp/Vagrant/projects/docker
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

chown id -u vagrant:id -g vagrant /vagrant

Stdout from the command:

Stderr from the command:

chown: changing ownership of `/vagrant': Not a directory

c:\HashiCorp\Vagrant\projects\docker>

@spuds51 This appears unrelated, so to maximize your chances to get answers you should post elsewhere โ€” a separate issue, a post on the mailing list, or on IRC (see README).

I didn't understand, how is this closed if I have still the same issue? Is the workaround a kind configuration? Is there documentation?

ubuntu 14.10 as guest,
windows 10 as host
vagrant 1.8.1
vb-guest 0.11.1

The workaround of @johnraz works:

config.vm.provision "fix-no-tty", type: "shell" do |s|
    s.privileged = false
    s.inline = "sudo sed -i '/tty/!s/mesg n/tty -s \\&\\& mesg n/' /root/.profile"
end

I'm getting the issue on:

Vagrant 1.8.5
VirtualBox 5.0.26
bento/ubuntu-16.04 version 20160805.0.0

default: Running: /var/folders/fv/4bgskv153wz93tdmbvmfb9fh0000gn/T/vagrant-shell20160807-7353-126ogg7.sh ==> default: mesg: ==> default: ttyname failed ==> default: : ==> default: Inappropriate ioctl for device

I re-wrote the /root/.profile editing snippet because it was broken for me:

(grep -q -E '^(mesg n \|\| true)$' /root/.profile && sed -ri 's/^(mesg n \|\| true)$/tty -s \&\& mesg n/' /root/.profile && echo 'Ignore the previous error about stdin not being a tty. Fixing it now...')

The error only occurs once while provisioning now.

@liquidice That's probably a different issue. See #7155

@Ajedi32 As I said, I run that code I provided above on initial provision, and the problem only happens once on initial provision now, instead of every time.

This is happening for me as well. I have attached the log file: vagrant.log.tar.gz.

Here are the annoying messages that appear when I run vagrant up:

$ vagrant up
.
.
.
==> acs: mesg:
==> acs: ttyname failed
==> acs: :
==> acs: Inappropriate ioctl for device
.
.
.
==> acs: dpkg-preconfigure: unable to re-open stdin: No such file or directory

Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

  # ansible control center
  config.vm.define "acs" do |acs|
    acs.vm.box = "boxcutter/ubuntu1604"
    acs.vm.hostname = "acs"
    acs.vm.network "private_network", ip: "192.168.33.10"
    acs.vm.provision "shell", inline: "sed -i 's/us.archive.ubuntu/au.archive.ubuntu/g' /etc/apt/sources.list && apt-get update && apt-get install ansible -y"
  end

end

Host OS: Ubuntu 16.04
VirtualBox version: 5.0.24_Ubuntur108355


CC: @mitchellh

lshw commented

mount -t devtmpfs none /home/chroot/dev
mount -t devpts none /home/chroot/dev/pts

I'm running into an issue with apt-get update if I use the fix-no-tty solution. Essentially, apt-get just stalls and does nothing.

Edit: It might just be apt-get hanging...

@berdon You sure apt-get isn't waiting for console input? Then it might do different things on a terminal or not (even failing on a non-terminal). That's surprising for apt-get update, but if a program isn't using input at all it shouldn't notice...

@Blaisorblade

I believe the issue was unrelated to Vagrant and more likely related to IPv6 issues and apt-get. I ran across a StackExchange post suggesting disabling IPv6 for updates and upgrades. This seems to have fixed the issue:

Pre-Config shell script:

echo "Disabling IPv6"
sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak
echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.default.disable_ipv6 = 1" >>  /etc/sysctl.conf
echo "net.ipv6.conf.lo.disable_ipv6 = 1" >>  /etc/sysctl.conf
sudo sysctl -p

Post-Config shell script:

# sudo apt-get -qq -y update
echo "Resetting IPv6"
mv /etc/sysctl.conf.bak /etc/sysctl.conf

I'm going to lock this issue because it has been closed for 30 days โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.