Archivo de la categoría: GNU/Linux

Hablando de C: Programa que borra comentarios del código

Estoy probando Windows 10 y quería compilar un programa en C. En un sistema Unix o GNU/Linux, bastaría con recurrir a gcc desde la línea de comandos. Para Windows, podemos utilizar las herramientas de MinGW “Minimalist GNU for Windows”, lo podemos descargar de la página oficial del proyecto: http://www.mingw.org/

Al finalizar de instalar hay que recordar agregar al PATH de las variables de entorno la ubicación de los binarios de MinGW.

Para las variables de entorno, en Windows 10 podemos apretar CTRL+X e ir al menú System, de ahi seleccionar Advanced System Settings:

pathenv

Finalmente agregamos/verificamos la ruta hacia la carpeta bin de MinGW:

pathenv2Una vez instalado reiniciamos y ya está listo para usarse desde la línea de comandos funcionando de la misma manera que si estuvieramos trabajando desde una terminal tipo Unix o GNU/Linux, por decir para compilar un archivo de C:

> gcc nombre_archivo.c -o nombre_programa

consola

Cuando estamos aprendiendo un nuevo lenguaje de programación, los aspectos técnicos antes de empezar son algo enfadosos, pero creo que C es muy agradable en ese aspecto, más si tenemos un sistema tipo Unix, puesto que por lo general ya incluyen compiladores para C (como gcc).

¿Qué otras ventajas tiene C?, bueno, en teoría si programas en ANSI C (el estándar), tu programa debe correr bien en cualquier implantación que respete el estándar, o en otras palabras, es portable.

Estaba leyendo el libro de “El Lenguaje de Programación C” de K&R y me detuve a revisar el problema 1-23, el cual dice:

Escriba un programa para eliminar todos los comentarios de un programa en C. No olvide manejar apropiadamente las cadenas entre comillas y las constantes de carácter. Los comentarios de C no se anidan.

Bueno, creo que los que han leído el libro notaron que desde el capítulo 1 hay problemas muy interesantes, comparto el código que hice para la respuesta a este problema, a lo mejor a alguien le puede resultar útil o incluso sería agradable ver alguna respuesta alternativa.

El código lo pueden descargar del siguiente enlace: http : //www. mediafire .com/view/vxibrpd1w2zb8dk/clean_comments.c (dejo el código con fin de referencia nadamas)

Código corregido:

Nuevo enlace: http://www.mediafire.com/view/hzn69fgxp9mlz0z/clean_commentsv2.c

Tuve que modificar un poco el código para que cumpliera el propósito, considerando:

  • Saltar cadenas de caracteres
  • No imprimir in-line comments (del tipo que empiezan con //)
  • Considerar comentario las lineas de texto que empiezan con /* y terminan con */

En el capítulo 1 del libro, hablan de la función getchar(), la cual lee el siguiente caracter que recibe de la Entrada Estándar. Así por decir, podríamos desde la consola redireccionar que la Entrada la lea de un archivo y mande la Salida a otro archivo, los pasos los podemos ver en la imágen, desde la compilación hasta la ejecución de este programa teniendo como entrada el mismo programa fuente y generando un archivo test.c con el código sin comentarios:

consola2

Finalmente, comparando los dos archivos, parece que el programa cumple el cometido:

comparativa

En programación hay más de una manera de resolver el mismo problema, por lo general se busca la solución más eficiente. A veces la eficiencia se mide en líneas de código, pero más importante aún, medirlo en el tiempo de procesamiento o los pasos (notación de la Big O) que le toma a mi programa ejecutar su tarea en el mejor y en el peor de los casos.

De C, podemos hablar mucho … en el capítulo uno se tocan los temas de variables, funciones y arreglos, cuando vas en capítulos más avanzados te invitan a regresar y resolver los problemas pero ahora con apuntadores.

Uno puede tratar un arreglo como si fuera un apuntador, cuando un arreglo se pasa como argumento a una función, lo que estamos pasando en realidad es la posición en memoria del primer elemento del arreglo, dicho de otra forma, un apuntador, por lo que la función puede modificar por referencia el valor del arreglo.

Espero el post anime a más gente a voltear a la programación en C, el lenguaje para programar Sistemas Operativos y del cual la mayoría de lenguajes modernos han heredado muchos conceptos (la sintaxis en Python, PHP, Java y Javascript a mi gusto es muy parecida).

EOF

Debian: Cómo instalar un servidor web (Apache + PHP)

feather-small Distro: GNU/Linux Debian “Wheezy” (7.2)

Funciona en: Debian “Etch” (4.0) – Debian “Wheezy” (7.3)

La ventaja de tener un equipo con Debian es que tenemos una gran cantidad de servicios y aplicaciones que podemos instalar directo de los repositorios oficiales, de hecho, la versión “Estable” de Debian está pensada para ser utilizada como servidor. En este post, revisaremos los pasos a seguir para montar Apache (servidor web) y hacer que soporte php5.

Pasos a seguir

1.- Instalaremos el servidor web Apache (como root):

$ su
# aptitude install apache2

Podemos comprobar que el servicio está instalado correctamente si abrimos en el navegador nuestra dirección local: http://127.0.0.1 y vemos el siguiente mensaje:

itWorks

Desde la consola podemos revisar el status del demonio* [status], detenerlo [stop] o reiniciarlo [restart] (para detener o reiniciar un servicio debemos estar loggeados como root) a través de la ruta /etc/init.d, de la siguiente manera:

# /etc/init.d/apache2 status

Nos regresa:

Apache2 is running (pid 2411).

*Entiéndase como demonio, un daemon, o proceso que corre en 2do plano

2.- Una vez instalado Apache debemos cargar el módulo para que soporte php5. Para hacerlo ejecutamos:

# aptitude install libapache2-mod-php5

3.- Por default, al finalizar la instalación de Apache, nuestra carpeta /var/www tendrá permiso y grupo de root, lo cual no nos permitirá poder escribir nuestros archivos en esa ruta a menos que tengamos los permisos pertinentes (esto es, ningún usuario salvo root puede escribir en esa carpeta). Una alternativa que tenemos es utilizar el grupo www-data (al instalarse Apache, creará un usuario y grupo www-data), asignando a éste grupo los usuarios que queremos tengan permisos de escritura en /var/www.

Para hacerlo ejecutaremos en una consola lo siguiente:

1) Agregamos el usuario que queramos al grupo www-data

# usermod -a -G www-data tuNombreDeUsuario

Si quieres que el home del usuario sea /var/www puedes ejecutar:

# usermod -d /var/www tuNombreDeUsuario

2) Definimos que el grupo para /var/www sea www-data

# chgrp -R www-data /var/www

3) Cambiamos los permisos para que podamos escribir sobre el directorio y establecemos el bit setgid (SGID):

# chmod 775 -R /var/www
# chmod g+s /var/www

Nuestros permisos quedarían algo como:

# ls -al /var
drwxrwsr-x  3 root www-data 4096 May 28 08:49 www

3.- Algunos puntos importantes:

– El archivo de configuración de apache se encuentra en /etc/apache2/apache2.conf

– Podemos leer el manual de referencia ejecutando:

# man apache2

– Los archivos de nuestras páginas web, los podremos encontrar/guardar en el directorio: /var/www

– Si tenemos instalado MySQL y queremos que PHP soporte la extensión para conexiones con MySQL podemos ejecutar:

# aptitude install php5-mysql

SOLUCIÓN A POSIBLES PROBLEMAS

– Archivo de configuración principal:
/etc/apache2/apache2.conf
En ese archivo podemos hacer configuraciones globales, contiene un resumen de como podemos administrar nuestro apache, nos presenta la siguiente estructura de directorios:

# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf.d
# | `-- *
# `-- sites-enabled

Y nos dice que para dar de alta nuevos módulos nos apoyemos de los comandos: a2enmod/a2dismod, a2ensite/a2dissite, a2enconf/a2disconf.

Veremos un ejemplo de como cargar un módulo en este post.

– Cambiar puerto de escucha:
En mi caso el servidor ya tenía nginx instalado por lo que al terminar de instalar Apache no pudo empezar a correr, por que no podía abrir el socket en el puerto 80. Para cambiar el puerto de escucha modificaremo el archivo:
/etc/apache2/ports.conf

En la línea:

Listen 80

Cambiamos el 80 por el nuevo puerto que ocupamos (mi caso 30100). ports.conf nos recomienda hacer los cambios apropiados para VirtualHost en: /etc/apache2/sites-enabled/000-default.conf

Reiniciamos apache:

# /etc/init.d/apache2 restart

Error: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to suppress this message

Para resolver este problema, nos vamos al directorio de archivos de configuración:

# cd /etc/apache2/conf-available

Creamos un nuevo archivo y lo daremos de alta como módulo:

# echo "ServerName localhost">servername.conf

Habilitamos el nuevo módulo:

# a2enconf servername.conf

Reiniciamos:

# /etc/init.d/apache2 restart

Como en el caso anterior, modificamos también el archivo /etc/apache2/sites-available/000-default.conf

Ejemplo de mi archivo /etc/apache2/sites-available/000-default.conf

<VirtualHost *:10000>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
ServerName localhost

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
</VirtualHost>



– Archivos de bitácora log (errores y acceso)

Se encontrarán en la ruta: /var/log/apache2

Solamente root puede acceder a éstos archivos, y son dos archivos los que nos interesan access.log y error.log

 

Enlaces de interés:

https://wiki.debian.org/Apache

http://www.rackspace.com/knowledge_center/article/how-to-add-linux-user-with-document-root-permissions

http://es.wikipedia.org/wiki/Chmod

Debian: Como correr un daemon en el arranque del sistema (Ej. Reglas de iptables)

pacamanfirewallPruebas realizadas desde: GNU/Linux Debian “Wheezy” (7.4)

Objetivo: En este tutorial trataremos de crear un script que se ejecute al arrancar nuestro sistema GNU/Linux, el script consiste en (aunque podemos hacer scripts que hagan otras cosas) reglas de iptables de un firewall stateful que acepta de ENTRADA: ICMP echo-request, peticiones a puerto 80 (servidor web) y de SALIDA: ICMP echo-request, con peticiones a servicios de uso común para poder navegar sin muchas restricciones (puerto 80, 53, 21, 22, 443).

Bueno, habrá veces que queramos ejecutar un script cuando arranca nuestro sistema Linux, por ejemplo, si queremos cargar reglas para nuestro firewall (iptables). El primer programa que corre Linux al arrancar es “init”, su archivo de configuración se encuentra en /etc/inittab, las primeras líneas del archivo serían algo como lo siguiente:

# The default runlevel.
id:2:initdefault:

# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS

Cada “runlevel” describe un estado de la máquina, por decir 0 es para halt (cuando se detiene), 1 es para single-user, de 2 a 5 es el multiusuario y 6 es cuando se reinicia. Los scripts que se ejecutan por cada runlevel se encuentran ubicados en rutas específicas, por ejemplo para el runlevel 0, en /etc/rc0.d … de manera genérica sería algo como /etc/rc#.d donde # sería el número del runlevel (0 a 6)… si queremos conocer nuestro runlevel podemos ejecutar en la terminal:

root:~# runlevel

Ahora bien, los demonios (daemons) que se ejecutan al inicio se encuentran ubicados en /etc/init.d, si queremos crear un script propio que se ejecute al arranque deberemos crearlo en esa ruta, por decir:

root:~# cd /etc/init.d
root:/etc/init.d# touch fw
root:/etc/init.d# chmod +x fw

Si lo queremos editar desde consola podemos usar nano, vi, etc:

root:/etc/init.d# nano fw

El script propiamente podría ejecutar cualquier cosa, por ejemplo:

#! /bin/bash
echo "Script que se ejecuta al arranque..."

Para habilitar daemons (con configuración default) usaremos el comando “insserv”, ejecutariamos en la terminal algo como:

root:/etc/init.d# insserv fw

Nos manda el siguiente mensaje:

insserv: warning: script 'fw' missing LSB tags and overrides

El problema es que nuestro script debe tener ciertos encabezados “LSB” para que el sistema lo reconozca y sepa que hacer con él. Nuestro script con encabezados quedaría algo como lo siguiente:

#! /bin/bash
### BEGIN INIT INFO
# Provides: fw
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Daemon que carga reglas de fw
# Description: Daemon que carga nuestras reglas de iptables.
### END INIT INFO
echo "Script que se ejecuta al arranque..."

+ Descripción de los encabezados

Ahora si lo volvemos a cargar con insserv:

root:/etc/init.d# insserv fw

Tenemos que si nuestros encabezados están bien ya no marcará error, y la próxima vez que reiniciemos se empezará a ejecutar nuestro demonio (considerando los encabezados LSB).

Para remover un daemon de la ejecución al inicio ejecutamos insserv con -r y el nombre del demonio:

root:/etc/init.d# insserv -r fw

Buscaremos programar nuestro script para que acepte cierto control, por decir, algunos daemons aceptan parámetros, del tipo start|stop|restart … por ejemplo el daemon de apache o del network-manager:

root:~# /etc/init.d/apache2 status
Apache2 is running (pid 2812).
root:~# /etc/init.d/network-manager status
[ ok ] NetworkManager is running.

Volviendo a nuestro script, si lo dejáramos como está se ejecutaría lo mismo independientemente de si se apaga o se inicia la computadora… lo que buscaríamos sería más bien que por decir, al iniciar el ordenador se cargaran las reglas del FW y al apagar se borraran las reglas.

De manera genérica, los pasos ya descritos nos servirán para que se ejecute cualquier script que programemos en el runlevel deseado … sin embargo pongo el código de como quedaría mi firewall gestionando los status de “start, stop y restart”. En otro post explicaré un poco más sobre iptables y firewalls pero por ahora espero con éste código se ejemplifique mejor el concepto de como correr daemons al arranque del sistema:

#! /bin/bash
### BEGIN INIT INFO
# Provides:	fw
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop:	0 1 6
# Short-Description: Carga Reglas de IPTABLES
# Description: Carga reglas de fw
### END INIT INFO

start() {
echo "CONFIGURANDO FIREWALL"

echo "[+] Limpiando reglas"
# Limpiar reglas
iptables -X
iptables -F
iptables -t nat -F

echo "[+] Definiendo politica dura"
# Politica dura
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

# Reglas de entrada
echo "[+] Configurando cadenas de ENTRADA"
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
iptables -A INPUT -p tcp --dport 80 --syn -m state --state NEW -j ACCEPT

# Reglas de salida
echo "[+] Configurando cadenas de SALIDA"
iptables -A OUTPUT -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT

iptables -A OUTPUT -p tcp --dport 80 --syn -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 21 --syn -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 --syn -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 --syn -m state --state NEW -j ACCEPT
}

stop() {
echo "[+] Borrando reglas de iptables"
iptables -F
iptables -X

echo "[+] Quitando politica dura"
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
}

#Revisamos permisos de root
if [ "$(id -u)" != "0" ]; then
	echo "Necesarios permisos de root..." 1>&2
	exit 1
fi

# En un case gestionamos start|stop|restart
case "$1" in
	start)
		start
		exit 0
	;;
	stop)
		stop
		exit 0
	;;
	restart)
		stop
		start
		exit 0
	;;
	**)
		echo "Uso: $0 {start|stop|restart}" 1>&2
		exit 1
	;;
esac

Espero sea de utilidad, se puede encontrar más información en el wiki de Debian, dejo los enlaces 🙂

Enlaces de interés:
https://wiki.debian.org/Daemon
http://www.debian.org/doc/debian-policy/ch-opersys.html#s-sysvinit
https://wiki.debian.org/LSBInitScripts/DependencyBasedBoot?highlight=%28\bCategoryBootProcess\b%29
https://wiki.debian.org/LSBInitScripts