Softpanorama

May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

Net-SNMP

Net-SNMP package began life as UCD-SNMP, since it was originally sponsored and maintained by the University of California - Davis. It was renamed in version 5.0 and has moved to SourceForge. In fact, if you do install SNMP from CPAN, you get the 4.2.0 module from the UCD-SNMP package. It will probably work with most of what you see here, but I recommend getting the 5.1 package if you can.

Net-SNMP is a suite of applications used to implement SNMP v1, SNMP v2c and SNMP v3 using both IPv4 and IPv6. The suite includes:

Net-SNMP is available for many Unix and Unix-like operating systems and also for Microsoft Windows. Note: Functionality can vary depending on the operating system. Please see the README files for information specific to your platform.

Net-SNMP comes with plenty of RFC-defined MIB modules, usually stored in /usr/share/snmp/mibs. However, most of the really good info you want from an SNMP agent is stored in the proprietary Enterprise MIBs  These MIBs are stored in the ' enterprises' MIB subtree. Each vendor has its own identifier (e.g. ' cisco' , ' nortel' , etc ), and under that, the vendor is free to create all the subtrees and objects they want. But for you to be able to get to them, you need to get Net-SNMP to parse the definitions for all this great stuff. You need to get it to load the MIB modules for your enterprise MIBs.

This is really a two-part problem. First, where are you going to keep the MIB files themselves? Second, how are you going to get the files imported when you go to do SNMP queries? I' ll tell you how I did it, and hopefully you' ll e-mail me if you find some horrible deficiency in this method.

The documentation section contains detailed information on command line tools, installation, configuration etc.

If you are new to Net-SNMP or SNMP in general, then a good place to start is the tutorial section.

The download section contains the source code and binaries for various platforms.

Please see our project development pages located at Sourceforge as well.


Top Visited
Switchboard
Latest
Past week
Past month

NEWS CONTENTS

Old News

[Jan 21, 2011] Homebrew NMS Put It Together with Perl and NetSNMP by Charlie Schluting

August 29, 2007 | www.enterprisenetworkingplanet.com

Taking SNMP for a Walk

On to the useful stuff. Let's try out an SNMP query, using out old friend snmpwalk, which comes with the net-snmp software on most *nix hosts. The snmpget command is useful to get a single object, but if you want all information available down a certain branch of the tree, snmpwalk will do just that.

% snmpwalk -v2c -c public nermal 1.3.6.1.2.1.1.6
 SNMPv2-MIB::sysLocation.0 = STRING: "System administrators office"

Running snmpwalk on a specific OID, where nothing follows in the tree, is akin to using snmpget. However, if we bump it up a notch, we can get the entire system MIB:

% snmpwalk -v2c -c public nermal 1.3.6.1.2.1.1
 SNMPv2-MIB::sysDescr.0 = STRING: SunOS nermal.domain.com 5.10 Generic_118833-24 sun4u
 SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.3
 DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (338266757) 39 days, 3:37:47.57
 SNMPv2-MIB::sysContact.0 = STRING: "System administrator"
 …

Experiment with your network gear, and the private, instead of mgmt branch, under Internet to see what's available. In the Cisco MIB, we can get everything we'd ever want to know, including the ARP table, the Bridge table, and MAC address with port locations. Those are all standards-based OIDs, and the interesting Cisco-specific goodies are in the private tree, under 1.3.6.1.4.1.9.

Port numbers are difficult, since Cisco uses an interface identifier and a few layers of indirection to identify a specific port, but it is possible. Let's start off easier. We'll fetch the port descriptions (string assigned to a port) from our Cisco switch, so that we can ensure they are accurate based on our formatting standards and MAC address discovery information.

[Jan 21, 2011] Using the SNMP module from the Net-SNMP library by Rhys (Pilgrim)

Where to get Net-SNMP

You can get the Net-SNMP library package from http://net-snmp.sourceforge.net/. If you have RedHat Linux 9 or RedHat Enterprise Linux 3, you can install the net-snmp-5.0.9 packages from you installation CDs (or from RedHat Network, if you are fortunate enough to have access).

If you install from source, you will need to compile and install the libraries, then cd into the ' perl' directory and install the Perl module separately. If you install using RPMs from RedHat, you need the net-snmp-perl package and all of its dependencies. If you build from the src.rpm package, make sure you use --with perl_modules.

NOTE: If you use RPM, I highly recommend uninstalling the 5.0.9 packages provided by RedHat, getting the 5.1.x src.rpm, and rebuilding from there. Version 5.1 resolves a problem that causes ' make test' to fail any time you use MakeMaker. Everything actually works, but you can' t test anything.

Update:As of January, 2005, version 5.2.1 of Net-SNMP is available. I have had no trouble with it so far.

Do Not Confuse Net-SNMP with Net::SNMP!

The naming is unfortunate, but the SNMP module that comes with the Net-SNMP package is just ' SNMP' . The Net::SNMP module is a completely different beast. Confusing the two will get you in big trouble. To include it use
use SNMP;

Try Some Trivial Queries

Before we get to the advanced stuff, let' s make sure it' s working. You will need to have a device attached to the network that will respond to SNMP queries (you can use ' localhost' if snmpd is running). Edit the script below to suit your environment and try it.
#!/usr/bin/perl
use warnings;
use strict;
use SNMP;
use Socket;

# VARIABLES YOU SHOULD EDIT.
my $comm = 'public';    # EDIT ME!
my $dest = 'localhost'; # EDIT ME!
my $mib  = 'sysDescr';  # Toy with this to get different
                        # results.
my $sver = '2';         # EDIT ME!

# VARIABLES YOU SHOULD LEAVE ALONE.
my $sess; # The SNMP::Session object that does the work.
my $var;  # Used to hold the individual responses.
my $vb;   # The Varbind object used for the 'real' query.

# Initialize the MIB (else you can't do queries).
&SNMP::initMib();

my %snmpparms;
$snmpparms{Community} = $comm;
$snmpparms{DestHost} = inet_ntoa(inet_aton($dest));
$snmpparms{Version} = $sver;
$snmpparms{UseSprintValue} = '1';
$sess = new SNMP::Session(%snmpparms);

# Turn the MIB object into something we can actually use.
$vb = new SNMP::Varbind([$mib,'0']); # '0' is the instance.

$var = $sess->get($vb); # Get exactly what we asked for.
if ($sess->{ErrorNum}) {
  die "Got $sess->{ErrorStr} querying $dest for $mib.\n";
  # Done as a block since you may not always want to die
  # in here.  You could set up another query, just go on,
  # or whatever...
}
print $vb->tag, ".", $vb->iid, " : $var\n";

# Now let's show a MIB that might return multiple instances.
$mib = 'ipNetToMediaPhysAddress'; # The ARP table!
$vb = new SNMP::Varbind([$mib]);  # No instance this time.

# I prefer this loop method.  YMMV.
for ( $var = $sess->getnext($vb);
      ($vb->tag eq $mib) and not ($sess->{ErrorNum});
      $var = $sess->getnext($vb)
    ) {
  print $vb->tag, ".", $vb->iid, " : ", $var, "\n";
}
if ($sess->{ErrorNum}) {
  die "Got $sess->{ErrorStr} querying $dest for $mib.\n";
}

exit;
			

Whew! That' s a lot of code just for a couple of simple queries! There are a lot of comments, and the code demonstrates the two most common ways of getting SNMP data from an agent (single query or loop through some unknown number of instances). Your coding style may be more succint, and you may not need some of the error checking. Proceed without it at your own peril, though.

Now, We' ll Add Enterprise MIB Files

Look, I Just Want to Load One File!

Fine. Here' s the fastest - and most unwise - way to do it. It works, of course, but you' ll soon find that this method is rife with practical problems:
& SNMP::addMibFiles(" /path/to/some/file.mib" ); & SNMP::initMib(); 

So What' s So Bad About That?

Since you asked, I' ll tell you.

First, that' s a hard-coded path to a particular file. The path may change. The file name may change, which happens a lot when vendors mark the version of a MIB module in the file name. This method is extremely resistant to change.

Second, what if this MIB module requires that you load another module first? Done this way, you' ll probably have to load all of the pre-requisite files by hand before this one will work, especially if the prereqs are other enterprise MIB modules. There' s a better way. Let' s go back to the beginning and pretend we want to do things the Right Way(tm).

Where to Put the Files

If you installed from RPM, the MIB files the come with Net-SNMP are put in /usr/share/snmp/mibs (or /usr/local/share/snmp/mibs if you installed from source). Every time I added a group of related MIBs files, I put them in a subdirectory under this one. For example, I wrote a program called JScan, and put several subdirectories named JScan/APC, JScan/BayStack, etc. for a full path of /usr/share/snmp/mibs/JScan/APC. This kept all of the files separate (so ' rm -r ..../JScan' would get rid of them all in a pinch), but in a predictable and sensible place.

Then a second problem presented itself. I decided it was a pain to add that many search directories all of the time (discussed below), so I created a single directory /usr/share/snmp/mibs/JScan/everything that contains symbolic links to all of the actual files in all of the other directories. This is done at install time by this excerpt of the post-install script:

# Where $destdir is /usr/share/snmp/mibs in most cases... system " mkdir -p $destdir/JScan/everything ; cd $destdir/JScan/everything ; find .. -type f -exec ln -sf {} \\; " ;

I then installed the MIB files for other packages in other subdirs under /usr/share/snmp/mibs. Again, keeps things separate, but still in more or less the Right Place.

Known Problem: While this has not happened to me yet in practice, it is possible that two vendors may name their MIB files with the same name, in which case ' ln' above will return an error when it tries to create the second link. This has never happened to me yet, though I have the practice of pulling the RFC-based MIB files out of the vendor-supplied list before I split them up, which resolves a LOT of conflicts.

Get Perl to Read Your MIB Files

There are several ways to do this, but in my opinion the best way is as follows. Suppose I wanted to load the MIB modules ' S5-CHASSIS-MIB' , ' RAPID-CITY' , and all of their pre-requisites. I would do this: # Add the search directory. & SNMP::addMibDirs(" /usr/share/snmp/mibs/JScan/everything" ); # Load the modules AND their pre-reqs. & SNMP::loadModules(' S5-CHASSIS-MIB' , ' RAPID-CITY' ); # Wonder-Twin powers, ACTIVATE! & SNMP::initMib(); In the example shown, the directories /usr/share/snmp/mibs AND /usr/share/snmp/mibs/JScan/everything will be searched for a file with the S5-CHASSIS-MIB module. It will then load that file. Since the S5-CHASSIS-MIB also requires the S5-ROOT-MIB, those same directories will be searched again for the file containing THAT MIB module, and so on until all the necessary modules have been loaded, or until something fails. If I load a non-existent module THIS-AND-THAT on my system, I get: Cannot find module (THIS-AND-THAT): At line 1 in (none) You can, of course, turn this off and make it fail silently, but by default it won' t cause your script to fail. The MIB parsing errors can be turned on or off in your snmp.conf file.

Other Useful Bits

There are several other ways you can get Net-SNMP to add directories to your search path and/or automatically load MIB modules. See the snmp.conf(5) man page for more details, paying particular attention to the parts about the MIBS and MIBDIRS environment variables and the ~/.snmp/snmp.conf file, which might be more appropriate than making system-wide changes.

At this time, I would like to suggest that you go back to Try Some Trivial Queries and play for a bit. Re-write this code in your own style, taking the time to understand as much of it as possible. Try loading some MIB modules and querying new stuff from those modules. Get used to OIDs, IIDs, values, and MIB object definitions before you proceed to the next section, in which we start doing the dangerous stuff (changing things on a remote agent).


Setting MIB Object Values

Okay, so we' ve covered how to get Net-SNMP, load new MIB modules, and query some MIB objects. Suppose now that you want to use Net-SNMP to set the value of a read/write MIB object, such as sysName or sysLocation. This is actually pretty simple... most of the time. Take these two objects for instance. Here' s the code to set the value of sysName on a host: my $comm = ' ihavepower' ; # Use read/write community. my $dest = ' 10.1.1.1' ; # IP or DNS will work. my $sver = ' 2' ; # Use 1 for simple devices, and 3 if you # really know your SNMP security. my %snmpparms; $snmpparms{Community} = $comm; $snmpparms{DestHost} = inet_ntoa(inet_aton($dest)); $snmpparms{Version} = $sver; $snmpparms{UseSprintValue} = 1; my $sess = new SNMP::Session(%snmpparms); my $mib = ' sysName' ; my $instance = ' 0' ; # There' s only one instance of sysName. my $value = " New system name." ; my $vb = new SNMP::Varbind([$mib,$instance,$value]); # This does it! $sess-> set($vb); if ( $sess-> {ErrorNum} ) { print " Got $sess-> {ErrorStr} setting $mib on $host.\n" ; } This works for most things. However, I have run into a lot of trouble when trying to set values that aren' t strings or integers when I have set UseSprintValue to true, which I usually do, since subsequent queries using the same session make FAR more sense with UseSprintValue (which translates enums and some packed binary values into readable strings for the user). Setting packed binary values, in particular, is a pain. Fortunately, all you need is a second session to cure this: my $comm = ' ihavepower' ; # Use read/write community. my $dest = ' 10.1.1.1' ; # IP or DNS will work. my $sver = ' 2' ; # Use 1 for simple devices, and 3 if you # really know your SNMP security. my %snmpparms; $snmpparms{Community} = $comm; $snmpparms{DestHost} = inet_ntoa(inet_aton($dest)); $snmpparms{Version} = $sver; $snmpparms{UseSprintValue} = 0; ### NEW SESSION REQUIRED! my $sess2 = new SNMP::Session(%snmpparms); my $mib = ' some32BitMib' ; # Suppose it takes a packed IP. my $instance = ' 0' ; # Will vary with the MIB object. my $value = inet_aton($ipaddr); my $vb = new SNMP::Varbind([$mib,$instance,$value]); $sess2-> set($vb); if ( $sess2-> {ErrorNum} ) { print " Got $sess2-> {ErrorStr} setting $mib on $host.\n" ; } Note that it' s almost entirely the same except that UseSprintValue is set to zero when the SNMP session object is created.

Using VarLists

Sometimes you want to query a bunch of different SNMP values on the same device. You could query each of them one at a time, but if you want to conserve bandwidth or if you' re trying to keep several variables in sync it' s a lot easier to use a VarList.

So what' s a VarList? A VarList is a blessed reference to an array of Varbinds (so you can' t just do push @varbinds, $vb;in a loop and expect that to work). So basically, a VarList is a bunch of Varbinds stuck together so you can make many queries at once. Let' s walk through two examples of using VarLists and see how they work.

Here we create a VarList and query a device for the variables ' sysName' , ' sysDescr' , and ' sysLocation' . We' re assuming that the session is already created and we' re going to just query instance 0, since we know from experience that this is the only instance that exists for these MIB objects.

$MIB[0] = ' sysName' ; $MIB[1] = ' sysDescr' ; $MIB[2] = ' sysLocation' ; $vl = new SNMP::VarList([$MIB[0], 0], [$MIB[1], 0], [$MIB[2], 0]); @ANSWERS = $sess-> get($vl);

And that' s it! Instead of using one array constructor with " MIB, instance, value" inside of it like with a Varbind, you just create a list of them. Now let' s do that same query above, but this time we' ll use a loop to create an array of Varbinds. For this example, it' s trivial, but this can make for an elegant solution in some cases and save you a lot of code and a lot of bandwidth.

@MIBS = (' sysName' , ' sysDescr' , ' sysLocation' ); foreach $mib ( @MIBS ) { push @bunchovbs, new SNMP::Varbind([$mib,0]); } # Now the magic! $vl = new SNMP::VarList(@bunchovbs); @ANSWERS = $sess-> get($vl); This method is most useful when the instance number or the value you need in the Varbind is only known after some calculation AND you want to put several MIB objects in the same get or set action. Here' s a more useful example of using a VarList:
 
@MIBS = (' ifAdminStatus' , ' ifOperStatus' , ' ifSpeed' ); $vl = new SNMP::VarList([$MIBS[0]], [$MIBS[1]], [$MIBS[2]]); for ( $ifindex = 1 ; $ifindex < 25 ; $ifindex++ ) { @STATUS = $sess-> getnext($vl); if ( $STATUS[0] eq ' up' ) { print " Port $ifindex enabled.\n" ; } else next; print " Link status is $STATUS[1]. Speed is $STATUS[2].\n" ; } Now we skipped all the setup and there' s absolutely no error checking in the loop shown, but you can see how using VarLists can drastically shorten the process of getting (or setting) several MIB objects at once.

TIP: One problem I' ve come across when using VarLists in this way is that in some cases the getnext causes one of the MIB objects in the list to get a different instance number than the others. Suppose in the example above that the switch does not keep a value for ' ifOperStatus' at all if ' ifAdminStatus' is ' down' . If port 2 is disabled, then on the second query, the instance ID for $$vl[0] will be 2, but for the other two objects the instance will be 3 (assuming port 3 is enabled). The getnext is performed on all of the MIBs regardless of the success or failure or values of the other MIBs in the same query SNMP doesn' t magically ' know' you want the objects in your VarList to be in sync.

SO: When using VarLists, even though you' re querying them all at once and they share a packet, they are separate queries, so if you want them to stay in sync, you may need to add code to make sure they actually do. Check that all of the instance IDs are the same after each query and then do whatever is appropriate to resolve it when they turn up unequal. Sometimes a getnext will skip an instance, but going back and doing a get on that same instance will return the information you want.

Getting Many Values in ONE Query

So far, we have been using SNMP commands that were defined in version 1 of the SNMP specification: GET, GETNEXT, and SET. In version 2, the SNMP designers decided that they wanted a way to send a single query that would return N values of a single object, like doing 20 " GETNEXTs" at once. To do this, they created the GETBULK command.

The syntax for the getbulk method in the SNMP module is a little complicated. Here' s what perldoc has to say about it:

$sess-> getbulk(< non-repeaters> , < max-repeaters> , < vars> ) do an SNMP GETBULK, from the list of Varbinds, the single next lex- ico instance is fetched for the first n Varbinds as defined by < non-repeaters> . For remaining Varbinds, the m lexico instances are retrieved each of the remaining Varbinds, where m is < max-repeaters> .

So the first two arguments, non-repeaters and max-repeaters are integers that define how getbulk is going to behave, and the remaining arguments are Varbinds (or better, a VarList).

Now getbulk is a little tricky. It' s behaves like a bunch of getnext commands strung together. If non-repeaters is set to ' 4' , it will take the first four Varbinds in the list given and get their next values exactly once (as if you had used getnext on each of them). Then if we suppose that max-repeaters is set to ' 10' , getbulk will behave like a getnext on the remaining Varbinds 10 times as a list. So it doesn' t get the next 10 of the first Varbind, then get 10 of the next Varbind, and so on, but rather it does 10 getnext' s on the list (just as if you had used a for loop on a VarList).

So let' s take an example that I threw together that queries some basic stuff about a 24-port switch, and hopefully things will become clearer:

use SNMP; use Socket; # Set up the SNMP session. my %snmpparms = (); $snmpparms{DestHost} = inet_ntoa(inet_aton($host)); $snmpparms{Community} = ' public' ; $snmpparms{UseSprintValue} = ' 1' ; # readable! $snmpparms{Version} = ' 2' ; # MUST USE 2 for GETBULK! my $sess = new SNMP::Session(%snmpparms); # I prefer to use VarLists for this sort of thing, since # we have enough confusion without making the actual # getbulk() call complicated. my @vbs = (); foreach my $mib ( ' sysName' , ' sysDescr' , ' sysLocation' , ' sysUpTime' , ' ifIndex' , ' ifAdminStatus' , ' ifOperStatus' ) { push @vbs, new SNMP::Varbind([$mib]); } my $vl = new SNMP::VarList(@vbs); # We' ll keep our answers in these. my %sysStuff; my @ANSWERS; # Query the first four objects ONCE EACH, and store the # answers in the appropriate places in %sysStuff. # Then get ifIndex and ifAdminStatus 24 times and store # all of those reponses in @ANSWERS. ($sysStuff{Name}, $sysStuff{Descr}, $sysStuff{Location}, $sysStuff{UpTime}, @ANSWERS) = $sess-> getbulk(4, 24, $vl); # AT LAST! # Always, always, always... if ( $sess-> {ErrorNum} ) { die " Got " , $sess-> {ErrStr}, " during getbulk.\n" ; } # So $ANSWERS[0] now contains the first value of ifIndex. # $ANSWERS[1] contains the FIRST VALUE OF ifAdminStatus, # NOT the second value of ifIndex. # The remaining code could be MUCH simpler, but it' s done # this way to illustrate how the answers are returned. my @INDEXES; my @STATUS; for ( my $x = 0 ; @ANSWERS ; $x++ ) { # Smart people would probably use map() for this. # I' m not that smart... $INDEXES[@INDEXES] = shift @ANSWERS; $STATUS[@STATUS] = shift @ANSWERS; # So we round-robin between @INDEXES and @STATUS, # thus " unstriping" the responses stored in @ANSWERS. } print " Name: $sysStuff{Name}\n" ; print " Description: $sysStuff{Descr}\n" ; print " Location: $sysStuff{Location}\n" ; print " Uptime: $sysStuff{UpTime}\n" ; print " \n" ; # This now prints out clearly. for ( my $x = 0 ; $x < = $#INDEXES ; $x++ ) { print " INDEX: $INDEXES[$x] STATUS: $STATUS[$x]\n" ; }

So we asked for four non-repeaters, sysName, sysDescr, sysLocation, and sysUpTime. We also ask for 24 instances of ifIndex and ifAdminStatus. The first four objects are queried once each, then the 24 answers for ifIndex and ifAdminStatus are " striped" together, and we use a simple for loop to break them apart again.

Now, if this were a real program, we would have just used @ANSWERS directly in the outputfor loop at the bottom and done $x+=2 for each iteration and saved a lot of code and extra variables, but I digress...

Using the getbulk command with max-repeaters set to less than ' 2' is silly, though it can be used with non-repeaters set to ' 0' . There is no requirement to have any non-repeaters in your query.

WARNING: The getbulk command is not the Hold Grail of Supah-Queries. You can' t just ask it to return 1000 instances, because SNMP will only send one packet in reply. SNMP can' t fragment its responses into multiple UDP messages, and won' t send a single UDP message that would cause the IP packet to be fragmented either, so you' ll have to use getbulk with a little circumspection. I' ve found that I can safely pack about 75 small queries (for ' ifAdminStatus' , say) into a single getbulk, but that' s about it. CHECK YOUR RESPONSES!

NOTE: It should be noted that I haven' t tried to see if this limitation still exists in SNMP version 3 when using TCP instead of UDP. If anyone gets large queries to work using this - or any other - method, PLEASE let me know. You can imagine how much simpler it would make large queries.

Recommended Links

Net-SNMP

Net-SNMP - Wikipedia, the free encyclopedia

net-snmp | Download net-snmp software for free at SourceForge.net

Net-Snmp Tutorial

Debian Package Tracking System - net-snmp

Using SNMP and RRDTool on FreeBSD



Etc

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D


Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: March 12, 2019