Sistema Operatiu Linux
Unitat: Linux com a entorn de programació
Tema: ús de les funcions de baix nivell del sistema (API de 'C')
Introducció a l'ús de funcions del sistema en els programes
'C'
-
Linux ofereix de forma pública accés a les funcions de baix
nivell que formen el propi sistema operatiu. S'anomena API (Aplication
Program Interface) a la interfície entre programes C i les funcions
del sistema. En aquest tema veurem alguns exemples de programes C que utilitzen
l'API de Linux per interactuar amb el sistema operatiu.
-
Quan creem un programa C que usa les funcions del sistema, tenim en les
mans una eina molt potent que ens permet dissenyar noves funcions
i comandaments que poden tenir la mateixa funcionalitat que els comandaments
originals del sistema.
-
Per tant hem arribat a un punt en el qual som capaços de redisenyar
el sistema operatiu, adequant-lo a les nostres necessitats. Direm
que estem fent desenvolupament de funcions en el sistema (crèdit
5 del cicle formatiu Adm. de sistemes informàtics). També
s'utilitza el terme programació de sistemes.
Funcions del sistema de fitxers: open
El primer exemple serà el programa crea.c que permet
crear un fitxer amb uns certs permisos, utilitzant la funció de
l'API de C open:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main(int argc, char *argv[1])
{
open(argv[1],O_WRONLY | O_CREAT | O_TRUNC ,
S_IRWXU);
}
Seguim les següents passes:
1. Introduïr el text del programa en el fitxer crea.c
2. Compilar el programa: $ gcc crea.c -o crea.exe
3. El provem: $./crea.exe fitxer
4. Comprovem: ls -l fitxer
_rwx_ _ _ _ _ _ fitxer
Explicació del programa:
-
Els fitxers #include contenen les declaracions de les funcions, constants
i tipus de dades de l'API de gestió del sistema de fitxers
-
Una de les funcions d'aquesta API és la open que té la següent
sintaxi:
int open(nom_fitxer, mode, permisos)
-
En l'exemple, el nom del fitxer és el paràmetre argv[1]
pasat per l'usuari quan executem el programa crea.exe
-
Els paràmetres que van a continuació del nom del programa
s'anomenen paràmetres en línia del comandament.
-
El mode determina la forma d'accés al fitxer, segons una
taula de posibles valors (constants predefindes en els fitxers #include)
alguns dels quals són:
O_WRONLY : accés en mode de lectura/escriptura
O_CREAT : crear el fitxer
O_TRUNC : si el fitxer ja existeix, aleshores es respecta
(no es crea de nou)
-
Podem combinar les diferents opcions amb l'operador de 'C' OR (barra vertical)
tal com hem fet en l'exemple. Per tan estem obrint el fitxer en lectura/escriptura,
amb creació, i respectant el contingut anterior.
-
Els permisos estableixen els drets d'accés sobre el fitxer per el
propietari, grup del propietari i resta d'usuaris. Hi ha una taula de posibles
valors (constants predefinides), un dels quals és S_IRWXU
que otorga tots els drets (lectura, escriptura i execució) al propietari.
Es poden combinar diferents constants amb l'operador OR de 'C'.
-
La funció open retorna un enter que posteriorment podem usar
per a referenciar el fitxer que hem obert.
-
El programa espera un paràmetre en la línia de comandaments,
que pren com al nom del fitxer a crear. Si no el posem, el programa generarà
un error d'execució.
Altres funcions del sistema de fitxers: mkdir, link
-
La funció mkdir crea un directori. La sintaxi és:
mkdir(char *directori, permisos)
-
Els paràmetres són: directori és una cadena
que conté l'ubicació i nom del directori, i permisos
té el mateix significat que en la funció open.
-
La funció link crea un vincle. La sintaxi és:
link(char *fitxer, char *vincle)
Exercicis:
1. Escriu un programa mdir.c per crear un directori amb
permísos rwx per el propietari. El nom del directori és
un paràmetre en línia del comandament.
2. Escriu un programa mlink.c per crear un vincle. El
nom del fitxer i del vincle són paràmetres en línia
del comandament.
Accés als directoris del sistema de fitxers: funcions opendir, readdir,
closedir
-
El següent exemple és un programa anomenat mils.c que
imita la funcionalitat del comandament ls (mi + ls = mils):
permet visualitzar el contingut d'un directori que li pasem com a paràmetre
en línia. El codi 'C' és el següent:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
main(int argc, char *argv[])
{ DIR *pdir;
struct dirent *dp;
pdir = opendir(argv[1]);
if (pdir == NULL)
{printf("error a l'obrir el directori\n"); exit(1);
}
dp = readdir(pdir);
while (dp != NULL)
{ printf("%s\n", dp ->d_name);
dp = readdir(pdir);
}
closedir(pdir);
exit(0);
}
Comentaris:
1. El tipus de dades DIR i l'estructura dirent
estan definides en els fitxers #include i són part de l'API
d'accés a directoris.
2. La funció opendir accepta com a paràmetre
un nom de directori i retorna un punter de tipus DIR que serveix
per referenciar el directori en el programa (els punters que referèncien
objectes del sistema s'anomenen "handles" que significa "manipuladors").
Si la funció no aconsegueix accedir al directori aleshores el punter
queda nul.
3. La funció readdir accepta com a a paràmetre
un "handle" a un directori i retorna la següent entrada del
directori. Si és el primer cop que cridem a readdir retornarà
el primer nom del directori, i en les següents crides anirà
retornant els següents noms, fins que arribi al final. El valor retornat
és un punter a una estructura dirent, la qual conté informació
sobre l'element del directori (un fitxer o un subdirectori).
4. El camp d_name de l'estructura dirent conté
el nom de l'element actual del directori.
5. La funció closedir allibera el directori i
els punters que el referèncien.
-
Per provar el programa escriurem: $ ./mils.exe directori
Entrada/Sortida de baix nivell: funcions read, write
-
La funció read llegeix bytes d'un dispositiu en un vector.
La seva sintaxi és:
int read(num_dispositiu, buffer, num_bytes)
-
num_dispositiu és un número que fa referència
al dispositiu d'entrada.
-
buffer és el vector on queden els bytes llegits del dispositiu
-
num_bytes és el nombre de bytes a llegir
-
La funció read retorna un enter amb el número de bytes
que realment ha llegit del dispositiu.
-
La funció write escriu els bytes continguts en un vector
en un dispositiu. La seva sintaxi és:
write(num_dispositiu, buffer, num_bytes)
-
El següent exemple serà el programa micat.c que llegeix
bytes del dispositiu d'entrada estàndard (el teclat) i els copia
en el dispositiu de sortida estàndard (el monitor). El codi és
el següent:
#define N 512 // nombre de bytes a llegir (arbitrari)
main( )
{ char buffer[N];
int n;
while (( n = read(0, buffer, sizeof(buffer)))
> 0 )
write(1, buffer,
n);
exit(0);
}
Prova 1: $ ./micat
El programa anirà repetint tot el que anem escrivint (actúa
com un "eco") fins que trenquem amb CTRL + C
Prova 2: Si redireccionem l'entrada estàndar aleshores
micat fa el mateix que el comandament cat:
$ ./micat < fitxer mostrarà el contingut del fitxer
Prova 3: Si redireccionem l'entrada i la sortida estàndar
micat realitzarà la còpia de fitxers:
$ ./micat < fitxer > fitxer_copia copiarà el fitxer en
fitxer_copia
Accés a les variables d'entorn: funció getenv
-
La funció getenv permet accedir al valor de les variables
de l'entorn. La sintaxi és:
char *getenv(variable)
on variable és el nom de la variable de l'entorn. Retorna
un punter a caràcter (normalment serà una cadena). Si la
variable d'entorn no existeix llavors retorna NULL.
-
El programa veure.c accedeix al valor d'una variable d'entorn anomenada
PROVA que conté un valor numéric enter i escriu "Hola"
tants cops com indiqui aquest valor. El codi és:
#include <stdio.h>
main( )
{ int i;
char *p, *getenv( );
if (( p = getenv("PROVA")) != NULL)
for (i = 0; i < atoi(p); i++) printf("Hola\n");
else printf("la variable PROVA no està definida\n");
Comentaris:
1. La funció atoi realitza la conversió
de cadena a enter (array-to-integer s'abrevia atoi).
2. Per provar el programa doneu valor a la variable PROVA:
$ PROVA=1; export PROVA
$ ./veure.exe
PRÀCTICA
1. Completar l'utilitat mils de forma que controli si l'usuari
ha escrit el nom del directori. Si no informa aquest paràmetre aleshores
mils dóna un missatge d'error i atura l'execució.
2. Modificar el programa de creació de fitxers crea:
consultarà la variable d'entorn GRUP i si val 1 aleshores donarà
com a permisos del fitxer rwx per el propietari i r per el
grup (constant S_IRGRP). Si GRUP no val 1 aleshores només donarà
els permisos rwx al propietari.
3. Convertir el programa mils.c en una funció int
mils(char *direc) i el programa crea.c en un altre funció
int crea(char *fitxer) que aniran en un mateix fitxer utilitats.c
. Compilar aquest fitxer i incloure'l en la biblioteca estàtica
mibiblio.a. Finlement provar les dues noves funcions en algún
programa de prova.