WARNING, INFO y DEBUG).
- Mejora de algunos mensajes de error.
- Reestructuración del archivo de configuración. Nueva sección [log] y
eliminación de algunas variables de configuración.
[general]
; Nivel de reporte de errores.
error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR
-; Nivel de loggeo: L_NON, L_CRI, L_ERR, L_WRN, L_INF, L_DBG, L_ALL
-; (ver T/logconstants.php)
-loglevel = L_ALL & ~L_DBG
-; Archivo de log (si no se especifica, se usa STDERR)
-logfile = /var/log/sercom.log
; Directorio base en donde almacenar los archivos de datos (entregas, intentos)
data_dir = /var/lib/sercom
; Claves para validar la identidad del alumno (a usar para crear el código)
; Usuario con el cual ejecutar las pruebas
user = sercom
+[log]
+; Nivel de loggeo: CRITICAL, ERROR, WARNING, INFO, DEBUG
+; (ver T/logconstants.php)
+level = INFO
+; Archivo de log (si no se especifica, se usa la salida de error)
+file =
+
[mail]
; E-Mail del administrador, a donde enviar errores graves, avisos, etc
-mail_admin = luca@llucax.hn.org
+admin = 7542@fi.uba.ar
; Dirección desde la cual enviar mails
-from = "TALLER DE PROGRAMACION I <mat7542@fi.uba.ar>"
-; Descripción del programa de mail (X-Mailer)
-mailer = "sercom v0.2"
-; Prefijo a poner en el subject
-prefijo = "[CORRECTOR]"
+from = "TALLER DE PROGRAMACION I <7542@fi.uba.ar>"
; Mailbox local en donde hacer backup de los mails entregados
; (si está vacío no se hace backup)
mbox_bak = /var/lib/sercom/entregas.mbox
$date = date('Y-m-d H:i:s', $this->llegada);
$entrega = DB_DataObject::factory('entrega');
$entrega->getFrom($inscripto->curso_id, $this->ejercicio, $this->entrega);
-var_dump($this);
-var_dump($inscripto->id);
-var_dump($inscripto->curso_id);
-var_dump($entrega->id);
-# 2005-01-06, 2005-02-26 20:00:00, 2005-02-03 19:48:15
-var_dump($entrega->desde, $entrega->hasta, $date);
-var_dump($entrega->desde <= $date);
-var_dump($entrega->hasta >= $date);
if (!($entrega->desde <= $date and $entrega->hasta >= $date)) return 'El ejercicio está siendo entregado fuera de fecha';
$intento = DB_DataObject::factory('intento');
$intento->id_entrega = $entrega->id;
<?php // vim: set binary noeol et sw=4 sts=4:
+$VERSION = 0.2;
+$NAME = 'sercom';
+
define('DB_DATAOBJECT_NO_OVERLOAD', 0);
// Seteo umask para que el grupo pueda leer.
require_once 'T/logconstants.php';
// obtengo configuración
-foreach (array('.', '/etc', '/etc/sercom') as $dir) {
- $cf = "$dir/sercom.ini";
+foreach (array('.', '/etc', '/etc/'.$NAME) as $dir) {
+ $cf = "$dir/$NAME.ini";
if (is_readable($cf)) {
if (!($CONF = @parse_ini_file($cf, true))) {
fputs(STDERR, "No se pudo abrir archivo de configuración '$cf' ($php_errormsg)!\n");
ini_set('track_errors', true);
// locale
-$lang = getenv('LANG');
-setlocale(LC_ALL, $lang);
+#$lang = getenv('LANG');
+setlocale(LC_ALL, '');
// si no está seteado el nivel de logueo, uso el del archivo de config
-if (!isset($LOGLEVEL)) $LOGLEVEL = isset($gconf['loglevel']) ? $gconf['loglevel'] : L_INF;
+if (!isset($LOGLEVEL)) $LOGLEVEL = isset($CONF['log']['level']) ? $CONF['log']['level'] : INFO;
// Abro file pointer para loguear.
if (!isset($LOGFP)) {
- if (@$gconf['logfile']) {
- $LOGFP = fopen($gconf['logfile'], 'a');
+ if (@$CONF['log']['file']) {
+ $LOGFP = fopen($CONF['log']['file'], 'a');
if (!$LOGFP) {
- fputs(STDERR, "No se pudo abrir archivo de log '{$gconf['logfile']}' ($php_errormsg)!\n");
+ fputs(STDERR, "No se pudo abrir archivo de log '{$CONF['log']['file']}' ($php_errormsg)!\n");
exit(2);
}
} else {
<?php // vim: set binary noeol et sw=4 sts=4:
-function logserr($str, $level = L_ERR) {
+require_once 'T/logconstants.php';
+
+function logserr($str, $level = ERROR) {
global $php_errormsg;
logs("$str ($php_errormsg)", $level);
}
-function logs($str, $level = L_INF) {
+function logsdie($str, $level = CRITICAL) {
+ logs($str, $level);
+ die("$str.\n");
+}
+
+function logs($str, $level = INFO) {
global $LOGLEVEL, $LOGFP, $argv;
if ($str and $LOGLEVEL & $level) {
fputs($LOGFP, sprintf("%s %s[%d] %-8s %s\n", strftime('%c'),
}
function loglevel2str($level) {
- $ret = array();
- if ($level & L_CRI) {
- $ret[] = 'CRITICAL';
- }
- if ($level & L_ERR) {
- $ret[] = 'ERROR';
- }
- if ($level & L_WRN) {
- $ret[] = 'WARNING';
+ if ($level == CRITICAL) {
+ return 'CRITICAL';
}
- if ($level & L_INF) {
- $ret[] = 'INFO';
+ if ($level == ERROR) {
+ return 'ERROR';
}
- if ($level & L_DBG) {
- $ret[] = 'DEBUG';
+ if ($level == WARNING) {
+ return 'WARNING';
}
- if (count($ret) == 1) {
- return reset($ret);
+ if ($level == INFO) {
+ return 'INFO';
}
- if ($ret) {
- return '['.join(',', $ret).']';
+ if ($level == DEBUG) {
+ return 'DEBUG';
}
- return '';
+ return 'UNKNOWN!';
}
?>
\ No newline at end of file
<?php // vim: set binary noeol et sw=4 sts=4:
-define('L_NON', 0);
-define('L_CRI', 1);
-define('L_ERR', 1 << 1);
-define('L_WRN', 1 << 2);
-define('L_INF', 1 << 3);
-define('L_DBG', 1 << 4 );
-define('L_ALL', 0xFFFF);
-#define('L_', );
+// Constantes
+define('CRITICAL', 1);
+define('ERROR', CRITICAL + 1 << 1);
+define('WARNING', ERROR + 1 << 2);
+define('INFO', WARNING + 1 << 3);
+define('DEBUG', INFO + 1 << 4 );
?>
\ No newline at end of file
--- /dev/null
+#!/usr/bin/php
+<?php // vim: set binary noeol et sw=4 sts=4:
+
+$LOGLEVEL = ERROR;
+
+require_once 'T/general.php';
+
+if ($argc < 2) {
+ echo "Uso: {$argv[0]} padron [clave]\n";
+ exit(1);
+}
+$claves = $CONF['general']['claves'];
+if ($argc > 2) $claves = $argv[2];
+
+echo T_generar_codigo($argv[1], $claves) . "\n";
+
+?>
\ No newline at end of file
$mailbox = "{{$mconf['server']}$port/{$mconf['protocol']}$options}$mailbox";
break;
default:
- die("Error: el protocolo {$mconf['protocol']} no está soportado.\n");
+ logsdie("Error: el protocolo {$mconf['protocol']} no está soportado");
}
#$mbox = imap_open($mailbox, @$mconf['user'], @$mconf['pass']);
$claves = $gconf['claves'];
+// Errores tratando de conectar al mail
+$mbox_errcount = 0;
+
// Sin cesar.
while (1) {
// Reseteo intervalo
$intervalo = $gconf['intervalo'];
// Abro mailbox o chillo.
if (!($mbox = imap_open($mailbox, @$mconf['user'], @$mconf['pass']))) {
- logs('No se pudo conectar al servidor ('.imap_last_error().')', L_ERR);
+ if ($mbox_errcount * $intervalo > 120) { // 2 horas sin poder conectarse
+ logs('Hace 2 horas que no se puede conectar al servidor ('.imap_last_error().')', ERROR);
+ $mbox_errcount = 0;
+ } else {
+ logs('No se pudo conectar al servidor ('.imap_last_error().')', WARNING);
+ }
+ $mbox_errcount++;
sleep($intervalo);
+ continue;
}
- logs('Conectado como '.@$mconf['user']." a $mailbox", L_DBG);
+ $mbox_errcount = 0;
+ logs('Conectado como '.@$mconf['user']." a $mailbox", DEBUG);
if (imap_num_msg($mbox) and $hdr = imap_headerinfo($mbox, 1)) {
logs("Nuevo mail '{$hdr->subject}' de {$hdr->fromaddress}");
@list($padron, $ej, $ent, $codigo) = validar_cabecera($hdr);
if ($padron) {
- logs('Cabecera válida', L_DBG);
+ logs('Cabecera válida', DEBUG);
$intento = new T_Intento($padron, $ej, $ent);
if (!($err = $intento->validar_entrega($codigo, $claves))) {
logs('Entrega aceptada ('.$intento->to_line().')');
if (!($err = preparar_entrega($intento, $mbox, 1, $gconf['data_dir']))) {
- logs('Intento preparado', L_DBG);
+ logs('Intento preparado', DEBUG);
$res = $intento->hacer_entrega($hdr->fromaddress);
if (PEAR::isError($res)) {
- logs('Error al hacer entrega (' . $res->getMessage() . ')', L_ERR);
- enviar_respuesta(R_ERR, $hdr->fromaddress, "Error al preparar entrega:\nError en la base de datos.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
- enviar_respuesta(R_ERR, $mconf['mail_admin'], "Error al preparar entrega:\n" . $res->getMessage(), $intento);
+ logs('Error al hacer entrega (' . $res->getMessage() . ')', ERROR);
+ enviar_respuesta(R_ERR, $hdr->fromaddress, "Error interno al preparar entrega.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
+ enviar_respuesta(R_ERR, $mconf['admin'], "Error de la DB al preparar entrega:\n" . $res->getMessage(), $intento);
} else {
- logs('Intento encolado para compilar');
+ logs('Intento encolado para compilar', DEBUG);
enviar_respuesta(R_OK, $hdr->fromaddress, null, $intento);
guardar_mbox($mbox, 1, $hdr, @$mconf['mbox_bak']);
}
} else {
- logs("Error al preparar entrega ($err)", L_ERR);
- enviar_respuesta(R_ERR, $hdr->fromaddress, "Error al preparar entrega:\n$err", $intento);
- enviar_respuesta(R_ERR, $mconf['mail_admin'], "Error al preparar entrega:\n$err.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
+ logs("Error al preparar entrega ($err)", ERROR);
+ enviar_respuesta(R_ERR, $hdr->fromaddress, "Error interno al preparar entrega.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
+ enviar_respuesta(R_ERR, $mconf['admin'], "Error al preparar entrega:\n$err", $intento);
}
} else {
- logs("Entrega rechazada ($err)");
+ logs("Entrega rechazada ($err)", WARNING);
enviar_respuesta(R_ERR, $hdr->fromaddress, $err, $intento);
}
} else {
- logs('Entrega rechazada (subject inválido)');
+ logs('Entrega rechazada (subject inválido)', WARNING);
enviar_respuesta(R_ERR, $hdr->fromaddress, "Asunto (subject) inválido.\n\n"
. "Recuerde que el formato del asunto es estricto:\n"
. "[padrón] [ejercicio].[entrega] [código]\n\n"
);
}
imap_delete($mbox, 1);
- logs('Mail borrado');
+ logs('Mail borrado', DEBUG);
imap_expunge($mbox);
- logs('Mensajes purgandos', L_DBG);
+ logs('Mensajes purgandos', DEBUG);
$intervalo = 0; // Que tome el próximo mail enseguida.
} else {
- logs('No hay mail nuevo', L_DBG);
+ logs('No hay mail nuevo', DEBUG);
}
- logs('Cerrando conexión', L_DBG);
+ logs('Cerrando conexión', DEBUG);
imap_close($mbox);
sleep($intervalo);
}
function enviar_respuesta($tipo, $to, $mensaje = '', $intento = null) {
global $mconf;
- $subject = $mconf['prefijo'] . ' Entrega ';
+ $subject = '[' . strtoupper($NAME) . '] Entrega ';
if ($tipo == R_OK) $estado = 'ACEPTADA';
else $estado = 'RECHAZADA';
$subject .= $estado;
$body .= "Estado: $estado\n";
if ($mensaje) $body .= "\n$mensaje\n";
if ($intento) $body .= "\n" . $intento->__toString() . "\n";
- logs("Envío de mail '$subject' a '$to'\n$body\n", L_DBG);
+ logs("Envío de mail '$subject' a '$to'\n$body\n", DEBUG);
$headers = <<<EOT
From: {$mconf['from']}
-Reply-To: {$mconf['mail_admin']}
-X-Mailer: {$mconf['mailer']}
+Reply-To: {$mconf['admin']}
+X-Mailer: $NAME $VERSION
X-Priority: 5
EOT;
mail($to, $subject, $body, $headers);
}
function preparar_entrega($intento, $mbox, $msgid, $dir) {
- logs('Acá debería verificar el cuerpo del mensaje', L_DBG);
+ logs('Acá debería verificar el cuerpo del mensaje', DEBUG);
$mail = imap_fetchstructure($mbox, $msgid);
foreach ($mail->parts as $id => $part) {
$fname = part_filename($part);
if ($fname) {
- logs("Escribiendo archivo '$fname' [enc={$part->encoding}]", L_DBG);
+ logs("Escribiendo archivo '$fname' [enc={$part->encoding}]", DEBUG);
$body = imap_fetchbody($mbox, $msgid, $id + 1);
$path = "$dir/" . $intento->path();
if (!mkdir_p($path)) return 'No se pudo crear el directorio';
case ENCQUOTEDPRINTABLE: return imap_qprint($body);
case ENCOTHER: return $body;
}
- logs('Encoding no reconocido.', L_ERR);
+ logs('Encoding no reconocido.', WARNING);
return $body;
}
define('R_ERR', 0);
define('R_OK', 1);
-$LOGLEVEL = L_ALL;
+$LOGLEVEL = DEBUG;
$gconf = $CONF['general'];
// Sin cesar.
while (1) {
if (!($mail = $intento->proximo_a_probar())) {
- logs('No hay intento para probar', L_DBG);
+ logs('No hay intento para probar', DEBUG);
sleep($gconf['intervalo']);
continue;
}
enviar_respuesta_error_log($mail, 'Error al cambiar al directorio del tp', $intento);
continue;
}
- logs("Cambio de directorio '$currdir' -> '$intento_dir'", L_DBG);
- logs('Ejecutando el comando: make -f '.escapeshellarg($makefile), L_DBG);
+ logs("Cambio de directorio '$currdir' -> '$intento_dir'", DEBUG);
+ logs('Ejecutando el comando: make -f '.escapeshellarg($makefile), DEBUG);
if (exec_get_info('make -f '.escapeshellarg($makefile), $ret, $err, $out)) {
if ($ret) {
logs('Error al compilar');
- logs("Código de retorno: $ret, mensaje: $err)", L_DBG);
+ logs("Código de retorno: $ret, mensaje: $err)", DEBUG);
//XXX $intento->informar_compilacion(false);
enviar_respuesta(R_ERR, $mail, "ERROR AL COMPILAR!\n\n$err\n\nCódigo de retorno: $ret\n", $intento);
continue;
// comienza la ejecución de casos de prueba
while ($prueba = $intento->pedir_caso_de_prueba()) {
- logs('Prueba: ' . $prueba->to_line(), L_DBG);
+ logs('Prueba: ' . $prueba->to_line(), DEBUG);
// ejecuta con fork
$pid = pcntl_fork();
if ($pid == -1) {
continue 2;
} elseif ($pid) {
// Estamos en el padre, controlamos el tiempo.
- logs("En el padre (hijo: $pid)", L_DBG);
+ logs("En el padre (hijo: $pid)", DEBUG);
// TODO controlar tiempo.
pcntl_waitpid($pid, $exitcode);
- logs("Fin de ejecución de caso de prueba (hijo: $pid, ret: $exitcode)", L_DBG);
+ logs("Fin de ejecución de caso de prueba (hijo: $pid, ret: $exitcode)", DEBUG);
$stderr = false; // FIXME ver si salida de error es vacia.
if ($exitcode or $stderr) {
- logs('Comando ejecutado ERROR', L_DBG);
+ logs('Comando ejecutado ERROR', DEBUG);
if ($ret) {
$msg = "El programa salió con código de error $ret";
$msgs[] = $msg;
- logs($msg, L_DBG);
+ logs($msg, DEBUG);
}
if ($stderr) {
$msg = "El programa imprimió mensajes en la salida de error: '$stderr'";
$msgs[] = $msg;
- logs($msg, L_DBG);
+ logs($msg, DEBUG);
}
$msg = join("\n", $msgs);
$intento->resultado_de_prueba($prueba, false, $msg);
enviar_respuesta(R_ERR, $mail, $msg, $intento);
exit(0); // salgo ok del hijo
} else { // Sin errores en la ejecución.
- logs('Comando ejecutado OK', L_DBG);
+ logs('Comando ejecutado OK', DEBUG);
// TODO
$salidas = array();
foreach ($prueba->salidas as $salida) {
$salidas[$salida] = file_get_contents($salida);
}
}
- logs('Salidas: ' . var_export($salidas, true), L_DBG);
+ logs('Salidas: ' . var_export($salidas, true), DEBUG);
$intento->resultado_de_prueba($prueba, true, 'Salidas: ' . var_export($salidas, true));
enviar_respuesta(R_ERR, $mail, 'Salidas: ' . var_export($salidas, true), $intento);
exit(0); // salgo ok del hijo
}
} else {
// Estamos en el hijo, corremos en chroot.
- logs('En el hijo', L_DBG);
+ logs('En el hijo', DEBUG);
// Hago chroot.
if (!@chroot('chroot')) {
$intento->resultado_de_prueba($prueba, false, 'Error al hacer chroot');
enviar_respuesta_error_log($mail, 'Error al hacer chroot', $intento);
exit(1); // salgo del hijo
}
- logs('Chrooteado, cwd = '.getcwd(), L_DBG);
+ logs('Chrooteado, cwd = '.getcwd(), DEBUG);
if (!@posix_setuid($usrinfo['uid'])) {
$intento->resultado_de_prueba($prueba, false, "Error al cambiar al uid '{$usrinfo['uid']}'");
enviar_respuesta_error_log($mail, "Error al cambiar al uid '{$usrinfo['uid']}'", $intento);
// TODO poner stdout y stderr en archivos para hacer diff o hacer diffs en memoria
$stdout = null;
if (in_array('stdout', $prueba->salidas)) $stdout = '';
- logs('Se ejecutará: chroot chroot /tp ' . escapeshellarg($prueba->params), L_DBG);
+ logs('Se ejecutará: chroot chroot /tp ' . escapeshellarg($prueba->params), DEBUG);
if (!pcntl_exec('/redir', array('tp', 'stdin', 'stdout', 'stderr', '/tp', '0', $prueba->params))) {
logserr('No se pudo ejecutar el comando');
$intento->resultado_de_prueba($prueba, false, 'No se pudo ejecutar el tp');
function enviar_respuesta($tipo, $to, $mensaje = '', $intento = null) {
$mconf = $GLOBALS['CONF']['mail'];
- $subject = $mconf['prefijo'] . ' Prueba ';
+ $subject = '[' . $NAME . '] Prueba ';
if ($tipo == R_OK) $estado = 'OK';
else $estado = 'ERROR';
$subject .= $estado;
$body .= "Estado: $estado\n";
if ($mensaje) $body .= "\n$mensaje\n";
if ($intento) $body .= "\n" . $intento->__toString() . "\n";
- logs("Envío de mail '$subject' a '$to'\n$body\n", L_DBG);
+ logs("Envío de mail '$subject' a '$to'\n$body\n", DEBUG);
$headers = <<<EOT
From: {$mconf['from']}
-Reply-To: {$mconf['mail_admin']}
-X-Mailer: {$mconf['mailer']}
+Reply-To: {$mconf['admin']}
+X-Mailer: $NAME $VERSION
X-Priority: 5
EOT;
mail($to, $subject, $body, $headers);
- mail($GLOBALS['CONF']['mail_admin'], $subject, $body, $headers);
+ //mail($mconf['admin'], $subject, $body, $headers);
return true;
}
function enviar_respuesta_error_log($to, $msg = '', $intento = null) {
logserr($msg);
enviar_respuesta(R_ERR, $to, "ERROR: $msg\n\nSe envió un mail al administrador para revisar el problema.\n", $intento);
- enviar_respuesta(R_ERR, $GLOBALS['CONF']['mail']['mail_admin'], $msg, $intento);
+ enviar_respuesta(R_ERR, $GLOBALS['CONF']['mail']['admin'], $msg, $intento);
}
?>
\ No newline at end of file