16 Mart 2014 Pazar

Linux Sistem Programlama - Bölüm 3

chown ve fchown Fonksiyonu

#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);

Chown fonksiyonu bir dosyanin sahiplik bilgilerini degistirir. Fonksiyonun prototipi yukaridaki gibidir.
Fonksiyonunlarin birinci parametresi ilfili dosyanin yol ifadesi yada dosya betimleyicisidir. Ikinci parametresi dosyanin yeni sahibinin id'sini, ucuncu parametre de dosyanin yeni grubunun id'sini alir. Ancak root processi bis dosyanin sahiplik bilgisini degistirebilir. Dosyanin sahibinin sahiplik bilgisini yada grup bilgisini degistirebilmesi bazi unix turevi sistemlede mumkundur. Bazilarinda ise degildir. POSIX bunu isletim sisteminin istegine birakmistir. Linux'da default durumda dosyanin sahibi sahipligini baska birisine devredemez. Fakat genel olarak dosyanin sahibi dosyanin grubunu degistirmektedir. Ancak dosyanin sahibi dosyanin grubunu POSIX standartlarina gore herhangi bir grup olarak degistiremez. Kendi etkin grupid'si olarak yada ek gruplarindan biri olarak degistirebilir.

POSIX Standartlarinda degisik baslik dosyalarinda xxx_t biciminde typedef edilmis bazi tur isimleri vardir. BU turlerin gercekte hangi tur olarak typedef edilecegibazi kosullar altinda isletim sistemini yazanlara birakilmistir. Bunlarin hepsi ayrica bir grup olarak /sys/types.h dosyasi icinde tanimlanmistir. Tipik xxx_t turleri sunlardir:
-> mode_tnlink_tuid_tgid_tid_t bir tamsayi olarak typedef edilmek zorundadir.
-> blksize_tpid_tssize_tblkcnt_t ve off_t isaretli tamsayi olacak bicimde typedef edilmek zorundadir.
-> size_t isaretsiz bir tamsayi turu olarak typedef edilmek zorundadir.
-> time_t ve clock_t tam sayi yada gercek sayio turunden typedef edilmek zorundadir.

stat ve fstat fonksiyonlari

Fonksiyonun prototipi su sekildedir.

#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);

Fonksiyonlarin birinci parametreleri bilgisi elde edilecek olan dosyani yol  ifadesini yada betimleyicisini almaktadir. ikinci parametre sys/types.h dosyasinda bildirilmis olan stat isimli bir yapi turunden nesnenin adresini alir. Fonksiyon basari durumunda 0 basarisizlik durumunda -1 degerine geri doner. 
Stat yapisinin icerisinde su bilgiler vardir. 
  • Dosyanin icinde bulundugu aygitin aygit numarasi.
  • Dosyanin inode numarasi
  • Dosyanin erisim bilgileri 
  • Dosyanin userid ve groupid bilgileri 
  • Dosyanin uzunlugu
  • Dosyani son erisim, son degistirilme, son statu degisimine iliskin tarih ve zaman bilgisi
  • Kopyalama gibi islemlerdeki etkin tampon buyuklugu 
  • Bu dosya icin kac disk blogu tahsis edildigi

Bir dosyanin kac bloktan olustugu bilgisi belirtilirken bir blogun kac byte uzunlugunda oldugu sistemden sisteme degisebilmektedir. Block kavrami Linux sistemlerde biraz lastik hale getirilmistir. Stat fonksiyonunda ise block 512 byei temsil eder,. Halbulki baska yarlerde de bloack terimi kullanilmaktadir ve baska uzunlugu gostermektedir. Sonuc olarak linux sistemiinde block terinide karsilasildiginda, o baglamda blogun kac byte dan olustugu bilgisini de edinmek gerekmektedir. 

/*-----------------------------------------------------------------------------------
 stat fonksiyonu
------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>

void exitsys(const char *msg);

int main(int argc, char *argv[])
{
 struct stat finfo;
 struct passwd *pwd;
 struct group *grp;
 struct tm *ftime;

 if (argc != 2) {
  fprintf(stderr, "cannot get stat info\n");
  exit(EXIT_FAILURE);
 }

 if (stat(argv[1], &finfo) < 0)
  exitsys("stat");

 if ((pwd = getpwuid(finfo.st_uid)) == NULL)
  exitsys("getpwuid");
 if ((grp = getgrgid(finfo.st_gid)) == NULL)
  exitsys("getgrgid");

 printf("%s\n", argv[1]);
 printf("User: %s(%lu)\n", pwd->pw_name, (unsigned long) finfo.st_uid);
 printf("Group: %s(%lu)\n", grp->gr_name, (unsigned long) finfo.st_gid);
 printf("Length: %lu\n", (unsigned long) finfo.st_size);
  
 ftime = localtime(&finfo.st_atime);
 printf("Access time: %02d/%02d/%04d %02d:%02d:%02d\n", ftime->tm_mday,
         ftime->tm_mon + 1, ftime->tm_year + 1900,ftime->tm_hour,
         ftime->tm_min, ftime->tm_sec);

 ftime = localtime(&finfo.st_mtime);
 printf("Modification time: %02d/%02d/%04d %02d:%02d:%02d\n", ftime->tm_mday,
         ftime->tm_mon + 1, ftime->tm_year + 1900,
         ftime->tm_hour, ftime->tm_min, ftime->tm_sec);

 ftime = localtime(&finfo.st_ctime);
 printf("Status time: %02d/%02d/%04d %02d:%02d:%02d\n", ftime->tm_mday,
         ftime->tm_mon + 1, ftime->tm_year + 1900,
         ftime->tm_hour, ftime->tm_min, ftime->tm_sec);

 return 0;
}

void exitsys(const char *msg)
{
 perror(msg);
 exit(EXIT_FAILURE);
}

/etc/passwd ve /etc/group dosyalarinin formatlari sistemden sisteme farkli olacilir/ Bilindigi gibi sistemler icsel olarak hep sayilarla calisirlar. Ornegin stat fonksiyonundan elde etmis oldugumuz userid ve groupid degerleri sayisal degerlerdir. Bunlari ancak biz /etc/passwd ve /etc/group dosyalarina bakarak isme donusturebiliriz. Iste bu isi yapan birkac posix fonksiyonu bulundurulmustur.
getpwuid ve getgrgid fonksiyonlari parametre olarak bizden userid ve groupid degerini alir. ve bize passwd ve group isimli yapi adresi ile geri doner. Bu yapilar, /tec/passwd ve /etc/group dosyalarindaki satirlari temsil etmektedir. tipik olarak bu fonksiyonlar sayisal userid ve gruopid degerlerini user ve group isimlerine donusturmek icin kullanilir. Bu islemin tersini yapan yani isimlerden sayi elde edilmesini saglayan getpwnam ve getgrnam fonksiyonlari vardi

geri donus degeri pointer olan fonksiyonlarda hata durrumunda geri donus -1 degil NULL pointerdir. Fonksiyon geri donusunu kontrol etmek icin NULL olup olmadigina bakmamiz omenlidir.

Stat fonksiyonu ile verilen tarihler bize 1.1.1970 tarihinden gecen saniye sayisi olarak verilmektedir. Stat yapisinin icerisinde erisim haklari st_mode icerisine bit bit kodlanmistir. Buradan dosyanin turunu almak icin s_isxxx biciminde makrolar bulundurulmustur. ayrica ilgili hakkin olup olmadigini anlamak icin daha once gorulmus olan S_IXXXX sembolik sabitleri ile bit end islem olusturmak gerekir.

/*------------------------------------------------------------------------------------
 dosya bilgilerinin ls -l tarzýnda elde edilmesi
-------------------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>

void exitsys(const char *msg);
char *getls(const char *path, const struct stat *finfo);

int main(int argc, char *argv[])
{
 struct stat finfo;

 if (argc != 2) {
  fprintf(stderr, "cannot get stat info\n");
  exit(EXIT_FAILURE);
 }

 if (stat(argv[1], &finfo) < 0)
  exitsys("stat");

 puts(getls(argv[1], &finfo));

 return 0;
}

char *getls(const char *path, const struct stat *finfo)
{
 char static buf[4096];
 int index;
 int i;
 int aflags[] = {S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP,
                     S_IROTH, S_IWOTH, S_IXOTH};
 char *rights = "rwx";
 struct passwd *pwd;
 struct group *grp;
 char *months[] = {"Oca", "Þub", "Mar", "Nis", "May", "Haz", "Tem", "Aðu", "Eyl", "Eki",
                     "Kas", "Ara"};
 struct tm *ftime;

 index = 0;
 if (S_ISREG(finfo->st_mode))
  buf[index] = '-';
 else if (S_ISDIR(finfo->st_mode))
  buf[index] = 'd';
 else if (S_ISCHR(finfo->st_mode))
  buf[index] = 'c';
 else if (S_ISBLK(finfo->st_mode))
  buf[index] = 'b';
 else if (S_ISFIFO(finfo->st_mode))
  buf[index] = 'p';
 else if (S_ISLNK(finfo->st_mode))
  buf[index] = 'l';
 else if (S_ISSOCK(finfo->st_mode))
  buf[index] = 's';

 ++index;

 for (i = 0; i < 9; ++i)
  buf[index++] = (finfo->st_mode & aflags[i]) ? rights[i % 3] : '-';
 buf[index++] = ' ';

 index += sprintf(&buf[index], "%lu", (unsigned long) finfo->st_nlink);
 buf[index++] = ' ';

 if ((pwd = getpwuid(finfo->st_uid)) == NULL)
  index += sprintf(&buf[index], "%lu", (unsigned long) finfo->st_uid);
 else
  index += sprintf(&buf[index], "%s", pwd->pw_name);
 buf[index++] = ' ';

 if ((grp = getgrgid(finfo->st_gid)) == NULL)
  index += sprintf(&buf[index], "%lu", (unsigned long) finfo->st_gid);
 else
  index += sprintf(&buf[index], "%s", grp->gr_name);
 buf[index++] = ' ';

 index += sprintf(&buf[index], "%ld", (long) finfo->st_size);
 buf[index++] = ' ';

 ftime = localtime(&finfo->st_mtime);
 index += sprintf(&buf[index], "%s %d %02d:%02d %s", months[ftime->tm_mon],
             ftime->tm_mday,ftime->tm_hour, ftime->tm_min, path);

 buf[index] = '\0';

 return buf;
}

void exitsys(const char *msg)
{
 perror(msg);
 exit(EXIT_FAILURE);
}

Dizin icindeki dosyalarin ele gecirilmesi
Bir dizin icerisindeki dosyalarin elde edilmesi su sekilde yapilir. 
Dizin opendir fonksiyonu ile acilir. Fonksiyon basari durumunda DIR isimli bir yapi turunden handle gorevi yapa bir adres verir.basarisizlik durumunde NULL adres verir.

#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);

Readdir isimli fonksiyon her cagirildiginda bize siradaki dosyanin isminin ve inode numarasinin bulundugu dirent isimli bir yapinn adresini verir. Dizinin sonuna gelindiginde fonksiyon NULL adres verir.

#include <dirent.h>
struct dirent *readdir(DIR *dirp);

Nihayet acilmis olan dizin closedir fonksiyonu ile kapatilir.

#include <dirent.h>
int closedir(DIR *dirp);

bir onceki konuda yapilan ls komutu ornegini dizindeki dosyalar icin yapilandiralim

/*---------------------------------------------------------------------------------
 Dizin içerisindeki dosyalarýn elde edilmesi
----------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>

void exitsys(const char *msg);
char *getls(const char *path);

int main(int argc, char *argv[])
{
 struct stat finfo;
 DIR *dir;
 struct dirent *dire;
 char path[1024];

 if (argc != 2) {
  fprintf(stderr, "wrong number of arguments\n");
  exit(EXIT_FAILURE);
 }

 if ((dir = opendir(argv[1])) == NULL)
  exitsys("opendir");

 while ((dire = readdir(dir)) != NULL) {
  sprintf(path, "%s/%s", argv[1], dire->d_name);
  printf("%s\n", getls(path));
 }
  
 closedir(dir);

 return 0;
}

char *getls(const char *path)
{
 char static buf[4096];
 struct stat finfo;
 int index;
 int i;
 int aflags[] = {S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP,
                     S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH};
 char *rights = "rwx";
 struct passwd *pwd;
 struct group *grp;
 char *months[] = {"Oca", "Þub", "Mar", "Nis", "May", "Haz",
                     "Tem", "Aðu", "Eyl", "Eki", "Kas", "Ara"};
 struct tm *ftime;
 char *fname;

 if (stat(path, &finfo) < 0)
  return NULL;
  
 if ((fname = strrchr(path, '/')) == NULL)
  return NULL;

 index = 0;
 if (S_ISREG(finfo.st_mode))
  buf[index] = '-';
 else if (S_ISDIR(finfo.st_mode))
  buf[index] = 'd';
 else if (S_ISCHR(finfo.st_mode))
  buf[index] = 'c';
 else if (S_ISBLK(finfo.st_mode))
  buf[index] = 'b';
 else if (S_ISFIFO(finfo.st_mode))
  buf[index] = 'p';
 else if (S_ISLNK(finfo.st_mode))
  buf[index] = 'l';
 else if (S_ISSOCK(finfo.st_mode))
  buf[index] = 's';

 ++index;

 for (i = 0; i < 9; ++i)
  buf[index++] = (finfo.st_mode & aflags[i]) ? rights[i % 3] : '-';
 buf[index++] = ' ';

 index += sprintf(&buf[index], "%lu", (unsigned long) finfo.st_nlink);
 buf[index++] = ' ';

 if ((pwd = getpwuid(finfo.st_uid)) == NULL)
  index += sprintf(&buf[index], "%lu", (unsigned long) finfo.st_uid);
 else
  index += sprintf(&buf[index], "%s", pwd->pw_name);
 buf[index++] = ' ';

 if ((grp = getgrgid(finfo.st_gid)) == NULL)
  index += sprintf(&buf[index], "%lu", (unsigned long) finfo.st_gid);
 else
  index += sprintf(&buf[index], "%s", grp->gr_name);
 buf[index++] = ' ';

 index += sprintf(&buf[index], "%ld", (long) finfo.st_size);
 buf[index++] = ' ';

 ftime = localtime(&finfo.st_mtime);
 index += sprintf(&buf[index], "%s %d %02d:%02d %s", months[ftime->tm_mon],
                     ftime->tm_mday,
      ftime->tm_hour, ftime->tm_min, fname + 1);

 buf[index] = '\0';

 return buf;
}

void exitsys(const char *msg)
{
 perror(msg);
 exit(EXIT_FAILURE);
}

Recursive olarak bir dizin icindeki bilgilerin elde edilmesi

Dizin agacini dolasabilmek icin ozyinelemeli (recursive) bir dolasim gerekmektedir. Tipik islem su sekilde yapilir.Kok dizinden dosyalar bulunarak ilerlenir. Bulunan dosyanin normal bir dosya mi yoksa bir dizin dosyasi mi olduguna bakilir.  Eger Bir dosya dizin dosyasi ise chdir fonksiyonu ile prosesin calisma dizini degistirilip fonksiyonun kendisini cagirmasi saglanir. Dizin bittiginde yine chdir fonksiyonu ile ust dizine gecilir. Her alt dizin icerisinde nokta (.) ve nokta nokta (..) isimli iki dizin otomatik olarak olusturulur. bunlarin dikkate alinmamasi gerekir.

C Programlama icerisinde yer alan recursive algoritmalar konusuna goz alilmasi gerekmektedir.
sdasd

/*-------------------------------------------------------------------------------------
                Dizin agacinin dolasilmasi
-------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>

void exitsys(const char *msg);
void walktree(const char *path);

int main(int argc, char *argv[])
{
                if (argc != 2) {
                               fprintf(stderr, "wrong number of arguments\n");
                               exit(EXIT_FAILURE);
                }
               
                walktree(argv[1]);
               
                return 0;
}

void walktree(const char *dirpath)
{
                struct stat finfo;
                DIR *dir;
                struct dirent *dire;
                char filepath[1024];
                              
                if ((dir = opendir(dirpath)) == NULL) {
                               perror("opendir");
                               return;
                }
               
                while ((dire = readdir(dir)) != NULL) {
                               if (!strcmp(dire->d_name, ".") || !strcmp(dire->d_name, ".."))
                                               continue;
                               sprintf(filepath, "%s/%s", dirpath, dire->d_name);
                               if (lstat(filepath, &finfo) < 0) {
                                               perror("stat");
                                               continue;
                               }
                               printf("%s\n", filepath);
                              
                               if (S_ISDIR(finfo.st_mode))
                                               walktree(filepath);
                }
                                              
                closedir(dir);
}

void exitsys(const char *msg)
{
                perror(msg);
                exit(EXIT_FAILURE);
}

Dosya Baglari (linkleri)

Dosya baglari siki (hard) ve sembolik olmak uzere ikiye ayrilmaktadir. Hard link sisteminin anlasilabilmesi icin diskin metadata formatinin biliniyor olmasi gerekmektedir.
Bir diskte okunabilecek veya yazilabilecek en kucu birim sektordur. Bir sektor varsayilan olarak 512 byte uzunlugundadir. Ancak isletim sistemleri diski sektpor temelinde organize etmek yerine block yada cluster denilen birimler ile organize etmektedir. Bir block yada Cluster ardisil n sektorden olusmaktadir. Bu sektorun sayisi formatlarken belirlenir. Bir block yada cluster bis dosyanin parcasi olabilen en kucuk birimdir(ornegin 1 byte uzunlugunda bir dosya olusturacak olsak sistemda bu dosya icin 1 block yer ayrilir). Bir volumu ext2, ext3 gibi inode tabanli bir dosya sistemi ile formatlarsak kabaca diskte 3 bolum olusturulur. Bunlar super blockinode blockdata block bolumleridir.
Super Blok, bolumlerin yerlerini uzunluklarini vesaire tutan bir blogun kaz sektorden olustugunu tutan bolumdur. Volume'nin kalbidir. 
Inode block, inode elemanlarindan olusur. Her inode elemanina 0'dan baslayarak bir sira  numarasi karsilik dusurulmustur. Bir dosyanin butun bigileri, yani stat fonksiyonu ile aldigimiz bilgiler inode elemaninda tutulur. Bir dosya yaratildiginda onun icin bir inode elemani olusturulur. Yani her dosyanin bir inode elemani vardir. Dizinler de birer dosya gibidir. Onlar icin de birer inode elemani vardir. BIr dosyanin inode numarasi demek o dosyanin bilgilerinin inode blogunun kacinci inode elemaninda saklandigi demekdir. dosyanin inode numarasi ls -i ile goruntulenmektedi
0 Numarali inode elemani kok dizinin elemanidir. Dizinler de dosyalar gibi bir dizin dosyasinin icerisinde dosya ismi ve inode numaralarindan olusan kayitlar vardir. 

 isim 
 inode no
 isim 
 inode no
 isim
 inode no
 ... 
 ...

Diskin data bolumu ilk blok sifirdan baslayacak sekilde bloklarla numaralandirilmistir. Her dosya data bolumu icerisinde bloklara parcalanmis bir bicimde oradaki bloklarda tutulmustur. Bu bloklar ardisil olmak zorunda degildir.  Dosyanin parcalarinin hangi bloklarda oldugu inode elemaninda tutulmaktadir. 
isletim sisteminin dosya sistemi yol ifadelerinden oncelikle bir bir inode elemani elde etmelidir. Cunku dosyani butun kontrol bilgisi inode elemanindadir. Genel olarak bir yol ifadesinden o dosyaya iliskin inode elemaninin elde edilmesi surecine "Pathname resolution" denilmektedir. Pathname resolution su sekilde gerceklestirilir. Ornegin /home/csd/test.dat dosyasina erisilmek istensin;
  1. Sistem 0 numarali inode elemanina gider. Onun bloklarini okur ve orada inode kayitlari vardir. Orada home isminii arar. Bulursa onun inode numarasini elde eder,
  2. Eger bulunan home ismi bir dizin dosyasina iliskinse ve erisim hakki varsa onun inode elemanina gide ve onun da bloklarini okur. Orada csd ismini arar ve onun inode numarasini elde eder.
  3. Artik csd'nin inode elemaninda onun bloklarina bakilarak bu kez orada test.dat aranir. ve nihayet dosyanin bilgisine erisir.

Hardlink nedir?

Hardlink farkli dizin girislerinin ayni inode numarasina sahip olmasidir. Boylece iki farkli yol ifadesiyle pathname resolution yapildiginda aslinda ayni dosyaya erisilmis olur.
Ornegin


Goruldugu gibi /home/kaan/b.dat dizin girisi ile /home/ali/y.dat dizin girisi ayni inode elemanini gostermektedir.

Peki rm gibi bir komutla bu dosyalardan biri silinse ne olur?

Eger dosyanin inode elemani ve inode bloklar free hale getirilirse diger yol ifadesiyle ardik diger dosyaya erisemiyoruz.iste bunun icin inode elemaninda isletimsistemi hardlink sayisini tutar. Dosya silinmeye calisildiginda once dizin girisini siler. Sonra dosyanin inode elemanina giderek oradaki hardlink sayacini 1 eksiltir. Eger sayac sifira duserse dosyanin inode numarasini ve o inoda bagli data bloklarini siler(metadata alanlari silinmis gibi gosterilir).
Inode tabanli dosya sistemlerinde ayrica hangi inode elemanlarinin  bos oldugu ve hangi data bloklarinin bos oldugu disk uzerinde bir yerlerde tutulmalidir. Suphesiz her blok yada inode elemani icin 1 bit yeterlidir. Ornegin ext2 dosya sisteminde bu bilgiler hemen superblok'tan asonra block bitmap ve inode bitmap isimleri ile tutulurlar.


Hiç yorum yok:

Yorum Gönder