Académique Documents
Professionnel Documents
Culture Documents
Programacn de Sstemas
Pabo Garazar Sagarmnaga
garazar@esde.deusto.es
GNU/Lnux:
Programacn de
Sstemas
Pabo Garazar Sagarmnaga
ema: garazar@esde.deusto.es
web: http://pagnaspersonaes.deusto.es/garazar
bog: http://bog.txpnet.com
Facutad de Ingenera - ESIDE
Unversdad de Deusto
Bbao
Taba de contendo
1. PROGRAMAClON EN GNU}LlNUX...........................................5
1.1 Lamadas a sstema..................................................... .....5
1.2 Programas, procesos, hos............................................. ...6
1.2.1 Estructuras de datos............................................. ..7
1.2.2 Estados de os procesos en Lnux...........................8
1.2.3 Identfcatvos de proceso.......................................9
1.2.4 Panfcacn....................................................... ...11
1.3 E GCC............................................ .................................12
1.3.1 Compacn bsca....................................... ........12
1.3.2 Paso a paso...................................................... .....13
1.3.3 Lbreras................................................... .............14
1.3.4 Optmzacones.....................................................14
1.3.5 Debuggng............................................................15
1.4 make word.............................................................. ........15
1.4.1 Makefe, e gun de make...................................16
1.5 Programando en C para GNU/Lnux.................................20
1.5.1 Hoa, mundo!....................................... .................20
1.5.2 Lamadas sencas............................................ ....21
1.5.3 Mane|o de drectoros...........................................32
1.5.4 |ugando con os permsos.....................................35
1.5.5 Creacn y dupcacn de procesos.....................38
1.5.6 Comuncacn entre procesos..............................43
1.5.7 Comuncacn por red......................................... ..62
2. LlCENClA....................................................................80
ndce de fguras
FlGURA 1.1.1 MECANlSMO DE PETlClON DE SERVlClOS AL KERNEL..........6
FlGURA 1.5.2 LOS DESCRlPTORES DE FlCHERO lNlClALES DE UN PROCESO.
..............................................................................24
FlGURA 1.5.3 DUPLlCAClON DE PROCESOS MEDlANTE FORK().............39
FlGURA 1.5.4 PROCESOS REClBlENDO SEALES, RUTlNAS DE CAPTURA Y
PROCESO DE SEALES.......................................................48
FlGURA 1.5.5 LA LLAMADA A LA FUNClON ALARM() GENERARA UNA SEAL
SlG_ALARM HAClA EL MlSMO PROCESO UE LA lNVOCA...............49
FlGURA 1.5.6 UNA TUBERlA ES UNlDlRECClONAL, COMO LOS TELEFONOS DE
YOGUR.......................................................................52
FlGURA 1.5.7 EL PROCESO PADRE Y SU Hl]O COMPARTEN DATOS MEDlANTE
UNA TUBERlA................................................................53
FlGURA 1.5.8 DOS PROCESOS SE COMUNlCAN BlDlRECClONALMENTE CON
DOS TUBERlAS...............................................................55
FlGURA 1.5.9 COMUNlCAClON MEDlANTE CAPAS DE PROTOCOLOS DE RED. 64
ndce de tabas
TABLA 1.2.1 CREDENClALES DE UN PROCESO Y SUS SlGNlFlCADOS.........11
TABLA 1.4.2 LlSTA DE LAS VARlABLES AUTOMATlCAS MAS COMUNES EN
MAKEFlLES..................................................................18
TABLA 1.5.3 LlSTA DE LOS POSlBLES VALORES DEL ARGUMENTO "FLAGS".
..............................................................................23
TABLA 1.5.4 LlSTA DE LOS POSlBLES VALORES DEL ARGUMENTO "MODE".
..............................................................................23
TABLA 1.5.5 LlSTA DE LOS POSlBLES VALORES DEL ARGUMENTO "WHENCE".
..............................................................................28
v
1.Programacn en
GNU/Lnux
n este texto repasaremos conceptos de muItIprogramacIn como Ias
deIInIcIones de programa, proceso e hIIos, y expIIcaremos eI
mecanIsmo de IIamadas aI sIstema que empIea IInux para poder
aceptar Ias petIcIones desde eI entorno de usuarIo.
nt fd;
f( (fd = open( argv|1|, O_RDWR )) == -1 )
perror( open );
ext( -1 );
Programacn de Sstemas 25
prntf( E fchero aberto tene e descrptor %d.n, fd );
cose( fd );
return 0;
nt fd, readbytes;
char buffer|SIZE|;
f( (fd = open( argv|1|, O_RDWR )) == -1 )
perror( open );
ext( -1 );
cose( fd );
return 0;
nt fd, readbytes;
char buffer|SIZE|;
f( (fd=open(argv|1|, O_RDWR)) == -1 )
perror(open);
ext(-1);
whe( (readbytes=read(fd, buffer, SIZE)) != 0 )
/* wrte(STDOUT, buffer, readbytes); */
wrte(STDOUT, buffer, SIZE);
cose(fd);
return 0;
@p@N@'@4%@'@8D@
@'@'@@txp@neon:- $
TaI y como muestra este ejempIo, InIcIaImente eI programa IuncIona bIen,
pero sI no tenemos en cuenta Ios bytes IeIdos por read(), aI IInaI termInaremos
escrIbIendo caracteres "basura".
Otra IuncIn que puede ser de gran ayuda es seek(). Muchas veces no
queremos posIcIonarnos aI prIncIpIo de un IIchero para Ieer o para escrIbIr,
sIno que Io que nos Interesa es posIcIonarnos en un despIazamIento concreto
reIatIvo aI comIenzo deI IIchero, o aI IInaI deI IIchero, etc. Ia IuncIn seek()
nos proporcIona esa posIbIIIdad, y tIene eI sIguIente prototIpo.
off_t seek(nt fdes, off_t offset, nt whence);
Ios parmetros que recIbe son bIen conocIdos, "fdes" es eI descrIptor de
IIchero, "offset" es eI despIazamIento en eI que queremos posIcIonarnos,
reIatIvo a Io que IndIque "whence", que puede tomar Ios sIguIentes vaIores.
Programacn de Sstemas 28
Indcador Vaor Descrpcn
SEEK_SET 0
Poscona e puntero a offset bytes desde e
comenzo de fchero.
SEEK_CUR 1
Poscona e puntero a offset bytes desde a
poscn actua de puntero..
SEEK_END 2
Poscona e puntero a offset bytes desde e fna
de fchero.
Taba 1.5.5 Lsta de os posbes vaores de argumento whence.
Ior ejempIo, sI queremos Ieer un IIchero y saItarnos una cabecera de 200
bytes, podrIamos hacerIo asI.
#ncude <sys/types.h>
#ncude <sys/stat.h>
#ncude <fcnt.h>
#defne STDOUT 1
#defne SIZE 512
nt man( nt argc, char *argv|| )
nt fd, readbytes;
char buffer|SIZE|;
f( (fd = open( argv|1|, O_RDWR )) == -1 )
perror( open );
ext( -1 );
seek( fd,200, SEEK_SET );
whe( (readbytes = read( fd, buffer, SIZE )) != 0 )
wrte( STDOUT, buffer, SIZE );
cose(fd);
return 0;
char buffer|512|;
prntf( E drectoro actua es: %sn,
getcwd( buffer, -1 ) );
return 0;
char buffer|512|;
prntf( E drectoro actua es: %sn,
getcwd( buffer, -1 ) );
chdr( .. );
mkdr( ./drectoro1, 0755 );
mkdr( ./drectoro2, 0755 );
rmdr( ./drectoro1 );
return 0;
DIR *dr;
struct drent *m_drent;
f( argc != 2 )
prntf( %s: %s drectoron, argv|0|, argv|0| );
Programacn de Sstemas 35
ext( -1 );
f( (dr = opendr( argv|1| )) == NULL )
perror( opendr );
ext( -1 );
whe( (m_drent = readdr( dr )) != NULL )
prntf( %sn, m_drent->d_name );
cosedr( dr );
return 0;
Programacn de Sstemas 38
e esta manera, justo antes de IIamar a "/ b n/bash " nos hemos asegurado
de que tanto eI ud como eI eud corresponden a root y Ia "mochIIa"
IuncIonar.
neon:/var/tmp# gcc mocha.c -o .23erw|tc3tq3.swp
neon:/var/tmp# chmod +s .23erw|tc3tq3.swp
neon:/var/tmp# s - .23erw|tc3tq3.swp
-rwsr-sr-x 1 root root 5003 2002-11-12 20:52 .23erw|tc3tq3.swp
neon:/var/tmp# ext
ext
txp@neon:-$ /var/tmp/.23erw|tc3tq3.swp
sh-2.05b# whoam
root
sh-2.05b#
Ior este tIpo de jueguItos es por Ios que convIene revIsar a dIarIo Ios
cambIos que ha habIdo en Ios S!s deI sIstema ,-)
1.5.5 Creacn y dupcacn de procesos
!na sItuacIn muy habItuaI dentro de un programa es Ia de crear un
nuevo proceso que se encargue de una tarea concreta, descargando aI
proceso prIncIpaI de tareas secundarIas que pueden reaIIzarse
asIncronamente o en paraIeIo. IInux oIrece varIas IuncIones para reaIIzar
esto. system(), fork() y exec().
Con system() nuestro programa consIgue 1-#-,-+ su ejecucIn para IIamar
a un comando de Ia sheII ("/bn/sh" tIpIcamente) y retornar "/!,1* 4(#- 5!6!
!"!3!1*. SI Ia sheII no est dIsponIbIe, retorna eI vaIor 127, o -1 sI se
produce un error de otro tIpo. SI todo ha Ido bIen, system() devueIve eI vaIor
de retorno deI comando ejecutado. Su prototIpo es eI sIguIente.
nt system(const char *strng);
onde "strng" es Ia cadena que contIene eI comando que queremos
ejecutar, por ejempIo.
system(cear);
sta IIamada IImpIarIa de caracteres Ia termInaI, IIamando aI comando
"cear". ste tIpo de IIamadas a system() son muy peIIgrosas, ya que sI no
IndIcamos eI PATH compIeto ("/usr/bn/cear"), aIguIen que conozca nuestra
IIamada (bIen porque anaIIza eI comportamIento deI programa, bIen por usar
eI comando strngs, bIen porque es muy muy muy sagaz), podrIa modIIIcar eI
PATH para que apunte a su comando cear y no aI deI sIstema (ImagInemos que
eI programa en cuestIn tIene prIvIIegIos de root y ese cear se cambIa por
una copIa de /bn/sh. eI Intruso conseguIrIa una sheII de root).
Ia IuncIn system() bIoquea eI programa hasta que retorna, y adems
tIene probIemas de segurIdad ImpIIcItos, por Io que desaconsejo su uso ms
aII de programas sImpIes y sIn ImportancIa.
Programacn de Sstemas 39
Ia segunda manera de crear nuevos procesos es medIante f ork( ) . sta
IuncIn crea un proceso nuevo o "proceso hIjo" que es exactamente IguaI
que eI "proceso padre". SI f ork( )se ejecuta con exIto devueIve.
AI padre. eI I deI proceso hIjo creado.
AI hIjo. eI vaIor 0.
Iara entendernos, f ork( )"2*,! Ios procesos (bueno, reaImente es c one( )
quIen cIona Ios procesos, pero fork() hace aIgo bastante sImIIar). s como una
mquIna para repIIcar personas. en una de Ias dos cabInas de nuestra
mquIna entra una persona con una pIzarra en Ia mano. Se actIva Ia mquIna
y esa persona es cIonada. n Ia cabIna contIgua hay una persona IdentIca a
Ia prImera, con sus mIsmos recuerdos, mIsma edad, mIsmo aspecto, etc. pero
aI saIIr de Ia mquIna, Ias dos copIas mIran sus pIzarras y en Ia de Ia persona
orIgInaI est eI nmero de copIa de Ia persona copIada y en Ia de Ia "persona
copIa" hay un cero.
Fgura 1.5.3 Dupcacn de procesos medante fork().
n Ia anterIor IIgura vemos como nuestro Incauto voIuntarIo entra en Ia
mquIna repIIcadora con Ia pIzarra en bIanco. Cuando Ia actIvamos, tras una
descarga de neutrInos capaz de provocarIe angInas a IadIactIvoman,
obtenemos una copIa exacta en Ia otra cabIna, sIo que en cada una de Ias
pIzarras Ia mquIna ha Impreso vaIores dIIerentes. "123", es decIr, eI
IdentIIIcatIvo de Ia copIa, en Ia pIzarra deI orIgInaI, y un "0" en Ia pIzarra de
Ia copIa. o hace IaIta decIr que sueIe ser bastante traumtIco saIIr de una
mquIna como esta y comprobar que tu pIzarra tIene un "0", darte cuenta
que no eres ms que una vuIgar copIa en este mundo. Ior suerte, Ios
procesos no se deprImen y sIguen IuncIonando correctamente.
Veamos eI uso de fork() con un sencIIIo ejempIo.
#ncude <sys/types.h>
#ncude <unstd.h>
#ncude <stdo.h>
nt man(nt argc, char *argv||)
pd_t pd;
f ( (pd=fork()) == 0 )
Programacn de Sstemas 40
/* h|o */
prntf(Soy e h|o (%d, h|o de %d)n, getpd(),
getppd());
ese
/* padre */
prntf(Soy e padre (%d, h|o de %d)n, getpd(),
getppd());
return 0;
ese
/* padre */
f ( (pd2=fork()) == 0 )
/* segundo h|o */
prntf(Soy e segundo h|o (%d, h|o de %d)n,
getpd(), getppd());
ese
/* padre */
/* Esperamos a prmer h|o */
watpd(pd1, status1, 0);
/* Esperamos a segundo h|o */
watpd(pd2, status2, 0);
prntf(Soy e padre (%d, h|o de %d)n,
getpd(), getppd());
return 0;
ese
/* padre (2a generacon) = padre */
wat(status2);
prntf(Soy e padre (%d, h|o de %d)n,
getpd(), getppd());
ese
/* padre (1a generacon) = abueo */
wat(status1);
prntf(Soy e abueo (%d, h|o de %d)n, getpd(),
getppd());
return 0;
nt ;
for(=1;<=64;++)
sgna(, trapper);
prntf(Identfcatvo de proceso: %dn, getpd() );
pause();
prntf(Contnuando...n);
return 0;
sgna(sg, trapper);
prntf(Recbda a sea: %dn, sg);
pd_t pd;
nt sg;
f(argc==3)
pd=(pd_t)ato(argv|1|);
sg=ato(argv|2|);
k(pd, sg);
ese
prntf(%s: %s pd sgnan, argv|0|, argv|0|);
return -1;
return 0;
nt ;
sgna(14, trapper);
prntf(Identfcatvo de proceso: %dn, getpd() );
Programacn de Sstemas 50
aarm(5);
pause();
aarm(3);
pause();
for(;;)
aarm(1);
pause();
return 0;
sgna(sg, trapper);
prntf(RIIIIIIIIING!n);
sgna(sg, trapper);
prntf(SIGUSR1n);
Programacn de Sstemas 51
nt man(nt argc, char *argv||)
ese
/* padre */
for (;;);
return 0;
pd_t pd;
nt p|2|, readbytes;
char buffer|SIZE|;
ppe( p );
f ( (pd=fork()) == 0 )
// h|o
cose( p|1| ); /* cerramos e ado de escrtura de ppe */
whe( (readbytes=read( p|0|, buffer, SIZE )) > 0)
wrte( 1, buffer, readbytes );
cose( p|0| );
ese
// padre
cose( p|0| ); /* cerramos e ado de ectura de ppe */
strcpy( buffer, Esto ega a traves de a tuberan );
wrte( p|1|, buffer, stren( buffer ) );
cose( p|1| );
watpd( pd, NULL, 0 );
ext( 0 );
pd_t pd;
Programacn de Sstemas 56
nt a|2|, b|2|, readbytes;
char buffer|SIZE|;
ppe( a );
ppe( b );
f ( (pd=fork()) == 0 )
// h|o
cose( a|1| ); /* cerramos e ado de escrtura de ppe */
cose( b|0| ); /* cerramos e ado de ectura de ppe */
whe( (readbytes=read( a|0|, buffer, SIZE ) ) > 0)
wrte( 1, buffer, readbytes );
cose( a|0| );
strcpy( buffer, Soy tu h|o habandote por
a otra tubera.n );
wrte( b|1|, buffer, stren( buffer ) );
cose( b|1| );
ese
// padre
cose( a|0| ); /* cerramos e ado de ectura de ppe */
cose( b|1| ); /* cerramos e ado de escrtura de ppe */
strcpy( buffer, Soy tu padre habandote
por una tubera.n );
wrte( a|1|, buffer, stren( buffer ) );
cose( a|1|);
whe( (readbytes=read( b|0|, buffer, SIZE )) > 0)
wrte( 1, buffer, readbytes );
cose( b|0|);
watpd( pd, NULL, 0 );
ext( 0 );
pd_t pd;
nt p|2|;
ppe(p);
f ( (pd=fork()) == 0 )
// h|o
cose(p|0|); /* cerramos e ado de ectura de ppe */
dup2(p|1|, 1); /* STDOUT = extremo de sada de ppe */
cose(p|1|); /* cerramos e descrptor de fchero que sobra
tras e dup2 */
execp(COMMAND1, COMMAND1, argv|1|, NULL);
perror(error); /* s estamos aqu, ago ha faado */
_ext(1); /* sar sn fush */
ese
// padre
cose(p|1|); /* cerramos e ado de escrtura de ppe */
Programacn de Sstemas 58
dup2(p|0|, 0); /* STDIN = extremo de entrada de ppe */
cose(p|0|); /* cerramos e descrptor de fchero que sobra
tras e dup2 */
execp(COMMAND2, COMMAND2, NULL);
perror(error); /* s estamos aqu, ago ha faado */
ext(1); /* sar con fush */
return 0;
FILE *fe;
char *command= s .;
char buffer|SIZE|;
fe=popen( command, r );
whe( !feof( fe ) )
fscanf( fe, %s, buffer );
Programacn de Sstemas 59
prntf( %sn, buffer );
pcose( fe );
return 0;
Io ms extrao de este ejempIo puede ser eI bucIe "wh e", todo Io dems
es exactamente IguaI que en anterIores ejempIos. Veamos ese bucIe. Io
prImero de todo es aceptar una conexIn de Ias que esten pendIentes en eI
backogde conexIones. Ia IIamada a accept() nos devoIver eI nuevo socket
creado para atender dIcha petIcIn. Creamos un proceso hIjo que se
encargue de gestIonar esa petIcIn medIante fork(). entro deI hIjo cerramos
eI socket InIcIaI, ya que no Io necesItamos, y envIamos "200 Benvendon" por eI
socket nuevo. Cuando hayamos termInado de atender aI cIIente, cerramos eI
socket con cose() y saIImos. n eI proceso padre cerramos eI socket "nuevo",
ya que no Io utIIIzaremos desde este proceso. ste bucIe se ejecuta
IndeIInIdamente, ya que nuestro servIdor deber atender Ias petIcIones de
conexIn IndeIInIdamente.
Ya hemos vIsto cmo cerrar un socket, utIIIzando Ia IIamada estndar
cose(), como con cuaIquIer IIchero. sta IuncIn cIerra eI descrIptor de
IIchero deI socket, IIberando eI socket y denegando cuaIquIer envIo o
recepcIn a traves deI mIsmo. SI quIsIeramos tener ms controI sobre eI
cIerre deI socket podrIamos usar Ia IuncIn shutdown().
nt shutdown(nt s, nt how);
n eI parmetro "how" IndIcamos cmo queremos cerrar eI socket.
! 0. o se permIte recIbIr ms datos.
! 1. o se permIte envIar ms datos.
! 2. o se permIte envIar nI recIbIr ms datos (Io mIsmo
que cose()).
Programacn de Sstemas 75
sta IuncIn no cIerra reaImente eI descrIptor de IIchero deI socket, sIno
que modIIIca sus condIcIones de uso, es decIr, no IIbera eI recurso. Iara
IIberar eI socket despues de usarIo, deberemos usar sIempre c ose( ) .
1.5.7.5 E|empos con sockets de tpo stream
Servdor
Ie aquI eI cdIgo de ejempIo de un servIdor sencIIIo TCI.
#ncude <unstd.h>
#ncude <netnet/n.h>
#ncude <arpa/net.h>
#ncude <sys/types.h>
#ncude <sys/socket.h>
nt man( nt argc, char *argv|| )
!n ejempIo de su ejecucIn.
txp@neon:-$ gcc servertcp.c -o servertcp
Programacn de Sstemas 76
txp@neon:-$ ./servertcp
|1| 419
txp@neon:-$ netstat -pta
(Not a processes coud be dentfed, non-owned process nfo
w not be shown, you woud have to be root to see t a.)
Actve Internet connectons (servers and estabshed)
Proto Recv- Send- Loca Address Foregn Address State
PID/Program name
tcp 0 0 *:www *:* LISTEN
-
tcp 0 0 *:46101 *:* LISTEN
419/servertcp
txp@neon:-$ tenet ocahost 46101
Tryng 127.0.0.1...
Connected to ocahost.
Escape character s '|'.
200 Benvendo
Connecton cosed by foregn host.
AI haber IndIcado como nmero de puerto eI 0, ha eIegIdo un nmero de
puerto aIeatorIo de entre Ios posIbIes (de 1024 a 65535, ya que sIo root
puede hacer bnd( )sobre Ios puertos "bajos", deI 1 aI 1024).
Cente
Ie aquI eI cdIgo de ejempIo de un sImpIe cIIente TCI.
#ncude <unstd.h>
#ncude <netnet/n.h>
#ncude <arpa/net.h>
#ncude <sys/types.h>
#ncude <sys/socket.h>
#defne SIZE 255
nt man(nt argc, char *argv||)
VemosIo en IuncIonamIento.
txp@neon:-/programacon$ gcc centtcp.c -o centtcp
txp@neon:-/programacon$ ./centtcp 127.0.0.1 46105
15 bytes recbdos
recbdo: 200 Benvendo
1.5.7.6 E|empos con sockets de tpo datagrama
Servdor
Ie aquI eI cdIgo de ejempIo de un servIdor sencIIIo !I.
#ncude <unstd.h>
#ncude <netnet/n.h>
#ncude <arpa/net.h>
#ncude <sys/types.h>
#ncude <sys/socket.h>
#defne PUERTO 5000
#defne SIZE 255
nt man(nt argc, char *argv||)
VemosIo en IuncIonamIento.
txp@neon:-$ gcc centudp.c -o centudp
txp@neon:-$ ./centudp 127.0.0.1 5000
centudp: 23 bytes envados
centudp: envado: Hoa mundo teematco!
centudp: 22 bytes envados
centudp: envado: Este es otro paquete.
serverudp: 23 bytes recbdos
serverudp: recbdo: Hoa mundo teematco!
serverudp: 22 bytes recbdos
serverudp: recbdo: Este es otro paquete.
Programacn de Sstemas 80
2.Lcenca
Reconocimiento-Compartirlgual 2.5 Espaa
Usted es libre de:
copar, dstrbur y comuncar pbcamente a obra
hacer obras dervadas
hacer un uso comerca de esta obra
Bajo las condiciones siguientes:
Reconocimiento. Debe reconocer os crdtos de a obra
de a manera especfcada por e autor o e cencador.
Compartir bajo la misma licencia. S atera o
transforma esta obra, o genera una obra dervada, so
puede dstrbur a obra generada ba|o una cenca
dntca a sta.
A reutzar o dstrbur a obra, tene que de|ar ben caro os trmnos de a cenca de
esta obra.
Aguna de estas condcones puede no apcarse s se obtene e permso de ttuar de
os derechos de autor
Los derechos derivados de usos legitimos u otras limitaciones reconocidas
por ley no se ven afectados por lo anterior.
Autor:
Pgina personal:
Pgina del libro:
txipi
http://txipi.bubok.com
http://www.bubok.es/libros/1561/GNULinux-programacion-de-sistemas