]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/commitdiff
fireinfo: Import latest changes from upstream.
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 2 Sep 2013 20:47:34 +0000 (22:47 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 2 Sep 2013 20:47:34 +0000 (22:47 +0200)
config/rootfiles/common/fireinfo
lfs/fireinfo
src/patches/fireinfo-2.1.7-testing.patch [new file with mode: 0644]

index ab7ecef0a557ea3883e0e96821d7f9d857c02a34..a4e209f941fdd5a04f5c5d7508f209e05e315569 100644 (file)
@@ -1,15 +1,27 @@
 usr/bin/sendprofile
-usr/lib/python2.7/site-packages/_fireinfo.so
 usr/lib/python2.7/site-packages/fireinfo
 usr/lib/python2.7/site-packages/fireinfo/__init__.py
 usr/lib/python2.7/site-packages/fireinfo/__init__.pyc
+usr/lib/python2.7/site-packages/fireinfo/__init__.pyo
+#usr/lib/python2.7/site-packages/fireinfo/_fireinfo.la
+usr/lib/python2.7/site-packages/fireinfo/_fireinfo.so
+usr/lib/python2.7/site-packages/fireinfo/bios.py
+usr/lib/python2.7/site-packages/fireinfo/bios.pyc
+usr/lib/python2.7/site-packages/fireinfo/bios.pyo
 usr/lib/python2.7/site-packages/fireinfo/cpu.py
 usr/lib/python2.7/site-packages/fireinfo/cpu.pyc
+usr/lib/python2.7/site-packages/fireinfo/cpu.pyo
 usr/lib/python2.7/site-packages/fireinfo/device.py
 usr/lib/python2.7/site-packages/fireinfo/device.pyc
+usr/lib/python2.7/site-packages/fireinfo/device.pyo
 usr/lib/python2.7/site-packages/fireinfo/hypervisor.py
 usr/lib/python2.7/site-packages/fireinfo/hypervisor.pyc
+usr/lib/python2.7/site-packages/fireinfo/hypervisor.pyo
 usr/lib/python2.7/site-packages/fireinfo/network.py
 usr/lib/python2.7/site-packages/fireinfo/network.pyc
+usr/lib/python2.7/site-packages/fireinfo/network.pyo
 usr/lib/python2.7/site-packages/fireinfo/system.py
 usr/lib/python2.7/site-packages/fireinfo/system.pyc
+usr/lib/python2.7/site-packages/fireinfo/system.pyo
+usr/share/doc/fireinfo
+usr/share/doc/fireinfo/COPYING
index 133111cdbd7466ea2617843085b6cdd3969a597d..3da01016129bd1c8e931d1dd116de76d76ef039d 100644 (file)
@@ -70,11 +70,12 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
-       cd $(DIR_APP) && python setup.py build
-       cd $(DIR_APP) && python setup.py install
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/fireinfo-2.1.7-testing.patch
 
-       # Remove egg-info
-       rm -rvf /usr/lib/python*/site-packages/fireinfo*.egg-info
+       cd $(DIR_APP) && [ -x "configure" ] || sh ./autogen.sh
+       cd $(DIR_APP) && ./configure --prefix=/usr
+       cd $(DIR_APP) && make $(MAKETUNING)
+       cd $(DIR_APP) && make install
 
        @rm -rf $(DIR_APP)
        @$(POSTBUILD)
diff --git a/src/patches/fireinfo-2.1.7-testing.patch b/src/patches/fireinfo-2.1.7-testing.patch
new file mode 100644 (file)
index 0000000..7690454
--- /dev/null
@@ -0,0 +1,4358 @@
+diff --git a/.gitignore b/.gitignore
+index 0caee61..92aa5c5 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,2 +1,31 @@
+-build
++/Makefile
++/build-aux
++/libtool
++/missing
++/src/fireinfo/__init__.py
+ *.py[co]
++/*.tar.bz2
++/*.tar.gz
++/*.tar.xz
++*.log
++*.a
++*.cache
++*.gmo
++*.la
++*.lo
++*.o
++*.stamp
++*.trs
++*~
++.deps
++.dirstamp
++.libs
++Makefile.in
++aclocal.m4
++config.h
++config.h.in
++config.log
++config.status
++configure
++install-sh
++stamp-*
+diff --git a/COPYING b/COPYING
+new file mode 100644
+index 0000000..94a9ed0
+--- /dev/null
++++ b/COPYING
+@@ -0,0 +1,674 @@
++                    GNU GENERAL PUBLIC LICENSE
++                       Version 3, 29 June 2007
++
++ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++                            Preamble
++
++  The GNU General Public License is a free, copyleft license for
++software and other kinds of works.
++
++  The licenses for most software and other practical works are designed
++to take away your freedom to share and change the works.  By contrast,
++the GNU General Public License is intended to guarantee your freedom to
++share and change all versions of a program--to make sure it remains free
++software for all its users.  We, the Free Software Foundation, use the
++GNU General Public License for most of our software; it applies also to
++any other work released this way by its authors.  You can apply it to
++your programs, too.
++
++  When we speak of free software, we are referring to freedom, not
++price.  Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++them if you wish), that you receive source code or can get it if you
++want it, that you can change the software or use pieces of it in new
++free programs, and that you know you can do these things.
++
++  To protect your rights, we need to prevent others from denying you
++these rights or asking you to surrender the rights.  Therefore, you have
++certain responsibilities if you distribute copies of the software, or if
++you modify it: responsibilities to respect the freedom of others.
++
++  For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must pass on to the recipients the same
++freedoms that you received.  You must make sure that they, too, receive
++or can get the source code.  And you must show them these terms so they
++know their rights.
++
++  Developers that use the GNU GPL protect your rights with two steps:
++(1) assert copyright on the software, and (2) offer you this License
++giving you legal permission to copy, distribute and/or modify it.
++
++  For the developers' and authors' protection, the GPL clearly explains
++that there is no warranty for this free software.  For both users' and
++authors' sake, the GPL requires that modified versions be marked as
++changed, so that their problems will not be attributed erroneously to
++authors of previous versions.
++
++  Some devices are designed to deny users access to install or run
++modified versions of the software inside them, although the manufacturer
++can do so.  This is fundamentally incompatible with the aim of
++protecting users' freedom to change the software.  The systematic
++pattern of such abuse occurs in the area of products for individuals to
++use, which is precisely where it is most unacceptable.  Therefore, we
++have designed this version of the GPL to prohibit the practice for those
++products.  If such problems arise substantially in other domains, we
++stand ready to extend this provision to those domains in future versions
++of the GPL, as needed to protect the freedom of users.
++
++  Finally, every program is threatened constantly by software patents.
++States should not allow patents to restrict development and use of
++software on general-purpose computers, but in those that do, we wish to
++avoid the special danger that patents applied to a free program could
++make it effectively proprietary.  To prevent this, the GPL assures that
++patents cannot be used to render the program non-free.
++
++  The precise terms and conditions for copying, distribution and
++modification follow.
++
++                       TERMS AND CONDITIONS
++
++  0. Definitions.
++
++  "This License" refers to version 3 of the GNU General Public License.
++
++  "Copyright" also means copyright-like laws that apply to other kinds of
++works, such as semiconductor masks.
++
++  "The Program" refers to any copyrightable work licensed under this
++License.  Each licensee is addressed as "you".  "Licensees" and
++"recipients" may be individuals or organizations.
++
++  To "modify" a work means to copy from or adapt all or part of the work
++in a fashion requiring copyright permission, other than the making of an
++exact copy.  The resulting work is called a "modified version" of the
++earlier work or a work "based on" the earlier work.
++
++  A "covered work" means either the unmodified Program or a work based
++on the Program.
++
++  To "propagate" a work means to do anything with it that, without
++permission, would make you directly or secondarily liable for
++infringement under applicable copyright law, except executing it on a
++computer or modifying a private copy.  Propagation includes copying,
++distribution (with or without modification), making available to the
++public, and in some countries other activities as well.
++
++  To "convey" a work means any kind of propagation that enables other
++parties to make or receive copies.  Mere interaction with a user through
++a computer network, with no transfer of a copy, is not conveying.
++
++  An interactive user interface displays "Appropriate Legal Notices"
++to the extent that it includes a convenient and prominently visible
++feature that (1) displays an appropriate copyright notice, and (2)
++tells the user that there is no warranty for the work (except to the
++extent that warranties are provided), that licensees may convey the
++work under this License, and how to view a copy of this License.  If
++the interface presents a list of user commands or options, such as a
++menu, a prominent item in the list meets this criterion.
++
++  1. Source Code.
++
++  The "source code" for a work means the preferred form of the work
++for making modifications to it.  "Object code" means any non-source
++form of a work.
++
++  A "Standard Interface" means an interface that either is an official
++standard defined by a recognized standards body, or, in the case of
++interfaces specified for a particular programming language, one that
++is widely used among developers working in that language.
++
++  The "System Libraries" of an executable work include anything, other
++than the work as a whole, that (a) is included in the normal form of
++packaging a Major Component, but which is not part of that Major
++Component, and (b) serves only to enable use of the work with that
++Major Component, or to implement a Standard Interface for which an
++implementation is available to the public in source code form.  A
++"Major Component", in this context, means a major essential component
++(kernel, window system, and so on) of the specific operating system
++(if any) on which the executable work runs, or a compiler used to
++produce the work, or an object code interpreter used to run it.
++
++  The "Corresponding Source" for a work in object code form means all
++the source code needed to generate, install, and (for an executable
++work) run the object code and to modify the work, including scripts to
++control those activities.  However, it does not include the work's
++System Libraries, or general-purpose tools or generally available free
++programs which are used unmodified in performing those activities but
++which are not part of the work.  For example, Corresponding Source
++includes interface definition files associated with source files for
++the work, and the source code for shared libraries and dynamically
++linked subprograms that the work is specifically designed to require,
++such as by intimate data communication or control flow between those
++subprograms and other parts of the work.
++
++  The Corresponding Source need not include anything that users
++can regenerate automatically from other parts of the Corresponding
++Source.
++
++  The Corresponding Source for a work in source code form is that
++same work.
++
++  2. Basic Permissions.
++
++  All rights granted under this License are granted for the term of
++copyright on the Program, and are irrevocable provided the stated
++conditions are met.  This License explicitly affirms your unlimited
++permission to run the unmodified Program.  The output from running a
++covered work is covered by this License only if the output, given its
++content, constitutes a covered work.  This License acknowledges your
++rights of fair use or other equivalent, as provided by copyright law.
++
++  You may make, run and propagate covered works that you do not
++convey, without conditions so long as your license otherwise remains
++in force.  You may convey covered works to others for the sole purpose
++of having them make modifications exclusively for you, or provide you
++with facilities for running those works, provided that you comply with
++the terms of this License in conveying all material for which you do
++not control copyright.  Those thus making or running the covered works
++for you must do so exclusively on your behalf, under your direction
++and control, on terms that prohibit them from making any copies of
++your copyrighted material outside their relationship with you.
++
++  Conveying under any other circumstances is permitted solely under
++the conditions stated below.  Sublicensing is not allowed; section 10
++makes it unnecessary.
++
++  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
++
++  No covered work shall be deemed part of an effective technological
++measure under any applicable law fulfilling obligations under article
++11 of the WIPO copyright treaty adopted on 20 December 1996, or
++similar laws prohibiting or restricting circumvention of such
++measures.
++
++  When you convey a covered work, you waive any legal power to forbid
++circumvention of technological measures to the extent such circumvention
++is effected by exercising rights under this License with respect to
++the covered work, and you disclaim any intention to limit operation or
++modification of the work as a means of enforcing, against the work's
++users, your or third parties' legal rights to forbid circumvention of
++technological measures.
++
++  4. Conveying Verbatim Copies.
++
++  You may convey verbatim copies of the Program's source code as you
++receive it, in any medium, provided that you conspicuously and
++appropriately publish on each copy an appropriate copyright notice;
++keep intact all notices stating that this License and any
++non-permissive terms added in accord with section 7 apply to the code;
++keep intact all notices of the absence of any warranty; and give all
++recipients a copy of this License along with the Program.
++
++  You may charge any price or no price for each copy that you convey,
++and you may offer support or warranty protection for a fee.
++
++  5. Conveying Modified Source Versions.
++
++  You may convey a work based on the Program, or the modifications to
++produce it from the Program, in the form of source code under the
++terms of section 4, provided that you also meet all of these conditions:
++
++    a) The work must carry prominent notices stating that you modified
++    it, and giving a relevant date.
++
++    b) The work must carry prominent notices stating that it is
++    released under this License and any conditions added under section
++    7.  This requirement modifies the requirement in section 4 to
++    "keep intact all notices".
++
++    c) You must license the entire work, as a whole, under this
++    License to anyone who comes into possession of a copy.  This
++    License will therefore apply, along with any applicable section 7
++    additional terms, to the whole of the work, and all its parts,
++    regardless of how they are packaged.  This License gives no
++    permission to license the work in any other way, but it does not
++    invalidate such permission if you have separately received it.
++
++    d) If the work has interactive user interfaces, each must display
++    Appropriate Legal Notices; however, if the Program has interactive
++    interfaces that do not display Appropriate Legal Notices, your
++    work need not make them do so.
++
++  A compilation of a covered work with other separate and independent
++works, which are not by their nature extensions of the covered work,
++and which are not combined with it such as to form a larger program,
++in or on a volume of a storage or distribution medium, is called an
++"aggregate" if the compilation and its resulting copyright are not
++used to limit the access or legal rights of the compilation's users
++beyond what the individual works permit.  Inclusion of a covered work
++in an aggregate does not cause this License to apply to the other
++parts of the aggregate.
++
++  6. Conveying Non-Source Forms.
++
++  You may convey a covered work in object code form under the terms
++of sections 4 and 5, provided that you also convey the
++machine-readable Corresponding Source under the terms of this License,
++in one of these ways:
++
++    a) Convey the object code in, or embodied in, a physical product
++    (including a physical distribution medium), accompanied by the
++    Corresponding Source fixed on a durable physical medium
++    customarily used for software interchange.
++
++    b) Convey the object code in, or embodied in, a physical product
++    (including a physical distribution medium), accompanied by a
++    written offer, valid for at least three years and valid for as
++    long as you offer spare parts or customer support for that product
++    model, to give anyone who possesses the object code either (1) a
++    copy of the Corresponding Source for all the software in the
++    product that is covered by this License, on a durable physical
++    medium customarily used for software interchange, for a price no
++    more than your reasonable cost of physically performing this
++    conveying of source, or (2) access to copy the
++    Corresponding Source from a network server at no charge.
++
++    c) Convey individual copies of the object code with a copy of the
++    written offer to provide the Corresponding Source.  This
++    alternative is allowed only occasionally and noncommercially, and
++    only if you received the object code with such an offer, in accord
++    with subsection 6b.
++
++    d) Convey the object code by offering access from a designated
++    place (gratis or for a charge), and offer equivalent access to the
++    Corresponding Source in the same way through the same place at no
++    further charge.  You need not require recipients to copy the
++    Corresponding Source along with the object code.  If the place to
++    copy the object code is a network server, the Corresponding Source
++    may be on a different server (operated by you or a third party)
++    that supports equivalent copying facilities, provided you maintain
++    clear directions next to the object code saying where to find the
++    Corresponding Source.  Regardless of what server hosts the
++    Corresponding Source, you remain obligated to ensure that it is
++    available for as long as needed to satisfy these requirements.
++
++    e) Convey the object code using peer-to-peer transmission, provided
++    you inform other peers where the object code and Corresponding
++    Source of the work are being offered to the general public at no
++    charge under subsection 6d.
++
++  A separable portion of the object code, whose source code is excluded
++from the Corresponding Source as a System Library, need not be
++included in conveying the object code work.
++
++  A "User Product" is either (1) a "consumer product", which means any
++tangible personal property which is normally used for personal, family,
++or household purposes, or (2) anything designed or sold for incorporation
++into a dwelling.  In determining whether a product is a consumer product,
++doubtful cases shall be resolved in favor of coverage.  For a particular
++product received by a particular user, "normally used" refers to a
++typical or common use of that class of product, regardless of the status
++of the particular user or of the way in which the particular user
++actually uses, or expects or is expected to use, the product.  A product
++is a consumer product regardless of whether the product has substantial
++commercial, industrial or non-consumer uses, unless such uses represent
++the only significant mode of use of the product.
++
++  "Installation Information" for a User Product means any methods,
++procedures, authorization keys, or other information required to install
++and execute modified versions of a covered work in that User Product from
++a modified version of its Corresponding Source.  The information must
++suffice to ensure that the continued functioning of the modified object
++code is in no case prevented or interfered with solely because
++modification has been made.
++
++  If you convey an object code work under this section in, or with, or
++specifically for use in, a User Product, and the conveying occurs as
++part of a transaction in which the right of possession and use of the
++User Product is transferred to the recipient in perpetuity or for a
++fixed term (regardless of how the transaction is characterized), the
++Corresponding Source conveyed under this section must be accompanied
++by the Installation Information.  But this requirement does not apply
++if neither you nor any third party retains the ability to install
++modified object code on the User Product (for example, the work has
++been installed in ROM).
++
++  The requirement to provide Installation Information does not include a
++requirement to continue to provide support service, warranty, or updates
++for a work that has been modified or installed by the recipient, or for
++the User Product in which it has been modified or installed.  Access to a
++network may be denied when the modification itself materially and
++adversely affects the operation of the network or violates the rules and
++protocols for communication across the network.
++
++  Corresponding Source conveyed, and Installation Information provided,
++in accord with this section must be in a format that is publicly
++documented (and with an implementation available to the public in
++source code form), and must require no special password or key for
++unpacking, reading or copying.
++
++  7. Additional Terms.
++
++  "Additional permissions" are terms that supplement the terms of this
++License by making exceptions from one or more of its conditions.
++Additional permissions that are applicable to the entire Program shall
++be treated as though they were included in this License, to the extent
++that they are valid under applicable law.  If additional permissions
++apply only to part of the Program, that part may be used separately
++under those permissions, but the entire Program remains governed by
++this License without regard to the additional permissions.
++
++  When you convey a copy of a covered work, you may at your option
++remove any additional permissions from that copy, or from any part of
++it.  (Additional permissions may be written to require their own
++removal in certain cases when you modify the work.)  You may place
++additional permissions on material, added by you to a covered work,
++for which you have or can give appropriate copyright permission.
++
++  Notwithstanding any other provision of this License, for material you
++add to a covered work, you may (if authorized by the copyright holders of
++that material) supplement the terms of this License with terms:
++
++    a) Disclaiming warranty or limiting liability differently from the
++    terms of sections 15 and 16 of this License; or
++
++    b) Requiring preservation of specified reasonable legal notices or
++    author attributions in that material or in the Appropriate Legal
++    Notices displayed by works containing it; or
++
++    c) Prohibiting misrepresentation of the origin of that material, or
++    requiring that modified versions of such material be marked in
++    reasonable ways as different from the original version; or
++
++    d) Limiting the use for publicity purposes of names of licensors or
++    authors of the material; or
++
++    e) Declining to grant rights under trademark law for use of some
++    trade names, trademarks, or service marks; or
++
++    f) Requiring indemnification of licensors and authors of that
++    material by anyone who conveys the material (or modified versions of
++    it) with contractual assumptions of liability to the recipient, for
++    any liability that these contractual assumptions directly impose on
++    those licensors and authors.
++
++  All other non-permissive additional terms are considered "further
++restrictions" within the meaning of section 10.  If the Program as you
++received it, or any part of it, contains a notice stating that it is
++governed by this License along with a term that is a further
++restriction, you may remove that term.  If a license document contains
++a further restriction but permits relicensing or conveying under this
++License, you may add to a covered work material governed by the terms
++of that license document, provided that the further restriction does
++not survive such relicensing or conveying.
++
++  If you add terms to a covered work in accord with this section, you
++must place, in the relevant source files, a statement of the
++additional terms that apply to those files, or a notice indicating
++where to find the applicable terms.
++
++  Additional terms, permissive or non-permissive, may be stated in the
++form of a separately written license, or stated as exceptions;
++the above requirements apply either way.
++
++  8. Termination.
++
++  You may not propagate or modify a covered work except as expressly
++provided under this License.  Any attempt otherwise to propagate or
++modify it is void, and will automatically terminate your rights under
++this License (including any patent licenses granted under the third
++paragraph of section 11).
++
++  However, if you cease all violation of this License, then your
++license from a particular copyright holder is reinstated (a)
++provisionally, unless and until the copyright holder explicitly and
++finally terminates your license, and (b) permanently, if the copyright
++holder fails to notify you of the violation by some reasonable means
++prior to 60 days after the cessation.
++
++  Moreover, your license from a particular copyright holder is
++reinstated permanently if the copyright holder notifies you of the
++violation by some reasonable means, this is the first time you have
++received notice of violation of this License (for any work) from that
++copyright holder, and you cure the violation prior to 30 days after
++your receipt of the notice.
++
++  Termination of your rights under this section does not terminate the
++licenses of parties who have received copies or rights from you under
++this License.  If your rights have been terminated and not permanently
++reinstated, you do not qualify to receive new licenses for the same
++material under section 10.
++
++  9. Acceptance Not Required for Having Copies.
++
++  You are not required to accept this License in order to receive or
++run a copy of the Program.  Ancillary propagation of a covered work
++occurring solely as a consequence of using peer-to-peer transmission
++to receive a copy likewise does not require acceptance.  However,
++nothing other than this License grants you permission to propagate or
++modify any covered work.  These actions infringe copyright if you do
++not accept this License.  Therefore, by modifying or propagating a
++covered work, you indicate your acceptance of this License to do so.
++
++  10. Automatic Licensing of Downstream Recipients.
++
++  Each time you convey a covered work, the recipient automatically
++receives a license from the original licensors, to run, modify and
++propagate that work, subject to this License.  You are not responsible
++for enforcing compliance by third parties with this License.
++
++  An "entity transaction" is a transaction transferring control of an
++organization, or substantially all assets of one, or subdividing an
++organization, or merging organizations.  If propagation of a covered
++work results from an entity transaction, each party to that
++transaction who receives a copy of the work also receives whatever
++licenses to the work the party's predecessor in interest had or could
++give under the previous paragraph, plus a right to possession of the
++Corresponding Source of the work from the predecessor in interest, if
++the predecessor has it or can get it with reasonable efforts.
++
++  You may not impose any further restrictions on the exercise of the
++rights granted or affirmed under this License.  For example, you may
++not impose a license fee, royalty, or other charge for exercise of
++rights granted under this License, and you may not initiate litigation
++(including a cross-claim or counterclaim in a lawsuit) alleging that
++any patent claim is infringed by making, using, selling, offering for
++sale, or importing the Program or any portion of it.
++
++  11. Patents.
++
++  A "contributor" is a copyright holder who authorizes use under this
++License of the Program or a work on which the Program is based.  The
++work thus licensed is called the contributor's "contributor version".
++
++  A contributor's "essential patent claims" are all patent claims
++owned or controlled by the contributor, whether already acquired or
++hereafter acquired, that would be infringed by some manner, permitted
++by this License, of making, using, or selling its contributor version,
++but do not include claims that would be infringed only as a
++consequence of further modification of the contributor version.  For
++purposes of this definition, "control" includes the right to grant
++patent sublicenses in a manner consistent with the requirements of
++this License.
++
++  Each contributor grants you a non-exclusive, worldwide, royalty-free
++patent license under the contributor's essential patent claims, to
++make, use, sell, offer for sale, import and otherwise run, modify and
++propagate the contents of its contributor version.
++
++  In the following three paragraphs, a "patent license" is any express
++agreement or commitment, however denominated, not to enforce a patent
++(such as an express permission to practice a patent or covenant not to
++sue for patent infringement).  To "grant" such a patent license to a
++party means to make such an agreement or commitment not to enforce a
++patent against the party.
++
++  If you convey a covered work, knowingly relying on a patent license,
++and the Corresponding Source of the work is not available for anyone
++to copy, free of charge and under the terms of this License, through a
++publicly available network server or other readily accessible means,
++then you must either (1) cause the Corresponding Source to be so
++available, or (2) arrange to deprive yourself of the benefit of the
++patent license for this particular work, or (3) arrange, in a manner
++consistent with the requirements of this License, to extend the patent
++license to downstream recipients.  "Knowingly relying" means you have
++actual knowledge that, but for the patent license, your conveying the
++covered work in a country, or your recipient's use of the covered work
++in a country, would infringe one or more identifiable patents in that
++country that you have reason to believe are valid.
++
++  If, pursuant to or in connection with a single transaction or
++arrangement, you convey, or propagate by procuring conveyance of, a
++covered work, and grant a patent license to some of the parties
++receiving the covered work authorizing them to use, propagate, modify
++or convey a specific copy of the covered work, then the patent license
++you grant is automatically extended to all recipients of the covered
++work and works based on it.
++
++  A patent license is "discriminatory" if it does not include within
++the scope of its coverage, prohibits the exercise of, or is
++conditioned on the non-exercise of one or more of the rights that are
++specifically granted under this License.  You may not convey a covered
++work if you are a party to an arrangement with a third party that is
++in the business of distributing software, under which you make payment
++to the third party based on the extent of your activity of conveying
++the work, and under which the third party grants, to any of the
++parties who would receive the covered work from you, a discriminatory
++patent license (a) in connection with copies of the covered work
++conveyed by you (or copies made from those copies), or (b) primarily
++for and in connection with specific products or compilations that
++contain the covered work, unless you entered into that arrangement,
++or that patent license was granted, prior to 28 March 2007.
++
++  Nothing in this License shall be construed as excluding or limiting
++any implied license or other defenses to infringement that may
++otherwise be available to you under applicable patent law.
++
++  12. No Surrender of Others' Freedom.
++
++  If conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License.  If you cannot convey a
++covered work so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you may
++not convey it at all.  For example, if you agree to terms that obligate you
++to collect a royalty for further conveying from those to whom you convey
++the Program, the only way you could satisfy both those terms and this
++License would be to refrain entirely from conveying the Program.
++
++  13. Use with the GNU Affero General Public License.
++
++  Notwithstanding any other provision of this License, you have
++permission to link or combine any covered work with a work licensed
++under version 3 of the GNU Affero General Public License into a single
++combined work, and to convey the resulting work.  The terms of this
++License will continue to apply to the part which is the covered work,
++but the special requirements of the GNU Affero General Public License,
++section 13, concerning interaction through a network will apply to the
++combination as such.
++
++  14. Revised Versions of this License.
++
++  The Free Software Foundation may publish revised and/or new versions of
++the GNU General Public License from time to time.  Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++  Each version is given a distinguishing version number.  If the
++Program specifies that a certain numbered version of the GNU General
++Public License "or any later version" applies to it, you have the
++option of following the terms and conditions either of that numbered
++version or of any later version published by the Free Software
++Foundation.  If the Program does not specify a version number of the
++GNU General Public License, you may choose any version ever published
++by the Free Software Foundation.
++
++  If the Program specifies that a proxy can decide which future
++versions of the GNU General Public License can be used, that proxy's
++public statement of acceptance of a version permanently authorizes you
++to choose that version for the Program.
++
++  Later license versions may give you additional or different
++permissions.  However, no additional obligations are imposed on any
++author or copyright holder as a result of your choosing to follow a
++later version.
++
++  15. Disclaimer of Warranty.
++
++  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
++APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
++HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
++OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
++THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
++IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
++ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
++
++  16. Limitation of Liability.
++
++  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
++THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
++GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
++USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
++DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
++PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
++EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
++SUCH DAMAGES.
++
++  17. Interpretation of Sections 15 and 16.
++
++  If the disclaimer of warranty and limitation of liability provided
++above cannot be given local legal effect according to their terms,
++reviewing courts shall apply local law that most closely approximates
++an absolute waiver of all civil liability in connection with the
++Program, unless a warranty or assumption of liability accompanies a
++copy of the Program in return for a fee.
++
++                     END OF TERMS AND CONDITIONS
++
++            How to Apply These Terms to Your New Programs
++
++  If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++  To do so, attach the following notices to the program.  It is safest
++to attach them to the start of each source file to most effectively
++state the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++    <one line to give the program's name and a brief idea of what it does.>
++    Copyright (C) <year>  <name of author>
++
++    This program is free software: you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation, either version 3 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program.  If not, see <http://www.gnu.org/licenses/>.
++
++Also add information on how to contact you by electronic and paper mail.
++
++  If the program does terminal interaction, make it output a short
++notice like this when it starts in an interactive mode:
++
++    <program>  Copyright (C) <year>  <name of author>
++    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++    This is free software, and you are welcome to redistribute it
++    under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License.  Of course, your program's commands
++might be different; for a GUI interface, you would use an "about box".
++
++  You should also get your employer (if you work as a programmer) or school,
++if any, to sign a "copyright disclaimer" for the program, if necessary.
++For more information on this, and how to apply and follow the GNU GPL, see
++<http://www.gnu.org/licenses/>.
++
++  The GNU General Public License does not permit incorporating your program
++into proprietary programs.  If your program is a subroutine library, you
++may consider it more useful to permit linking proprietary applications with
++the library.  If this is what you want to do, use the GNU Lesser General
++Public License instead of this License.  But first, please read
++<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+diff --git a/MANIFEST b/MANIFEST
+deleted file mode 100644
+index 24ca115..0000000
+--- a/MANIFEST
++++ /dev/null
+@@ -1,9 +0,0 @@
+-sendprofile
+-setup.py
+-fireinfo/__init__.py
+-fireinfo/cpu.py
+-fireinfo/device.py
+-fireinfo/hypervisor.py
+-fireinfo/network.py
+-fireinfo/system.py
+-src/fireinfo.c
+diff --git a/Makefile.am b/Makefile.am
+new file mode 100644
+index 0000000..260f14f
+--- /dev/null
++++ b/Makefile.am
+@@ -0,0 +1,87 @@
++###############################################################################
++#                                                                             #
++# Pakfire - The IPFire package management system                              #
++# Copyright (C) 2013 Pakfire development team                                 #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
++AM_MAKEFLAGS = --no-print-directory
++AUTOMAKE_OPTIONS = color-tests
++
++# remove target it the command fails
++.DELETE_ON_ERROR:
++
++# keep itermediate files
++.SECONDARY:
++
++CLEANFILES =
++DISTCLEANFILES =
++EXTRA_DIST =
++
++AM_CPPFLAGS = \
++      -include $(top_builddir)/config.h \
++      -I $(top_srcdir)/include \
++      $(OUR_CPPFLAGS)
++
++AM_CFLAGS = $(OUR_CFLAGS)
++AM_LDFLAGS = $(OUR_LDFLAGS)
++
++pkgpyexec_LTLIBRARIES =
++
++# ------------------------------------------------------------------------------
++
++dist_doc_DATA = \
++      COPYING
++
++# ------------------------------------------------------------------------------
++
++dist_bin_SCRIPTS = \
++      src/sendprofile
++
++# ------------------------------------------------------------------------------
++
++fireinfo_PYTHON = \
++      src/fireinfo/__init__.py \
++      src/fireinfo/bios.py \
++      src/fireinfo/cpu.py \
++      src/fireinfo/device.py \
++      src/fireinfo/hypervisor.py \
++      src/fireinfo/network.py \
++      src/fireinfo/system.py
++
++fireinfodir = $(pythondir)/fireinfo
++
++# ------------------------------------------------------------------------------
++
++pkgpyexec_LTLIBRARIES += \
++      _fireinfo.la
++
++_fireinfo_la_SOURCES = \
++      src/_fireinfo/fireinfo.c
++
++_fireinfo_la_CFLAGS = \
++      $(AM_CFLAGS) \
++      $(PYTHON_DEVEL_CFLAGS)
++
++_fireinfo_la_LDFLAGS = \
++      $(AM_LDFLAGS) \
++      -shared \
++      -module \
++      -avoid-version
++
++_fireinfo_la_LIBADD = \
++      $(PYTHON_DEVEL_LIBS)
+diff --git a/autogen.sh b/autogen.sh
+new file mode 100755
+index 0000000..c08fadf
+--- /dev/null
++++ b/autogen.sh
+@@ -0,0 +1,3 @@
++#!/bin/sh
++
++autoreconf --force --install --symlink
+diff --git a/configure.ac b/configure.ac
+new file mode 100644
+index 0000000..4d5efef
+--- /dev/null
++++ b/configure.ac
+@@ -0,0 +1,110 @@
++###############################################################################
++#                                                                             #
++# Pakfire - The IPFire package management system                              #
++# Copyright (C) 2013 Pakfire development team                                 #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++AC_PREREQ([2.64])
++
++AC_INIT([fireinfo],
++      [2.1.7],
++      [info@ipfire.org],
++      [fireinfo],
++      [http://git.ipfire.org/?p=oddments/fireinfo.git;a=summary])
++
++AC_CONFIG_MACRO_DIR([m4])
++AC_CONFIG_HEADERS([config.h])
++AC_CONFIG_AUX_DIR([build-aux])
++
++AC_USE_SYSTEM_EXTENSIONS
++AC_SYS_LARGEFILE
++AC_PREFIX_DEFAULT([/usr])
++
++AM_INIT_AUTOMAKE([
++      foreign
++      1.11
++      -Wall
++      -Wno-portability
++      silent-rules
++      tar-pax
++      subdir-objects
++])
++AM_SILENT_RULES([yes])
++LT_PREREQ(2.2)
++LT_INIT([disable-static])
++
++# pkg-config
++PKG_PROG_PKG_CONFIG
++# This makes sure pkg.m4 is available.
++m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config])
++
++# C Compiler
++AC_PROG_CC
++AC_PROG_CC_C99
++AC_PROG_CC_C_O
++AC_PROG_GCC_TRADITIONAL
++AC_OPENMP
++
++CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
++      -pipe \
++      -Wall \
++      -Wextra \
++      -Wno-inline \
++      -Wundef \
++      "-Wformat=2 -Wformat-security -Wformat-nonliteral" \
++      -Wno-unused-parameter \
++      -Wno-unused-result \
++      -fno-strict-aliasing \
++      -ffunction-sections \
++      -fdata-sections \
++      -fstack-protector-all \
++      --param=ssp-buffer-size=4])
++AC_SUBST([OUR_CFLAGS], $with_cflags)
++
++AS_CASE([$CFLAGS], [*-O[[12345g\ ]]*],
++      [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\
++              -Wp,-D_FORTIFY_SOURCE=2])],
++      [AC_MSG_RESULT([skipping -D_FORTIFY_SOURCE, optimization not enabled])])
++AC_SUBST([OUR_CPPFLAGS], $with_cppflags)
++
++CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\
++      -Wl,--as-needed \
++      -Wl,--no-undefined \
++      -Wl,--gc-sections \
++      -Wl,-z,relro \
++      -Wl,-z,now])
++AC_SUBST([OUR_LDFLAGS], $with_ldflags)
++
++# Python
++AM_PATH_PYTHON([2.7])
++PKG_CHECK_MODULES([PYTHON_DEVEL], [python-${PYTHON_VERSION}])
++
++AC_CONFIG_FILES([
++      Makefile
++      src/fireinfo/__init__.py
++])
++
++AC_OUTPUT
++AC_MSG_RESULT([
++      $PACKAGE_NAME $VERSION
++
++      CFLAGS:                 ${OUR_CFLAGS} ${CFLAGS}
++      CPPFLAGS:               ${OUR_CPPFLAGS} ${CPPFLAGS}
++      LDFLAGS:                ${OUR_LDFLAGS} ${LDFLAGS}
++      PYTHON_CFLAGS:          ${PYTHON_DEVEL_CFLAGS}
++      PYTHON_LIBS:            ${PYTHON_DEVEL_LIBS}
++])
+diff --git a/fireinfo/__init__.py b/fireinfo/__init__.py
+deleted file mode 100644
+index 86fcc66..0000000
+--- a/fireinfo/__init__.py
++++ /dev/null
+@@ -1,24 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-__version__ = "2.1.7"
+-
+-from system import System
+diff --git a/fireinfo/cpu.py b/fireinfo/cpu.py
+deleted file mode 100644
+index 32d885d..0000000
+--- a/fireinfo/cpu.py
++++ /dev/null
+@@ -1,194 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-import os
+-
+-import system
+-
+-PROC_CPUINFO = "/proc/cpuinfo"
+-
+-class CPU(object):
+-      """
+-              A class that represents the first CPU in a system.
+-
+-              We get all information form the first CPU (or core) and assume that
+-              all other ones are equal.
+-      """
+-
+-      __cpuinfo = {}
+-
+-      def __init__(self):
+-              """
+-                      Initialize this class by reading all data from /proc/cpuinfo.
+-              """
+-              self.__cpuinfo = self.read_cpuinfo()
+-
+-      @property
+-      def system(self):
+-              return system.System()
+-
+-      @staticmethod
+-      def read_cpuinfo():
+-              """
+-                      Read information from PROC_CPUINFO and store
+-                      it into a dictionary cpuinfo.
+-              """
+-              cpuinfo = {}
+-
+-              f = open(PROC_CPUINFO)
+-              while True:
+-                      line = f.readline()
+-
+-                      if not line:
+-                              break
+-
+-                      try:
+-                              key, val = line.split(":", 1)
+-                      except ValueError:
+-                              # We got a line without key, pass that.
+-                              pass
+-
+-                      key = key.strip().replace(" ", "_")
+-                      val = val.strip()
+-
+-                      cpuinfo[key] = val
+-
+-              f.close()
+-
+-              return cpuinfo
+-
+-      @property
+-      def bogomips(self):
+-              """
+-                      Return the bogomips of this CPU.
+-              """
+-              try:
+-                      bogomips = self.__cpuinfo["bogomips"]
+-              except KeyError:
+-                      bogomips = self.__cpuinfo["BogoMIPS"]
+-
+-              return float(bogomips)
+-
+-      @property
+-      def model(self):
+-              """
+-                      Return the model id of this CPU.
+-              """
+-              try:
+-                      model = int(self.__cpuinfo["model"])
+-              except KeyError:
+-                      model = None
+-
+-              return model
+-
+-      @property
+-      def model_string(self):
+-              """
+-                      Return the model string of this CPU.
+-              """
+-              try:
+-                      return self.__cpuinfo["model_name"]
+-              except KeyError:
+-                      return self.__cpuinfo["Processor"]
+-
+-      @property
+-      def vendor(self):
+-              """
+-                      Return the vendor string of this CPU.
+-              """
+-              try:
+-                      vendor = self.__cpuinfo["vendor_id"]
+-              except KeyError:
+-                      if self.system.arch.startswith("arm"):
+-                              vendor = "ARM"
+-                      else:
+-                              vendor = ""
+-
+-              return vendor
+-
+-      @property
+-      def stepping(self):
+-              """
+-                      Return the stepping id of this CPU.
+-              """
+-              try:
+-                      stepping = int(self.__cpuinfo["stepping"])
+-              except KeyError:
+-                      stepping = None
+-
+-              return stepping
+-
+-      @property
+-      def flags(self):
+-              """
+-                      Return all flags of this CPU.
+-              """
+-              try:
+-                      flags = self.__cpuinfo["flags"]
+-              except KeyError:
+-                      flags = self.__cpuinfo["Features"]
+-
+-              return flags.split()
+-
+-      @property
+-      def speed(self):
+-              """
+-                      Return the speed (in MHz) of this CPU.
+-              """
+-              try:
+-                      speed = float(self.__cpuinfo["cpu_MHz"])
+-              except KeyError:
+-                      speed = 0
+-
+-              return speed
+-
+-      @property
+-      def family(self):
+-              """
+-                      Return the family id of this CPU.
+-              """
+-              try:
+-                      family = int(self.__cpuinfo["cpu_family"])
+-              except KeyError:
+-                      family = None
+-
+-              return family
+-      
+-      @property
+-      def count(self):
+-              """
+-                      Count number of CPUs (cores).
+-              """
+-              return os.sysconf("SC_NPROCESSORS_ONLN")
+-
+-
+-if __name__ == "__main__":
+-      c = CPU()
+-
+-      print "Vendor:", c.vendor
+-      print "Model:", c.model
+-      print "Stepping:", c.stepping
+-      print "Flags:", c.flags
+-      print "Bogomips:", c.bogomips
+-      print "Speed:", c.speed
+-      print "Family:", c.family
+-      print "Count:", c.count
+-      print "Model string:", c.model_string
+diff --git a/fireinfo/device.py b/fireinfo/device.py
+deleted file mode 100644
+index 01338b2..0000000
+--- a/fireinfo/device.py
++++ /dev/null
+@@ -1,133 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-import os.path
+-
+-class Device(object):
+-      """
+-              This is an abstract class that represents all devices in the system.
+-              Every single device has its own instance of this class.
+-      """
+-
+-      def __init__(self, path):
+-              """
+-                      Collect all information about the device by reading the
+-                      "uevent" file and parsing it.
+-              """
+-
+-              # Save the path in /sys to the device.
+-              self.path = path
+-
+-              # Datastructure to store information we read.
+-              self._uevent = {}
+-
+-              # Open the uevent file and parse all lines.
+-              with open(os.path.join(path, "uevent")) as f:
+-                      for line in f.readlines():
+-                              key, val = line.split("=")
+-                              self._uevent[key] = val.rstrip().lower()
+-
+-      @property
+-      def driver(self):
+-              """
+-                      Get the driver/kernel module that device is driven by or return None.
+-              """
+-              return self._uevent.get("DRIVER", None)
+-
+-                      
+-class PCIDevice(Device):
+-      """
+-              A class that represents all PCI (and PCIe) devices in a system.
+-      """
+-
+-      subsystem = "pci"
+-
+-      @property
+-      def model(self):
+-              """
+-                      Return the PCI model id of this device.
+-              """
+-              return self._uevent['PCI_ID'].split(":")[1]
+-              
+-      @property
+-      def vendor(self):
+-              """
+-                      Return the PCI vendor id of this device.
+-              """
+-              return self._uevent['PCI_ID'].split(":")[0]
+-
+-      @property
+-      def deviceclass(self):
+-              """
+-                      Return the PCI device class of this device.
+-              """
+-              return self._uevent['PCI_CLASS']
+-
+-      @property
+-      def sub_vendor(self):
+-              """
+-                      Return the PCI vendor sub id of this device.
+-              """
+-              return self._uevent["PCI_SUBSYS_ID"].split(":")[0]
+-
+-      @property
+-      def sub_model(self):
+-              """
+-                      Return the PCI model sub id of this device.
+-              """
+-              return self._uevent["PCI_SUBSYS_ID"].split(":")[1]
+-
+-
+-class USBDevice(Device):
+-      """
+-              A class that represents all USB devices in a system.
+-      """
+-
+-      subsystem = "usb"
+-      
+-      def pad(self, s):
+-              """
+-                      A function to pad ids that have no leading zeroes.
+-              """
+-              while len(s) < 4:
+-                      s = "0"+s
+-              return s
+-
+-      @property
+-      def vendor(self):
+-              """
+-                      Return the USB vendor id of this device.
+-              """
+-              return self.pad(self._uevent['PRODUCT'].split("/")[0])
+-
+-      @property
+-      def model(self):
+-              """
+-                      Return the USB model id of this device.
+-              """
+-              return self.pad(self._uevent['PRODUCT'].split("/")[1])
+-
+-      @property
+-      def deviceclass(self):
+-              """
+-                      Return the USB device class of this device.
+-              """
+-              return self._uevent.get("INTERFACE", None)
+diff --git a/fireinfo/hypervisor.py b/fireinfo/hypervisor.py
+deleted file mode 100644
+index 9a3fb09..0000000
+--- a/fireinfo/hypervisor.py
++++ /dev/null
+@@ -1,149 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-import _fireinfo
+-import system
+-
+-class Hypervisor(object):
+-      def __init__(self):
+-              self.__info = _fireinfo.get_hypervisor()
+-
+-      @property
+-      def system(self):
+-              """
+-                      Return the current instance of the System class.
+-
+-                      We need to do that as a property because otherwise
+-                      we get a recursion.
+-              """
+-              return system.System()
+-
+-      @property
+-      def vendor(self):
+-              """
+-                      Returns the name of the hypervisor vendor.
+-              """
+-              if not self.virtual:
+-                      return None
+-
+-              # Some of the hypervisors can be detected in a right way.
+-              # We can return them at this place.
+-              if self.__info["hypervisor"] in ("Xen", "VMWare", "KVM"):
+-                      return self.__info["hypervisor"]
+-
+-              # Citrix Xen says it is Microsoft Hv.
+-              if self.__info["hypervisor"] == "Microsoft" and \
+-                              self.system.bios_vendor == "Xen":
+-                      return "Xen"
+-
+-              if not self.__info["hypervisor"]:
+-                      # On VMWare systems, the bios vendor string contains "VMWare".
+-                      if self.__is_hypervisor_vmware():
+-                              return "VMWare"
+-
+-                      # VirtualBox got "innotek GmbH" as bios vendor.
+-                      elif self.__is_hypervisor_virtualbox():
+-                              return "VirtualBox"
+-
+-                      # Check for qemu.
+-                      elif self.__is_hypervisor_qemu():
+-                              return "Qemu"
+-
+-                      # Check for Microsoft.
+-                      elif self.__is_hypervisor_microsoft():
+-                              return "Microsoft"
+-
+-              return "unknown"
+-
+-      @property
+-      def type(self):
+-              """
+-                      Returns if the host is running in full virt mode or
+-                      if it is running in a paravirtualized environment.
+-              """
+-              if not self.virtual:
+-                      return None
+-
+-              if self.__info["virtype"]:
+-                      return self.__info["virtype"]
+-
+-              if self.vendor in ("Qemu", "KVM", "VirtualBox", "VMWare"):
+-                      return "full"
+-
+-              return "unknown"
+-
+-      @property
+-      def virtual(self):
+-              """
+-                      Returns true if the host is running in a virtual environment.
+-                      Otherwise: false.
+-              """
+-              return _fireinfo.is_virtualized() or \
+-                      "hypervisor" in self.system.cpu.flags or \
+-                      self.__is_hypervisor_virtualbox() or \
+-                      self.__is_hypervisor_vmware() or \
+-                      self.__is_hypervisor_qemu() or \
+-                      self.__is_hypervisor_microsoft()
+-
+-      def __is_hypervisor_virtualbox(self):
+-              """
+-                      Check for virtualbox hypervisor by comparing the bios vendor string
+-                      to "innotek GmbH".
+-              """
+-              return self.system.bios_vendor == "innotek GmbH"
+-
+-      def __is_hypervisor_vmware(self):
+-              """
+-                      Check for the VMWare hypervisor by the VMWare Hypervisor port check.
+-
+-                      http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458
+-              """
+-              if self.system.vendor:
+-                      return self.system.vendor.startswith("VMware")
+-
+-                      # XXX We should use _fireinfo.vmware_hypervisor_port_check() here, too.
+-                      # This currently segfaults (and I have no clue why) on VMware player.
+-
+-      def __is_hypervisor_qemu(self):
+-              """
+-                      Check for old qemu emulator.
+-              """
+-              if self.system.bios_vendor:
+-                      return self.system.bios_vendor == "Bochs"
+-
+-              return False
+-
+-      def __is_hypervisor_microsoft(self):
+-              """
+-                      Check for Microsoft hypervisor.
+-              """
+-              if self.system.vendor:
+-                      return "Microsoft" in self.system.vendor
+-
+-              return False
+-
+-
+-if __name__ == "__main__":
+-      h = Hypervisor()
+-
+-      print "Vendor:", h.vendor
+-      print "Type:", h.type
+-      print "Virtual:", h.virtual
+diff --git a/fireinfo/network.py b/fireinfo/network.py
+deleted file mode 100644
+index 063e9ec..0000000
+--- a/fireinfo/network.py
++++ /dev/null
+@@ -1,53 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-import os
+-
+-SYS_CLASS_NET = "/sys/class/net"
+-
+-class Network(object):
+-      def __init__(self):
+-              self._devices = os.listdir(SYS_CLASS_NET)
+-
+-      def has_green(self):
+-              return "green0" in self._devices
+-
+-      def has_red(self):
+-              for i in ("red0", "ppp0"):
+-                      if i in self._devices:
+-                              return True
+-
+-              return False
+-
+-      def has_blue(self):
+-              return "blue0" in self._devices
+-
+-      def has_orange(self):
+-              return "orange0" in self._devices
+-
+-
+-if __name__ == "__main__":
+-      n = Network()
+-
+-      print "has_green", n.has_green()
+-      print "has_red", n.has_red()
+-      print "has_blue", n.has_blue()
+-      print "has_orange", n.has_orange()
+diff --git a/fireinfo/system.py b/fireinfo/system.py
+deleted file mode 100644
+index 6f02312..0000000
+--- a/fireinfo/system.py
++++ /dev/null
+@@ -1,449 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-import hashlib
+-import json
+-import os
+-import string
+-
+-import _fireinfo
+-
+-import cpu
+-import device
+-import hypervisor
+-import network
+-
+-PROFILE_VERSION = 0
+-
+-SYS_CLASS_DMI = "/sys/class/dmi/id"
+-SECRET_ID_FILE = "/etc/fireinfo-id"
+-
+-INVALID_ID_STRINGS = (
+-      "OEM", "O.E.M.", "o.e.m.",
+-      "N/A", "n/a",
+-      "12345", "54321", "202020",
+-      "Chassis", "chassis",
+-      "Not Applicable",
+-      "None", "empty",
+-      "01010101-0101-0101-0101-010101010101",
+-      "00020003-0004-0005-0006-000700080009",
+-      "03000200-0400-0500-0006-000700080009",
+-      "0000000", "00000000",
+-)
+-
+-class Singleton(type):
+-      def __init__(cls, name, bases, dict):
+-              super(Singleton, cls).__init__(name, bases, dict)
+-              cls.instance = None
+-
+-      def __call__(cls, *args, **kw):
+-              if cls.instance is None:
+-                      cls.instance = super(Singleton, cls).__call__(*args, **kw)
+-
+-              return cls.instance
+-
+-
+-def read_from_file(filename):
+-      """
+-              Read all data from filename.
+-      """
+-      if not os.path.exists(filename):
+-              return
+-
+-      try:
+-              with open(filename) as f:
+-                      return f.read().strip()
+-      except IOError:
+-              pass
+-
+-class System(object):
+-      __metaclass__ = Singleton
+-
+-      def __init__(self):
+-              # find all devices
+-              self.devices = []
+-              self.scan()
+-              self.cpu = cpu.CPU()
+-              self.hypervisor = hypervisor.Hypervisor()
+-
+-              # Read /proc/cpuinfo for vendor information.
+-              self.__cpuinfo = self.cpu.read_cpuinfo()
+-
+-      def profile(self):
+-              p = {}
+-              p["system"] = {
+-                      # System information
+-                      "model"  : self.model,
+-                      "vendor" : self.vendor,
+-
+-                      # Indicator if the system is running in a
+-                      # virtual environment.
+-                      "virtual" : self.virtual,
+-                      
+-                      # System language
+-                      "language" : self.language,
+-
+-                      # Release information
+-                      "release" : self.release,
+-                      "kernel_release" : self.kernel_release,
+-
+-                      "memory" : self.memory,
+-                      "root_size" : self.root_size,
+-              }
+-
+-              p["devices"] = []
+-              for device in self.devices:
+-                      d = {
+-                              "subsystem" : device.subsystem.lower(), 
+-                              "vendor" : device.vendor.lower(), 
+-                              "model" : device.model.lower(), 
+-                              "deviceclass" : device.deviceclass,
+-                              "driver" : device.driver,
+-                      }
+-
+-                      # PCI devices provide subsystem information, USB don't.
+-                      if d["subsystem"] == "pci":
+-                              d["sub_model"] = device.sub_model
+-                              d["sub_vendor"] = device.sub_vendor
+-
+-                      p["devices"].append(d)
+-
+-              p["cpu"] = {
+-                      "arch" : self.arch,
+-                      "vendor" : self.cpu.vendor,
+-                      "model" : self.cpu.model,
+-                      "model_string" : self.cpu.model_string,
+-                      "stepping" : self.cpu.stepping,
+-                      "flags" : self.cpu.flags,
+-                      "bogomips" : self.cpu.bogomips,
+-                      "speed" : self.cpu.speed,
+-                      "family" : self.cpu.family,
+-                      "count" : self.cpu.count                                
+-              }
+-
+-              p["network"] = {
+-                      "green" : self.network.has_green(),
+-                      "blue" : self.network.has_blue(),
+-                      "orange" : self.network.has_orange(),
+-                      "red" : self.network.has_red(),
+-               }
+-
+-              # Only append hypervisor information if we are virtualized.
+-              if self.virtual:
+-                      p["hypervisor"] = {
+-                              "type"   : self.hypervisor.type,
+-                              "vendor" : self.hypervisor.vendor,
+-                      }
+-
+-              return {
+-                      # Profile version
+-                      "profile_version" : PROFILE_VERSION,
+-
+-                      # Identification and authorization codes
+-                      "public_id" : self.public_id,
+-                      "private_id" : self.private_id,
+-
+-                      # Actual profile data
+-                      "profile" : p,
+-              }
+-                              
+-              
+-      @property
+-      def arch(self):
+-              return os.uname()[4]
+-
+-      @property
+-      def public_id(self):
+-              """
+-                      This returns a globally (hopefully) ID to identify the host
+-                      later (by request) in the database.
+-              """
+-              public_id = self.secret_id
+-              if not public_id:
+-                      return "0" * 40
+-
+-              return hashlib.sha1(public_id).hexdigest()
+-
+-      @property
+-      def private_id(self):
+-              """
+-                      The private ID is built out of the _unique_id and used to
+-                      permit a host to do changes on the database.
+-
+-                      No one could ever guess this without access to the host.
+-              """
+-              private_id = ""
+-              for i in reversed(self.secret_id):
+-                      private_id += i
+-
+-              if not private_id:
+-                      return "0" * 40
+-
+-              return hashlib.sha1(private_id).hexdigest()
+-
+-      @property
+-      def secret_id(self):
+-              """
+-                      Read a "secret" ID from a file if available
+-                      or calculate it from the hardware.
+-              """
+-              if os.path.exists(SECRET_ID_FILE):
+-                      return read_from_file(SECRET_ID_FILE)
+-
+-              return hashlib.sha1(self._unique_id).hexdigest()
+-
+-      @property
+-      def _unique_id(self):
+-              """
+-                      This is a helper ID which is generated out of some hardware information
+-                      that is considered to be constant over a PC's lifetime.
+-
+-                      None of the data here is ever sent to the server.
+-              """
+-              ids = []
+-
+-              # Virtual machines (for example) and some boards have a UUID
+-              # which is globally unique.
+-              for file in ("product_uuid", "product_serial", "chassis_serial"):
+-                      id = read_from_file(os.path.join(SYS_CLASS_DMI, file))
+-                      ids.append(id)
+-
+-              # Sort out all bogous or invalid strings from the list.
+-              _ids = []
+-              for id in ids:
+-                      if id is None:
+-                              continue
+-
+-                      for i in INVALID_ID_STRINGS:
+-                              if i in id:
+-                                      id = None
+-                                      break
+-
+-                      if id:
+-                              _ids.append(id)
+-
+-              ids = _ids
+-
+-              # Use serial number from root disk (if available) and if
+-              # no other ID was found, yet.
+-              if not ids:
+-                      root_disk_serial = self.root_disk_serial
+-                      if root_disk_serial and not root_disk_serial.startswith("QM000"):
+-                              ids.append(root_disk_serial)
+-
+-              # As last resort, we use the UUID from pakfire.
+-              if not ids:
+-                      id = read_from_file("/opt/pakfire/db/uuid")
+-                      ids.append(id)
+-
+-              return "#".join(ids)
+-
+-      @property
+-      def language(self):
+-              """
+-                      Return the language code of IPFire or "unknown" if we cannot get it.
+-              """
+-              # Return "unknown" if settings file does not exist.
+-              filename = "/var/ipfire/main/settings"
+-              if not os.path.exists(filename):
+-                      return "unknown"
+-
+-              with open(filename, "r") as f:
+-                      for line in f.readlines():
+-                              key, val = line.split("=", 1)
+-                              if key == "LANGUAGE":
+-                                      return val.strip()
+-
+-      @property
+-      def release(self):
+-              """
+-                      Return the system release string.
+-              """
+-              return read_from_file("/etc/system-release") or "unknown"
+-
+-      @property
+-      def bios_vendor(self):
+-              """
+-                      Return the bios vendor name.
+-              """
+-              return read_from_file("/sys/class/dmi/id/bios_vendor")
+-
+-      def vendor_model_tuple(self):
+-              try:
+-                      s = self.__cpuinfo["Hardware"]
+-              except KeyError:
+-                      return (None, None)
+-
+-              if s.startswith("ARM-Versatile"):
+-                      return ("ARM", s)
+-
+-              try:
+-                      v, m = s.split(" ", 1)
+-              except ValueError:
+-                      if s.startswith("BCM"):
+-                              v = "Broadcom"
+-                              m = s
+-                      else:
+-                              v = None
+-                              m = s
+-
+-              return v, m
+-
+-      @property
+-      def vendor(self):
+-              """
+-                      Return the vendor string of this system (if any).
+-              """
+-              ret = None
+-              for file in ("sys_vendor", "board_vendor", "chassis_vendor",):
+-                      ret = read_from_file(os.path.join(SYS_CLASS_DMI, file))
+-                      if ret:
+-                              break
+-
+-              if ret is None:
+-                      v, m = self.vendor_model_tuple()
+-                      ret = v
+-
+-              return ret
+-
+-      @property
+-      def model(self):
+-              """
+-                      Return the model string of this system (if any).
+-              """
+-              ret = None
+-              for file in ("product_name", "board_model", "chassis_model",):
+-                      ret = read_from_file(os.path.join(SYS_CLASS_DMI, file))
+-                      if ret:
+-                              break
+-
+-              if ret is None:
+-                      v, m = self.vendor_model_tuple()
+-                      ret = m
+-
+-              return ret
+-
+-      @property
+-      def memory(self):
+-              """
+-                      Return the amount of memory in kilobytes.
+-              """
+-              with open("/proc/meminfo", "r") as f:
+-                      firstline = f.readline().strip()
+-                      return int(firstline.split()[1])
+-
+-      @property
+-      def kernel_release(self):
+-              """
+-                      Return the kernel release string.
+-              """
+-              return os.uname()[2]
+-
+-      @property
+-      def root_disk(self):
+-              """
+-                      Return the dev node of the root disk.
+-              """
+-              with open("/etc/mtab", "r") as f:
+-                      dev, mountpoint, rest = f.readline().split(" ", 2)
+-                      if mountpoint == "/":
+-                              # Cut off /dev
+-                              dev = dev[5:]
+-
+-                              # Handle raids and MMC cards like (mmcblk0p3).
+-                              if dev[-2] == "p":
+-                                      return dev[:-2]
+-
+-                              # Otherwise cut off all digits at end of string
+-                              while dev[-1] in string.digits:
+-                                      dev = dev[:-1]
+-
+-                              return dev
+-
+-      @property
+-      def root_size(self):
+-              """
+-                      Return the size of the root disk in kilobytes.
+-              """
+-              path = "/sys/block/%s/size" % self.root_disk
+-              if not os.path.exists(path):
+-                      return
+-
+-              with open(path, "r") as f:
+-                      return int(f.readline()) * 512 / 1024
+-
+-      @property
+-      def root_disk_serial(self):
+-              """
+-                      Return the serial number of the root disk (if any).
+-              """
+-              serial = _fireinfo.get_harddisk_serial("/dev/%s" % self.root_disk)
+-
+-              if serial:
+-                      # Strip all spaces
+-                      return serial.strip()
+-
+-      def scan(self):
+-              """
+-                      Scan for all devices (PCI/USB) in the system and append them
+-                      to our list.
+-              """
+-              self.devices = []
+-
+-              toscan = (
+-                      ("/sys/bus/pci/devices", device.PCIDevice),
+-                      ("/sys/bus/usb/devices", device.USBDevice)
+-              )
+-              for path, cls in toscan:
+-                      if not os.path.exists(path):
+-                              continue
+-
+-                      dirlist = os.listdir(path)
+-                      for dir in dirlist:
+-                              self.devices.append(cls(os.path.join(path, dir)))
+-
+-      @property
+-      def virtual(self):
+-              """
+-                      Say if the host is running in a virtual environment.
+-              """
+-              return self.hypervisor.virtual
+-
+-      @property
+-      def network(self):
+-              """
+-                      Reference to the network class.
+-              """
+-              return network.Network()
+-
+-
+-if __name__ == "__main__":
+-      s=System()
+-      print s.arch
+-      print s.language
+-      print s.release
+-      print s.bios_vendor
+-      print s.memory
+-      print s.kernel
+-      print s.root_disk
+-      print s.root_size
+-      print "------------\n", s.devices, "\n------------\n"
+-      print json.dumps(s.profile(), sort_keys=True, indent=4)
+diff --git a/m4/.gitignore b/m4/.gitignore
+new file mode 100644
+index 0000000..38066dd
+--- /dev/null
++++ b/m4/.gitignore
+@@ -0,0 +1,5 @@
++libtool.m4
++ltoptions.m4
++ltsugar.m4
++ltversion.m4
++lt~obsolete.m4
+diff --git a/m4/attributes.m4 b/m4/attributes.m4
+new file mode 100644
+index 0000000..7e080da
+--- /dev/null
++++ b/m4/attributes.m4
+@@ -0,0 +1,288 @@
++dnl Macros to check the presence of generic (non-typed) symbols.
++dnl Copyright (c) 2006-2008 Diego Pettenò <flameeyes@gmail.com>
++dnl Copyright (c) 2006-2008 xine project
++dnl Copyright (c) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
++dnl
++dnl This program is free software; you can redistribute it and/or modify
++dnl it under the terms of the GNU General Public License as published by
++dnl the Free Software Foundation; either version 2, or (at your option)
++dnl any later version.
++dnl
++dnl This program is distributed in the hope that it will be useful,
++dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
++dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++dnl GNU General Public License for more details.
++dnl
++dnl You should have received a copy of the GNU General Public License
++dnl along with this program; if not, write to the Free Software
++dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++dnl 02110-1301, USA.
++dnl
++dnl As a special exception, the copyright owners of the
++dnl macro gives unlimited permission to copy, distribute and modify the
++dnl configure scripts that are the output of Autoconf when processing the
++dnl Macro. You need not follow the terms of the GNU General Public
++dnl License when using or distributing such scripts, even though portions
++dnl of the text of the Macro appear in them. The GNU General Public
++dnl License (GPL) does govern all other use of the material that
++dnl constitutes the Autoconf Macro.
++dnl
++dnl This special exception to the GPL applies to versions of the
++dnl Autoconf Macro released by this project. When you make and
++dnl distribute a modified version of the Autoconf Macro, you may extend
++dnl this special exception to the GPL to apply to your modified version as
++dnl well.
++
++dnl Check if FLAG in ENV-VAR is supported by compiler and append it
++dnl to WHERE-TO-APPEND variable
++dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG])
++
++AC_DEFUN([CC_CHECK_FLAG_APPEND], [
++  AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2],
++                 AS_TR_SH([cc_cv_$2_$3]),
++          [eval "AS_TR_SH([cc_save_$2])='${$2}'"
++           eval "AS_TR_SH([$2])='-Werror $3'"
++           AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a = 0; int main(void) { return a; } ])],
++                                    [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"],
++                                    [eval "AS_TR_SH([cc_cv_$2_$3])='no'"])
++           eval "AS_TR_SH([$2])='$cc_save_$2'"])
++
++  AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes],
++        [eval "$1='${$1} $3'"])
++])
++
++dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2])
++AC_DEFUN([CC_CHECK_FLAGS_APPEND], [
++  for flag in $3; do
++    CC_CHECK_FLAG_APPEND($1, $2, $flag)
++  done
++])
++
++dnl Check if the flag is supported by linker (cacheable)
++dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
++
++AC_DEFUN([CC_CHECK_LDFLAGS], [
++  AC_CACHE_CHECK([if $CC supports $1 flag],
++    AS_TR_SH([cc_cv_ldflags_$1]),
++    [ac_save_LDFLAGS="$LDFLAGS"
++     LDFLAGS="$LDFLAGS $1"
++     AC_LINK_IFELSE([int main() { return 1; }],
++       [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
++       [eval "AS_TR_SH([cc_cv_ldflags_$1])="])
++     LDFLAGS="$ac_save_LDFLAGS"
++    ])
++
++  AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
++    [$2], [$3])
++])
++
++dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
++dnl the current linker to avoid undefined references in a shared object.
++AC_DEFUN([CC_NOUNDEFINED], [
++  dnl We check $host for which systems to enable this for.
++  AC_REQUIRE([AC_CANONICAL_HOST])
++
++  case $host in
++     dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
++     dnl are requested, as different implementations are present; to avoid problems
++     dnl use -Wl,-z,defs only for those platform not behaving this way.
++     *-freebsd* | *-openbsd*) ;;
++     *)
++        dnl First of all check for the --no-undefined variant of GNU ld. This allows
++        dnl for a much more readable commandline, so that people can understand what
++        dnl it does without going to look for what the heck -z defs does.
++        for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
++           CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
++           break
++        done
++     ;;
++  esac
++
++  AC_SUBST([LDFLAGS_NOUNDEFINED])
++])
++
++dnl Check for a -Werror flag or equivalent. -Werror is the GCC
++dnl and ICC flag that tells the compiler to treat all the warnings
++dnl as fatal. We usually need this option to make sure that some
++dnl constructs (like attributes) are not simply ignored.
++dnl
++dnl Other compilers don't support -Werror per se, but they support
++dnl an equivalent flag:
++dnl  - Sun Studio compiler supports -errwarn=%all
++AC_DEFUN([CC_CHECK_WERROR], [
++  AC_CACHE_CHECK(
++    [for $CC way to treat warnings as errors],
++    [cc_cv_werror],
++    [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
++      [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
++    ])
++])
++
++AC_DEFUN([CC_CHECK_ATTRIBUTE], [
++  AC_REQUIRE([CC_CHECK_WERROR])
++  AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
++    AS_TR_SH([cc_cv_attribute_$1]),
++    [ac_save_CFLAGS="$CFLAGS"
++     CFLAGS="$CFLAGS $cc_cv_werror"
++     AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
++       [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
++       [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
++     CFLAGS="$ac_save_CFLAGS"
++    ])
++
++  AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
++    [AC_DEFINE(
++       AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
++         [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
++         )
++     $4],
++    [$5])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
++  CC_CHECK_ATTRIBUTE(
++    [constructor],,
++    [void __attribute__((constructor)) ctor() { int a; }],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
++  CC_CHECK_ATTRIBUTE(
++    [format], [format(printf, n, n)],
++    [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
++  CC_CHECK_ATTRIBUTE(
++    [format_arg], [format_arg(printf)],
++    [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
++  CC_CHECK_ATTRIBUTE(
++    [visibility_$1], [visibility("$1")],
++    [void __attribute__((visibility("$1"))) $1_function() { }],
++    [$2], [$3])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
++  CC_CHECK_ATTRIBUTE(
++    [nonnull], [nonnull()],
++    [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
++  CC_CHECK_ATTRIBUTE(
++    [unused], ,
++    [void some_function(void *foo, __attribute__((unused)) void *bar);],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
++  CC_CHECK_ATTRIBUTE(
++    [sentinel], ,
++    [void some_function(void *foo, ...) __attribute__((sentinel));],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
++  CC_CHECK_ATTRIBUTE(
++    [deprecated], ,
++    [void some_function(void *foo, ...) __attribute__((deprecated));],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
++  CC_CHECK_ATTRIBUTE(
++    [alias], [weak, alias],
++    [void other_function(void *foo) { }
++     void some_function(void *foo) __attribute__((weak, alias("other_function")));],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
++  CC_CHECK_ATTRIBUTE(
++    [malloc], ,
++    [void * __attribute__((malloc)) my_alloc(int n);],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_PACKED], [
++  CC_CHECK_ATTRIBUTE(
++    [packed], ,
++    [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_CONST], [
++  CC_CHECK_ATTRIBUTE(
++    [const], ,
++    [int __attribute__((const)) twopow(int n) { return 1 << n; } ],
++    [$1], [$2])
++])
++
++AC_DEFUN([CC_FLAG_VISIBILITY], [
++  AC_REQUIRE([CC_CHECK_WERROR])
++  AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
++    [cc_cv_flag_visibility],
++    [cc_flag_visibility_save_CFLAGS="$CFLAGS"
++     CFLAGS="$CFLAGS $cc_cv_werror"
++     CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
++     cc_cv_flag_visibility='yes',
++     cc_cv_flag_visibility='no')
++     CFLAGS="$cc_flag_visibility_save_CFLAGS"])
++
++  AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
++    [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
++       [Define this if the compiler supports the -fvisibility flag])
++     $1],
++    [$2])
++])
++
++AC_DEFUN([CC_FUNC_EXPECT], [
++  AC_REQUIRE([CC_CHECK_WERROR])
++  AC_CACHE_CHECK([if compiler has __builtin_expect function],
++    [cc_cv_func_expect],
++    [ac_save_CFLAGS="$CFLAGS"
++     CFLAGS="$CFLAGS $cc_cv_werror"
++     AC_COMPILE_IFELSE([AC_LANG_SOURCE(
++       [int some_function() {
++        int a = 3;
++        return (int)__builtin_expect(a, 3);
++     }])],
++       [cc_cv_func_expect=yes],
++       [cc_cv_func_expect=no])
++     CFLAGS="$ac_save_CFLAGS"
++    ])
++
++  AS_IF([test "x$cc_cv_func_expect" = "xyes"],
++    [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
++     [Define this if the compiler supports __builtin_expect() function])
++     $1],
++    [$2])
++])
++
++AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
++  AC_REQUIRE([CC_CHECK_WERROR])
++  AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
++    [cc_cv_attribute_aligned],
++    [ac_save_CFLAGS="$CFLAGS"
++     CFLAGS="$CFLAGS $cc_cv_werror"
++     for cc_attribute_align_try in 64 32 16 8 4 2; do
++        AC_COMPILE_IFELSE([AC_LANG_SOURCE([
++          int main() {
++            static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
++            return c;
++          }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
++     done
++     CFLAGS="$ac_save_CFLAGS"
++  ])
++
++  if test "x$cc_cv_attribute_aligned" != "x"; then
++     AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
++       [Define the highest alignment supported])
++  fi
++])
+diff --git a/runpychecker.sh b/runpychecker.sh
+index 407b7d6..64366fd 100755
+--- a/runpychecker.sh
++++ b/runpychecker.sh
+@@ -5,4 +5,4 @@ pychecker --only --limit 1000 \
+       --no-callinit --no-local --no-shadow --no-shadowbuiltin \
+       --no-import --no-miximport --no-pkgimport --no-reimport \
+       --no-argsused --no-varargsused --no-override \
+-      fireinfo/*.py
++      src/fireinfo/*.py
+diff --git a/sendprofile b/sendprofile
+deleted file mode 100644
+index da480ce..0000000
+--- a/sendprofile
++++ /dev/null
+@@ -1,132 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-import json
+-import logging
+-import logging.handlers
+-import os
+-import sys
+-import urllib
+-import urllib2
+-
+-import fireinfo
+-
+-ENABLED_FILE = "/var/ipfire/main/send_profile"
+-PROXY_SETTINGS = "/var/ipfire/proxy/advanced/settings"
+-
+-log_level = logging.INFO
+-if "-d" in sys.argv:
+-      log_level = logging.DEBUG
+-
+-# Setup logging
+-log = logging.getLogger()
+-log.setLevel(log_level)
+-log.addHandler(logging.handlers.SysLogHandler("/dev/log"))
+-log.addHandler(logging.StreamHandler(sys.stderr))
+-for handler in log.handlers:
+-      handler.setLevel(log_level)
+-
+-PROFILE_URL = "http://fireinfo.ipfire.org/send/%(public_id)s"
+-
+-def get_upstream_proxy():
+-      if not os.path.exists(PROXY_SETTINGS):
+-              return {"host" : ""}
+-
+-      proxy_settings = {}
+-      with open(PROXY_SETTINGS) as f:
+-              for line in f.readlines():
+-                      k, v = line.split("=", 1)
+-                      proxy_settings[k] = v.strip()
+-
+-      return {
+-              "host" : proxy_settings.get("UPSTREAM_PROXY", ""),
+-              "user" : proxy_settings.get("UPSTREAM_USER", ""),
+-              "pass" : proxy_settings.get("UPSTREAM_PASSWORD", ""),
+-      }
+-
+-def send_profile(profile):
+-      logging.debug("Sending profile:")
+-      for line in json.dumps(profile, sort_keys=True, indent=4).splitlines():
+-              logging.debug(line)
+-
+-      request = urllib2.Request(PROFILE_URL % profile,
+-              data = urllib.urlencode({"profile" : json.dumps(profile)}),
+-      )
+-      request.add_header("User-Agent", "fireinfo/%s" % fireinfo.__version__)
+-
+-      # Set upstream proxy if we have one.
+-      # XXX this cannot handle authentication
+-      proxy = get_upstream_proxy()
+-      if proxy["host"]:
+-              request.set_proxy(proxy["host"], "http")
+-
+-      try:
+-              urllib2.urlopen(request, timeout=60)
+-      except (urllib2.HTTPError, urllib2.URLError), e:
+-              reason = "Unknown reason"
+-
+-              if isinstance(e, urllib2.HTTPError):
+-                      reason = "%s" % e
+-              elif isinstance(e, urllib2.URLError):
+-                      reason = e.reason
+-
+-              logging.error("Profile was not sent propertly: %s" % reason)
+-              return
+-
+-      logging.debug("Profile was sent successfully.")
+-
+-def main():
+-      # Collect system information
+-      system = fireinfo.System()
+-      profile = system.profile()
+-
+-      # If --dump is passed -> only dump the output.
+-      if "--dump" in sys.argv:
+-              # Remove the private id when dumping the profile because
+-              # it contains no information and may confuse people.
+-              del profile["private_id"]
+-
+-              print json.dumps(profile, sort_keys=True, indent=4)
+-              return 0
+-
+-      if "--secret-id" in sys.argv:
+-              print system.secret_id
+-              return 0
+-
+-      if "--hardware-string" in sys.argv:
+-              print system._unique_id
+-              return 0
+-
+-      if "--public-id" in sys.argv:
+-              print system.public_id
+-              return 0
+-
+-      if not os.path.exists(ENABLED_FILE):
+-              del profile["profile"]
+-
+-      try:
+-              send_profile(profile)
+-      except urllib2.URLError:
+-              return 1
+-
+-      return 0
+-
+-sys.exit(main())
+diff --git a/setup.py b/setup.py
+deleted file mode 100644
+index 8149f0a..0000000
+--- a/setup.py
++++ /dev/null
+@@ -1,37 +0,0 @@
+-#!/usr/bin/python
+-###############################################################################
+-#                                                                             #
+-# Fireinfo                                                                    #
+-# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
+-#                                                                             #
+-# This program is free software: you can redistribute it and/or modify        #
+-# it under the terms of the GNU General Public License as published by        #
+-# the Free Software Foundation, either version 3 of the License, or           #
+-# (at your option) any later version.                                         #
+-#                                                                             #
+-# This program is distributed in the hope that it will be useful,             #
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+-# GNU General Public License for more details.                                #
+-#                                                                             #
+-# You should have received a copy of the GNU General Public License           #
+-# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+-#                                                                             #
+-###############################################################################
+-
+-from distutils.core import setup, Extension
+-
+-setup(
+-      name = "fireinfo",
+-      version = "2.1.7",
+-      description = "Hardware information gathering library.",
+-      license = "GPLv3",
+-      author = "IPFire.org Team",
+-      author_email = "info@ipfire.org",
+-      url = "https://bugzilla.ipfire.org/describecomponents.cgi?product=Fireinfo",
+-      ext_modules = [
+-              Extension("_fireinfo", ["src/fireinfo.c"])
+-      ],
+-      packages = ["fireinfo"],
+-      scripts = ["sendprofile"],
+-)
+diff --git a/src/_fireinfo/fireinfo.c b/src/_fireinfo/fireinfo.c
+new file mode 100644
+index 0000000..08d714b
+--- /dev/null
++++ b/src/_fireinfo/fireinfo.c
+@@ -0,0 +1,231 @@
++/*
++ * Fireinfo
++ * Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <Python.h>
++
++#include <errno.h>
++#include <fcntl.h>
++#include <linux/hdreg.h>
++#include <stdbool.h>
++#include <string.h>
++#include <sys/ioctl.h>
++
++/* hypervisor vendors */
++enum hypervisors {
++      HYPER_NONE       = 0,
++      HYPER_XEN,
++      HYPER_KVM,
++      HYPER_MSHV,
++      HYPER_VMWARE,
++      HYPER_OTHER,
++      HYPER_LAST /* for loop - must be last*/
++};
++
++const char *hypervisor_ids[] = {
++      [HYPER_NONE]    = NULL,
++      [HYPER_XEN]     = "XenVMMXenVMM",
++      [HYPER_KVM]     = "KVMKVMKVM",
++      /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
++      [HYPER_MSHV]    = "Microsoft Hv",
++      /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
++      [HYPER_VMWARE]  = "VMwareVMware",
++      [HYPER_OTHER]   = NULL
++};
++
++const char *hypervisor_vendors[] = {
++      [HYPER_NONE]    = NULL,
++      [HYPER_XEN]     = "Xen",
++      [HYPER_KVM]     = "KVM",
++      [HYPER_MSHV]    = "Microsoft",
++      [HYPER_VMWARE]  = "VMWare",
++      [HYPER_OTHER]   = "other"
++};
++
++#define NEWLINE "\n\r"
++
++char *truncate_nl(char *s) {
++      assert(s);
++
++      s[strcspn(s, NEWLINE)] = 0;
++      return s;
++}
++
++int read_one_line_file(const char *filename, char **line) {
++      assert(filename);
++      assert(line);
++
++      FILE *f = NULL;
++      f = fopen(filename, "re");
++      if (!f)
++              return -errno;
++
++      char t[2048];
++      if (!fgets(t, sizeof(t), f)) {
++              if (ferror(f))
++                      return errno ? -errno : -EIO;
++
++              t[0] = 0;
++      }
++
++      char *c = strdup(t);
++      if (!c)
++              return -ENOMEM;
++      truncate_nl(c);
++
++      *line = c;
++      return 0;
++}
++
++/*
++ * This CPUID leaf returns the information about the hypervisor.
++ * EAX : maximum input value for CPUID supported by the hypervisor.
++ * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
++ */
++#define HYPERVISOR_INFO_LEAF   0x40000000
++
++int detect_hypervisor(int *hypervisor) {
++#if defined(__x86_64__) || defined(__i386__)
++      /* Try high-level hypervisor sysfs file first: */
++      char *hvtype = NULL;
++      int r = read_one_line_file("/sys/hypervisor/type", &hvtype);
++      if (r >= 0) {
++              if (strcmp(hvtype, "xen") == 0) {
++                      *hypervisor = HYPER_XEN;
++                      return 1;
++              }
++      } else if (r != -ENOENT)
++              return r;
++
++      /* http://lwn.net/Articles/301888/ */
++
++#if defined(__amd64__)
++#define REG_a "rax"
++#define REG_b "rbx"
++#elif defined(__i386__)
++#define REG_a "eax"
++#define REG_b "ebx"
++#endif
++
++      uint32_t eax = 1;
++      uint32_t ecx;
++      union {
++              uint32_t sig32[3];
++              char text[13];
++      } sig = {};
++
++      __asm__ __volatile__ (
++              /* ebx/rbx is being used for PIC! */
++              "  push %%"REG_b"       \n\t"
++              "  cpuid                \n\t"
++              "  pop %%"REG_b"        \n\t"
++
++              : "=a" (eax), "=c" (ecx)
++              : "0" (eax)
++      );
++
++      bool has_hypervisor = !!(ecx & 0x80000000U);
++
++      if (has_hypervisor) {
++              /* There is a hypervisor, see what it is... */
++              eax = 0x40000000U;
++              __asm__ __volatile__ (
++                      "  push %%"REG_b"       \n\t"
++                      "  cpuid                \n\t"
++                      "  mov %%ebx, %1        \n\t"
++                      "  pop %%"REG_b"        \n\t"
++
++                      : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
++                      : "0" (eax)
++              );
++              sig.text[12] = '\0';
++
++              *hypervisor = HYPER_OTHER;
++
++              int id;
++              for (id = HYPER_NONE + 1; id < HYPER_LAST; id++) {
++                      if (strcmp(hypervisor_ids[id], sig.text) == 0) {
++                              *hypervisor = id;
++                              break;
++                      }
++              }
++
++              return 1;
++      }
++#endif
++      return 0;
++}
++
++
++static PyObject *
++do_detect_hypervisor() {
++      /*
++              Get hypervisor from the cpuid command.
++      */
++      int hypervisor = HYPER_NONE;
++
++      int r = detect_hypervisor(&hypervisor);
++      if (r >= 1) {
++              const char* hypervisor_vendor = hypervisor_vendors[hypervisor];
++              if (!hypervisor_vendor)
++                      Py_RETURN_NONE;
++
++              return PyString_FromString(hypervisor_vendor);
++      }
++
++      Py_RETURN_NONE;
++}
++
++static PyObject *
++do_get_harddisk_serial(PyObject *o, PyObject *args) {
++      /*
++              Python wrapper around read_harddisk_serial.
++      */
++      static struct hd_driveid hd;
++      int fd;
++      char *device;
++
++      if (!PyArg_ParseTuple(args, "s", &device))
++              return NULL;
++
++      if ((fd = open(device, O_RDONLY | O_NONBLOCK)) < 0)
++              return NULL;
++
++      if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
++              char serial[21];
++              strncpy(serial, (const char *)hd.serial_no, sizeof(serial));
++
++              if (serial[0])
++                      return PyString_FromString(serial);
++      }
++
++      Py_RETURN_NONE;
++}
++
++static PyMethodDef fireinfoModuleMethods[] = {
++      { "detect_hypervisor", (PyCFunction) do_detect_hypervisor, METH_NOARGS, NULL },
++      { "get_harddisk_serial", (PyCFunction) do_get_harddisk_serial, METH_VARARGS, NULL },
++      { NULL, NULL, 0, NULL }
++};
++
++void init_fireinfo(void) {
++      PyObject *m;
++
++      m = Py_InitModule("_fireinfo", fireinfoModuleMethods);
++      if (m == NULL)
++              return;
++}
+diff --git a/src/fireinfo.c b/src/fireinfo.c
+deleted file mode 100644
+index 25b5333..0000000
+--- a/src/fireinfo.c
++++ /dev/null
+@@ -1,427 +0,0 @@
+-/*
+- * Fireinfo
+- * Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 3 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#include <Python.h>
+-
+-#include <fcntl.h>
+-#include <linux/hdreg.h>
+-#include <stdbool.h>
+-#include <sys/ioctl.h>
+-
+-/*
+-      Big parts of this were taken from
+-      http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git;a=blob;f=sys-utils/lscpu.c
+-*/
+-
+-/* /sys paths */
+-#define _PATH_PROC_XEN                "/proc/xen"
+-#define _PATH_PROC_XENCAP     _PATH_PROC_XEN "/capabilities"
+-#define _PATH_PROC_PCIDEVS    "/proc/bus/pci/devices"
+-
+-/* Used for the vmware hypervisor port detection */
+-#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
+-#define VMWARE_HYPERVISOR_PORT  0x5658
+-
+-#define VMWARE_PORT_CMD_GETVERSION      10
+-
+-/* virtualization types */
+-enum {
+-      VIRT_NONE       = 0,
+-      VIRT_PARA,
+-      VIRT_FULL
+-};
+-const char *virt_types[] = {
+-      [VIRT_NONE]     = "none",
+-      [VIRT_PARA]     = "para",
+-      [VIRT_FULL]     = "full"
+-};
+-
+-/* hypervisor vendors */
+-enum {
+-      HYPER_NONE      = 0,
+-      HYPER_XEN,
+-      HYPER_KVM,
+-      HYPER_MSHV,
+-      HYPER_VMWARE
+-};
+-const char *hv_vendors[] = {
+-      [HYPER_NONE]    = NULL,
+-      [HYPER_XEN]     = "Xen",
+-      [HYPER_KVM]     = "KVM",
+-      [HYPER_MSHV]    = "Microsoft",
+-      [HYPER_VMWARE]  = "VMWare"
+-};
+-
+-struct hypervisor_desc {
+-      int hyper;              /* hypervisor vendor ID */
+-      int virtype;    /* VIRT_PARA|FULL|NONE ? */
+-};
+-
+-static size_t sysrootlen;
+-static char pathbuf[PATH_MAX];
+-
+-static FILE *path_fopen(const char *mode, const char *path, ...)
+-              __attribute__ ((__format__ (__printf__, 2, 3)));
+-static int path_exist(const char *path, ...)
+-              __attribute__ ((__format__ (__printf__, 1, 2)));
+-
+-static const char *
+-path_vcreate(const char *path, va_list ap)
+-{
+-      if (sysrootlen)
+-              vsnprintf(pathbuf + sysrootlen,
+-                        sizeof(pathbuf) - sysrootlen, path, ap);
+-      else
+-              vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
+-      return pathbuf;
+-}
+-
+-static FILE *
+-path_vfopen(const char *mode, const char *path, va_list ap)
+-{
+-      const char *p = path_vcreate(path, ap);
+-
+-      return fopen(p, mode);
+-}
+-
+-static FILE *
+-path_fopen(const char *mode, const char *path, ...)
+-{
+-      FILE *fd;
+-      va_list ap;
+-
+-      va_start(ap, path);
+-      fd = path_vfopen(mode, path, ap);
+-      va_end(ap);
+-
+-      return fd;
+-}
+-
+-static int
+-path_exist(const char *path, ...)
+-{
+-      va_list ap;
+-      const char *p;
+-
+-      va_start(ap, path);
+-      p = path_vcreate(path, ap);
+-      va_end(ap);
+-
+-      return access(p, F_OK) == 0;
+-}
+-
+-static int
+-has_pci_device(int vendor, int device)
+-{
+-      FILE *f;
+-      int num, fn, ven, dev;
+-      int res = 1;
+-
+-      f = path_fopen("r", _PATH_PROC_PCIDEVS);
+-      if (!f)
+-              return 0;
+-
+-       /* for more details about bus/pci/devices format see
+-        * drivers/pci/proc.c in linux kernel
+-        */
+-      while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
+-                      &num, &fn, &ven, &dev) == 4) {
+-
+-              if (ven == vendor && dev == device)
+-                      goto found;
+-      }
+-
+-      res = 0;
+-found:
+-      fclose(f);
+-      return res;
+-}
+-
+-#if defined(__x86_64__) || defined(__i386__)
+-
+-/*
+- * This CPUID leaf returns the information about the hypervisor.
+- * EAX : maximum input value for CPUID supported by the hypervisor.
+- * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
+- */
+-#define HYPERVISOR_INFO_LEAF   0x40000000
+-
+-static inline void
+-cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
+-                       unsigned int *ecx, unsigned int *edx)
+-{
+-      __asm__(
+-#if defined(__PIC__) && defined(__i386__)
+-              /* x86 PIC cannot clobber ebx -- gcc bitches */
+-              "pushl %%ebx;"
+-              "cpuid;"
+-              "movl %%ebx, %%esi;"
+-              "popl %%ebx;"
+-              : "=S" (*ebx),
+-#else
+-              "cpuid;"
+-              : "=b" (*ebx),
+-#endif
+-                "=a" (*eax),
+-                "=c" (*ecx),
+-                "=d" (*edx)
+-              : "1" (op), "c"(0));
+-}
+-
+-static void
+-read_hypervisor_cpuid(struct hypervisor_desc *desc)
+-{
+-      unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
+-      char hyper_vendor_id[13];
+-
+-      memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
+-
+-      cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
+-      memcpy(hyper_vendor_id + 0, &ebx, 4);
+-      memcpy(hyper_vendor_id + 4, &ecx, 4);
+-      memcpy(hyper_vendor_id + 8, &edx, 4);
+-      hyper_vendor_id[12] = '\0';
+-
+-      if (!hyper_vendor_id[0])
+-              return;
+-
+-      if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
+-              desc->hyper = HYPER_XEN;
+-      else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
+-              desc->hyper = HYPER_KVM;
+-      else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
+-              desc->hyper = HYPER_MSHV;
+-      else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
+-              desc->hyper = HYPER_VMWARE;
+-}
+-
+-#else /* ! __x86_64__ */
+-static void
+-read_hypervisor_cpuid(struct hypervisor_desc *desc)
+-{
+-}
+-#endif
+-
+-static void
+-read_hypervisor(struct hypervisor_desc *desc)
+-{
+-      read_hypervisor_cpuid(desc);
+-
+-      if (desc->hyper)
+-              /* hvm */
+-              desc->virtype = VIRT_FULL;
+-
+-      else if (path_exist(_PATH_PROC_XEN)) {
+-              /* Xen para-virt or dom0 */
+-              FILE *fd = path_fopen("r", _PATH_PROC_XENCAP);
+-              int dom0 = 0;
+-
+-              if (fd) {
+-                      char buf[256];
+-
+-                      if (fscanf(fd, "%s", buf) == 1 &&
+-                          !strcmp(buf, "control_d"))
+-                              dom0 = 1;
+-                      fclose(fd);
+-              }
+-              desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
+-              desc->hyper = HYPER_XEN;
+-
+-      } else if (has_pci_device(0x5853, 0x0001)) {
+-              /* Xen full-virt on non-x86_64 */
+-              desc->hyper = HYPER_XEN;
+-              desc->virtype = VIRT_FULL;
+-      }
+-}
+-
+-static void
+-read_harddisk_serial(char *device, char *serial) {
+-      static struct hd_driveid hd;
+-      int fd;
+-
+-      if ((fd = open(device, O_RDONLY | O_NONBLOCK)) < 0) {
+-          return;
+-      }
+-
+-      if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
+-          strncpy(serial, (const char *)hd.serial_no, 20);
+-      }
+-}
+-
+-#if defined(__x86_64__) || defined(__i386__)
+-static bool
+-is_virtualized() {
+-      unsigned int eax, ebx, ecx, edx;
+-
+-      cpuid(0x1, &eax, &ebx, &ecx, &edx);
+-
+-      /*
+-              Bitwise detection of the 31st bit.
+-              This indicates if a host runs in a virtual environment.
+-      */
+-      if (ecx & (1<<31))
+-              return true;
+-
+-      return false;
+-}
+-
+-void
+-hypervisor_port(unsigned int cmd, unsigned int *eax, unsigned int *ebx,
+-              unsigned int *ecx, unsigned int *edx)
+-{
+-      __asm__(
+-#if defined(__PIC__) && defined(__i386__)
+-              /* x86 PIC really cannot clobber ebx */
+-              "pushl %%ebx;"
+-              "inl (%%dx);"
+-              "movl %%ebx, %%esi;"
+-              "popl %%ebx;"
+-              : "=S" (*ebx),
+-#else
+-              "inl (%%dx);"
+-              : "=b" (*ebx),
+-#endif
+-                "=a" (*eax),
+-                "=c" (*ecx),
+-                "=d" (*edx)
+-              : "0" (VMWARE_HYPERVISOR_MAGIC),
+-                "1" (cmd),
+-                "2" (VMWARE_HYPERVISOR_PORT),
+-                "3" (UINT_MAX)
+-              : "memory"
+-      );
+-}
+-#else
+-static bool
+-is_virtualized() {
+-      /*
+-              Always return false, because other architectures
+-              do not support the virtualization bit.
+-      */
+-      return false;
+-}
+-
+-void
+-hypervisor_port(unsigned int cmd, unsigned int *eax, unsigned int *ebx,
+-              unsigned int *ecx, unsigned int *edx)
+-{
+-}
+-#endif
+-
+-int
+-hypervisor_port_check(void) {
+-              uint32_t eax, ebx, ecx, edx;
+-
+-              hypervisor_port(VMWARE_PORT_CMD_GETVERSION, &eax, &ebx, &ecx, &edx);
+-
+-              if (ebx == VMWARE_HYPERVISOR_MAGIC)
+-                      return 1; // Success - running under VMware
+-              else
+-                      return 0;
+-}
+-
+-static PyObject *
+-do_get_hypervisor() {
+-      /*
+-              Get hypervisor from the cpuid command.
+-      */
+-      struct hypervisor_desc _desc, *desc = &_desc;
+-      memset(desc, 0, sizeof(*desc));
+-
+-      read_hypervisor(desc);
+-
+-      PyObject *d = PyDict_New();
+-      PyObject *o;
+-
+-      /* Hypervisor */
+-      if (desc->hyper == HYPER_NONE) {
+-              o = Py_None;
+-      } else {
+-              o = PyString_FromString((const char *)hv_vendors[desc->hyper]);
+-      }
+-      PyDict_SetItemString(d, "hypervisor", o);
+-
+-      /* Virtualization type */
+-      if (desc->virtype == VIRT_NONE) {
+-              o = Py_None;
+-      } else {
+-              o = PyString_FromString((const char *)virt_types[desc->virtype]);
+-      }
+-      PyDict_SetItemString(d, "virtype", o);
+-
+-      return d;
+-}
+-
+-static PyObject *
+-do_is_virtualized() {
+-      /*
+-              Python wrapper around is_virtualized().
+-      */
+-
+-      if (is_virtualized())
+-              return Py_True;
+-
+-      return Py_False;
+-}
+-
+-static PyObject *
+-do_get_harddisk_serial(PyObject *o, PyObject *args) {
+-      /*
+-              Python wrapper around read_harddisk_serial.
+-      */
+-
+-      char serial[21];
+-      memset(serial, 0, sizeof(serial));
+-
+-      char *device;
+-      if (!PyArg_ParseTuple(args, "s", &device))
+-              return NULL;
+-
+-      read_harddisk_serial(device, serial);
+-
+-      if (serial[0])
+-              return PyString_FromString(serial);
+-
+-      return Py_None;
+-}
+-
+-static PyObject *
+-do_hypervisor_port_check() {
+-      /*
+-              Python wrapper around hypervisor_port_check().
+-      */
+-
+-      if (hypervisor_port_check())
+-              return Py_True;
+-
+-      return Py_False;
+-}
+-
+-static PyMethodDef fireinfoModuleMethods[] = {
+-      { "get_hypervisor", (PyCFunction) do_get_hypervisor, METH_NOARGS, NULL },
+-      { "is_virtualized", (PyCFunction) do_is_virtualized, METH_NOARGS, NULL },
+-      { "get_harddisk_serial", (PyCFunction) do_get_harddisk_serial, METH_VARARGS, NULL },
+-      { "vmware_hypervisor_port_check", (PyCFunction) do_hypervisor_port_check, METH_NOARGS, NULL },
+-      { NULL, NULL, 0, NULL }
+-};
+-
+-void init_fireinfo(void) {
+-      PyObject *m;
+-
+-      m = Py_InitModule("_fireinfo", fireinfoModuleMethods);
+-}
+diff --git a/src/fireinfo/__init__.py.in b/src/fireinfo/__init__.py.in
+new file mode 100644
+index 0000000..05c520e
+--- /dev/null
++++ b/src/fireinfo/__init__.py.in
+@@ -0,0 +1,24 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++__version__ = "@PACKAGE_VERSION@"
++
++from system import System
+diff --git a/src/fireinfo/bios.py b/src/fireinfo/bios.py
+new file mode 100644
+index 0000000..56e3af0
+--- /dev/null
++++ b/src/fireinfo/bios.py
+@@ -0,0 +1,50 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2013 IPFire Team (www.ipfire.org)                             #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import os.path
++
++DMI_VENDORS = [
++      "/sys/class/dmi/id/sys_vendor",
++      "/sys/class/dmi/id/board_vendor",
++      "/sys/class/dmi/id/bios_vendor",
++]
++
++class BIOS(object):
++      def __init__(self, system):
++              self.system = system
++
++      def check_vendor(self, vendor, startswith=True):
++              for file in DMI_VENDORS:
++                      if not os.path.exists(file):
++                              continue
++
++                      with open(file, "r") as f:
++                              v = f.read()
++
++                      # Strip the vendor string.
++                      v = v.strip()
++
++                      if startswith and v.startswith(vendor):
++                              return True
++                      elif v == vendor:
++                              return True
++
++              return False
+diff --git a/src/fireinfo/cpu.py b/src/fireinfo/cpu.py
+new file mode 100644
+index 0000000..32d885d
+--- /dev/null
++++ b/src/fireinfo/cpu.py
+@@ -0,0 +1,194 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import os
++
++import system
++
++PROC_CPUINFO = "/proc/cpuinfo"
++
++class CPU(object):
++      """
++              A class that represents the first CPU in a system.
++
++              We get all information form the first CPU (or core) and assume that
++              all other ones are equal.
++      """
++
++      __cpuinfo = {}
++
++      def __init__(self):
++              """
++                      Initialize this class by reading all data from /proc/cpuinfo.
++              """
++              self.__cpuinfo = self.read_cpuinfo()
++
++      @property
++      def system(self):
++              return system.System()
++
++      @staticmethod
++      def read_cpuinfo():
++              """
++                      Read information from PROC_CPUINFO and store
++                      it into a dictionary cpuinfo.
++              """
++              cpuinfo = {}
++
++              f = open(PROC_CPUINFO)
++              while True:
++                      line = f.readline()
++
++                      if not line:
++                              break
++
++                      try:
++                              key, val = line.split(":", 1)
++                      except ValueError:
++                              # We got a line without key, pass that.
++                              pass
++
++                      key = key.strip().replace(" ", "_")
++                      val = val.strip()
++
++                      cpuinfo[key] = val
++
++              f.close()
++
++              return cpuinfo
++
++      @property
++      def bogomips(self):
++              """
++                      Return the bogomips of this CPU.
++              """
++              try:
++                      bogomips = self.__cpuinfo["bogomips"]
++              except KeyError:
++                      bogomips = self.__cpuinfo["BogoMIPS"]
++
++              return float(bogomips)
++
++      @property
++      def model(self):
++              """
++                      Return the model id of this CPU.
++              """
++              try:
++                      model = int(self.__cpuinfo["model"])
++              except KeyError:
++                      model = None
++
++              return model
++
++      @property
++      def model_string(self):
++              """
++                      Return the model string of this CPU.
++              """
++              try:
++                      return self.__cpuinfo["model_name"]
++              except KeyError:
++                      return self.__cpuinfo["Processor"]
++
++      @property
++      def vendor(self):
++              """
++                      Return the vendor string of this CPU.
++              """
++              try:
++                      vendor = self.__cpuinfo["vendor_id"]
++              except KeyError:
++                      if self.system.arch.startswith("arm"):
++                              vendor = "ARM"
++                      else:
++                              vendor = ""
++
++              return vendor
++
++      @property
++      def stepping(self):
++              """
++                      Return the stepping id of this CPU.
++              """
++              try:
++                      stepping = int(self.__cpuinfo["stepping"])
++              except KeyError:
++                      stepping = None
++
++              return stepping
++
++      @property
++      def flags(self):
++              """
++                      Return all flags of this CPU.
++              """
++              try:
++                      flags = self.__cpuinfo["flags"]
++              except KeyError:
++                      flags = self.__cpuinfo["Features"]
++
++              return flags.split()
++
++      @property
++      def speed(self):
++              """
++                      Return the speed (in MHz) of this CPU.
++              """
++              try:
++                      speed = float(self.__cpuinfo["cpu_MHz"])
++              except KeyError:
++                      speed = 0
++
++              return speed
++
++      @property
++      def family(self):
++              """
++                      Return the family id of this CPU.
++              """
++              try:
++                      family = int(self.__cpuinfo["cpu_family"])
++              except KeyError:
++                      family = None
++
++              return family
++      
++      @property
++      def count(self):
++              """
++                      Count number of CPUs (cores).
++              """
++              return os.sysconf("SC_NPROCESSORS_ONLN")
++
++
++if __name__ == "__main__":
++      c = CPU()
++
++      print "Vendor:", c.vendor
++      print "Model:", c.model
++      print "Stepping:", c.stepping
++      print "Flags:", c.flags
++      print "Bogomips:", c.bogomips
++      print "Speed:", c.speed
++      print "Family:", c.family
++      print "Count:", c.count
++      print "Model string:", c.model_string
+diff --git a/src/fireinfo/device.py b/src/fireinfo/device.py
+new file mode 100644
+index 0000000..01338b2
+--- /dev/null
++++ b/src/fireinfo/device.py
+@@ -0,0 +1,133 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import os.path
++
++class Device(object):
++      """
++              This is an abstract class that represents all devices in the system.
++              Every single device has its own instance of this class.
++      """
++
++      def __init__(self, path):
++              """
++                      Collect all information about the device by reading the
++                      "uevent" file and parsing it.
++              """
++
++              # Save the path in /sys to the device.
++              self.path = path
++
++              # Datastructure to store information we read.
++              self._uevent = {}
++
++              # Open the uevent file and parse all lines.
++              with open(os.path.join(path, "uevent")) as f:
++                      for line in f.readlines():
++                              key, val = line.split("=")
++                              self._uevent[key] = val.rstrip().lower()
++
++      @property
++      def driver(self):
++              """
++                      Get the driver/kernel module that device is driven by or return None.
++              """
++              return self._uevent.get("DRIVER", None)
++
++                      
++class PCIDevice(Device):
++      """
++              A class that represents all PCI (and PCIe) devices in a system.
++      """
++
++      subsystem = "pci"
++
++      @property
++      def model(self):
++              """
++                      Return the PCI model id of this device.
++              """
++              return self._uevent['PCI_ID'].split(":")[1]
++              
++      @property
++      def vendor(self):
++              """
++                      Return the PCI vendor id of this device.
++              """
++              return self._uevent['PCI_ID'].split(":")[0]
++
++      @property
++      def deviceclass(self):
++              """
++                      Return the PCI device class of this device.
++              """
++              return self._uevent['PCI_CLASS']
++
++      @property
++      def sub_vendor(self):
++              """
++                      Return the PCI vendor sub id of this device.
++              """
++              return self._uevent["PCI_SUBSYS_ID"].split(":")[0]
++
++      @property
++      def sub_model(self):
++              """
++                      Return the PCI model sub id of this device.
++              """
++              return self._uevent["PCI_SUBSYS_ID"].split(":")[1]
++
++
++class USBDevice(Device):
++      """
++              A class that represents all USB devices in a system.
++      """
++
++      subsystem = "usb"
++      
++      def pad(self, s):
++              """
++                      A function to pad ids that have no leading zeroes.
++              """
++              while len(s) < 4:
++                      s = "0"+s
++              return s
++
++      @property
++      def vendor(self):
++              """
++                      Return the USB vendor id of this device.
++              """
++              return self.pad(self._uevent['PRODUCT'].split("/")[0])
++
++      @property
++      def model(self):
++              """
++                      Return the USB model id of this device.
++              """
++              return self.pad(self._uevent['PRODUCT'].split("/")[1])
++
++      @property
++      def deviceclass(self):
++              """
++                      Return the USB device class of this device.
++              """
++              return self._uevent.get("INTERFACE", None)
+diff --git a/src/fireinfo/hypervisor.py b/src/fireinfo/hypervisor.py
+new file mode 100644
+index 0000000..0c07cfa
+--- /dev/null
++++ b/src/fireinfo/hypervisor.py
+@@ -0,0 +1,119 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import _fireinfo
++import system
++
++class Hypervisor(object):
++      def __init__(self):
++              self.__hypervisor = _fireinfo.detect_hypervisor()
++
++      @property
++      def system(self):
++              """
++                      Return the current instance of the System class.
++
++                      We need to do that as a property because otherwise
++                      we get a recursion.
++              """
++              return system.System()
++
++      @property
++      def vendor(self):
++              """
++                      Returns the name of the hypervisor vendor.
++              """
++              # Citrix Xen says it is Microsoft Hv.
++              if self.__hypervisor == "Microsoft" and self.system.bios_vendor == "Xen":
++                      return "Xen"
++
++              # Some of the hypervisors can be detected in a right way.
++              # We can return them at this place.
++              if self.__hypervisor:
++                      return self.__hypervisor
++
++              # Check DMI and BIOS information...
++              if self.__bios_is_bochs():
++                      return "Bochs"
++              elif self.__bios_is_microsoft():
++                      return "Microsoft"
++              elif self.__bios_is_qemu():
++                      return "Qemu"
++              elif self.__bios_is_virtualbox():
++                      return "VirtualBox"
++              elif self.__bios_is_vmware():
++                      return "VMWare"
++              elif self.__bios_is_xen():
++                      return "Xen"
++
++      @property
++      def virtual(self):
++              """
++                      Returns true if the host is running in a virtual environment.
++                      Otherwise: false.
++              """
++              if self.vendor:
++                      return True
++
++              return False
++
++      def __bios_is_bochs(self):
++              """
++                      Check for Bochs emulator.
++              """
++              return self.system.bios.check_vendor("Bochs")
++
++      def __bios_is_microsoft(self):
++              """
++                      Check for Microsoft hypervisor.
++              """
++              return self.system.bios.check_vendor("Microsoft Corporation")
++
++      def __bios_is_qemu(self):
++              """
++                      Check for qemu emulator.
++              """
++              return self.system.bios.check_vendor("QEMU")
++
++      def __bios_is_virtualbox(self):
++              """
++                      Check for virtualbox hypervisor by comparing the bios vendor string
++                      to "innotek GmbH".
++              """
++              return self.system.bios.check_vendor("innotek GmbH")
++
++      def __bios_is_vmware(self):
++              if self.system.bios.check_vendor("VMware-"):
++                      return True
++              elif self.system.bios.check_vendor("VMW"):
++                      return True
++
++              return False
++
++      def __bios_is_xen(self):
++              return self.system.bios.check_vendor("Xen")
++
++
++if __name__ == "__main__":
++      h = Hypervisor()
++
++      print "Vendor:", h.vendor
++      print "Virtual:", h.virtual
+diff --git a/src/fireinfo/network.py b/src/fireinfo/network.py
+new file mode 100644
+index 0000000..063e9ec
+--- /dev/null
++++ b/src/fireinfo/network.py
+@@ -0,0 +1,53 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import os
++
++SYS_CLASS_NET = "/sys/class/net"
++
++class Network(object):
++      def __init__(self):
++              self._devices = os.listdir(SYS_CLASS_NET)
++
++      def has_green(self):
++              return "green0" in self._devices
++
++      def has_red(self):
++              for i in ("red0", "ppp0"):
++                      if i in self._devices:
++                              return True
++
++              return False
++
++      def has_blue(self):
++              return "blue0" in self._devices
++
++      def has_orange(self):
++              return "orange0" in self._devices
++
++
++if __name__ == "__main__":
++      n = Network()
++
++      print "has_green", n.has_green()
++      print "has_red", n.has_red()
++      print "has_blue", n.has_blue()
++      print "has_orange", n.has_orange()
+diff --git a/src/fireinfo/system.py b/src/fireinfo/system.py
+new file mode 100644
+index 0000000..0a60bcc
+--- /dev/null
++++ b/src/fireinfo/system.py
+@@ -0,0 +1,451 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import hashlib
++import json
++import os
++import string
++
++import _fireinfo
++
++import bios
++import cpu
++import device
++import hypervisor
++import network
++
++PROFILE_VERSION = 0
++
++SYS_CLASS_DMI = "/sys/class/dmi/id"
++SECRET_ID_FILE = "/etc/fireinfo-id"
++
++INVALID_ID_STRINGS = (
++      "OEM", "O.E.M.", "o.e.m.",
++      "N/A", "n/a",
++      "12345", "54321", "202020",
++      "Chassis", "chassis",
++      "Not Applicable",
++      "None", "empty",
++      "01010101-0101-0101-0101-010101010101",
++      "00020003-0004-0005-0006-000700080009",
++      "03000200-0400-0500-0006-000700080009",
++      "0000000", "00000000",
++)
++
++class Singleton(type):
++      def __init__(cls, name, bases, dict):
++              super(Singleton, cls).__init__(name, bases, dict)
++              cls.instance = None
++
++      def __call__(cls, *args, **kw):
++              if cls.instance is None:
++                      cls.instance = super(Singleton, cls).__call__(*args, **kw)
++
++              return cls.instance
++
++
++def read_from_file(filename):
++      """
++              Read all data from filename.
++      """
++      if not os.path.exists(filename):
++              return
++
++      try:
++              with open(filename) as f:
++                      return f.read().strip()
++      except IOError:
++              pass
++
++class System(object):
++      __metaclass__ = Singleton
++
++      def __init__(self):
++              self.bios = bios.BIOS(self)
++
++              # find all devices
++              self.devices = []
++              self.scan()
++              self.cpu = cpu.CPU()
++              self.hypervisor = hypervisor.Hypervisor()
++
++              # Read /proc/cpuinfo for vendor information.
++              self.__cpuinfo = self.cpu.read_cpuinfo()
++
++      def profile(self):
++              p = {}
++              p["system"] = {
++                      # System information
++                      "model"  : self.model,
++                      "vendor" : self.vendor,
++
++                      # Indicator if the system is running in a
++                      # virtual environment.
++                      "virtual" : self.virtual,
++                      
++                      # System language
++                      "language" : self.language,
++
++                      # Release information
++                      "release" : self.release,
++                      "kernel_release" : self.kernel_release,
++
++                      "memory" : self.memory,
++                      "root_size" : self.root_size,
++              }
++
++              p["devices"] = []
++              for device in self.devices:
++                      d = {
++                              "subsystem" : device.subsystem.lower(), 
++                              "vendor" : device.vendor.lower(), 
++                              "model" : device.model.lower(), 
++                              "deviceclass" : device.deviceclass,
++                              "driver" : device.driver,
++                      }
++
++                      # PCI devices provide subsystem information, USB don't.
++                      if d["subsystem"] == "pci":
++                              d["sub_model"] = device.sub_model
++                              d["sub_vendor"] = device.sub_vendor
++
++                      p["devices"].append(d)
++
++              p["cpu"] = {
++                      "arch" : self.arch,
++                      "vendor" : self.cpu.vendor,
++                      "model" : self.cpu.model,
++                      "model_string" : self.cpu.model_string,
++                      "stepping" : self.cpu.stepping,
++                      "flags" : self.cpu.flags,
++                      "bogomips" : self.cpu.bogomips,
++                      "speed" : self.cpu.speed,
++                      "family" : self.cpu.family,
++                      "count" : self.cpu.count                                
++              }
++
++              p["network"] = {
++                      "green" : self.network.has_green(),
++                      "blue" : self.network.has_blue(),
++                      "orange" : self.network.has_orange(),
++                      "red" : self.network.has_red(),
++               }
++
++              # Only append hypervisor information if we are virtualized.
++              if self.virtual:
++                      p["hypervisor"] = {
++                              "vendor" : self.hypervisor.vendor,
++                      }
++
++              return {
++                      # Profile version
++                      "profile_version" : PROFILE_VERSION,
++
++                      # Identification and authorization codes
++                      "public_id" : self.public_id,
++                      "private_id" : self.private_id,
++
++                      # Actual profile data
++                      "profile" : p,
++              }
++                              
++              
++      @property
++      def arch(self):
++              return os.uname()[4]
++
++      @property
++      def public_id(self):
++              """
++                      This returns a globally (hopefully) ID to identify the host
++                      later (by request) in the database.
++              """
++              public_id = self.secret_id
++              if not public_id:
++                      return "0" * 40
++
++              return hashlib.sha1(public_id).hexdigest()
++
++      @property
++      def private_id(self):
++              """
++                      The private ID is built out of the _unique_id and used to
++                      permit a host to do changes on the database.
++
++                      No one could ever guess this without access to the host.
++              """
++              private_id = ""
++              for i in reversed(self.secret_id):
++                      private_id += i
++
++              if not private_id:
++                      return "0" * 40
++
++              return hashlib.sha1(private_id).hexdigest()
++
++      @property
++      def secret_id(self):
++              """
++                      Read a "secret" ID from a file if available
++                      or calculate it from the hardware.
++              """
++              if os.path.exists(SECRET_ID_FILE):
++                      return read_from_file(SECRET_ID_FILE)
++
++              return hashlib.sha1(self._unique_id).hexdigest()
++
++      @property
++      def _unique_id(self):
++              """
++                      This is a helper ID which is generated out of some hardware information
++                      that is considered to be constant over a PC's lifetime.
++
++                      None of the data here is ever sent to the server.
++              """
++              ids = []
++
++              # Virtual machines (for example) and some boards have a UUID
++              # which is globally unique.
++              for file in ("product_uuid", "product_serial", "chassis_serial"):
++                      id = read_from_file(os.path.join(SYS_CLASS_DMI, file))
++                      ids.append(id)
++
++              # Sort out all bogous or invalid strings from the list.
++              _ids = []
++              for id in ids:
++                      if id is None:
++                              continue
++
++                      for i in INVALID_ID_STRINGS:
++                              if i in id:
++                                      id = None
++                                      break
++
++                      if id:
++                              _ids.append(id)
++
++              ids = _ids
++
++              # Use serial number from root disk (if available) and if
++              # no other ID was found, yet.
++              if not ids:
++                      root_disk_serial = self.root_disk_serial
++                      if root_disk_serial and not root_disk_serial.startswith("QM000"):
++                              ids.append(root_disk_serial)
++
++              # As last resort, we use the UUID from pakfire.
++              if not ids:
++                      id = read_from_file("/opt/pakfire/db/uuid")
++                      ids.append(id)
++
++              return "#".join(ids)
++
++      @property
++      def language(self):
++              """
++                      Return the language code of IPFire or "unknown" if we cannot get it.
++              """
++              # Return "unknown" if settings file does not exist.
++              filename = "/var/ipfire/main/settings"
++              if not os.path.exists(filename):
++                      return "unknown"
++
++              with open(filename, "r") as f:
++                      for line in f.readlines():
++                              key, val = line.split("=", 1)
++                              if key == "LANGUAGE":
++                                      return val.strip()
++
++      @property
++      def release(self):
++              """
++                      Return the system release string.
++              """
++              return read_from_file("/etc/system-release") or "unknown"
++
++      @property
++      def bios_vendor(self):
++              """
++                      Return the bios vendor name.
++              """
++              return read_from_file("/sys/class/dmi/id/bios_vendor")
++
++      def vendor_model_tuple(self):
++              try:
++                      s = self.__cpuinfo["Hardware"]
++              except KeyError:
++                      return (None, None)
++
++              if s.startswith("ARM-Versatile"):
++                      return ("ARM", s)
++
++              try:
++                      v, m = s.split(" ", 1)
++              except ValueError:
++                      if s.startswith("BCM"):
++                              v = "Broadcom"
++                              m = s
++                      else:
++                              v = None
++                              m = s
++
++              return v, m
++
++      @property
++      def vendor(self):
++              """
++                      Return the vendor string of this system (if any).
++              """
++              ret = None
++              for file in ("sys_vendor", "board_vendor", "chassis_vendor",):
++                      ret = read_from_file(os.path.join(SYS_CLASS_DMI, file))
++                      if ret:
++                              break
++
++              if ret is None:
++                      v, m = self.vendor_model_tuple()
++                      ret = v
++
++              return ret
++
++      @property
++      def model(self):
++              """
++                      Return the model string of this system (if any).
++              """
++              ret = None
++              for file in ("product_name", "board_model", "chassis_model",):
++                      ret = read_from_file(os.path.join(SYS_CLASS_DMI, file))
++                      if ret:
++                              break
++
++              if ret is None:
++                      v, m = self.vendor_model_tuple()
++                      ret = m
++
++              return ret
++
++      @property
++      def memory(self):
++              """
++                      Return the amount of memory in kilobytes.
++              """
++              with open("/proc/meminfo", "r") as f:
++                      firstline = f.readline().strip()
++                      return int(firstline.split()[1])
++
++      @property
++      def kernel_release(self):
++              """
++                      Return the kernel release string.
++              """
++              return os.uname()[2]
++
++      @property
++      def root_disk(self):
++              """
++                      Return the dev node of the root disk.
++              """
++              with open("/etc/mtab", "r") as f:
++                      dev, mountpoint, fs, rest = f.readline().split(" ", 3)
++                      if mountpoint == "/" and not fs == "rootfs":
++                              # Cut off /dev
++                              dev = dev[5:]
++
++                              # Handle raids and MMC cards like (mmcblk0p3).
++                              if dev[-2] == "p":
++                                      return dev[:-2]
++
++                              # Otherwise cut off all digits at end of string
++                              while dev[-1] in string.digits:
++                                      dev = dev[:-1]
++
++                              return dev
++
++      @property
++      def root_size(self):
++              """
++                      Return the size of the root disk in kilobytes.
++              """
++              path = "/sys/block/%s/size" % self.root_disk
++              if not os.path.exists(path):
++                      return
++
++              with open(path, "r") as f:
++                      return int(f.readline()) * 512 / 1024
++
++      @property
++      def root_disk_serial(self):
++              """
++                      Return the serial number of the root disk (if any).
++              """
++              serial = _fireinfo.get_harddisk_serial("/dev/%s" % self.root_disk)
++
++              if serial:
++                      # Strip all spaces
++                      return serial.strip()
++
++      def scan(self):
++              """
++                      Scan for all devices (PCI/USB) in the system and append them
++                      to our list.
++              """
++              self.devices = []
++
++              toscan = (
++                      ("/sys/bus/pci/devices", device.PCIDevice),
++                      ("/sys/bus/usb/devices", device.USBDevice)
++              )
++              for path, cls in toscan:
++                      if not os.path.exists(path):
++                              continue
++
++                      dirlist = os.listdir(path)
++                      for dir in dirlist:
++                              self.devices.append(cls(os.path.join(path, dir)))
++
++      @property
++      def virtual(self):
++              """
++                      Say if the host is running in a virtual environment.
++              """
++              return self.hypervisor.virtual
++
++      @property
++      def network(self):
++              """
++                      Reference to the network class.
++              """
++              return network.Network()
++
++
++if __name__ == "__main__":
++      s=System()
++      print s.arch
++      print s.language
++      print s.release
++      print s.bios_vendor
++      print s.memory
++      print s.kernel
++      print s.root_disk
++      print s.root_size
++      print "------------\n", s.devices, "\n------------\n"
++      print json.dumps(s.profile(), sort_keys=True, indent=4)
+diff --git a/src/sendprofile b/src/sendprofile
+new file mode 100644
+index 0000000..da480ce
+--- /dev/null
++++ b/src/sendprofile
+@@ -0,0 +1,132 @@
++#!/usr/bin/python
++###############################################################################
++#                                                                             #
++# Fireinfo                                                                    #
++# Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)                       #
++#                                                                             #
++# This program is free software: you can redistribute it and/or modify        #
++# it under the terms of the GNU General Public License as published by        #
++# the Free Software Foundation, either version 3 of the License, or           #
++# (at your option) any later version.                                         #
++#                                                                             #
++# This program is distributed in the hope that it will be useful,             #
++# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
++# GNU General Public License for more details.                                #
++#                                                                             #
++# You should have received a copy of the GNU General Public License           #
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
++#                                                                             #
++###############################################################################
++
++import json
++import logging
++import logging.handlers
++import os
++import sys
++import urllib
++import urllib2
++
++import fireinfo
++
++ENABLED_FILE = "/var/ipfire/main/send_profile"
++PROXY_SETTINGS = "/var/ipfire/proxy/advanced/settings"
++
++log_level = logging.INFO
++if "-d" in sys.argv:
++      log_level = logging.DEBUG
++
++# Setup logging
++log = logging.getLogger()
++log.setLevel(log_level)
++log.addHandler(logging.handlers.SysLogHandler("/dev/log"))
++log.addHandler(logging.StreamHandler(sys.stderr))
++for handler in log.handlers:
++      handler.setLevel(log_level)
++
++PROFILE_URL = "http://fireinfo.ipfire.org/send/%(public_id)s"
++
++def get_upstream_proxy():
++      if not os.path.exists(PROXY_SETTINGS):
++              return {"host" : ""}
++
++      proxy_settings = {}
++      with open(PROXY_SETTINGS) as f:
++              for line in f.readlines():
++                      k, v = line.split("=", 1)
++                      proxy_settings[k] = v.strip()
++
++      return {
++              "host" : proxy_settings.get("UPSTREAM_PROXY", ""),
++              "user" : proxy_settings.get("UPSTREAM_USER", ""),
++              "pass" : proxy_settings.get("UPSTREAM_PASSWORD", ""),
++      }
++
++def send_profile(profile):
++      logging.debug("Sending profile:")
++      for line in json.dumps(profile, sort_keys=True, indent=4).splitlines():
++              logging.debug(line)
++
++      request = urllib2.Request(PROFILE_URL % profile,
++              data = urllib.urlencode({"profile" : json.dumps(profile)}),
++      )
++      request.add_header("User-Agent", "fireinfo/%s" % fireinfo.__version__)
++
++      # Set upstream proxy if we have one.
++      # XXX this cannot handle authentication
++      proxy = get_upstream_proxy()
++      if proxy["host"]:
++              request.set_proxy(proxy["host"], "http")
++
++      try:
++              urllib2.urlopen(request, timeout=60)
++      except (urllib2.HTTPError, urllib2.URLError), e:
++              reason = "Unknown reason"
++
++              if isinstance(e, urllib2.HTTPError):
++                      reason = "%s" % e
++              elif isinstance(e, urllib2.URLError):
++                      reason = e.reason
++
++              logging.error("Profile was not sent propertly: %s" % reason)
++              return
++
++      logging.debug("Profile was sent successfully.")
++
++def main():
++      # Collect system information
++      system = fireinfo.System()
++      profile = system.profile()
++
++      # If --dump is passed -> only dump the output.
++      if "--dump" in sys.argv:
++              # Remove the private id when dumping the profile because
++              # it contains no information and may confuse people.
++              del profile["private_id"]
++
++              print json.dumps(profile, sort_keys=True, indent=4)
++              return 0
++
++      if "--secret-id" in sys.argv:
++              print system.secret_id
++              return 0
++
++      if "--hardware-string" in sys.argv:
++              print system._unique_id
++              return 0
++
++      if "--public-id" in sys.argv:
++              print system.public_id
++              return 0
++
++      if not os.path.exists(ENABLED_FILE):
++              del profile["profile"]
++
++      try:
++              send_profile(profile)
++      except urllib2.URLError:
++              return 1
++
++      return 0
++
++sys.exit(main())