Національний університет «Львівська політехніка»
Інститут комп’ютерних технологій, автоматики та метрології
ІКТА
Кафедра БІТ
Звіт
Лабораторна робота № 3
«Системні виклики та робота з файлами в ОС Linux»
Варіант – 14
Львів 2018
Мета роботи
Оволодіти практичними навичками роботи з компілятором GCC та системними викликами в операційній системі Linux. Ознайомитись із механізмом виконання системних викликів, процесом компіляції та побудови виконавчих файлів в ОС Linux.
Теоретичні відомості
1. Знайомство з компілятором GCC
Засобами, традиційно використовуваними для створення програм для відкритих операційних систем, є інструменти розробника GNU. Проект GNU був заснований в 1984 році Річардом Столлманом. Його необхідність була викликана тим, що в той час співпраця між програмістами не обходилась без труднощів, оскільки власники комерційного програмного забезпечення чинили численні перешкоди для такої співпраці. Метою проекту GNU було створення комплекту програмного забезпечення під єдиною ліцензією, яка не допускала б можливості присвоювання кимось ексклюзивних прав на це ПЗ. Частиною цього комплекту і є набір інструментів для розробника, яким ми і будемо користуватися, і який повинен входити в усі дистрибутиви Linux.
Одним з цих інструментів є компілятор GCC. Спочатку ця абревіатура розшифровувалась, як GNU C Compiler. Зараз вона означає - GNU Compiler Collection. Розглянемо створення простої програми за допомогою GCC. За сформованою традицією перша програма буде просто виводити в консолі привітання «Hello world!».
2. Системні виклики
Під терміном «системний виклик» в програмуванні та обчислювальній техніці розуміють звернення прикладної програми до ядра операційної системи (ОС) для виконання будь-якої операції.
Сучасні операційні системи (ОС) передбачають поділ часу між обчислювальними процесами, що виконуються (багатозадачність) і розділення повноважень, що перешкоджає виконуваним програмам звертатися до даних інших програм і обладнання. Ядро ОС виконується в привілейованому режимі роботи процесора. Для виконання міжпроцесної операції або операції, що вимагає доступу до обладнання, програма звертається до ядра, яке, в залежності від повноважень викликає процес, виконує або відмовляє у виконанні такого виклику. З точки зору програміста, системний виклик зазвичай виглядає як виклик підпрограми або функції з системної бібліотеки. Однак системний виклик, як окремий випадок виклику такої функції або підпрограми, слід відрізняти від більш загального звернення до системної бібліотеки, оскільки останнє може і не вимагати виконання привілейованих операцій.
Завдання
Варіант – 14
Створити три файли з кодом на мові С. Два файли з вихідним кодом на мові С, перший повинен містити процедури, що реалізують задане варіантом завдання, а другий функцію main. Третій файл – заголовний (.h). Створити Make-файл, що міститиме правила для створення виконавчого файлу, а також правила clean, install і uninstall.
За допомогою системних викликів у своїй домашній директорії створити дворівневу структуру директорій. У директорії другого рівня створити 2 файли та виконати їх копіювання у директорію першого рівня. Реалізувати обробку помилок, які можуть виникнути в ході роботи програми.
Хід роботи
Використані системні виклики:
mkdir
creat
open
read
write
Текст програми
1. Makefile.
lab3: functions.o lab3.o
gcc functions.o lab3.o -o lab3
functions.o: functions.c functions.h
gcc -c functions.c
lab3.o: lab3.c functions.h
gcc -c lab3.c
clean:
rm -f lab3 functions.o lab3.o
install:
cp lab3 /usr/local/bin/lab3
uninstall:
rm -f /usr/local/bin/lab3
2. functions.h.
int main(int argc, char* argv[]);
int executeTask(char* argv[]);
int createDir(const char* path);
int createFile(const char* path);
int copyFile(const char* src, const char* dest);
3. lab3.c.
#include <stdio.h>
#include "functions.h"
int main(int argc, char* argv[]) {
int res;
if (argc == 5) {
res = executeTask(argv);
} else {
printf("Error! 4 parameters are required: dir1, dir2, file1, file2\n");
res = -1;
}
return res;
}
4. functions.c.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "functions.h"
#define PATH_LENGHT 50
#define FORMAT "%s/%s"
#define BUF_SIZE 4096
#define OUTPUT_MODE 0777
#define TRUE 1
#define PWD "/home/jharvard"
int executeTask(char* argv[]){
int res;
// all paths
char path_dir1[PATH_LENGHT], path_dir2[PATH_LENGHT]; char path_file1[PATH_LENGHT], path_file2[PATH_LENGHT];
char path_copy_file1[PATH_LENGHT], path_copy_file2[PATH_LENGHT];
char* dir1 = argv[1];
char* dir2 = argv[2];
char* file1 = argv[3];
char* file2 = argv[4];
sprintf(path_dir1, FORMAT, PWD, dir1);
sprintf(path_dir2, FORMAT, path_dir1, dir2);
sprintf(path_file1, FORMAT, path_dir2, file1);
sprintf(path_file2, FORMAT, path_dir2, file2);
sprintf(path_copy_file1, FORMAT, path_dir1, file1);
sprintf(path_copy_file2, FORMAT, path_dir1, file2);
errno = 0;
res = createDir(path_dir1);
if (res < 0) {
printf("Something went wrong with createDir(dir1)! %s\n", strerror(errno));
exit(errno);
}
res = createDir(path_dir2);
if (res < 0) {
printf("Something went wrong with createDir(dir2)! %s\n", strerror(errno));
exit(errno);
}
res = createFile(path_file1);
if (res < 0) {
printf("Something went wrong with createFile(file1)! %s\n", strerror(errno));
exit(errno);
}
res = createFile(path_file2);
if (res < 0) {
printf("Something went wrong with createFile(file2)! %s\n", strerror(errno));
exit(errno);
}
res = copyFile(path_file1, path_copy_file1);
if (res < 0) {
printf("Something went wrong with copyFile(path_file1, path_copy_file1)! %s\n", strerror(errno));
exit(errno);
}
res = copyFile(path_file2, path_copy_file2);
if (res < 0) {
printf("Something went wrong with copyFile(path_file2, path_copy_file2)! %s\n", strerror(errno));
exit(errno);
}
return res;
}
int createDir(const char* path) {
int res = mkdir(path, OUTPUT_MODE);
return res;
}
int createFile(const char* path) {
int res = creat(path, OUTPUT_MODE);
return res;
}
int copyFile(const char* src, const char* dest) {
int in_fd, out_fd, rd_count, wt_count;
char buffer[BUF_SIZE];
in_fd = open(src, O_RDONLY);
if (in_fd < 0) {
printf("Something went wrong with open(path_file1, O_RDONLY)! %s\n", strerror(errno));
exit(errno);
}
out_fd = createFile(dest);
if (out_fd < 0) {
printf("Something went wrong with createFile(path_file2)! %s\n", strerror(errno));
exit(errno);
}
while(TRUE) {
rd_count = read(in_fd, buffer, BUF_SIZE);
if (rd_count <= 0) break;
wt_count = write(out_fd, buffer, rd_count);
if (wt_count <= 0) {
printf("Something went wrong with write(out_fd, buffer, rd_count)! %s\n", strerror(errno));
exit(errno);
}
}
close(in_fd);
close(out_fd);
return rd_count;
}
Результати виконання програми
/
/
/
/
Висновок
Оволодів практичними навичками роботи з компілятором GCC та системними викликами в операційній системі Linux. Ознайомився із механізмом виконання системних викликів, процесом компіляції та побудови виконавчих файлів в ОС Linux.