GNU ed Ödevimi Yedim


Eğer eski UNIX kitaplarının ve e-posta listelerinin arşivlerine girdiyseniz, şüphesiz ki UNIX efsanesine rastlamışsınızdır. ed. ed (/iː diː/ olarak telaffuz edilir) tıpkı bir metin editörüdür vim Ve emacs. Ancak benzerlerinin aksine, ed En iyi şekilde özetlenebilecek bir arayüzle birlikte gelir…

$ ed
q
?
q
?
q
?
qqqqqqqqqqqqqqqqqq
?
q
?
q

?
q
$

Tüm bunlara rağmen efsaneye göre: “ed standart metin editörüdür”. Öyle ki çoğu Linux dağıtımı /bin/ed bir Priority ile ilgili -100.

$ sudo update-alternatives --config editor
There are 5 choices for the alternative editor (providing ∕usr∕bin∕editor).

  Selection    Path               Priority   Status
------------------------------------------------------------
* 0            ∕usr∕bin∕vim.gtk3   50        auto mode
  1            ∕bin∕ed            -100       manual mode
  2            ∕bin∕nano           40        manual mode
  3            ∕usr∕bin∕code       0         manual mode
  4            ∕usr∕bin∕vim.gtk3   50        manual mode
  5            ∕usr∕bin∕vim.tiny   15        manual mode

Şaka bir yana, sık sık olmasına rağmen micro ve Visual Studio Code kullanıcısıyım, kendimi oyun oynarken buluyorum ed ve bazen kaynak kodu. En önemlisi GNU uygulaması ed.

Bu bir hikaye böcek GNU’daki özellik ed Geçen yıl kaynak kodunu incelerken birinin işini kaybetmesine neden olabilecek bir şeye rastladım.

Zamanın kısa bir tarihi

Bu tasarım kusurunun önemini anlamak için kısaca GNU’nun kökenine geri dönmeliyiz. ed editör. 1976’da Brian Kernighan ve PJ Plauger “Pascal’daki Yazılım Araçları” Pascal programlama dilini kullanarak iyi kod yazmayı araştıran bir kitap. Bu kitap aşağıdakiler gibi muhteşem pasajlar içeriyor:

“Bu arada, gerçek hayatta rutinin adını mutlaka koyarsınız sortOlumsuz bubbleböylece kullanıcıları rahatsız etmeden algoritmayı değiştirebilirsiniz.”

— Brian Kernighan ve PJ Plauger, Pascal’daki Yazılım Araçları “Kabarcık Sıralaması”na referansla

Bu kitap neden bu kadar önemli? GNU’da belirtildiği gibi info sayfa açık edGNU uygulaması ed Bölüm 6’dan ilham aldı, “Düzenleme”. İlk GNU uygulaması Kernighan ve Plauger’in spesifikasyonuna göre tasarlandı.

ed-0.1 ❯ cat THANKS
[...]

GNU ed originated with the editor algorithm from Brian W. Kernighan & P.
J. Plauger's wonderful book "Software Tools in Pascal," Addison-Wesley,
1981. [...]

Kitabı okurken özellikle şu paragraf dikkatimi çekti (vurgu bana ait):

“Hata düzeltme, editörün tasarımı üzerindeki ikinci büyük etkidir. […] edit değerli dosyaları korur, bu nedenle dikkatli olmalıdır. […] Sorunsuz bir şekilde iyileşmesi gerekir, aksi halde küçük bir hata değerli bilgilerin kaybına neden olabilir.

— Brian Kernighan ve PJ Plauger, Pascal’da Yazılım Araçları

Bu alıntıyı aklınızda tutun. Bu pasaja birazdan geri döneceğiz.

Doğrudan kaynağa

GNU’nun nasıl olduğunu incelemek için ed özelliğin altında çalışıyor, en son GNU sürümünün bir kopyasını alın (sürüm 1.18 Bu blog yazısını yazarken). Kaynak kodunda yalnızca 8 C dosyasıyla gezinmek kolaydır.

❯ find . -name "*.c"
./buffer.c
./io.c
./carg_parser.c
./main_loop.c
./main.c
./signal.c
./global.c
./regex.c

GNU ed bir SIGHUP işleyicisi var signal.c her seferinde bir yedekleme dosyası oluşturur. ed süreç bir SIGHUP sinyaliyle karşılaşır. Bu, kişinin işini kaybetmemesini sağlar. ed süreç çöküyor. Bu şuna benzer vim dosyaları değiştir.

Kendi yorumlarımı ekleme özgürlüğünü kullandım. sighup_handler() Okuyucuya rehberlik etmeye yardımcı olmak için aşağıdaki işlev.

static void sighup_handler(int signum)
{
  // [...]

  // Listen for SIGHUP signal
  if (mutex)
  {
    sighup_pending = true;
    return;
  }
  sighup_pending = false;

  // Hardcode backup filename
  const char hb[] = "ed.hup";

  // If there are unsaved changes, write current buffer to ed.hup
  // in current working directory
  if (last_addr() <= 0 || !modified() ||
      write_file(hb, "w", 1, last_addr()) >= 0)
    exit(0); // Exit here if write was successful

  // Otherwise continue executing code and attempt to write to home directory

  // Get home directory location from $HOME environment variable
  char *const s = getenv("HOME");

  // Check if $HOME environment variable is set
  if (!s || !s[0])
    exit(1);

  // Get length of $HOME path
  const int len = strlen(s);

  // Does $HOME end with a forward slash? 1 if it does, 0 else
  const int need_slash = s[len - 1] != '/';

  // Construct full path for backup file
  char *const hup = (len + need_slash + (int)sizeof hb < path_max(0)) ? (char *)malloc(len + need_slash + sizeof hb) : 0;

  // Throw error if path construction fails
  if (!hup)
    exit(1);

  memcpy(hup, s, len);

  // Append forward slash to $HOME if missing final forward slash
  if (need_slash)
    hup[len] = '/';

  // Copy backup file contents to
  memcpy(hup + len + need_slash, hb, sizeof hb);

  // Write contents to
  if (write_file(hup, "w", 1, last_addr()) >= 0)
    exit(0);
  exit(1); /* hup file write failed */
}

Ne yazık ki, kod yorumumda da belirtildiği gibi, yedekleme dosyası her zaman adlandırılacaktır. ed.hup bu da arzulanan çok şey bırakıyor.

const char hb[] = "ed.hup";

Bunun sorunlara yol açmasının pek çok nedeni var. GNU ise ed ana dizine veya geçerli dizine yazılamıyor ed.hup dosya, kullanıcı tüm çalışmalarını kaybedecektir ed çöküyor. Bunun neden kötü bir fikir olduğunu araştırmak için bir senaryo kullanacağım.

Sudo bana bir sandviç yap

Bu nasıl kullanılacağına dair bir eğitim olmadığından edkısaca: yol ed işe yarayan şey, şunu kullanarak bir arabelleğe satır ekleyebilmenizdir: a komutunu kullanın ve ardından kullanarak bir dosyaya yazın. w emretmek. Daha fazlası var ama okuyucunun aşağıda özetlenen her şeyi anlaması için bu yeterli olacaktır.

ed kullanılarak ana dizinde başlatılır. sudo ve bir miktar metin ara belleğe yazılır.

❯ ls
❯ sudo ed
a
Writing some text to a buffer using sudo
After the single '.', this process will experience
a SIGHUP signal from a different terminal window
.
141

Bu işlem, kullanılarak adlandırılan bir SIGHUP sinyaliyle karşılaşır. sudo kill -SIGHUP başka bir terminal penceresinde. ed arabelleğin içeriğini bir dosyaya yazar ed.hup geçerli çalışma dizinindeki dosya (ör. $HOME).

❯ ls -l
total 4
-rw-r--r-- 1 root        wheel    141 Feb  7 13:07 ed.hup
❯ cat ed.hup
Writing some text to a buffer using sudo
After the single '.', this process will experience
a SIGHUP signal from a different terminal window

Şimdi bir alt dizine gidiyoruz (örn. demo) ve kullanarak aynı işlemi tekrarlayın. sudo ve sebep ed SIGHUP sinyaliyle karşılaşmak için. O zamandan beri ed geçerli çalışma dizinini tercih eder $HOME dizin, ed.hup geçerli çalışma dizinine yazılacaktır.

demo ❯ ls
total 4
-rw-r--r-- 1 root        wheel    141 Feb  7 13:07 ed.hup
demo ❯ cat ed.hup
Writing some text to a buffer using sudo
After the single '.', this process will experience
a SIGHUP signal from a different terminal window

Mevcut dizin yapımız aşağıdaki gibi çalıştırılarak gösterilebilir. tree ana dizinde.

❯ tree
.
├── ed.hup
└── demo
    └── ed.hup

Bu kurulumla nihayet nasıl olduğunu gösterebiliriz ed sonunda ödevini yemek zorunda kalabilirsin. Alt dizinde başlatın ed olmadan sudo ve sürecin çökmesine neden olur.

demo ❯ ed
a
This is my homework for the assignment on Tuesday!
I hope this doesn't get lost. :(
.
ed.hup: Permission denied
/Users//ed.hup: Permission denied
84
demo ❯ ls -l
total 4
-rw-r--r-- 1 root wheel 141 Feb  7 13:07 ed.hup
demo ❯ cat ed.hup
Writing some text to a buffer using sudo
After the single '.', this process will experience
a SIGHUP signal from a different terminal window
demo ❯ cd $HOME
❯ cat ed.hup
Writing some text to a buffer using sudo
After the single '.', this process will experience
a SIGHUP signal from a different terminal window

Az önce tüm ödevlerimizi kaybettik. ed adresine yazılamadı ed.hup İşlem gerekli ayrıcalıklara sahip olmadığından, hem geçerli çalışma dizinindeki hem de giriş dizinindeki dosyalar.

Kernighan ve Plauger’in pasajı buraya çok uygun görünüyor.

“Hata düzeltme, editörün tasarımı üzerindeki ikinci büyük etkidir. […] edit değerli dosyaları korur, bu nedenle dikkatli olmalıdır. […] Sorunsuz bir şekilde iyileşmesi gerekir, aksi takdirde küçük bir hata değerli bilgilerin kaybına neden olabilir.

— Brian Kernighan ve PJ Plauger, Pascal’da Yazılım Araçları

Bu, statik yedekleme dosya adlarının neden kullanılmaması gerektiğine dair bir derstir.


Güncelleme (Nisan 2022)

  • @qrs bağlantı kesildiğinde bir SIGHUP gönderildiğini Twitter’da bana bildirdi; bir süre boyunca değil ed kaza. Blog yazımı buna göre güncelledim.
  • Hacker News kullanıcısı projektfu, kullanıcıların “sudo -e yerine sudo $EDITOR Kök izinleriyle önemli bir şeyi düzenlerken”.





Source link