Üye Kayıt Üye Giriş

STDIN_FILENO, STDOUT_FILENO ve STDERR_FILENO Sembolik Sabitleri


STDIN_FILENO, STDOUT_FILENO ve STDERR_FILENO Sembolik Sabitleri

 

Bir process çalıştırıldığında dosya tablosunda default olarak üç dosya betimleyicisinin
bulunduğunu belirtmiştik. Bunlar stdin, stdout, stderr dosyalarına ilişkin betimleyicilerdir.
Bunlara ilişkin betimleyiciler sırasıyla geleneksel olarak 0, 1, 2 değerlerindedir. Ancak bu
değerler POSIX standartlarına göre zorunlu değerler değildir. Bu standart dosyalara ilişkin
betimleyici değerleri unistd.h başlık dosyası içerisinde STDIN_FILENO, STDOUT_FILENO
ve STDERR_FILENO biçiminde belirtilmişlerdir. Fakat 0, 1 ve 2 değerlerini doğrudan
kullanan pek çok program kodu mevcuttur. Hemen hemen tüm POSIX sistemlerinde bu
sembolik sabitler geleneksel değerlerindedir.


#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#define BUFLEN 1024


int main(int argc, char *argv[])
{
char buf[BUFLEN];
C ve Sistem Programcıları Derneği 38
int fd;
int n;
if (argc != 2) {
fprintf(stderr, "Wrong number of arguments...!\n");
exit(EXIT_FAILURE);
}
if ((fd = open(argv[1], O_RDONLY)) == -1) {
perror("open error");
exit(1);
}
while (( n = read(fd, buf, BUFLEN)) > 0 )
write(STDOUT_FILENO, buf, n);
close(fd);
}


Sembolik Linkler
Bilindiği gibi ln komutu bir dosyanın aynı i-node elemanına ilişkin bir kopyasından
oluşturmaktadır. Örneğin,


‘ln a b’
gibi. ln komutu tipik olarak link sistem fonksiyonunu çağırmaktadır. UNIX/Linux
terminolojisinde link denildiği zaman aynı i-node elemanını gören dosyalar anlaşılmaktadır.
Bazen bu kavrama ‘Hard Link’ de denilmektedir.


Bir dizin için hard link işlemi yapılabilir mi? Bu işlem çok tehlikeli olabilir, çünkü dizin
ağacını dolaşan algoritmalar sonsuz döngüye girebilirler; bu durum dosya sisteminin
bozulmasına bile yol açabilmektedir. Örneğin aşağıdaki dizin yapısı içerisinde A ile T
dizinleri bir hard link oluşturmuş olsunlar.


A<dir> K<dir>
X M
Y Z
K <dir> T<dir>


Burada A dizini dolaşılmaya çalışılırsa A ile T dizinleri aynı i-node elemanına sahip olduğu
için sonsuz döngüsel bir durum oluşacaktır. Bu nedenle pek çok sistemde bir dizinin hard link
işlemine sokulması ya tamamen yasaklanmıştır ya da yalnızca root kullanıcılarına serbest
bırakılmıştır. İşte bu nedenlerden dolayı sembolik link kavramı da geliştirilmiştir. Sembolik
link ln –s komutu ile yaratılır. Örneğin,


‘ln –s a b’
gibi. Dizinler de her hangi bir kullanıcı tarafından sembolik link işlemine sokulabilmektedir.
Sembolik link durumu ls –l komutunda açık olarak görülebilmektedir (erişim bilgilerinin en
solundaki karakter de 'l' olarak gözükmektedir). Sembolik link dosyaları aslında ayrı bir
dosyadır. Ancak başka bir dosyayı referans etmektedir. Sembolik link dosyaları bazı işlemlere
sokulduğunda sembolik link dosyasının kendisi değil, onun referans ettiği dosya işlem
görmektedir. Örneğin stat fonksiyonu ile bir sembolik link dosyasının bilgileri alınacak olsa
sembolik link dosyaların kendi bilgisi değil, onun referans ettiği dosyaların bilgileri
C ve Sistem Programcıları Derneği 39
alınmaktadır. Bir dizinin sembolik link’i oluşturulduğunda artık bu dizin sistem için bir dizin
görünümünde olmaz, normal bir dosya görünümünde olur. Tabii dizin dolaşma işlemi de stat
fonksiyonu ile yapılmamalıdır. Bunun için lstat isminde başka bir fonksiyon
bulundurulmaktadır. lstat fonksiyonunun stat fonksiyonundan normal dosyalar için hiç bir
farkı yoktur. Ancak sembolik link dosyalarında lstat fonksiyonu sembolik link dosyasının
referans ettiği dosyanın bilgilerini değil, sembolik link dosyasının kendi dosya bilgilerini elde
eder. lstat fonksiyonu bir sembolik link içeren dizin dosyası ile karşılaştığında bunu bir dizin
dosyası olarak görmez. Bütün bu anlatılanların özeti şudur: Dizin ağacını dolaşan
uygulamalarda stat değil, lstat fonksiyonu kullanılmalıdır. Eğer stat fonksiyonu kullanılırsa
sembolik link işlemine tutulmuş dizinlerde yine sonsuz döngü oluşmuş olur. Bazı önemli
sistem fonksiyonlarının sembolik link dosyalarına karşı davranışları şöyledir:


Fonksiyon İsmi Kendi Dosyası mı?
Referans Ettiği Dosya mı?
lstat Kendi dosyası
open referans ettiği dosya
remove Kendi dosyası
rename Kendi dosyası
unlink Kendi dosyası
access Referans ettiği dosya


Sembolik link oluşturmak için symlink fonksiyonu kullanılır.


int symlink(const char *actualpath, const char *sympath);
Fonksiyon başarılıysa 0 değerine, başarısızsa –1 değerine geri döner.
Dosyanın Tarih ve Zaman Bilgileri
Bir dosyanın ya da dizinin tarih/zaman bilgisi olarak stat ya da lstat fonksiyonu ile üç tür bilgi
çekilmektedir.


st_atime
st_mtime
st_ctime
st_atime dosyanın data bilgilerine son erişim zamanını belirtir. Yani dosya üzerinde herhangi
bir read ya da write işlemi yapıldığında bu değer değişir.


st_mtime dosyanın datalarında yapılan son değişiklik zamanını verir. Yani dosyaya write
işlemi uygulandığında bu bilgi güncellenir.


st_ctime dosyanın dataları üzerinde değil, i-node bilgileri üzerinde değişiklik yapıldığında
güncellenir. Örneğin dosyanın dataları üzerinde işlem yapmayıp yalnızca i-node ile ilgili
işlem yapan link fonksiyonu, utime fonksiyonu bu zaman bilgisini günceller.
i-node bilgilerine erişim ile ilgili özel bir bilgiye gerek duyulmamıştır.


Dosya Erişim Haklarının Değiştirilmesi


chmod fonksiyonu bir dosyanın erişim haklarını değiştirmek için kullanılır. Ancak dosyanın
erişim haklarının değiştirilebilmesi için bu fonksiyonu çağıran process’in etkin kullanıcı
ID’sinin root ya da değiştirilecek dosyanın kullanıcı ID’si ile aynı olması gerekir.
int chmod(const char *path, mode_t mode);


Fonksiyonun birinci parametresi değiştirilecek dosyanın ismi, ikinci parametresi ise yeni
erişim bilgileridir. Fonksiyon başarılı ise 0 değerine, başarısızsa –1 değerine geri döner.
Dosyanın erişim bilgilerini değiştirmek için chmod isimli shell komutu da kullanılabilir.
chmod 666 a.dat ¿


password ve group Dosyaları Üzerinde İşlemler
Önceden de belirtildiği gibi geleneksel olarak UNIX/Linux sistemlerinde yaratılan bir
kullanıcıya ilişkin pek çok değerli bilgi bir password dosyasında saklanır. Geleneksel olarak
password dosyası /etc/passwd ismi ile bulunur ve geleneksel olarak bu dosya text tabanlı bir
dosyadır. POSIX standartlarında password dosyasının genel yapısı belirtilmemiştir. Yalnızca
olması gereken minimum bilgilerden bahsedilmiştir. Ancak klasik olarak password dosyası
her bir satırın 7 parçadan oluştuğu kayıtlar halindedir. Her satırdaki 7 parça birbirlerinden ‘:’
ile ayrılmıştır. Örneğin “a:b:c:d:e:f:g” gibi. password dosyasının 7 bölümü genellikle
şunlardır:


1) Kullanıcı ismi: Kullanıcı giriş ismi


2) Şifrelenmiş password bilgisi: Yeni kullanıcı yaratılırken bu bölüm boş geçilebilir.
Bazı sistemlerde burada x harfi varsa şifrelenmiş password bilgisinin başka bir dosyada
olduğu anlamına gelir (geleneksel olarak /etc/shadow).


3) Kullanıcı ID değeri: Sistemin kullanıcıları tespit etmek için gerçek kullandığı değer
kullanıcı ID değeridir. Kullanıcının ismi okunabilirlik amacıyla düşünülmüştür. Örneğin stat
fonksiyonundan elde edilen değer dosyanın kullanıcı ID değeridir. Kullanıcının ID değeri
bilindiğinde kullanıcının ismini elde edebilmek için passwd dosyasına başvurmak gerekir. Bu
bilgi başka bir biçimde elde edilemez. Tipik olarak ls komutu dizin içerisindeki dosyaların
isimlerini readdir fonksiyonu ile alır, bu isimler ile stat fonksiyonunu çağırır, struct stat
yapısından kullanıcı ID değerini elde eder, sonra passwd dosyasına başvurarak kullanıcı
ismini elde eder ve listeleme işleminde bu ismi kullanır.


4) Grup ID değeri: Her kullanıcı bir gruba ilişkin olur, gruplar da sistem tarafından ID
değerleri ile kullanılırlar. Bu kısımda kullanıcının ilişkin olduğu grubun ID değeri
bulunmaktadır. Grup ID değeri bilindiğinde grubun ismi group dosyasından elde edilir.


5) Açıklama bilgisi: Bu bölüm tamamen açıklama bilgisi içerir.


6) cwd: Bu bölümde çalıştırılacak olan shell process’inin varsayılan dizini belirtilir. Bir
kullanıcı yaratıldığında genellikle buradaki bilgi /home/kullanıcı ismi biçimindedir. Yani
geleneksel olarak her kullanıcının bir ismi vardır, bu isim de /home dizininin altında bir dizine
karşılık gelir. Aslında teknik olarak buradaki bilgi shell process’inin varsayılan dizin (current
working directory) bilgisidir. Aslında varsayılan dizin kavramı kullanıcıya özgü bir kavram
değil, process’e özgü bir kavramdır. login programı 7. bölümde belirtilen shell programını
çalıştırır ve shell process’inin geçerli dizinini burada belirtilen dizin yapar. Yani kullanıcı
shell programına düştüğünde o andaki geçerli dizin bu bölümde belirtilen dizin olacaktır.
UNIX/Linux sistemlerinde process’in geçerli dizini fork işlemi sırasında yeni yaratılan
process’e doğrudan geçirilmektedir.


7) shell: Burada login programının çalıştıracağı shell programının path ismi
belirtilmektedir (Sisteme login olunduğunda bir shell programının çalıştırılması zorunlu
değildir).


login Programı Ne Yapar?
login programı tipik olarak şunları yapar:


1) Kullanıcı ismi ve password sorma işlemini yapar.


2) /etc/passwd ve /etc/shadow dosyalarına başvurarak doğruluğunu araştırır.


3) password doğruysa passwd dosyasında yedinci bölümde bulunan shell process’ini
çalıştırır.


4) shell process’inin kullanıcı ID değerini kullanıcının ID değeri olarak, grup ID değerini
kullanıcının ilişkin olduğu grup ID değeri olarak, geçerli dizin bilgisini passwd dosyasında
belirtilen 6. bölüm olarak oluşturur.


5) shell üzerinden bir program çalıştırıldığında bu bilgiler çalıştırılan programa
aktarıldığından çalıştırılan process’in kullanıcı ID değeri, grup ID değeri ve geçerli dizini aynı
olacaktır.


Process’in Geçerli Dizini
Geçerli dizin process’e özgü bir bilgidir ve process tablosunda tutulur. Bu bilgi default olarak
fork işlemi sırasında, yani bir process’in çalıştırılması işleminde process’i çalıştıran
process’ten default olarak aktarılmaktadır. Yani shell’den bir program çalıştırdığımızda o
programın geçerli dizini default olarak shell process’ininki olacaktır, shell’inki de passwd
dosyasından alınarak belirlenmektedir. Aslında bir dizinde olmak gibi bir kavram yoktur.
shell programları process’in geçerli dizinini sanki bir dizin içerisindeymiş gibi
göstermektedir. shell üzerinden cd işlemi uygulandığında aslında shell programı chdir sistem
fonksiyonu ile process’in geçerli dizinini değiştirir, sonra bunu bir prompt eşliğinde
kullanıcıya gösterir.


passwd Dosyası Üzerinde İşlemler

password dosyalarının genel formatı sistemden sisteme değişebilmektedir. Programcı
password dosyası içerisinden bilgi almak isteyebilir. Örneğin bir dosyanın kullanıcı ID’si
bellidir (örneğin lstat fonksiyonu ile alınmıştır). Programcı kullanıcı ID’si yerine dosyanın
kullanıcı ismini yazdırmak isteyebilir. Bu durumda password dosyasına başvurmak
zorundadır. Pek çok UNIX/Linux sisteminde password dosyaları yukarıda belirtilen text
formatına sahiptir. Ancak POSIX standartlarında bunun bir garantisi yoktur, bu nedenle
password dosyası ile ilgili çeşitli işlemleri yapan taşınabilir bir grup fonksiyon
bulundurulmuştur.


getpwuid ve getpwnam Fonksiyonları
struct passwd *getpwuid(uid_t uid); //sys/types.h
struct passwd *getpwnam(const char *name);
C ve Sistem Programcıları Derneği 42
Bu fonksiyonlar kullanıcı ID veya kullanıcı ismine göre password dosyasında arama yapar ve
kişinin password bilgilerini struct passwd isimli bir yapı içerisine doldurur. Geri verilen adres
static yerel bir nesnenin adresidir, yani fonksiyon her zaman aynı adresi geri vermektedir.
struct passwd {
char *pw_name;
char *pw_passwd;
uid_t pw_uid;
gid_t pw_gid;
char *pw_gecos;
char *pw_dir;
char *pw_shell;
};


Fonksiyonların prototipleri ve struct passwd yapısı pwd.h başlık dosyası içerisinde
bildirilmiştir.


#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
struct passwd *passi;
if (argc != 2) {
fprintf(stderr, "wrong number f arguments!...\n");
exit(1);
}
passi = getpwnam(argv[1]);
if (passi == NULL) {
fprintf(stderr, "Cannot get password info\n");
exit(1);
}
printf("username: %s\n", passi->pw_name);
printf("user id: %d\n", passi->pw_uid);
printf("Group id: %d\n", passi->pw_gid);
printf("Home directory: %s\n", passi->pw_dir);
printf("Shell prog: %s\n", passi->pw_shell);
return 0;
}


password Dosyasındaki Tüm Kayıtların Elde Edilmesi


password dosyasında tıpkı dizinlerde olduğu gibi gezinilerek tüm kayıtlar elde edilebilir.
Bunun için aşağıdaki 3 POSIX fonksiyonu kullanılır.
void setpwent(void);
struct passwd *getpwent(void);
void endpwent(void);
C ve Sistem Programcıları Derneği 43
Programcı bir kere setpwent fonksiyonu ile başlangıç işlemini yapar, sonra döngü içerisinde
getpwent fonksiyonunu çağırır. En sonunda da endpwent fonksiyonu ile işlemi bitirir.
Örneğin getpwnam fonksiyonu tipik olarak bu fonksiyonlar kullanılarak yazılmıştır. Bu
fonksiyon aşağıdaki gibi yazılabilir.
struct passwd *getpwnam(const char *name)
{
struct passwd *passi;
setpwent();
while((passi = getpwent()) != NULL) {
if (!strcmp(name, passi->pw_name))
break;
}
endpwent();
return passi;
}


group Dosyası Üzerinde İşlemler


Normal olarak her kullanıcının gerçek tek bir grubu vardır. Bir kullanıcının hangi gruba
ilişkin olduğu passwd dosyasında grubun ID değeri ile bulunmaktadır. Zaten struct passwd
yapısında bu bilgi de bulunmaktadır. Gruplar hakkındaki bilgiler (örneğin grupların isimleri,
gruplar içerisinde hangi kullanıcıların bulunduğu, grubun password bilgisi gibi) tipik olarak
bir grup dosyasında tutulur. Tipik olarak UNIX/Linux sistemlerinde bu dosya /etc/group
dosyasıdır. Grup dosyası tipik olarak grup ismi, ID değeri, grup password’ü ve o grupta hangi
kullanıcıların olduğunu belirten bilgilerden oluşur. Bu dosya da tipik olarak her bir kayıt bir
satırda olacak biçimde text formatındadır. Grup dosyasında tek tek satırlar incelenerek bir
kişinin ek olarak hangi gruplarda bulunduğu da tespit edilebilir. Bir kişinin gerçek grubu bir
tanedir ve password dosyasında belirtilir.
Tıpkı password dosyasında olduğu gibi grup dosyası üzerinde de arama bulma işlemleri yapan
fonksiyonlar vardır.
struct group *getgrgid(gdi_t gid);
struct group *getgrnam(const char *name);
Fonksiyonlar “grp.h” başlık dosyası içerisinde bildirilmiştir. Bunların yanı sıra grup dosyasını
dolaşan aşağıdaki fonksiyonlar da vardır.
void setgrent(void);
struct *getgrent(void);
void endgrent(void);

Bilgisayar Dershanesi Ders Sahibi;
Bilgisayar Dershanesi

Yorumlar

Yorum Yapabilmek İçin Üye Girişi Yapmanız Gerekmektedir.

ETİKETLER