Wednesday, June 23, 2010

perlipc in CGI

Sometimes we need start a background process from CGI. When leave that CGI by closing page or window we wish to clean up what we have put in the background. This is perlipc get into role.

There is an example. I have a page displaying a list of network interfaces. I want to get a real time throughput(I/O) chart window when I click on one of these interfaces. Certainly it should be "UP". My solution is forking a poller in background. Poller keeps polling, calculating, and writing data to a shared memory segment. CGI reads from shared memory segment then draws chart for user.



+----------+ fork +------+
|chart page| ----------------> |poller|
+----------+ +------+
| ^
| |
|request |Shared Memory
| |
| +--------+ |
+------> | charter| <------+
+--------+


When click "Close" button on chart page, I need to clean up shared memory and kill the poller. This works fine.

This is the chart page:


...
...

defined (my $pid = fork) or die "Can't fork: $!";

if (!$pid) {
setsid;
open STDIN, '>/dev/null' or die "Can't read from /dev/null: $!";
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
exec '/usr/local/NPMS/bin/if_poller.pl', $val->{ip}, $val->{commstring}, $val->{if};
}
...
...

print <<ENDOFFORM;
<script type="text/javascript">
function clean_up() {
document.getElementById('form1').submit();
window.close();
}
</script>
<form id="form1" method="post" action="clean_poller.cgi">
<input name="pid" value="$pid" type="hidden">
<input name="close" value="Close" onclick="clean_up();" type="button">
</form>
ENDOFFORM



This is the clean_poller.cgi:


...
...
kill 'INT' => $in{'pid'};
...
...


This is the poller which trap SIGINT to gracefully exit after clean up resources:


...
...
my $EXIT = 0;
$SIG{INT} = sub {
$EXIT = 1;
};
...
...
while (1) {
...
...
do polling stuff
do {
IPC::Shareable->clean_up_all;
exit;
} if $EXIT;
...
...
}



Let me explain this whole thing:
1. User click one of the active interfaces("UP" state)
2. Open a new window
3. Before display chart, fork a poller
4. poller start to work in background
5. poller write data sample to shared memory segment
6. chart page request charter to draw a chart
7. charter read data sample from shared memory segment and draw
8. User click "Close" button
9. chart page request clean_poller.cgi before closing
10. clean_poller.cgi get pid and send a INT to it
11. clean_poller.cgi close window
12. poller get INT signal, clean up shared memory segment he created
13. poller exit
14. all resources get cleaned up

That's it!

Detail information refer to perlipc, IPC::Shareable, signal, fork, ...

Monday, June 21, 2010

SNMP read IfInOctets => great trend But what about the absolute throughput value?

Original Link

If you have ever tried to read the throughput value of an ethernet interface in and out using SNMP you may notice that it’s quite easy to get a nice trend graph using your favorite plotting tool (MRTG, zabbix,…) but when you try to get the actual throughput value the amount just never seems to be correct.

During this article I’ll try to explain how the Cisco IfInOctets and IfOutOctets work and what you need to do to get the right value.


1) What is the IfInOctets and IfOutOctets value:

The first thing you need to know is that a Cisco router holds it’s interface value in two tables IfTable and IfXTable, these are fully described in RFC1213/RFC2233.

- ifTable defines 32-bit counters for inbound and outbound octets

-ifXTable provides similar 64-bit counters, also called high capacity (HC) counters

The values we are interested in are IfInOctest, IfHCInOctest, IfOutOctest and IfHCOutOctests. For the sake of this article we will focus on the In values but know that the exact same logic also holds for the Out counters. So lets have a look at the two in Counters. Let’s have a look at what the Cisco documentation tell’s us about these two counters:

- IfInOctets: "The total number of octets received on the interface,
including framing characters. The reference OID is: 1.3.6.1.2.1.2.2.1.10

Lets query this value of interface eth0 of a CentOS Linux Server and see the result:

[root@buildbox55-64bit Perl]# snmpwalk -Os -c public -v2c 192.168.1.230 .1.3.6.1.2.1.2.2.1.10.2
ifInOctets.2 = Counter32: 77043026


- IfHCInOctets: "The total number of octets received on the interface,
including framing characters. This object is a 64-bit
version of ifInOctets. The reference OID is: 1.3.6.1.2.1.31.1.1.1.6

Lets query this value of interface eth0 of a CentOS Linux Server and see the result:

[root@buildbox55-64bit Perl]# snmpwalk -Os -c public -v2c localhost 1.3.6.1.2.1.31.1.1.1.6.2
ifHCInOctets.2 = Counter64: 78219248


As you can read, both values actually return the same data “Total number of octest received”, but we are faced with a first dilemma, you have two counters to poll, each returning a different absolute value and in some bizarre way both are giving you the Total number of octets received.

- IfInOctets 1.3.6.1.2.1.2.2.1.10

For us to understand this we need to know what the value is that is being returned. SNMP is a very basic protocol that runs on just about any network device,… The core idea behind SNMP is simplicity, generic usable and low footprint. To ensure the low footprint SNMP has very little to no intelligence built in. It just returns values you would like to monitor and relies on your toolset to harvest this data en make it usable for you.

The counter we are reading returns the amount of octets received since

- the boot of the device

- since the last rollover period

There are two concepts here that we need to explain be for the puzzle will start to fall together for you:

1) # of octets received => that means if you want to know the data throughput you will have to read the counter twice at time_slot1_value and then lets say 1 second later at time_slot2_value. To know the throughput of octets now subtract

time_slot2_value – time_slot1_value = total # of octets send

2) since the last rollover => as you can imagine the amount of octet bytes sent is just an increasing value and this number can grow really really fast. And this is where the 32bit / 64bit values come into play. In the old days with slow speed networks a 32bit value was used to store the # of octets send, once this 32bit value fill’s to it’s maximum the counter resets to Null and restarts it’s count until it reaches the maximum value again. As you can imagine on a slow speed network this 32bit value fill’s up quite gradually and rollover does not occur all that often. However on a high speed gigabit network a lot of packets are passing through the interface and a 32bit value in memory fill’s up much faster. The net problem with roll over is that at a certain point in time you will subtract time_slot1_value from time_slot2_value but time_slot2_value will be smaller than time_slot1_value thus giving you a negative net value. This is alright for trend,… analysis as long as it does not happen to often.

To give you an idea of how fast this rollover occurs:

- a 10 Mbps stream of back-to-back, full-size packets causes ifInOctets to wrap in just over 57 minutes.

- At 100 Mbps, the minimum wrap time is 5.7 minutes

- At 1 Gbps, the minimum is 34 seconds.

=> this means the 32bit value is just not good enough for modern high speed networks and you will almost always ant to resort back to the 64bit ifHCInOctets counter value.

To follow Cisco documenation: “

For interfaces that operate at 20,000,000 (20 million) bits per second or less, you must use 32-bit byte and packet counters. For interfaces that operate faster than 20 million bits per second, and slower than 650,000,000 bits per second, you must use 32-bit packet counters and 64-bit octet counters. For interfaces that operate at 650,000,000 bits/second or faster, 64-bit packet and octet counters must be used.

Correspondingly, Cisco IOS® Software does not support 64-bit counters for interface speeds of less than 20 Mbps. This means that 64-bit counters are not supported on 10 Mb Ethernet ports, only 100 Mb Fast-Ethernet and other high speed ports support 64-bit counters. “

3) Converting Octets to bits is the last part we need to understand if we want to know the bits per tick that pass through our network interface. To convert the amount of transmitted octets on the Ethernet network to bits we must multiply by 8.

The ending formula to know the #of bits being transferred between two ticks would thus be:

Value2-Value1 * 8 = # bits transferred

Sunday, June 20, 2010

Permission denied of shmget

When using IPC::Shareable as a non-root user, sometimes got this:


IPC::Shareable::SharedMem: shmget: Permission denied


Just because shared memory is same as regular file. If someone has already created this "file", you can not create it with the same name ($glue) unless your are root.

So, whoever your are, please clean up this shm after you done with it.

(tied VARIABLE)->remove;
IPC::Shareable->clean_up;
IPC::Shareable->clean_up_all;


Refer to: perldoc IPC::Shareable

find tips - about the last char

Packaging Moose binary need some CPAN source. I am using cpan2rpm. On my build box, I just use cpan to install Moose, then I knew that all the dependcies are ready. :)

Next I need to convert Moose to binary RPM, for all the source, I want to just get from ~/.cpan, but I always can not remember the -exec syntax for find. Here:

# find ~/.cpan/sources/authors/id -regex '.*\.tar\.gz$' -exec cp {} . \;

Thursday, June 17, 2010

Change IF-MIB ifTable update frequency

CentOS 5.5 x86_64
net-snmp-5.3.2.2-9

When I run this command to try to get the updated data for InOctets:

[root@buildbox55-64bit SPECS]# while [ 1 ]; do snmpwalk -Os -c MYCOMMUNITY -v2c localhost .1.3.6.1.2.1.2.2.1.10.2; sleep 1; done


It seems that the data does not change in a 30 seconds interval:

ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7925145
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505
ifInOctets.2 = Counter32: 7927505


That's ok for "Standard" SNMP poller with a minimum polling interval > 60 seconds. Now if I need a very short interval, say 3 seconds or even 1 seconds. This does not work well.

The solution is to change the IFTABLE_CACHE_TIMEOUT in net-snmp source, here is mine:

/usr/src/redhat/SOURCES/net-snmp-5.3.2.2/agent/mibgroup/if-mib/ifTable/ifTable_data_access.h

Change:

#define IFTABLE_CACHE_TIMEOUT 30

to:

#define IFTABLE_CACHE_TIMEOUT 1


then rebuild net-snmp and upgrade it. now it's working as expected:

[root@buildbox55-64bit SPECS]# while [ 1 ]; do snmpwalk -Os -c MYCOMMUNITY -v2c localhost .1.3.6.1.2.1.2.2.1.10.2; sleep 1; done
ifInOctets.2 = Counter32: 8087029
ifInOctets.2 = Counter32: 8087421
ifInOctets.2 = Counter32: 8087519
ifInOctets.2 = Counter32: 8087911
ifInOctets.2 = Counter32: 8088219
ifInOctets.2 = Counter32: 8088475
ifInOctets.2 = Counter32: 8088633
ifInOctets.2 = Counter32: 8088731
ifInOctets.2 = Counter32: 8088889
ifInOctets.2 = Counter32: 8088987
ifInOctets.2 = Counter32: 8089145
ifInOctets.2 = Counter32: 8089243
ifInOctets.2 = Counter32: 8089401
ifInOctets.2 = Counter32: 8089499
ifInOctets.2 = Counter32: 8089657
ifInOctets.2 = Counter32: 8090085
ifInOctets.2 = Counter32: 8090670
ifInOctets.2 = Counter32: 8090768
ifInOctets.2 = Counter32: 8091268
ifInOctets.2 = Counter32: 8091426
ifInOctets.2 = Counter32: 8091524
ifInOctets.2 = Counter32: 8091682
ifInOctets.2 = Counter32: 8091780
ifInOctets.2 = Counter32: 8091938
ifInOctets.2 = Counter32: 8092036
ifInOctets.2 = Counter32: 8092194
ifInOctets.2 = Counter32: 8092382
ifInOctets.2 = Counter32: 8092604
ifInOctets.2 = Counter32: 8092702
ifInOctets.2 = Counter32: 8092924
ifInOctets.2 = Counter32: 8093022
ifInOctets.2 = Counter32: 8093180
ifInOctets.2 = Counter32: 8093278
ifInOctets.2 = Counter32: 8093436
ifInOctets.2 = Counter32: 8093692
ifInOctets.2 = Counter32: 8093790
ifInOctets.2 = Counter32: 8093948
ifInOctets.2 = Counter32: 8094046
ifInOctets.2 = Counter32: 8094452
ifInOctets.2 = Counter32: 8094550
ifInOctets.2 = Counter32: 8094708
ifInOctets.2 = Counter32: 8094806
ifInOctets.2 = Counter32: 8094964
ifInOctets.2 = Counter32: 8095062
ifInOctets.2 = Counter32: 8095220
ifInOctets.2 = Counter32: 8095318
ifInOctets.2 = Counter32: 8095476
ifInOctets.2 = Counter32: 8095818
ifInOctets.2 = Counter32: 8095976

Tuesday, June 15, 2010

Emacs: Replace the standard perl-mode with cperl-mode

CPerlMode is a more advanced mode for programming Perl than the default PerlMode. To replace the standard perl-mode with cperl-mode in all cases you need the following in your ~/.emacs file (or your InitFile):

;;; cperl-mode is preferred to perl-mode
;;; "Brevity is the soul of wit"
(defalias 'perl-mode 'cperl-mode)


Alternatively, use:

(add-to-list 'auto-mode-alist '("\\.\\([pP][Llm]\\|al\\)\\'" . cperl-mode))
(add-to-list 'auto-mode-alist '("\\.\\([tT]\\)\\'" . cperl-mode))
(add-to-list 'interpreter-mode-alist '("perl" . cperl-mode))
(add-to-list 'interpreter-mode-alist '("perl5" . cperl-mode))
(add-to-list 'interpreter-mode-alist '("miniperl" . cperl-mode))


Or the more robust equivalent:

(mapc
(lambda (pair)
(if (eq (cdr pair) 'perl-mode)
(setcdr pair 'cperl-mode)))
(append auto-mode-alist interpreter-mode-alist))

Monday, June 14, 2010

Asterisk quick start guide

10-minute guide to Asterisk

Easy tips if you want to get Asterisk up and running on your Linux system within minutes:

* Download the tarball: Download the Asterisk stable distribution tarball from http://www.voip-info.org/wiki-Asterisk-mirrors.


* Build Asterisk: Unpack the tarball and run make to build it. After that, run make install.


* Install sample configuration: Run make samples after make install. This will install the standard sample configuration in the directory /etc/asterisk. Go there.


* Start Asterisk: The first time, start Asterisk in console mode with some debugging applied. If it does not start, check the hardware requirements.

# asterisk -vvvvc

* Don't change anything yet: Try to start Asterisk with NO changes to the config files. If it doesn't start then the problem is probably with your system hardware.


* Create a SIP account: Copy one of the device configs in the SIP configuration file sip.conf and change for one of your phones. You should only have to change the device id. Don't get fancy with authentication or NAT. Make sure the phone (see Asterisk phones) and your Asterisk server is on the same network, with no firewall and NAT device between them. If you want to learn more on how to get this configured, read the introdcution articles referenced to on the Asterisk page, the bottom half. (If you have a physical card, you can configure a card like an X100P instead of configuring SIP by making 2 small changes, see: http://www.digium.com/downloads/hw_article)


* Restart Asterisk: Either issue the RELOAD command at the command line interface or completly shutdown and restart Asterisk. (RELOAD should be sufficient but one of the 2 is required)


* Call the demo: test that phone by calling extension 1000 (assuming you have the sample extensions.conf). You should get the demo greeting and be able to do such things as ECHO test, leave voicemail for a sample mailbox. Instructions are in the demo greeting you will hear. How this works is explained in the extensions.conf demo file installed for you in the /etc/asterisk directory.


* Add another phone: If all of the above works then add your 2nd phone into sip.conf and add a dialplan for those 2 devices to extensions.conf so that they can call each other. (don't forget to RELOAD or restart)


* Choose a voice: Once things are working, you should decide if you want to use the default voice distributed with Asterisk, or install a professional third-party sound file collection made to replace the default voice. Voice Vector Media and others offer complete replacement sound file collections for free. In addition, inexpensive custom recording services are typically offered to allow you to customize the collection for your needs using the same voice.


* Start exploring Asterisk: If all of that works then start making fancy config files and using additional features. Maybe add a hardware card to connect your PSTN connection to your Asterisk or start experimenting with free SIP accounts on the Internet, like Free World Dialup.


Welcome to the growing Asterisk user base!

If you need more in-depth directions, see Asterisk Step-by-step Installation.

Sunday, June 13, 2010

Tell CPAN use wget only

vi /usr/lib/perl5/5.8.8/CPAN/Config.pm, add:
'dontload_hash' => {"Net::FTP" => 1, "LWP" =>1 },

then o conf:

ftp ""
links ""
ncftp ""
ncftpget ""
wget /usr/bin/wget

o conf commit

have fun!

Building RPMs from CPAN Distributions

This entry was written by Dave Cross, posted on February 8, 2010 at 1:01 PM , filed under CPAN. Bookmark the permalink.

This is the original link.

Regular readers will know that in the past I've shown some interest in building RPMs from CPAN distributions. It's been a while since I did much work in this area (although I do still release the occasional module to my RPM repository.

Over the weekend I was at FOSDEM and I attended Gabor's talk on packaging CPAN modules for Linux distributions. This has rekindled my interest in this area and I spent most of the train journey back from Brussels hacking around the area.

There's one thing that has been bothering me in particular recently. The standard RPM building mechanism (or, at least, the way it's configured in Fedora and Centos) does something incredible brain dead when trying to work out what other modules the current module depends on. It does it by parsing the source code and looking for "use" statements. This means that a module that might only be used in really obscure cases is going to be listed as a mandatory requirement for your module.

Gabor and I actually saw an example of this over the weekend when the Fedora packaging team raised a bug against Padre because it requires Win32::API. Padre, of course, only uses Win32::API when being used on Windows. And for that reason Win32::API is not listed as a dependency in its META.yml.

And that's, of course, where the RPM builders should be going to get a list of dependencies. META.yml contains the list of other modules that the author wants the module to depend on. This should be seen as the definitive list. Of course, there might be errors in that list - but that should be addressed by raising a bug against the module.

I've poked at this problem a few times, trying to work out how the RPM system parses the code and trying to replace that with code that looks at META.yml instead. But the RPM system uses a baroque system of interdependent macros and eventually they all lead to a piece of rather clunky Perl code. So each time I've approached this problem, I've backed off again.

The problem became more urgent when I wanted to package Plack for Fedora. Plack supports all sorts of hosting environments and therefore includes "use" statements loading a number of modules that most people will never use. Fedora includes Apache2, so Apache::Request (which is for Apache1) will never be available. It's not listed in META.YML, but it is used by one of the modules. The RPM build system was therefore insisting that it should be present. An impasse was reached.

Then I decided to turn the problem on its head. RPM building has two steps. You create a spec file for the RPM and then you build the RPM using the spec file and your original tarball. I started wondering if I could ensure that the spec had all of the requirements (from the META.yml). Once I'd done that I would only need to find some way to turn off the RPM build system's default behaviour.

People packaging CPAN modules for Fedora (and Centos) use a program called 'cpanspec' to generate spec files. I started digging into the code there in order to find out how to insert the list of correct dependencies.

Only to find that it has already been done. cpanspec is already doing the right thing and generating a list of 'Requires' statements from the data in META.yml.

Then all I needed to do was to see if I could turn off the (broken) default RPM build behaviour which was adding spurious extra dependencies. That proved to be easy too. It's just a case of adding %__perl_requires %{nil} to your .rpmmacros files.

So now all of my RPMs will have only the correct dependencies listed. This makes me very happy.

I suppose I should go back and rebuild all of the older ones too.

Oh, and because I've worked out a really easy way to generate this - here's a spreadsheet listing which CPAN modules are available as RPMs for Fedora. I plan to keep this list up to date (and make it much longer). [Link now fixed]

Comment for a customized spec file

Recently I need to build .rpm for ming-0.4.2. There is a perl-ext in the source tree and I need include it in .rpm:


[sean@Build-64bit SPECS]$ ./configure --prefix=/usr/local --enable-perl --disable-cpp


For C part, the original spec file is just fine, but for Perl part, I got "Installed but not packaged" error. After added missing files to spec %files section, I got working version. This is final version of ming.spec:


1 # Some distributions name their Freetype 2 package "freetype", while others
2 # name it "freetype2". You can define the name your distribution uses here.
3 %define freetype2 freetype
4
5 Summary: A SWF output library
6 Name: nMetrics-ming
7 Version: 0.4.2
8 Release: 1
9 License: LGPL
10 Group: System Environment/Libraries
11 Source: http://prdownloads.sourceforge.net/ming/nMetrics-ming-%{version}.tar.gz
12 URL: http://ming.sourceforge.net/
13 BuildRoot: %{_tmppath}/%{name}-%{version}-root
14 BuildRequires: %{freetype2}-devel zlib-devel giflib-devel libpng-devel
15 Requires: %{freetype2} zlib giflib libpng
16
17 %description
18 Ming is a C library for generating SWF ("Flash") format movies, plus a set of wrappers for using the library from C++ and popular script ing languages like PHP, Perl, Python, and Ruby.
19
20 %package devel
21 Summary: A SWF output library
22 Group: Development/Libraries
23 Requires: %{name} = %{version}
24 Requires: %{freetype2}-devel zlib-devel giflib-devel libpng-devel
25
26 %description devel
27 The ming-devel package includes the static libraries,
28 header files, and developer docs for the ming package.
29
30 Install ming-devel if you want to develop programs which
31 will use ming.
32
33 %prep
34 %setup -q
35
36 %build
37 %configure --enable-perl --disable-cpp
38 %__make %{?_smp_mflags}
39
40 %install
41 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
42 %__make %{?_smp_mflags} \
43 DESTDIR=$RPM_BUILD_ROOT \
44 docdir=$RPM_BUILD_ROOT%{_docdir}/%{name} \
45 pkgconfigdir=%{_libdir}/pkgconfig \
46 install
47
48 %clean
49 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
50
51 %post -p /sbin/ldconfig
52
53 %postun -p /sbin/ldconfig
54
55 %files
56 %defattr(-, root, root)
57 %doc README AUTHORS COPYING ChangeLog
58 %{_libdir}/libming*.so.*
59 %{_bindir}/*
60 %{_mandir}/man1/*
61 /usr/local/lib64/perl5/5.8.8/x86_64-linux-thread-multi/perllocal.pod
62 /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/SWF.pm
63 /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/SWF
64 /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/SWF
65 /usr/local/share/man/man3/SWF*
66
67 %files devel
68 %defattr(-, root, root)
69 %{_includedir}/*
70 %{_libdir}/*.a
71 %{_libdir}/*.la
72 %{_libdir}/libming.so
73 %{_libdir}/pkgconfig
74 %{_mandir}/man3/*
75
76 %changelog
77 * Tue Sep 02 2006 John Ellson
78 - Initial changelog entry


This is the diff output between this version and original version:


6c6
< Name: nMetrics-ming
---
> Name: ming
11c11
< Source: http://prdownloads.sourceforge.net/ming/nMetrics-ming-%{version}.tar.gz
---
> Source: http://prdownloads.sourceforge.net/ming/ming-%{version}.tar.gz
37c37
< %configure --enable-perl --disable-cpp
---
> %configure
61,65d60
< /usr/local/lib64/perl5/5.8.8/x86_64-linux-thread-multi/perllocal.pod
< /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/SWF.pm
< /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/SWF
< /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/SWF
< /usr/local/share/man/man3/SWF*


Comments:
1. I changed "Name:" tag(Line 6). And of course I changed tarball from ming-0.4.2.tar.gz to nMetrics-ming-0.4.2.tar.gz as you can see in the "Source:" tag(Line 11)
2. Add build options to "%configure" macro
3. Add files to "%files" section
4. The last thing not in spec file is that I changed "%{_prefix}" from default(/usr) to (/usr/local) by type this:


[sean@Build-64bit SPECS]$ rpmbuild -bb ming.spec --define '_prefix /usr/local'