├── COPYING-GPL ├── COPYING-OSL ├── COPYING.LIB ├── Makefile-std ├── Makefile.am ├── README ├── autogen.sh ├── bin ├── firmwaretool └── inventory_firmware_gui ├── configure.ac ├── doc ├── bootstrap.txt ├── bootstrap_firmware.8 ├── inventory_firmware.8 ├── inventory_firmware_gui.8 ├── update_firmware.8 └── verbosity.txt ├── etc └── firmware │ └── firmware.conf ├── firmwaretools ├── __init__.py ├── bootstrap_pci.py ├── compat_subprocess.py ├── dep_parser.py ├── errors.py ├── i18n.py ├── mockpackage.py ├── mockrepository.py ├── package.py ├── peak_util_decorators.py ├── peak_util_decorators_README.txt ├── plugins.py ├── ply_lex.py ├── ply_yacc.py ├── pycompat.py ├── repository.py └── trace_decorator.py ├── ft-cli ├── cli.py ├── ftcommands.py ├── ftmain.py ├── guihelpers.py └── plugins │ ├── bootstrap_cmd.py │ ├── inventory_cmd.py │ ├── listplugins_cmd.py │ └── update_cmd.py ├── glade ├── inventory_firmware_gui.glade └── inventory_firmware_gui.gladep ├── pkg ├── debian │ ├── changelog.in │ ├── compat │ ├── control │ ├── copyright │ ├── docs │ ├── linda.overrides │ ├── manpages │ ├── postinst │ ├── pyversions │ ├── rules │ ├── triggers │ └── watch ├── firmware-tools.spec.in └── mk-rel-rpm.sh ├── test ├── TestLib.py ├── datafiles │ ├── system_ven_0x5555_dev_0x1234 │ │ ├── system_specific-a03 │ │ │ └── package.ini │ │ └── system_specific-a04 │ │ │ └── package.ini │ ├── system_ven_0x5555_dev_0x4321 │ │ ├── system_specific-a08 │ │ │ └── package.ini │ │ └── system_specific-a09 │ │ │ └── package.ini │ ├── test_requires-a09 │ │ └── package.ini │ ├── testorder1-a04 │ │ └── package.ini │ ├── testorder2-a05 │ │ └── package.ini │ ├── testorder3-a06 │ │ └── package.ini │ ├── testpack-a04 │ │ └── package.ini │ ├── testpack-a05 │ │ └── package.ini │ ├── testpack-a06 │ │ └── package.ini │ ├── testpack_another-a04 │ │ └── package.ini │ ├── testpack_different-a07 │ │ └── package.ini │ └── testpack_newpkgstrat-a08 │ │ └── package.ini ├── testAll.py ├── testDepParser.py ├── testPackage.py ├── testPciBootstrap.py ├── testPycompat.py └── testRepository.py └── yum-plugin ├── firmwaretools_bootstrap.conf └── firmwaretools_bootstrap.py /COPYING-GPL: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /COPYING-OSL: -------------------------------------------------------------------------------- 1 | Open Software License ("OSL") v. 3.0 2 | 3 | This Open Software License (the "License") applies to any original 4 | work of authorship (the "Original Work") whose owner (the "Licensor") 5 | has placed the following licensing notice adjacent to the copyright 6 | notice for the Original Work: 7 | 8 | Licensed under the Open Software License version 3.0 9 | 10 | 1. Grant of Copyright License. Licensor grants You a worldwide, 11 | royalty-free, non-exclusive, sublicensable license, for the 12 | duration of the copyright, to do the following: 13 | 14 | 1. to reproduce the Original Work in copies, either alone or 15 | as part of a collective work; 16 | 17 | 2. to translate, adapt, alter, transform, modify, or arrange 18 | the Original Work, thereby creating derivative works 19 | ("Derivative Works") based upon the Original Work; 20 | 21 | 3. to distribute or communicate copies of the Original Work 22 | and Derivative Works to the public, with the proviso that 23 | copies of Original Work or Derivative Works that You 24 | distribute or communicate shall be licensed under this 25 | Open Software License; 26 | 27 | 4. to perform the Original Work publicly; and 28 | 29 | 5. to display the Original Work publicly. 30 | 31 | 2. Grant of Patent License. Licensor grants You a worldwide, 32 | royalty-free, non-exclusive, sublicensable license, under patent 33 | claims owned or controlled by the Licensor that are embodied in 34 | the Original Work as furnished by the Licensor, for the duration 35 | of the patents, to make, use, sell, offer for sale, have made, 36 | and import the Original Work and Derivative Works. 37 | 38 | 3. Grant of Source Code License. The term "Source Code" means the 39 | preferred form of the Original Work for making modifications to 40 | it and all available documentation describing how to modify the 41 | Original Work. Licensor agrees to provide a machine-readable 42 | copy of the Source Code of the Original Work along with each 43 | copy of the Original Work that Licensor distributes. Licensor 44 | reserves the right to satisfy this obligation by placing a 45 | machine-readable copy of the Source Code in an information 46 | repository reasonably calculated to permit inexpensive and 47 | convenient access by You for as long as Licensor continues to 48 | distribute the Original Work. 49 | 50 | 4. Exclusions From License Grant. Neither the names of Licensor, 51 | nor the names of any contributors to the Original Work, nor any 52 | of their trademarks or service marks, may be used to endorse or 53 | promote products derived from this Original Work without express 54 | prior permission of the Licensor. Except as expressly stated 55 | herein, nothing in this License grants any license to Licensor's 56 | trademarks, copyrights, patents, trade secrets or any other 57 | intellectual property. No patent license is granted to make, 58 | use, sell, offer for sale, have made, or import embodiments of 59 | any patent claims other than the licensed claims defined in 60 | Section 2. No license is granted to the trademarks of Licensor 61 | even if such marks are included in the Original Work. Nothing in 62 | this License shall be interpreted to prohibit Licensor from 63 | licensing under terms different from this License any Original 64 | Work that Licensor otherwise would have a right to license. 65 | 66 | 5. External Deployment. The term "External Deployment" means the 67 | use, distribution, or communication of the Original Work or 68 | Derivative Works in any way such that the Original Work or 69 | Derivative Works may be used by anyone other than You, whether 70 | those works are distributed or communicated to those persons or 71 | made available as an application intended for use over a 72 | network. As an express condition for the grants of license 73 | hereunder, You must treat any External Deployment by You of the 74 | Original Work or a Derivative Work as a distribution under 75 | section 1(c). 76 | 77 | 6. Attribution Rights. You must retain, in the Source Code of any 78 | Derivative Works that You create, all copyright, patent, or 79 | trademark notices from the Source Code of the Original Work, as 80 | well as any notices of licensing and any descriptive text 81 | identified therein as an "Attribution Notice." You must cause 82 | the Source Code for any Derivative Works that You create to 83 | carry a prominent Attribution Notice reasonably calculated to 84 | inform recipients that You have modified the Original Work. 85 | 86 | 7. Warranty of Provenance and Disclaimer of Warranty. Licensor 87 | warrants that the copyright in and to the Original Work and the 88 | patent rights granted herein by Licensor are owned by the 89 | Licensor or are sublicensed to You under the terms of this 90 | License with the permission of the contributor(s) of those 91 | copyrights and patent rights. Except as expressly stated in the 92 | immediately preceding sentence, the Original Work is provided 93 | under this License on an "AS IS" BASIS and WITHOUT WARRANTY, 94 | either express or implied, including, without limitation, the 95 | warranties of non-infringement, merchantability or fitness for a 96 | particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE 97 | ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY 98 | constitutes an essential part of this License. No license to the 99 | Original Work is granted by this License except under this 100 | disclaimer. 101 | 102 | 8. Limitation of Liability. Under no circumstances and under no 103 | legal theory, whether in tort (including negligence), contract, 104 | or otherwise, shall the Licensor be liable to anyone for any 105 | indirect, special, incidental, or consequential damages of any 106 | character arising as a result of this License or the use of the 107 | Original Work including, without limitation, damages for loss of 108 | goodwill, work stoppage, computer failure or malfunction, or any 109 | and all other commercial damages or losses. This limitation of 110 | liability shall not apply to the extent applicable law prohibits 111 | such limitation. 112 | 113 | 9. Acceptance and Termination. If, at any time, You expressly 114 | assented to this License, that assent indicates your clear and 115 | irrevocable acceptance of this License and all of its terms and 116 | conditions. If You distribute or communicate copies of the 117 | Original Work or a Derivative Work, You must make a reasonable 118 | effort under the circumstances to obtain the express assent of 119 | recipients to the terms of this License. This License conditions 120 | your rights to undertake the activities listed in Section 1, 121 | including your right to create Derivative Works based upon the 122 | Original Work, and doing so without honoring these terms and 123 | conditions is prohibited by copyright law and international 124 | treaty. Nothing in this License is intended to affect copyright 125 | exceptions and limitations (including 'fair use' or 'fair 126 | dealing'). This License shall terminate immediately and You may 127 | no longer exercise any of the rights granted to You by this 128 | License upon your failure to honor the conditions in Section 129 | 1(c). 130 | 131 | 10. Termination for Patent Action. This License shall terminate 132 | automatically and You may no longer exercise any of the rights 133 | granted to You by this License as of the date You commence an 134 | action, including a cross-claim or counterclaim, against 135 | Licensor or any licensee alleging that the Original Work 136 | infringes a patent. This termination provision shall not apply 137 | for an action alleging patent infringement by combinations of 138 | the Original Work with other software or hardware. 139 | 140 | 11. Jurisdiction, Venue and Governing Law. Any action or suit 141 | relating to this License may be brought only in the courts of a 142 | jurisdiction wherein the Licensor resides or in which Licensor 143 | conducts its primary business, and under the laws of that 144 | jurisdiction excluding its conflict-of-law provisions. The 145 | application of the United Nations Convention on Contracts for 146 | the International Sale of Goods is expressly excluded. Any use 147 | of the Original Work outside the scope of this License or after 148 | its termination shall be subject to the requirements and 149 | penalties of copyright or patent law in the appropriate 150 | jurisdiction. This section shall survive the termination of this 151 | License. 152 | 153 | 12. Attorneys' Fees. In any action to enforce the terms of this 154 | License or seeking damages relating thereto, the prevailing 155 | party shall be entitled to recover its costs and expenses, 156 | including, without limitation, reasonable attorneys' fees and 157 | costs incurred in connection with such action, including any 158 | appeal of such action. This section shall survive the 159 | termination of this License. 160 | 161 | 13. Miscellaneous. If any provision of this License is held to be 162 | unenforceable, such provision shall be reformed only to the 163 | extent necessary to make it enforceable. 164 | 165 | 14. Definition of "You" in This License. "You" throughout this License, 166 | whether in upper or lower case, means an individual or a legal 167 | entity exercising rights under, and complying with all of the 168 | terms of, this License. For legal entities, "You" includes any 169 | entity that controls, is controlled by, or is under common 170 | control with you. For purposes of this definition, "control" 171 | means (i) the power, direct or indirect, to cause the direction 172 | or management of such entity, whether by contract or otherwise, 173 | or (ii) ownership of fifty percent (50%) or more of the 174 | outstanding shares, or (iii) beneficial ownership of such 175 | entity. 176 | 177 | 15. Right to Use. You may use the Original Work in all ways not 178 | otherwise restricted or conditioned by this License or by law, 179 | and Licensor promises not to interfere with or be responsible 180 | for such uses by You. 181 | 182 | 16. Modification of This License. This License is Copyright (c) 2005 183 | Lawrence Rosen. Permission is granted to copy, distribute, or 184 | communicate this License without modification. Nothing in this 185 | License permits You to modify this License as applied to the 186 | Original Work or to Derivative Works. However, You may modify 187 | the text of this License and copy, distribute or communicate 188 | your modified version (the "Modified License") and apply it to 189 | other original works of authorship subject to the following 190 | conditions: (i) You may not indicate in any way that your 191 | Modified License is the "Open Software License" or "OSL" and you 192 | may not use those names in the name of your Modified License; 193 | (ii) You must replace the notice specified in the first 194 | paragraph above with the notice "Licensed under " or with a notice of your own that is not 196 | confusingly similar to the notice in this License; and (iii) You 197 | may not claim that your original works are open source software 198 | unless your Modified License has been approved by Open Source 199 | Initiative (OSI) and You comply with its license review and 200 | certification process. 201 | -------------------------------------------------------------------------------- /Makefile-std: -------------------------------------------------------------------------------- 1 | # vim:noexpandtab:autoindent:tabstop=8:shiftwidth=8:filetype=make:nocindent:tw=0: 2 | # This is a template of all of the 'Standard' stuff that we use in all our 3 | # projects. 4 | 5 | CLEANFILES=$(PACKAGE_NAME)-*.tar.gz $(PACKAGE_NAME)-*.tar.bz2 $(PACKAGE_NAME)-*.rpm _buildtemp version 6 | DISTCLEANFILES=*~ 7 | 8 | EXTRA_DIST = 9 | EXTRA_PROGRAMS= 10 | 11 | CLEANFILES += $(EXTRA_PROGRAMS) 12 | CLEANFILES += *.pyc */*.pyc */*/*.pyc */*/*/*.pyc 13 | DISTCLEANFILES += pkg/$(PACKAGE).spec 14 | 15 | clean-local: 16 | -test -z "$(CLEANFILES)" || rm -rf $(CLEANFILES) 17 | 18 | distclean-local: 19 | -test -z "$(DISTCLEANFILES)" || rm -rf $(DISTCLEANFILES) 20 | 21 | .PHONY: git-tag 22 | git-tag: 23 | git tag -u libsmbios -m "tag for official release: $(PACKAGE_STRING)" v$(PACKAGE_VERSION) 24 | 25 | .PHONY: get-version 26 | get-version: 27 | @echo 'PACKAGE_STRING="$(PACKAGE_STRING)"' 28 | @echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' 29 | @echo 'PACKAGE="$(PACKAGE)"' 30 | 31 | ChangeLog: 32 | (GIT_DIR=$(top_srcdir)/.git git log > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2) 33 | 34 | AUTHORS: 35 | (GIT_DIR=$(top_srcdir)/.git git log | grep ^Author | sort |uniq > .authors.tmp && mv .authors.tmp AUTHORS; rm -f .authors.tmp) || (touch AUTHORS; echo 'git directory not found: installing possibly empty AUTHORS.' >&2) 36 | 37 | REPLACE_VARS=GETTEXT_PACKAGE PACKAGE_VERSION PACKAGE localedir libdir libexecdir datadir sysconfdir pythondir pkgpythondir pkgdatadir pkgconfdir pkggladedir pkglibexecdir 38 | 39 | define replace_vars_in_file 40 | $(foreach VAR,$(REPLACE_VARS),perl -p -i -e "s|^$(VAR)\s*=.*|$(VAR)=\"$($(VAR))\"|" $(1);) 41 | endef 42 | 43 | DATA_HOOK_REPLACE= 44 | install-data-hook: 45 | $(foreach FILE,$(DATA_HOOK_REPLACE),$(call replace_vars_in_file,$(addprefix $(DESTDIR)/,$(FILE)))) 46 | 47 | EXEC_HOOK_REPLACE= 48 | install-exec-hook: 49 | $(foreach FILE,$(EXEC_HOOK_REPLACE),$(call replace_vars_in_file,$(addprefix $(DESTDIR)/,$(FILE)))) 50 | 51 | TOPDIR := $(shell cd $(top_builddir);pwd) 52 | BUILDDIR = $(TOPDIR)/_rpmbuild 53 | RPMDIR = $(TOPDIR) 54 | SOURCEDIR = $(TOPDIR) 55 | SPECFILE= $(TOPDIR)/pkg/$(PACKAGE_NAME).spec 56 | SPECDIR = $(TOPDIR)/pkg 57 | SRCRPMDIR = $(TOPDIR) 58 | 59 | AM_RPM_DEFINES = --define "_topdir $(TOPDIR)" \ 60 | --define "_builddir $(BUILDDIR)" \ 61 | --define "_rpmdir $(RPMDIR)" \ 62 | --define "_sourcedir $(SOURCEDIR)" \ 63 | --define "_specdir $(SPECDIR)" \ 64 | --define "_srcrpmdir $(SRCRPMDIR)" \ 65 | $(RPM_DEFINES) 66 | 67 | .PHONY: rpm srpm 68 | rpm: pkg/$(PACKAGE_NAME).spec dist 69 | mkdir -p $(BUILDDIR) 70 | rpmbuild $(AM_RPM_DEFINES) -ba --nodeps $(SPECFILE) 71 | rm -rf $(BUILDDIR) 72 | 73 | srpm: pkg/$(PACKAGE_NAME).spec dist 74 | mkdir -p $(BUILDDIR) 75 | rpmbuild $(AM_RPM_DEFINES) -bs --nodeps $(SPECFILE) 76 | rm -rf $(BUILDDIR) 77 | 78 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # vim:noexpandtab:autoindent:tabstop=8:shiftwidth=8:filetype=make:nocindent:tw=0: 2 | 3 | include Makefile-std 4 | 5 | pkgconfdir = $(sysconfdir)/firmware/ 6 | nodist_pkgconf_DATA = etc/firmware/firmware.conf 7 | 8 | EXTRA_DIST += etc doc glade test yum-plugin COPYING-GPL COPYING-OSL COPYING.LIB 9 | 10 | TESTS = test/testAll.py 11 | nodist_check_SCRIPTS = test/testAll.py 12 | 13 | dist_sbin_SCRIPTS = \ 14 | bin/firmwaretool \ 15 | bin/inventory_firmware_gui 16 | 17 | nodist_pkgdata_DATA = glade/inventory_firmware_gui.glade 18 | 19 | pkgpython_PYTHON = \ 20 | firmwaretools/bootstrap_pci.py \ 21 | firmwaretools/dep_parser.py \ 22 | firmwaretools/errors.py \ 23 | firmwaretools/i18n.py \ 24 | firmwaretools/mockpackage.py \ 25 | firmwaretools/mockrepository.py \ 26 | firmwaretools/package.py \ 27 | firmwaretools/plugins.py \ 28 | firmwaretools/ply_lex.py \ 29 | firmwaretools/ply_yacc.py \ 30 | firmwaretools/pycompat.py \ 31 | firmwaretools/repository.py \ 32 | firmwaretools/trace_decorator.py \ 33 | firmwaretools/peak_util_decorators.py \ 34 | firmwaretools/compat_subprocess.py \ 35 | firmwaretools/generated/__init__.py 36 | 37 | clidir = $(datadir)/$(PACKAGE) 38 | cli_PYTHON = \ 39 | ft-cli/cli.py \ 40 | ft-cli/ftcommands.py \ 41 | ft-cli/ftmain.py \ 42 | ft-cli/guihelpers.py 43 | 44 | plugindir = $(clidir)/plugins 45 | plugin_PYTHON = \ 46 | ft-cli/plugins/bootstrap_cmd.py \ 47 | ft-cli/plugins/inventory_cmd.py \ 48 | ft-cli/plugins/listplugins_cmd.py \ 49 | ft-cli/plugins/update_cmd.py 50 | 51 | __VERSION__=$(VERSION) 52 | PYTHONDIR=$(pythondir) 53 | PKGDATADIR=$(pkgdatadir) 54 | PKGGLADEDIR=$(pkgdatadir) 55 | SYSCONFDIR=$(sysconfdir) 56 | PKGPYTHONDIR=$(pkgpythondir) 57 | DATADIR=$(datadir) 58 | PKGCONFDIR=$(pkgconfdir) 59 | REPLACE_VARS+= __VERSION__ PYTHONDIR PKGDATADIR PKGGLADEDIR SYSCONFDIR PKGPYTHONDIR DATADIR PKGCONFDIR 60 | DATA_HOOK_REPLACE += \ 61 | $(sbindir)/firmwaretool \ 62 | $(sbindir)/inventory_firmware_gui 63 | 64 | EXTRA_DIST += firmwaretools/__init__.py 65 | DISTCLEANFILES += firmwaretools/generated/__init__.py 66 | 67 | REPL_FILE= 68 | firmwaretools/generated/__init__.py: firmwaretools/__init__.py configure Makefile config.status 69 | mkdir -p $$(dirname $@) ||: 70 | cp $< $@ 71 | $(call replace_vars_in_file,$@) 72 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This software is dual-licensed under GPL/OSL. 2 | 3 | * Copyright (C) 2005 Dell Inc. 4 | * by Michael Brown 5 | * Licensed under the Open Software License version 3.0 or later. 6 | * 7 | * Alternatively, you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, 10 | * or (at your option) any later version. 11 | 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | * See the GNU General Public License for more details. 16 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # run this script to create all the autotools fluff. It will also run configure 4 | # unless told not to 5 | 6 | set -e 7 | 8 | CURDIR=$(pwd) 9 | SCRIPT_DIR=$(cd $(dirname $0); pwd) 10 | 11 | cd $SCRIPT_DIR 12 | 13 | autoreconf -i -f -Wno-portability 14 | 15 | run_configure=true 16 | for arg in $*; do 17 | case $arg in 18 | --no-configure) 19 | run_configure=false 20 | ;; 21 | *) 22 | ;; 23 | esac 24 | done 25 | 26 | if test $run_configure = true; then 27 | cd $CURDIR 28 | $SCRIPT_DIR/configure "$@" 29 | fi 30 | 31 | -------------------------------------------------------------------------------- /bin/firmwaretool: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys 3 | import os 4 | 5 | # these are replaced by autotools when installed. 6 | __VERSION__="unreleased_version" 7 | PYTHONDIR=os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),"..") 8 | PKGDATADIR=os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),"..","ft-cli") 9 | # end build system subs 10 | 11 | sys.path.insert(0, PKGDATADIR) 12 | sys.path.insert(0,PYTHONDIR) 13 | 14 | try: 15 | if "inventory_firmware" in sys.argv[0]: 16 | sys.argv.append("--inventory") 17 | if "update_firmware" in sys.argv[0]: 18 | sys.argv.append("--update") 19 | if "bootstrap_firmware" in sys.argv[0]: 20 | sys.argv.append("--bootstrap") 21 | 22 | import ftmain 23 | ftmain.main(sys.argv[1:]) 24 | except KeyboardInterrupt, e: 25 | print >> sys.stderr, "\n\nExiting on user cancel." 26 | sys.exit(1) 27 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # vim:tw=0:et:ts=4:sw=4 3 | # Process this file with autoconf to produce a configure script. 4 | 5 | ############################################################################## 6 | # RELEASE VARIABLES 7 | ############################################################################## 8 | # 9 | # The following variables define the libsmbios release version. 10 | # This is the "marketing" version, or overall version of the project. 11 | # This doesnt have anything in relation to the ABI versions of individual 12 | # libraries, which are defined further below. 13 | # 14 | m4_define([release_major_version], [2]) 15 | m4_define([release_minor_version], [1]) 16 | m4_define([release_micro_version], [15]) 17 | # if you define any "extra" version info, include a leading dot (".") 18 | m4_define([release_extra_version], []) 19 | 20 | AC_INIT([firmware-tools], 21 | [release_major_version().release_minor_version().release_micro_version()release_extra_version()]) 22 | 23 | #################################### 24 | 25 | AC_PREREQ(2.61) 26 | AC_CONFIG_AUX_DIR([pkg]) 27 | AM_INIT_AUTOMAKE([1.10 subdir-objects tar-ustar dist-bzip2 dist-lzma no-define foreign]) 28 | 29 | # Checks for programs. 30 | AC_PROG_INSTALL 31 | 32 | # automake macros 33 | AM_PATH_PYTHON 34 | 35 | # versioning 36 | AC_SUBST([RELEASE_MAJOR], [release_major_version()]) 37 | AC_SUBST([RELEASE_MINOR], [release_minor_version()]) 38 | AC_SUBST([RELEASE_MICRO], [release_micro_version()]) 39 | AC_SUBST([RELEASE_EXTRA], [release_extra_version()]) 40 | AC_SUBST([RELEASE_RPM_EXTRA], [%{nil}]) 41 | if test -n "$RELEASE_EXTRA"; then 42 | RELEASE_RPM_EXTRA=$RELEASE_EXTRA 43 | fi 44 | 45 | # firmware-tools oddity: package name cannot contain '-', so we have to fix it 46 | pkgpythondir=\${pythondir}/firmwaretools 47 | pkgpyexecdir=\${pyexecdir}/firmwaretools 48 | 49 | # generate files and exit 50 | AC_CONFIG_FILES([Makefile]) 51 | AC_CONFIG_FILES([pkg/${PACKAGE_NAME}.spec]) 52 | AC_OUTPUT 53 | 54 | -------------------------------------------------------------------------------- /doc/bootstrap.txt: -------------------------------------------------------------------------------- 1 | 2 | 1) Run dell-repository bootstrap: 3 | # wget -q -O - http://linux.dell.com/yum/software/bootstrap.sh | bash 4 | 5 | 2) Run firmware bootstrap 6 | # wget -q -O - http://linux.dell.com/yum/firmware/bootstrap.sh | bash 7 | 8 | 9 | 10 | 11 | 12 | Firmware bootstrap does the following: 13 | 1) Install firmware-tools (which pulls libsmbios-bin, libsmbios-libs) 14 | 15 | 2) Install firmware-raw-inventory pkgs. These are packages that "provide:" 16 | a virtual package named "firmware_inventory(*capability*)", where 17 | "*capability*" varies. 18 | proposed packages: 19 | - firmware_inventory(bios) *included in firmware-tools* 20 | - firmware_inventory(bmc) *included in firmware-tools* 21 | - firmware_inventory(pci) *included in firmware-tools* 22 | - firmware_inventory(scsi) *optional* 23 | - firmware_inventory(sas) *optional* 24 | - firmware_inventory(rac) *optional* 25 | For optional modules, cmdline option to pull in all unconditionally, 26 | or hints module to pull in based on, eg. sysid. 27 | 28 | 3) run 'inventory-firmware --bootstrap' 29 | output: 30 | system_bios(ven_0x1028_dev_0x0152) 31 | system_firmware(ven_0x1028_dev_0x0152) 32 | pci_firmware(ven_0x8086_dev_0x3580_subven_0x1028_subdev_0x0152) 33 | pci_firmware(ven_0x8086_dev_0x2448) 34 | scsi_enclosure_firmware(ven_0x9999_dev_0x9999) 35 | sas_enclosure_firmware(ven_0x9999_dev_0x9999) 36 | ... etc ... 37 | 38 | 4) Install the RPMs that 'provide' the above raw output. 39 | This pulls in the firmware data RPM, plus any execution/inventory RPMs 40 | that may be necessary. 41 | 42 | 5) run 'apply-updates' 43 | 44 | 45 | firmware-tools RPM has the skeleton for everything: 46 | 1) system-raw-inventory 47 | 2) system-inventory 48 | 2) apply-updates 49 | 50 | 51 | apply-updates 52 | 1) get complete system inventory 53 | 2) get installed firmware update list 54 | 3) calculate list of updates to install 55 | 4) check prereqs for each update 56 | 57 | 58 | prereqs: 59 | Each update is composed of a firmware data file, plus an optional prereq file. Prereqs have the following format: 60 | 61 | src_pkg: REQTYPE pkg [op version] [if Condition] 62 | 63 | REQTYPE: 64 | Requires: 65 | Conflicts: src_pkg cannot be installed if pkg meets op version and 66 | condition 67 | PreRequires: Target pkg must be running required level before src_pkg 68 | can go. Implies reboot if pkg must be updated first and cannot be 69 | updated without reboot (like rbu). 70 | 71 | Condition: 72 | match_sysid SYSID 73 | pci_present PCI_ID 74 | match_pkg PKG_NAME [op version] 75 | 76 | op: 77 | > >= = <= < != <> 78 | 79 | examples: 80 | lsi_fw_upd: Requires backplane 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /doc/bootstrap_firmware.8: -------------------------------------------------------------------------------- 1 | .\" Process this file with 2 | .\" groff -man -Tascii bootstrap_firmware.8 3 | .\" 4 | .TH bootstrap_firmware 8 "DECEMBER 2007" Linux "User Manuals" 5 | .SH NAME 6 | bootstrap_firmware \- detect hardware for use with a package manager 7 | 8 | .SH SYNOPSIS 9 | .B bootstrap_firmware [\-h | \-\-help] [\-c 10 | .I config\-file 11 | .B ] 12 | .B [\-o | \-\-over 13 | .I section,key,value 14 | .B ] 15 | .B [ \-u | \-\-up2date_mode ] 16 | .B [ \-a | \-\-apt_mode ] 17 | .B [ \-v | \-\-verbose ] 18 | .SH DESCRIPTION 19 | .B bootstrap_firmware 20 | scans hardware, and emits tags suitable for use by package managers to 21 | download and install packages providing those tags. This can emit 22 | tags appropriate for YUM (by default), up2date, and aptitude. 23 | .SH OPTIONS 24 | .IP \-h 25 | Print help text 26 | .IP "\-c config\-file" 27 | Use the alternate system wide 28 | .I config\-file 29 | instead of 30 | .IR /etc/firmware/firmware.conf 31 | .IP "\-o | \-\-over section,key,value" 32 | Override values in firmware.conf with new values as section, key, and 33 | value. 34 | .IP "\-u | \-\-up2date_mode" 35 | Generate tags suitable for consumption by Red Hat Network's 36 | .B up2date 37 | program. 38 | .IP "\-a | \-\-apt_mode" 39 | Generate tags suitable for consumption by Debian's 40 | .B aptitude 41 | program. 42 | .IP "\-v | \-\-verbose" 43 | Print additional information. 44 | .SH EXAMPLES 45 | yum install $(bootstrap_firmware) 46 | 47 | up2date \-u \-\-solvedeps=$(bootstrap_firmware \-u) 48 | 49 | aptitude install $(bootstrap_firmware \-a) 50 | 51 | .SH FILES 52 | .I /etc/firmware/firmware.conf 53 | .RS 54 | The system wide configuration file. 55 | .SH AUTHOR 56 | firmware\-tools team 57 | .SH "SEE ALSO" 58 | .BR update_firmware (8) 59 | .BR inventory_firmware (8) 60 | .BR inventory_firmware_gui (8) 61 | -------------------------------------------------------------------------------- /doc/inventory_firmware.8: -------------------------------------------------------------------------------- 1 | .\" Process this file with 2 | .\" groff -man -Tascii inventory_firmware.8 3 | .\" 4 | .TH inventory_firmware 8 "DECEMBER 2007" Linux "User Manuals" 5 | .SH NAME 6 | inventory_firmware \- detect versions of firmware installed in hardware 7 | 8 | .SH SYNOPSIS 9 | .B inventory_firmware [\-h | \-\-help] [\-c 10 | .I config\-file 11 | .B ] 12 | .B [\-o | \-\-over 13 | .I section,key,value 14 | .B ] 15 | .B [ \-u | \-\-up2date_mode ] 16 | .B [ \-a | \-\-apt_mode ] 17 | .B [ \-v | \-\-verbose ] 18 | .SH DESCRIPTION 19 | .B inventory_firmware 20 | scans hardware, and emits human\-readable names for firmwares installed 21 | in that hardware. 22 | .SH OPTIONS 23 | .IP \-h 24 | Print help text 25 | .IP "\-c config\-file" 26 | Use the alternate system wide 27 | .I config\-file 28 | instead of 29 | .IR /etc/firmware/firmware.conf 30 | .IP "\-o | \-\-over section,key,value" 31 | Override values in firmware.conf with new values as section, key, and 32 | value. 33 | .IP "\-b | \-\-bootstrap" 34 | Output results same as 35 | .B bootstrap_firmware\. 36 | All command line options are passed to 37 | .B bootstrap_firmware\. 38 | You should use 39 | .B bootstrap_firmware 40 | directly instead. This option is provided for historical backwards 41 | compatibility only. 42 | .IP "\-u | \-\-up2date_mode" 43 | Generate tags suitable for consumption by Red Hat Network's 44 | .B up2date 45 | program. 46 | .IP "\-a | \-\-apt_mode" 47 | Generate tags suitable for consumption by Debian's 48 | .B aptitude 49 | program. 50 | .IP "\-v | \-\-verbose" 51 | Print additional information. 52 | .SH FILES 53 | .I /etc/firmware/firmware.conf 54 | .RS 55 | The system wide configuration file. 56 | .SH AUTHOR 57 | firmware\-tools team 58 | .SH "SEE ALSO" 59 | .BR update_firmware (8) 60 | .BR bootstrap_firmware (8) 61 | -------------------------------------------------------------------------------- /doc/inventory_firmware_gui.8: -------------------------------------------------------------------------------- 1 | .\" Process this file with 2 | .\" groff -man -Tascii inventory_firmware.8 3 | .\" 4 | .TH inventory_firmware_gui 8 "DECEMBER 2007" Linux "User Manuals" 5 | .SH NAME 6 | inventory_firmware_gui \- graphically inventory and update firmware installed in hardware 7 | 8 | .SH SYNOPSIS 9 | .B inventory_firmware_gui [\-h | \-\-help] [\-c 10 | .I config\-file 11 | .B ] 12 | .B [\-o | \-\-over 13 | .I section,key,value 14 | .B ] 15 | .B [ \-v | \-\-verbose ] 16 | .B [ \-w | \-\-warnings ] 17 | .I directory 18 | .B ] 19 | .SH DESCRIPTION 20 | .B inventory_firmware_gui 21 | scans hardware and directories of available firmware, graphically 22 | shows the inventory, and upgrades the firmwares in that hardware. 23 | .SH OPTIONS 24 | .IP \-h 25 | Print help text 26 | .IP "\-c config\-file" 27 | Use the alternate system wide 28 | .I config\-file 29 | instead of 30 | .IR /etc/firmware/firmware.conf 31 | .IP "\-o | \-\-over section,key,value" 32 | Override values in firmware.conf with new values as section, key, and 33 | value. 34 | .IP "\-v | \-\-verbose" 35 | Print additional information. 36 | .IP "\-w | \-\-warnings" 37 | Print additional warnings. 38 | .SH FILES 39 | .I /etc/firmware/firmware.conf 40 | .RS 41 | The system wide configuration file. 42 | .RE 43 | .I /usr/share/firmware\-tools 44 | .RS 45 | The location of the glade description files. 46 | .SH AUTHOR 47 | firmware\-tools team 48 | .SH "SEE ALSO" 49 | .BR update_firmware (8) 50 | .BR bootstrap_firmware (8) 51 | .BR inventory_firmware (8) 52 | -------------------------------------------------------------------------------- /doc/update_firmware.8: -------------------------------------------------------------------------------- 1 | .\" Process this file with 2 | .\" groff -man -Tascii update_firmware.8 3 | .\" 4 | .TH update_firmware 8 "DECEMBER 2007" Linux "User Manuals" 5 | .SH NAME 6 | update_firmware \- writes firmware into the flash memory of system devices 7 | .SH SYNOPSIS 8 | .B update_firmware [\-h | \-\-help] [\-c 9 | .I config\-file 10 | .B ] 11 | .B [\-o | \-\-over 12 | .I section,key,value 13 | .B ] 14 | .B ... 15 | .SH DESCRIPTION 16 | .B update_firmware 17 | scans /usr/share/firmware/* for firmware images newer than those 18 | present in hardware devices, and writes the newer firmware images into 19 | the devices. 20 | .SH OPTIONS 21 | .IP \-h 22 | Print help text 23 | .IP "\-c config\-file" 24 | Use the alternate system wide 25 | .I config\-file 26 | instead of 27 | .IR /etc/firmware/firmware.conf 28 | .IP "\-o | \-\-over section,key,value" 29 | Override values in firmware.conf with new values as section, key, and value. 30 | .SH FILES 31 | .I /etc/firmware/firmware.conf 32 | .RS 33 | The system wide configuration file. 34 | .SH AUTHOR 35 | firmware\-tools team 36 | .SH "SEE ALSO" 37 | .BR bootstrap_firmware (8) 38 | .BR inventory_firmware (8) 39 | .BR inventory_firmware_gui (8) 40 | -------------------------------------------------------------------------------- /doc/verbosity.txt: -------------------------------------------------------------------------------- 1 | 2 | default 3 | handler def 4 | Logger List level lvl propagate 5 | =================================================== 6 | root NOTSET INFO 1 7 | ft NOTSET INFO 1 8 | ft.verbose NOTSET INFO 0 9 | ft.trace NOTSET INFO 0 10 | 11 | 12 | cmdline: 13 | verbose == 0: ft.propagate=0 14 | verbose >= 1: ft.propagate=1 15 | verbose >= 2: ft.verbose.propagate=1 16 | verbose >= 3: handler lvl == DEBUG for root 17 | tracing == 1: ft.trace.propagate = 1 18 | -------------------------------------------------------------------------------- /etc/firmware/firmware.conf: -------------------------------------------------------------------------------- 1 | # vim:et:ts=4:sw=4:tw=80 2 | # 3 | # INI file. 4 | # This file is read by python ConfigParser module. You can do 5 | # variable interpolation using python-style string interpolation rules. 6 | 7 | [main] 8 | # this section has overarching options that should apply across the board 9 | storage_topdir=%(datadir)s/firmware/ 10 | plugin_config_dir=%(pkgconfdir)s/firmware.d/ 11 | plugin_search_path=%(pkgdatadir)s/plugins 12 | 13 | # Automatically install BIOS updates when an RPM BIOS Update file is installed 14 | # can be overridden in each section (bios, bmc, lsi, etc) 15 | # values: 'auto', 'manual' 16 | # default: 'manual' 17 | rpm_mode=manual 18 | 19 | [plugin:bootstrap_pci] 20 | # This provides the raw lspci inventory that is used to find payloads for pci 21 | # cards. 22 | enabled=1 23 | module=firmwaretools.bootstrap_pci 24 | 25 | [plugin:mock_inventory_bootstrap] 26 | # this module provides fake data for testing purposes. 27 | # only activated when --fake-mode is passed 28 | enabled=1 29 | module=firmwaretools.mockpackage 30 | 31 | [plugin:mock_repository] 32 | # this module provides fake data for testing purposes. 33 | # only activated when --fake-mode is passed 34 | enabled=1 35 | module=firmwaretools.mockrepository 36 | 37 | # command plugins 38 | [plugin:bootstrap_cmd] 39 | enabled=1 40 | module=bootstrap_cmd 41 | 42 | [plugin:inventory_cmd] 43 | enabled=1 44 | module=inventory_cmd 45 | 46 | [plugin:update_cmd] 47 | enabled=1 48 | module=update_cmd 49 | 50 | [plugin:listplugins_cmd] 51 | enabled=1 52 | module=listplugins_cmd 53 | 54 | 55 | # loggers 56 | [logger_root] 57 | level: NOTSET 58 | handlers: unadorned_console 59 | 60 | [logger_ft] 61 | level: NOTSET 62 | handlers: 63 | qualname: firmwaretools 64 | 65 | [logger_verbose] 66 | level: NOTSET 67 | handlers: 68 | qualname: verbose 69 | 70 | [logger_trace] 71 | level: NOTSET 72 | handlers: 73 | qualname: trace 74 | 75 | [logger_updates] 76 | level: NOTSET 77 | handlers: updatelog 78 | qualname: ftupdates 79 | 80 | # logging configuration 81 | [formatters] 82 | keys: detailed,simple,unadorned,time 83 | 84 | [handlers] 85 | keys: unadorned_console,updatelog 86 | 87 | [loggers] 88 | keys: root,ft,verbose,trace,updates 89 | 90 | [formatter_unadorned] 91 | format: %(message)s 92 | 93 | [formatter_simple] 94 | format: %(levelname)s: %(message)s 95 | 96 | [formatter_time] 97 | format: %(asctime)s: %(message)s 98 | 99 | ;useful for debugging: 100 | [formatter_detailed] 101 | format: %(levelname)s %(filename)s, Line: %(lineno)d: %(message)s 102 | 103 | [handler_unadorned_console] 104 | class: StreamHandler 105 | args: [] 106 | formatter: unadorned 107 | level: INFO 108 | 109 | [handler_updatelog] 110 | class: FileHandler 111 | args: ['/var/log/firmware-updates.log','a', None,1] 112 | formatter: time 113 | level: DEBUG 114 | -------------------------------------------------------------------------------- /firmwaretools/__init__.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | 17 | 18 | """ 19 | Firmware-tools: update infrastructure for firmware 20 | """ 21 | 22 | import ConfigParser 23 | import fcntl 24 | import glob 25 | import logging 26 | import logging.config 27 | import os 28 | import sys 29 | 30 | from trace_decorator import decorate, traceLog, getLog 31 | import errors 32 | import repository 33 | 34 | #import config 35 | import plugins 36 | 37 | def mkselfrelpath(*args): 38 | return os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), *args)) 39 | 40 | # these are replaced by autotools when installed. 41 | __VERSION__="unreleased_version" 42 | SYSCONFDIR=mkselfrelpath("..", "etc") 43 | PYTHONDIR=mkselfrelpath("..") 44 | PKGPYTHONDIR=mkselfrelpath("..", "firmwaretools") 45 | PKGDATADIR=mkselfrelpath("..", "ft-cli") 46 | DATADIR=mkselfrelpath("..", "ft-cli") 47 | PKGCONFDIR=os.path.join(SYSCONFDIR,"firmware") 48 | LOCALSTATEDIR=mkselfrelpath("..", "var") 49 | # end build system subs 50 | 51 | PID_FILE = '/var/run/ft.pid' 52 | 53 | class confObj(object): 54 | def __getattribute__(self, name): 55 | return object.__getattribute__(self, name.lower()) 56 | def __setattr__(self, name, value): 57 | object.__setattr__(self, name.lower(), value) 58 | 59 | decorate(traceLog()) 60 | def callCB(cb, *args, **kargs): 61 | if cb is None: return 62 | try: 63 | return cb(*args, **kargs) 64 | except TypeError: 65 | pass 66 | 67 | class Callback(object): 68 | def __init__(self): 69 | pass 70 | 71 | def __call__(self, *args, **kargs): 72 | func = getattr(self, kargs.get("what", "UNKNOWN"), None) 73 | if func is not None: 74 | return func(*args, **kargs) 75 | 76 | class FtBase(object): 77 | """This is a primary structure and base class. It houses the objects and 78 | methods needed to perform most things . It is almost an abstract 79 | class in that you will need to add your own class above it for most 80 | real use.""" 81 | 82 | def __init__(self): 83 | self.logger = getLog() 84 | self.verbose_logger = getLog(prefix="verbose.") 85 | 86 | self.cmdargs = [] 87 | self.cb = None 88 | 89 | self._conf = None 90 | self._repo = None 91 | self._systemInventory = None 92 | self._vendorId = None 93 | self._systemId = None 94 | 95 | self.verbosity = 0 96 | self.trace = 0 97 | self.loggingConfig = os.path.join(PKGCONFDIR, "firmware.conf") 98 | 99 | # Start with plugins disabled 100 | self.disablePlugins() 101 | 102 | def _getConfig(self, cfgFiles=None, pluginTypes=(plugins.TYPE_CORE, plugins.TYPE_INVENTORY,), optparser=None, disabledPlugins=None): 103 | if self._conf is not None: 104 | return self._conf 105 | 106 | if cfgFiles is None: 107 | cfgFiles = [os.path.join(PKGCONFDIR, "firmware.conf"),] 108 | 109 | if disabledPlugins is None: 110 | disabledPlugins = [] 111 | 112 | self.conf = confObj() 113 | 114 | self.setupLogging(self.loggingConfig, self.verbosity, self.trace) 115 | 116 | self.setConfFromIni(cfgFiles) 117 | 118 | self.conf.uid = os.geteuid() 119 | 120 | self.doPluginSetup(optparser, pluginTypes, disabledPlugins) 121 | 122 | return self._conf 123 | 124 | 125 | def setupLogging(self, configFile, verbosity=1, trace=0): 126 | # set up logging 127 | logging.config.fileConfig(configFile) 128 | root_log = logging.getLogger() 129 | ft_log = logging.getLogger("firmwaretools") 130 | ft_verbose_log = logging.getLogger("verbose") 131 | ft_trace_log = logging.getLogger("trace") 132 | 133 | ft_log.propagate = 0 134 | ft_trace_log.propagate = 0 135 | ft_verbose_log.propagate = 0 136 | 137 | if verbosity >= 1: 138 | ft_log.propagate = 1 139 | if verbosity >= 2: 140 | ft_verbose_log.propagate = 1 141 | if verbosity >= 3: 142 | for hdlr in root_log.handlers: 143 | hdlr.setLevel(logging.DEBUG) 144 | if trace: 145 | ft_trace_log.propagate = 1 146 | 147 | decorate(traceLog()) 148 | def setConfFromIni(self, cfgFiles): 149 | defaults = { 150 | "sysconfdir": SYSCONFDIR, 151 | "pythondir": PYTHONDIR, 152 | "datadir": DATADIR, 153 | "pkgpythondir": PKGPYTHONDIR, 154 | "pkgdatadir": PKGDATADIR, 155 | "pkgconfdir": PKGCONFDIR, 156 | "localstatedir": LOCALSTATEDIR, 157 | } 158 | self._ini = ConfigParser.SafeConfigParser(defaults) 159 | for i in cfgFiles: 160 | self._ini.read(i) 161 | 162 | mapping = { 163 | # conf.WHAT : (iniSection, iniOption, default) 164 | "storageTopdir": ('main', 'storage_topdir', "%s/firmware" % DATADIR), 165 | "pluginSearchPath": ('main', 'plugin_search_path', os.path.join(PKGDATADIR, "plugins")), 166 | "pluginConfDir": ('main', 'plugin_config_dir', os.path.join(PKGCONFDIR, "firmware.d")), 167 | "rpmMode": ('main', 'rpm_mode', "manual"), 168 | } 169 | for key, val in mapping.items(): 170 | if self._ini.has_option( val[0], val[1] ): 171 | setattr(self.conf, key, self._ini.get(val[0], val[1])) 172 | else: 173 | setattr(self.conf, key, val[2]) 174 | 175 | # read plugin configs 176 | for i in glob.glob( "%s/*.conf" % self.conf.pluginConfDir ): 177 | self._ini.read(i) 178 | 179 | decorate(traceLog()) 180 | def listPluginsFromIni(self): 181 | return [x[len("plugin:"):] for x in self._ini.sections() if x.startswith("plugin:")] 182 | 183 | decorate(traceLog()) 184 | def getPluginConfFromIni(self, plugin): 185 | section = "plugin:%s" % plugin 186 | conf = confObj() 187 | 188 | conf.module = None 189 | conf.enabled = False 190 | conf.search = None 191 | 192 | for i in self._ini.options(section): 193 | setattr(conf, i, self._ini.get(section, i)) 194 | 195 | #required ("enabled", "module"): 196 | if getattr(conf, "module", None) is None: 197 | conf.enabled = False 198 | 199 | return conf 200 | 201 | # called early so no tracing. 202 | def disablePlugins(self): 203 | '''Disable plugins 204 | ''' 205 | self.plugins = plugins.DummyPlugins() 206 | 207 | decorate(traceLog()) 208 | def doPluginSetup(self, optparser=None, pluginTypes=None, disabledPlugins=None): 209 | if isinstance(self.plugins, plugins.Plugins): 210 | raise RuntimeError("plugins already initialised") 211 | 212 | self.plugins = plugins.Plugins(self, optparser, pluginTypes, disabledPlugins) 213 | 214 | decorate(traceLog()) 215 | def _getRepo(self): 216 | if self._repo is not None: 217 | return self._repo 218 | 219 | self._repo = repository.Repository( self.conf.storageTopdir ) 220 | return self._repo 221 | 222 | decorate(traceLog()) 223 | def _getInventory(self): 224 | if self._systemInventory is not None: 225 | return self._systemInventory 226 | 227 | self._systemInventory = repository.SystemInventory() 228 | self.plugins.run("preinventory", inventory=self._systemInventory) 229 | self.plugins.run("inventory", inventory=self._systemInventory) 230 | self.plugins.run("postinventory", inventory=self._systemInventory) 231 | return self._systemInventory 232 | 233 | decorate(traceLog()) 234 | def calculateUpgradeList(self, cb=None): 235 | saveCb = self.cb 236 | self.cb = cb 237 | try: 238 | for candidate in self.repo.iterPackages(cb=cb): 239 | self.systemInventory.addAvailablePackage(candidate) 240 | 241 | self.systemInventory.calculateUpgradeList(cb) 242 | finally: 243 | self.cb = saveCb 244 | 245 | return self.systemInventory 246 | 247 | # properties so they auto-create themselves with defaults 248 | repo = property(fget=lambda self: self._getRepo(), 249 | fset=lambda self, value: setattr(self, "_repo", value)) 250 | conf = property(fget=lambda self: self._getConfig(), 251 | fset=lambda self, value: setattr(self, "_conf", value), 252 | fdel=lambda self: setattr(self, "_conf", None)) 253 | systemInventory = property( 254 | fget=lambda self: self._getInventory(), 255 | fset=lambda self, value: setattr(self, "_systemInventory", value), 256 | fdel=lambda self: setattr(self, "_systemInventory", None)) 257 | 258 | decorate(traceLog()) 259 | def lock(self): 260 | if self.conf.uid == 0: 261 | self.runLock = open(PID_FILE, "a+") 262 | try: 263 | fcntl.lockf(self.runLock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) 264 | except IOError, e: 265 | raise errors.LockError, "unable to obtain exclusive lock." 266 | 267 | decorate(traceLog()) 268 | def unlock(self): 269 | if self.conf.uid == 0: 270 | fcntl.lockf(self.runLock.fileno(), fcntl.LOCK_UN) 271 | os.unlink(PID_FILE) 272 | 273 | decorate(traceLog()) 274 | def setSystemId(self, vendorId, systemId): 275 | if not (vendorId and systemId): 276 | raise RuntimeError("Need non-null, non-zero, id for vendor and system id.") 277 | self._vendorId = vendorId 278 | self._systemId = systemId 279 | 280 | decorate(traceLog()) 281 | def getSystemId(self): 282 | return (self._vendorId, self._systemId) 283 | 284 | decorate(traceLog()) 285 | def yieldInventory(self, cb=None): 286 | saveCb = self.cb 287 | try: 288 | self.cb = cb 289 | for dev in self.systemInventory.iterDevices(): 290 | yield dev 291 | except: 292 | self.cb = saveCb 293 | raise 294 | 295 | 296 | -------------------------------------------------------------------------------- /firmwaretools/bootstrap_pci.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """module 10 | 11 | some docs here eventually. 12 | """ 13 | 14 | from __future__ import generators 15 | 16 | # import arranged alphabetically 17 | import os 18 | try: 19 | import subprocess 20 | except ImportError: 21 | import compat_subprocess as subprocess 22 | 23 | # my stuff 24 | import firmwaretools.package as package 25 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 26 | import firmwaretools.plugins as plugins 27 | 28 | plugin_type = (plugins.TYPE_INVENTORY,) 29 | requires_api_version = "2.0" 30 | 31 | # ====== 32 | # public API 33 | # ====== 34 | 35 | sysfs_pcidevdir="/sys/bus/pci/devices" 36 | 37 | decorate(traceLog()) 38 | def inventory_hook(conduit, inventory=None, *args, **kargs): 39 | base = conduit.getBase() 40 | cb = base.cb 41 | devdir = sysfs_pcidevdir 42 | 43 | for d in os.listdir(devdir): 44 | d = makePciDevice(os.path.join(devdir, d)) 45 | if inventory.getDevice(d.uniqueInstance) is None: 46 | inventory.addDevice(d) 47 | 48 | decorate(traceLog()) 49 | def getFile(f): 50 | fd = open(f,"r") 51 | ret = fd.read() 52 | fd.close() 53 | if ret[-1:] == '\n': ret = ret[:-1] 54 | return ret 55 | 56 | decorate(traceLog()) 57 | def chomp(s): 58 | if s.endswith("\n"): 59 | return s[:-1] 60 | return s 61 | 62 | LSPCI = None 63 | for i in ("/sbin/lspci", "/usr/bin/lspci"): 64 | if os.path.exists(i): 65 | LSPCI=i 66 | break 67 | 68 | 69 | decorate(traceLog()) 70 | def makePciDevice(devDir): 71 | kargs = {} 72 | kargs["pciVendor"] = int(getFile(os.path.join(devDir, "vendor")),16) 73 | kargs["pciDevice"] = int(getFile(os.path.join(devDir, "device")),16) 74 | kargs["pciSubVendor"] = int(getFile(os.path.join(devDir, "subsystem_vendor")),16) 75 | kargs["pciSubDevice"] = int(getFile(os.path.join(devDir, "subsystem_device")),16) 76 | kargs["pciClass"] = int(getFile(os.path.join(devDir, "class")),16) 77 | 78 | shortname = None 79 | name = "pci_firmware(ven_0x%04x_dev_0x%04x" % (kargs["pciVendor"], kargs["pciDevice"]) 80 | if kargs["pciSubVendor"] and kargs["pciSubDevice"]: 81 | shortname = name + ")" 82 | name = name + "_subven_0x%04x_subdev_0x%04x" % (kargs["pciSubVendor"], kargs["pciSubDevice"]) 83 | name = name + ")" 84 | 85 | dirname = os.path.basename(devDir) 86 | dets = dirname.split(":") 87 | kargs["pciBDF_Domain"] = int(dets[0],16) 88 | kargs["pciBDF_Bus"] = int(dets[1],16) 89 | kargs["pciBDF_Device"] = int(dets[2].split(".")[0],16) 90 | kargs["pciBDF_Function"] = int(dets[2].split(".")[1],16) 91 | 92 | kargs["pciDbdf"] = (kargs["pciBDF_Domain"], kargs["pciBDF_Bus"], kargs["pciBDF_Device"], kargs["pciBDF_Function"]) 93 | 94 | null = open("/dev/null", "w") 95 | p = subprocess.Popen([LSPCI, "-s", "%02x:%02x:%02x.%x" % kargs["pciDbdf"]], stdout=subprocess.PIPE, stderr=null, stdin=null) 96 | lspciname = chomp(p.communicate()[0]) 97 | null.close() 98 | 99 | if lspciname is not None and len(lspciname) > 0: 100 | displayname = lspciname 101 | else: 102 | displayname = "unknown device" 103 | 104 | if shortname is not None: 105 | return package.PciDevice( 106 | name=name, 107 | shortname=shortname, 108 | version='unknown', 109 | displayname=displayname, 110 | lspciname=lspciname, 111 | **kargs 112 | ) 113 | else: 114 | return package.PciDevice( 115 | name=name, 116 | version='unknown', 117 | displayname=displayname, 118 | lspciname=lspciname, 119 | **kargs 120 | ) 121 | 122 | if __name__ == "__main__": 123 | for p in getPciDevs(): 124 | print "%s" % p.name 125 | 126 | -------------------------------------------------------------------------------- /firmwaretools/dep_parser.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """ 10 | repository module 11 | """ 12 | 13 | from __future__ import generators 14 | 15 | import sys 16 | 17 | import package 18 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 19 | 20 | class DepParser(object): 21 | tokens = ( 'ID', 'LT', 'LE', 'EQ', 'GE', 'GT', 'COMMA' ) 22 | t_ID = r'[\w()]+' 23 | t_LT = r'<' 24 | t_LE = r'<=' 25 | t_EQ = r'==' 26 | t_GE = r'>=' 27 | t_GT = r'>' 28 | t_COMMA = r',' 29 | t_ignore = " \t" 30 | 31 | def t_error(self, t): 32 | print "Illegal character '%s'" % t.value[0] 33 | t.skip(1) 34 | 35 | decorate(traceLog()) 36 | def __init__(self, string, inventory, fullInventory, *args, **kargs): 37 | self.inventory = inventory 38 | self.fullInventory = fullInventory 39 | self.depPass = 1 40 | 41 | import ply_lex 42 | lexer = ply_lex.lex( module=self ) 43 | 44 | import ply_yacc 45 | parser = ply_yacc.yacc( module=self, write_tables=0, debug=0 ) 46 | 47 | parser.parse(string, lexer=lexer, debug=0) 48 | 49 | precedence = ( 50 | ('left', 'COMMA'), 51 | ) 52 | 53 | def p_error(self, t): 54 | print "Syntax error at '%s'" % t 55 | 56 | def p_stmt(self, t): 57 | # statement_list can be 1) empty, 2) single statement, or 3) list 58 | """statement_list : 59 | | statement 60 | | statement_list COMMA statement 61 | statement : dep""" 62 | pass 63 | 64 | def p_package_depencency(self, t): 65 | """dep : ID LT ID 66 | | ID LE ID 67 | | ID EQ ID 68 | | ID GE ID 69 | | ID GT ID 70 | """ 71 | op = t[2] 72 | reqPkg = package.Package (name=t[1], version=t[3], displayname="virtual package") 73 | pkg = self.inventory.get(t[1]) 74 | if pkg: 75 | r = pkg.compareVersion(reqPkg) 76 | evalStr = "%s %s 0" % (r, op) 77 | if not eval(evalStr): 78 | self.reason = "Failed for rule: requires %s %s %s" % (t[1], t[2], t[3]) 79 | self.depPass = 0 80 | else: 81 | self.reason = "Repository package doesn't exist in system inventory." 82 | self.depPass = 0 83 | 84 | 85 | def p_package_exists(self, t): 86 | """dep : ID""" 87 | if not self.inventory.get(t[1]): 88 | self.reason = "Failed for rule: requires %s" % t[1] 89 | self.depPass = 0 90 | -------------------------------------------------------------------------------- /firmwaretools/errors.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | import exceptions 4 | 5 | class BaseError(exceptions.Exception): pass 6 | 7 | class ConfigError(BaseError): pass 8 | class LockError(BaseError): pass 9 | -------------------------------------------------------------------------------- /firmwaretools/i18n.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | """i18n abstraction 3 | 4 | License: GPL 5 | Author: Vladimir Bormotov 6 | 7 | $Id$ 8 | """ 9 | # $RCSfile$ 10 | __version__ = "$Revision$"[11:-2] 11 | __date__ = "$Date$"[7:-2] 12 | 13 | try: 14 | import gettext 15 | import sys 16 | if sys.version_info[0] == 2: 17 | t = gettext.translation('firmwaretools') 18 | _ = t.ugettext 19 | else: 20 | gettext.bindtextdomain('firmwaretools', '/usr/share/locale') 21 | gettext.textdomain('firmwaretools') 22 | _ = gettext.gettext 23 | 24 | except: 25 | def _(str): 26 | """pass given string as-is""" 27 | return str 28 | 29 | if __name__ == '__main__': 30 | pass 31 | 32 | # vim: set ts=4 et : 33 | -------------------------------------------------------------------------------- /firmwaretools/mockpackage.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """module 10 | 11 | some docs here eventually. 12 | """ 13 | 14 | from __future__ import generators 15 | 16 | import os 17 | import time 18 | import logging 19 | 20 | # import arranged alphabetically 21 | import package 22 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 23 | import firmwaretools.plugins as plugins 24 | 25 | plugin_type = (plugins.TYPE_MOCK_INVENTORY,) 26 | requires_api_version = "2.0" 27 | 28 | moduleLog = getLog() 29 | moduleVerboseLog = getLog(prefix="verbose.") 30 | 31 | #============================================================== 32 | # mock classes for unit tests 33 | # plus expected data returns 34 | #============================================================== 35 | decorate(traceLog()) 36 | def inventory_hook(conduit, inventory=None, *args, **kargs): 37 | base = conduit.getBase() 38 | cb = base.cb 39 | 40 | import firmwaretools as ft 41 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd") 42 | inventory.addDevice( package.Device( 43 | name = "debug_system_bios", 44 | displayname = "System BIOS for Imaginary Server 1234", 45 | version = "A02")) 46 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd 2") 47 | inventory.addDevice( package.Device( 48 | name = "debug_system_bmc", 49 | displayname = "Baseboard Management Controller for Imaginary Server 1234", 50 | version = "1.0")) 51 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd 3") 52 | inventory.addDevice( package.Device( 53 | name = "debug_pci_firmware_ven_crappy_dev_slow", 54 | displayname = "ReallyFast Network Controller", 55 | version = "1.0")) 56 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd 4") 57 | inventory.addDevice( package.Device( 58 | name = "debug_pci_firmware_ven_0x0c64_dev_0xrocked", 59 | displayname = "Pokey Modem -- Enhanced 1200baud", 60 | version = "2.0")) 61 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd 5") 62 | inventory.addDevice( package.Device( 63 | name = "debug_pci_firmware_ven_corrupt_dev_yourdata", 64 | displayname = "SafeData RAID Controller v2i", 65 | version = "2.0")) 66 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd 6") 67 | inventory.addDevice( package.Device( 68 | name = "debug_pci_firmware_ven_violates_dev_scsistandard", 69 | displayname = "AdapFirm SloTek AHA-1501", 70 | version = "3.0")) 71 | ft.callCB(cb, who="mock_inventory", what="running_inventory", details="fake cmd 7") 72 | inventory.addDevice( package.Device( 73 | name = "debug_pci_firmware_ven_draws_dev_polygons", 74 | displayname = "PixelPusher 2000 Video Adapter", 75 | version = "4.0")) 76 | 77 | 78 | #new style -- used by unit tests. 79 | class MockPackage2(package.RepositoryPackage): 80 | decorate(traceLog()) 81 | def __init__(self, *args, **kargs): 82 | super(MockPackage2, self).__init__(*args, **kargs) 83 | 84 | decorate(traceLog()) 85 | def install(self): 86 | self.status = "in_progress" 87 | self.status = "success" 88 | return "SUCCESS" 89 | 90 | # used when we switch to 'fake' data 91 | class MockRepositoryPackage(package.RepositoryPackage): 92 | decorate(traceLog()) 93 | def __init__(self, *args, **kargs): 94 | super(MockRepositoryPackage, self).__init__(*args, **kargs) 95 | self.capabilities['can_downgrade'] = True 96 | self.capabilities['can_reflash'] = True 97 | self.capabilities['accurate_update_percentage'] = True 98 | self.uniqueInstance = self.name 99 | 100 | decorate(traceLog()) 101 | def install(self): 102 | self.status = "in_progress" 103 | for i in xrange(100): 104 | self.progressPct = i/100.0 105 | time.sleep(0.01) 106 | #print "MockRepositoryPackage -> Install pkg(%s) version(%s)" % (str(self), self.version) 107 | self.progressPct = 1 108 | self.status = "success" 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | #============================================================== 117 | # mock classes for unit tests 118 | # plus expected data returns 119 | #============================================================== 120 | 121 | mockExpectedOutput = """debug_pci_firmware_ven_0x0c64_dev_0xrocked 122 | debug_pci_firmware_ven_crappy_dev_slow 123 | debug_system_bmc 124 | debug_pci_firmware_ven_corrupt_dev_yourdata 125 | debug_system_bios 126 | debug_pci_firmware_ven_draws_dev_polygons 127 | debug_pci_firmware_ven_violates_dev_scsistandard""" 128 | 129 | 130 | # re-use mock data from low-level getSystemId mock function 131 | mockExpectedOutput_inventory = [("mock_package(ven_0x1028_dev_0x1234)", "a05"), ] 132 | 133 | #============================================================== 134 | # mock classes for unit tests 135 | # plus expected data returns 136 | #============================================================== 137 | 138 | # re-use mock data from low-level getSystemId mock function 139 | mockExpectedOutput_bootstrap = """mock_package(ven_0x1028_dev_0x1234)""" 140 | 141 | -------------------------------------------------------------------------------- /firmwaretools/mockrepository.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """ 10 | repository module 11 | """ 12 | 13 | from __future__ import generators 14 | 15 | import os 16 | 17 | import repository 18 | import mockpackage 19 | import sys 20 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 21 | import firmwaretools.plugins as plugins 22 | 23 | plugin_type = (plugins.TYPE_MOCK_INVENTORY, ) 24 | requires_api_version = "2.0" 25 | 26 | moduleLog = getLog() 27 | moduleVerboseLog = getLog(prefix="verbose.") 28 | 29 | # 30 | # DEBUG ONLY 31 | # 32 | 33 | # a null function that just eats args. Default callback 34 | def nullFunc(*args, **kargs): pass 35 | 36 | def config_hook(conduit, *args, **kargs): 37 | repository.Repository.iterPackages = iterPackages_DEBUG 38 | 39 | decorate(traceLog()) 40 | def iterPackages_DEBUG(self, cb=(nullFunc, None)): 41 | # TODO: put this in a separate function 42 | yield mockpackage.MockRepositoryPackage( 43 | displayname="Baseboard Management Controller for Imaginary Server 1234", 44 | name="debug_system_bmc", 45 | version="0.9") 46 | yield mockpackage.MockRepositoryPackage( 47 | displayname="ReallyFast Network Controller", 48 | name="debug_pci_firmware_ven_crappy_dev_slow", 49 | version="1.1") 50 | 51 | # in fake mode, this pkg should never show up. 52 | from ConfigParser import ConfigParser 53 | conf = ConfigParser() 54 | conf.add_section("package") 55 | conf.set("package", "limit_system_support", "nonexistent_system") 56 | yield mockpackage.MockRepositoryPackage( 57 | displayname="ReallyFast Network Controller", 58 | name="debug_pci_firmware_ven_crappy_dev_slow", 59 | version="1.2", 60 | conf = conf) 61 | 62 | yield mockpackage.MockRepositoryPackage( 63 | displayname="Pokey Modem -- Enhanced 1200baud", 64 | name="debug_pci_firmware_ven_0x0c64_dev_0xrocked", 65 | version="1.1") 66 | yield mockpackage.MockRepositoryPackage( 67 | displayname="Pokey Modem -- Enhanced 1200baud", 68 | name="debug_pci_firmware_ven_0x0c64_dev_0xrocked", 69 | version="1.9") 70 | yield mockpackage.MockRepositoryPackage( 71 | displayname="SafeData RAID Controller v2i", 72 | name="debug_pci_firmware_ven_corrupt_dev_yourdata", 73 | version="1.1") 74 | yield mockpackage.MockRepositoryPackage( 75 | displayname="SafeData RAID Controller v2i", 76 | name="debug_pci_firmware_ven_corrupt_dev_yourdata", 77 | version="2.9") 78 | yield mockpackage.MockRepositoryPackage( 79 | displayname="AdapFirm SloTek AHA-1501", 80 | name="debug_pci_firmware_ven_violates_dev_scsistandard", 81 | version="2.1") 82 | yield mockpackage.MockRepositoryPackage( 83 | displayname="AdapFirm SloTek AHA-1501", 84 | name="debug_pci_firmware_ven_violates_dev_scsistandard", 85 | version="2.5") 86 | yield mockpackage.MockRepositoryPackage( 87 | displayname="AdapFirm SloTek AHA-1501", 88 | name="debug_pci_firmware_ven_violates_dev_scsistandard", 89 | version="3.0") 90 | yield mockpackage.MockRepositoryPackage( 91 | displayname="PixelPusher 2000 Video Adapter", 92 | name="debug_pci_firmware_ven_draws_dev_polygons", 93 | version="4.0") 94 | yield mockpackage.MockRepositoryPackage( 95 | displayname="PixelPusher 2000 Video Adapter", 96 | name="debug_pci_firmware_ven_draws_dev_polygons", 97 | version="4.1") 98 | yield mockpackage.MockRepositoryPackage( 99 | displayname="PixelPusher 2000 Video Adapter", 100 | name="debug_pci_firmware_ven_draws_dev_polygons", 101 | version="4.1.1") 102 | yield mockpackage.MockRepositoryPackage( 103 | displayname="PixelPusher 2000 Video Adapter", 104 | name="debug_pci_firmware_ven_draws_dev_polygons", 105 | version="4.1.2") 106 | 107 | -------------------------------------------------------------------------------- /firmwaretools/package.py: -------------------------------------------------------------------------------- 1 | # vim:tw=0:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """ 10 | package module 11 | """ 12 | 13 | import rpm 14 | from gettext import gettext as _ 15 | 16 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 17 | 18 | class InternalError(Exception): pass 19 | class InstallError(Exception): pass 20 | class NoInstaller(Exception): pass 21 | 22 | def defaultCompareStrategy(ver1, ver2): 23 | return rpm.labelCompare( ("0", str(ver1), "0"), ("0", str(ver2), "0")) 24 | 25 | packageStatusEnum = { 26 | "unknown": _("The package status is not known."), 27 | "not_installed": _("The device has not been updated to this version."), 28 | "in_progress": _("The device is being updated now"), 29 | "failed": _("Device update failed."), 30 | "success": _("Device update was successful."), 31 | "disabled": _("Device update is disabled for this device."), 32 | "warm_reboot_needed": _("Update complete. You must perform a warm reboot for the update to take effect."), 33 | } 34 | 35 | # Package public API: 36 | # pkg.name 37 | # pkg.version 38 | # str(pkg) == display name 39 | # pkg.compareVersion(otherPkg) 40 | class Package(object): 41 | def __init__(self, *args, **kargs): 42 | self.name = None 43 | self.version = None 44 | self.compareStrategy = defaultCompareStrategy 45 | for key, value in kargs.items(): 46 | setattr(self, key, value) 47 | 48 | assert(hasattr(self, "name")) 49 | assert(hasattr(self, "version")) 50 | assert(hasattr(self, "displayname")) 51 | assert(len(self.name)) 52 | assert(len(self.version)) 53 | assert(len(self.displayname)) 54 | 55 | status = "unknown" 56 | 57 | def __str__(self): 58 | if hasattr(self, "displayname"): 59 | return self.displayname 60 | return self.name 61 | 62 | def compareVersion(self, otherPackage): 63 | return self.compareStrategy(self.version, otherPackage.version) 64 | 65 | class RepositoryPackage(Package): 66 | mainIni = None 67 | def __init__(self, *args, **kargs): 68 | self.installFunction = None 69 | self.path = None 70 | super(RepositoryPackage, self).__init__(*args, **kargs) 71 | 72 | self.capabilities = { 73 | # if package is capable of downgrading 74 | 'can_downgrade': False, 75 | 76 | # if package is capable of reflashing same version 77 | 'can_reflash': False, 78 | 79 | # if package has/updates .percent_done member var 80 | # GUI can use progress bar if this is set. 81 | # otherwise, GUI should just use a spinner or something 82 | 'accurate_update_percentage': False, 83 | 84 | # if update has .update_status_text member var 85 | # GUI should use for 'view log' function 86 | 'update_log_string': False, 87 | 88 | # if update has .update_status_logfile member var 89 | # GUI should use for 'view log' function 90 | 'update_log_filename': False, 91 | } 92 | 93 | self.progressPct = 0 94 | self.status = "not_installed" 95 | self.deviceList = [] 96 | self.currentInstallDevice = None 97 | 98 | def getProgress(self): 99 | # returns real number between 0-1, or -1 for "not supported" 100 | if self.capabilities['accurate_update_percentage']: 101 | return self.progressPct 102 | else: 103 | return -1 104 | 105 | def install(self): 106 | self.status = "in_progress" 107 | if self.installFunction is not None: 108 | return self.installFunction(self) 109 | 110 | self.status = "failed" 111 | raise NoInstaller(_("Attempt to install a package with no install function. Name: %s, Version: %s") % (self.name, self.version)) 112 | 113 | def getCapability(self, capability): 114 | return self.capabilities.get(capability, None) 115 | 116 | def attachToDevice(self, device): 117 | self.deviceList.append(device) 118 | 119 | def getDeviceList(self): 120 | return self.deviceList 121 | 122 | def setCurrentInstallDevice(self, device): 123 | self.currentInstallDevice = device 124 | 125 | def getCurrentInstallDevice(self): 126 | return self.currentInstallDevice 127 | 128 | def getStatusStr(self): 129 | return packageStatusEnum.get(self.status, _("Programming error: status code not found.")) 130 | 131 | 132 | # Base class for all devices on a system 133 | # required: 134 | # displayname 135 | # name 136 | # version 137 | # optional: 138 | # compareStrategy 139 | class Device(Package): 140 | def __init__(self, *args, **kargs): 141 | self.name = None 142 | self.version = None 143 | self.compareStrategy = defaultCompareStrategy 144 | for key, value in kargs.items(): 145 | setattr(self, key, value) 146 | 147 | if not hasattr(self, "uniqueInstance"): 148 | self.uniqueInstance = self.name 149 | 150 | assert(hasattr(self, "name")) 151 | assert(hasattr(self, "version")) 152 | assert(hasattr(self, "displayname")) 153 | 154 | status = "unknown" 155 | 156 | def __str__(self): 157 | if hasattr(self, "displayname"): 158 | return self.displayname 159 | return self.name 160 | 161 | def compareVersion(self, otherPackage): 162 | return self.compareStrategy(self.version, otherPackage.version) 163 | 164 | 165 | # required: (in addition to base class) 166 | # pciDbdf 167 | class PciDevice(Device): 168 | def __init__(self, *args, **kargs): 169 | super(Device, self).__init__(*args, **kargs) 170 | assert(hasattr(self, "pciDbdf")) 171 | self.uniqueInstance = "pci_dev_at_domain_0x%04x_bus_0x%02x_dev_0x%02x_func_0x%01x" % self.pciDbdf 172 | 173 | 174 | -------------------------------------------------------------------------------- /firmwaretools/plugins.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU General Public License as published by 3 | # the Free Software Foundation; either version 2 of the License, or 4 | # (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU Library General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 14 | # Copyright 2005 Duke University 15 | 16 | import atexit 17 | import gettext 18 | import sys 19 | 20 | from trace_decorator import decorate, traceLog, getLog 21 | import errors 22 | 23 | API_VERSION = '2.0' 24 | 25 | # plugin can raise this to disable plugin during load 26 | class DisablePlugin(ImportError): pass 27 | 28 | NEXT_AVAIL_TYPE_NUM = 0 29 | def registerPluginType(name): 30 | global NEXT_AVAIL_TYPE_NUM 31 | globals()[name] = NEXT_AVAIL_TYPE_NUM 32 | NEXT_AVAIL_TYPE_NUM = NEXT_AVAIL_TYPE_NUM + 1 33 | 34 | # Plugin types 35 | registerPluginType("TYPE_CORE") 36 | registerPluginType("TYPE_INVENTORY") 37 | 38 | registerPluginType("TYPE_CLI") 39 | 40 | # testing types 41 | registerPluginType("TYPE_MOCK_CORE") 42 | registerPluginType("TYPE_MOCK_INVENTORY") 43 | 44 | # all the 'normal' types 45 | ALL_TYPES = (TYPE_CORE, TYPE_INVENTORY) 46 | 47 | SLOT_TO_CONDUIT = {} 48 | def registerSlotToConduit(slot, conduit): 49 | global SLOT_TO_CONDUIT 50 | SLOT_TO_CONDUIT[slot] = conduit 51 | 52 | registerSlotToConduit('config', 'PluginConduit') 53 | registerSlotToConduit('preinventory', 'PluginConduit') 54 | registerSlotToConduit('inventory', 'PluginConduit') 55 | registerSlotToConduit('postinventory', 'PluginConduit') 56 | registerSlotToConduit('close', 'PluginConduit') 57 | 58 | moduleLog = getLog() 59 | moduleLogVerbose = getLog(prefix="verbose.") 60 | 61 | class PluginExit(Exception): 62 | '''Used by plugins to signal to stop 63 | ''' 64 | def __init__(self, value="", translation_domain=""): 65 | self.value = value 66 | self.translation_domain = translation_domain 67 | def __str__(self): 68 | if self.translation_domain: 69 | return gettext.dgettext(self.translation_domain, self.value) 70 | else: 71 | return self.value 72 | 73 | class Plugins: 74 | ''' 75 | Manager class for plugins. 76 | ''' 77 | 78 | def __init__(self, base, optparser=None, types=None, disabled=None): 79 | '''Initialise the instance. 80 | ''' 81 | self.base = base 82 | self.optparser = optparser 83 | self.cmdline = (None, None) 84 | 85 | self.verbose_logger = getLog(prefix="verbose.") 86 | 87 | self.disabledPlugins = disabled 88 | if types is None: 89 | types = ALL_TYPES 90 | if not isinstance(types, (list, tuple)): 91 | types = (types,) 92 | 93 | # TODO: load plugins here 94 | self._plugins = {} 95 | for i in self.base.listPluginsFromIni(): 96 | conf = self.base.getPluginConfFromIni(i) 97 | moduleLogVerbose.info( "Checking Plugin (%s)" % i ) 98 | if conf.enabled: 99 | self._loadModule(i, conf, types) 100 | 101 | # Call close handlers when yum exit's 102 | #atexit.register(self.run, 'close') 103 | 104 | # Let plugins register custom config file options 105 | self.run('config') 106 | 107 | decorate(traceLog()) 108 | def _loadModule(self, pluginName, conf, types): 109 | # load plugin 110 | try: 111 | savePath = sys.path 112 | sys.path.insert(0,self.base.conf.pluginSearchPath) 113 | if conf.search is not None: 114 | sys.path.insert(0, conf.search) 115 | module = __import__(conf.module, globals(), locals(), []) 116 | sys.path = savePath 117 | except DisablePlugin: 118 | moduleLogVerbose.info("\tPlugin raised DisablePlugin exception. skipping.") 119 | return 120 | except ImportError, e: 121 | sys.path = savePath 122 | raise errors.ConfigError( 123 | 'Plugin "%s" cannot be loaded: %s' % (conf.module, e)) 124 | 125 | for i in conf.module.split(".")[1:]: 126 | module = getattr(module, i) 127 | 128 | # Check API version required by the plugin 129 | if not hasattr(module, 'requires_api_version'): 130 | raise errors.ConfigError( 131 | 'Plugin "%s" doesn\'t specify required API version' % conf.module 132 | ) 133 | 134 | if not apiverok(API_VERSION, module.requires_api_version): 135 | raise errors.ConfigError( 136 | 'Plugin "%s" requires API %s. Supported API is %s.' % ( 137 | conf.module, 138 | module.requires_api_version, 139 | API_VERSION, 140 | )) 141 | 142 | # Check plugin type against filter 143 | plugintypes = getattr(module, 'plugin_type', None) 144 | if plugintypes is None: 145 | raise errors.ConfigError( 146 | 'Plugin "%s" doesn\'t specify plugin type' % pluginName 147 | ) 148 | if not isinstance(plugintypes, (list, tuple)): 149 | plugintypes = (plugintypes,) 150 | for plugintype in plugintypes: 151 | if plugintype not in types: 152 | moduleLogVerbose.info("\tPlugin %s not loaded: doesnt match load type (%s)" % (pluginName, plugintypes)) 153 | return 154 | # Check if this plugin has been temporary disabled 155 | if self.disabledPlugins: 156 | if pluginName in self.disabledPlugins: 157 | moduleLogVerbose.info("\tPlugin %s not loaded: disabled" % pluginName) 158 | return 159 | 160 | moduleLogVerbose.info("\tLoaded %s plugin" % pluginName) 161 | self._plugins[pluginName] = {"conf": conf, "module": module} 162 | 163 | decorate(traceLog()) 164 | def listLoaded(self): 165 | return self._plugins.keys() 166 | 167 | decorate(traceLog()) 168 | def run(self, slotname, *args, **kargs): 169 | '''Run all plugin functions for the given slot. 170 | ''' 171 | # Determine handler class to use 172 | conduitcls = SLOT_TO_CONDUIT.get(slotname, None) 173 | if conduitcls is None: 174 | raise ValueError('unknown slot name "%s"' % slotname) 175 | conduitcls = eval(conduitcls) # Convert name to class object 176 | 177 | for pluginName, dets in self._plugins.items(): 178 | module = dets['module'] 179 | conf = dets['conf'] 180 | hook = "%s_hook" % slotname 181 | if hasattr(module, hook): 182 | getattr(module, hook)(conduitcls(self, self.base, conf), *args, **kargs) 183 | 184 | 185 | class DummyPlugins: 186 | ''' 187 | This class provides basic emulation of the YumPlugins class. It exists so 188 | that calls to plugins.run() don't fail if plugins aren't in use. 189 | ''' 190 | decorate(traceLog()) 191 | def run(self, *args, **kwargs): 192 | pass 193 | 194 | decorate(traceLog()) 195 | def setCmdLine(self, *args, **kwargs): 196 | pass 197 | 198 | class PluginConduit(object): 199 | decorate(traceLog()) 200 | def __init__(self, parent, base, conf): 201 | self._parent = parent 202 | self._base = base 203 | self._conf = conf 204 | 205 | self.logger = getLog() 206 | self.verbose_logger = getLog(prefix="verbose.") 207 | 208 | decorate(traceLog()) 209 | def info(self, msg): 210 | self.verbose_logger.info(msg) 211 | 212 | decorate(traceLog()) 213 | def error(self, msg): 214 | self.logger.error(msg) 215 | 216 | decorate(traceLog()) 217 | def getVersion(self): 218 | import firmwaretools 219 | return firmwaretools.__version__ 220 | 221 | decorate(traceLog()) 222 | def getOptParser(self): 223 | '''Return the optparse.OptionParser instance for this execution of Yum 224 | 225 | In the "config" slot a plugin may add extra options to this 226 | instance to extend the command line options that Yum exposes. 227 | 228 | In all other slots a plugin may only read the OptionParser instance. 229 | Any modification of the instance at this point will have no effect. 230 | 231 | @return: the global optparse.OptionParser instance used by Yum. May be 232 | None if an OptionParser isn't in use. 233 | ''' 234 | return self._parent.optparser 235 | 236 | decorate(traceLog()) 237 | def getBase(self): 238 | return self._base 239 | 240 | decorate(traceLog()) 241 | def getConf(self): 242 | return self._conf 243 | 244 | decorate(traceLog()) 245 | def parsever(apiver): 246 | maj, min = apiver.split('.') 247 | return int(maj), int(min) 248 | 249 | decorate(traceLog()) 250 | def apiverok(a, b): 251 | '''Return true if API version "a" supports API version "b" 252 | ''' 253 | a = parsever(a) 254 | b = parsever(b) 255 | 256 | if a[0] != b[0]: 257 | return 0 258 | 259 | if a[1] >= b[1]: 260 | return 1 261 | 262 | return 0 263 | -------------------------------------------------------------------------------- /firmwaretools/pycompat.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """module 10 | 11 | some docs here eventually. 12 | """ 13 | 14 | from __future__ import generators 15 | 16 | # import arranged alphabetically 17 | import commands 18 | import getopt 19 | import glob 20 | import os 21 | import sys 22 | import ConfigParser 23 | import math 24 | import zipfile 25 | import re 26 | import shutil 27 | import signal 28 | import time 29 | import threading 30 | 31 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 32 | 33 | def clearLine(): 34 | return "\033[2K\033[0G" 35 | 36 | def spinner(cycle=['/', '-', '\\', '|']): 37 | step = cycle[0] 38 | del cycle[0] 39 | cycle.append(step) 40 | # ESC codes for clear line and position cursor at horizontal pos 0 41 | return step 42 | 43 | def pad(strn, pad_width=67): 44 | # truncate strn to pad_width so spinPrint does not scroll 45 | if len(strn) > pad_width: 46 | return strn[:pad_width] + ' ...' 47 | else: 48 | return strn 49 | 50 | def spinPrint(strn, outFd=sys.stderr): 51 | outFd.write(clearLine()) 52 | outFd.write("%s\t%s" % (spinner(), pad(strn))) 53 | outFd.flush() 54 | 55 | def timedSpinPrint( strn, start ): 56 | now = time.time() 57 | # ESC codes for position cursor at horizontal pos 65 58 | spinPrint( strn + "\033[65G time: %2.2f" % (now - start) ) 59 | 60 | 61 | # helper class & functions for executeCommand() 62 | # User should handle this if they specify a timeout 63 | class commandTimeoutExpired(Exception): pass 64 | 65 | # the problem with os.system() is that the command that is run gets any 66 | # keyboard input and/or signals. This means that -C interrupts the 67 | # sub-program instead of the python program. This helper function fixes that. 68 | # It also allows us to set up a maximum timeout before all children are killed 69 | decorate(traceLog()) 70 | def executeCommand(cmd, timeout=0): 71 | class alarmExc(Exception): pass 72 | def alarmhandler(signum,stackframe): 73 | raise alarmExc("timeout expired") 74 | 75 | pid = os.fork() 76 | if pid: 77 | #parent 78 | rpid = ret = 0 79 | oldhandler=signal.signal(signal.SIGALRM,alarmhandler) 80 | starttime = time.time() 81 | prevTimeout = signal.alarm(timeout) 82 | try: 83 | (rpid, ret) = os.waitpid(pid, 0) 84 | signal.alarm(0) 85 | signal.signal(signal.SIGALRM,oldhandler) 86 | if prevTimeout: 87 | passed = time.time() - starttime 88 | signal.alarm(int(math.ceil(prevTimeout - passed))) 89 | except alarmExc: 90 | try: 91 | os.kill(-pid, signal.SIGTERM) 92 | time.sleep(1) 93 | os.kill(-pid, signal.SIGKILL) 94 | except OSError: # errno=3 == no such process 95 | pass 96 | (rpid, ret) = os.waitpid(pid, 0) 97 | signal.signal(signal.SIGALRM,oldhandler) 98 | if prevTimeout: 99 | passed = time.time() - starttime 100 | signal.alarm(int(max(math.ceil(prevTimeout - passed), 1))) 101 | raise commandTimeoutExpired( "Specified timeout of %s seconds expired before command finished. Command was: %s" 102 | % (timeout, cmd) 103 | ) 104 | except KeyboardInterrupt: 105 | signal.signal(signal.SIGALRM,oldhandler) 106 | try: 107 | os.kill(-pid, signal.SIGTERM) 108 | time.sleep(1) 109 | os.kill(-pid, signal.SIGKILL) 110 | except OSError: # errno=3 == no such process 111 | pass 112 | (rpid, ret) = os.waitpid(pid, 0) 113 | raise 114 | 115 | # mask and return just return value 116 | return (ret & 0xFF00) >> 8 117 | else: 118 | #child 119 | os.setpgrp() # become process group leader so that we can kill all our children 120 | signal.signal(signal.SIGINT, signal.SIG_IGN) #ignore -C so parent gets it 121 | ret = os.system(cmd) 122 | os._exit( (ret & 0xFF00) >> 8 ) 123 | 124 | decorate(traceLog()) 125 | def copyFile( source, dest, ignoreException=0 ): 126 | try: 127 | shutil.copyfile(source, dest) 128 | except IOError: 129 | if not ignoreException: 130 | raise 131 | 132 | # python 2.3 has a better version, but we have to run on python 2.2. :-( 133 | decorate(traceLog()) 134 | def mktempdir( prefix="/tmp" ): 135 | status, output = commands.getstatusoutput("mktemp -d %s/tempdir-$$-$RANDOM-XXXXXX" % prefix) 136 | if status != 0: 137 | raise Exception("could not create secure temporary directory: %s" % output) 138 | return output 139 | 140 | # generator function -- emulates the os.walk() generator in python 2.3 (mostly) 141 | # ret = (path, dirs, files) foreach dir 142 | decorate(traceLog()) 143 | def walkPath(topdir, direction=0): 144 | rawFiles = os.listdir(topdir) 145 | 146 | files=[f for f in rawFiles if os.path.isfile(os.path.join(topdir,f))] 147 | dirs =[f for f in rawFiles if os.path.isdir (os.path.join(topdir,f))] 148 | 149 | if direction == 0: 150 | yield (topdir, dirs, files) 151 | 152 | for d in dirs: 153 | if not os.path.islink(os.path.join(topdir,d)): 154 | for (newtopdir, newdirs, newfiles) in walkPath(os.path.join(topdir,d)): 155 | yield (newtopdir, newdirs, newfiles) 156 | 157 | if direction == 1: 158 | yield (topdir, dirs, files) 159 | 160 | 161 | decorate(traceLog()) 162 | def runLongProcess(function, args=None, kargs=None, waitLoopFunction=None): 163 | # runs a function in a separate thread. Runs waitLoopFunction() while it 164 | # waits for the function to finish. Good for updating GUI, or other stuff 165 | thread = BackgroundWorker(function, args, kargs) 166 | while thread.running: 167 | if waitLoopFunction is not None: 168 | waitLoopFunction() 169 | 170 | # run waitLoopFunction one last time before exit. 171 | # gives status opportunity to update to 100% 172 | if waitLoopFunction is not None: 173 | waitLoopFunction() 174 | 175 | if thread.exception: 176 | getLog(prefix="verbose.").exception(thread.exception) 177 | raise thread.exception 178 | return thread.returnCode 179 | 180 | class BackgroundWorker(threading.Thread): 181 | def __init__ (self, function, args=None, kargs=None): 182 | threading.Thread.__init__(self) 183 | self.function = function 184 | self.args = args 185 | self.kargs = kargs 186 | 187 | self.exception = None 188 | self.returnCode = None 189 | self.running=1 190 | 191 | if self.args is None: self.args = [] 192 | if self.kargs is None: self.kargs = {} 193 | 194 | self.start() 195 | 196 | decorate(traceLog()) 197 | def run(self): 198 | try: 199 | self.returnCode = self.function(*self.args, **self.kargs) 200 | except (Exception,), e: 201 | self.exception = e 202 | 203 | self.running=0 204 | 205 | -------------------------------------------------------------------------------- /firmwaretools/repository.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | ############################################################################# 4 | # 5 | # Copyright (c) 2005 Dell Computer Corporation 6 | # Dual Licenced under GNU GPL and OSL 7 | # 8 | ############################################################################# 9 | """ 10 | repository module 11 | """ 12 | 13 | from __future__ import generators 14 | 15 | import os 16 | import ConfigParser 17 | 18 | import package 19 | import pycompat 20 | import dep_parser 21 | import sys 22 | import traceback 23 | import firmwaretools as ft 24 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 25 | 26 | import logging 27 | moduleLog = getLog() 28 | moduleVerboseLog = getLog(prefix="verbose.") 29 | 30 | class CircularDependencyError(Exception): pass 31 | 32 | # TODO: 33 | # -- conf item should NEVER be used outside of constructor (makePackage) 34 | 35 | decorate(traceLog()) 36 | def makePackage(configFile): 37 | conf = ConfigParser.ConfigParser() 38 | conf.read(configFile) 39 | 40 | # make a standard package 41 | displayname = "unknown" 42 | if conf.has_option("package", "displayname"): 43 | displayname = conf.get("package", "displayname") 44 | 45 | type = package.RepositoryPackage 46 | 47 | try: 48 | pymod = conf.get("package","module") 49 | moduleLog.debug("pymod: %s" % pymod) 50 | module = __import__(pymod, globals(), locals(), []) 51 | for i in pymod.split(".")[1:]: 52 | module = getattr(module, i) 53 | 54 | packageTypeClass = conf.get("package", "type") 55 | type = getattr(module, packageTypeClass) 56 | moduleLog.debug("direct instantiate") 57 | except (ConfigParser.NoOptionError, ConfigParser.NoSectionError, ImportError, AttributeError): 58 | moduleLog.debug(''.join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))) 59 | pass 60 | 61 | p = type( 62 | displayname=displayname, 63 | name=conf.get("package", "name"), 64 | version=conf.get("package", "version"), 65 | conf=conf, 66 | path=os.path.dirname(configFile), 67 | ) 68 | 69 | return p 70 | 71 | class SystemInventory(object): 72 | decorate(traceLog()) 73 | def __init__(self, *args, **kargs): 74 | self.deviceList = {} 75 | self.allowDowngrade=False 76 | self.allowReflash=False 77 | 78 | decorate(traceLog()) 79 | def addDevice(self, device): 80 | self.deviceList[device.uniqueInstance] = { "device": device, "update": None, "available_updates": []} 81 | 82 | decorate(traceLog()) 83 | def getDevice(self, uniqueInstance, default=None): 84 | return self.deviceList.get(uniqueInstance, default) 85 | 86 | decorate(traceLog()) 87 | def iterDevices(self, name=None): 88 | for device, details in self.deviceList.items(): 89 | if name is None: 90 | yield details["device"] 91 | else: 92 | if details["device"].name == name: 93 | yield details["device"] 94 | else: 95 | try: 96 | if details["device"].shortname == name: 97 | yield details["device"] 98 | except AttributeError: 99 | pass 100 | 101 | decorate(traceLog()) 102 | def addAvailablePackage(self, package): 103 | for myDev in self.iterDevices(name=package.name): 104 | available_updates = self.deviceList[myDev.uniqueInstance]["available_updates"] 105 | available_updates.append(package) 106 | self.deviceList[myDev.uniqueInstance]["available_updates"] = available_updates 107 | package.attachToDevice(myDev) 108 | 109 | decorate(traceLog()) 110 | def iterAvailableUpdates(self, device): 111 | unionInventory = {} 112 | for deviceUniqueInstance, details in self.deviceList.items(): 113 | unionInventory[deviceUniqueInstance] = details["device"] 114 | 115 | for pkg in self.deviceList[device.uniqueInstance]["available_updates"]: 116 | if self.checkRules(device, pkg, unionInventory, runSoftRules=False, cb=None): 117 | yield pkg 118 | 119 | decorate(traceLog()) 120 | def getSuggestedUpdatePackageForDevice(self, device): 121 | ret = None 122 | if self.deviceList.has_key(device.uniqueInstance): 123 | ret = self.deviceList[device.uniqueInstance]["update"] 124 | return ret 125 | 126 | decorate(traceLog()) 127 | def getUpdatePackageForDevice(self, device): 128 | ret = None 129 | if self.deviceList.has_key(device.uniqueInstance): 130 | if self.deviceList[device.uniqueInstance].has_key("pinned_update"): 131 | ret = self.deviceList[device.uniqueInstance]["pinned_update"] 132 | else: 133 | ret = self.deviceList[device.uniqueInstance]["update"] 134 | return ret 135 | 136 | decorate(traceLog()) 137 | def pinUpdatePackage(self, device, pkg): 138 | #TODO: ensure that pkg is in 'available_pkgs' 139 | hasOldPin = False 140 | if self.deviceList[device.uniqueInstance].has_key("pinned_update"): 141 | hasOldPin = True 142 | oldPin = self.deviceList[device.uniqueInstance]["pinned_update"] 143 | 144 | self.deviceList[device.uniqueInstance]["pinned_update"] = pkg 145 | 146 | # just check the rules... not actually installing 147 | try: 148 | for i in self.generateInstallationOrder(): pass 149 | except CircularDependencyError, e: 150 | # roll back 151 | if hasOldPin: 152 | self.deviceList[device.uniqueInstance]["pinned_update"] = oldPin 153 | else: 154 | del(self.deviceList[device.uniqueInstance]["pinned_update"]) 155 | raise 156 | 157 | 158 | decorate(traceLog()) 159 | def unPinDevice(self, device): 160 | if self.deviceList[device.uniqueInstance].has_key("pinned_update"): 161 | del(self.deviceList[device.uniqueInstance]["pinned_update"]) 162 | 163 | decorate(traceLog()) 164 | def reset(self): 165 | for device in self.iterDevices(): 166 | self.unPinDevice(device) 167 | 168 | decorate(traceLog()) 169 | def getMemento(self, deviceHint=None): 170 | memento = {} 171 | memento['savePin'] = {} 172 | for deviceUniqueInstance, details in self.deviceList.items(): 173 | if deviceHint: 174 | if deviceHint.uniqueInstance != deviceUniqueInstance: 175 | continue 176 | if details.has_key("pinned_update"): 177 | memento['savePin'][deviceUniqueInstance] = { 'device': details["device"], 'hasPin': 1, 'oldPin': details["pinned_update"] } 178 | else: 179 | memento['savePin'][deviceUniqueInstance] = { 'device': details["device"], 'hasPin': 0, 'oldPin': None } 180 | 181 | memento["internal.allowReflash"] = self.allowReflash 182 | memento["internal.allowDowngrade"] = self.allowDowngrade 183 | return memento 184 | 185 | decorate(traceLog()) 186 | def setMemento(self, memento): 187 | self.allowReflash = memento["internal.allowReflash"] 188 | self.allowDowngrade = memento["internal.allowDowngrade"] 189 | for deviceUniqueInstance, details in memento['savePin'].items(): 190 | if details['hasPin']: 191 | self.pinUpdatePackage(details["device"], details["oldPin"]) 192 | else: 193 | self.unPinDevice(details["device"]) 194 | 195 | decorate(traceLog()) 196 | def setAllowDowngrade(self, val): 197 | self.allowDowngrade = val 198 | 199 | decorate(traceLog()) 200 | def getAllowDowngrade(self): 201 | return self.allowDowngrade 202 | 203 | decorate(traceLog()) 204 | def setAllowReflash(self, val): 205 | self.allowReflash = val 206 | 207 | decorate(traceLog()) 208 | def getAllowReflash(self): 209 | return self.allowReflash 210 | 211 | decorate(traceLog()) 212 | def checkRules(self, device, candidate, unionInventory, cb=None, runSoftRules=True): 213 | # is candidate newer than what is installed 214 | if runSoftRules and not self.allowDowngrade and device.compareVersion(candidate) > 0: 215 | ft.callCB(cb, who="checkRules", what="package_not_newer", package=candidate, device=device) 216 | return 0 217 | 218 | # is candidate newer than what is installed 219 | if runSoftRules and not self.allowReflash and device.compareVersion(candidate) == 0: 220 | ft.callCB(cb, who="checkRules", what="package_same_version", package=candidate, device=device) 221 | return 0 222 | 223 | #check to see if this package has specific system requirements 224 | # for now, check if we are on a specific system by checking for 225 | # a BIOS package w/ matching id. In future, may have specific 226 | # system package. 227 | if hasattr(candidate,"conf") and candidate.conf.has_option("package", "limit_system_support"): 228 | systemVenDev = candidate.conf.get("package", "limit_system_support") 229 | if not unionInventory.get( "system_bios(%s)" % systemVenDev ): 230 | ft.callCB(cb, who="checkRules", what="fail_limit_system_check", package=candidate) 231 | return 0 232 | 233 | #check generic dependencies 234 | if hasattr(candidate,"conf") and candidate.conf.has_option("package", "requires"): 235 | requires = candidate.conf.get("package", "requires") 236 | if len(requires): 237 | d = dep_parser.DepParser(requires, unionInventory, self.deviceList) 238 | if not d.depPass: 239 | ft.callCB(cb, who="checkRules", what="fail_dependency_check", package=candidate, reason=d.reason) 240 | return 0 241 | return 1 242 | 243 | 244 | decorate(traceLog()) 245 | def calculateUpgradeList(self, cb=None): 246 | unionInventory = {} 247 | for deviceUniqueInstance, details in self.deviceList.items(): 248 | unionInventory[deviceUniqueInstance] = details["device"] 249 | 250 | # for every device, look at the available updates to see if one can be applied. 251 | # if we do any work, start over so that dependencies work themselves out over multiple iterations. 252 | workToDo = 1 253 | while workToDo: 254 | workToDo = 0 255 | for device in self.iterDevices(): 256 | for candidate in self. iterAvailableUpdates(device): 257 | # check if this package is better than the current best 258 | if unionInventory[device.uniqueInstance].compareVersion(candidate) >= 0: 259 | continue 260 | 261 | if self.checkRules(device, candidate, unionInventory, cb=cb): 262 | self.deviceList[device.uniqueInstance]["update"] = candidate 263 | # update union inventory 264 | unionInventory[device.uniqueInstance] = candidate 265 | # need another run-through in case this fixes deps for another package 266 | workToDo = 1 267 | 268 | decorate(traceLog()) 269 | def generateInstallationOrder(self, returnDeviceToo=0, cb=None): 270 | unionInventory = {} 271 | for deviceUniqueInstance, details in self.deviceList.items(): 272 | unionInventory[deviceUniqueInstance] = details["device"] 273 | 274 | # generate initial union inventory 275 | # we will start with no update packages and add them in one at a time 276 | # as we install them 277 | updateDeviceList = [] # [ pkg, pkg, pkg ] 278 | for pkgName, details in self.deviceList.items(): 279 | update = self.getUpdatePackageForDevice(details["device"]) 280 | if update: 281 | updateDeviceList.append( (details["device"], update) ) 282 | 283 | workToDo = 1 284 | while workToDo: 285 | workToDo = 0 286 | for device, candidate in updateDeviceList: 287 | if self.checkRules(device, candidate, unionInventory, cb=cb): 288 | candidate.setCurrentInstallDevice(device) 289 | if returnDeviceToo: 290 | yield (device, candidate) 291 | else: 292 | yield candidate 293 | 294 | # move pkg from to-install list to inventory list 295 | updateDeviceList.remove((device,candidate)) 296 | unionInventory[device.uniqueInstance] = candidate 297 | 298 | # need another run-through in case this fixes deps for another package 299 | workToDo = 1 300 | 301 | if len(updateDeviceList): 302 | raise CircularDependencyError("packages have circular dependency, or are otherwise uninstallable.") 303 | 304 | 305 | 306 | class Repository(object): 307 | decorate(traceLog()) 308 | def __init__(self, *args): 309 | self.dirList = [] 310 | for i in args: 311 | self.dirList.append(i) 312 | 313 | decorate(traceLog()) 314 | def iterPackages(self, cb=None): 315 | for dir in self.dirList: 316 | try: 317 | for (path, dirs, files) in pycompat.walkPath(dir): 318 | if "package.ini" in files: 319 | ft.callCB(cb, who="iterPackages", what="found_package_ini", path=os.path.join(path, "package.ini" )) 320 | try: 321 | p = makePackage( os.path.join(path, "package.ini" )) 322 | ft.callCB(cb, who="iterPackages", what="made_package", package=p) 323 | yield p 324 | except: 325 | moduleLog.debug(''.join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))) 326 | pass 327 | except OSError: # directory doesnt exist, so no repo packages. :-) 328 | pass 329 | 330 | decorate(traceLog()) 331 | def iterLatestPackages(self, cb=None): 332 | latest = {} 333 | for candidate in self.iterPackages(cb=cb): 334 | pkgName = candidate.name 335 | if candidate.conf.has_option("package", "limit_system_support"): 336 | pkgName = pkgName + "_" + candidate.conf.get("package", "limit_system_support") 337 | 338 | p = latest.get(pkgName) 339 | if not p: 340 | latest[pkgName] = candidate 341 | elif p.compareVersion(candidate) < 0: 342 | latest[pkgName] = candidate 343 | 344 | ft.callCB(cb, who="iterLatestPackages", what="done_generating_list") 345 | keys = latest.keys() 346 | keys.sort() 347 | for package in keys: 348 | ft.callCB(cb, who="iterLatestPackages", what="made_package", package=latest[package]) 349 | yield latest[package] 350 | 351 | 352 | -------------------------------------------------------------------------------- /firmwaretools/trace_decorator.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0: 2 | # License: GPL2 or later see COPYING 3 | # Written by Michael Brown 4 | # Copyright (C) 2007 Michael E Brown 5 | 6 | import logging 7 | import os 8 | import sys 9 | import types 10 | 11 | 12 | import warnings 13 | warnings.filterwarnings('ignore', category=FutureWarning) 14 | 15 | # use python-decoratortools if it is installed, otherwise use our own local 16 | # copy. Imported this locally because it doesnt appear to be available on SUSE 17 | # and the fedora RPM doesnt appear to compile cleanly on SUSE 18 | try: 19 | from peak.util.decorators import rewrap, decorate 20 | except ImportError: 21 | from peak_util_decorators import rewrap, decorate 22 | 23 | 24 | class NullHandler(logging.Handler): 25 | def emit(self, record): 26 | pass 27 | 28 | #initialize this late because if it get initialized but unused we throw an exception on exit 29 | null_handler = None 30 | 31 | 32 | # defaults to module log 33 | # does a late binding on log. Forwards all attributes to logger. 34 | # works around problem where reconfiguring the logging module means loggers 35 | # configured before reconfig dont output. 36 | class getLog(object): 37 | def __init__(self, name=None, prefix="", *args, **kargs): 38 | # name the log per the module name if not supplied 39 | if name is None: 40 | frame = sys._getframe(1) 41 | name = frame.f_globals["__name__"] 42 | object.__setattr__(self, "name", prefix + name) 43 | 44 | # forward all attribute access to the logger 45 | def __getattr__(self, name): 46 | # get logger her so it gets instantiated as late as possible 47 | logger = logging.getLogger(self.name) 48 | global null_handler 49 | if null_handler is None: 50 | null_handler = NullHandler() 51 | # add null handlers so we can suppress usless "no handlers could be found for..." messages 52 | if not null_handler in logger.handlers: 53 | logger.addHandler(null_handler) 54 | return getattr( logger, name ) 55 | 56 | # forward all attribute access to the logger 57 | def __setattr__(self, name, value): 58 | # get logger her so it gets instantiated as late as possible 59 | logger = logging.getLogger(self.name) 60 | global null_handler 61 | if null_handler is None: 62 | null_handler = NullHandler() 63 | # add null handlers so we can suppress usless "no handlers could be found for..." messages 64 | if not null_handler in logger.handlers: 65 | logger.addHandler(null_handler) 66 | return setattr( logger, name, value ) 67 | 68 | 69 | # emulates logic in logging module to ensure we only log 70 | # messages that logger is enabled to produce. 71 | def doLog(logger, level, *args, **kargs): 72 | if logger.manager.disable >= level: 73 | return 74 | if logger.isEnabledFor(level): 75 | try: 76 | logger.handle(logger.makeRecord(logger.name, level, *args, **kargs)) 77 | except TypeError: 78 | del(kargs["func"]) 79 | logger.handle(logger.makeRecord(logger.name, level, *args, **kargs)) 80 | 81 | def traceLog(log = None): 82 | def decorator(func): 83 | def trace(*args, **kw): 84 | # default to logger that was passed by module, but 85 | # can override by passing logger=foo as function parameter. 86 | # make sure this doesnt conflict with one of the parameters 87 | # you are expecting 88 | 89 | filename = os.path.normcase(func.func_code.co_filename) 90 | func_name = func.func_code.co_name 91 | lineno = func.func_code.co_firstlineno 92 | 93 | l2 = kw.get('logger', log) 94 | if l2 is None: 95 | l2 = getLog("trace.%s" % func.__module__) 96 | if isinstance(l2, basestring): 97 | l2 = getLog(l2) 98 | 99 | message = "ENTER %s(" % func_name 100 | for arg in args: 101 | message = message + repr(arg) + ", " 102 | for k,v in kw.items(): 103 | message = message + "%s=%s" % (k,repr(v)) 104 | message = message + ")" 105 | 106 | frame = sys._getframe(2) 107 | doLog(l2, logging.INFO, os.path.normcase(frame.f_code.co_filename), frame.f_lineno, message, args=[], exc_info=None, func=frame.f_code.co_name) 108 | try: 109 | result = "Bad exception raised: Exception was not a derived class of 'Exception'" 110 | try: 111 | result = func(*args, **kw) 112 | except (KeyboardInterrupt, Exception), e: 113 | result = "EXCEPTION RAISED" 114 | doLog(l2, logging.INFO, filename, lineno, "EXCEPTION: %s\n" % e, args=[], exc_info=sys.exc_info(), func=func_name) 115 | raise 116 | finally: 117 | doLog(l2, logging.INFO, filename, lineno, "LEAVE %s --> %s\n" % (func_name, repr(result)), args=[], exc_info=None, func=func_name) 118 | 119 | return result 120 | return rewrap(func, trace) 121 | return decorator 122 | 123 | # helper function so we can use back-compat format but not be ugly 124 | def decorateAllFunctions(module, logger=None): 125 | methods = [ method for method in dir(module) 126 | if isinstance(getattr(module, method), types.FunctionType) 127 | ] 128 | for i in methods: 129 | setattr(module, i, traceLog(logger)(getattr(module,i))) 130 | 131 | # unit tests... 132 | if __name__ == "__main__": 133 | logging.basicConfig(level=logging.WARNING, 134 | format='%(name)s %(levelname)s %(filename)s, %(funcName)s, Line: %(lineno)d: %(message)s',) 135 | log = getLog("foobar.bubble") 136 | root = getLog(name="") 137 | log.setLevel(logging.WARNING) 138 | root.setLevel(logging.DEBUG) 139 | 140 | log.debug(" --> debug") 141 | log.error(" --> error") 142 | 143 | decorate(traceLog(log)) 144 | def testFunc(arg1, arg2="default", *args, **kargs): 145 | return 42 146 | 147 | testFunc("hello", "world", logger=root) 148 | testFunc("happy", "joy", name="skippy") 149 | testFunc("hi") 150 | 151 | decorate(traceLog(root)) 152 | def testFunc22(): 153 | return testFunc("archie", "bunker") 154 | 155 | testFunc22() 156 | 157 | decorate(traceLog(root)) 158 | def testGen(): 159 | yield 1 160 | yield 2 161 | 162 | for i in testGen(): 163 | log.debug("got: %s" % i) 164 | 165 | decorate(traceLog()) 166 | def anotherFunc(*args): 167 | return testFunc(*args) 168 | 169 | anotherFunc("pretty") 170 | 171 | getLog() 172 | -------------------------------------------------------------------------------- /ft-cli/cli.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # 17 | # Copyright (C) 2008 Dell Inc. 18 | # by Michael Brown 19 | # 20 | # Based in part on design and code in Yum 3.2: 21 | # Copyright 2006 Duke University 22 | # Written by Seth Vidal 23 | 24 | 25 | """ 26 | Command line interface class and related. 27 | """ 28 | 29 | import os 30 | import re 31 | import sys 32 | import time 33 | import random 34 | import logging 35 | 36 | from optparse import OptionParser 37 | 38 | import firmwaretools 39 | import firmwaretools.plugins as plugins 40 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 41 | 42 | from firmwaretools.i18n import _ 43 | import signal 44 | import ftcommands 45 | from firmwaretools import errors 46 | 47 | __VERSION__=firmwaretools.__VERSION__ 48 | 49 | def sigquit(signum, frame): 50 | """ SIGQUIT handler for the cli. """ 51 | print >> sys.stderr, "Quit signal sent - exiting immediately" 52 | sys.exit(1) 53 | 54 | class CliError(errors.BaseError): pass 55 | 56 | class BaseCli(firmwaretools.FtBase): 57 | """This is the base class for cli. 58 | Inherits from FtBase """ 59 | 60 | def __init__(self): 61 | # handle sigquit early on 62 | signal.signal(signal.SIGQUIT, sigquit) 63 | logging.basicConfig() 64 | logging.raiseExceptions = 0 65 | firmwaretools.FtBase.__init__(self) 66 | 67 | self.logger = getLog() 68 | self.verbose_logger = getLog(prefix="verbose.") 69 | 70 | self.cli_commands = {} 71 | 72 | def registerCommand(self, command): 73 | for name in command.getModes(): 74 | if self.cli_commands.has_key(name): 75 | raise errors.ConfigError('Command "%s" already defined' % name) 76 | self.cli_commands[name] = command 77 | 78 | def getOptionsConfig(self, args): 79 | """parses command line arguments, takes cli args: 80 | sets up self.conf and self.cmds as well as logger objects 81 | in base instance""" 82 | 83 | self.fullCmdLine = args 84 | 85 | self.optparser = FtOptionParser( usage='%prog [options]', version=__VERSION__) 86 | 87 | # Parse only command line options that affect basic yum setup 88 | self.args = [] 89 | self.opts = self.optparser.firstParse(args) 90 | 91 | self.verbosity = self.opts.verbosity 92 | self.trace = self.opts.trace 93 | self.loggingConfig = self.opts.configFiles[0] 94 | 95 | pluginTypes = [plugins.TYPE_CLI, plugins.TYPE_CORE] 96 | if not self.opts.fake_mode: 97 | pluginTypes.extend([plugins.TYPE_INVENTORY,]) 98 | else: 99 | pluginTypes.extend([plugins.TYPE_MOCK_CORE, plugins.TYPE_MOCK_INVENTORY,]) 100 | 101 | # Read up configuration options and initialise plugins 102 | try: 103 | self._getConfig(self.opts.configFiles, 104 | pluginTypes, 105 | optparser=self.optparser, 106 | disabledPlugins=self.opts.disabledPlugins) 107 | 108 | except errors.ConfigError, e: 109 | self.logger.critical(_('Config Error: %s'), e) 110 | sys.exit(1) 111 | except ValueError, e: 112 | self.logger.critical(_('Options Error: %s'), e) 113 | sys.exit(1) 114 | 115 | # redo firstparse in case plugin added a new mode 116 | self.opts = self.optparser.firstParse(args) 117 | 118 | # subcommands can add new optparser stuff in addSubOptions() 119 | self.doCommands("addSubOptions") 120 | 121 | # Now parse the command line for real and 122 | self.opts, self.args = self.optparser.parse_args(args) 123 | 124 | # check fully-processed cmdline options 125 | self.doCommands("doCheck") 126 | 127 | decorate(traceLog()) 128 | def doCommands(self, funcName="doCommand"): 129 | if not self.cli_commands.has_key(self.opts.mode): 130 | self.usage() 131 | raise CliError, "mode not specified." 132 | 133 | return getattr(self.cli_commands[self.opts.mode], funcName)(self, 134 | self.opts.mode, self.fullCmdLine, self.args) 135 | 136 | 137 | decorate(traceLog()) 138 | def usage(self): 139 | ''' Print out command line usage ''' 140 | self.optparser.print_help() 141 | 142 | decorate(traceLog()) 143 | def updateFirmware(self, showUnknown=False): 144 | print 145 | 146 | print "Running system inventory..." 147 | depFailures = {} 148 | updateSet = self.calculateUpgradeList(cb=mycb(depFailures)) 149 | 150 | print "\033[2K\033[0G" # clear line 151 | needUpdate = 0 152 | print "Searching storage directory for available BIOS updates..." 153 | for device in updateSet.iterDevices(): 154 | if device.version == "unknown" and not showUnknown: 155 | continue 156 | 157 | print "Checking %s - %s" % (str(device), device.version) 158 | for availPkg in updateSet.iterAvailableUpdates(device): 159 | print "\tAvailable: %s - %s" % (availPkg.name, availPkg.version) 160 | 161 | pkg = updateSet.getUpdatePackageForDevice(device) 162 | if pkg is None: 163 | print "\tDid not find a newer package to install that meets all installation checks." 164 | else: 165 | print "\tFound Update: %s - %s" % (pkg.name, pkg.version) 166 | needUpdate = 1 167 | 168 | if depFailures: 169 | print 170 | print "Following packages could apply, but have dependency failures:" 171 | 172 | for pkg, reason in depFailures.values(): 173 | print "\t%s - %s" % (pkg.name, pkg.version) 174 | print "\t\t REASON: %s" % reason 175 | 176 | if not needUpdate: 177 | print 178 | print "This system does not appear to have any updates available." 179 | print "No action necessary." 180 | print 181 | return 1 182 | else: 183 | print 184 | print "Found firmware which needs to be updated." 185 | print 186 | 187 | # if we get to this point, that means update is necessary. 188 | # any exit before this point means that there was an error, or no update 189 | # was necessary and should return non-zero 190 | if self.opts.interactive == 2: 191 | print 192 | print "Test mode complete." 193 | print 194 | return 0 195 | 196 | if self.opts.interactive == 1: 197 | print 198 | print "Please run the program with the '--yes' switch to enable BIOS update." 199 | print " UPDATE NOT COMPLETED!" 200 | print 201 | return 0 202 | 203 | print "Running updates..." 204 | for pkg in updateSet.generateInstallationOrder(): 205 | try: 206 | 207 | def statusFunc(): 208 | if pkg.getCapability('accurate_update_percentage'): 209 | firmwaretools.pycompat.spinPrint("%s%% Installing %s - %s" % (pkg.getProgress() * 100, pkg.name, pkg.version)) 210 | else: 211 | firmwaretools.pycompat.spinPrint("Installing %s - %s" % (pkg.name, pkg.version)) 212 | time.sleep(0.2) 213 | 214 | ret = firmwaretools.pycompat.runLongProcess(pkg.install, waitLoopFunction=statusFunc) 215 | print firmwaretools.pycompat.clearLine(), 216 | print "100%% Installing %s - %s" % (pkg.name, pkg.version) 217 | print "Done: %s" % pkg.getStatusStr() 218 | print 219 | 220 | except (firmwaretools.package.NoInstaller,), e: 221 | print "package %s - %s does not have an installer available." % (pkg.name, pkg.version) 222 | print "skipping this package for now." 223 | continue 224 | except (firmwaretools.package.InstallError,), e: 225 | print "Installation failed for package: %s - %s" % (pkg.name, pkg.version) 226 | print "aborting update..." 227 | print 228 | print "The error message from the low-level command was:" 229 | print 230 | print e 231 | break 232 | 233 | 234 | class mycb(firmwaretools.Callback): 235 | def __init__(self, depFailures): 236 | super(mycb, self).__init__() 237 | self.depFailures = depFailures 238 | self.message = "" 239 | 240 | def __call__(self, *args, **kargs): 241 | return super(mycb, self).__call__(*args, **kargs) 242 | 243 | def UNKNOWN(self, *args, **kargs): 244 | firmwaretools.pycompat.spinPrint(self.message) 245 | 246 | def running_inventory(self, who, what, details, *args, **kargs): 247 | self.message = "%s: Running Inventory: %s" % (who, details) 248 | firmwaretools.pycompat.spinPrint("%s: Running Inventory: %s" % (who, details)) 249 | 250 | def found_package_ini(what, path, *args, **kargs): 251 | if len(path) > 50: 252 | path = path[-50:] 253 | self.message = "Checking: %s" % path 254 | firmwaretools.pycompat.spinPrint("Checking: %s" % path) 255 | 256 | def fail_dependency_check(self, what, package, *args, **kargs): 257 | pkgName = "%s-%s" % (package.name, package.version) 258 | if package.conf.has_option("package", "limit_system_support"): 259 | pkgName = pkgName + "-" + package.conf.get("package", "limit_system_support") 260 | self.depFailures[pkgName] = (kargs.get("package"), kargs.get("reason")) 261 | 262 | 263 | class FtOptionParser(OptionParser): 264 | """Unified cmdline option parsing and config file handling.""" 265 | def __init__(self, *args, **kargs): 266 | OptionParser.__init__(self, *args, **kargs) 267 | 268 | self.add_option("-c", "--config", help="Override default config file with user-specified config file.", dest="configFiles", action="append", default=[]) 269 | self.add_option("--extra-plugin-config", help="Add additional plugin config file.", action="append", default=[], dest="extraConfigs") 270 | self.add_option("-v", "--verbose", action="count", dest="verbosity", default=1, help="Display more verbose output.") 271 | self.add_option("-q", "--quiet", action="store_const", const=0, dest="verbosity", help="Minimize program output. Only errors and warnings are displayed.") 272 | self.add_option("--trace", action="store_true", dest="trace", default=False, help="Enable verbose function tracing.") 273 | self.add_option("--fake-mode", action="store_true", dest="fake_mode", default=False, help="Display fake data for unit-testing.") 274 | self.add_option("--disableplugin", action="append", dest="disabledPlugins", default=[], help="Disable single named plugin.") 275 | 276 | # put all 'mode' arguments here so we know early what mode we are in. 277 | self.parseOptionsFirst_novalopts = [ 278 | "--version", "-q", "-v", "--quiet", "--verbose", 279 | "--trace", "--fake-mode", ] 280 | self.parseOptionsFirst_valopts = [ 281 | "-c", "--config", "--disableplugin", "--extra-plugin-config"] 282 | 283 | def addEarlyParse(self, opt, arg=0): 284 | if arg: 285 | self.parseOptionsFirst_valopts.append(opt) 286 | else: 287 | self.parseOptionsFirst_novalopts.append(opt) 288 | 289 | def firstParse(self, args): 290 | args = _filtercmdline( 291 | self.parseOptionsFirst_novalopts, 292 | self.parseOptionsFirst_valopts, 293 | args) 294 | opts, args = self.parse_args(args=args) 295 | 296 | if not opts.configFiles: 297 | opts.configFiles = [os.path.join(firmwaretools.PKGCONFDIR, "firmware.conf"), ] 298 | 299 | opts.configFiles = opts.configFiles + opts.extraConfigs 300 | 301 | return opts 302 | 303 | def _filtercmdline(novalopts, valopts, args): 304 | '''Keep only specific options from the command line argument list 305 | 306 | This function allows us to peek at specific command line options when using 307 | the optparse module. This is useful when some options affect what other 308 | options should be available. 309 | 310 | @param novalopts: A sequence of options to keep that don't take an argument. 311 | @param valopts: A sequence of options to keep that take a single argument. 312 | @param args: The command line arguments to parse (as per sys.argv[:1] 313 | @return: A list of strings containing the filtered version of args. 314 | 315 | Will raise ValueError if there was a problem parsing the command line. 316 | ''' 317 | out = [] 318 | args = list(args) # Make a copy because this func is destructive 319 | 320 | while len(args) > 0: 321 | a = args.pop(0) 322 | if '=' in a: 323 | opt, _ = a.split('=', 1) 324 | if opt in valopts: 325 | out.append(a) 326 | 327 | elif a in novalopts: 328 | out.append(a) 329 | 330 | elif a in valopts: 331 | if len(args) < 1: 332 | raise ValueError 333 | next = args.pop(0) 334 | if next[0] == '-': 335 | raise ValueError 336 | 337 | out.extend([a, next]) 338 | 339 | else: 340 | # Check for single letter options that take a value, where the 341 | # value is right up against the option 342 | for opt in valopts: 343 | if len(opt) == 2 and a.startswith(opt): 344 | out.append(a) 345 | 346 | return out 347 | -------------------------------------------------------------------------------- /ft-cli/ftcommands.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # 17 | # Copyright (C) 2008 Dell Inc. 18 | # by Michael Brown 19 | # 20 | # Based in part on design and code in Yum 3.2: 21 | # Copyright 2006 Duke University 22 | # Written by Seth Vidal 23 | 24 | """ 25 | Classes for subcommands of the yum command line interface. 26 | """ 27 | 28 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 29 | 30 | moduleLog = getLog() 31 | 32 | class YumCommand(object): 33 | 34 | def getModes(self): 35 | return [] 36 | 37 | def doCheck(self, base, mode, cmdline, processedArgs): 38 | pass 39 | 40 | def addSubOptions(self, base, mode, cmdline, processedArgs): 41 | pass 42 | 43 | def doCommand(self, base, mode, cmdline, processedArgs): 44 | """ 45 | @return: (exit_code, [ errors ]) where exit_code is: 46 | 0 = we're done, exit 47 | 1 = we've errored, exit with error string 48 | """ 49 | return 0, ['Nothing to do'] 50 | 51 | 52 | -------------------------------------------------------------------------------- /ft-cli/ftmain.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # Copyright 2005 Duke University 17 | 18 | """ 19 | Entrance point for the command line interface. 20 | """ 21 | 22 | import sys 23 | import locale 24 | import logging 25 | import signal 26 | import time # test purposes only 27 | 28 | # fixup 'no handlers could be found for...' message 29 | logging.raiseExceptions = 0 30 | 31 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 32 | from firmwaretools import errors 33 | from firmwaretools import plugins 34 | import cli 35 | 36 | def main(args): 37 | """This does all the real work""" 38 | def setDebug(): 39 | import pdb 40 | pdb.set_trace() 41 | 42 | signal.signal(signal.SIGUSR1,setDebug) 43 | 44 | def exUserCancel(): 45 | logger.critical('Exiting on user cancel') 46 | sys.exit(1) 47 | 48 | decorate(traceLog()) 49 | def exIOError(e): 50 | if e.errno == 32: 51 | logger.critical('Exiting on Broken Pipe') 52 | else: 53 | logger.critical(str(e)) 54 | sys.exit(1) 55 | 56 | decorate(traceLog()) 57 | def exPluginExit(e): 58 | '''Called when a plugin raises PluginExit. 59 | 60 | Log the plugin's exit message if one was supplied. 61 | ''' 62 | if str(e): 63 | logger.warn('%s' % e) 64 | sys.exit(1) 65 | 66 | decorate(traceLog()) 67 | def exFatal(e): 68 | logger.critical('%s' % e) 69 | sys.exit(1) 70 | 71 | 72 | try: 73 | locale.setlocale(locale.LC_ALL, '') 74 | except locale.Error, e: 75 | # default to C locale if we get a failure. 76 | print >> sys.stderr, 'Failed to set locale, defaulting to C' 77 | locale.setlocale(locale.LC_ALL, 'C') 78 | 79 | # our core object for the cli 80 | base = cli.BaseCli() 81 | 82 | logger = getLog() 83 | verbose_logger = getLog(prefix="verbose.") 84 | 85 | # do our cli parsing and config file setup 86 | # also sanity check the things being passed on the cli 87 | try: 88 | # no logging before this returns. 89 | base.getOptionsConfig(args) 90 | except plugins.PluginExit, e: 91 | exPluginExit(e) 92 | except errors.BaseError, e: 93 | exFatal(e) 94 | 95 | lockerr = "" 96 | while True: 97 | try: 98 | base.lock() 99 | except errors.LockError, e: 100 | if "%s" %(e.msg,) != lockerr: 101 | lockerr = "%s" %(e.msg,) 102 | logger.critical(lockerr) 103 | logger.critical("Another app is currently holding the lock; waiting for it to exit...") 104 | time.sleep(2) 105 | else: 106 | break 107 | 108 | try: 109 | result, resultmsgs = base.doCommands() 110 | except plugins.PluginExit, e: 111 | exPluginExit(e) 112 | except errors.BaseError, e: 113 | result = 1 114 | resultmsgs = [str(e)] 115 | except KeyboardInterrupt: 116 | exUserCancel() 117 | except IOError, e: 118 | exIOError(e) 119 | 120 | verbose_logger.info('Complete!') 121 | base.unlock() 122 | sys.exit(0) 123 | 124 | 125 | if __name__ == "__main__": 126 | try: 127 | main(sys.argv[1:]) 128 | except KeyboardInterrupt, e: 129 | print >> sys.stderr, "\n\nExiting on user cancel." 130 | sys.exit(1) 131 | -------------------------------------------------------------------------------- /ft-cli/guihelpers.py: -------------------------------------------------------------------------------- 1 | # vim:ai:ts=4:sw=4:et:filetype=python: 2 | 3 | #future imports always first 4 | from __future__ import generators 5 | 6 | # std python stuff 7 | import logging 8 | import gtk 9 | 10 | from firmwaretools.pycompat import runLongProcess 11 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 12 | 13 | moduleLog = getLog() 14 | moduleVerboseLog = getLog(prefix="verbose.") 15 | 16 | 17 | decorate(traceLog()) 18 | def getSelectionPaths(treeview): 19 | def func(model, path, iterator, data): 20 | model = None 21 | iterator = None 22 | data.append(path) 23 | 24 | paths = [] 25 | treeselection = treeview.get_selection() 26 | treeselection.selected_foreach(func, paths) 27 | return paths 28 | 29 | # too verbose to trace 30 | #decorate(traceLog()) 31 | def gtkYield(): 32 | # process gui events during long-running loops 33 | # so that we are more responsive 34 | while gtk.events_pending(): 35 | gtk.main_iteration(False) 36 | 37 | 38 | decorate(traceLog()) 39 | def runLongProcessGtk(function, args=None, kargs=None, waitLoopFunction=None): 40 | # too verbose to trace 41 | #decorate(traceLog()) 42 | def myFunc(): 43 | # can access outer function variables 44 | if waitLoopFunction is not None: 45 | waitLoopFunction() 46 | gtkYield() # make sure current GUI is fully displayed 47 | 48 | return runLongProcess(function, args, kargs, waitLoopFunction=myFunc) 49 | -------------------------------------------------------------------------------- /ft-cli/plugins/bootstrap_cmd.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # 17 | # Copyright (C) 2008 Dell Inc. 18 | # by Michael Brown 19 | 20 | """ 21 | Classes for subcommands of the yum command line interface. 22 | """ 23 | 24 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 25 | import firmwaretools.plugins as plugins 26 | 27 | import ftcommands 28 | 29 | plugin_type = (plugins.TYPE_CLI,) 30 | requires_api_version = "2.0" 31 | 32 | moduleLog = getLog() 33 | 34 | def config_hook(conduit, *args, **kargs): 35 | conduit.getOptParser().addEarlyParse("--bootstrap") 36 | conduit.getOptParser().add_option( 37 | "-b", "--bootstrap", help="List the bootstrap inventory", 38 | action="store_const", const="bootstrap", dest="mode", default=None) 39 | conduit.getBase().registerCommand(BootstrapCommand()) 40 | 41 | class BootstrapCommand(ftcommands.YumCommand): 42 | decorate(traceLog()) 43 | def getModes(self): 44 | return ['bootstrap'] 45 | 46 | decorate(traceLog()) 47 | def addSubOptions(self, base, mode, cmdline, processedArgs): 48 | # need to add bootstrap-specific options to optparser 49 | base.optparser.add_option("-u", "--up2date_mode", action="store_true", dest="comma_separated", default=False, help="Comma-separate values for use with up2date.") 50 | base.optparser.add_option("-a", "--apt_mode", action="store_true", dest="apt_mode", default=False, help="fixup names so that they are compatible with apt") 51 | 52 | decorate(traceLog()) 53 | def doCommand(self, base, mode, cmdline, processedArgs): 54 | parse=str 55 | if base.opts.apt_mode: 56 | parse = debianCleanName 57 | 58 | venId, sysId = base.getSystemId() 59 | 60 | out = "" 61 | for pkg in base.yieldInventory(): 62 | if base.opts.comma_separated: 63 | if venId and sysId: 64 | out = out + ",%s" % parse(pkg.name + "/system(ven_0x%04x_dev_0x%04x)" % (venId, sysId)) 65 | out = out + ",%s" % parse(pkg.name) 66 | try: 67 | if venId and sysId: 68 | out = out + ",%s" % parse(pkg.shortname + "/system(ven_0x%04x_dev_0x%04x)" % (venId, sysId)) 69 | out = out + ",%s" % parse(pkg.shortname) 70 | except AttributeError: 71 | pass 72 | else: 73 | if venId and sysId: 74 | print("%s/system(ven_0x%04x_dev_0x%04x)" % (parse(pkg.name), venId, sysId)) 75 | print("%s" % parse(pkg.name)) 76 | try: 77 | if venId and sysId: 78 | print("%s/system(ven_0x%04x_dev_0x%04x)" % (parse(pkg.shortname), venId, sysId)) 79 | print("%s" % parse(pkg.shortname)) 80 | except AttributeError: 81 | pass 82 | 83 | 84 | # strip leading comma: 85 | out = out[1:] 86 | if out: 87 | print(out) 88 | 89 | return [0, "Done"] 90 | 91 | 92 | # used by bootstrap 93 | decorate(traceLog()) 94 | def debianCleanName(s): 95 | s = s.replace('_', '-') 96 | s = s.replace('(', '-') 97 | s = s.replace(')', '') 98 | s = s.lower() 99 | return s 100 | 101 | -------------------------------------------------------------------------------- /ft-cli/plugins/inventory_cmd.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # 17 | # Copyright (C) 2008 Dell Inc. 18 | # by Michael Brown 19 | 20 | """ 21 | Classes for subcommands of the yum command line interface. 22 | """ 23 | 24 | import sys 25 | 26 | import firmwaretools.pycompat 27 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 28 | import firmwaretools.plugins as plugins 29 | 30 | import ftcommands 31 | import cli 32 | 33 | plugin_type = (plugins.TYPE_CLI,) 34 | requires_api_version = "2.0" 35 | 36 | moduleLog = getLog() 37 | 38 | def config_hook(conduit, *args, **kargs): 39 | conduit.getOptParser().addEarlyParse("--inventory") 40 | conduit.getOptParser().add_option( 41 | "--inventory", help="List system inventory", 42 | action="store_const", const="inventory", 43 | dest="mode", default=None) 44 | conduit.getBase().registerCommand(InventoryCommand()) 45 | 46 | class InventoryCommand(ftcommands.YumCommand): 47 | decorate(traceLog()) 48 | def getModes(self): 49 | return ['inventory'] 50 | 51 | decorate(traceLog()) 52 | def addSubOptions(self, base, mode, cmdline, processedArgs): 53 | base.optparser.add_option( 54 | "--show-unknown", help="Show unknown devices.", 55 | action="store_true", dest="show_unknown", default=False) 56 | 57 | decorate(traceLog()) 58 | def doCommand(self, base, mode, cmdline, processedArgs): 59 | sys.stderr.write("Wait while we inventory system:\n") 60 | 61 | headerWasPrinted=False 62 | for pkg in base.yieldInventory(cb=cli.mycb({})): 63 | if not headerWasPrinted: 64 | sys.stderr.write(firmwaretools.pycompat.clearLine()) 65 | sys.stderr.write("System inventory:\n") 66 | sys.stderr.flush() 67 | headerWasPrinted = True 68 | 69 | if pkg.version == "unknown" and not base.opts.show_unknown : 70 | continue 71 | 72 | print("\t%s = %s" % (str(pkg), pkg.version)) 73 | 74 | return [0, "Done"] 75 | 76 | -------------------------------------------------------------------------------- /ft-cli/plugins/listplugins_cmd.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # 17 | # Copyright (C) 2008 Dell Inc. 18 | # by Michael Brown 19 | 20 | """ 21 | Classes for subcommands of the yum command line interface. 22 | """ 23 | 24 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 25 | import firmwaretools.plugins as plugins 26 | 27 | import ftcommands 28 | 29 | plugin_type = (plugins.TYPE_CLI,) 30 | requires_api_version = "2.0" 31 | 32 | moduleLog = getLog() 33 | 34 | def config_hook(conduit, *args, **kargs): 35 | conduit.getOptParser().addEarlyParse("--listplugins") 36 | conduit.getOptParser().add_option( 37 | "--listplugins", action="store_const", const="listplugins", 38 | dest="mode", help="list available plugins.") 39 | conduit.getBase().registerCommand(ListPluginsCommand()) 40 | 41 | class ListPluginsCommand(ftcommands.YumCommand): 42 | decorate(traceLog()) 43 | def getModes(self): 44 | return ['listplugins'] 45 | 46 | decorate(traceLog()) 47 | def doCommand(self, base, mode, cmdline, processedArgs): 48 | print("Available Plugins:") 49 | for p in base.listPluginsFromIni(): 50 | print("\t%s" % p) 51 | 52 | print("Loaded Plugins:") 53 | for p in base.plugins.listLoaded(): 54 | print("\t%s" % p) 55 | 56 | return [0, "Done"] 57 | 58 | 59 | -------------------------------------------------------------------------------- /ft-cli/plugins/update_cmd.py: -------------------------------------------------------------------------------- 1 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 2 | 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Library General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | # 17 | # Copyright (C) 2008 Dell Inc. 18 | # by Michael Brown 19 | 20 | """ 21 | Classes for subcommands of the yum command line interface. 22 | """ 23 | 24 | from firmwaretools.trace_decorator import decorate, traceLog, getLog 25 | import firmwaretools.plugins as plugins 26 | 27 | import ftcommands 28 | 29 | plugin_type = (plugins.TYPE_CLI,) 30 | requires_api_version = "2.0" 31 | 32 | moduleLog = getLog() 33 | moduleVerboseLog = getLog(prefix="verbose.") 34 | 35 | def config_hook(conduit, *args, **kargs): 36 | conduit.getOptParser().addEarlyParse("--update") 37 | conduit.getOptParser().add_option( 38 | "--update", help="Update the system's firmware.", 39 | action="store_const", const="update", dest="mode") 40 | conduit.getBase().registerCommand(UpdateCommand()) 41 | 42 | class UpdateCommand(ftcommands.YumCommand): 43 | decorate(traceLog()) 44 | def getModes(self): 45 | return ['update'] 46 | 47 | decorate(traceLog()) 48 | def addSubOptions(self, base, mode, cmdline, processedArgs): 49 | base.optparser.add_option("--rpm", action="store_true", dest="rpmMode", default=False, help="Used when running as part of an rpm \%post script.") 50 | base.optparser.add_option("--yes", "-y", action="store_const", const=0, dest="interactive", default=1, help="Default all answers to 'yes'.") 51 | base.optparser.add_option("--test", "-t", action="store_const", const=2, dest="interactive", help="Perform test but do not actually update.") 52 | base.optparser.add_option( "--show-unknown", help="Show unknown devices.", action="store_true", dest="show_unknown", default=False) 53 | base.optparser.add_option( "--storage-topdir", help="Override configured storage topdir.", action="store", dest="storage_topdir", default=None) 54 | 55 | decorate(traceLog()) 56 | def doCheck(self, base, mode, cmdline, processedArgs): 57 | if base.opts.storage_topdir is not None: 58 | moduleLog.info("overriding storage topdir. Original: %s New: %s" % (base.conf.storageTopdir, base.opts.storage_topdir)) 59 | base.conf.storageTopdir = base.opts.storage_topdir 60 | 61 | decorate(traceLog()) 62 | def doCommand(self, base, mode, cmdline, processedArgs): 63 | if base.opts.rpmMode: 64 | if base.conf.rpmMode != 'auto': 65 | print "Config does not specify automatic install during package install." 66 | print "Please run update_firmware manually to install updates." 67 | return [0, "Done"] 68 | 69 | base.updateFirmware(base.opts.show_unknown) 70 | return [0, "Done"] 71 | 72 | -------------------------------------------------------------------------------- /glade/inventory_firmware_gui.gladep: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Inventory_firmware_gui 6 | Inventory_firmware_gui 7 | FALSE 8 | FALSE 9 | FALSE 10 | FALSE 11 | strings.txt 12 | 13 | -------------------------------------------------------------------------------- /pkg/debian/changelog.in: -------------------------------------------------------------------------------- 1 | firmware-tools (1.6.0-0ubuntu1#DISTTAG#) #DIST#; urgency=low 2 | 3 | * update to new 1.6.0 upstream, which now uses autotools 4 | 5 | -- Matt Domsch Sun, 16 Dec 2007 21:06:38 -0600 6 | 7 | firmware-tools (1.5.10-0ubuntu5#DISTTAG#) #DIST#; urgency=low 8 | 9 | * add linda.overrides for yum-plugins warning 10 | * use debian/docs instead of DEB_INSTALL_DOCS_ALL 11 | * add pointer to LGPL in debian/copyright 12 | * update Standards-Version to 3.7.3 13 | * add debian/watch 14 | * add manpages for usr/bin/* 15 | * forcably install debian/triggers because <= Gutsy debhelper doesn't. 16 | * drop unneeded dpkg versioned dependency 17 | * Initial release. (LP: #163120) 18 | 19 | -- Matt Domsch Sun, 09 Dec 2007 17:45:06 -0600 20 | -------------------------------------------------------------------------------- /pkg/debian/compat: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /pkg/debian/control: -------------------------------------------------------------------------------- 1 | Source: firmware-tools 2 | Section: admin 3 | Priority: optional 4 | Maintainer: Ubuntu MOTU Developers 5 | XSBC-Original-Maintainer: Michael Brown 6 | Build-Depends: debhelper (>= 5), cdbs (>= 0.4.49) 7 | Build-Depends-Indep: python-support (>= 0.5.3) 8 | Standards-Version: 3.7.3 9 | Homepage: http://linux.dell.com 10 | 11 | Package: firmware-tools 12 | Architecture: all 13 | # Depends: python-rpm provides a useful version comparison function 14 | Depends: ${python:Depends}, python-glade2, python-rpm 15 | Python-Depends: python-decoratortools 16 | Provides: ${python:Provides} 17 | Description: Scripts and tools to manage firmware and BIOS updates 18 | The firmware-tools project provides tools to inventory hardware and a plugin 19 | architecture so that different OEM vendors can provide different inventory 20 | components. It is intended to tie to the package system to enable seamless 21 | installation of updated firmware via your package manager, as well as provide 22 | a framework for BIOS and firmware updates. 23 | 24 | -------------------------------------------------------------------------------- /pkg/debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by the firmware-tools team 2 | on Mon, 9 Apr 2007 19:15:12 3 | +0530. 4 | 5 | It was downloaded from: 6 | http://linux.dell.com/libsmbios/download/firmware-tools/ 7 | 8 | Upstream Author: Michael_E_Brown 9 | 10 | The Debian packaging is Copyright 2007 Dell, Inc. 11 | and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. 12 | 13 | The upstream sources are licensed thusly: 14 | 15 | * Copyright (C) 2001-2005, David M. Beazley (LGPL 2.1+) 16 | * Copyright (C) 2003-2007 Dell Inc. 17 | * by Michael Brown 18 | * Licensed under the Open Software License version 3.0 or later. 19 | * 20 | * Alternatively, you can redistribute it and/or modify 21 | * it under the terms of the GNU General Public License as published 22 | * by the Free Software Foundation; either version 2 of the License, 23 | * or (at your option) any later version. 24 | 25 | * This program is distributed in the hope that it will be useful, but 26 | * WITHOUT ANY WARRANTY; without even the implied warranty of 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 28 | * See the GNU General Public License for more details. 29 | 30 | 31 | You should have received a copy of the GNU General Public License 32 | along with this program; if not, write to the Free Software 33 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 34 | USA 35 | 36 | On Debian systems, the complete text of the GNU General Public License 37 | can be found in `/usr/share/common-licenses/GPL-2'. 38 | 39 | ply_lex.py and ply_yacc.py Copyright (C) 2001-2005, David M. Beazley, 40 | licensed GNU Lesser General Public License 2.1+. 41 | 42 | On Debian systems, the complete text of the GNU Lesser General Public License 43 | can be found in `/usr/share/common-licenses/LGPL-2.1'. 44 | 45 | 46 | ------------------------------------------------------------------------------- 47 | Open Software License ("OSL") v. 3.0 48 | 49 | This Open Software License (the "License") applies to any original 50 | work of authorship (the "Original Work") whose owner (the "Licensor") 51 | has placed the following licensing notice adjacent to the copyright 52 | notice for the Original Work: 53 | 54 | Licensed under the Open Software License version 3.0 55 | 56 | 1. Grant of Copyright License. Licensor grants You a worldwide, 57 | royalty-free, non-exclusive, sublicensable license, for the 58 | duration of the copyright, to do the following: 59 | 60 | 1. to reproduce the Original Work in copies, either alone or 61 | as part of a collective work; 62 | 63 | 2. to translate, adapt, alter, transform, modify, or arrange 64 | the Original Work, thereby creating derivative works 65 | ("Derivative Works") based upon the Original Work; 66 | 67 | 3. to distribute or communicate copies of the Original Work 68 | and Derivative Works to the public, with the proviso that 69 | copies of Original Work or Derivative Works that You 70 | distribute or communicate shall be licensed under this 71 | Open Software License; 72 | 73 | 4. to perform the Original Work publicly; and 74 | 75 | 5. to display the Original Work publicly. 76 | 77 | 2. Grant of Patent License. Licensor grants You a worldwide, 78 | royalty-free, non-exclusive, sublicensable license, under patent 79 | claims owned or controlled by the Licensor that are embodied in 80 | the Original Work as furnished by the Licensor, for the duration 81 | of the patents, to make, use, sell, offer for sale, have made, 82 | and import the Original Work and Derivative Works. 83 | 84 | 3. Grant of Source Code License. The term "Source Code" means the 85 | preferred form of the Original Work for making modifications to 86 | it and all available documentation describing how to modify the 87 | Original Work. Licensor agrees to provide a machine-readable 88 | copy of the Source Code of the Original Work along with each 89 | copy of the Original Work that Licensor distributes. Licensor 90 | reserves the right to satisfy this obligation by placing a 91 | machine-readable copy of the Source Code in an information 92 | repository reasonably calculated to permit inexpensive and 93 | convenient access by You for as long as Licensor continues to 94 | distribute the Original Work. 95 | 96 | 4. Exclusions From License Grant. Neither the names of Licensor, 97 | nor the names of any contributors to the Original Work, nor any 98 | of their trademarks or service marks, may be used to endorse or 99 | promote products derived from this Original Work without express 100 | prior permission of the Licensor. Except as expressly stated 101 | herein, nothing in this License grants any license to Licensor's 102 | trademarks, copyrights, patents, trade secrets or any other 103 | intellectual property. No patent license is granted to make, 104 | use, sell, offer for sale, have made, or import embodiments of 105 | any patent claims other than the licensed claims defined in 106 | Section 2. No license is granted to the trademarks of Licensor 107 | even if such marks are included in the Original Work. Nothing in 108 | this License shall be interpreted to prohibit Licensor from 109 | licensing under terms different from this License any Original 110 | Work that Licensor otherwise would have a right to license. 111 | 112 | 5. External Deployment. The term "External Deployment" means the 113 | use, distribution, or communication of the Original Work or 114 | Derivative Works in any way such that the Original Work or 115 | Derivative Works may be used by anyone other than You, whether 116 | those works are distributed or communicated to those persons or 117 | made available as an application intended for use over a 118 | network. As an express condition for the grants of license 119 | hereunder, You must treat any External Deployment by You of the 120 | Original Work or a Derivative Work as a distribution under 121 | section 1(c). 122 | 123 | 6. Attribution Rights. You must retain, in the Source Code of any 124 | Derivative Works that You create, all copyright, patent, or 125 | trademark notices from the Source Code of the Original Work, as 126 | well as any notices of licensing and any descriptive text 127 | identified therein as an "Attribution Notice." You must cause 128 | the Source Code for any Derivative Works that You create to 129 | carry a prominent Attribution Notice reasonably calculated to 130 | inform recipients that You have modified the Original Work. 131 | 132 | 7. Warranty of Provenance and Disclaimer of Warranty. Licensor 133 | warrants that the copyright in and to the Original Work and the 134 | patent rights granted herein by Licensor are owned by the 135 | Licensor or are sublicensed to You under the terms of this 136 | License with the permission of the contributor(s) of those 137 | copyrights and patent rights. Except as expressly stated in the 138 | immediately preceding sentence, the Original Work is provided 139 | under this License on an "AS IS" BASIS and WITHOUT WARRANTY, 140 | either express or implied, including, without limitation, the 141 | warranties of non-infringement, merchantability or fitness for a 142 | particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE 143 | ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY 144 | constitutes an essential part of this License. No license to the 145 | Original Work is granted by this License except under this 146 | disclaimer. 147 | 148 | 8. Limitation of Liability. Under no circumstances and under no 149 | legal theory, whether in tort (including negligence), contract, 150 | or otherwise, shall the Licensor be liable to anyone for any 151 | indirect, special, incidental, or consequential damages of any 152 | character arising as a result of this License or the use of the 153 | Original Work including, without limitation, damages for loss of 154 | goodwill, work stoppage, computer failure or malfunction, or any 155 | and all other commercial damages or losses. This limitation of 156 | liability shall not apply to the extent applicable law prohibits 157 | such limitation. 158 | 159 | 9. Acceptance and Termination. If, at any time, You expressly 160 | assented to this License, that assent indicates your clear and 161 | irrevocable acceptance of this License and all of its terms and 162 | conditions. If You distribute or communicate copies of the 163 | Original Work or a Derivative Work, You must make a reasonable 164 | effort under the circumstances to obtain the express assent of 165 | recipients to the terms of this License. This License conditions 166 | your rights to undertake the activities listed in Section 1, 167 | including your right to create Derivative Works based upon the 168 | Original Work, and doing so without honoring these terms and 169 | conditions is prohibited by copyright law and international 170 | treaty. Nothing in this License is intended to affect copyright 171 | exceptions and limitations (including 'fair use' or 'fair 172 | dealing'). This License shall terminate immediately and You may 173 | no longer exercise any of the rights granted to You by this 174 | License upon your failure to honor the conditions in Section 175 | 1(c). 176 | 177 | 10. Termination for Patent Action. This License shall terminate 178 | automatically and You may no longer exercise any of the rights 179 | granted to You by this License as of the date You commence an 180 | action, including a cross-claim or counterclaim, against 181 | Licensor or any licensee alleging that the Original Work 182 | infringes a patent. This termination provision shall not apply 183 | for an action alleging patent infringement by combinations of 184 | the Original Work with other software or hardware. 185 | 186 | 11. Jurisdiction, Venue and Governing Law. Any action or suit 187 | relating to this License may be brought only in the courts of a 188 | jurisdiction wherein the Licensor resides or in which Licensor 189 | conducts its primary business, and under the laws of that 190 | jurisdiction excluding its conflict-of-law provisions. The 191 | application of the United Nations Convention on Contracts for 192 | the International Sale of Goods is expressly excluded. Any use 193 | of the Original Work outside the scope of this License or after 194 | its termination shall be subject to the requirements and 195 | penalties of copyright or patent law in the appropriate 196 | jurisdiction. This section shall survive the termination of this 197 | License. 198 | 199 | 12. Attorneys' Fees. In any action to enforce the terms of this 200 | License or seeking damages relating thereto, the prevailing 201 | party shall be entitled to recover its costs and expenses, 202 | including, without limitation, reasonable attorneys' fees and 203 | costs incurred in connection with such action, including any 204 | appeal of such action. This section shall survive the 205 | termination of this License. 206 | 207 | 13. Miscellaneous. If any provision of this License is held to be 208 | unenforceable, such provision shall be reformed only to the 209 | extent necessary to make it enforceable. 210 | 211 | 14. Definition of "You" in This License. "You" throughout this License, 212 | whether in upper or lower case, means an individual or a legal 213 | entity exercising rights under, and complying with all of the 214 | terms of, this License. For legal entities, "You" includes any 215 | entity that controls, is controlled by, or is under common 216 | control with you. For purposes of this definition, "control" 217 | means (i) the power, direct or indirect, to cause the direction 218 | or management of such entity, whether by contract or otherwise, 219 | or (ii) ownership of fifty percent (50%) or more of the 220 | outstanding shares, or (iii) beneficial ownership of such 221 | entity. 222 | 223 | 15. Right to Use. You may use the Original Work in all ways not 224 | otherwise restricted or conditioned by this License or by law, 225 | and Licensor promises not to interfere with or be responsible 226 | for such uses by You. 227 | 228 | 16. Modification of This License. This License is Copyright (c) 2005 229 | Lawrence Rosen. Permission is granted to copy, distribute, or 230 | communicate this License without modification. Nothing in this 231 | License permits You to modify this License as applied to the 232 | Original Work or to Derivative Works. However, You may modify 233 | the text of this License and copy, distribute or communicate 234 | your modified version (the "Modified License") and apply it to 235 | other original works of authorship subject to the following 236 | conditions: (i) You may not indicate in any way that your 237 | Modified License is the "Open Software License" or "OSL" and you 238 | may not use those names in the name of your Modified License; 239 | (ii) You must replace the notice specified in the first 240 | paragraph above with the notice "Licensed under " or with a notice of your own that is not 242 | confusingly similar to the notice in this License; and (iii) You 243 | may not claim that your original works are open source software 244 | unless your Modified License has been approved by Open Source 245 | Initiative (OSI) and You comply with its license review and 246 | certification process. 247 | -------------------------------------------------------------------------------- /pkg/debian/docs: -------------------------------------------------------------------------------- 1 | doc/bootstrap.txt 2 | doc/verbosity.txt 3 | changelog 4 | -------------------------------------------------------------------------------- /pkg/debian/linda.overrides: -------------------------------------------------------------------------------- 1 | Tag: usr-lib-in-arch-all 2 | Data: yum-plugins 3 | -------------------------------------------------------------------------------- /pkg/debian/manpages: -------------------------------------------------------------------------------- 1 | doc/bootstrap_firmware.8 2 | doc/inventory_firmware.8 3 | doc/inventory_firmware_gui.8 4 | doc/update_firmware.8 5 | -------------------------------------------------------------------------------- /pkg/debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #DEBHELPER# 4 | 5 | if [ "$1" == "triggered" ]; then 6 | for t in $2; do 7 | if [ "$t" == "firmware-tools-update-firmware" ]; then 8 | /usr/sbin/update_firmware --rpm -y 9 | fi 10 | done 11 | fi 12 | 13 | -------------------------------------------------------------------------------- /pkg/debian/pyversions: -------------------------------------------------------------------------------- 1 | 2.2- 2 | -------------------------------------------------------------------------------- /pkg/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # vim:noet:ts=8:sw=8:filetype=make 4 | 5 | DEB_PYTHON_SYSTEM=pysupport 6 | include /usr/share/cdbs/1/rules/debhelper.mk 7 | include /usr/share/cdbs/1/rules/simple-patchsys.mk 8 | include /usr/share/cdbs/1/class/autotools.mk 9 | include /usr/share/cdbs/1/rules/utils.mk 10 | 11 | binary-install/firmware-tools:: 12 | dh_pysupport -pfirmware-tools 13 | 14 | install/firmware-tools:: 15 | install -d debian/firmware-tools/usr/share/linda/overrides 16 | install -m 644 debian/linda.overrides \ 17 | debian/firmware-tools/usr/share/linda/overrides/firmware-tools 18 | mv ChangeLog changelog 19 | 20 | # because Gutsy debhelper doesn't install triggers 21 | binary-predeb/firmware-tools:: 22 | install -m 644 -o root -g root debian/triggers \ 23 | debian/firmware-tools/DEBIAN/triggers 24 | -------------------------------------------------------------------------------- /pkg/debian/triggers: -------------------------------------------------------------------------------- 1 | interest firmware-tools-update-firmware 2 | -------------------------------------------------------------------------------- /pkg/debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | 3 | http://linux.dell.com/files/libsmbios/download/firmware-tools/firmware-tools-(.*)/firmware-tools-(.*)\.tar\.gz 4 | -------------------------------------------------------------------------------- /pkg/firmware-tools.spec.in: -------------------------------------------------------------------------------- 1 | # vim:tw=0:ts=4:sw=4:et 2 | 3 | %define major @RELEASE_MAJOR@ 4 | %define minor @RELEASE_MINOR@ 5 | %define micro @RELEASE_MICRO@ 6 | %define extra @RELEASE_RPM_EXTRA@ 7 | %define release_version %{major}.%{minor}.%{micro}%{extra} 8 | %define rpm_release 1 9 | 10 | # per fedora python packaging guidelines 11 | %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 12 | 13 | Name: firmware-tools 14 | Version: %{release_version} 15 | Release: %{rpm_release}%{?dist} 16 | Summary: Scripts and tools to manage firmware and BIOS updates 17 | 18 | Group: Applications/System 19 | License: GPLv2+ or OSL 2.1 20 | URL: http://linux.dell.com/libsmbios/download/ 21 | Source0: http://linux.dell.com/libsmbios/download/%{name}/%{name}-%{version}/%{name}-%{version}.tar.bz2 22 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 23 | 24 | # SUSE doesnt have noarch python, so for SUSE, always build arch-dependent 25 | %if ! 0%{?suse_version} 26 | BuildArch: noarch 27 | %endif 28 | 29 | BuildRequires: python-devel, rpm-python 30 | Requires: rpm-python, pciutils 31 | Provides: firmware_inventory(pci) = 0:%{release_version} 32 | 33 | # packages that dont conform to latest ABI 34 | Conflicts: firmware_addon_dell < 0:2.1.0 35 | Conflicts: dell-dup < 0:1.1.0 36 | 37 | %description 38 | The firmware-tools project provides tools to inventory hardware and a plugin 39 | architecture so that different OEM vendors can provide different inventory 40 | components. It is intended to tie to the package system to enable seamless 41 | installation of updated firmware via your package manager, as well as provide 42 | a framework for BIOS and firmware updates. 43 | 44 | 45 | %prep 46 | %setup -q 47 | 48 | 49 | %build 50 | # this line lets us build an RPM directly from a git tarball 51 | [ -e ./configure ] || \ 52 | RELEASE_MAJOR=%{major} \ 53 | RELEASE_MINOR=%{minor} \ 54 | RELEASE_MICRO=%{micro} \ 55 | RELEASE_EXTRA=%{extra} \ 56 | ./autogen.sh --no-configure 57 | 58 | # fix problems when buildsystem time is out of sync. ./configure will 59 | # fail if newly created files are older than the packaged files. 60 | # this should normally be a no-op on proper buildsystems. 61 | touch configure 62 | find . -type f -newer configure -print0 | xargs -r0 touch 63 | 64 | %configure 65 | make -e %{?_smp_mflags} 66 | 67 | %check 68 | make -e %{?_smp_mflags} check 69 | 70 | %install 71 | # Fedora Packaging guidelines 72 | rm -rf $RPM_BUILD_ROOT 73 | # SUSE Packaging rpmlint 74 | mkdir $RPM_BUILD_ROOT 75 | 76 | make install DESTDIR=%{buildroot} INSTALL="%{__install} -p" 77 | 78 | mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/firmware/firmware.d/ 79 | mkdir -p $RPM_BUILD_ROOT/%{_datadir}/firmware 80 | 81 | # backwards compatibility symlinks 82 | mkdir -p $RPM_BUILD_ROOT/%{_bindir} 83 | ln -s firmwaretool $RPM_BUILD_ROOT/%{_sbindir}/inventory_firmware 84 | ln -s firmwaretool $RPM_BUILD_ROOT/%{_sbindir}/bootstrap_firmware 85 | ln -s firmwaretool $RPM_BUILD_ROOT/%{_sbindir}/update_firmware 86 | ln -s %{_sbindir}/firmwaretool $RPM_BUILD_ROOT/%{_bindir}/update_firmware 87 | 88 | 89 | %clean 90 | rm -rf $RPM_BUILD_ROOT 91 | 92 | 93 | %files 94 | %defattr(-,root,root,-) 95 | %doc COPYING-GPL COPYING-OSL COPYING.LIB README 96 | %{python_sitelib}/* 97 | %attr(0755,root,root) %{_sbindir}/* 98 | %attr(0755,root,root) %{_bindir}/* 99 | %{_datadir}/firmware-tools/ 100 | %dir %{_sysconfdir}/firmware 101 | %dir %{_sysconfdir}/firmware/firmware.d 102 | %config(noreplace) %{_sysconfdir}/firmware/firmware.conf 103 | %{_datadir}/firmware/ 104 | 105 | 106 | %changelog 107 | * Thu Aug 23 2007 Michael E Brown - 1.5.6-1 108 | - rebase to upstream release 109 | 110 | * Fri Aug 17 2007 Michael E Brown - 1.5.5-1 111 | - rebase to upstream release 112 | 113 | * Fri Aug 17 2007 Michael E Brown - 1.4.2-1 114 | - rebase to upstream release 115 | 116 | * Tue May 1 2007 Michael E Brown - 1.2.6-1 117 | - disable empty debuginfo package 118 | 119 | * Tue Mar 20 2007 Michael E Brown - 1.2.5-1 120 | - Remove python-abi dep for RHEL3 (it was broken) 121 | 122 | * Fri Mar 16 2007 Michael E Brown - 1.2.4-1 123 | - fix typo in sitelib path -- only for RHEL3 build 124 | 125 | * Wed Mar 14 2007 Michael E Brown - 1.2.3-1 126 | - create and own {_sysconfdir}/firmware/firmware.d/ for plugins. 127 | - Fedora review changes 128 | 129 | * Mon Mar 12 2007 Michael E Brown - 1.2.0-1 130 | - Fedora-compliant packaging changes. 131 | -------------------------------------------------------------------------------- /pkg/mk-rel-rpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # vim:et:ai:ts=4:sw=4:filetype=sh:tw=0: 3 | 4 | set -x 5 | 6 | cur_dir=$(cd $(dirname $0); pwd) 7 | cd $cur_dir/../ 8 | 9 | umask 002 10 | 11 | [ -n "$LIBSMBIOS_TOPDIR" ] || 12 | LIBSMBIOS_TOPDIR=/var/ftp/pub/Applications/libsmbios/ 13 | 14 | set -e 15 | 16 | chmod -R +w _builddir ||: 17 | rm -rf _builddir 18 | 19 | mkdir _builddir 20 | pushd _builddir 21 | ../autogen.sh 22 | make -e distcheck 23 | make -e srpm 24 | 25 | make git-tag 26 | eval "$(make get-version)" 27 | 28 | DEST=$LIBSMBIOS_TOPDIR/download/${PACKAGE}/$PACKAGE-$PACKAGE_VERSION/ 29 | mkdir -p $DEST 30 | for i in *.tar.{gz,bz2} *.zip *.src.rpm; do 31 | [ -e $i ] || continue 32 | [ ! -e $DEST/$(basename $i) ] || continue 33 | cp $i $DEST 34 | done 35 | 36 | git push --tags origin master:master 37 | -------------------------------------------------------------------------------- /test/TestLib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # VIM declarations 3 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 4 | 5 | #alphabetical order 6 | import os 7 | import unittest 8 | 9 | def usage(): 10 | print "wrong command line options." #need better help eventually 11 | 12 | def parseOptions(*args): 13 | pass 14 | 15 | def runTests( testCase ): 16 | testToRun = 'test' 17 | 18 | myTestSuite = unittest.TestSuite() 19 | for i in testCase: 20 | try: 21 | temp = unittest.makeSuite( i, testToRun ) 22 | myTestSuite.addTest(temp) 23 | except ValueError: 24 | pass 25 | 26 | runner = unittest.TextTestRunner( verbosity=3 ) 27 | retval = runner.run(myTestSuite) 28 | 29 | return retval.wasSuccessful() 30 | 31 | #END main( testCase ): 32 | 33 | main = runTests 34 | 35 | def areFilesDifferent( orig, copy ): 36 | ret = os.system( "diff -q %s %s >/dev/null 2>&1" % (orig, copy) ) >> 8 37 | if ret == 0: 38 | return 0 39 | if ret == 1: 40 | return 1 41 | raise "something bad happened" 42 | 43 | def copyFile( source, dest ): 44 | fileOrig = open( source, "r" ) 45 | fileCopy = open( dest, "w" ) 46 | 47 | line = fileOrig.read( 512 ) 48 | while line != "": 49 | fileCopy.write(line) 50 | line = fileOrig.read( 512 ) 51 | 52 | fileOrig.close() 53 | fileCopy.close() 54 | 55 | if __name__ == "__main__": 56 | print "This file is not executable." 57 | -------------------------------------------------------------------------------- /test/datafiles/system_ven_0x5555_dev_0x1234/system_specific-a03/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = system_specific 3 | version = a03 4 | limit_system_support = ven_0x5555_dev_0x1234 5 | -------------------------------------------------------------------------------- /test/datafiles/system_ven_0x5555_dev_0x1234/system_specific-a04/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = system_specific 3 | version = a04 4 | limit_system_support = ven_0x5555_dev_0x1234 5 | -------------------------------------------------------------------------------- /test/datafiles/system_ven_0x5555_dev_0x4321/system_specific-a08/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = system_specific 3 | version = a08 4 | limit_system_support = ven_0x5555_dev_0x4321 5 | -------------------------------------------------------------------------------- /test/datafiles/system_ven_0x5555_dev_0x4321/system_specific-a09/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = system_specific 3 | version = a09 4 | limit_system_support = ven_0x5555_dev_0x4321 5 | -------------------------------------------------------------------------------- /test/datafiles/test_requires-a09/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = test_requires 3 | version = a09 4 | requires = otherpackage, foo > 42 5 | -------------------------------------------------------------------------------- /test/datafiles/testorder1-a04/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testorder1 3 | version = a04 4 | requires = 5 | -------------------------------------------------------------------------------- /test/datafiles/testorder2-a05/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testorder2 3 | version = a05 4 | requires = testorder1 > a03 5 | -------------------------------------------------------------------------------- /test/datafiles/testorder3-a06/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testorder3 3 | version = a06 4 | requires = testorder1 > a03, testorder2 > a04 5 | -------------------------------------------------------------------------------- /test/datafiles/testpack-a04/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testpack 3 | version = a04 4 | requies = 5 | -------------------------------------------------------------------------------- /test/datafiles/testpack-a05/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testpack 3 | version = a05 4 | -------------------------------------------------------------------------------- /test/datafiles/testpack-a06/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testpack 3 | version = a06 4 | -------------------------------------------------------------------------------- /test/datafiles/testpack_another-a04/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testpack_another 3 | version = a04 4 | requires = 5 | -------------------------------------------------------------------------------- /test/datafiles/testpack_different-a07/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testpack_different 3 | version = a07 4 | module = mockpackage 5 | type = MockPackage2 6 | requires = "" 7 | -------------------------------------------------------------------------------- /test/datafiles/testpack_newpkgstrat-a08/package.ini: -------------------------------------------------------------------------------- 1 | [package] 2 | name = testpack_newpkgstrat 3 | version = a08 4 | module = mockpackage 5 | type = MockPackage2 6 | requires = "" 7 | -------------------------------------------------------------------------------- /test/testAll.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # VIM declarations 3 | # vim:tw=0:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 4 | 5 | #alphabetical 6 | import os 7 | import sys 8 | import glob 9 | 10 | # all of the variables below are substituted by the build system 11 | __VERSION__="1.0.0" 12 | 13 | import TestLib 14 | 15 | exeName = os.path.realpath(sys.argv[0]) 16 | top_srcdir = os.path.join(os.path.dirname(exeName), "..") 17 | top_builddir = os.getcwd() 18 | 19 | sys.path.insert(0,top_srcdir) 20 | sys.path.insert(0,"%s/ft-cli/" % top_srcdir) 21 | 22 | # runs all modules TestCase() classes in files that match test*.py 23 | if __name__ == "__main__": 24 | testModulePath="%s/test/" % top_srcdir 25 | 26 | moduleNames = glob.glob( "%s/test*.py" % testModulePath ) 27 | moduleNames = [ m[len(testModulePath):-3] for m in moduleNames ] 28 | 29 | tests = [] 30 | for moduleName in moduleNames: 31 | if "testAll" in moduleName: 32 | continue 33 | module = __import__(moduleName, globals(), locals(), []) 34 | module.TestCase.top_srcdir=top_srcdir 35 | module.TestCase.top_builddir=top_builddir 36 | tests.append(module.TestCase) 37 | 38 | retval = 1 39 | if tests: 40 | retval = TestLib.runTests( tests ) 41 | 42 | sys.exit( not retval ) 43 | -------------------------------------------------------------------------------- /test/testDepParser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 3 | """ 4 | """ 5 | 6 | from __future__ import generators 7 | 8 | import sys 9 | import os 10 | import unittest 11 | 12 | class TestCase(unittest.TestCase): 13 | def setUp(self): 14 | if globals().get('firmwaretools'): del(firmwaretools) 15 | for k in sys.modules.keys(): 16 | if k.startswith("firmwaretools"): 17 | del(sys.modules[k]) 18 | 19 | import firmwaretools.package as package 20 | pkgA = package.Package(name="pkgA", version="a01", displayname="test pkgA") 21 | pkgB = package.Package(name="pkgC", version="a02", displayname="test pkgC") 22 | pkgC = package.Package(name="pkgC", version="a03", displayname="test pkgC") 23 | 24 | self.inventory = {} 25 | self.inventory['pkgA'] = pkgA 26 | self.inventory['pkgB'] = pkgB 27 | self.inventory['pkgC'] = pkgC 28 | 29 | def tearDown(self): 30 | if globals().get('firmwaretools'): del(firmwaretools) 31 | for k in sys.modules.keys(): 32 | if k.startswith("firmwaretools"): 33 | del(sys.modules[k]) 34 | 35 | def testExist(self): 36 | import firmwaretools.dep_parser as dep_parser 37 | s = "pkgA" 38 | d = dep_parser.DepParser(s, self.inventory, {}) 39 | self.assertEquals(1, d.depPass) 40 | 41 | def testExist2(self): 42 | import firmwaretools.dep_parser as dep_parser 43 | tests = [ ("exist", "pkgA"), 44 | ("gt", "pkgA > a00"), 45 | ("ge1", "pkgA >= a00"), 46 | ("ge2", "pkgA >= a01"), 47 | ("eq", "pkgA == a01"), 48 | ("le1", "pkgA <= a01"), 49 | ("le2", "pkgA <= a02"), 50 | ("lt", "pkgA < a02"), 51 | ("exist_gt", "pkgA, pkgB > a01"), 52 | ("exist_gt_exist", "pkgA, pkgB > a01, pkgC"), ] 53 | 54 | for name, testStr in tests: 55 | d = dep_parser.DepParser(testStr, self.inventory, {}) 56 | self.assertEquals(1, d.depPass) 57 | 58 | def testExist3(self): 59 | import firmwaretools.dep_parser as dep_parser 60 | tests = [ ("exist", "pkgD"), 61 | ("gt", "pkgA > a01"), 62 | ("ge1", "pkgA >= a02"), 63 | ("ge2", "pkgA >= a03"), 64 | ("eq", "pkgA == a02"), 65 | ("le1", "pkgA <= a00"), 66 | ("lt", "pkgA < a01"), 67 | ("exist_gt", "pkgA, pkgB > a01, pkgD"), 68 | ("exist_gt_exist", "pkgA, pkgB < a01, pkgC"), ] 69 | 70 | for name, testStr in tests: 71 | d = dep_parser.DepParser(testStr, self.inventory, {}) 72 | self.assertEquals(0, d.depPass) 73 | 74 | 75 | 76 | 77 | 78 | 79 | if __name__ == "__main__": 80 | import test.TestLib 81 | sys.exit(not test.TestLib.runTests( [TestCase] )) 82 | -------------------------------------------------------------------------------- /test/testPackage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # vim:tw=0:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 3 | """ 4 | """ 5 | 6 | from __future__ import generators 7 | 8 | import sys 9 | import os 10 | import unittest 11 | 12 | class TestCase(unittest.TestCase): 13 | def setUp(self): 14 | if globals().get('firmwaretools'): del(firmwaretools) 15 | for k in sys.modules.keys(): 16 | if k.startswith("firmwaretools"): 17 | del(sys.modules[k]) 18 | 19 | def tearDown(self): 20 | if globals().get('firmwaretools'): del(firmwaretools) 21 | for k in sys.modules.keys(): 22 | if k.startswith("firmwaretools"): 23 | del(sys.modules[k]) 24 | 25 | def testCompareVersions(self): 26 | import firmwaretools.package as package 27 | self.assertEqual(-1, package.defaultCompareStrategy( "1.0", "2.0")) 28 | self.assertEqual( 0, package.defaultCompareStrategy( "1.0", "1.0")) 29 | self.assertEqual( 1, package.defaultCompareStrategy( "2.0", "1.0")) 30 | 31 | 32 | if __name__ == "__main__": 33 | import test.TestLib 34 | sys.exit(not test.TestLib.runTests( [TestCase] )) 35 | -------------------------------------------------------------------------------- /test/testPciBootstrap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 3 | """ 4 | """ 5 | 6 | from __future__ import generators 7 | 8 | import sys 9 | import unittest 10 | import ConfigParser 11 | import os 12 | 13 | class TestCase(unittest.TestCase): 14 | def setUp(self): 15 | if globals().get('firmwaretools'): del(firmwaretools) 16 | for k in sys.modules.keys(): 17 | if k.startswith("firmwaretools"): 18 | del(sys.modules[k]) 19 | 20 | def tearDown(self): 21 | if globals().get('firmwaretools'): del(firmwaretools) 22 | for k in sys.modules.keys(): 23 | if k.startswith("firmwaretools"): 24 | del(sys.modules[k]) 25 | 26 | def testBootstrapInventory(self): 27 | import firmwaretools 28 | import firmwaretools.plugins as plugins 29 | 30 | # manually setup fake config file 31 | f = firmwaretools.FtBase() 32 | pluginTypes = [ 33 | plugins.TYPE_CORE, 34 | plugins.TYPE_MOCK_CORE, plugins.TYPE_MOCK_INVENTORY, 35 | ] 36 | #instead of "f._getConfig(None, pluginTypes, None, [])" 37 | # do the below to avoid "logging.config.fileConfig(configFile)" 38 | cfgFiles = [os.path.join(firmwaretools.PKGCONFDIR, "firmware.conf"),] 39 | f.conf = firmwaretools.confObj() 40 | f.setConfFromIni(cfgFiles) 41 | f.conf.uid = os.geteuid() 42 | f.doPluginSetup(None , pluginTypes, []) 43 | 44 | # import functions for bootstrap/compare 45 | 46 | # run bootstrap and compare. 47 | index = 0 48 | for pkg in f.yieldInventory(): 49 | self.assertEqual( firmwaretools.mockpackage.mockExpectedOutput.split("\n")[index], pkg.name ) 50 | index = index + 1 51 | 52 | # ensure it actually ran. 53 | self.assertEqual(index, len(firmwaretools.mockpackage.mockExpectedOutput.split("\n"))) 54 | 55 | 56 | if __name__ == "__main__": 57 | import test.TestLib 58 | sys.exit(not test.TestLib.runTests( [TestCase] )) 59 | -------------------------------------------------------------------------------- /test/testPycompat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 3 | """ 4 | """ 5 | 6 | from __future__ import generators 7 | 8 | import sys 9 | import os 10 | import unittest 11 | 12 | class TestCase(unittest.TestCase): 13 | def setUp(self): 14 | if globals().get('firmwaretools'): del(firmwaretools) 15 | for k in sys.modules.keys(): 16 | if k.startswith("firmwaretools"): 17 | del(sys.modules[k]) 18 | 19 | def tearDown(self): 20 | if globals().get('firmwaretools'): del(firmwaretools) 21 | for k in sys.modules.keys(): 22 | if k.startswith("firmwaretools"): 23 | del(sys.modules[k]) 24 | 25 | def testExcCommandNoTimeout(self): 26 | import firmwaretools.pycompat as pycompat 27 | pycompat.executeCommand("sleep 0", timeout=0) 28 | 29 | def testExcCommandTimeout(self): 30 | import firmwaretools.pycompat as pycompat 31 | self.assertRaises(pycompat.commandTimeoutExpired, pycompat.executeCommand, "sleep 3", timeout=1) 32 | 33 | def testExcCommandAlarmNoTimeout(self): 34 | # test that executeCommand() doesn't interfere with existing alarm calls 35 | # given a command that itself doesnt timeout 36 | import signal, time 37 | import firmwaretools.pycompat as pycompat 38 | class alarmExc(Exception): pass 39 | def alarmhandler(signum,stackframe): 40 | raise alarmExc("timeout expired") 41 | 42 | oldhandler=signal.signal(signal.SIGALRM,alarmhandler) 43 | prevTimeout = signal.alarm(1) 44 | pycompat.executeCommand("sleep 0", timeout=1) 45 | self.assertRaises(alarmExc, time.sleep, 5) 46 | 47 | def testExcCommandAlarmTimeout(self): 48 | # test that executeCommand() doesn't interfere with existing alarm calls 49 | # given a command that itself times out 50 | import signal, time 51 | import firmwaretools.pycompat as pycompat 52 | class alarmExc(Exception): pass 53 | def alarmhandler(signum,stackframe): 54 | raise alarmExc("timeout expired") 55 | 56 | oldhandler=signal.signal(signal.SIGALRM,alarmhandler) 57 | prevTimeout = signal.alarm(2) 58 | self.assertRaises(pycompat.commandTimeoutExpired, pycompat.executeCommand,"sleep 2", timeout=1) 59 | self.assertRaises(alarmExc, time.sleep, 10) 60 | 61 | 62 | 63 | if __name__ == "__main__": 64 | import test.TestLib 65 | sys.exit(not test.TestLib.runTests( [TestCase] )) 66 | -------------------------------------------------------------------------------- /test/testRepository.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:tw=0 3 | """ 4 | """ 5 | 6 | from __future__ import generators 7 | 8 | import sys 9 | import os 10 | import unittest 11 | 12 | try: 13 | test_path = os.path.dirname( os.path.realpath( globals()["__file__"] ) ) 14 | except KeyError: 15 | test_path = os.path.realpath( sys.path[0] ) 16 | 17 | datafiles = os.path.join( test_path, "datafiles" ) 18 | 19 | def generateUpdateSet(repo, inv): 20 | import firmwaretools.repository as repository 21 | _systemInventory = repository.SystemInventory() 22 | for dev in inv: 23 | _systemInventory.addDevice(dev) 24 | 25 | for candidate in repo.iterPackages(): 26 | _systemInventory.addAvailablePackage(candidate) 27 | 28 | _systemInventory.calculateUpgradeList() 29 | return _systemInventory 30 | 31 | 32 | class TestCase(unittest.TestCase): 33 | def setUp(self): 34 | if globals().get('firmwaretools'): del(firmwaretools) 35 | for k in sys.modules.keys(): 36 | if k.startswith("firmwaretools"): 37 | del(sys.modules[k]) 38 | 39 | def tearDown(self): 40 | if globals().get('firmwaretools'): del(firmwaretools) 41 | for k in sys.modules.keys(): 42 | if k.startswith("firmwaretools"): 43 | del(sys.modules[k]) 44 | 45 | def testRepositoryInventory(self): 46 | import firmwaretools.repository as repository 47 | r = repository.Repository(datafiles) 48 | for pkg in r.iterPackages(): 49 | pass 50 | 51 | def testIterLatest(self): 52 | import firmwaretools.repository as repository 53 | r = repository.Repository(datafiles) 54 | list = [] 55 | 56 | # list of versions for system_specific 57 | li = ["a04", "a09"] 58 | 59 | for pkg in r.iterLatestPackages(): 60 | if pkg.name == "testpack": 61 | self.assertEqual( pkg.version, "a06" ) 62 | elif pkg.name == "testpack_another": 63 | self.assertEqual( pkg.version, "a04" ) 64 | elif pkg.name == "testpack_different": 65 | self.assertEqual( pkg.version, "a07" ) 66 | elif pkg.name == "testpack_newpkgstrat": 67 | self.assertEqual( pkg.version, "a08" ) 68 | elif pkg.name == "system_specific": 69 | self.failUnless( pkg.version in li ) 70 | li.remove(pkg.version) 71 | elif pkg.name == "test_requires": 72 | self.assertEqual( pkg.version, "a09" ) 73 | elif pkg.name == "testorder1": 74 | self.assertEqual( pkg.version, "a04" ) 75 | elif pkg.name == "testorder2": 76 | self.assertEqual( pkg.version, "a05" ) 77 | elif pkg.name == "testorder3": 78 | self.assertEqual( pkg.version, "a06" ) 79 | elif pkg.name == "circtest1": 80 | self.assertEqual( pkg.version, "a04" ) 81 | elif pkg.name == "circtest2": 82 | self.assertEqual( pkg.version, "a04" ) 83 | else: 84 | self.fail("Unknown package. %s version %s" % (pkg.name, pkg.version)) 85 | 86 | self.assertEqual( len(li), 0 ) 87 | 88 | def testGenerateUpdateSet1(self): 89 | import firmwaretools.repository as repository 90 | import firmwaretools.package as package 91 | p = package.Device( 92 | name = "testpack", 93 | version = "a04", 94 | displayname = "fake" 95 | ) 96 | systemInventory = [p,] 97 | r = repository.Repository(datafiles) 98 | updateSet = generateUpdateSet(r, systemInventory) 99 | 100 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "testpack" ) 101 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a06" ) 102 | 103 | def testGenerateUpdateSet2(self): 104 | import firmwaretools.repository as repository 105 | import firmwaretools.package as package 106 | p = package.Device( 107 | name = "testpack_different", 108 | version = "a04", 109 | displayname = "fake" 110 | ) 111 | systemInventory = [p,] 112 | r = repository.Repository(datafiles) 113 | updateSet = generateUpdateSet(r, systemInventory) 114 | 115 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "testpack_different" ) 116 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a07" ) 117 | 118 | def testGenerateUpdateSet3(self): 119 | import firmwaretools.repository as repository 120 | import firmwaretools.package as package 121 | p = package.Device( 122 | name = "testpack", 123 | version = "a08", 124 | displayname = "fake" 125 | ) 126 | systemInventory = [p,] 127 | r = repository.Repository(datafiles) 128 | updateSet = generateUpdateSet(r, systemInventory) 129 | 130 | self.failUnless( updateSet.getUpdatePackageForDevice(p) is None ) 131 | 132 | def testGenerateUpdateSet4_andInstall(self): 133 | import firmwaretools.repository as repository 134 | import firmwaretools.package as package 135 | p = package.Device( 136 | name = "testpack_newpkgstrat", 137 | version = "a04", 138 | displayname = "fake" 139 | ) 140 | systemInventory = [p,] 141 | r = repository.Repository(datafiles) 142 | updateSet = generateUpdateSet(r, systemInventory) 143 | 144 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "testpack_newpkgstrat" ) 145 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a08") 146 | res = updateSet.getUpdatePackageForDevice(p).install() 147 | self.assertEqual( res, "SUCCESS" ) 148 | 149 | def testGenerateUpdateSetMultiple(self): 150 | import firmwaretools.repository as repository 151 | import firmwaretools.package as package 152 | 153 | p = package.Device( 154 | name = "testpack", 155 | version = "a04", 156 | displayname = "fake" 157 | ) 158 | 159 | q = package.Device( 160 | name = "testpack_different", 161 | version = "a04", 162 | displayname = "fake" 163 | ) 164 | 165 | r = package.Device( 166 | name = "testpack_another", 167 | version = "a05", 168 | displayname = "fake" 169 | ) 170 | 171 | systemInventory = [p,q,r] 172 | repo = repository.Repository(datafiles) 173 | updateSet = generateUpdateSet(repo, systemInventory) 174 | 175 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "testpack" ) 176 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a06" ) 177 | self.assertEqual( updateSet.getUpdatePackageForDevice(q).name, "testpack_different" ) 178 | self.assertEqual( updateSet.getUpdatePackageForDevice(q).version, "a07" ) 179 | self.failUnless( updateSet.getUpdatePackageForDevice(r) is None ) 180 | 181 | def testGenerateUpdateSetInstallDefault(self): 182 | import firmwaretools.repository as repository 183 | import firmwaretools.package as package 184 | p = package.Device( 185 | name = "testpack", 186 | version = "a04", 187 | displayname = "fake" 188 | ) 189 | systemInventory = [p,] 190 | r = repository.Repository(datafiles) 191 | updateSet = generateUpdateSet(r, systemInventory) 192 | self.assertRaises(package.NoInstaller, updateSet.getUpdatePackageForDevice(p).install) 193 | 194 | def testGenerateUpdateSetInstall(self): 195 | import firmwaretools.repository as repository 196 | import firmwaretools.package as package 197 | p = package.Device( 198 | name = "testpack_different", 199 | version = "a04", 200 | displayname = "fake" 201 | ) 202 | systemInventory = [p,] 203 | r = repository.Repository(datafiles) 204 | updateSet = generateUpdateSet(r, systemInventory) 205 | res = updateSet.getUpdatePackageForDevice(p).install() 206 | self.assertEqual( res, "SUCCESS" ) 207 | 208 | 209 | def testGenerateUpdateSet_SystemSpecific1(self): 210 | # test the case where system specific update available that doesn't 211 | # apply to current system 212 | import firmwaretools.repository as repository 213 | import firmwaretools.package as package 214 | p = package.Device( 215 | name = "system_specific", 216 | version = "a01", 217 | displayname = "fake" 218 | ) 219 | systemInventory = [p,] 220 | r = repository.Repository(datafiles) 221 | updateSet = generateUpdateSet(r, systemInventory) 222 | 223 | self.failUnless( updateSet.getUpdatePackageForDevice(p) is None ) 224 | 225 | def testGenerateUpdateSet_SystemSpecific2(self): 226 | # test the case where system specific update available that does 227 | # apply to current system 228 | import firmwaretools.repository as repository 229 | import firmwaretools.package as package 230 | 231 | p = package.Device( 232 | name = "system_specific", 233 | version = "a01", 234 | displayname = "fake" 235 | ) 236 | 237 | q = package.Device( 238 | name = "system_bios(ven_0x5555_dev_0x1234)", 239 | version = "a00", 240 | displayname = "fake" 241 | ) 242 | 243 | systemInventory = [p,q] 244 | r = repository.Repository(datafiles) 245 | updateSet = generateUpdateSet(r, systemInventory) 246 | 247 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "system_specific" ) 248 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a04" ) 249 | 250 | def testGenerateUpdateSet_SystemSpecific3(self): 251 | # test the case where system specific update available that does 252 | # apply to current system 253 | import firmwaretools.repository as repository 254 | import firmwaretools.package as package 255 | 256 | p = package.Device( 257 | name = "system_specific", 258 | version = "a01", 259 | displayname = "fake" 260 | ) 261 | 262 | q = package.Device( 263 | name = "system_bios(ven_0x5555_dev_0x4321)", 264 | version = "a00", 265 | displayname = "fake" 266 | ) 267 | 268 | systemInventory = [p,q] 269 | r = repository.Repository(datafiles) 270 | updateSet = generateUpdateSet(r, systemInventory) 271 | 272 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "system_specific" ) 273 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a09" ) 274 | 275 | 276 | def testGenerateUpdateSet_testRequires1(self): 277 | # test the case where system specific update available that doesn't 278 | # apply to current system 279 | import firmwaretools.repository as repository 280 | import firmwaretools.package as package 281 | 282 | p = package.Device( 283 | name = "test_requires", 284 | version = "a01", 285 | displayname = "fake" 286 | ) 287 | 288 | systemInventory = [p,] 289 | r = repository.Repository(datafiles) 290 | updateSet = generateUpdateSet(r, systemInventory) 291 | 292 | self.failUnless( updateSet.getUpdatePackageForDevice(p) is None ) 293 | 294 | def testGenerateUpdateSet_testRequires2(self): 295 | # test the case where system specific update available that does 296 | # apply to current system 297 | import firmwaretools.repository as repository 298 | import firmwaretools.package as package 299 | 300 | p = package.Device( 301 | name = "test_requires", 302 | version = "a01", 303 | displayname = "fake" 304 | ) 305 | 306 | q = package.Device( 307 | name = "otherpackage", 308 | version = "a00", 309 | displayname = "fake" 310 | ) 311 | 312 | r = package.Device( 313 | name = "foo", 314 | version = "43", 315 | displayname = "fake" 316 | ) 317 | 318 | systemInventory = [p,q,r] 319 | repo = repository.Repository(datafiles) 320 | updateSet = generateUpdateSet(repo, systemInventory) 321 | 322 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).name, "test_requires" ) 323 | self.assertEqual( updateSet.getUpdatePackageForDevice(p).version, "a09" ) 324 | 325 | def testInstallationOrder1(self): 326 | import firmwaretools.repository as repository 327 | import firmwaretools.package as package 328 | 329 | p = package.Device( 330 | name = "testorder1", 331 | version = "a01", 332 | displayname = "fake" 333 | ) 334 | 335 | q = package.Device( 336 | name = "testorder2", 337 | version = "a01", 338 | displayname = "fake" 339 | ) 340 | 341 | r = package.Device( 342 | name = "testorder3", 343 | version = "a01", 344 | displayname = "fake" 345 | ) 346 | 347 | systemInventory = [r,p,q] 348 | r = repository.Repository(datafiles) 349 | 350 | installationOrder = ["testorder1", "testorder2", "testorder3" ] 351 | updateSet = generateUpdateSet(r, systemInventory) 352 | for pkg in updateSet.generateInstallationOrder(): 353 | n = installationOrder[0] 354 | if len(installationOrder) > 1: 355 | installationOrder = installationOrder[1:] 356 | 357 | self.assertEqual( n, pkg.name ) 358 | 359 | def testInstallationOrder2(self): 360 | import firmwaretools.repository as repository 361 | import firmwaretools.package as package 362 | 363 | p = package.Device( 364 | name = "testorder1", 365 | version = "a01", 366 | displayname = "fake" 367 | ) 368 | 369 | q = package.Device( 370 | name = "testorder2", 371 | version = "a08", 372 | displayname = "fake" 373 | ) 374 | 375 | r = package.Device( 376 | name = "testorder3", 377 | version = "a01", 378 | displayname = "fake" 379 | ) 380 | 381 | systemInventory = [r,p,q] 382 | r = repository.Repository(datafiles) 383 | 384 | installationOrder = ["testorder1", "testorder3" ] 385 | updateSet = generateUpdateSet(r, systemInventory) 386 | for pkg in updateSet.generateInstallationOrder(): 387 | n = installationOrder[0] 388 | if len(installationOrder) > 1: 389 | installationOrder = installationOrder[1:] 390 | 391 | self.assertEqual( n, pkg.name ) 392 | 393 | 394 | if __name__ == "__main__": 395 | import test.TestLib 396 | sys.exit(not test.TestLib.runTests( [TestCase] )) 397 | -------------------------------------------------------------------------------- /yum-plugin/firmwaretools_bootstrap.conf: -------------------------------------------------------------------------------- 1 | [main] 2 | enabled=1 3 | 4 | -------------------------------------------------------------------------------- /yum-plugin/firmwaretools_bootstrap.py: -------------------------------------------------------------------------------- 1 | # vim:tw=0:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python: 2 | """ 3 | Yum plugin to automatically bootstrap packages. 4 | 5 | The purpose of this plugin is to automatically always add firmware-tools 6 | bootstrap to the yum transaction. Before this was done by an explicit added 7 | step. The instructions used to say: 8 | 9 | # yum install $(bootstrap_firmware) 10 | 11 | Normal bootstrap_firmware output looks like this: 12 | 13 | # bootstrap_firmware 14 | pci_firmware(ven_0x10de_dev_0x00e1) 15 | pci_firmware(ven_0x10de_dev_0x00e0_subven_0x10de_subdev_0x0c11) 16 | pci_firmware(ven_0x10de_dev_0x00e4_subven_0x10de_subdev_0x0c11) 17 | pci_firmware(ven_0x10de_dev_0x00e7_subven_0x10de_subdev_0x0c11) 18 | ... cut ... 19 | 20 | The yum install command would effectively look up each pci_firmware(...) line 21 | and look for RPM packages that had "Provides:" tags for the corresponding 22 | firmware. 23 | 24 | The purpose of this plugin is to remove that additional step. Now anytime the 25 | user says "yum upgrade", they will automatically get the latest bootstrap 26 | packages installed on their system. 27 | """ 28 | 29 | # TODO List: 30 | # -- command line option to disable 31 | # -- investigate using preresolve_hook w/ command line option to force 32 | # -- dont add firmware if user specifies pkgs in update cmd 33 | # -- way to not break CentOS 4 34 | 35 | from yum.plugins import TYPE_CORE 36 | import yum.Errors 37 | 38 | version="1.5.10" 39 | requires_api_version = '2.1' 40 | plugin_type = (TYPE_CORE,) 41 | 42 | import ConfigParser 43 | import os 44 | import sys 45 | import time 46 | 47 | global firmwaretools 48 | import firmwaretools.clifuncs 49 | import firmwaretools.trace_decorator as trace_decorator 50 | 51 | if os.environ.get('DEBUG_BOOTSTRAP') == "1": 52 | # provide a made-up set of bootstrap packages rather than real one. 53 | # useful for testing. 54 | import firmwaretools.mockpackage 55 | 56 | if os.environ.get('DEBUG'): 57 | # activate function tracing 58 | trace_decorator.debug["__main__"] = 9 59 | 60 | def exclude_hook(conduit): 61 | start = time.time() 62 | print "exclude hook start: %s" % start 63 | ini = ConfigParser.ConfigParser() 64 | firmwaretools.clifuncs.getConfig(ini, firmwaretools.clifuncs.configLocations) 65 | for pkg in firmwaretools.clifuncs.runBootstrapInventory(ini): 66 | # see if it is a normal package name 67 | try: 68 | conduit._base.install(name=pkg.name) 69 | continue 70 | except yum.Errors.InstallError, e: 71 | pass 72 | 73 | # isnt a straight name, need to see if it is a dep 74 | try: 75 | mypkg = conduit._base.returnPackageByDep(pkg.name) 76 | conduit._base.install(mypkg) 77 | except yum.Errors.YumBaseError, e: 78 | pass 79 | print "exclude hook end: %s" % (time.time() - start) 80 | 81 | ## debugging stuff... 82 | def debug_hook_calls(where, *args, **kargs): 83 | print "Where: %s" % where 84 | 85 | import functools 86 | for hook in ( 87 | 'config', 88 | 'postconfig', 89 | 'init', 90 | 'predownload', 91 | 'postdownload', 92 | 'prereposetup', 93 | 'postreposetup', 94 | 'close', 95 | 'clean', 96 | 'pretrans', 97 | 'posttrans', 98 | 'exclude', 99 | 'preresolve', 100 | 'postresolve', 101 | ): 102 | hookname = "%s_hook" % hook 103 | setattr(sys.modules[__name__], hookname, functools.partial(debug_hook_calls, hookname)) 104 | 105 | # this decorates all functions in this module to provide tracing if it is enabled. 106 | trace_decorator.decorateAllFunctions(sys.modules[__name__]) 107 | --------------------------------------------------------------------------------