Reduce a filesystem, a logical volume and even a physical disk

June 27th, 2024 No comments

Imagine that your linux system is running on a 1To drive. At one point you needed 1To but nowaday you only use 70Go on it. You may want to transfer your system to a smaller drive either to :

  • Reuse this 1To physical drive in another system
  • Free up some space on your host if this 1To drive is a thick provisioned virtual hard drive

As a reminder, if this 1To drive is a virtual thin provisioned hard drive, you can reclaim the space by ensuring that your hypervisor is correctly configured to support discard on this drive, then run the fstrim command in the linux VM. The discard option in fstab would trim automatically

In the following example, the system is a debian VM using LVM and the hard drive will be changed from 32G to 10G.
My filesystem type on the root partition I’ll shrink is ext4 and I boot using UEFI

Before starting be sure you have a backup of your data. You could loose all your data if something goes wrong.
To be able to perform this operation, your filesystem should not be mounted.
In my case I’m shrinking the root filesystem so I’ll boot on a debian system installed on a second disk.
Another option would be to boot in the debian installation media and choose Advanced -> Rescue mode in the installer to get a shell and perform the commands. If you do so, ensure to answer “do not use a root file system” when the installer will ask what partition to use a the root filesystem.

Let’s start by identifying the drives and filesystem to reduce

root@debian:~# lsblk 
NAME                  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                     8:0    0    7G  0 disk 
├─sda1                  8:1    0  512M  0 part /boot/efi
├─sda2                  8:2    0  5.5G  0 part /
└─sda3                  8:3    0  976M  0 part [SWAP]
sdb                     8:16   0   32G  0 disk 
├─sdb1                  8:17   0  512M  0 part 
├─sdb2                  8:18   0  488M  0 part 
└─sdb3                  8:19   0   31G  0 part 
  ├─debian--vg-root   254:0    0 30.1G  0 lvm  
  └─debian--vg-swap_1 254:1    0  976M  0 lvm  
sdc                     8:32   0   10G  0 disk 
root@debian:~# fdisk -l /dev/sdb
Disk /dev/sdb: 32 GiB, 34359738368 bytes, 67108864 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0C445618-2828-451C-BBD8-3105C88F2D06

Device       Start      End  Sectors  Size Type
/dev/sdb1     2048  1050623  1048576  512M EFI System
/dev/sdb2  1050624  2050047   999424  488M Linux filesystem
/dev/sdb3  2050048 67106815 65056768   31G Linux LVM  

In my case the original hard drive is sdb and target is sdc.
sdb have 3 parition, sdb1 is the EFI parition, sdb2 is the boot partition and sdb3 is the LVM partition where my root and swap partition is located.

We will shrink “debian–vg-root” and move everything from sdb to sdc

Let’s see/confirm the current root filesystem size.

root@debian:~# mount /dev/debian-vg/root /mnt
root@debian:~# df -h | grep root
/dev/mapper/debian--vg-root   30G  1.7G   27G   6% /mnt
root@debian:~# umount /dev/debian-vg/root

To be able to reduce the logical volume root of the debian-vg volume group we must start be reducing the filesystem size.

We start by a forced fsck check on the filesystem

root@debian:~# e2fsck -f /dev/debian-vg/root 
e2fsck 1.47.0 (5-Feb-2023)
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/debian-vg/root: 38223/1970416 files (0.2% non-contiguous), 590657/7879680 blocks

Then reduce your filesystem with the resize2fs command. The -M option will reduce as much as possible. This command could be very long to execute depending to the size of the filesystem

root@debian:~# resize2fs -M /dev/debian-vg/root 
resize2fs 1.47.0 (5-Feb-2023)
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/debian-vg/root to 784869 (4k) blocks.
The filesystem on /dev/debian-vg/root is now 784869 (4k) blocks long.

Check the result

root@debian:~# mount /dev/debian-vg/root /mnt
root@debian:~# df -h | grep root
/dev/mapper/debian--vg-root  2.8G  1.7G  1.1G  62% /mnt
root@debian:~# umount /dev/debian-vg/root

Now let’s resize the LVM logical volume. Stay safe between the filesystem size and the lv size. A lv smaller than the filesystem will destroy it. Add at least ~1G to be safe. Here I resize to 6G as i want to keep enough free space on the root filesystem

root@debian:~# lvresize -L 6G /dev/debian-vg/root 
  WARNING: Reducing active logical volume to 6.00 GiB.
  THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce debian-vg/root? [y/n]: y
  Size of logical volume debian-vg/root changed from <30.06 GiB (7695 extents) to 6.00 GiB (1536 extents).
  Logical volume debian-vg/root successfully resized.

You can extend the filesystem to 100% of the logical volume if you want


root@debian:~# e2fsck -f /dev/debian-vg/root
e2fsck 1.47.0 (5-Feb-2023)
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/debian-vg/root: 38223/196224 files (0.2% non-contiguous), 474182/784869 blocks
root@debian:~# resize2fs /dev/debian-vg/root 
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/debian-vg/root to 1572864 (4k) blocks.
The filesystem on /dev/debian-vg/root is now 1572864 (4k) blocks long.

root@debian:~# mount /dev/debian-vg/root /mnt
root@debian:~# df -h | grep root
/dev/mapper/debian--vg-root  5.8G  1.7G  3.9G  30% /mnt
root@debian:~# umount /mnt 

Let’s run lsblk again

root@debian:~# lsblk 
NAME                  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                     8:0    0    7G  0 disk 
├─sda1                  8:1    0  512M  0 part /boot/efi
├─sda2                  8:2    0  5.5G  0 part /
└─sda3                  8:3    0  976M  0 part [SWAP]
sdb                     8:16   0   32G  0 disk 
├─sdb1                  8:17   0  512M  0 part 
├─sdb2                  8:18   0  488M  0 part 
└─sdb3                  8:19   0   31G  0 part 
  ├─debian--vg-root   254:0    0    6G  0 lvm  
  └─debian--vg-swap_1 254:1    0  976M  0 lvm  
sdc                     8:32   0   10G  0 disk 

The sdb3 parition is still 31G but it’s content is only 6G+976M + 512M of sdb1 + 488M of sdb2 = ~8G. It will fit in sdc. We can start to move our data to the new disk.

Let’s see again the partition table of sdb

root@debian:~# fdisk -l /dev/sdb
Disk /dev/sdb: 32 GiB, 34359738368 bytes, 67108864 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0C445618-2828-451C-BBD8-3105C88F2D06

Device       Start      End  Sectors  Size Type
/dev/sdb1     2048  1050623  1048576  512M EFI System
/dev/sdb2  1050624  2050047   999424  488M Linux filesystem
/dev/sdb3  2050048 67106815 65056768   31G Linux LVM

Then we need to replicate this on sdc. Of course the LVM partition will be smaller.
I start by creating a GPT disklabel (as I’m using EFI boot. If you are using “Legacy bios” you need to create a MBR disklabel with o instead of g and making the new system bootable will require extra step not explained here)

root@debian:~# fdisk /dev/sdc

Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS (MBR) disklabel with disk identifier 0x9cf3f81a.

Command (m for help): g
Created a new GPT disklabel (GUID: 3D38E71C-613D-5345-AA1B-8979A377E738).

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Now we will replicate the partition table of sdb to sdc.

root@debian:~# fdisk /dev/sdc

Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition number (1-128, default 1): 
First sector (2048-20971486, default 2048): 2048
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-20971486, default 20969471): +1048576

Created a new partition 1 of type 'Linux filesystem' and of size 512 MiB.

Command (m for help): t
Selected partition 1
Partition type or alias (type L to list all): 1
Changed type of partition 'Linux filesystem' to 'EFI System'.

Command (m for help): n
Partition number (2-128, default 2): 2
First sector (1050625-20971486, default 1052672): 1052672
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1052672-20971486, default 20969471): +999424

Created a new partition 2 of type 'Linux filesystem' and of size 488 MiB.

Command (m for help): n
Partition number (3-128, default 3): 3
First sector (1050625-20971486, default 2054144): 2054144
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2054144-20971486, default 20969471): 

Created a new partition 3 of type 'Linux filesystem' and of size 9 GiB.

Command (m for help): t
Partition number (1-3, default 3): 3
Partition type or alias (type L to list all): lvm

Changed type of partition 'Linux filesystem' to 'Linux LVM'.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3D38E71C-613D-5345-AA1B-8979A377E738

Device       Start      End  Sectors  Size Type
/dev/sdc1     2048  1050624  1048577  512M EFI System
/dev/sdc2  1052672  2052096   999425  488M Linux filesystem
/dev/sdc3  2054144 20969471 18915328    9G Linux LVM

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Let’s copy sdb1 to sdc1 and sdb2 to sdc2 (EFI and boot partition)

root@debian:~# dd if=/dev/sdb1 of=/dev/sdc1 bs=4k
131072+0 records in
131072+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 3.80218 s, 141 MB/s
root@debian:~# dd if=/dev/sdb2 of=/dev/sdc2 bs=4k
124928+0 records in
124928+0 records out
511705088 bytes (512 MB, 488 MiB) copied, 4.3996 s, 116 MB/s

We will now extend the lvm physical volume

root@debian:~# vgextend debian-vg /dev/sdc3 
  Physical volume "/dev/sdc3" successfully created.
  Volume group "debian-vg" successfully extended

Then move the volume group from sdb3 to sdc3.

root@debian:~# pvmove -v /dev/sdb3 /dev/sdc3
  Executing: /sbin/modprobe dm-mirror
  Creating logical volume pvmove0
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/root.
  Moving 1536 extents of logical volume debian-vg/root.
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/swap_1.
  Moving 244 extents of logical volume debian-vg/swap_1.
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/root.
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/swap_1.
  Archiving volume group "debian-vg" metadata (seqno 5).
  Creating debian--vg-pvmove0
  Loading table for debian--vg-pvmove0 (254:2).
  Loading table for debian--vg-root (254:0).
  Loading table for debian--vg-swap_1 (254:1).
  Suspending debian--vg-root (254:0) with device flush
  Suspending debian--vg-swap_1 (254:1) with device flush
  Resuming debian--vg-pvmove0 (254:2).
  Resuming debian--vg-root (254:0).
  Resuming debian--vg-swap_1 (254:1).
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/pvmove0.
  Creating volume group backup "/etc/lvm/backup/debian-vg" (seqno 6).
  Checking progress before waiting every 15 seconds.
  /dev/sdb3: Moved: 0.39%
  /dev/sdb3: Moved: 52.36%
  /dev/sdb3: Moved: 86.29%
  /dev/sdb3: Moved: 100.00%
  Polling finished successfully.

The last step is to remove sdb3 from the volume group

root@debian:~# pvs
  PV         VG        Fmt  Attr PSize   PFree  
  /dev/sdb3  debian-vg lvm2 a--  <31.02g <31.02g
  /dev/sdc3  debian-vg lvm2 a--   <9.02g   2.06g
root@debian:~# vgreduce debian-vg /dev/sdb3
  Removed "/dev/sdb3" from volume group "debian-vg"
root@debian:~# pvs
  PV         VG        Fmt  Attr PSize  PFree 
  /dev/sdb3            lvm2 ---  31.02g 31.02g
  /dev/sdc3  debian-vg lvm2 a--  <9.02g  2.06g

You can now halt the system, remove the sdb disk and boot on the new disk.
Depending on your OS and the UEFI, you may need to tell the EFI to boot on the right file on the new disk. For example, you use debian and proxmox, you will need to create a new boot entry

Categories: Uncategorized Tags:

Upgrade the firmware of Crucial MX500 SSD

June 27th, 2024 No comments

I was looking to upgrade the firmware of a MX500 SDD from M3CR043 to M3CR046

Crucial only provide update software for Windows. If you are using another system like Linux or macOS, you will have to create a bootable media from the ISO file provided by Crucrial (M3CR046_ISO.iso for this specific firmware version which can be downloaded from https://www.crucial.com/support/ssd-support/mx500-support (the ISO is inside the zip file))

I did not tried to burn the ISO to a CD (who still have CD-ROM in 2024 ? Not me.) may be it would have work directly. I took the option to create a bootable USB flash drive. It SHOULD be simple and easy. It was not (at least for me..)

I first created an USB key with belena etcher (it’s easy to use, work great and is multi plateform) but when I started my computer on the key, I got a “grub >” prompt

I then followed crucial documentation on how to create a bootable usb flash drive line by line, including using the Windows software they recommend to create the usb key. Guess what, it was not booting better.

I lost a bit of time to try many things I’ll not detail here but like another USB key, EFI vs MBR boot, some adjustment in the content of the USB key, etc…

So I decided to manualy load the linux os that is on the USB key with grub commands. This sounds a bit scary as if the software is not run correctly it’s unsure what can happen to the disk but:

  • I was ok to lose data on this disk as it was part of a RAID 5 system and I have backup
  • I deeply looked the content of the USB key (if you are curious, decompress corepure64.gz) and was confident of what I was going to do
  • I made boot test without any disk connected

So inside the key, the boot/isolinux/isolinux.cfg has the following content

DEFAULT tc
PROMPT 0
TIMEOUT 0
LABEL tc
KERNEL /boot/vmlinuz64
INITRD /boot/corepure64.gz
APPEND libata.allow_tpm=1 quiet base loglevel=3 waitusb=10 superuser mse-iso rssd-fw-update rssd-fwdir=/opt/firmware    

If you never used grub, it difficult to understand, but if you are a bit familiar with grub you see that the last 3 lines give us the information to give to grub. What we miss is the identifier of the USB key to boot on.

If you run ls in grub you will see an output like

grub> ls
(hd0)

If you SSD is connected (which is needed at some point if you want to update the firmware) you will see more then 1 entry when doing the ls command. To know which “hd” is the right to boot on run ls (hd0)/ on each entry you see, so that may also be ls (hd1)/, ls (hd1,1)/, ls (hd0,msdos1)/, etc. Most likely if you see an entry like (hdX,…) (entry with a “,”) this is likely not the good entry. The output of the right entry should look like this

grub> ls (hd0)/
boot/ efi/

I highly recommend to first try to boot without any disk inside your computer. This way you will only see the USB key when running ls and you will be sure to run ls (hd...)/ on the USB key. When your SDD will be in the computer (hd0) which was likely your USB key before may now be your SDD and the USB key may be (hd1) or something else. But by running ls (hd...) on all entry and by comparing the result with the result when only the USB key was connected, you are sure to identify easily the right (hd…).

To boot, enter the following line. Replace hd0 by the right hdx for you. Of course do not type “grub >”

grub> linux (hd0)/boot/vmlinuz64 root=ram1 libata.allow_tpm=1 base loglevel=3 waitusb=10 superuser mse-iso rssd-fw-update rssd-fwdir=/opt/firmware 
grub> initrd (hd0)/boot/corepure64.gz
grub> boot


If it doesn’t boot correctly, you may try to change root=ram1 by another ram number like root=ram0, root=ram2, etc..

Categories: Uncategorized Tags:

Install ESXi 7 with less than 4GB of RAM

July 19th, 2022 No comments

If you are looking a way to install ESXi with less than 4GB of memory, you’re on the right place.

Before starting, please note that ESXi 7 will use about 1.4GB for itself, so if you have less than 4GB of memory, you will end up with a very limited amount of RAM to run VMs. But that may be enough for a test system.

Like me, when googling on how to solve the issue, you probably ended up on this page https://open-sourced.be/installing-esxi-with-less-than-4gb-of-ram/

The problem is that with ESXi 7 you will not be able to edit update_precheck.py because of filesystem restriction preventing to alter files.
Please note that even if the file is called update_precheck.py it apply to fresh installation.
It’s interesting to see in update_precheck.py that the actual requirement is not 4GB but 4GB minus 3.125% = 4096M – 128MB = 3968MB
My system do have a 4GB of RAM but 192MB is used for the integrated video card, leaving me with 3804MB seen by the OS.

def memorySizeComparator(found, expected):
    '''Custom memory size comparator
    Let minimum memory go as much as 3.125% below MEM_MIN_SIZE.
    See PR 1229416 for more details.
    '''
    return operator.ge(found[0], expected[0] - (0.03125 * expected[0]))

def checkMemorySize():
    '''Check that there is enough memory
    '''
    mem = vmkctl.HardwareInfoImpl().GetMemoryInfo()
    if hasattr(mem, 'get'):
       mem = mem.get()
    found = mem.GetPhysicalMemory()

    MEM_MIN_SIZE = (4 * 1024) * SIZE_MiB
    return Result("MEMORY_SIZE", [found], [MEM_MIN_SIZE],
                  comparator=memorySizeComparator,
                  errorMsg="The memory is less than recommended",
                  mismatchCode = Result.ERROR)

If we can’t modify the file during the installation, let’s do it on the installation media.
To do that, you will need another computer (likely the one with which you created the installation media), a tool to compress/decompress the gzip format and an hexadecimal editor.

In my case I did the modification on macOS. On the root directory of the installation media, you will found a file called WEASELIN.V00, this file is a tar file compressed with gzip. Let’s uncompress it

$ file WEASELIN.V00 
WEASELIN.V00: gzip compressed data, max compression, original size modulo 2^32 2548792
$ mv WEASELIN.V00 WEASELIN.V00.gz
$ gzip -d WEASELIN.V00.gz 
$ file WEASELIN.V00 
WEASELIN.V00: tar archive

For a reason I did not look for, if you try to untar the file, you will get errors

$ tar xf WEASELIN.V00 
tar: Damaged tar archive
tar: Retrying...

If we can’t untar the file to directly edit upgrade_precheck.py, let’s edit the tar archive directly as a tar file is a collection of file “as is” (I mean there is no compression, no encoding, etc.)

So open WEASELIN.V00 in your favorite hexadecimal editor, in my case i used Hex Friend

Search for MEM_MIN, you will see MEM_MIN_SIZE = (4 * 1024) * SIZE_MiB, edit 4 by something fiting your need. In my case I changed 4 by 3

Save your change and compress WEASELIN.V00

$ gzip WEASELIN.V00 
$ mv WEASELIN.V00.gz WEASELIN.V00

Your are good to eject the installation media (close your terminal windows if you’re in your installation media directory) and retry the installation. Enjoy

Categories: Uncategorized Tags:

Trend / Prediction with RRDtool

December 4th, 2009 18 comments

I’ve not used RRDtool for a while and put back my attention on it few weeks ago. I found out that lots of new cool stuff are avalaible, like LSLSLOPE, LSLINT. These function return the parameters of the Least Squares Line (y = ax +b) approximating a dataset (LSLSLOPE return a, LSLINT return b).
This is interesting because with the function approximating your data you can graph a prediction of future data. Of course a Least Squares Line function will work best to approximate a dataset that tend to grow or shrink (like filesystem usage, memory usage, …) but not for data like temperature. I would say that if your data can be expressed in a percentage, an Least Squares Line can be fine. For data not tending to grow or shrink rrdtool provide some other function like TREND and PREDICT.

I will show how to use LSLSLOPE and LSLINT taking memory usage of a device as an example. My exemple will produce a graph like the following :
MemoryTrend

As you see, the graph show trend using two Least Squares Line function, one generated from the full dataset (dataset is starting 24 Oct 2009) and one generated only from last week data. Projection on time axis is done from 90% to 100% of memory usage and the date resulting of calculation for 90% and 100% of usage is displayed. I’ve seen lots of question asking how to do this but did not found any answer, so I hope that my example will provide an answer.

Here is the perl code I’m using to generate this graph. There is no Perl specific code, so it can be converted to a normal rrdtool command.

#! /usr/bin/perl
use RRDs;

$rrd_file = 'MEMORY.rrd';

RRDs::graph "MEMORY_Trend.png",
'--start', "10/24/2009",
'--end', "12/31/2009 00:00am",
'--title', "Memory Usage",
'--interlace', '--width=620', '--height=200',
"--color","ARROW#009900",
'--vertical-label', "Memory used (%)",
'--lower-limit', '0',
'--upper-limit', '100',
'--border','0',
'--rigid',

"DEF:used1=$rrd_file:used:AVERAGE",
"DEF:used2=$rrd_file:used:AVERAGE:start=10/24/2009",
"DEF:used3=$rrd_file:used:AVERAGE:start=-1w",
"DEF:used4=$rrd_file:used:AVERAGE:start=-2w",
"DEF:used5=$rrd_file:used:AVERAGE:start=-4w",
"DEF:free1=$rrd_file:free:AVERAGE",
"DEF:free2=$rrd_file:free:AVERAGE:start=10/24/2009",
"DEF:free3=$rrd_file:free:AVERAGE:start=-1w",
"DEF:free4=$rrd_file:free:AVERAGE:start=-2w",
"DEF:free5=$rrd_file:free:AVERAGE:start=-4w",

"CDEF:pused1=used1,100,*,used1,free1,+,/",
"CDEF:pused2=used2,100,*,used2,free2,+,/",
"CDEF:pused3=used3,100,*,used3,free3,+,/",
"CDEF:pused4=used4,100,*,used4,free4,+,/",
"CDEF:pused5=used5,100,*,used5,free5,+,/",

“LINE1:90″,
“AREA:5#FF000022::STACK”,
“AREA:5#FF000044::STACK”,

"COMMENT:                         Now          Min             Avg             Max\\n",
"AREA:pused1#00880077:Memory Used",
'GPRINT:pused1:LAST:%12.0lf%s',
'GPRINT:pused1:MIN:%10.0lf%s',
'GPRINT:pused1:AVERAGE:%13.0lf%s',
'GPRINT:pused1:MAX:%13.0lf%s' . "\\n",
"COMMENT: \\n",

'VDEF:D2=pused2,LSLSLOPE',
'VDEF:H2=pused2,LSLINT',
'CDEF:avg2=pused2,POP,D2,COUNT,*,H2,+',
'CDEF:abc2=avg2,90,100,LIMIT',
'VDEF:minabc2=abc2,FIRST',
'VDEF:maxabc2=abc2,LAST',

'VDEF:D3=pused3,LSLSLOPE',
'VDEF:H3=pused3,LSLINT',
'CDEF:avg3=pused3,POP,D3,COUNT,*,H3,+',
'CDEF:abc3=avg3,90,100,LIMIT',
'VDEF:minabc3=abc3,FIRST',
'VDEF:maxabc3=abc3,LAST',

"AREA:abc2#FFBB0077",
"AREA:abc3#0077FF77",
"LINE2:abc2#FFBB00",
"LINE2:abc3#0077FF",

"LINE1:avg2#FFBB00:Trend since 24 Oct 2009                      :dashes=10",
"LINE1:avg3#0077FF:Trend since 1 week\\n:dashes=10",
"GPRINT:minabc2:  Reach  90% @ %c :strftime",
"GPRINT:minabc3:  Reach  90% @ %c \\n:strftime",
"GPRINT:maxabc2:  Reach 100% @ %c :strftime",
"GPRINT:maxabc3:  Reach 100% @ %c \\n:strftime",

;

my $ERR=RRDs::error;
die "ERROR : $ERR" if $ERR;
Categories: RRDTool Tags: ,

Tiff to JPEG

December 20th, 2008 No comments
for file in `ls *.tiff`; do file2=`basename $file .tiff`;/bla/bin/tifftopnm "$file" | /bla/bin/pnmtojpeg > "$file2.jpg"; done
Categories: Unix Tags:

Per virtual user sa-learn training

December 17th, 2008 3 comments

Context

I use a LDA that use Virtual User, and store email in /some/path/mail/<domaine.tld>/<user>/, this is a quite standard way to do.
I also use spamassassin but wanted to have a per user bayes database and configuration. It’s still simple with spamc/spamd by running spamd -c --virtual-config-dir=/some/path/to/spamassassin/%d/%l ... and invoking spamc from you MTA with spamc -u ${recipient} -f -e /path/to/your/LDA so that i have user preference in /some/path/saconf/<domaine.tld>/<user>/.
Now I would like to provide 2 imap folder to users, LearnSpam and LearnHam so that they could train their bayes database.
Here the problem start, especially if you are not using one of the latest spamassassin version.

The bad way

What sa-learn command will you run to take care of LearnSpam and LearnHam folders ? sa-lean has an –username option, you may want to use that but this is not intended to be use in this case, it’s to be used when bayes database are stored in an SQL database instead of file (this is correctly documented in latest SA version). So don’t try sa-learn --username=<user>@<domaine.tld> --spam /some/path/mail/<domaine.tld>/<user>/.INBOX.LearnSpam/cur/* it will not work. Imagine how this can work ? it can’t, how sa-learn could convert <user>@<domaine.tld> to /some/path/saconf/<domaine.tld>/<user>/ ?

The good way

So the right command to use is sa-learn -p /some/path/saconf/<domaine.tld>/<user>/user_prefs --spam /some/path/mail/<domaine.tld>/<user>/.INBOX.LearnSpam/cur/* Using the -D (debug) option could be very helpfull to check if it’s work correctly, you must see dbg: bayes: tie-ing to DB file R/O /some/path/saconf/<domaine.tld>/<user>/bayes_toks

Categories: Unix Tags:

Backup file of multiple user with rsync

December 17th, 2008 No comments

root problem with rsync

Imagine that you want to backup the /home directory of server ‘A’ to server ‘B’ using rsync.

There is two way to do this :

  • You can run rsync on the server ‘A’, but if you want to correctly backup (I mean, having correct uid/gid/.. on backuped files) files you should connect to the server ‘B’ as root. I’m sure you don’t want to do that.
  • You can run rsync on the server ‘B’, but you should connect to ‘A’ with an user that can read all file in /home. This could be complicated depending of your gid managment.

When Tar start to be your best friend

So how can you do ? the solution would be to store (uid/gid/permission/..) information in a dedicated file, so that you can apply them if you need to restore data.
How can you do that ? I’m sure you are too lazy to write a shell/perl/python/.. script to do that. You’re right ! Use tar.
What ? What ? You want me to tar /home and rsync it ? Are you mad ? I don’t use rsync to transfer 20Go at each backup.

When 1 option and 2 lines can save you

Tar as an incremental option. This mean that you can make a 1st tar file with /home then you can do a 2nd tar file with only modified file since previous tar. This option is -g.
Here is a 2 lines shell script to do the job

gtar -g /var/backup/home/home-backup.snar -cpvzf /var/backup/home/home-backup.`/bin/date +%s`.tgz /home/
rsync --delay-updates -avz -e ssh /var/backup/home backupuser@'B':/var/backup/

–delay-updates is very important because if you don’t use it if ‘A’ crash when rsync is copying the .snar file (used to store incrementation information) you will miss it on ‘B’ and can’t retore tar file correctly.
-g only exist in GNU Tar. You may have to install it if you’re running *BSD. First check if you have a gtar binnary

Categories: Backup, Unix Tags: , ,

Misconfigured Perl install path

December 17th, 2008 No comments

I got a strange problem on a server. CPAN was installing module outside of perl @INC, this is quite a nightmare.
I found what was wrong and it was quite easy to solve.
Run this command:

# perl -V:'install.*'

Look at installprivlib and installarchlib. If they don’t match @INC you can change them at the end of perl Config.pm (in tie %Config, ‘Config’, {..})

To find your Config.pm file type

# perl -MConfig -le 'print $INC{"Config.pm"};'

If you only use CPAN to install module I guess you can just change PREFIX in the CPAN Config.pm (but I haven’t tested this)

N.B.: If you can’t find installprivlib and installarchlib in tie %Config just add them.

Categories: Perl Tags: ,

Getting human reading time info from RRD files

December 17th, 2008 No comments

You have a .rrd file but you don’t remember how much time RRAs can store data ? all right, no problem.

First save this Perl code into a .pl file.

$step = $1 if (m/step = (\d+)/);
$rows = $1 if (m/rra.*\.rows = (\d+)/);
if (m/(.*)\.pdp_per_row = (\d+)/) {
$pdp = $2; $time = $step*$rows*$pdp;
if ($time > 31536000) { $time = sprintf("%.2f year",$time/31536000) }
elsif ($time > 86400) { $time = sprintf("%.2f days",$time/86400) }
elsif ($time > 3600) { $time = sprintf("%.2f hours",$time/3600) }
print "$1: $step*$rows*$pdp = $time\n";
}

Assuming the filename of the script is rrd_info.pl, run this Shell command:

rrdtool info file.rrd | perl -n rrd_info.pl

Here is an output example:

rra[0]: 300*864*1 = 3.00 days
rra[1]: 300*864*5 = 15.00 days
rra[2]: 300*702*25 = 60.94 days
rra[3]: 300*840*125 = 364.58 days
rra[4]: 300*840*625 = 4.99 year
rra[5]: 300*864*1 = 3.00 days
rra[6]: 300*864*5 = 15.00 days
rra[7]: 300*702*25 = 60.94 days
rra[8]: 300*840*125 = 364.58 days
rra[9]: 300*840*625 = 4.99 year
rra[10]: 300*864*1 = 3.00 days
rra[11]: 300*864*5 = 15.00 days
rra[12]: 300*702*25 = 60.94 days
rra[13]: 300*840*125 = 364.58 days
rra[14]: 300*840*625 = 4.99 year

The formula is update step time * numbers of rows in the rra * pdp_per_row

Categories: Perl, RRDTool Tags: , ,

Booting NetBSD on Mac (iMac DV+)

December 17th, 2008 No comments

This is what to use to boot NetBSD MacPPC CD on an iMac DV+ (at least):

boot cd:,ofwboot.xcf netbsd.macppc

or

boot cd:0,ofwboot.xcf netbsd.macppc

You may not need to put netbsd.macppc depending of the CD


To boot on HD try this:

boot cd:,ofwboot.xcf hd:/nebtsd

or

boot cd:,ofwboot.xcf hd:13/nebtsd

Where 13 is the number of the netbsd partition (usualy near 13)

Categories: NetBSD Tags: ,