Tuesday, April 17, 2012

Things you can do with packages based on time.

RPM keeps a history of installed things. In opensuse there is also a var log zypp history.  Here is an example of checking packages based on time.

    rpm -qa --qf '(%{INSTALLTIME:date})%{NAME}\n'

Will yield something like this:


 (Mon 20 Feb  2012  01:45:49  PM   UTC) libSDL-devel
 (Wed 30 Nov 2011  06:24:38  PM   UTC) kdebase4-workspace-liboxygenstyle
 (Sat   14 Apr  2012  07:27:40  AM   UTC) ffmpegthumbnailer
 (Wed 30 Nov 2011  06:19:28   PM  UTC) ptools
 (Thu  05 Jan   2012  07:41:54  AM   UTC) NetworkManager
 (Fri    11 Nov  2011  12:17:16  AM   UTC) xorg-x11-driver-video
 (Wed 01 Feb   2012  01:32:00  AM  UTC) libmysqlclient_r18
 (Wed 30 Nov  2011  09:22:45  PM   UTC) libwpg-0_2-2
 (Wed 30 Nov  2011  06:21:22  PM   UTC) gegl-0_1
 (Sun  01 Apr   2012  08:00:55  PM  UTC) glibc-locale-32bit


Ckecking /var/log/zypp/history

  while  IFS=\| read -ra line; do [[ $line = \#* ]] && continue; echo "${line[0]} -> ${line[2]}"; done < /var/log/zypp/history  

Or if you change your shell to something more advance :-), you can use awk.

 awk -F '|' '/^#/ {next} {printf("%s -> %s\n", $1, $3)}' /var/log/zypp/history 

Will yield something like this:


 2012-04-16 06:41:57 -> libquicktime0
 2012-04-16 06:42:23 -> avidemux
 2012-04-16 06:42:26 -> libswscale0
 2012-04-16 06:42:28 -> libpostproc50
 2012-04-16 06:42:41 -> libavcodec52
 2012-04-16 06:42:49 -> smplayer
 2012-04-16 06:42:54 -> gmplayer
 2012-04-16 06:43:02 -> mlt
 2012-04-16 06:43:40 -> kino
 2012-04-16 06:43:44 -> libavformat52
 2012-04-16 06:43:57 -> smplayer-themes
 2012-04-16 06:44:15 -> kdenlive
 2012-04-16 06:44:18 -> libavfilter1


If you want to know when a specific package was installed or updated you can just filter out the correct package name as shown on  below.

 rpm -qa --qf '(%{INSTALLTIME:date}) %{NAME}\n'  '*packagename*' 

Using awk to print out a certain field but in this example we just print out the whole line.

  awk '/packagename/{print $0}'  < <(rpm -qa --qf '(%{INSTALLTIME:date}) %{NAME}\n') 

Replace packagename with the correct one and you should be fine. That  looks good, now we want to take action about the packages that is based on a certain time/date. First we need to sanitize the packages names, meaning we only need to extract the names and not the date so we can take action (eg pass the output to zypper). Let us go back to the first example using rpm to query packages. IMHO a better tool for extracting only the names is awk. Here is an example.


 rpm -qa --qf '(%{INSTALLTIME:date}) %{NAME}\n' |  awk '/Sun 01 Apr 2012/{print $NF}'  


 will yield something like this:


 wavpack
 glibc-locale
 glibc-info
 libmp3lame0
 aircrack-ng
 vlc-qt
 glibc-32bit
 ladspa-lemux
 libmad0
 2ManDVD
 glibc-i18ndata
 glibc
 libfaac0
 faac
 twolame
 vlc
 glibc-devel
 liba52-0
 libzen0
 libxvidcore4
 xvidcore
 libvlc5



The awk code above looks for lines with the date 'Sun 01 Apr 2012' on it and then prints the last field so the result is just the package names that we are after. You can test the output without printing the last field by removing the last part of the code, then the awk code will be like   awk '/Sun 01 Apr 2012/' . You can even add the specific time (hours minutes and seconds) so you can have more control on the search, just add the end of the date of your awk code before the last /. After that you need  to pass it to zypper, fortunately bash4 has a builtin feature called mapfile aka readarray. This is an example of using mapfile for that, run this code as a normal user like the rest of the previous code.


    mapfile -t < <(rpm -qa --qf '(%{INSTALLTIME:date}) %{NAME}\n' | awk '/Sun 01 Apr 2012/{print $NF}')

  echo zypper rm "${MAPFILE[@]}"


You will see the out put of what zypper will remove from your installed packages. If you are satisfied with zypper's proposal then you can run that above code; again as root without the 'echo'  so that zypper can remove the packages. Remember that mapfile is a bash4 feature if your bash is lower than bash4 you can use read and IFS.



  IFS=$'\n' read -rd '' -a files < <(rpm -qa --qf '(%{INSTALLTIME:date}) %{NAME}\n' | awk '/Sun 01 Apr 2012/{print $NF}')

  echo zypper rm "${files[@]}"



  For those of you who change the default shell to something more advance :-). Try
 creating a script with a shebang  #!/bin/bash  and put the out put of the code:

   rpm -qa --qf '(%{INSTALLTIME:date}) %{NAME}\n' | awk '/Sun 01 Apr 2012/{print$NF}' ORS=" " > myscript


Now open that myscript with your favorite text editor and add the shebang then prefend   zypper rm   and a literal white space before the first package name then make it executable and  finally execute it.

I have done this only in a vm just for a proof of concept and it works as expected. I have never been in a situation where i am forced to do such hacks in my production system. For those of you who are adventurous enough to try tumbleweed release then this might be the solution if you ever get into desperate situations that needs desperate measures to solve  it :-).


Take it easy!