Иногда приложения выдают нам очень странные сообщения об ошибках и приходится изрядно поломать голову, чтобы понять, в чем именно проблема и как ее исправить.

Мы решили, что подобные случаи достойны серии небольших статей под общим названием «Работа с сообщениями об ошибках».

И сегодня у нас подарок от всеми любимой программы git.
В очередной раз, сделав git pull на тестовый сервер, клиент увидел вот такое сообщение:
fatal: write failure on 'stdout': No space left on device

И обратился к нам с просьбой разобраться, почему это он не может на stdout писать

Место на диске и свободных inode было достаточно. Клонирование того же репозитория на этот же сервер в другой каталог проходило без проблем.

Гугление по данной фразе ни к чему не привело.

То, что клонирование проходит настойчиво, подвигает нас к выводу, что поломалась локальная копия тестового сервера. Начали поиск инструментов для починки git-репозитория, но тут заметили странную вещь:

df -h 

Filesystem      Size  Used Avail Use% Mounted on
/dev/simfs      535G  364G  144G  72% /
none            2.9G  2.9G     0 100% /dev
none            583M  1.1M  582M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            1.2G     0  1.2G   0% /run/shm
none            100M     0  100M   0% /run/user

На разделе /dev занято 100% места. Все 2.9G — странно.
Заходим в /dev и видим файл /dev/null размером как раз с эти 2.9 гигабайта.

Видимо, кто-то когда-то удалил устройство /dev/null, а сервисы так и продолжили писать в /dev/null, создав обычный файл и потихоньку забивая место.

Удалили файл, создали устройство, перестартовали сервисы, которые писали в /dev/null — освободилось место на /dev и git pull отработал без проблем и ошибок.

Комментарии (17)


  1. amarao
    17.04.2015 16:26
    +6

    Вы устройство руками создавали? Ошибка.

    Правильно:
    mount|grep '/dev'
    udev on /dev type devtmpfs (rw,relatime,size=1994644k,nr_inodes=206376,mode=755)

    А /dev/null вам не «удалили», а «не создали» в процессе запуска контейнера/докера/mountnamespace'а/etc.


  1. ploop
    17.04.2015 16:36
    +22

    Интересно, а при чём здесь git? :)


    1. LuckySB Автор
      17.04.2015 19:28
      -7

      Не при чем. При чем тут авторы git, которые поленились организовать более подробный вывод ошибок.

      Вот одна из частых ошибок:

      fatal: The remote end hung up unexpectedly

      Сообщение от капитана Очевидность. А можно было бы хотя бы указывать в процессе какой операции удаленный конец оборвал соединение


      1. ploop
        17.04.2015 20:03
        +2

        Полагаю, что 'No space left on device' уже системное сообщение, git его просто перебросил.
        Да не суть — выскочить могла любая программа. При чём молча.


        1. LuckySB Автор
          17.04.2015 20:31
          -2

          вот именно!
          Вот к этому — «просто перебросил» — и есть основная претензия.

          unix way — три-четыре утилиты перебросили системное сообщение — в итоге теряется контекст и оказывается, что вам показывают ошибку, которая слабо коррелирует с исходной командой.

          И приходится писать вот такие мелкие постики, просто для того, чтобы сохранить информацию вида «а вы выключатель в шкафу поищите»
          Чтобы в следующий раз проблему решило быстрое гугление, а не вдумчивое чтение исходников git


          1. ploop
            17.04.2015 21:06
            +2

            unix way — три-четыре утилиты перебросили системное сообщение — в итоге теряется контекст и оказывается, что вам показывают ошибку, которая слабо коррелирует с исходной командой.

            Так он же перед этим явно сказал, что ошибка возникла при записи в stdout. Ошибка такая-то, и выдал системную, что уже заставляет задуматься (что вы и сделали).
            Ну как вот вы, на месте разработчиков гита, разрулили бы такую нестандартную ситуацию? Стали оборачивать обработчиками исключения каждое конкретное обращение к stdout, или всё-таки каким-нибудь базовым классом обошлись?


            1. LuckySB Автор
              20.04.2015 14:31

              я не силен во внутренних алгоритмах гита, и читать исходники у меня времени нету.

              но просто предположение:

              git вызвал что-то типа patch file /dev/null
              patch попытался записать в свой stdout, который на самом деле направлен в ФАЙЛ /dev/null
              на разделе, занятом на 100%

              а ошибка-то про запись в stdout. не надо обрабатывать исключения, достаточно вывести команду, которая вернула ошибку. Было бы намного информативнее.


              1. ploop
                20.04.2015 14:43
                +1

                Да я тоже не силён в них, просто предполагал. Понимаете, практически любой мало-мальски сложный код можно улучшить. Всегда. И заниматься этим можно до бесконечности. Думаю, у разработчиков гита есть более важные проблемы, которые надо решать, а не предусматривать все мыслимые и немыслимые варианты работы в хаотичном окружении.


          1. grossws
            18.04.2015 04:02
            +3

            А что git fetch ... >/dev/null, например, должен был бы вывести? Откуда git fetch ... может узнать куда перенаправили stdout?


            1. Power
              18.04.2015 17:04

              Теоретически, он мог бы посмотреть на /proc/self/fd/1. Но это может быть не очень кросс-платформенно.


              1. grossws
                18.04.2015 19:56
                +1

                Оно, конечно, есть на linux. На freebsd, вроде, есть /proc/curproc. На mac os x procfs нет, на win — тоже.

                Главный вопрос в том, зачем все эти сложности? Защититься от кого-то, который не смонтировал devfs? А если это было через неименованный pipe? Ошибка станет понятнее?


  1. kahi4
    17.04.2015 16:38
    +4

    «Клонирование того же репозитория на этот же сервер в другой каталог проходило без проблем.»

    Эта цитата противоречит причине возникновения ошибки.


    1. LuckySB Автор
      17.04.2015 19:14

      Вот именно. Противоречит.
      Но так было.

      Единственно, что могу предположить, ошибка происходила в момент изменения рабочего дерева.
      А при клонировании с нуля файлы сразу создавались в последней версии.


  1. m0n9oose
    17.04.2015 18:04
    +23

    Умопомрачительной полезности пост.


  1. maximw
    17.04.2015 18:59
    +9

    Можно было придумать более «кричащий» заголовок.

    Как забить под завязку /dev/null
    Что если /dev/null «отправить в /dev/null»
    Git! А теперь когда вы обратили внимание, /dev/null бывает не создано.


    1. LuckySB Автор
      17.04.2015 19:31

      Извините. я в начале попытался объяснить суть названия.

      Если переимновать ее в
      «Работа с сообщениями об ошибках — git»

      Будет не слишком кричаще?
      А как насчет тяжеловестности и сложности для восприятия?


      1. maximw
        17.04.2015 20:17
        +8

        Да не, это вы извините. Это был юмор, сарказм.
        Я вообще не стал бы публиковать такой пост.