Основы linux кодинга. Часть 1.

Discussion in 'Безопасность и Анонимность' started by --StraNger--, 25 Jun 2009.

  1. --StraNger--

    --StraNger-- Member

    Joined:
    4 Jan 2009
    Messages:
    63
    Likes Received:
    57
    Reputations:
    5
    Основы *NIX кодинга. Часть 1.

    Основы *NIX кодинга. Часть 1.

    Привет всем.
    Цель данной статьи рассказать читателям об основах linux программирования с помощью системных вызовов.
    В качестве инструментов нам понадобится gcc и make. Они входят в поставку большинства дистрибутивов, ниже я опишу их.


    Инструменты.

    Перед тем как начать программировать, стоит разобрать, что нам поможет в этом.
    Для начала компилятор gcc(GNU project C Compiler):
    Пример простейшего использования:
    Code:
    $gcc /proga.c -o /prog
    
    или так:
    Code:
    $gcc -o /prog /proga.c 
    
    Ключ -o указываем имя и путь к будущему бинарнику
    Если в исходном тексте есть ошибки, то умный компилятор укажет на них.
    Маны:
    http://www.linuxcenter.ru/lib/books/linuxdev/linuxdev1.phtml
    http://skif.bas-net.by/bsuir/prog_in_linux/node3.html

    Make - программа может состоять из множества файлов, которые нужно как то собрать в один. Если файлов мало то можно собрать использую только gcc, но файлов может быть очень много. Именно для таких случаев и применяем сборщик Make. Для ее работы необходимо использовать makefile - специальные файлы со сценарием сборки.
    Что бы лучше понять эти сценарии давайте попробуем собрать программу, состоящую из двух частей с помощью gcc:
    У нас есть файл main.c и modul.c:
    Code:
    		   $gcc - -c main.c
    		   $gcc - -c modul.c
    
    Тут мы указали ключ -c, он означает, что нужно собрать объектный файл, это еще не является полноценной программой, ее мы соберем дальше:
    Code:
    		   $ gcc -o programm main.o modul.c
    
    Теперь мы собрали бинарник из двух файлов.
    Итак, вернемся к make, как я уже говорил файлов для сборки может быть очень много, поэтому используем makefile. Попробуем сделать его самим:
    Code:
         hello: 
    	     main.o programm.o
    	     gcc -o programm main.o modul.o
    
         main.o: 
                 main.c
    	     gcc -c main.c
    
         modul.o: 
                 modul.c
    	      gcc -c modul.c
    
          clean:
    	       rm -f *.o programm
    				  
    Думаю все ясно. Мы выполняем почти те же действия, что и выше, но уже автоматически. В разделе Clean мы отчищаем директорию от временных файлов. Да, и не забываем про знаки табуляции, они очень важны

    Вот мануал для самостоятельного изучения
    http://www.linuxrsp.ru/docs/gm.html

    Тянуть не будем, и перейдем к делу.
    Для начала определимся, что такое системный вызов:
    Системный вызов это обращение, какой либо прикладной программы к ядру ОС, для выполнения какой либо операции.

    Первым, как думаю самым несложным, мы разберем работу с файлами.

    Общее представление о работе с файлами.


    Для работы с файлами в linux существуют вызовы open, creat, write, read. Думаю, смысл их ясен. Разберем, как они работают.
    Code:
    open(char *filename, int mode);
    
    Во-первых, функция возвращает -1 при ошибке. Если все нормально, то возвращает дескриптор файла.
    char *filename - имя/путь файла
    int mode - режим, с которым нужно открыть, т.е. что нужно делать с файлом - читать, писать или читать и писать (=\)
    O_RDONLY - чтение
    O_WRONLY - запись
    O_RDWR - чтение и запись
    Для использования этой функции нужно подключить модуль fcntl.h

    Пример:
    Code:
    -----
    -----
    [COLOR=Lime]open("/var/log",O_RDONLY);[/COLOR]
    -----
    -----
    
    Code:
    read(int d, char *buf, size_t countb)
    
    Аналогично предыдущей функции возвращается -1 при ошибке, а если ошибок нет то целое число.
    int d - источник, т.е. дескриптор, т.е. результат выполнения функции open.
    ichar *buf - место, куда будут считаны данные.
    size_t countb - ну и кол-во байт, которые нужно считать.
    Для использование подключаем модуль unistd.h

    Пример
    Code:
    -------
    -------
    [COLOR=Lime]
    int d=open('/var/log/',RDONLY);
    char *buf;
    size_t count b=1024;
    read(d,buf,countb)[/COLOR]
    -------
    -------
    
    Code:
    creat(char *name, mode_t right)[/COLOR]
    
    char *name - имя создаваемого файла
    mode_t right - права на доступ
    При ошибке -1.
    Для работы подключаем модуль fcntl.h

    Пример
    Code:
    -------
    -------
    [COLOR=Lime]creat("/home/stranger/myfile",754)[/COLOR]
    -------
    -------
    
    Code:
    write(int d, char *buff,size_ size);
    

    int d – дескриптор файла для записи
    char *buff – сами данные которые нужно записать
    size_ size – кол-во байт при записи
    -1 при ошибке, для использования подключаем unistd.h

    И в конце стоит сказать про -
    Code:
    close(int d);
    
    Единственный аргумент, который нужно передать функции, это дескриптор открытого файла. И функция закрывает файл.


    Ну что ж пришло время написать полноценный пример.
    Начнем с простенькой программы для копирования файлов.
    В качестве аргументов она будет принимать имя/путь исходного файла и имя/путь
    скопированного файла.
    Значит сначала открываем исходный файл (open) и считываем его(read). Далее создаем файл (create) и записываем в него считанный первый файл (write).
    Code:
    [COLOR=Lime]#include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #define BUF 1024
    main(int argc, char *argv[])
    
    {
    int in,out,chars;
    char buffer[BUF];
    if(argc!=3)
    {
    printf("Вы ошиблись в вводе аргументов\n");
    exit(1);
    }
    if((in=open(argv[1],O_RDONLY))==-1)
    {
    printf("Ошибка открытия файла для копирования\n");
    exit(1);
    }
    if((out=creat(argv[2],755))==-1)
    {
    printf("Ошибка при создании нового файла");
    exit(1);
    }
    while((chars=read(in,buffer,1024))>0)
    write(out,buffer,1024);
    }[/COLOR]
    
    Замечу, что новый файл мы создали с правами 755, что означает rwxr-xr-x. Можно было бы принять эти данные от пользователя.
    Теперь я расскажу о таком вызовы как: stat.
    Он возвращает нам информацию о файле.
    Code:
    [COLOR=Lime]int i=stat(chat *name, struct stat *buff);[/COLOR]
    
    chat *name – имя файла
    struct stat *buff – структура типа stat, в ней будет храниться информация о файле.

    Какие поля есть у это структуры?:
    Code:
    st_mode - тип, права доступа.
    st_atime - время последнего доступа.
    st_size - размер.
    st_uid - юид юзера.
    st_gid - идентификатор группы пользователей
    st_mtime — время последней модификации файла
    st_atime — время последнего доступа
    
    Для этого вызова нужно использовать библиотеку sys/stat.h
    Давайте напишем пример, который будет выводить информацию о заданном файле:
    Code:
    [COLOR=Lime]#include <stdlib.h>
    #include <stdio.h>
    #include <sys/stat.h>
    int main(int ac,char *ag[])
    {
    struct stat buffer; 
    int r;
    if(ac!=2) 
    {
    printf("Пожалуйста введите необходимые аргументы\n");
    exit(1);
    }
    if((r=stat(ag[1],&buffer))==-1)
    {
    printf("Файл не найден\n");
    exit(1);
    }
    printf("Размер файла: %o\n",buffer.st_size);
    printf("Права доступа к файлу: %d\n ",buffer.st_mode);
    printf("UID: %d\n ",buffer.st_uid);
    printf("GID: %d\n ",buffer.st_gid);
    }[/COLOR]
    
    Изменение статусной информации файла.

    Мы уже разобрали несколько операций с файлами. Теперь давайте поговорим об изменении информации о файле. А это – имя, gid, uid, и т.п.
    Вообще для этих целей существуют специальные вызовы (разберем ниже), но их использовать необязательно.
    Приведу пример, нужно изменить uid файла. Для этого используем всю туже структуру stat, но теперь не считываем информацию, а записываем ее. Пример.
    Code:
    	
    ------
    ------
    [COLOR=Lime]
    buffer.st_uid=0644;
    [/COLOR]
    ------
    ------
    
    А вот такой пример изменяет uid файла на наш собственный.
    Code:
    	
    ------
    ------
    [COLOR=Lime]buffer.st_uid=getuid();[/COLOR]
    ------
    ------
    
    Прокомментирую что getuid() возвращает юид текущего юзера.

    Вот такой пример проверяет рут вы или нет:
    Code:
    [COLOR=Lime]If(getuid()!=0)
    Printf(“Вы не рут, курите дальше»)
    Else
    Printf(«Похоже вы порутили этот сервер =)»);[/COLOR]
    
    Выше упоминалось, что существуют специальные функции для изменения статусной информации о файле. Разберем их:
    Меняем имя файла
    Code:
    Rename(char *oldname, char *newname);
    
    char *oldname – старое имя
    char *newname – новое имя
    Для использования подключаем stdio.h
    Пример:
    Code:
    ------
    ------
    [COLOR=Lime]rename(“/dvu”,/home/stranger/jd”);[/COLOR]
    ------
    ------
    
    Меняем права доступа к файлу.
    Code:
    chmod(char *namefile, mode_t mode);
    
    char *namefile – путь и имя файла
    mode_t modeновые права для файла.

    Для испольвания подключаем sys/types.h, sys/stat.h
    Пример
    Code:
    -------
    -------
    [COLOR=Lime]chmod(“/sploit.c”,755);[/COLOR]
    -------
    -------
    
    Изменяем uid,gid:
    Code:
    chown(char *filename,uid_t uid,gid_t gid);
    
    char *filename – путь и имы файла
    uid_t uid[ новые юид
    gid_t gid новый gid
    Можно указать только uid или только gid.
    Для использоания подключаем unistd.h
    Пример:
    Code:
    -------
    -------
    [COLOR=Lime]chown(“/jaga”,0,11);[/COLOR]
    -------
    -------
    
    Побайтное смещение.
    Напоследок разберем одну функцию – lseek
    она изменят текущую позицию в файле
    Code:
    lseek(int d,off_t di,int base);
    
    int d – дескриптор файла
    off_t di - смещение в байтах
    int base – позиция.
    Позиции бывают такие:
    Code:
    SEEK_SET – от начала файла
    SEEK_CUR -  от текущей позиции
    SEEK_END – от конца файла
    
    Напишем пример, который добавляет строку в конец текстового файла
    Code:
    [COLOR=Lime]#include <unistd.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <stdio.h>
    int main()
    {
    int r;
    r=open("/home/stranger/hell.txt",O_RDWR);
    lseek(r,0,SEEK_END);
    write(r,"hello man!",sizeof("hello man!"));
    close(r);
    }[/COLOR]
    
    OUTRO
    На этом пока все. Если статья будет актуальна, то продолжу писать.
    Как дополнительный материал могу дать вам статью Ричарда Столлмена “Проект GNU”
    http://www.gnu.org/gnu/thegnuproject.html
    – исходный текст английский, но снизу страницы можно найти перевод
    Удачи!
    StraNger/2009
     
    #1 --StraNger--, 25 Jun 2009
    Last edited: 27 Jun 2009
    9 people like this.
  2. m1lo

    m1lo Banned

    Joined:
    30 May 2009
    Messages:
    154
    Likes Received:
    5
    Reputations:
    0
    Респект за статью) я так понимаю пишем на чистом си не привязываясь к оболочке( кеды гном)
    вообщем жду с нетерпением продолжения!! пасиб ++
     
  3. viliam

    viliam Member

    Joined:
    8 Jun 2009
    Messages:
    15
    Likes Received:
    13
    Reputations:
    0
    Хорошая статейка..... продолжайте.
     
  4. razb

    razb Active Member

    Joined:
    24 Mar 2009
    Messages:
    658
    Likes Received:
    133
    Reputations:
    18
    Вообще не стоит привязываться к сис. вызовам, а лучше юзать обертки над ними, тк в разных системах они могут различаться противореча тому что гласят стандарты POSIX.
     
  5. zythar

    zythar Elder - Старейшина

    Joined:
    16 Feb 2008
    Messages:
    517
    Likes Received:
    109
    Reputations:
    5
    насколько позволяют судить мне мои познания в С, это неправильный код.
    дальше. и read и write возврящают не просто целое число, а количество байтов, которые были прочитаны/написаны. при read-e 0, если конец файла.
    просмотрел доконца. нормально, но не вижу смысл статьи.
     
    #5 zythar, 27 Jun 2009
    Last edited: 27 Jun 2009
  6. --StraNger--

    --StraNger-- Member

    Joined:
    4 Jan 2009
    Messages:
    63
    Likes Received:
    57
    Reputations:
    5
    исправил.
    думаю писать дальше или нет...
    вобще в следущей части хотел еще рассказать про Autotools
     
  7. H1Z

    H1Z Elder - Старейшина

    Joined:
    23 Mar 2007
    Messages:
    103
    Likes Received:
    61
    Reputations:
    6
    напиши про toolchain(binutils,gcc,glibc), вот тогда будет +. Но опять же не копипаст, а свою статью. И подробней о gcc, т.е. его опции, ключи компиляции и т.д. так же и о дебагере gdb. вот тут как раз новички и скажут спасибо =)
     
    #7 H1Z, 27 Jun 2009
    Last edited: 27 Jun 2009
  8. X-3

    X-3 Member

    Joined:
    28 Mar 2009
    Messages:
    306
    Likes Received:
    58
    Reputations:
    -2
    Некоторые моменты показались мне интересными, возможно, за счет доступности описания, возможно, за счет структуры, не знаю, вроде ничего необычного, но читается легко. Что бы хотел порекомендовать - использовать более точные термины, например, компиляция, линковка вместо "собираем такой-то файл". Мы не за партой, академическим языком не стоит злоупотреблять, а в простой манере пояснить какой-либо процесс грамотным языком будет полезно и для читателя и для автора.