Her bir Sözde Terminal (PTY) bileşeninin (yazılım, ana taraf, ikincil taraf) sorumlulukları nelerdir?


59

Bir tty'nin nasıl çalıştığını 1 çözmeye çalışıyorum (her bir öğenin iş akışı ve sorumlulukları). Bununla ilgili birkaç ilginç makale okudum, ancak hala bulanık alanlar var.

Şimdiye dek anladığım şey bu:

  • Öykünülmüş terminal /dev/ptmx, sözde terminalin ana kısmına farklı sistem çağrıları yapar .
  • Sahte terminalin ana kısmı /dev/pts/[0-N], kullanılmayan seri porta karşılık gelen bir dosya tahsis eder ve ona bir köle sahte terminali "ekler".
  • Slave sözde terminal, oturum kimliği, ön plan işi, ekran boyutu gibi bilgileri tutar.

İşte benim sorularım:

  1. Ptmx , köle kısmını tahsis etmekten başka bir amacı var mı? Bir tür "zeka" sağlıyor mu , yoksa öykünmüş terminal (örneğin xterm) bir terminal gibi davranmanın tüm zekasına sahip mi?
  2. Xterm neden ana bölümle etkileşime girmek zorunda , çünkü yalnızca köle bölümünün stdout'unu ve stdin'ini iletiyor? Neden doğrudan pts dosyasından yazıp okuyamıyor ?
  3. Bir oturum kimliği her zaman bir pts dosyasına ve bunun tersi ekli midir? Bir ps komutu yazıp aynı / dev / pts / X için 2 sessionId bulabilir miyim ?
  4. ptsMağaza başka hangi bilgileri saklar? Xterm tüm alanları tek başına mı güncelliyor, yoksa ptmüzerine bir "zeka" mı ekliyor?

1. Anlayışımı Linus Akesson ve Andries Brouwer'ın Linux Çekirdeği tarafından tasvir edilen TTY'ye ve bu sitelerdeki diğer bazı sorulara dayandırıyorum.

Yanıtlar:


58

Terminal emülatörleri

Ana taraf, terminale giden çizgiyi (TX / RX tel çifti) değiştirir.

Terminal , tellerden birinde aldığı karakterleri görüntüler (bunlardan bazıları kontrol karakterleridir ve imleci hareket ettirmek, rengini değiştirmek ... gibi şeyler yapmak) ve başka bir kabloya yazdığınız tuşlara karşılık gelen karakterleri gönderir.

Xterm gibi terminal emülatörleri , kablolara karakter göndermek ve almak yerine, dosya tanımlayıcılarındaki karakterleri ana tarafa okur ve yazar. Köle terminalini doğurduklarında ve kabuğunuzu bunun üzerine başlattıklarında, artık ona dokunmuyorlar. Tel çiftinin taklit edilmesine ek olarak, xterm, çizgi disiplini özelliklerinin bazılarını bu dosya tanıtıcısı aracılığıyla ana tarafa da değiştirebilir. Örneğin, boyut niteliklerini güncelleyebilirler; böylece değiştirilen bir boyutta onları bilgilendirmek için köle pty ile etkileşime giren uygulamalara bir SIGWINCH gönderilir.

Bunun dışında terminal / terminal emülatöründe çok az istihbarat var .

Bir uçbirim aygıtına yazdığınız şey (küçük köle gibi) orada gösterilmek istediğiniz şey, ondan okuduğunuz şey orada yazdığınız şeydir, bu yüzden terminal emülatörünün bunu okuyup yazması bir anlam ifade etmemektedir. . Diğer ucunda olanlar onlar.


Tty çizgi disiplini

Bir çok zeka olduğunu tty hat disiplin . Çizgi disiplini, bu aygıtla çizgi / tel (bir pty'nin ana tarafı) arasında oturan bir seri / pty aygıtının üzerine itilmiş (sürücüde, çekirdekte bulunan) bir yazılım modülüdür.

Bir seri hattın diğer ucunda bir terminali olabilir, fakat aynı zamanda bir fare veya ağ için başka bir bilgisayarı olabilir. Örneğin bir seri aygıtın (ya da pty aygıtının) bir ağ arabirimine erişmek için bir SLIP hattı disiplini ekleyebilirsiniz ya da bir tty hat disiplininiz olabilir. Tty satırı disiplini, en azından seri ve pty aygıtları için Linux'taki varsayılan çizgi disiplinidir. Linux'ta çizgi disiplinini ile değiştirebilirsiniz ldattach.

Tty line disiplinini devre dışı bırakmanın etkisini yayınlayarak görebilirsiniz stty raw -echo(bash isteminin ya vida terminali ihtiyaç duydukları tam modda ayarlamak gibi diğer etkileşimli uygulamaların , bu nedenle catdeneyimlemek gibi aptal bir uygulama kullanmak istediğinize dikkat edin). Daha sonra, slave terminal cihazına yazılan her şey xterm'in okunmasını hemen ana tarafa getirir ve xterm tarafından master tarafa yazılan her karakter slave cihazından okumak için hemen kullanılabilir.

Çizgi disiplini, terminal cihazı dahili çizgi editörünün uygulandığı yerdir . Örneğin, stty icanon echo(varsayılan gibi) ayazdığınızda, xterm amaster'a yazar , daha sonra çizgi disiplini tekrar yankılanır ( görüntüleme aiçin okumaya uygun hale getirir xterm), ancak ikincil kısımda okumak için uygun bir şey yapmaz . Eğer geri tuşuna yazarsanız Sonra, xterm bir gönderir ^?veya ^H(bu kadar karakteri, çizgi disiplin ^?veya ^Htekabül erasehat disiplin ayarı) ana a geri gönderir ^H, spaceve ^Hiçin xtermsilmekaaz önce ekranını yazdınız ve hala köle tarafından okunan uygulamaya hiçbir şey göndermiyor, daha aönce yazdıklarınızı kaldırmak için iç satır düzenleyicisi arabelleğini güncelleştiriyor .

Enter tuşuna Sonra, xterm gönderir ^Mçizgi disiplin bir ^ J (LF) için girişe dönüştüren (CR), ve bir uygulama üzerinde okuma (köle tarafında okumak için şimdiye kadar girdiğiniz gönderir /dev/pts/xne alacak LF'yi yazdınız, ancak asildiğinizden beri değil), ana tarafta iken imleci bir sonraki satıra ve ekranın başına götürmek için bir CR ve LF gönderir.

Hat disiplini, sinyalin ana tarafta bir karakter aldığında terminalin ön plan işlem grubuna gönderilmesindenSIGINT de sorumludur ^C.

Pek çok etkileşimli terminal uygulaması , bu disiplinin özelliklerinin çoğunu, kendileri uygulamak için devre dışı bırakır . Ancak, her durumda, terminalin ( xterm) bununla çok az ilgisi olduğuna dikkat edin (gösterilmesi söylenenleri gösterme hariç).

Ve işlem başına ve terminal cihazı başına sadece bir oturum olabilir. Bir oturum, kendisine bağlı bir kontrol terminaline sahip olabilir, ancak bunu yapmak zorunda değildir (tüm oturumlar bir terminal açmadan başlayana kadar başlar). xterm, kabuğunuzu çalıştırmaya zorladığı süreçte tipik olarak yeni bir oturum oluşturur (ve bu nedenle varsa başlattığınız terminalden ayrılır xterm), /dev/pts/xbu terminal cihazını yeni oturuma bağlayarak açtığı yeni olanı açar. Daha sonra bu süreçte kabuğunuzu çalıştırır, böylece kabuğunuz oturum lideri olur. Kabuk veya o oturumdaki herhangi bir etkileşimli kabuk tipik olarak işlem gruplarıyla hokkabazlık yapacak tcsetpgrp()ve bu terminal için ön ve arka plan işlerini ayarlayacaktır.

Hangi bilgilerin tty disipline sahip (seri veya pty) bir terminal cihazı tarafından saklandığına gelince , genellikle sttykomutun gösterdiği ve değiştirdiği şey budur. Tüm disiplin yapılandırması: terminal ekranı boyutu, yerel, giriş çıkış bayrakları, özel karakter ayarları (^ C, ^ Z ... gibi), giriş ve çıkış hızı (pty'ler için geçerli değildir). Bu , Linux haritasında / ioctls öğesine ve / için ekran boyutuna tcgetattr()/ tcsetattr()işlevlerine karşılık gelir . Geçerli ön plan işlem grubunun terminal cihazında ( / , ioctls) depolanan başka bir bilgi veya mevcut giriş veya çıkış tamponu olduğunu iddia edebilirsiniz .TCGETSTCSETSTIOCGWINSZTIOCSWINSZtcsetpgrp()tcgetpgrp()TIOC{G,S}PGRP

Terminal cihazda depolanan ekran boyutu bilgilerinin gerçeği yansıtmayabileceğini unutmayın. Terminal emülatörü tipik olarak, penceresi yeniden boyutlandırıldığında (ana boyuttaki aynı ioctl aracılığıyla) penceresi yeniden boyutlandırıldığında ayarlayacaktır, ancak bir uygulama köle tarafındaki ioctl'i çağırdığında veya yeniden boyutlandırma iletilmediğinde senkronizasyondan çıkabilecektir (durumda örneğin ihmal sshdederse başka bir küçük ürüne işaret eden bir ssh bağlantısı . Bazı terminaller de kaçış dizileri aracılığıyla boyutlarını sorgulayabilir, böylece bir uygulama bu şekilde sorgulayabilir ve çizgi disiplinini bu bilgilerle güncelleyebilir.sshSIGWINCH

Daha fazla ayrıntı için, örneğin Debian'daki termiosve tty_ioctlman sayfalarına göz atabilirsiniz .

Diğer hat disiplinleriyle oynamak için:

  1. Bir fareye sözde-terminal taklit:

    socat pty,link=mouse fifo:fifo
    sudo inputattach -msc mouse # sets the MOUSE line discipline and specifies protocol
    xinput list # see the new mouse there
    exec 3<> fifo
    printf '\207\12\0' >&3 # moves the cursor 10 pixels to the right
    

    Yukarıda, çukurun ana tarafı, socat tarafından adlandırılmış bir pipe ( fifo) üzerine sonlandırılır . Bu fifoyu, fare sistemleri protokolünde, 0x87 0x0a 0x00 yazan bir işleme (kabuk) bağlarız no button pressed, delta(x,y) = (10,0). (Terminal cihazından bir uygulama tarafından (potansiyel olarak dönüştürülmüş) okunmamalıdır Burada, (kabuk) bir terminal, ama fare taklit olmamak üzere, biz göndermek 3 bayt olan mouse, yukarıda yapılan bir sembolik olan socatbazı /dev/pts/xcihaz) , ancak bir fare giriş olayı olarak yorumlanmalıdır.

  2. Bir SLIP arayüzü oluşturun:

    # on hostA
    socat tcp-listen:12345,reuseaddr pty,link=interface
    # after connection from hostB:
    sudo ldattach SLIP interface
    ifconfig -a # see the new interface there
    sudo ifconfig sl0 192.168.123.1/24
    
    # on hostB
    socat -v -x pty,link=interface tcp:hostA:12345
    sudo ldattach SLIP interface
    sudo ifconfig sl0 192.168.123.2/24
    ping 192.168.123.1 # see the packets on socat output
    

    Yukarıda, seri kablo socathostA ve hostB arasında bir TCP soketi olarak taklit edilir . SLIP hat disiplini, bu sanal hat üzerinden alınıp verilen baytları sl0arayüzde teslimat için SLIP kapsüllenmiş IP paketleri olarak yorumlar .


1
Bu en iyi cevap. Doğru olarak işaretler ve oylar. Pts'in sakladığı bilgilerle ilgili son bölümü ekleyebilir misiniz? Bu sayfaya göre (TTY cihazını yapılandırma bölümü) , pts satır sayısı ve satır sayısı gibi değerleri saklar. Sakladığı başka bilgi var mı?
Pierre-Jean

@ Pierre-Jean, daha fazla bilgi ekledi.
Stéphane Chazelas 17:14

Cevabınız tatmin edici olmamakla birlikte, gerçekte nasıl bir / dev / pts / M oluşturduğunuza ilişkin daha basit bir örnek görmek ilginç olacaktır. cat /dev/ptmx &Hangisini yeni bir çukur açan kullanmaya çalıştım , ama sonra onunla ilişkili bulabileceğim bir işlem yok, peki nasıl kullanırsın? İkincisi denedim echo "1" >/dev/ptmxama bu hiçbir şey yapmadı ... Neden bununla ilgileniyorum? Sıklıkla biri ssh(örneğin) uzaktan bağlandığında , iş kontrolünü önleyen hata PTY allocation request failedveya No controlling tty: open /dev/ttyhata alırsınız . Bunları daha iyi anlamak güzel olurdu.
not2qubit

@ user1147688, nasıl bir pty oluşturulacağı farklı bir soru olurdu. Bu, bir seferde çok fazla soru zaten. Ancak ayrıntılar için ptyman sayfanıza bakın.
Stéphane Chazelas,

@ StéphaneChazelas Küçük açıklamalar: 1. Yani akış gibi olduğunu söylüyorsun physical term---- tty---- bashterminalleri üzerinde ve pty(m)---- tty---- pty(s)---- bashterminal öykünücülerinde? ttyDisiplin , fiziksel terminaldeki karakterlerin yankılanmasından da sorumlu muydu ? 2. Girişi yönetmek için klavyeye / ekrana bağlanan terminal emülatör programı mı? 3. Anladığım kadarıyla, bash komutlarının / tüm terminal girişlerinin ttysatır tamponlamasının CI / O fonksiyonlarının I / O tamponları yerine hat disipliniyle yapıldığını söylediniz . Bu doğru mu?
forumulator

29

Düzenleme: Bu yanıttan bu yana , daha fazla ayrıntıyla ilgilenebilecek kişiler için blogumda özel bir makale yazdım .


Çok okuduktan sonra anladım.

  • Ptmx, köle kısmını tahsis etmekten başka bir amacı var mı? Bir tür "zeka" sağlıyor mu, yoksa öykünmüş terminal (örneğin xterm) bir terminal gibi davranmanın tüm zekasına sahip mi?

    /dev/ptmxikincil bölümü tahsis etmez : "sözde terminal ana bölümünü" tahsis eder. / dev / ptmx ana sahte terminal değil : sahte terminal master çoğullayıcı . Master sözde terminali ( kaynak ) tahsis ederken yarış koşullarından kaçınmak için Unix98 PTY standardı ile yaratılmıştır .

    Ana parça (ıun) uçbirimin dosya sisteminde temsil edilir. Bir dosya tanıtıcısı ile temsil edilir.

    Köle bölüm (PTS) bir dosya ile temsil edilir /dev/pts/Nburada Nbir sayıdır.

    Puan ardışık çağrı yoluyla PTM elde edilir grandpt, unlockpt, ptsname. ( Kaynak )

    Ptm, aygıtla iletişim kurmaya adanmış AUR sürücüsünün ve satır baskısının yerini alır. Bu nedenle, herhangi bir şekilde bir uçbirime öykünmediği gibi, satır baskısı özelliğini de sağlar ve noktalarla görselleştirmenin ve iletişim kurmanın bir yolunu sağlar. ( Kaynak )

    Bir donanım cihazına bağlı TTY'nin bir grafiği AUR ile TTY iletişimi

    Ve burada bir ptm'ye bağlı bir tty grafiği PTM ile TTY iletişimi

    Ptm dosyası, pts'den farklı Ioctl argümanlarını (ISPTM, UNLKPT, TIOCREMOTE, TIOCSIGNAL) ele alır.

  • Xterm neden ana bölümle etkileşime girmek zorunda, çünkü yalnızca köle bölümünün stdout'unu ve stdin'ini iletiyor? Neden doğrudan pts dosyasından yazıp okuyamıyor?

    İşlemler, sanal bir dosyaya yapılan eylemler aracılığıyla aygıtlarla etkileşime girer (okuma, yazma, iyilik ..). Dosyanın kendisi yoktur ve sürücü, okuma veya yazma yöntemleri çağrıldığında eylemleri tetiklemek için dosyayı kullanır. (Sürücüler hakkında bilgi için Eke bakınız)

    Bir TTY, onunla etkileşime girmenin kesin bir yolunu tanımlar. İşlemler cihazdan yazıp okur ve ne tür TTY'nin uygulandığına bakılmaksızın aynı davranışı bekler.

    • Okuma fonksiyonu , işlemler tarafından terminalden girişleri okumak için kullanılır.
    • Yazma işlevi , çıkışları terminale göndermek için işlemler tarafından kullanılır.

    PTS, bir TTY sürücüsü gibi davranıyor. Okuma ve yazma yöntemi, TTY Sürücüsü davranışını uygulamak için kullanılır. Verileri gönderecek gerçek bir cihaz olmadığı için, bir akış çifti oluşturulur ve ptm, pts tarafından akışa gönderilen verileri okumak için bir okuma fonksiyonu ve mevcut olan akışa veri göndermek için bir yazma işlevi uygular. pts onu okuyacak.

    Unutmayın, bir cihazı temsil eden dosya klasik bir dosya değildir ve dosyaya xtermne yazıldığını görmek istiyorsa, bu işlevlerin burada tamamen farklı bir davranışı olduğu için sadece açık olarak adlandırılamaz ve okunamaz.

  • Bir oturum kimliği her zaman bir pts dosyasına ve bunun tersi eklenmiş mi? Bir ps komutu yazıp aynı / dev / pts / X için 2 sessionId bulabilir miyim?

    Bunu sanmıyorum, oturum kimliği pts'i ekleyen ilk işlem tarafından tanımlanır (genellikle bash) ve başka bir oturum oluşturmanın ve aynı noktalara eklemenin bir yolunu göremiyorum. Belki böyle bir araç socatbunu yapabilir?

  • Pts başka hangi bilgileri saklar? Xterm tüm alanları tek başına günceller mi yoksa ptm üzerine bir miktar "zeka" ekler mi?

    Pts, iletişim kurduğu terminalle ilgili 2 bilgi kategorisini saklar: the Terminfove Termcap. Genellikle, birçok terminal emülatörü, bunlar için termcap bilgilerini yöneten kütüphaneye dayanır (örneğin, bir VTX100'ü taklit etmek için tüm yetenek değerlerini sağlar). Böyle bir kütüphanenin bir örneği libvte'dir . Düzenleme (bkz.Stephane Chazelas yorumu): Terminal yetenekleri pts tarafından depolanmaz.

ek bina


termcap ve terminfo terminal veya terminal emulator yetenekleri hakkındaki veritabanlarıdır, tty veya pty cihazlarıyla ilgisi yoktur.
Stéphane Chazelas

Tamam, cevabımı düzenleyeceğim. Yorumunuz için teşekkürler. Biliyorsanız cevabınıza pts hakkında bu bilgileri ekleyebilir misiniz (örneğin pts ekran boyutunu saklar).
Pierre-Jean

6
Bunlar güzel görüntüler. Onları yapmak için hangi yazılımı kullandınız?
Gilles 'SO- kötü olmaktan' eylül

5
@Gilles Teşekkürler. Onları açık kaynaklı bir vektör grafik editörü olan Inkscape ile yaptım . Bu tür grafikleri yapmanın en etkili yolu belki de olmayabilir, ancak ilgileniyorsanız, bu tür izometrik çizimlerin nasıl oluşturulacağı hakkında bir makale yazdım .
Pierre-Jean

Bir kontrol terminaline iki seansa katılabileceğinizi veya bir seansın birden fazla kontrol terminaline
sahip olabileceğini düşünmüyorum

9

İşte bir süre önce nasıl sshdçalıştığı hakkında yaptığım bir şema . Çizgi disiplini ve benzeri şeylerin çalışmasını ilgilendirmez, ancak kimin neyle etkileşime girdiğinin gerçek hayattan bir resmini ekler:

görüntü tanımını buraya girin


Bunun için çok teşekkür ederim. Anlamaya çalışarak 2 gün geçirdim. Sadece bir pty başlatılmadığında ne olacağını merak ediyorum. stdin mevcut değil, iyi, ama stdout ve stderr nereye yazılır?
küçük dostum

@emmasculateur size yardımcı oldu. Üzgünüm, ne demek istediğinizi "pty başlatılmadığında" anlayamıyorum. Pty'nin somutlaştırılmadığı bir örnek verebilir misiniz?
Boris Burkov

1
"Hiçbir pty başlatılmadı" derken -T, ssh ile çalıştığınızda , bu adam sahte terminal tahsisini devre dışı bıraktığını söylüyor. örneğin: ssh -T emasculateur@localhost "sleep 10" o zaman bunu ps aux|grep sleepgösterir: emasculateur 21826 0.0 0.0 23032 3728 ? Ss 02:49 0:00 zsh -c sleep 10 Bu durumda bash nerede yazıyor stdoutve stderr? Umarım sorum mantıklı.
küçük dostum

@emmasculateur hm, güzel bir soru, mantıklı, daha önce düşünmedim. Sanırım bu şekilde, uzaktaki makinede ilişkili terminal olmadan bir daemon olarak işleminize başlayabilirsiniz. Tahminime göre, standart girdi / çıktı / hata sadece /dev/nullnormal bir arka plan programı için hoşuna gidiyor , ancak emin değil. Ayrıca bakınız: serverfault.com/questions/593399/…
Boris Burkov

@emmasculateur Aynı zamanda sizinkinden farklı bir davaya da rastladım: işleminiz terminal kullanıyordu, ancak bu terminal kapatıldıysa, okuma / yazma girişimi stdout / stdin girişimi üzerine çekirdekten SIGHUP alırdı. Bu genellikle ssh ile başlayan nohupve screen/ olmadan işleri öldürür tmux.
Boris Burkov

0

man pts diyor:

/ Dev / ptmx dosyası, büyük sayı 5 ve küçük sayı 2 olan, genellikle 0666 kipindeki bir root.root owner.group grubuna sahip bir karakter dosyasıdır. Bir sözde terminal master ve slave çifti oluşturmak için kullanılır.

Bir işlem / dev / ptmx açıldığında, sözde-terminal master (PTM) için bir dosya tanımlayıcı alır ve / dev / pts dizininde bir sözde-terminal slave (PTS) cihazı oluşturulur. / Dev / ptmx açılarak elde edilen her dosya tanıtıcısı, yolu tanımlayıcıyı ptsname (3) 'e geçirerek bulunabilen kendi ilişkili PTS'sine sahip bağımsız bir PTM'dir.

Sözde-terminal slave'i açmadan önce, master (3) ve unlockpt (3) için master'in dosya tanımlayıcısını geçmelisiniz.

Hem sözde terminal master hem de slave açıldığında, slave, gerçek terminal ile aynı arayüze sahip işlemler sağlar.

Bağımlıya yazılan veriler ana tanımlayıcıda girdi olarak sunulur. Master'a yazılan veriler slave'e giriş olarak sunulur.

Uygulamada, sözde terminaller, sözde terminal master'den okunan verinin uygulama tarafından yorumlandığı aynı şekilde gerçek bir terminalin verileri yorumlayacağı şekilde ve aynı zamanda uzaktan kumanda uygulamak için xterm (1) gibi terminal emülatörlerini uygulamak için kullanılır. Sözde-terminal master'dan okunan verilerin ağ üzerinden bir terminale veya terminal emülatörüne bağlı bir istemci programa gönderildiği sshd (8) gibi programlar.

Sözde terminaller ayrıca normalde borulardan girişi okumayı reddeden programlara (su (8) ve passwd (8)) giriş yapmak için de kullanılabilir.

Hakkında /dev/pts/X indexing:

Her bir X, açtığınız bir oturumdur, yani kölelerin indekslenmesi gerekir.

Hakkında TeteType (/dev/ttyN):

Gerçek konsolu gibi önyükleme sisteminiz tarafından oluşturuldu sysV.

Neden köle efendiye aşılanmış: http://commons.wikimedia.org/wiki/File:Termios-script-diagram.png


Üzgünüm, ama soruları cevaplamadın. Adam sayfasını okudum ve bu grafiği gördüm, ancak davranış açık değildi. Aydınlatmanın önerdiği gibi, sorunuza cevabınızı uzatır mısınız?
Pierre-Jean


Sahte TTY alt sistemini kullanmak için, ana taraf sürücüsü / dev / ptmx ve N bağımlı sürücü sayısı (kurulum sırasında N belirlenir) için bir düğüm kurulmalıdır. Bağımlı cihazların adları / dev / pts / M'dir, burada M, 0'dan N-1'e kadar değerlere sahiptir. Bir kullanıcı, sırayla klon sürücüsü yoluyla erişilen ana aygıt (ptm olarak adlandırılan) takma bir TTY cihazına erişir. Ana aygıt, ana aygıt numarasının klon aygıtı ve aygıtın ana aygıt olduğu Küçük cihaz numarası, ptm sürücüsü için çok önemlidir.
PersGulf

evet man pan sayfasını okudum ....!
PersGulf

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.