Pages

Wednesday, December 03, 2014

rpm spec file magic

In Unix flavored Operating Systems various software packages are packaged along with the source file in the form of an rpm package. The rpm package contains the source rpm and the binary rpm, along with optional other dependent tools rpm packages that is needed for the main binary rpm to work. In earlier days it was achieved in the form of an tarball, which contains the configure script. The configure scripts calls the Makefile to build the final binary package that's finally ready to installed on that platform.


Here I plan to discuss some of the tricks I have learned in the rpm spec file.
The spec file contains various sections:
a) %description
b) %prep
c) %build
d) %install
e) %files
f) %package  ## This is optional section
g) %clean
h) %changelog

Some of these sections are self explanatory, like the %description, %clean and %changelog section. The most interesting things happen in the %build, %install and %files section.
In the %build and %install section you can write anything that you can write in a bash script, they understand the bash syntax and executes them.
The %files section however does not understand the bash scripting language, and only understand the rpm macros.
If you want to include addition packages in the same package.spec.in file, then the %package section comes handy, and you include a %package section for each additional rpm package you intend to produce.


The basic structure goes like this:
# This is a comment
Name:          my-package
Version:        1.0
Release:        %RPM_RELTAG%
Summary:     my package update release
Source:         %RPM_SOURCE%
License:        License info
Vendor:         The source code belong to
Packager:      The repackaging is done by
Group:          System Environment/Libraries
Requires:       my-package-tools
BuildRequires:  coreutils                  ##dependent packages needed to build this package

%description
This provides the my package which is very important for everyone.


%define debug_package %{nil}
## This is how you define a local variable (called prefix)
%define prefix  /lib/firmware/important/


%define MY_FILE_LIST %{expand:%( \
FW="" \
FW+=" a.bin" \    ## a file
FW+=" b.bin" \     ## b file
FW+=" c.bin"        ##c file
##FW+=" c1.bin" \   ##c1 file
FW+=" d.bin"        ##d file
FW+=" e.bin"    ##e file
FW+=" f.bin"    ## f file
echo $FW \
)}

%global flist() %{expand:%( \
files="%*" \
if [ -n "%{?1}" ] ; then \
for pkg in $files  \
do \
  echo "%%{prefix}/$pkg" \
done \
fi \
)}

%prep
%setup -n src



## The % build section is also common between the base rpm package and additional (tools) rpm package

%build
RM=rm
MD5SUM=/usr/bin/md5sum 
## md5sum is part of coreutils, hence it's mentioned in the BuildRequires

cd fw/
${RM} -fr checksum.txt

for FW in %{MY_FILE_LIST}; do \
        echo ${FW}; \
        ${MD5SUM} ${FW} >> checksum.txt; \
done

%install
install -d ${RPM_BUILD_ROOT}%{prefix}/
cd fw/



## This will install all the a.bin, b.bin etc files into the right place, no need list one by one
for FW in %{MY_FILE_LIST}; do \
        install ${FW} ${RPM_BUILD_ROOT}%{prefix};
done
install checksum.txt ${RPM_BUILD_ROOT}%{prefix}

## The tools rpm that this spec file produces installs the my_special_tool as part of it, and
## the % install section is common for both the base package and the addition (tools) package
# Install Tools files
install -d ${RPM_BUILD_ROOT}%{prefix}
cd ../tools
install -m 0755 -D my_special_tool ${RPM_BUILD_ROOT}%{prefix}

%files
%defattr(0664,root,root)
## This is the magic
% flist %MY_FILE_LIST
## Otherwise you have to install each individual file separately like
#% {prefix}/a.bin
#% {prefix}/b.bin
#etc

## Now comes information about the additional package
##
## Tools package
##

%package tools
Summary:        %{name} deployment tools
Group:          System Environment/Base
Requires:       special-tools >= 1.4-5

%description tools
This package provides the special deployment tool for the my software.

%files tools
%defattr(-,root,root,-)
%attr(700,root,root) %{prefix}/my_special_tool
%doc %{_mandir}/man8/my_special_tool.8.gz

%clean
rm -rf ${RPM_BUILD_ROOT}

%changelog
* Wed Dec 03 2014 Kongkon Jyoti Dutta
        - ABC-123 Releasing my special tool to the world


Tuesday, June 10, 2014

How to update the drive firmware in Linux



echo "Using firmware file $fwfile for upgrading $product on device $x…"

The process to download in Solid State Drive and Hard Disk Drive is a little different. In case of SDD we can burn the firmware in one command, but in case of HDD we need to write in a loop since there is a limitation of 0x80000 bytes on VFS module system call.



           if [ "$rev" != "$target_fw_ver" ]; then
               echo "Upgrading $disk_type firmware to version $target_fw_ver on $x i.e.$sg_dev..."
               if  [ "$disk_type" = "ssd" ]; then
                   sg_write_buffer --in=${fwfile} --mode=5 --id=0 $sg_dev
                   if [ $? -ne 0 ]; then
                       echo "Failed to upgrade SSD firmware on $x i.e.$sg_dev to version $target_fw_ver!" >&2
                       exit 1
                   fi
               else
                   # hdd firmware upgrade
                   bytes=`ls -l $fwfile | awk '{ print $5; }'`
                   start=0
       #length = 0x80000 Bytes
                   length=524288
                   while [ $start -lt $bytes ]; do
                       if let 'start+length>bytes'; then
                           let 'length=bytes-start'
                       fi
                       sg_write_buffer --in=$fwfile --skip=$start --offset=$start --length=$length --mode=0x7 --id=0 $sg_dev
                       if [ $? -ne 0 ]; then
                           echo "Failed to upgrade HDD firmware $x i.e.$sg_dev to version $target_fw_ver!" >&2
                           exit 1
                       fi
                       let start+=length
                   done
               fi