El otro día dí una charlita un poquito larga de ssh/scp y screen
en el IATE, el lugar donde
laburo. En la misma hablo de ssh/scp básico, mas cómo
poner claves públicas/privadas y cómo usar el
ssh-agent para administrarlas (algo de lo que ya
hablé en este glob), mas otros temas como el X11 forwarding y
el agent-forwarding. Además hablé de screen, una
herramineta que se complementa muy bien con ssh. Dejo
las filminas acá.
El sábado pasado recibo un mail de un chango del laburo con subject «ayuuuudaaa urgenteeeeee»[sic]. Me dice que estaba boludeando el viernes a la noche cuando la máquina se quedó primero sin sonido y luego se tildaba. Cuando la quizo reiniciar no arrancó más. «dice algo de disco no booteable...».
El lunes caigo como siempre y me voy a verla. Efectivamente, decía algo de disco no booteable. Booteo con un GRML que tengo en un pendrive y descubro que el disco no tiene particiones.
Pánico.
El tipo está acá haciendo un posdoc en algo astronómico (literalmente) y todo su laburo está ahí dentro. No hay backups, como corresponde, así que me preparo a hacer un rescate de particiones.
En el mismo pendrive tengo un sistema con parted. Booteo con eso y trato de usar el rescue del parted. Naranja. Le pregunto cómo eran las particiones, etc. Me responde que él sólo instaló un Kubuntu por defecto. Por defecto Kubuntu crea una partición swap y una ext3 para / y eso es todo, lo cual hacía mas fácil lo que estaba por venir.
Reninicio en el GRML y con hexdump -C /dev/sda |
more me pongo a ver el contenido del diso a pelo. No es la
primera vez que hago malabares con particiones y MBRs, pero antes
lo hacía con una herramienta que creo que a esta ahora está
discontinuada (El programa se llamaba adecuadamente DiskEdit, de
una empresa que lleva el mismo nobre que un vino y que el apellido
del dueño, cuyo nombre es el mismo que el padre en Family Guy, y
que vienen haciendo Utilities para Windows desde que las hacían
para DOS) y que tenía visores especiales para estos sectores y
también editar FATs y un montón cosas útiles... en el universo
M$.
Primero confirmo que, efectivamente, el primer sector es un MBR
(al menos tiene el signature 0x55aa en los últimos dos
bytes), y toda la tabla
de particiones está vacía, pero que en el segundo sector parece
haber una copia. Agarro papel y lápiz, transcribo lo que parece
haber, pero al final resulta que no sólo tengo la mitad de los
datos, sino que es una partición muy chica.
Entonces me propongo buscar la partición ext3 a mano. Para ello tuve que averiguar cómo es que hace un ext3 para saber que la partición realmente es una ext3 y no cualquier verdura. Sabía que que sería con un magic, pero no tenía ni idea. Instalé las fuentes del 2.6.29 en mi laptop y me puse a mirar el código de ext3. Después de dar bastante vueltas, incluyendo seguir el código que se ejecuta cuando montás un filesystem ext3, donde podemos ver que usa un magic[3] y también la estructura del superblock del ext3, donde vemos que el offset del magic es 0x38.
Entonces el problema de encontrar un ext3 en un disco se reduce
a buscar un 0x53ef (fucking little endian) en la posición 0x38 de
un sector en el disco. Por suerte more tiene para
buscar, así que me siento a buscar toooodas las ocurrencias de
53 ef esperando que la dirección a la derecha termine
con 30 y que sean el 9no y el 10mo byte de la línea
(maldito 0 based).
Unos cuantos next después, tengo mi primer candidato. Pinta muy
bien, porque además lo estaba comparando con el mismo dump pero del
pendrive (que tengo formateado en ext2, y por suerte ext2 y ext3
comparten todas estas estructuras), y además pude ver algo que
tenía toda la pinta de ser un
uuid.
Saco que la dirección del magic es 0x80731038. A
eso le resto los 0x38 y me da que el superblock
empieza en 0x80731000, un lindo número redondito.
Pasado a decimal me dá el byte 2.155.024.384, unos
2GiB desde del comienzo del disco. ¡Pinta muy bien! El swap podría
estar primero, y ser de unos 2GiB.
Arranco un fdisk /dev/sda y al mostrar la tabla
(aún vacía) de particiones me dice que hay 16.065
sectores por cilindro*512 bytes por sector=
8.225.280 bytes por cilindro. Casi todas las distros
(en realidad creo que todas) particionan los discos por
cilindros[1], por lo que si el sector éste está justo al principio
de un cilindro...
Divido 2.155.024.384/8.225.280=...
(suspenso)[2]
262.000124494...
¡Damn! Casi lo tenía... Hmm, ¿y cuánto es lo que sobra?
(262.000124494-262)*8.225.280=... ¡1024!
¿Será que...?
Arranco un strace debugfs -R show_super_stats
/dev/sdb1 (la partición en mi pendrive) y veo que
¡efectivamente hace un seek de 1024 bytes dentro de la
partición para leer el superblock!
This is it. Con el 262 en la cabeza arranco fdisk
/dev/sda y creo dos particiones: un swap en los cilindros
1-261 y una linux del cilindro 262 en adelante. Guardo, salgo,
cruzo los dedos y corro un debugfs -R show_super_stats
/dev/sda1. ¡Fail! ¿Qué pasa? Reinicio y pruebo de nuevo, no
vaya a ser que el kernel no haya leído bien la nueva tabla de
particiones. Tampoco. ¿WTF?
Ah, duh, es sda2. Ok, debugfs -R
show_super_stats /dev/sda2... ¡Anda, el muy HDP anda! No lo
puedo creer. Me la juego: fsck -n /dev/sda2.
«Filesystem is clean» Damn, vamos de nuevo: fsck -n -f
/dev/sda2...
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sda2 sarasa sarasa...
¡Intacto! Pero el MBR no tiene un grub, así que hago el habitual proceso de reinstalar Grub, reinicio...
Bootea perfecto, y termina en un hermoso login. Satisfecho, me doy unas palmaditas en la espalda, cargo mis cosas y comienzo el fin de semana.
sysadmin rescue
[1] ... desperdiciando unos 8MiB entre el MBR y la primera partición
[2] Los perspicaces se darán cuenta al toque que eso no puede ni a ganchos dar entero.
[3] Son muy graciosos los magics de Reiser. Parece haber iniciado una moda que ahora usan los AdOlEsCeNtEs.
Acaba de terminar la edición 2009 de pyCamp. Esta vez vinieron cerca de 40 personas, lo cual hizo que hubiera más proyectos dando vueltas y mas gente en los proyectos. Fueron 4 días fantásticos llenos de ideas, código, reuniones, juegos, algo de alcohol y mucho mas. A diferencia del año pasado, esta vez vienieron algunos audaces con familia, no sé cómo les habrá ido.
Este año estuve mucho mas enganchado. El primer día hicimos un
schedule cuasi definitivo y en el momento se me ocurrió hacer cosas
con Fuse y Python. Cuando tocó el slot, di una charla de cómo
funciona Fuse y algunas puntas de cómo implementar file systems con
él. Al final del evento yo había terminado el wrapper que venía
haciendo hace unas semanas (ok, ok, falta statvfs) y
perrito se hizo un
filesystem para acceder los iPod. Lucio me hizo prometer ver cómo
combinar Fuse async con Twisted. También le estuve explicando
ctypes al Polako, con lo que creo que terminé de
entender el módulo y me ayudó a entender algunas cosas que había
hecho para el wrapper.
También estuve en el diseño y (re)implementación del bot de irc.
En apenas 2 días y medio ya tenemos el core y unos cuantos plugins,
y hay varios desarrolladores haciendo mas. Sólo faltan implementar
pedezos de infraestructura, sobre todo la parte de bases de datos,
pero me veo metiendo un par de plugins mas y ponerla en producción
muy muy pronto (en relaidad perrito le va a dar hosting). También
fue una oportunidad para (re)aprender Twisted, y enterarse de cosas
como que
no podés hacer asincrónico un proceso sincrónico, y de aprender
de boca de Guillo cómo usar bzr para laburar entre los
6 u 8 que metíamos código.
También estuve renegando los dos primeros días con el applet de batería de KDE4. Terminé encontrando (un bug en Solid)[https://bugs.kde.org/show_bug.cgi?id=187600] y aprendiendo detalles sobre Hal, D-Bus, algunos bastante oscuros y bizarros. Al mismo tiempo estuve viendo cómo se comportan los algoritmos de recarga de batería y de estimación de los tiempos de descarga y de descarga. Resulta que cuando está terminando de cargar se empieza a estirar el tiempo y los últimos 5 minutos pueden termiar siendo 20.
Estuvo genial poder conocer más gente y de volver a ver algunas caras conocidas (hace rato que no estaba en un evento de alguna comunidad). Entre los nuevos encontré a gente de Kde-ar como Leo u otros jugando con PyQt. Me encantó volver a sentir que programaba, ver unos proyectos arrancar y otros continuar a velocidades de la hostia, con features apareciendo como hongos y bugs desapareciendo como... bueno, no es una buena fecha para hablar de desapariciones :|
El último sprint estuvo genial; monitoreen la lista y/o el canal para enterarse de los resultados ;-)
When I arrived to pyCamp (I'm at pyCamp!) I was fighting with a battery applet bug. When the battery is almost full the applet got 'confused' and thought the battery just finished charging, and if it where showing the remaining time, it switched to charge percentage, which actually showed that it wasn't fully charged, but somewhere near 96% or so (this is wrong assuming the battery can fully charge up to 100%, as my 6 month old Dell battery). The problem was really that my code was checking if the remaining time were 0 or not. So I started from there down.
Down was it indeed. Seems like from time to time, when the
bettry is filling up, one can't ask hal about the remaining time.
Using qdbus to ask hal directly we get
this answer:
Error: org.freedesktop.Hal.NoSuchProperty
No property battery.remaining_time on device
This situation is not stable; sometimes I get the value I want. Not only that, when the battery is full, the values get horrobly wrong. Here's some samples (values are seconds since epoch and remaining time in seconds):
1237677446 1134
1237677746 261
1237677806 235
1237677866 313
1237677927 190
# at some moment in this gap the battery is fully charged
1237678167 188836
1237678227 152509
1237678287 112581
So I changed the algorithm to a more correct one; that is, ask if the battery is charging or discharging or none of those (in that case the battery is full) and show the time or the percentage accordingly. This works, except that it doesn't.
The problem has shifted to another place. Now I don't get the
signal when is_chaging goes false. With lshal
-m I can see the event:
11:48:46.823: computer_power_supply_battery_BAT0 property battery.rechargeable.is_charging = false
but I keep getting "Charging" from this code:
battery_data.value()["State"].toString()
where battery is a powermanagement data engine.
Interesting enough, if I close the applet and load it again (as
anyone debugging plasmoids, I'm using plasmoidviewer),
that line returns the correct value of "NoCharge",
which is what's spected.
I will try to file a bug against the data engine, or maybe Solid, and wait for the fix before comitting the fix to this bug.
Update: it ended being a bug in Solid, after all. I posted a fix.
I'm implementing a wrapper of a C library for Python. The
obvious choice is to write some C linked to libpython,
and the not so obvious but simpler one is to use
ctypes. ctypes is really simple to use:
it has ways to declare structures and function types, with several
classes that represents the simple types: c_int,
c_char, c_char_p, c_void_p,
etc.
Now, this library has a function, write(), that
handles a buffer. In this case, for buffer I mean a fixed size
space in memory with data, paired with an integer telling us how
much of the space is really data. So basically its declaration is
like this:
void (*write) (const char *buf, size_t size);
The void pointer is because this is the type of a struct member
that has to point to such a function. Looking at that declaration,
one would think that, assuming a c_size_t is already
declared with the correct type, the corresponding declaration in
ctypes is:
write_t = CFUNCTYPE(c_void_p, c_char_p, c_size_t)
This is what the
ctypes documentation calls a callback
function.
The problem arises with the c_char_p there. With
this class, ctypes assumes that the parameter is a
string, and not a buffer. Both strings and buffers in C are fixed
size space in memory. The difference between them is that strings
are \x00 ended, so its size it's determined by the
first occurence of a \x00 in the memory space, while a
buffer has to be accompanied by an integer, as I mentioned before.
A \x00 cannot occur in a string (the trailing one is
not always considered as part of the string per se), while
it can occur several times in a buffer. In fact, a buffer can be
entirely full of \x00's.
So what ctypes does here is to convert our buffer
into a string. Any occurence of a \x00 in the original
data will make c_char_p end the string and forget
about the rest of the data, ignoring the real size of the buffer.
Even more, if the original data has no \x00 in it,
ctypes might cause a segmentation fault trying to find
one beyond the process' memory space. This not only corrupts data,
but might even crash the app!
The solution is simple, luckly enough. You just neet to treat
your buffer as a void * instead of a char
*. So the declaration ends up being:
write_t = CFUNCTYPE(c_void_p, c_void_p, c_size_t)
The later, in our callback, we can convert that buffer into a
str()[1] to manipulate it as such:
def write(buf, size):
data = string_at(buf, size)
The size parameter is again important; if not,
string_at() will again think in terms of string and
not of buffer. I think this has to be improved a little. Maybe
next
PyCamp I'll file a bug and
develope a patch, either for the code or the documentation; maybe
both.
[1] This is Python 2.5
I'm implementing a wrapper of a C library for Python. The
obvious choice is to write some C linked to libpython,
and the not so obvious but simpler one is to use
ctypes. ctypes is really simple to use:
it has ways to declare structures and function types, with several
classes that represents the simple types: c_int,
c_char, c_char_p, c_void_p,
etc.
Now, this library has a function, write(), that
handles a buffer. In this case, for buffer I mean a fixed size
space in memory with data, paired with an integer telling us how
much of the space is really data. So basically its declaration is
like this:
void (*write) (const char *buf, size_t size);
The void pointer is because this is the type of a struct member
that has to point to such a function. Looking at that declaration,
one would think that, assuming a c_size_t is already
declared with the correct type, the corresponding declaration in
ctypes is:
write_t = CFUNCTYPE(c_void_p, c_char_p, c_size_t)
This is what the
ctypes documentation calls a callback
function.
The problem arises with the c_char_p there. With
this class, ctypes assumes that the parameter is a
string, and not a buffer. Both strings and buffers in C are fixed
size space in memory. The difference between them is that strings
are \x00 ended, so its size it's determined by the
first occurence of a \x00 in the memory space, while a
buffer has to be accompanied by an integer, as I mentioned before.
A \x00 cannot occur in a string (the trailing one is
not always considered as part of the string per se), while
it can occur several times in a buffer. In fact, a buffer can be
entirely full of \x00's.
So what ctypes does here is to convert our buffer
into a string. Any occurence of a \x00 in the original
data will make c_char_p end the string and forget
about the rest of the data, ignoring the real size of the buffer.
Even more, if the original data has no \x00 in it,
ctypes might cause a segmentation fault trying to find
one beyond the process' memory space. This not only corrupts data,
but might even crash the app!
The solution is simple, luckly enough. You just neet to treat
your buffer as a void * instead of a char
*. So the declaration ends up being:
write_t = CFUNCTYPE(c_void_p, c_void_p, c_size_t)
The later, in our callback, we can convert that buffer into a
str()[1] to manipulate it as such:
def write(buf, size):
data = string_at(buf, size)
The size parameter is again important; if not,
string_at() will again think in terms of string and
not of buffer. I think this has to be improved a little. Maybe
next
PyCamp I'll file a bug and
develope a patch, either for the code or the documentation; maybe
both.
[1] This is Python 2.5
No somos muchos en Córdoba. Tal vez uno 10, tal vez menos. Pero tenemos un objetivo común: hacer KDE, y hacerlo una mejor plataforma para nosotros, y para todo el mundo. Este objetivo tan amplio incluye desde desarrollar aplicaciones o simples features, arreglar bugs, hasta reportarlos, difundir un poco su potencia y lindura (no me pidan redacción a esta hora de la noche).
Por eso nos juntamos esta noche a tomar unas cervezas y ver en qué parte de este objetivo quiere estar cada uno, y hasta dónde cree llegar hoy día y slogan-de-una-empresa-gigantesca-de-software. Estuvimos Emanuel emanuel Sartori, Franco frapell Pellegrini, Manuel elpreto Ramírez y yo. Tomamos unos cafecitos, comimos unos tostaditos y charlamos.
Cosas concretas aún no tenemos; somos pocos, y si bien eso parece simplificar la organización, hace que sea difícil que pensemos en exactamente lo mismo. Lo que sí sabemos que ésta no es la última reunión, y que en las siguientes vamos a estar viendo de hacer lo que cada uno quiere aprovechando lo que el otro sabe. Esto puede parecer poco, pero la idea es fortalecernos con el tiempo.
Aún no hay fecha fija; queremos que sea la semana que viene, pero empiezan las clases y eso significa cambios de horarios para muchos. Ya avisaremos con anticipación en la lista kde-ar.
No somos muchos en Córdoba. Tal vez uno 10, tal vez menos. Pero tenemos un objetivo común: hacer KDE, y hacerlo una mejor plataforma para nosotros, y para todo el mundo. Este objetivo tan amplio incluye desde desarrollar aplicaciones o simples features, arreglar bugs, hasta reportarlos, difundir un poco su potencia y lindura (no me pidan redacción a esta hora de la noche).
Por eso nos juntamos esta noche a tomar unas cervezas y ver en qué parte de este objetivo quiere estar cada uno, y hasta dónde cree llegar hoy día y slogan-de-una-empresa-gigantesca-de-software. Estuvimos Emanuel emanuel Sartori, Franco frapell Pellegrini, Manuel elpreto Ramírez y yo. Tomamos unos cafecitos, comimos unos tostaditos y charlamos.
Cosas concretas aún no tenemos; somos pocos, y si bien eso parece simplificar la organización, hace que sea difícil que pensemos en exactamente lo mismo. Lo que sí sabemos que ésta no es la última reunión, y que en las siguientes vamos a estar viendo de hacer lo que cada uno quiere aprovechando lo que el otro sabe. Esto puede parecer poco, pero la idea es fortalecernos con el tiempo.
Aún no hay fecha fija; queremos que sea la semana que viene, pero empiezan las clases y eso significa cambios de horarios para muchos. Ya avisaremos con anticipación en la lista kde-ar.
Estoy organizado un code jam en Córdoba y Lisandro está organizando una en Bahía Blanca. La idea es que nos juntemos a laburar un poco en KDE, aprendiendo y haciendo o features o cerrando bugs o lo que sea. En función de eso estaría piola que cada uno ya lleve un kde trunk compiladito, al menos la parte que les interese. Este post apunta a explicar cómo hacerlo. Casi toda la info la saqué en su momento de techbase y/o preguntando en IRC, listas de correo y hasta en DebConf.
Veamos cómo se organiza el código de KDE. Éste reside en un repositorio subversion que tiene dos formas de acceso: uno autenticado por ssh para los desarrolladores que tienen cuenta y uno anónimo que es de sólo lectura. Los que ya tienen cuenta ya deberían saber usarlo y hasta cómo compilar, así que para ellos este post no sirve. Cuando mencioné a trunk en el párrafo anterior me refería a la rama principal de este repo.
A su vez el código está diseminado en distintos módulos: kdesupport, kdelibs, kdepimlibs, kdebase, etc. Estos módulos y otras porciones de código que andan dando vueltas están en un árbol:
anonsvn.kde.org/home/kde/
+ branches
| + ...
+ tags
| + ...
+ trunk
+ extragear
| + ...
+ kdereview
| + ...
+ playground
| + ...
+ kdesupport
| + ...
+ qt-copy
+ KDE
+ kdebase
+ kdegraphics
+ kdelibs
+ kdemultimedia
+ kdenetwork
+ kdepim
+ kdepimlibs
+ ...
Pueden ver este mismo árbol por
web. La rama KDE es la que tiene el código de los
distintos módulos de KDE. kdesupport contiene un
montón de software que no es de KDE, pero que es necesario para
correrlo. Allí van a encontrar las versiones adecuadas de los
mismos, y por lo general es muy aconsejable compilarlo.
qt-copy es una copia del código de Qt a su última
versión, con el agregado de varios parches. kdereview
son proyectos que están siendo considerados para la inclusión en
KDE. playground está llenos de proyectos a medias o
casi completos, pero que no tienen pinta de estar listos para
revisión. Los nuevos proyectos normalmente nacen y/o crecen allí.
Sin embargo, mucho de lo que hay ahí funciona. Por último,
extragear contiene aplicaciones KDE que no se ajustan
al ciclo de desarrollo de KDE (actualemnte, un release menor cada 6
meses). En este directorio podemos encontrar aplicaciones grosas
como el amarok, el k3b o el
digikam.
Una instalación mínima de KDE consta de los módulos
qt-copy, kdesupport,
kdelibs, kdepimlibs y
kdebase. Compilarlos uno por uno es un garrón, por lo
que vamos a usar kdesvn-build, un script que lo
automatiza todo. Pero antes, las dependencias.
Por un lado necesitamos las herramientas de configuración y de
compiloación. Éstas son cmake y g++ (en
realidad es cualquier compilador de C++, pero para hacerla fácil me
voy a limitar a g++. También me voy a limitar a
distros basadas en Debian, como *buntu, sólo porque es lo que más
conozco.). El cmake de Debian Sid es el 2.6.0 y desde
hace un rato KDE necesita el 2.6.2 [ Update: 2.6.2 acaba de
entrar en Sid ], así que capaz haya que bajar y compilar
ése también. Si lo hacen, les aconsejo que corran el
configure con la opción
--prefix=/usr/local o mejor, apuntando a algún lado de
su propio home. En mi caso, instalé todo en
~/local/soft/kde4.
Luego están las dependencias de cada módulo per se. La siguiente es una tabla que he ido creando con el tiempo y que trata de ser tan completa como pude, pero seguro se me ha escapado más de un paquete. Los nombres corresponden a los de los paquetes en Debian Sid, y que deben ser muy similares a los de los *buntu. En cada módulo encontramos dos grupos de dependencias: las estrictamente necesarias, sin las cuales el módulo no compila, seguido de una línea en blanco, seguida por otra lista con las dependencias opcionales. Estas dependencias hacen que el módulo ofrezca más funcionalidad. Yo puse las que me interesan; después veremos cómo ver qué otras son posibles.
cmake:
~~~~~~
libncurses5-dev
qt-copy:
~~~~~~~~
libssl-dev
libpng12-dev
zlib1g-dev
libsqlite3-dev
libxinerama-dev
libdbus-1-dev
libjpeg62-dev
libsm-dev
kdesupport:
~~~~~~~~~~~
cmake
mysql
libclucene-dev
doxygen
dotty
librdf0-dev
libbz2-dev
libxml2-dev
libexiv2-dev
libgstreamer0.10-dev
libgstreamer-plugins-base0.10-dev
libgl1-mesa-dev
libgamin-dev
sun-java6-jdk
kdelibs:
~~~~~~~~
libsm-dev
libpcre3-dev
libgif-dev
libxrender-dev
libglu1-mesa-dev
libopenexr-dev
libenchant-dev
libgamin-dev
kdepimlibs
~~~~~~~~~~
libical-dev
libgpg-error-dev
libgpgme11-dev
libboost-dev
libsasl2-dev
kdebase
~~~~~~~
libfontconfig1-dev
libxt-dev
libsensors4-dev
libxklavier12-dev
libusb-1.0-0-dev
libxcomposite-dev
libxdamage-dev
libxtst-dev
libusb++-dev
libasound2-dev
libxss-dev
libxft-dev
libxkbfile-dev
kdemultimedia
~~~~~~~~~~~~~
libvorbis-dev
libcdparanoia0-dev
libxine-dev
kdegraphics
~~~~~~~~~~~
liblcms1-dev
libgphoto2-2-dev
libxxf86vm-dev
libimlib2-dev
kdepim
~~~~~~
libopensync0-dev
libpisock-dev
extragear
~~~~~~~~~
libjasper-dev
kdenetwork
~~~~~~~~~~
libavahi-compat-libdnssd-dev
Muchas, eh? Y éstos son sólo algunos de los módulos.
Ah! Antes de que nos mandemos a compilar, tenemos que preparar
tres cosas: un directorio donde van a ir las fuentes, otro donde
vamos a compilar y otro donde lo vamos a instalar. Yo personalmente
prefiero mantener todo a nivel de usuario, por lo que las fuentes
las pongo en ~/src/system/kde4, compilo en
build dentro de ese directorio y lo instalo en
~/local/soft/kde4. El primero en realidad puede ser
cualquier directorio, realmente no es relevante, salvo por el
espacio que ocupa. Las fuentes de cada módulo (en MiB):
316 extragear[*]
549 kdebase
42 kdegraphics
185 kdelibs
18 kdemultimedia
106 kdenetwork
156 kdepim
41 kdepimlibs
10 kdereview
160 kdesupport
81 playground[*]
570 qt-copy
Los marcados con [*] no están completos, sino que elegí algunas cosas que me interesaban. Los directorios donde compilamos, también en MiB:
2146 build/extragear
1152 build/kdebase
253 build/kdegraphics
971 build/kdelibs
99 build/kdemultimedia
570 build/kdenetwork
1045 build/kdepim
194 build/kdepimlibs
33 build/kdereview
623 build/kdesupport
264 build/playground
1441 build/qt-copy
El último directorio sí me parece relevante; si no les gusta
instalarlo en su home, les aconsejo que lo hagan en
/opt o al menos en /usr/local, de forma
de no destruir lo que haya instalado sus sistemas.
Ok, suficiente introducción, vamos a los bifes. Bajamos
kdesvn-build en el directorio de compilación, lo
descomprimimos y lo configuramos. La configuración pasa por darle
algunos detalles de qué, cómo y dónde compilar e instalar. Pueden
tomar del kdesvn-buildrc-sample que viene incluido o
tomar del
que estoy usando yo. Revísenlo bien; la mayoría del trabajo es
configurar la sección global, que es la que está al
principio del archivo; está bastante comentada. Vean en particular
source-dir, build-dir,
kdedir (donde va a ser instalado), qtdir
(donde vamos a instalar qt-copy; yo lo puse en el
mismo directorio que todo kde4), svn-server (ojo que
mi copia apunta al servicio autenticado, pero tiene el anónimo
comentado), cmake-options, y lo que mas o menos les
pinte. Ponemos este archivo en ~/.kdesvn-buildrc y ya
casi estamos.
Otra cosa que hay que hacer es poner todo un conjunto de
variables de entorno a tono. Yo robé mucho de
un script en techbase. A diferencia de todos los tutoriales en
techbase, en vez de crear todo un usuario para hacer toda la bola,
yo simplemente puse todas esas variables en un
script que podía cargar a piaccere. Allí tambié puse que el
directorio donde KDE4 va a guardar la configuración es
.kde4-dev, así no me pisa la configuración de KDE3.
también péguenle una revisada así pega con lo que tienen puesto en
otros lados.
Bueno, ya estamos listos. Levantamos las variables de entorno y lanzamos el script de compilación:
$ source environ.sh
$ ./kdesvn-build-1.7.1/kdesvn-build --reconfigure --verbose --color
¡Eso es todo! El script saca los módulos unos a uno de svn; a medida que los tiene bajado los va compilando e instalando en paralelo. La primera vez tarda muchisimo, sobre todo si configuraron muchos módulos. Recomiendo compilar primero lo mínimo indispensable, dejarlo compilado de noche, y luego ir compilando de a pedacitos.
El script va dejando en log/latest logs de la
compilación de cada módulo. Allí podemos encontrar la salida del
proceso de configuración, donde veremos qué dependencias encontró y
cuáles faltan. Si hay errores deja un error.log con la
falla.
Para ejecutar la bestia, la cosa no se complica mucho mas. Yo no sé bien cómo hacer para que me lo tome el DM de turno (KDM, GDM, el que sea), por lo que lo lanzo a mano desde una terminal de texto:
$ source ~/src/system/kde4/environ.sh
$ xinit /home/mdione/local/soft/kde4/bin/startkde
También podemos lanzarlo en un Xephir, que es como un X dentro
de X. Eso sí, no le pidan OpenGL (necdesario para los efectos de
escritorio). Abrimos un konsole o la terminal que
prefieran y:
$ Xephyr :1 -screen 1280x800 -ac -extension GLX
$ export DISPLAY=:1
$ ~/local/soft/kde4/bin/startkde
Una forma truchísima mal es entrar en una sesión failsafe
(*buntu le llama 'Terminal a prueba de fallos' últimamente). Esto
nos da un X pelado con una xterm y ni siquiera un
Window Manager. En la terminal entramos levantamos el entorno y
lanzamos KDE4:
$ source ~/src/system/kde4/environ.sh
$ ~/local/soft/kde4/bin/startkde
Voilá. Sólo asegúrensé no cerrar nunca esa xterm, sino se les cierra todo sin preguntar nada.
Un detalle es que el sistema queda solamente en inglés. Ya me voy a sentar a ver cómo meter los módulos de traducción al español.
Ok, ya estoy cansadísimo y esto es larguísimo. Cualquier duda la seguimos en el thread en kde-ar y lo vamos puliendo.
Since a couple of hal versions
(0.5.12~git20090406.46dc48-1) in Debian Sid, it
stopped using system groups as the method to grant privileges to
users, and started using something called PolicyKit
instead. Just to remember what are we talking about here, a user in
the powerdevil group used to suspend or hibernate his
machine sucessfully. But now Mr. PL is a not-understood monster and
the package does not give a smooth transition. That's what I'll
try to do here.
To make sure this is the problem, let's try to suspend the
machine simply by calling hal through
d-bus. I use qdbus here, found in the
libqt4-dbus package, because it lets me introspect the
dbus interface, but you could use dbus-send
instead:
qdbus --system org.freedesktop.Hal /org/freedesktop/Hal/devices/computer org.freedesktop.Hal.Device.SystemPowerManagement.Suspend 0
Error: org.freedesktop.Hal.Device.PermissionDeniedByPolicy
org.freedesktop.hal.power-management.suspend no <-- (action, result)
If we edit the file /etc/PolicyKit/PolicyKit.conf
we'll see the empty default config that comes with the package.
According to its
documentation, we just need to add a couple of nested
<match> tags with a <return>
inside. The outher match will filter the
hal action, the inner one the group, and
the return will grant access.
... we wish! There's no way to match to a group, only to a user. Ok, the first shot will use the user, then we'll see if we really can do it.
How do we discover which action we must use? We can use
polkit-action to see what are the available actions.
In the first case,
org.freedesktop.hal.power-management.* will do.
<match action="org.freedesktop.hal.power-management.*">
<!--match group="powerdev"-->
<match user="mdione">
<return result="yes"/>
</match>
</match>
Now the previous command suspends the machine allright! Next, removable devices:
<match action="org.freedesktop.hal.storage.mount-removable">
<!--match group="plugdev"-->
<match user="mdione">
<return result="yes"/>
</match>
</match>
<match action="org.freedesktop.hal.storage.eject">
<!--match group="plugdev"-->
<match user="mdione">
<return result="yes"/>
</match>
</match>
I added the eject action just in case. All this
works fine for my user, but I really liked the group interface. The
complaining about it was that it was too coarse, and now this way
one can grant specific actions in amore fine grained way, but I
think is too fine grained. Unluckly we cannot (ab)use the
define_admin_auth tag to give a similar functionality,
it doesn't work that way (I don't know what way it works
either).
As a final note, see that I used a per-action approach, where the outer match points to an action. we could use a per-user approach, where the outer match points to a user:
<match user="mdione">
<match action="...">
<match action="...">
<match action="...">
</match>