From f61e776bde1f7513f797dc33fdc3ab9133969f60 Mon Sep 17 00:00:00 2001 From: a Date: Sat, 19 Nov 2016 03:00:48 +0100 Subject: [PATCH] . --- .gitignore | 73 +- LICENSE | 231 --- Makefile.am | 18 + README.md | 716 +++++++++- configure.ac | 54 + doc/Makefile | 33 + doc/README.md | 9 + doc/man_template.pdc | 23 + doc/pinkybar.1 | 1490 ++++++++++++++++++++ doc/pinkybar.texi | 1314 +++++++++++++++++ extra/FreeBSD/Makefile | 53 + extra/FreeBSD/pkg-descr | 1 + extra/FreeBSD/scripts/post-extract | 29 + extra/FreeBSD/scripts/post-fetch | 21 + extra/FreeBSD/scripts/post-install | 26 + .../pinky-curses/pinky-curses-9999.ebuild | 62 + extra/Gentoo/app-admin/pinky/metadata.xml | 29 + extra/Gentoo/app-admin/pinky/pinky-bar-9999.ebuild | 123 ++ extra/bash_zsh/_pinkybar | 90 ++ extra/bash_zsh/pinkybar | 40 + extra/deprecated/Makefile.skel | 87 ++ extra/deprecated/README.md | 5 + extra/deprecated/bootstrap | 262 ++++ extra/misc/openbsd_bugs.md | 62 + extra/misc/skdump.c | 38 + extra/mpd/README.md | 1 + extra/mpd/freebsd.conf | 17 + extra/mpd/linux.conf | 17 + extra/mpd/openbsd.conf | 17 + extra/ported_or_not_included/cpu_brand.S | 64 + extra/ported_or_not_included/cpu_cache.S | 60 + extra/ported_or_not_included/not_included.c | 267 ++++ extra/scripts/drive-temperature.sh | 40 + extra/scripts/dwm.sh | 24 + extra/scripts/pinky-curses.sh | 27 + extra/scripts/pinky.lua | 33 + extra/scripts/pinky.pl | 40 + extra/scripts/pinky.py | 41 + extra/scripts/pinky.rb | 33 + extra/scripts/xmonad.sh | 25 + extra/xbm_icons/arch.xbm | 4 + extra/xbm_icons/bat.xbm | 4 + extra/xbm_icons/clock.xbm | 4 + extra/xbm_icons/cpu.xbm | 4 + extra/xbm_icons/diskette.xbm | 4 + extra/xbm_icons/fan.xbm | 4 + extra/xbm_icons/fox.xbm | 4 + extra/xbm_icons/mem.xbm | 4 + extra/xbm_icons/mobo.xbm | 4 + extra/xbm_icons/mpd.xbm | 6 + extra/xbm_icons/net.xbm | 4 + extra/xbm_icons/sm4tik-icon-pack.tar.bz2 | Bin 0 -> 5228 bytes extra/xbm_icons/statio.xbm | 4 + extra/xbm_icons/temp.xbm | 4 + extra/xbm_icons/uptime.xbm | 4 + extra/xbm_icons/vol.xbm | 4 + extra/xbm_icons/voltage.xbm | 4 + img/cpu-temp.png | Bin 0 -> 40173 bytes img/mobo-temp.png | Bin 0 -> 34586 bytes img/pic.png | Bin 0 -> 1146 bytes img/pic2.png | Bin 0 -> 4877 bytes img/pic4.png | Bin 0 -> 5968 bytes img/pic5.png | Bin 0 -> 6595 bytes img/pic6.png | Bin 0 -> 8463 bytes img/pic7.png | Bin 0 -> 1453 bytes m4/1errs.m4 | 74 + m4/alsa.m4 | 134 ++ m4/ax_append_flag.m4 | 71 + m4/cflagz.m4 | 145 ++ m4/dvd.m4 | 85 ++ m4/extend.m4 | 309 ++++ m4/mpd.m4 | 78 + m4/net.m4 | 301 ++++ m4/sensors.m4 | 193 +++ m4/the_rest_funcs.m4 | 482 +++++++ m4/typez.m4 | 168 +++ m4/weather.m4 | 232 +++ m4/x11.m4 | 186 +++ set.pl | 144 ++ src/Makefail.skel | 37 + src/common.c | 474 +++++++ src/cpu.c | 466 ++++++ src/freebsd_functions.c | 293 ++++ src/include/freebzd.h | 31 + src/include/functions_constants.h | 156 ++ src/include/headers.h | 37 + src/include/ncurses_colours.h | 42 + src/include/non_x11_colours.h | 69 + src/include/openbzd.h | 31 + src/include/options_constants.h | 100 ++ src/include/options_generator.h | 109 ++ src/include/x11_colours.h | 45 + src/linux_functions.c | 373 +++++ src/lua.c | 92 ++ src/main.c | 48 + src/net.c | 697 +++++++++ src/openbsd_functions.c | 310 ++++ src/options.c | 408 ++++++ src/perl.c | 121 ++ src/prototypes/common.h | 56 + src/prototypes/cpu.h | 79 ++ src/prototypes/functions.h | 52 + src/prototypes/lua.h | 27 + src/prototypes/net.h | 43 + src/prototypes/options.h | 26 + src/prototypes/perl.h | 27 + src/prototypes/python.h | 36 + src/prototypes/ruby.h | 27 + src/prototypes/smart.h | 25 + src/prototypes/sound.h | 31 + src/prototypes/weather.h | 27 + src/python.c | 90 ++ src/ruby.c | 73 + src/smart.c | 208 +++ src/sound.c | 250 ++++ src/weather.c | 171 +++ 116 files changed, 13186 insertions(+), 264 deletions(-) delete mode 100644 LICENSE create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 doc/Makefile create mode 100644 doc/README.md create mode 100644 doc/man_template.pdc create mode 100644 doc/pinkybar.1 create mode 100644 doc/pinkybar.texi create mode 100644 extra/FreeBSD/Makefile create mode 100644 extra/FreeBSD/pkg-descr create mode 100644 extra/FreeBSD/scripts/post-extract create mode 100644 extra/FreeBSD/scripts/post-fetch create mode 100644 extra/FreeBSD/scripts/post-install create mode 100644 extra/Gentoo/app-admin/pinky-curses/pinky-curses-9999.ebuild create mode 100644 extra/Gentoo/app-admin/pinky/metadata.xml create mode 100644 extra/Gentoo/app-admin/pinky/pinky-bar-9999.ebuild create mode 100644 extra/bash_zsh/_pinkybar create mode 100644 extra/bash_zsh/pinkybar create mode 100644 extra/deprecated/Makefile.skel create mode 100644 extra/deprecated/README.md create mode 100644 extra/deprecated/bootstrap create mode 100644 extra/misc/openbsd_bugs.md create mode 100644 extra/misc/skdump.c create mode 100644 extra/mpd/README.md create mode 100644 extra/mpd/freebsd.conf create mode 100644 extra/mpd/linux.conf create mode 100644 extra/mpd/openbsd.conf create mode 100644 extra/ported_or_not_included/cpu_brand.S create mode 100644 extra/ported_or_not_included/cpu_cache.S create mode 100644 extra/ported_or_not_included/not_included.c create mode 100644 extra/scripts/drive-temperature.sh create mode 100644 extra/scripts/dwm.sh create mode 100644 extra/scripts/pinky-curses.sh create mode 100644 extra/scripts/pinky.lua create mode 100644 extra/scripts/pinky.pl create mode 100644 extra/scripts/pinky.py create mode 100644 extra/scripts/pinky.rb create mode 100644 extra/scripts/xmonad.sh create mode 100644 extra/xbm_icons/arch.xbm create mode 100644 extra/xbm_icons/bat.xbm create mode 100644 extra/xbm_icons/clock.xbm create mode 100644 extra/xbm_icons/cpu.xbm create mode 100644 extra/xbm_icons/diskette.xbm create mode 100644 extra/xbm_icons/fan.xbm create mode 100755 extra/xbm_icons/fox.xbm create mode 100644 extra/xbm_icons/mem.xbm create mode 100644 extra/xbm_icons/mobo.xbm create mode 100644 extra/xbm_icons/mpd.xbm create mode 100644 extra/xbm_icons/net.xbm create mode 100644 extra/xbm_icons/sm4tik-icon-pack.tar.bz2 create mode 100644 extra/xbm_icons/statio.xbm create mode 100644 extra/xbm_icons/temp.xbm create mode 100644 extra/xbm_icons/uptime.xbm create mode 100644 extra/xbm_icons/vol.xbm create mode 100644 extra/xbm_icons/voltage.xbm create mode 100644 img/cpu-temp.png create mode 100644 img/mobo-temp.png create mode 100644 img/pic.png create mode 100644 img/pic2.png create mode 100644 img/pic4.png create mode 100644 img/pic5.png create mode 100644 img/pic6.png create mode 100644 img/pic7.png create mode 100644 m4/1errs.m4 create mode 100644 m4/alsa.m4 create mode 100644 m4/ax_append_flag.m4 create mode 100644 m4/cflagz.m4 create mode 100644 m4/dvd.m4 create mode 100644 m4/extend.m4 create mode 100644 m4/mpd.m4 create mode 100644 m4/net.m4 create mode 100644 m4/sensors.m4 create mode 100644 m4/the_rest_funcs.m4 create mode 100644 m4/typez.m4 create mode 100644 m4/weather.m4 create mode 100644 m4/x11.m4 create mode 100644 set.pl create mode 100644 src/Makefail.skel create mode 100644 src/common.c create mode 100644 src/cpu.c create mode 100644 src/freebsd_functions.c create mode 100644 src/include/freebzd.h create mode 100644 src/include/functions_constants.h create mode 100644 src/include/headers.h create mode 100644 src/include/ncurses_colours.h create mode 100644 src/include/non_x11_colours.h create mode 100644 src/include/openbzd.h create mode 100644 src/include/options_constants.h create mode 100644 src/include/options_generator.h create mode 100644 src/include/x11_colours.h create mode 100644 src/linux_functions.c create mode 100644 src/lua.c create mode 100644 src/main.c create mode 100644 src/net.c create mode 100644 src/openbsd_functions.c create mode 100644 src/options.c create mode 100644 src/perl.c create mode 100644 src/prototypes/common.h create mode 100644 src/prototypes/cpu.h create mode 100644 src/prototypes/functions.h create mode 100644 src/prototypes/lua.h create mode 100644 src/prototypes/net.h create mode 100644 src/prototypes/options.h create mode 100644 src/prototypes/perl.h create mode 100644 src/prototypes/python.h create mode 100644 src/prototypes/ruby.h create mode 100644 src/prototypes/smart.h create mode 100644 src/prototypes/sound.h create mode 100644 src/prototypes/weather.h create mode 100644 src/python.c create mode 100644 src/ruby.c create mode 100644 src/smart.c create mode 100644 src/sound.c create mode 100644 src/weather.c diff --git a/.gitignore b/.gitignore index e7388b9..52847b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,43 @@ -# ---> C -# Object files +Makefil* +src/Makefil* +auto* +conf* +aclocal.m4 *.o -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ +*bar +temp_dir/ +src/.deps/ +.deps/ +*.in +*.in~ +*stam* +*.txt +src/pinky_curses +*.xz +*.pdc +*.pyo +__pycache__ +*.info + + + + + + + + + +!Makefile.am +src/Makefile.am + + + +!configure.ac +!Makefile.skel +!extra/FreeBSD/Makefile +!extra/bash_zsh/_pinkybar +!extra/bash_zsh/pinkybar +!doc/man_template.pdc +!extra/Gentoo/app-admin/pinky/* +!doc/Makefile diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 7083002..0000000 --- a/LICENSE +++ /dev/null @@ -1,231 +0,0 @@ -GNU GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -Preamble - -The GNU General Public License is a free, copyleft license for software and other kinds of works. - -The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - -To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - -The precise terms and conditions for copying, distribution and modification follow. - -TERMS AND CONDITIONS - -0. Definitions. - -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the Program. - -To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - -To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - -1. Source Code. -The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - -The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - -The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - -2. Basic Permissions. -All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - -You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. -No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - -4. Conveying Verbatim Copies. -You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. -You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - -a) The work must carry prominent notices stating that you modified it, and giving a relevant date. - -b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. - -c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - -d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - -A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - -6. Conveying Non-Source Forms. -You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - -a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. - -b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. - -c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. - -d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. - -e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - -The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - -Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - -7. Additional Terms. -“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - -Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - -a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or - -b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or - -c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or - -d) Limiting the use for publicity purposes of names of licensors or authors of the material; or - -e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or - -f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - -All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - -8. Termination. -You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - -9. Acceptance Not Required for Having Copies. -You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. -Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - -11. Patents. -A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - -12. No Surrender of Others' Freedom. -If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. -Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - -14. Revised Versions of this License. -The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - -Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - -15. Disclaimer of Warranty. -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. Limitation of Liability. -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. -If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. - - -Copyright (C) - -This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - - Copyright (C) -This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. - -You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . - -The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3b80e89 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = src + +dist_man_MANS = doc/pinkybar.1 + +# Optional, create and install +# the pinkybar info document +# info_TEXINFOS = doc/pinkybar.texi +# MAKEINFOFLAGS = --no-validate --no-warn --force + +# To satisfy make dist +EXTRA_DIST = \ + src/ncurses.c \ + bootstrap \ + README.md \ + .gitignore \ + m4 \ + doc \ + extra diff --git a/README.md b/README.md index 64d7d8f..ef394a3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,716 @@ -# pinky-bar +The code doesn't age, neither it has expiration date. +## Table of Contents + +- [Program Options](#program-options) +- [Configure Options](#gnu-build-system-configure-options) +- [Installation for dwm](#installation-for-dwm) +- [Installation for xmonad/other WM](#installation-for-xmonad-or-other-wm) +- [Installation in FreeBSD](#installation-in-freebsd) +- [Installation in OpenBSD](#installation-in-openbsd) +- [pinky curses installation](#pinky-curses-installation) +- [pinky urxvt](#pinky-urxvt) +- [Installation for anything else](#installation-for-anything-else) +- [Using configuration file](#using-configuration-file) +- [Linux Requirements](#linux-mandatory-requirements) +- [BSD Requirements](#bsd-mandatory-requirements) +- [Opt-in Requirements](#opt-in-requirements) +- [WM Requirements](#wm-specific-requirements) +- [Wish list](#wish-list) + +--- + +dwm + +![](img/pic.png) + +xmonad + +![](img/pic5.png) + +![](img/pic7.png) + +ncurses + +![](img/pic6.png) + +Gather some system information and show it in this statusbar program, not tied to any Window Manager, terminal multiplexer, etc. + +Please note that the program won't detect fans connected via molex connetor(s) or external fan controller. Also I have not tested it with fan splitter(s) either. + +The program is smart enough to detect whether some of your fan(s) blades are spinning, or the particular fan have been removed. Hold down some of your fan blades and you'll see that the program won't include this fan and it's RPM, release the blades and you'll see the fan and it's RPM in the statusbar. Try simulating real fan hardware failure by holding down all system fan blades and watch what the program will show you, just try not to slice your cheesy fingers open in the process. + +You can extend pinky-bar with your own crafted perl/python/ruby/lua script. + +If you compile your kernel from source code make sure to include your cpu and motherboard sensors as **modules** and not inlined. + +**Just an example if you use BSD - acpi/aibs, coretemp/amdtemp.** + +![](img/cpu-temp.png) + +![](img/mobo-temp.png) + +--- + +## Program options + +The order of supplied options will dictate how, where and what system information to be shown. + +| short option | long option | Descrtiption | +|--------------|-------------|--------------------------------------------------------------------| +| -M | --mpd | The song filename | +| -W | --mpdtrack | The song track name (not available in cmus) | +| -x | --mpdartist | The song artist(s) name(s) | +| -X | --mpdtitle | The song title | +| -y | --mpdalbum | The song album name | +| -Y | --mpddate | The song date | +| -c | --cpu | The current cpu load (summed up all cores/threads) | +| -L | --coresload | Show the load regarding each individual cpu core/thread | +| -T | --cputemp | The current cpu temperature | +| -C | --cpuspeed | Show your maximum cpu clock speed in MHz, regardless of the used governor. Uses assembly. | +| -I | --cpuinfo | Detect your CPU vendor, stepping, family, clflush, l1/l2 cache and line size, physical cores, physical and virtual bits. Uses assembly. | +| -r | --ramperc | The used ram in percentage | +| -J | --ramtotal | The total ram | +| -K | --ramfree | The free ram | +| -l | --ramshared | The shared ram | +| -o | --rambuffer | The buffer ram (not available in OpenBSD) | +| -s | --driveperc | The used drive storage in percentage | +| -n | --drivetotal| The total drive storage | +| -N | --drivefree | The free drive storage | +| -O | --driveavail| The available drive storage (total - used) | +| | --drivetemp | Read the drive temperature from S.M.A.R.T | +| -g | --battery | The remaining battery charge | +| -z | --dvdstr | The vendor and model name of your cdrom/dvdrom | +| -S | --statio | Read and written MBs to the drive so far [argument - sda] | +| -p | --packages | The number of installed packages | +| -P | --kernsys | The kernel name | +| | --kernode | The network node hostname | +| -Q | --kernrel | The kernel release | +| -R | --kernver | The kernel version | +| -u | --kernarch | The machine architecture | +| -k | --kernel | Combined kernel name and version | +| | --perl | Extend pinkybar with your scripts written in perl, learn more from the Opt-in section. | +| | --python | Extend pinkybar with your scripts written in python, learn more from the Opt-in section. | +| | --ruby | Extend pinkybar with your scripts written in ruby, learn more from the Opt-in section. | +| | --lua | Extend pinkybar with your scripts written in lua, learn more from the Opt-in section. | +| -q | --weather | Show the temperature outside [argument - London,uk] | +| -U | --uptime | The system uptime | +| -w | --loadavg | The system average load for past 1, 5 and 15 minutes | +| -v | --voltage | The system voltage | +| -f | --fans | All system fans and their speed in RPM | +| -m | --mobo | Show the motherboard name and vendor | +| -d | --mobotemp | The motherboard temperature | +| -V | --volume | The sound volume level | +| -t | --time | The current time | +| -a | --ipaddr | The local ip address [argument - eth0] | +| -b | --bandwidth | The consumed internet bandwidth so far [argument - eth0] | +| -i | --iface | The current download and upload speed [argument - eth0] | +| -A | --ipmac | The NIC mac address [argument - eth0] | +| -B | --ipmask | The NIC subnet mask [argument - eth0] | +| -D | --ipcast | The NIC broadcast address [argument - eth0] | +| -E | --iplookup | Mini website IP lookup [website argument - google.com] | + +Be aware of the options that mention **Uses assembly** are tested only on AMD and Intel CPUs (starting from pentium 4 onwards). + +The following options are available only in Linux: + +| short option | long option | Descrtiption | +|--------------|-------------|--------------------------------------------------------------------| +| -F | --drivemodel| The vendor name of your drive [argument - sda] | +| -G | --nicinfo | The NIC vendor and model [argument - eth0] | +| | --nicdrv | The NIC driver [argument - eth0] | +| -H | --nicver | The NIC version [argument - eth0] | +| -e | --iplink | The NIC link speed (useful for wireless/wifi) [argument - eth0] | +| -j | --nicfw | The NIC firmware [argument - eth0] | +| -h | --wifiname | The name of currently connected wifi/wireless network [argument - wlan0] | + +The following options are available only to FreeBSD and OpenBSD: + +| short option | long option | Descrtiption | +|--------------|-------------|--------------------------------------------------------------------| +| -j | --nicgw | The NIC gateway address [argument - re0] | +| -Z | --swapused | The used drive swap in MB | +| -F | --swaperc | The used drive swap in percentage | +| -h | --swaptotal | The total drive swap | +| -H | --swapavail | The available drive swap (total - used) | + +The following options are available only in OpenBSD: + +| short option | long option | Descrtiption | +|--------------|-------------|--------------------------------------------------------------------| +| -l | --ramused | The used ram in MB | + +--- + +## GNU Build System (configure) options + +Before the source code is passed to the compiler, you can enable/disable the following **configure** options +that will increase/reduce the number of dependencies required to compile the program. + +It's up to you to decide which features suit you best. + +| To include | Not to include | Descrtiption | +|----------------|---------------------|--------------------------------------------------------------------------------------------| +| --with-x11 | --without-x11 | Enable it if you are using dwm. | +| --with-alsa | --without-alsa | To get the sound volume level. | +| --with-oss | --without-oss | To get the sound volume level in \*BSD. | +| --with-net | --without-net | Enable the internet related options. | +| --with-libnl | --without-libnl | Enable the wifi related options regarding chipsets supporting the cfg80211/mac80211 modules (linux only). | +| --with-pci | --without-pci | To get the NIC vendor and model in linux | +| --with-dvd | --without-dvd | To get the cdrom/dvdrom vendor and model | +| --with-sensors | --without-sensors | Alternative way to get data from the sensors (linux only) | +| --with-apm | --without-apm | APM power and resource management for laptops (FreeBSD only) | +| --with-ncurses | --without-ncurses | Output the data to the terminal using the ncurses library, can be colorized | +| --with-perl | --without-perl | Extend pinkybar with your own crafted scripts written in perl | +| --with-lua | --without-lua | Extend pinkybar with your own crafted scripts written in lua | +| --with-ruby | --without-ruby | Extend pinkybar with your own crafted scripts written in ruby | +| --with-python2 | --without-python2 | Extend pinkybar with your own crafted scripts written in python2 | +| --with-python3 | --without-python3 | Extend pinkybar with your own crafted scripts written in python3 | +| --with-weather | --without-weather | The temperature outside (some details must be provided) | +| api\_key='123458976' | | API key obtained after registering yourself in the weather website, must be combined **--with-weather** | +| --with-smartemp | --without-smartemp | Read the drive temperature from S.M.A.R.T cross-platform available | +| --with-drivetemp | --without-drivetemp | Read the drive temperature from S.M.A.R.T (linux only) uses curl | +| --with-drivetemp-light | --without-drivetemp-light | Read the drive temperature from S.M.A.R.T (linux only) light version | +| drive\_port='1234' | | Different TCP port to listen to for the drive temperature, default one is 7634, must be combined **--with-drivetemp** or **--with-drivetemp-light** | +| --with-colours | --without-colours | Colorize the output data. | +| icons=/tmp | | xbm icons that can be used by dzen2 for example. Discarded when **--with-x11** is used | +| --with-mpd | --without-mpd | To see the currently played song name (if any). | +| --prefix=/tmp | | The directory where the program will be installed | +| mobo\_sensor='dev.aibs.0' | | FreeBSD motherboard sensor module name to use in the sysctl calls. Read the FreeBSD installation below | +| cpu\_sensor='dev.cpu.0.temperature' | | FreeBSD cpu temperature module name to use in the sysctl calls . Read the FreeBSD installation below | + +By default, if **no** options are passed, the program will be compiled with: + +```bash +--with-net --with-pci +``` + +Affects only FreeBSD users with laptops, **--without-apm** will compile the program with acpi support to obtain the current battery life. + +**--without-mpd** will compile the program with cmus support, the options syntax stays as is. + +The pci and sensors configure options will be discarded in \*BSD. + +Affects only linux users with wifi/wireless chipsets, run `lsmod|grep 802` and see whether your chipset uses cfg80211/mac80211. If that's so you can rely on libnl and enable **--with-libnl** configure options, otherwise your chipset probably still uses we/wext, so type **--without-libnl**. + +Affects only linux users, **--with-drivetemp** pretty much locks you down to hddtemp. You can adjust **extra/scripts/drive-temperature.sh** and compile the program **--with-smartemp**, so you can switch between hddtemp and smartmontools at any time without the need recompile pinkybar with different options. **--with-smartemp** only cares for the existance of /tmp/pinkytemp file. + +**--with-weather** is using [this url](http://openweathermap.org/current), register yourself there, create a new [API key](https://home.openweathermap.org/api\_keys). + +Don't just rush to register yourself, read carefully what the "Free" account limits are and take in account how often the program should call their api service. I'm not responsible if you exceeded the limits, you've been warned. + +```bash +# Make sure it's working first +# curl 'http://api.openweathermap.org/data/2.5/weather?q=London,uk&units=metric&APPID=28459ae16e4b3a7e5628ff21f4907b6f' + +# what to pass to configure +--with-weather api_key='28459ae16e4b3a7e5628ff21f4907b6f' +``` + +--- + +## Installation for dwm + +```bash +perl set.pl "distro" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --with-x11 +make +make install +``` + +Copy the code from extra/scripts/dwm.sh or `exec` it from **xinitrc** or the script used to start dwm. + +## Installation for xmonad (or other WM) + +```bash +# Copy the xbm icons +mkdir -p --mode=700 $HOME/.xmonad/icons +cp -r extra/xbm_icons/*.xbm $HOME/.xmonad/icons + +perl set.pl "distro" +autoreconf --install --force + +# disable X11, point the location to the icons +./configure --prefix=$HOME/.cache --without-x11 icons=$HOME/.xmonad/icons + +# compile 'n install +make +make install +``` + +Copy the code from extra/scripts/xmonad.sh or `exec` it from **xinitrc** or the script used to start xmonad. + +## Installation in FreeBSD + +FreeBSD has no other way than using the module specific convention to query sysctl and obtain data from the sensors. Maintaining a list with all the possible module names and performing expensive sysctl calls in a loop to determine that X module is loaded into your system is no-go. Be prepared to spend a minute or two to find out some system information. + +Determine the motherboard sensor module name. + +```bash +sysctl -a|grep 'aibs' + +dev.aibs.0.volt.0: 1356 850 1600 +dev.aibs.0.volt.1: 3344 2970 3630 +dev.aibs.0.volt.2: 5040 4500 5500 +dev.aibs.0.volt.3: 12278 10200 13800 +dev.aibs.0.temp.0: 39.0C 60.0C 95.0C +dev.aibs.0.temp.1: 38.0C 45.0C 75.0C +dev.aibs.0.fan.0: 1053 600 7200 +dev.aibs.0.fan.1: 1053 600 7200 +``` + +Copy only 'dev.MODULE.NUMBER' (if there is any number at all) and paste it into the **mobo\_sensor** option below. + +Do the same for your cpu temperature, copy and paste the variable as is. **dev.cpu.0.temperature** below is provied as example. + +```bash +perl set.pl "freebsd" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --with-x11 --without-alsa --with-oss mobo_sensor='dev.aibs.0' cpu_sensor='dev.cpu.0.temperature' +make +make install +``` + +Send a request to the FreeBSD mailing list and request the OpenBSD sensors API to be ported. + +## Installation in OpenBSD + +Before proceeding, you'll have to: + +```bash +# To detect the newer compiler that you are +# about to install +sed -i 's/#AC_PROG_CC(/AC_PROG_CC(/g' configure.ac + +ls /usr/local/bin/automake-* +ls /usr/local/bin/autoconf-* + +# Then replace the numbers below +export AUTOCONF_VERSION=2.69 +export AUTOMAKE_VERSION=1.15 + +# Your call, gcc or llvm ? +pkg_add gcc + +# after that: +perl set.pl "openbsd" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --without-alsa --with-oss +make +make install +``` + +## pinky curses installation + +Step one, compile pinky-bar **--with-ncurses**, so the output to be formated in a way that pinky-curses can parse and colorize. + +```bash +perl set.pl "distro" +autoreconf --install --force + +# disable X11, enable the colours and ncurses opts. +./configure --prefix=$HOME/.cache --without-x11 --with-alsa --with-colours --with-ncurses + +# compile 'n install +make +make install +``` + +Step two, compile and install pinky-curses - https://notabug.org/void0/pinky-curses + +Copy the code from extra/scripts/pinky-curses.sh + +## pinky urxvt + +What a coincidence, pinky-urxvt is my 3rd urxvt extension and 3rd member of the pinky family. + +The sole purpose of this urxvt extension is to make it easy for you to keep track of things that you are interested to monitor while hacking your way something in the terminal. + +Link - https://notabug.org/void0/pinky-urxvt + +![](https://notabug.org/void0/pinky-urxvt/raw/master/2.png) + +pinky-urxvt, and pinky-curses are not tied to pinky-bar. + +## Installation for anything else + +pinky-bar is no longer tied to Window Managers only. With the addition of "without colours", the output can be shown in any program, just bear in mind that the more options you've supplied the more system information will be shown. + +The tmux status bar in action: + +![](img/pic4.png) + +The installation steps: + +```bash +perl set.pl "distro" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --without-x11 --without-colours +make +make install +``` + +By choosing this 3rd installation method it is up to you where, how to start and use the system information that's produced by pinky-bar. + +--- + +Replace **distro** with archlinux, debian, gentoo, slackware, rhel, frugalware, angstrom. Here's some short distros list of some popular distros that are based on another one: + +- [x] archlinux based distros: parabola, chakra, manjaro +- [x] debian based distros: ubuntu, linux mint, trisquel, back track, kali linux, peppermint linux, solusos, crunchbang, deepin, elementary os, and the rest \*buntu based distros +- [x] gentoo based distros: funtoo, sabayon, calculate linux +- [x] slackware +- [x] rhel based distros: opensuse (uses rpm), fedora, fuduntu, mandriva, mandrake, viperr, mageia +- [x] frugalware +- [x] angstrom + +Cannot list the \*BSD flavours as "distros", so they deserve own options: + +- [x] freebsd +- [x] openbsd + +--- + +## Using configuration file + +**~/.pinky** is the location of the configuration file. It uses the same short and long command line options. + +I do advise you to use the long options syntax. + +If any option depends on argument, don't put any space between the option and the argument. + +Use one option per line. Contrary to your shell, the "parser" won't expand ~/my\_script.pl to point to /home/sweethome/my\_script.pl + +```bash +--weather=London,uk +--coresload +--cputemp +--ramperc +--driveperc +--packages +--kernel +--voltage +--fans +--mobo +--mobotemp +--perl=/home/sweethome/my_script.pl +``` + +Execute the program without supplying any command line options and it will parse the configuration file. + +--- + +## Linux Mandatory requirements + +* gcc/clang +* glibc +* autoconf +* automake +* m4 +* gawk +* perl + +## \*BSD Mandatory requirements + +* gcc/clang +* autoconf +* automake +* autoconf-wrapper +* automake-wrapper +* autoconf-archive +* argp-standalone +* libtool +* m4 +* gawk +* perl + +Some llvm and gcc versions will not check for headers and libraries in /usr/local, if that's the case for you, you should export the following environment variables: + +```bash +export LDFLAGS='-L/usr/local/lib' +export CFLAGS='-I/usr/local/include' +``` + +After editing the wrong prototype I managed to stumble upon a bug in OpenBSD's own libc. + +**Warning !!! OpenBSD users !!!** + +The majority of SCN\* macros differs from their PRI\* cousins. And I cannot guarantee the accuracy of fixed width integers when OpenBSD own libc managed to use different format specifiers. Read extra/misc/openbsd\_bugs.md for more details. + +## Opt-in requirements + +Linux camp: + +The internet related options rely on headers provided iproute2. +By default the program will try to compile with those headers included. +If for any reason you would like to compile the program without internet related options, then pass **--without-net** to configure. + +* iproute2 + +wifi/wireless chipsets supporting mac80211/cfg80211: + +* libnl (>= 3.0) +* pkg-config + +In Gentoo there are two versions of pkg-config. The first one is named dev-util/pkgconfig and the second one is dev-ruby/pkg-config. In order to use the first one, you'll have to export the pkg-config path to the following environment variable: + +```bash +export PKG_CONFIG_PATH=/usr/bin/pkg-config +``` + +Then pass **--with-libnl** to configure. + +To get the NIC vendor and model names: + +* pciutils + +Alternative way to obtain data from the sensors: + +* lm\_sensors + +To read the drive temperature from S.M.A.R.T **--with-drivetemp**: + +* hddtemp +* curl + +To read the drive temperature from S.M.A.R.T **--with-drivetemp-light**: + +* hddtemp + +The "light" version does not rely on curl, and will not force -O0 CFLAGS. + +```bash +# --with-drivetemp-light +0.00s user 0.00s system 15% cpu 0.006 + +# --with-drivetemp +0.01s user 0.00s system 72% cpu 0.008 +``` + +Try running hddtemp to see if it detects your drive, depending if it has temperature sensor in first place: + +```bash +sudo hddtemp /dev/sda + +WARNING: Drive /dev/sda doesn't appear in the database of supported drives +WARNING: But using a common value, it reports something. +WARNING: Note that the temperature shown could be wrong. +WARNING: See --help, --debug and --drivebase options. +WARNING: And don't forget you can add your drive to hddtemp.db +/dev/sda: Corsair Force GT: 23°C or °F +``` + +The message is pretty clear "don't forget to add your drive to hddtemp.db", first run the debug command to see which field is responsible to report your drive temperature, it should be in the range of 190 - 200: + +```bash +# Copy the Model: line + +sudo hddtemp --debug /dev/sda + +================= hddtemp 0.3-beta15 ================== +Model: Corsair Force GT + +field(1) = 0 +field(5) = 0 +field(9) = 253 +field(12) = 237 +field(171) = 0 +field(172) = 0 +field(174) = 147 +field(177) = 1 +field(181) = 0 +field(182) = 0 +field(187) = 0 +field(194) = 22 +field(195) = 0 +field(196) = 0 +field(201) = 0 +field(204) = 0 +field(230) = 100 +field(231) = 0 +field(233) = 130 +field(234) = 216 +field(241) = 216 +field(242) = 151 +``` + +Open up **/usr/share/hddtemp/hddtemp.db** and append the Model: line that you copied earlier with the correct field that reports your drive temperature. + +```bash +"Corsair Force GT" 194 C "Corsair Force GT 120GB SSD" +``` + +Next run hddtemp in daemon mode so we can request the temperature back: + +```bash +sudo hddtemp -d /dev/sda +``` + +Open up your browser and navigate to 127.0.0.1:7634 and you'll get instant temperature report back to you. + +The "init" lock-in for those of you that cannot choose between udev or eudev puts me in position not rely on libatasmart, regardless how neat the library is. There is stripped example program in extra/misc/skdump.c if you are curious to check and test libatasmart. + +Linux camp end. + +To read the drive temperature from S.M.A.R.T **--with-smartemp**: + +* smartmontools + +smartmontools are not mandatory in OpenBSD, `atactl` does the same job. + +Execute the following command as root `visudo` and append: + +```bash +# 'frost' is my computer username +frost ALL=NOPASSWD:/usr/sbin/smartctl +``` + +Copy the code from extra/scripts/drive-temperature.sh or `exec` it from **xinitrc** or the script used to start your DE/WM. + +To extend pinkybar with your own crafted perl/python/ruby/lua script: + +* perl +* python == 2.7 (--with-python2) +* python >= 3.3 (--with-python3) +* lua >= 5.1 +* ruby >= 2.0 and pkg-config + +Have a look at extra/scripts/pinky.{py,pl,ruby,lua}, they serve as examples how to write the most basic scripts in order to extend pinkybar in python/perl/ruby/lua. You can use the 3 languages simultaneously. + +Please, please do **NOT** export or set PYTHONPATH on it's own line. + +`WRONG`: + +```bash +export PYTHONPATH=/meh +pinkybar --python my_script +``` + +`WRONG`: + +```bash +PYTHONPATH=/meh +pinkybar --python my_script +``` + +Correct PYTHONPATH usage: + +```bash +# ~/chewbacca is the path where pinky.py resides +# ~/chewbacca/pinky.py + +# python2 +PYTHONPATH=~/chewbacca ~/pinkybar --python pinky + +# python3 +# executed only once +fuNky=$(python3 -c 'import sys;print(":".join([x for x in sys.path]))') + +# executed in a loop +PYTHONPATH=$fuNky:~/chewbacca ~/pinkybar --python pinky +``` + +**--with-perl**: + +```bash +~/pinkybar --perl ~/chewbacca/pinky.pl +``` + +**--with-ruby**: + +```bash +~/pinkybar --ruby ~/chewbacca/pinky.rb +``` + +**--with-lua**: + +Non byte-compiled script: + +```bash +~/pinkybar --lua ~/chewbacca/pinky.lua +``` + +Once done editing your script, you can byte-compile it: + +```bash +luac -o pinky.luac pinky.lua +~/pinkybar --lua ~/chewbacca/pinky.luac # <-- .luac and not .lua +``` + +To get the sound volume level: + +* alsa-utils +* alsa-lib + +Then pass **--with-alsa** to configure. + +\*BSD users can use the baked OSS instead, pass **--without-alsa --with-oss** to configure instead. + +To output the data to the terminal using the ncurses library: + +* ncurses + +To get the vendor and model name of your cdrom/dvdrom/blu-ray: + +* libcdio +* libcddb + +In linux **--without-dvd** will still compile the program with dvd support. Except it will be limited only to dvd support, it will try to parse the sr0 vendor and model name detected by the kernel. + +The weather related options, please go back and read **Don't just rush to register yourself**: + +* curl +* gzip + +**Warning, I'm not responsible for any lawsuit towards you, neither encourage you to pirate content that is not licensed as free and/or for fair use.** + +To see the currently played song name **--with-mpd**: + + Server side: + + * mpd (can be build with soundcloud support) + + Client side: + + * libmpdclient + * mpc/ncmpc/ncmpcpp, [and the rest](http://mpd.wikia.com/wiki/Clients) + +To see the currently played song name **--without-mpd**: + +* cmus + +The "soundcloud" alternative that is supported in cmus and your mpd client will be to download **.m3u/.pls** files according to the [radio stream station](https://www.internet-radio.com) that you are interested to listen. + +The FreeBSD users will notice that "mpd" is named "musicpd". + +If you've never used mpd before copy the example configuration from extra/mpd according to your OS. + +Keep an eye on the **log file size** if you are using raspberry pi (or equivalent device) that streams the music, make sure that it's deleted automatically if it exceeds some pre-defined size. + +--- + +## WM specific requirements + +If you would like the output to be shown in your Window Manager, those are the following requirements: + +for non-dwm WM: + +* dzen2 + +for dwm: + +* libx11 +* xorg-server + +use **--without-colours** to skip the following step: + +* dwm compiled with statuscolor patch. The colours in use are specified in your dwm config.h + +## Wish list + +It would be great if I had \*BSD compatible usb wifi dongle or wireless pci adapter to add wifi options in pinky-bar. diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f77af77 --- /dev/null +++ b/configure.ac @@ -0,0 +1,54 @@ +# This file is processed by autoconf to create a configure script +AC_INIT([pinkybar], [1.0.0]) +AC_CONFIG_AUX_DIR([temp_dir]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([src/config.h]) +# -Werror -Wportability +AM_INIT_AUTOMAKE([1.13 -Wall no-define foreign subdir-objects dist-xz no-dist-gzip std-options]) + +AM_SILENT_RULES([yes]) +{perl will replace this line} + +# With the addition of more runtime compile and +# link tests, this option is no longer necessary. +# Any compiler and C library succeeding to pass the +# tests will be able to compile and run the +# program flawlessly. +# If you use OpenBSD uncomment the AC_PROG_CC([]) +# line below. Make sure that you have the latest gcc/llvm +# AC_PROG_CC([egcc clang llvm-gcc gcc]) + +AC_PROG_CC_C99 +AC_C_CONST +AC_HEADER_STDC +AM_PROG_CC_C_O + +# AM_EXTRA_RECURSIVE_TARGETS([ncurses]) + +# The linker flags tests in m4 dir +TEST_SOME_FUNCS +TEST_NET +TEST_PCI +TEST_X11 +TEST_ALSA +TEST_MPD +TEST_DVD +TEST_SENSORS +TEST_TYPEZ +TEST_WEATHER +TEST_PERL +TEST_PYTHON +TEST_LUA +TEST_RUBY +TEST_CFLAGZ + +AC_CONFIG_FILES([ + Makefile + src/Makefile +]) + +AC_OUTPUT + +echo +echo 'Now type \"make\" and \"make install\" afterwards' +echo diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..15a9ea8 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,33 @@ +# 10/29/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +define pandora_snap + -sed -e '15r ../README.md' 'man_template.pdc' | \ + sed -e '15,50d' | pandoc -s -S $(1) - -o pinkybar.$(2) +endef + +man: + $(call pandora_snap,-f markdown -t man,1) + +info: pinkybar.info + +pinkybar.info: + $(call pandora_snap, ,texi) + -sed -i '2i @setfilename pinkybar.info' pinkybar.texi + $(MAKEINFO) --no-validate --no-warn --force pinkybar.texi + +.PHONY: man info pinkybar.info diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..b47f119 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,9 @@ +To re-create the man page and info document you'll have to install the whole pandoc suite, texinfo, gmake, gsed (replace sed with gsed on \*BSD), then invoke: + +```bash +make man info +``` + +--- + +Open up Makefile and delete the PHONY line. Execute `touch man`, followed by `make man`, bring back the PHONY line and execute `make man`. diff --git a/doc/man_template.pdc b/doc/man_template.pdc new file mode 100644 index 0000000..92578db --- /dev/null +++ b/doc/man_template.pdc @@ -0,0 +1,23 @@ +% pinkybar(1) manual +% Aaron Caffrey +% Oktoberfest 23, 2016 + +# NAME +This man page is converted from markdown, and some information might not look good and/or have been stripped during the automated process. + +# SYNOPSIS +pinkybar [*option*] + +# DESCRIPTION + + + + + + +# REPORTING BUGS +Report bugs to https://gitlab.com/void0/pinky-bar + +# COPYRIGHT +Copyright (c) 2016 Aaron Caffrey \ +Free use of this software is granted under the terms of the GNU General Public License (GPL). diff --git a/doc/pinkybar.1 b/doc/pinkybar.1 new file mode 100644 index 0000000..9886996 --- /dev/null +++ b/doc/pinkybar.1 @@ -0,0 +1,1490 @@ +.\"t +.TH "pinkybar" "1" "Oktoberfest 23, 2016" "manual" "" +.SH NAME +.PP +This man page is converted from markdown, and some information might not +look good and/or have been stripped during the automated process. +.SH SYNOPSIS +.PP +pinkybar [\f[I]option\f[]] +.SH DESCRIPTION +.PP +Gather some system information and show it in this statusbar program, +not tied to any Window Manager, terminal multiplexer, etc. +.PP +Please note that the program won't detect fans connected via molex +connetor(s) or external fan controller. +Also I have not tested it with fan splitter(s) either. +.PP +The program is smart enough to detect whether some of your fan(s) blades +are spinning, or the particular fan have been removed. +Hold down some of your fan blades and you'll see that the program won't +include this fan and it's RPM, release the blades and you'll see the fan +and it's RPM in the statusbar. +Try simulating real fan hardware failure by holding down all system fan +blades and watch what the program will show you, just try not to slice +your cheesy fingers open in the process. +.PP +You can extend pinky\-bar with your own crafted perl/python/ruby/lua +script. +.PP +If you compile your kernel from source code make sure to include your +cpu and motherboard sensors as \f[B]modules\f[] and not inlined. +.PP +\f[B]Just an example if you use BSD \- acpi/aibs, coretemp/amdtemp.\f[] +.PP +[IMAGE: image (img/cpu-temp.png)] +.PP +[IMAGE: image (img/mobo-temp.png)] +.PP + * * * * * +.SS Program options +.PP +The order of supplied options will dictate how, where and what system +information to be shown. +.PP +.TS +tab(@); +l l l. +T{ +short option +T}@T{ +long option +T}@T{ +Descrtiption +T} +_ +T{ +\-M +T}@T{ +\[en]mpd +T}@T{ +The song filename +T} +T{ +\-W +T}@T{ +\[en]mpdtrack +T}@T{ +The song track name (not available in cmus) +T} +T{ +\-x +T}@T{ +\[en]mpdartist +T}@T{ +The song artist(s) name(s) +T} +T{ +\-X +T}@T{ +\[en]mpdtitle +T}@T{ +The song title +T} +T{ +\-y +T}@T{ +\[en]mpdalbum +T}@T{ +The song album name +T} +T{ +\-Y +T}@T{ +\[en]mpddate +T}@T{ +The song date +T} +T{ +\-c +T}@T{ +\[en]cpu +T}@T{ +The current cpu load (summed up all cores/threads) +T} +T{ +\-L +T}@T{ +\[en]coresload +T}@T{ +Show the load regarding each individual cpu core/thread +T} +T{ +\-T +T}@T{ +\[en]cputemp +T}@T{ +The current cpu temperature +T} +T{ +\-C +T}@T{ +\[en]cpuspeed +T}@T{ +Show your maximum cpu clock speed in MHz, regardless of the used +governor. +Uses assembly. +T} +T{ +\-I +T}@T{ +\[en]cpuinfo +T}@T{ +Detect your CPU vendor, stepping, family, clflush, l1/l2 cache and line +size, physical cores, physical and virtual bits. +Uses assembly. +T} +T{ +\-r +T}@T{ +\[en]ramperc +T}@T{ +The used ram in percentage +T} +T{ +\-J +T}@T{ +\[en]ramtotal +T}@T{ +The total ram +T} +T{ +\-K +T}@T{ +\[en]ramfree +T}@T{ +The free ram +T} +T{ +\-l +T}@T{ +\[en]ramshared +T}@T{ +The shared ram +T} +T{ +\-o +T}@T{ +\[en]rambuffer +T}@T{ +The buffer ram (not available in OpenBSD) +T} +T{ +\-s +T}@T{ +\[en]driveperc +T}@T{ +The used drive storage in percentage +T} +T{ +\-n +T}@T{ +\[en]drivetotal +T}@T{ +The total drive storage +T} +T{ +\-N +T}@T{ +\[en]drivefree +T}@T{ +The free drive storage +T} +T{ +\-O +T}@T{ +\[en]driveavail +T}@T{ +The available drive storage (total \- used) +T} +T{ +T}@T{ +\[en]drivetemp +T}@T{ +Read the drive temperature from S.M.A.R.T +T} +T{ +\-g +T}@T{ +\[en]battery +T}@T{ +The remaining battery charge +T} +T{ +\-z +T}@T{ +\[en]dvdstr +T}@T{ +The vendor and model name of your cdrom/dvdrom +T} +T{ +\-S +T}@T{ +\[en]statio +T}@T{ +Read and written MBs to the drive so far [argument \- sda] +T} +T{ +\-p +T}@T{ +\[en]packages +T}@T{ +The number of installed packages +T} +T{ +\-P +T}@T{ +\[en]kernsys +T}@T{ +The kernel name +T} +T{ +T}@T{ +\[en]kernode +T}@T{ +The network node hostname +T} +T{ +\-Q +T}@T{ +\[en]kernrel +T}@T{ +The kernel release +T} +T{ +\-R +T}@T{ +\[en]kernver +T}@T{ +The kernel version +T} +T{ +\-u +T}@T{ +\[en]kernarch +T}@T{ +The machine architecture +T} +T{ +\-k +T}@T{ +\[en]kernel +T}@T{ +Combined kernel name and version +T} +T{ +T}@T{ +\[en]perl +T}@T{ +Extend pinkybar with your scripts written in perl, learn more from the +Opt\-in section. +T} +T{ +T}@T{ +\[en]python +T}@T{ +Extend pinkybar with your scripts written in python, learn more from the +Opt\-in section. +T} +T{ +T}@T{ +\[en]ruby +T}@T{ +Extend pinkybar with your scripts written in ruby, learn more from the +Opt\-in section. +T} +T{ +T}@T{ +\[en]lua +T}@T{ +Extend pinkybar with your scripts written in lua, learn more from the +Opt\-in section. +T} +T{ +\-q +T}@T{ +\[en]weather +T}@T{ +Show the temperature outside [argument \- London,uk] +T} +T{ +\-U +T}@T{ +\[en]uptime +T}@T{ +The system uptime +T} +T{ +\-w +T}@T{ +\[en]loadavg +T}@T{ +The system average load for past 1, 5 and 15 minutes +T} +T{ +\-v +T}@T{ +\[en]voltage +T}@T{ +The system voltage +T} +T{ +\-f +T}@T{ +\[en]fans +T}@T{ +All system fans and their speed in RPM +T} +T{ +\-m +T}@T{ +\[en]mobo +T}@T{ +Show the motherboard name and vendor +T} +T{ +\-d +T}@T{ +\[en]mobotemp +T}@T{ +The motherboard temperature +T} +T{ +\-V +T}@T{ +\[en]volume +T}@T{ +The sound volume level +T} +T{ +\-t +T}@T{ +\[en]time +T}@T{ +The current time +T} +T{ +\-a +T}@T{ +\[en]ipaddr +T}@T{ +The local ip address [argument \- eth0] +T} +T{ +\-b +T}@T{ +\[en]bandwidth +T}@T{ +The consumed internet bandwidth so far [argument \- eth0] +T} +T{ +\-i +T}@T{ +\[en]iface +T}@T{ +The current download and upload speed [argument \- eth0] +T} +T{ +\-A +T}@T{ +\[en]ipmac +T}@T{ +The NIC mac address [argument \- eth0] +T} +T{ +\-B +T}@T{ +\[en]ipmask +T}@T{ +The NIC subnet mask [argument \- eth0] +T} +T{ +\-D +T}@T{ +\[en]ipcast +T}@T{ +The NIC broadcast address [argument \- eth0] +T} +T{ +\-E +T}@T{ +\[en]iplookup +T}@T{ +Mini website IP lookup [website argument \- google.com] +T} +.TE +.PP +Be aware of the options that mention \f[B]Uses assembly\f[] are tested +only on AMD and Intel CPUs (starting from pentium 4 onwards). +.PP +The following options are available only in Linux: +.PP +.TS +tab(@); +l l l. +T{ +short option +T}@T{ +long option +T}@T{ +Descrtiption +T} +_ +T{ +\-F +T}@T{ +\[en]drivemodel +T}@T{ +The vendor name of your drive [argument \- sda] +T} +T{ +\-G +T}@T{ +\[en]nicinfo +T}@T{ +The NIC vendor and model [argument \- eth0] +T} +T{ +T}@T{ +\[en]nicdrv +T}@T{ +The NIC driver [argument \- eth0] +T} +T{ +\-H +T}@T{ +\[en]nicver +T}@T{ +The NIC version [argument \- eth0] +T} +T{ +\-e +T}@T{ +\[en]iplink +T}@T{ +The NIC link speed (useful for wireless/wifi) [argument \- eth0] +T} +T{ +\-j +T}@T{ +\[en]nicfw +T}@T{ +The NIC firmware [argument \- eth0] +T} +T{ +\-h +T}@T{ +\[en]wifiname +T}@T{ +The name of currently connected wifi/wireless network [argument \- +wlan0] +T} +.TE +.PP +The following options are available only to FreeBSD and OpenBSD: +.PP +.TS +tab(@); +l l l. +T{ +short option +T}@T{ +long option +T}@T{ +Descrtiption +T} +_ +T{ +\-j +T}@T{ +\[en]nicgw +T}@T{ +The NIC gateway address [argument \- re0] +T} +T{ +\-Z +T}@T{ +\[en]swapused +T}@T{ +The used drive swap in MB +T} +T{ +\-F +T}@T{ +\[en]swaperc +T}@T{ +The used drive swap in percentage +T} +T{ +\-h +T}@T{ +\[en]swaptotal +T}@T{ +The total drive swap +T} +T{ +\-H +T}@T{ +\[en]swapavail +T}@T{ +The available drive swap (total \- used) +T} +.TE +.PP +The following options are available only in OpenBSD: +.PP +.TS +tab(@); +l l l. +T{ +short option +T}@T{ +long option +T}@T{ +Descrtiption +T} +_ +T{ +\-l +T}@T{ +\[en]ramused +T}@T{ +The used ram in MB +T} +.TE +.PP + * * * * * +.SS GNU Build System (configure) options +.PP +Before the source code is passed to the compiler, you can enable/disable +the following \f[B]configure\f[] options that will increase/reduce the +number of dependencies required to compile the program. +.PP +It's up to you to decide which features suit you best. +.PP +.TS +tab(@); +l l l. +T{ +To include +T}@T{ +Not to include +T}@T{ +Descrtiption +T} +_ +T{ +\[en]with\-x11 +T}@T{ +\[en]without\-x11 +T}@T{ +Enable it if you are using dwm. +T} +T{ +\[en]with\-alsa +T}@T{ +\[en]without\-alsa +T}@T{ +To get the sound volume level. +T} +T{ +\[en]with\-oss +T}@T{ +\[en]without\-oss +T}@T{ +To get the sound volume level in *BSD. +T} +T{ +\[en]with\-net +T}@T{ +\[en]without\-net +T}@T{ +Enable the internet related options. +T} +T{ +\[en]with\-libnl +T}@T{ +\[en]without\-libnl +T}@T{ +Enable the wifi related options regarding chipsets supporting the +cfg80211/mac80211 modules (linux only). +T} +T{ +\[en]with\-pci +T}@T{ +\[en]without\-pci +T}@T{ +To get the NIC vendor and model in linux +T} +T{ +\[en]with\-dvd +T}@T{ +\[en]without\-dvd +T}@T{ +To get the cdrom/dvdrom vendor and model +T} +T{ +\[en]with\-sensors +T}@T{ +\[en]without\-sensors +T}@T{ +Alternative way to get data from the sensors (linux only) +T} +T{ +\[en]with\-apm +T}@T{ +\[en]without\-apm +T}@T{ +APM power and resource management for laptops (FreeBSD only) +T} +T{ +\[en]with\-ncurses +T}@T{ +\[en]without\-ncurses +T}@T{ +Output the data to the terminal using the ncurses library, can be +colorized +T} +T{ +\[en]with\-perl +T}@T{ +\[en]without\-perl +T}@T{ +Extend pinkybar with your own crafted scripts written in perl +T} +T{ +\[en]with\-lua +T}@T{ +\[en]without\-lua +T}@T{ +Extend pinkybar with your own crafted scripts written in lua +T} +T{ +\[en]with\-ruby +T}@T{ +\[en]without\-ruby +T}@T{ +Extend pinkybar with your own crafted scripts written in ruby +T} +T{ +\[en]with\-python2 +T}@T{ +\[en]without\-python2 +T}@T{ +Extend pinkybar with your own crafted scripts written in python2 +T} +T{ +\[en]with\-python3 +T}@T{ +\[en]without\-python3 +T}@T{ +Extend pinkybar with your own crafted scripts written in python3 +T} +T{ +\[en]with\-weather +T}@T{ +\[en]without\-weather +T}@T{ +The temperature outside (some details must be provided) +T} +T{ +api_key=`123458976' +T}@T{ +T}@T{ +API key obtained after registering yourself in the weather website, must +be combined \f[B]\[en]with\-weather\f[] +T} +T{ +\[en]with\-smartemp +T}@T{ +\[en]without\-smartemp +T}@T{ +Read the drive temperature from S.M.A.R.T cross\-platform available +T} +T{ +\[en]with\-drivetemp +T}@T{ +\[en]without\-drivetemp +T}@T{ +Read the drive temperature from S.M.A.R.T (linux only) uses curl +T} +T{ +\[en]with\-drivetemp\-light +T}@T{ +\[en]without\-drivetemp\-light +T}@T{ +Read the drive temperature from S.M.A.R.T (linux only) light version +T} +T{ +drive_port=`1234' +T}@T{ +T}@T{ +Different TCP port to listen to for the drive temperature, default one +is 7634, must be combined \f[B]\[en]with\-drivetemp\f[] or +\f[B]\[en]with\-drivetemp\-light\f[] +T} +T{ +\[en]with\-colours +T}@T{ +\[en]without\-colours +T}@T{ +Colorize the output data. +T} +T{ +icons=/tmp +T}@T{ +T}@T{ +xbm icons that can be used by dzen2 for example. +Discarded when \f[B]\[en]with\-x11\f[] is used +T} +T{ +\[en]with\-mpd +T}@T{ +\[en]without\-mpd +T}@T{ +To see the currently played song name (if any). +T} +T{ +\[en]prefix=/tmp +T}@T{ +T}@T{ +The directory where the program will be installed +T} +T{ +mobo_sensor=`dev.aibs.0' +T}@T{ +T}@T{ +FreeBSD motherboard sensor module name to use in the sysctl calls. +Read the FreeBSD installation below +T} +T{ +cpu_sensor=`dev.cpu.0.temperature' +T}@T{ +T}@T{ +FreeBSD cpu temperature module name to use in the sysctl calls . +Read the FreeBSD installation below +T} +.TE +.PP +By default, if \f[B]no\f[] options are passed, the program will be +compiled with: +.IP +.nf +\f[C] +\-\-with\-net\ \-\-with\-pci +\f[] +.fi +.PP +Affects only FreeBSD users with laptops, \f[B]\[en]without\-apm\f[] will +compile the program with acpi support to obtain the current battery +life. +.PP +\f[B]\[en]without\-mpd\f[] will compile the program with cmus support, +the options syntax stays as is. +.PP +The pci and sensors configure options will be discarded in *BSD. +.PP +Affects only linux users with wifi/wireless chipsets, run +\f[C]lsmod|grep\ 802\f[] and see whether your chipset uses +cfg80211/mac80211. +If that's so you can rely on libnl and enable \f[B]\[en]with\-libnl\f[] +configure options, otherwise your chipset probably still uses we/wext, +so type \f[B]\[en]without\-libnl\f[]. +.PP +Affects only linux users, \f[B]\[en]with\-drivetemp\f[] pretty much +locks you down to hddtemp. +You can adjust \f[B]extra/scripts/drive\-temperature.sh\f[] and compile +the program \f[B]\[en]with\-smartemp\f[], so you can switch between +hddtemp and smartmontools at any time without the need recompile +pinkybar with different options. +\f[B]\[en]with\-smartemp\f[] only cares for the existance of +/tmp/pinkytemp file. +.PP +\f[B]\[en]with\-weather\f[] is using this +url (http://openweathermap.org/current), register yourself there, create +a new API key (https://home.openweathermap.org/api_keys). +.PP +Don't just rush to register yourself, read carefully what the +\[lq]Free\[rq] account limits are and take in account how often the +program should call their api service. +I'm not responsible if you exceeded the limits, you've been warned. +.IP +.nf +\f[C] +#\ Make\ sure\ it\[aq]s\ working\ first +#\ curl\ \[aq]http://api.openweathermap.org/data/2.5/weather?q=London,uk&units=metric&APPID=28459ae16e4b3a7e5628ff21f4907b6f\[aq] + +#\ what\ to\ pass\ to\ configure +\-\-with\-weather\ api_key=\[aq]28459ae16e4b3a7e5628ff21f4907b6f\[aq] +\f[] +.fi +.PP + * * * * * +.SS Installation for dwm +.IP +.nf +\f[C] +perl\ set.pl\ "distro" +autoreconf\ \-\-install\ \-\-force + +\&./configure\ \-\-prefix=$HOME/.cache\ \-\-with\-x11 +make +make\ install +\f[] +.fi +.PP +Copy the code from extra/scripts/dwm.sh or \f[C]exec\f[] it from +\f[B]xinitrc\f[] or the script used to start dwm. +.SS Installation for xmonad (or other WM) +.IP +.nf +\f[C] +#\ Copy\ the\ xbm\ icons +mkdir\ \-p\ \-\-mode=700\ $HOME/.xmonad/icons +cp\ \-r\ extra/xbm_icons/*.xbm\ $HOME/.xmonad/icons + +perl\ set.pl\ "distro" +autoreconf\ \-\-install\ \-\-force + +#\ disable\ X11,\ point\ the\ location\ to\ the\ icons +\&./configure\ \-\-prefix=$HOME/.cache\ \-\-without\-x11\ icons=$HOME/.xmonad/icons + +#\ compile\ \[aq]n\ install +make +make\ install +\f[] +.fi +.PP +Copy the code from extra/scripts/xmonad.sh or \f[C]exec\f[] it from +\f[B]xinitrc\f[] or the script used to start xmonad. +.SS Installation in FreeBSD +.PP +FreeBSD has no other way than using the module specific convention to +query sysctl and obtain data from the sensors. +Maintaining a list with all the possible module names and performing +expensive sysctl calls in a loop to determine that X module is loaded +into your system is no\-go. +Be prepared to spend a minute or two to find out some system +information. +.PP +Determine the motherboard sensor module name. +.IP +.nf +\f[C] +sysctl\ \-a|grep\ \[aq]aibs\[aq] + +dev.aibs.0.volt.0:\ 1356\ 850\ 1600 +dev.aibs.0.volt.1:\ 3344\ 2970\ 3630 +dev.aibs.0.volt.2:\ 5040\ 4500\ 5500 +dev.aibs.0.volt.3:\ 12278\ 10200\ 13800 +dev.aibs.0.temp.0:\ 39.0C\ 60.0C\ 95.0C +dev.aibs.0.temp.1:\ 38.0C\ 45.0C\ 75.0C +dev.aibs.0.fan.0:\ 1053\ 600\ 7200 +dev.aibs.0.fan.1:\ 1053\ 600\ 7200 +\f[] +.fi +.PP +Copy only `dev.MODULE.NUMBER' (if there is any number at all) and paste +it into the \f[B]mobo_sensor\f[] option below. +.PP +Do the same for your cpu temperature, copy and paste the variable as is. +\f[B]dev.cpu.0.temperature\f[] below is provied as example. +.IP +.nf +\f[C] +perl\ set.pl\ "freebsd" +autoreconf\ \-\-install\ \-\-force + +\&./configure\ \-\-prefix=$HOME/.cache\ \-\-with\-x11\ \-\-without\-alsa\ \-\-with\-oss\ mobo_sensor=\[aq]dev.aibs.0\[aq]\ cpu_sensor=\[aq]dev.cpu.0.temperature\[aq] +make +make\ install +\f[] +.fi +.PP +Send a request to the FreeBSD mailing list and request the OpenBSD +sensors API to be ported. +.SS Installation in OpenBSD +.PP +Before proceeding, you'll have to: +.IP +.nf +\f[C] +#\ To\ detect\ the\ newer\ compiler\ that\ you\ are +#\ about\ to\ install +sed\ \-i\ \[aq]s/#AC_PROG_CC(/AC_PROG_CC(/g\[aq]\ configure.ac + +ls\ /usr/local/bin/automake\-* +ls\ /usr/local/bin/autoconf\-* + +#\ Then\ replace\ the\ numbers\ below +export\ AUTOCONF_VERSION=2.69 +export\ AUTOMAKE_VERSION=1.15 + +#\ Your\ call,\ gcc\ or\ llvm\ ? +pkg_add\ gcc + +#\ after\ that: +perl\ set.pl\ "openbsd" +autoreconf\ \-\-install\ \-\-force + +\&./configure\ \-\-prefix=$HOME/.cache\ \-\-without\-alsa\ \-\-with\-oss +make +make\ install +\f[] +.fi +.SS pinky curses installation +.PP +Step one, compile pinky\-bar \f[B]\[en]with\-ncurses\f[], so the output +to be formated in a way that pinky\-curses can parse and colorize. +.IP +.nf +\f[C] +perl\ set.pl\ "distro" +autoreconf\ \-\-install\ \-\-force + +#\ disable\ X11,\ enable\ the\ colours\ and\ ncurses\ opts. +\&./configure\ \-\-prefix=$HOME/.cache\ \-\-without\-x11\ \-\-with\-alsa\ \-\-with\-colours\ \-\-with\-ncurses + +#\ compile\ \[aq]n\ install +make +make\ install +\f[] +.fi +.PP +Step two, compile and install pinky\-curses \- +https://notabug.org/void0/pinky\-curses +.PP +Copy the code from extra/scripts/pinky\-curses.sh +.SS pinky urxvt +.PP +What a coincidence, pinky\-urxvt is my 3rd urxvt extension and 3rd +member of the pinky family. +.PP +The sole purpose of this urxvt extension is to make it easy for you to +keep track of things that you are interested to monitor while hacking +your way something in the terminal. +.PP +Link \- https://notabug.org/void0/pinky\-urxvt +.PP +[IMAGE: image (https://notabug.org/void0/pinky-urxvt/raw/master/2.png)] +.PP +pinky\-urxvt, and pinky\-curses are not tied to pinky\-bar. +.SS Installation for anything else +.PP +pinky\-bar is no longer tied to Window Managers only. +With the addition of \[lq]without colours\[rq], the output can be shown +in any program, just bear in mind that the more options you've supplied +the more system information will be shown. +.PP +The tmux status bar in action: +.PP +[IMAGE: image (img/pic4.png)] +.PP +The installation steps: +.IP +.nf +\f[C] +perl\ set.pl\ "distro" +autoreconf\ \-\-install\ \-\-force + +\&./configure\ \-\-prefix=$HOME/.cache\ \-\-without\-x11\ \-\-without\-colours +make +make\ install +\f[] +.fi +.PP +By choosing this 3rd installation method it is up to you where, how to +start and use the system information that's produced by pinky\-bar. +.PP + * * * * * +.PP +Replace \f[B]distro\f[] with archlinux, debian, gentoo, slackware, rhel, +frugalware, angstrom. +Here's some short distros list of some popular distros that are based on +another one: +.IP \[bu] 2 +[x] archlinux based distros: parabola, chakra, manjaro +.IP \[bu] 2 +[x] debian based distros: ubuntu, linux mint, trisquel, back track, kali +linux, peppermint linux, solusos, crunchbang, deepin, elementary os, and +the rest *buntu based distros +.IP \[bu] 2 +[x] gentoo based distros: funtoo, sabayon, calculate linux +.IP \[bu] 2 +[x] slackware +.IP \[bu] 2 +[x] rhel based distros: opensuse (uses rpm), fedora, fuduntu, mandriva, +mandrake, viperr, mageia +.IP \[bu] 2 +[x] frugalware +.IP \[bu] 2 +[x] angstrom +.PP +Cannot list the *BSD flavours as \[lq]distros\[rq], so they deserve own +options: +.IP \[bu] 2 +[x] freebsd +.IP \[bu] 2 +[x] openbsd +.PP + * * * * * +.SS Using configuration file +.PP +\f[B]~/.pinky\f[] is the location of the configuration file. +It uses the same short and long command line options. +.PP +I do advise you to use the long options syntax. +.PP +If any option depends on argument, don't put any space between the +option and the argument. +.PP +Use one option per line. +Contrary to your shell, the \[lq]parser\[rq] won't expand ~/my_script.pl +to point to /home/sweethome/my_script.pl +.IP +.nf +\f[C] +\-\-weather=London,uk +\-\-coresload +\-\-cputemp +\-\-ramperc +\-\-driveperc +\-\-packages +\-\-kernel +\-\-voltage +\-\-fans +\-\-mobo +\-\-mobotemp +\-\-perl=/home/sweethome/my_script.pl +\f[] +.fi +.PP +Execute the program without supplying any command line options and it +will parse the configuration file. +.PP + * * * * * +.SS Linux Mandatory requirements +.IP \[bu] 2 +gcc/clang +.IP \[bu] 2 +glibc +.IP \[bu] 2 +autoconf +.IP \[bu] 2 +automake +.IP \[bu] 2 +m4 +.IP \[bu] 2 +gawk +.IP \[bu] 2 +perl +.SS *BSD Mandatory requirements +.IP \[bu] 2 +gcc/clang +.IP \[bu] 2 +autoconf +.IP \[bu] 2 +automake +.IP \[bu] 2 +autoconf\-wrapper +.IP \[bu] 2 +automake\-wrapper +.IP \[bu] 2 +autoconf\-archive +.IP \[bu] 2 +argp\-standalone +.IP \[bu] 2 +libtool +.IP \[bu] 2 +m4 +.IP \[bu] 2 +gawk +.IP \[bu] 2 +perl +.PP +Some llvm and gcc versions will not check for headers and libraries in +/usr/local, if that's the case for you, you should export the following +environment variables: +.IP +.nf +\f[C] +export\ LDFLAGS=\[aq]\-L/usr/local/lib\[aq] +export\ CFLAGS=\[aq]\-I/usr/local/include\[aq] +\f[] +.fi +.PP +After editing the wrong prototype I managed to stumble upon a bug in +OpenBSD's own libc. +.PP +\f[B]Warning !!! OpenBSD users !!!\f[] +.PP +The majority of SCN* macros differs from their PRI* cousins. +And I cannot guarantee the accuracy of fixed width integers when OpenBSD +own libc managed to use different format specifiers. +Read extra/misc/openbsd_bugs.md for more details. +.SS Opt\-in requirements +.PP +Linux camp: +.PP +The internet related options rely on headers provided iproute2. +By default the program will try to compile with those headers included. +If for any reason you would like to compile the program without internet +related options, then pass \f[B]\[en]without\-net\f[] to configure. +.IP \[bu] 2 +iproute2 +.PP +wifi/wireless chipsets supporting mac80211/cfg80211: +.IP \[bu] 2 +libnl (>= 3.0) +.IP \[bu] 2 +pkg\-config +.PP +In Gentoo there are two versions of pkg\-config. +The first one is named dev\-util/pkgconfig and the second one is +dev\-ruby/pkg\-config. +In order to use the first one, you'll have to export the pkg\-config +path to the following environment variable: +.IP +.nf +\f[C] +export\ PKG_CONFIG_PATH=/usr/bin/pkg\-config +\f[] +.fi +.PP +Then pass \f[B]\[en]with\-libnl\f[] to configure. +.PP +To get the NIC vendor and model names: +.IP \[bu] 2 +pciutils +.PP +Alternative way to obtain data from the sensors: +.IP \[bu] 2 +lm_sensors +.PP +To read the drive temperature from S.M.A.R.T +\f[B]\[en]with\-drivetemp\f[]: +.IP \[bu] 2 +hddtemp +.IP \[bu] 2 +curl +.PP +To read the drive temperature from S.M.A.R.T +\f[B]\[en]with\-drivetemp\-light\f[]: +.IP \[bu] 2 +hddtemp +.PP +The \[lq]light\[rq] version does not rely on curl, and will not force +\-O0 CFLAGS. +.IP +.nf +\f[C] +#\ \-\-with\-drivetemp\-light +0.00s\ user\ 0.00s\ system\ 15%\ cpu\ 0.006 + +#\ \-\-with\-drivetemp +0.01s\ user\ 0.00s\ system\ 72%\ cpu\ 0.008 +\f[] +.fi +.PP +Try running hddtemp to see if it detects your drive, depending if it has +temperature sensor in first place: +.IP +.nf +\f[C] +sudo\ hddtemp\ /dev/sda + +WARNING:\ Drive\ /dev/sda\ doesn\[aq]t\ appear\ in\ the\ database\ of\ supported\ drives +WARNING:\ But\ using\ a\ common\ value,\ it\ reports\ something. +WARNING:\ Note\ that\ the\ temperature\ shown\ could\ be\ wrong. +WARNING:\ See\ \-\-help,\ \-\-debug\ and\ \-\-drivebase\ options. +WARNING:\ And\ don\[aq]t\ forget\ you\ can\ add\ your\ drive\ to\ hddtemp.db +/dev/sda:\ Corsair\ Force\ GT:\ \ 23°C\ or\ °F +\f[] +.fi +.PP +The message is pretty clear \[lq]don't forget to add your drive to +hddtemp.db\[rq], first run the debug command to see which field is +responsible to report your drive temperature, it should be in the range +of 190 \- 200: +.IP +.nf +\f[C] +#\ Copy\ the\ Model:\ line + +sudo\ hddtemp\ \-\-debug\ /dev/sda + +=================\ hddtemp\ 0.3\-beta15\ ================== +Model:\ Corsair\ Force\ GT + +field(1)\ \ \ \ \ \ \ \ \ =\ 0 +field(5)\ \ \ \ \ \ \ \ \ =\ 0 +field(9)\ \ \ \ \ \ \ \ \ =\ 253 +field(12)\ \ \ \ \ \ \ \ =\ 237 +field(171)\ \ \ \ \ \ \ =\ 0 +field(172)\ \ \ \ \ \ \ =\ 0 +field(174)\ \ \ \ \ \ \ =\ 147 +field(177)\ \ \ \ \ \ \ =\ 1 +field(181)\ \ \ \ \ \ \ =\ 0 +field(182)\ \ \ \ \ \ \ =\ 0 +field(187)\ \ \ \ \ \ \ =\ 0 +field(194)\ \ \ \ \ \ \ =\ 22 +field(195)\ \ \ \ \ \ \ =\ 0 +field(196)\ \ \ \ \ \ \ =\ 0 +field(201)\ \ \ \ \ \ \ =\ 0 +field(204)\ \ \ \ \ \ \ =\ 0 +field(230)\ \ \ \ \ \ \ =\ 100 +field(231)\ \ \ \ \ \ \ =\ 0 +field(233)\ \ \ \ \ \ \ =\ 130 +field(234)\ \ \ \ \ \ \ =\ 216 +field(241)\ \ \ \ \ \ \ =\ 216 +field(242)\ \ \ \ \ \ \ =\ 151 +\f[] +.fi +.PP +Open up \f[B]/usr/share/hddtemp/hddtemp.db\f[] and append the Model: +line that you copied earlier with the correct field that reports your +drive temperature. +.IP +.nf +\f[C] +"Corsair\ Force\ GT"\ 194\ C\ "Corsair\ Force\ GT\ 120GB\ SSD" +\f[] +.fi +.PP +Next run hddtemp in daemon mode so we can request the temperature back: +.IP +.nf +\f[C] +sudo\ hddtemp\ \-d\ /dev/sda +\f[] +.fi +.PP +Open up your browser and navigate to 127.0.0.1:7634 and you'll get +instant temperature report back to you. +.PP +The \[lq]init\[rq] lock\-in for those of you that cannot choose between +udev or eudev puts me in position not rely on libatasmart, regardless +how neat the library is. +There is stripped example program in extra/misc/skdump.c if you are +curious to check and test libatasmart. +.PP +Linux camp end. +.PP +To read the drive temperature from S.M.A.R.T +\f[B]\[en]with\-smartemp\f[]: +.IP \[bu] 2 +smartmontools +.PP +smartmontools are not mandatory in OpenBSD, \f[C]atactl\f[] does the +same job. +.PP +Execute the following command as root \f[C]visudo\f[] and append: +.IP +.nf +\f[C] +#\ \[aq]frost\[aq]\ is\ my\ computer\ username +frost\ ALL=NOPASSWD:/usr/sbin/smartctl +\f[] +.fi +.PP +Copy the code from extra/scripts/drive\-temperature.sh or \f[C]exec\f[] +it from \f[B]xinitrc\f[] or the script used to start your DE/WM. +.PP +To extend pinkybar with your own crafted perl/python/ruby/lua script: +.IP \[bu] 2 +perl +.IP \[bu] 2 +python == 2.7 (\[en]with\-python2) +.IP \[bu] 2 +python >= 3.3 (\[en]with\-python3) +.IP \[bu] 2 +lua >= 5.1 +.IP \[bu] 2 +ruby >= 2.0 and pkg\-config +.PP +Have a look at extra/scripts/pinky.{py,pl,ruby,lua}, they serve as +examples how to write the most basic scripts in order to extend pinkybar +in python/perl/ruby/lua. +You can use the 3 languages simultaneously. +.PP +Please, please do \f[B]NOT\f[] export or set PYTHONPATH on it's own +line. +.PP +\f[C]WRONG\f[]: +.IP +.nf +\f[C] +export\ PYTHONPATH=/meh +pinkybar\ \-\-python\ my_script +\f[] +.fi +.PP +\f[C]WRONG\f[]: +.IP +.nf +\f[C] +PYTHONPATH=/meh +pinkybar\ \-\-python\ my_script +\f[] +.fi +.PP +Correct PYTHONPATH usage: +.IP +.nf +\f[C] +#\ ~/chewbacca\ is\ the\ path\ where\ pinky.py\ resides +#\ ~/chewbacca/pinky.py + +#\ python2 +PYTHONPATH=~/chewbacca\ ~/pinkybar\ \-\-python\ pinky + +#\ python3 +#\ executed\ only\ once +fuNky=$(python3\ \-c\ \[aq]import\ sys;print(":".join([x\ for\ x\ in\ sys.path]))\[aq]) + +#\ executed\ in\ a\ loop +PYTHONPATH=$fuNky:~/chewbacca\ ~/pinkybar\ \-\-python\ pinky +\f[] +.fi +.PP +\f[B]\[en]with\-perl\f[]: +.IP +.nf +\f[C] +~/pinkybar\ \-\-perl\ ~/chewbacca/pinky.pl +\f[] +.fi +.PP +\f[B]\[en]with\-ruby\f[]: +.IP +.nf +\f[C] +~/pinkybar\ \-\-ruby\ ~/chewbacca/pinky.rb +\f[] +.fi +.PP +\f[B]\[en]with\-lua\f[]: +.PP +Non byte\-compiled script: +.IP +.nf +\f[C] +~/pinkybar\ \-\-lua\ ~/chewbacca/pinky.lua +\f[] +.fi +.PP +Once done editing your script, you can byte\-compile it: +.IP +.nf +\f[C] +luac\ \-o\ pinky.luac\ pinky.lua +~/pinkybar\ \-\-lua\ ~/chewbacca/pinky.luac\ #\ <\-\-\ .luac\ and\ not\ .lua +\f[] +.fi +.PP +To get the sound volume level: +.IP \[bu] 2 +alsa\-utils +.IP \[bu] 2 +alsa\-lib +.PP +Then pass \f[B]\[en]with\-alsa\f[] to configure. +.PP +*BSD users can use the baked OSS instead, pass \f[B]\[en]without\-alsa +\[en]with\-oss\f[] to configure instead. +.PP +To output the data to the terminal using the ncurses library: +.IP \[bu] 2 +ncurses +.PP +To get the vendor and model name of your cdrom/dvdrom/blu\-ray: +.IP \[bu] 2 +libcdio +.IP \[bu] 2 +libcddb +.PP +In linux \f[B]\[en]without\-dvd\f[] will still compile the program with +dvd support. +Except it will be limited only to dvd support, it will try to parse the +sr0 vendor and model name detected by the kernel. +.PP +The weather related options, please go back and read \f[B]Don't just +rush to register yourself\f[]: +.IP \[bu] 2 +curl +.IP \[bu] 2 +gzip +.PP +\f[B]Warning, I'm not responsible for any lawsuit towards you, neither +encourage you to pirate content that is not licensed as free and/or for +fair use.\f[] +.PP +To see the currently played song name \f[B]\[en]with\-mpd\f[]: +.PP +Server side: +.IP \[bu] 2 +mpd (can be build with soundcloud support) +.PP +Client side: +.IP \[bu] 2 +libmpdclient +.IP \[bu] 2 +mpc/ncmpc/ncmpcpp, and the rest (http://mpd.wikia.com/wiki/Clients) +.PP +To see the currently played song name \f[B]\[en]without\-mpd\f[]: +.IP \[bu] 2 +cmus +.PP +The \[lq]soundcloud\[rq] alternative that is supported in cmus and your +mpd client will be to download \f[B]\&.m3u/.pls\f[] files according to +the radio stream station (https://www.internet-radio.com) that you are +interested to listen. +.PP +The FreeBSD users will notice that \[lq]mpd\[rq] is named +\[lq]musicpd\[rq]. +.PP +If you've never used mpd before copy the example configuration from +extra/mpd according to your OS. +.PP +Keep an eye on the \f[B]log file size\f[] if you are using raspberry pi +(or equivalent device) that streams the music, make sure that it's +deleted automatically if it exceeds some pre\-defined size. +.PP + * * * * * +.SS WM specific requirements +.PP +If you would like the output to be shown in your Window Manager, those +are the following requirements: +.PP +for non\-dwm WM: +.IP \[bu] 2 +dzen2 +.PP +for dwm: +.IP \[bu] 2 +libx11 +.IP \[bu] 2 +xorg\-server +.PP +use \f[B]\[en]without\-colours\f[] to skip the following step: +.IP \[bu] 2 +dwm compiled with statuscolor patch. +The colours in use are specified in your dwm config.h +.SS Wish list +.PP +It would be great if I had *BSD compatible usb wifi dongle or wireless +pci adapter to add wifi options in pinky\-bar. +.SH REPORTING BUGS +.PP +Report bugs to https://gitlab.com/void0/pinky\-bar +.SH COPYRIGHT +.PP +Copyright (c) 2016 Aaron Caffrey +.PD 0 +.P +.PD +Free use of this software is granted under the terms of the GNU General +Public License (GPL). +.SH AUTHORS +Aaron Caffrey. diff --git a/doc/pinkybar.texi b/doc/pinkybar.texi new file mode 100644 index 0000000..3834af4 --- /dev/null +++ b/doc/pinkybar.texi @@ -0,0 +1,1314 @@ +\input texinfo +@setfilename pinkybar.info +@documentencoding UTF-8 + +@ifnottex +@paragraphindent 0 +@end ifnottex +@titlepage +@title pinkybar(1) manual +@author Aaron Caffrey +Oktoberfest 23, 2016 +@end titlepage + +@node Top +@top pinkybar(1) manual + +@menu +* NAME:: +* SYNOPSIS:: +* DESCRIPTION:: +* REPORTING BUGS:: +* COPYRIGHT:: +@end menu + +@node NAME +@chapter NAME +@anchor{#name} +This man page is converted from markdown, and some information might not +look good and/or have been stripped during the automated process. + +@node SYNOPSIS +@chapter SYNOPSIS +@anchor{#synopsis} +pinkybar [@emph{option}] + +@node DESCRIPTION +@chapter DESCRIPTION +@anchor{#description} +Gather some system information and show it in this statusbar program, +not tied to any Window Manager, terminal multiplexer, etc. + +Please note that the program won't detect fans connected via molex +connetor(s) or external fan controller. Also I have not tested it with +fan splitter(s) either. + +The program is smart enough to detect whether some of your fan(s) blades +are spinning, or the particular fan have been removed. Hold down some of +your fan blades and you'll see that the program won't include this fan +and it's RPM, release the blades and you'll see the fan and it's RPM in +the statusbar. Try simulating real fan hardware failure by holding down +all system fan blades and watch what the program will show you, just try +not to slice your cheesy fingers open in the process. + +You can extend pinky-bar with your own crafted perl/python/ruby/lua +script. + +If you compile your kernel from source code make sure to include your +cpu and motherboard sensors as @strong{modules} and not inlined. + +@strong{Just an example if you use BSD - acpi/aibs, coretemp/amdtemp.} + +@float +@image{img/cpu-temp,,,,png} +@end float + +@float +@image{img/mobo-temp,,,,png} +@end float + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex +@menu +* Program options:: +* GNU Build System configure options:: +* Installation for dwm:: +* Installation for xmonad or other WM:: +* Installation in FreeBSD:: +* Installation in OpenBSD:: +* pinky curses installation:: +* pinky urxvt:: +* Installation for anything else:: +* Using configuration file:: +* Linux Mandatory requirements:: +* *BSD Mandatory requirements:: +* Opt-in requirements:: +* WM specific requirements:: +* Wish list:: +@end menu + +@node Program options +@section Program options +@anchor{#program-options} +The order of supplied options will dictate how, where and what system +information to be shown. + +@multitable {short option} {--driveavail} {Detect your CPU vendor, stepping, family, clflush, l1/l2 cache and line size, physical cores, physical and virtual bits. Uses assembly.} +@headitem +short option + @tab long option + @tab Descrtiption +@item +-M + @tab --mpd + @tab The song filename +@item +-W + @tab --mpdtrack + @tab The song track name (not available in cmus) +@item +-x + @tab --mpdartist + @tab The song artist(s) name(s) +@item +-X + @tab --mpdtitle + @tab The song title +@item +-y + @tab --mpdalbum + @tab The song album name +@item +-Y + @tab --mpddate + @tab The song date +@item +-c + @tab --cpu + @tab The current cpu load (summed up all cores/threads) +@item +-L + @tab --coresload + @tab Show the load regarding each individual cpu core/thread +@item +-T + @tab --cputemp + @tab The current cpu temperature +@item +-C + @tab --cpuspeed + @tab Show your maximum cpu clock speed in MHz, regardless of the used +governor. Uses assembly. +@item +-I + @tab --cpuinfo + @tab Detect your CPU vendor, stepping, family, clflush, l1/l2 cache and +line size, physical cores, physical and virtual bits. Uses assembly. +@item +-r + @tab --ramperc + @tab The used ram in percentage +@item +-J + @tab --ramtotal + @tab The total ram +@item +-K + @tab --ramfree + @tab The free ram +@item +-l + @tab --ramshared + @tab The shared ram +@item +-o + @tab --rambuffer + @tab The buffer ram (not available in OpenBSD) +@item +-s + @tab --driveperc + @tab The used drive storage in percentage +@item +-n + @tab --drivetotal + @tab The total drive storage +@item +-N + @tab --drivefree + @tab The free drive storage +@item +-O + @tab --driveavail + @tab The available drive storage (total - used) +@item +--drivetemp + @tab Read the drive temperature from S.M.A.R.T +@item +-g + @tab --battery + @tab The remaining battery charge +@item +-z + @tab --dvdstr + @tab The vendor and model name of your cdrom/dvdrom +@item +-S + @tab --statio + @tab Read and written MBs to the drive so far [argument - sda] +@item +-p + @tab --packages + @tab The number of installed packages +@item +-P + @tab --kernsys + @tab The kernel name +@item +--kernode + @tab The network node hostname +@item +-Q + @tab --kernrel + @tab The kernel release +@item +-R + @tab --kernver + @tab The kernel version +@item +-u + @tab --kernarch + @tab The machine architecture +@item +-k + @tab --kernel + @tab Combined kernel name and version +@item +--perl + @tab Extend pinkybar with your scripts written in perl, learn more from +the Opt-in section. +@item +--python + @tab Extend pinkybar with your scripts written in python, learn more +from the Opt-in section. +@item +--ruby + @tab Extend pinkybar with your scripts written in ruby, learn more from +the Opt-in section. +@item +--lua + @tab Extend pinkybar with your scripts written in lua, learn more from +the Opt-in section. +@item +-q + @tab --weather + @tab Show the temperature outside [argument - London,uk] +@item +-U + @tab --uptime + @tab The system uptime +@item +-w + @tab --loadavg + @tab The system average load for past 1, 5 and 15 minutes +@item +-v + @tab --voltage + @tab The system voltage +@item +-f + @tab --fans + @tab All system fans and their speed in RPM +@item +-m + @tab --mobo + @tab Show the motherboard name and vendor +@item +-d + @tab --mobotemp + @tab The motherboard temperature +@item +-V + @tab --volume + @tab The sound volume level +@item +-t + @tab --time + @tab The current time +@item +-a + @tab --ipaddr + @tab The local ip address [argument - eth0] +@item +-b + @tab --bandwidth + @tab The consumed internet bandwidth so far [argument - eth0] +@item +-i + @tab --iface + @tab The current download and upload speed [argument - eth0] +@item +-A + @tab --ipmac + @tab The NIC mac address [argument - eth0] +@item +-B + @tab --ipmask + @tab The NIC subnet mask [argument - eth0] +@item +-D + @tab --ipcast + @tab The NIC broadcast address [argument - eth0] +@item +-E + @tab --iplookup + @tab Mini website IP lookup [website argument - google.com] +@end multitable + +Be aware of the options that mention @strong{Uses assembly} are tested +only on AMD and Intel CPUs (starting from pentium 4 onwards). + +The following options are available only in Linux: + +@multitable {short option} {--drivemodel} {The name of currently connected wifi/wireless network [argument - wlan0]} +@headitem +short option + @tab long option + @tab Descrtiption +@item +-F + @tab --drivemodel + @tab The vendor name of your drive [argument - sda] +@item +-G + @tab --nicinfo + @tab The NIC vendor and model [argument - eth0] +@item +--nicdrv + @tab The NIC driver [argument - eth0] +@item +-H + @tab --nicver + @tab The NIC version [argument - eth0] +@item +-e + @tab --iplink + @tab The NIC link speed (useful for wireless/wifi) [argument - eth0] +@item +-j + @tab --nicfw + @tab The NIC firmware [argument - eth0] +@item +-h + @tab --wifiname + @tab The name of currently connected wifi/wireless network [argument - +wlan0] +@end multitable + +The following options are available only to FreeBSD and OpenBSD: + +@multitable {short option} {--swapavail} {The NIC gateway address [argument - re0]} +@headitem +short option + @tab long option + @tab Descrtiption +@item +-j + @tab --nicgw + @tab The NIC gateway address [argument - re0] +@item +-Z + @tab --swapused + @tab The used drive swap in MB +@item +-F + @tab --swaperc + @tab The used drive swap in percentage +@item +-h + @tab --swaptotal + @tab The total drive swap +@item +-H + @tab --swapavail + @tab The available drive swap (total - used) +@end multitable + +The following options are available only in OpenBSD: + +@multitable {short option} {long option} {The used ram in MB} +@headitem +short option + @tab long option + @tab Descrtiption +@item +-l + @tab --ramused + @tab The used ram in MB +@end multitable + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex + +@node GNU Build System configure options +@section GNU Build System (configure) options +@anchor{#gnu-build-system-configure-options} +Before the source code is passed to the compiler, you can enable/disable +the following @strong{configure} options that will increase/reduce the +number of dependencies required to compile the program. + +It's up to you to decide which features suit you best. + +@multitable {cpu_sensor=`dev.cpu.0.temperature'} {--without-drivetemp-light} {Different TCP port to listen to for the drive temperature, default one is 7634, must be combined @strong{--with-drivetemp} or @strong{--with-drivetemp-light}} +@headitem +To include + @tab Not to include + @tab Descrtiption +@item +--with-x11 + @tab --without-x11 + @tab Enable it if you are using dwm. +@item +--with-alsa + @tab --without-alsa + @tab To get the sound volume level. +@item +--with-oss + @tab --without-oss + @tab To get the sound volume level in *BSD. +@item +--with-net + @tab --without-net + @tab Enable the internet related options. +@item +--with-libnl + @tab --without-libnl + @tab Enable the wifi related options regarding chipsets supporting the +cfg80211/mac80211 modules (linux only). +@item +--with-pci + @tab --without-pci + @tab To get the NIC vendor and model in linux +@item +--with-dvd + @tab --without-dvd + @tab To get the cdrom/dvdrom vendor and model +@item +--with-sensors + @tab --without-sensors + @tab Alternative way to get data from the sensors (linux only) +@item +--with-apm + @tab --without-apm + @tab APM power and resource management for laptops (FreeBSD only) +@item +--with-ncurses + @tab --without-ncurses + @tab Output the data to the terminal using the ncurses library, can be +colorized +@item +--with-perl + @tab --without-perl + @tab Extend pinkybar with your own crafted scripts written in perl +@item +--with-lua + @tab --without-lua + @tab Extend pinkybar with your own crafted scripts written in lua +@item +--with-ruby + @tab --without-ruby + @tab Extend pinkybar with your own crafted scripts written in ruby +@item +--with-python2 + @tab --without-python2 + @tab Extend pinkybar with your own crafted scripts written in python2 +@item +--with-python3 + @tab --without-python3 + @tab Extend pinkybar with your own crafted scripts written in python3 +@item +--with-weather + @tab --without-weather + @tab The temperature outside (some details must be provided) +@item +api_key=`123458976' + @tab + @tab API key obtained after registering yourself in the weather +website, must be combined @strong{--with-weather} +@item +--with-smartemp + @tab --without-smartemp + @tab Read the drive temperature from S.M.A.R.T cross-platform available +@item +--with-drivetemp + @tab --without-drivetemp + @tab Read the drive temperature from S.M.A.R.T (linux only) uses curl +@item +--with-drivetemp-light + @tab --without-drivetemp-light + @tab Read the drive temperature from S.M.A.R.T (linux only) light +version +@item +drive_port=`1234' + @tab + @tab Different TCP port to listen to for the drive temperature, default +one is 7634, must be combined @strong{--with-drivetemp} or +@strong{--with-drivetemp-light} +@item +--with-colours + @tab --without-colours + @tab Colorize the output data. +@item +icons=/tmp + @tab + @tab xbm icons that can be used by dzen2 for example. Discarded when +@strong{--with-x11} is used +@item +--with-mpd + @tab --without-mpd + @tab To see the currently played song name (if any). +@item +--prefix=/tmp + @tab + @tab The directory where the program will be installed +@item +mobo_sensor=`dev.aibs.0' + @tab + @tab FreeBSD motherboard sensor module name to use in the sysctl calls. +Read the FreeBSD installation below +@item +cpu_sensor=`dev.cpu.0.temperature' + @tab + @tab FreeBSD cpu temperature module name to use in the sysctl calls . +Read the FreeBSD installation below +@end multitable + +By default, if @strong{no} options are passed, the program will be +compiled with: + +@verbatim +--with-net --with-pci +@end verbatim + +Affects only FreeBSD users with laptops, @strong{--without-apm} will +compile the program with acpi support to obtain the current battery +life. + +@strong{--without-mpd} will compile the program with cmus support, the +options syntax stays as is. + +The pci and sensors configure options will be discarded in *BSD. + +Affects only linux users with wifi/wireless chipsets, run +@code{lsmod|grep 802} and see whether your chipset uses +cfg80211/mac80211. If that's so you can rely on libnl and enable +@strong{--with-libnl} configure options, otherwise your chipset probably +still uses we/wext, so type @strong{--without-libnl}. + +Affects only linux users, @strong{--with-drivetemp} pretty much locks +you down to hddtemp. You can adjust +@strong{extra/scripts/drive-temperature.sh} and compile the program +@strong{--with-smartemp}, so you can switch between hddtemp and +smartmontools at any time without the need recompile pinkybar with +different options. @strong{--with-smartemp} only cares for the existance +of /tmp/pinkytemp file. + +@strong{--with-weather} is using +@uref{http://openweathermap.org/current,this url}, register yourself +there, create a new @uref{https://home.openweathermap.org/api_keys,API +key}. + +Don't just rush to register yourself, read carefully what the ``Free'' +account limits are and take in account how often the program should call +their api service. I'm not responsible if you exceeded the limits, +you've been warned. + +@verbatim +# Make sure it's working first +# curl 'http://api.openweathermap.org/data/2.5/weather?q=London,uk&units=metric&APPID=28459ae16e4b3a7e5628ff21f4907b6f' + +# what to pass to configure +--with-weather api_key='28459ae16e4b3a7e5628ff21f4907b6f' +@end verbatim + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex + +@node Installation for dwm +@section Installation for dwm +@anchor{#installation-for-dwm} + +@verbatim +perl set.pl "distro" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --with-x11 +make +make install +@end verbatim + +Copy the code from extra/scripts/dwm.sh or @code{exec} it from +@strong{xinitrc} or the script used to start dwm. + +@node Installation for xmonad or other WM +@section Installation for xmonad (or other WM) +@anchor{#installation-for-xmonad-or-other-wm} + +@verbatim +# Copy the xbm icons +mkdir -p --mode=700 $HOME/.xmonad/icons +cp -r extra/xbm_icons/*.xbm $HOME/.xmonad/icons + +perl set.pl "distro" +autoreconf --install --force + +# disable X11, point the location to the icons +./configure --prefix=$HOME/.cache --without-x11 icons=$HOME/.xmonad/icons + +# compile 'n install +make +make install +@end verbatim + +Copy the code from extra/scripts/xmonad.sh or @code{exec} it from +@strong{xinitrc} or the script used to start xmonad. + +@node Installation in FreeBSD +@section Installation in FreeBSD +@anchor{#installation-in-freebsd} +FreeBSD has no other way than using the module specific convention to +query sysctl and obtain data from the sensors. Maintaining a list with +all the possible module names and performing expensive sysctl calls in a +loop to determine that X module is loaded into your system is no-go. Be +prepared to spend a minute or two to find out some system information. + +Determine the motherboard sensor module name. + +@verbatim +sysctl -a|grep 'aibs' + +dev.aibs.0.volt.0: 1356 850 1600 +dev.aibs.0.volt.1: 3344 2970 3630 +dev.aibs.0.volt.2: 5040 4500 5500 +dev.aibs.0.volt.3: 12278 10200 13800 +dev.aibs.0.temp.0: 39.0C 60.0C 95.0C +dev.aibs.0.temp.1: 38.0C 45.0C 75.0C +dev.aibs.0.fan.0: 1053 600 7200 +dev.aibs.0.fan.1: 1053 600 7200 +@end verbatim + +Copy only `dev.MODULE.NUMBER' (if there is any number at all) and paste +it into the @strong{mobo_sensor} option below. + +Do the same for your cpu temperature, copy and paste the variable as is. +@strong{dev.cpu.0.temperature} below is provied as example. + +@verbatim +perl set.pl "freebsd" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --with-x11 --without-alsa --with-oss mobo_sensor='dev.aibs.0' cpu_sensor='dev.cpu.0.temperature' +make +make install +@end verbatim + +Send a request to the FreeBSD mailing list and request the OpenBSD +sensors API to be ported. + +@node Installation in OpenBSD +@section Installation in OpenBSD +@anchor{#installation-in-openbsd} +Before proceeding, you'll have to: + +@verbatim +# To detect the newer compiler that you are +# about to install +sed -i 's/#AC_PROG_CC(/AC_PROG_CC(/g' configure.ac + +ls /usr/local/bin/automake-* +ls /usr/local/bin/autoconf-* + +# Then replace the numbers below +export AUTOCONF_VERSION=2.69 +export AUTOMAKE_VERSION=1.15 + +# Your call, gcc or llvm ? +pkg_add gcc + +# after that: +perl set.pl "openbsd" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --without-alsa --with-oss +make +make install +@end verbatim + +@node pinky curses installation +@section pinky curses installation +@anchor{#pinky-curses-installation} +Step one, compile pinky-bar @strong{--with-ncurses}, so the output to be +formated in a way that pinky-curses can parse and colorize. + +@verbatim +perl set.pl "distro" +autoreconf --install --force + +# disable X11, enable the colours and ncurses opts. +./configure --prefix=$HOME/.cache --without-x11 --with-alsa --with-colours --with-ncurses + +# compile 'n install +make +make install +@end verbatim + +Step two, compile and install pinky-curses - +https://notabug.org/void0/pinky-curses + +Copy the code from extra/scripts/pinky-curses.sh + +@node pinky urxvt +@section pinky urxvt +@anchor{#pinky-urxvt} +What a coincidence, pinky-urxvt is my 3rd urxvt extension and 3rd member +of the pinky family. + +The sole purpose of this urxvt extension is to make it easy for you to +keep track of things that you are interested to monitor while hacking +your way something in the terminal. + +Link - https://notabug.org/void0/pinky-urxvt + +@float +@image{https://notabug.org/void0/pinky-urxvt/raw/master/2,,,,png} +@end float + +pinky-urxvt, and pinky-curses are not tied to pinky-bar. + +@node Installation for anything else +@section Installation for anything else +@anchor{#installation-for-anything-else} +pinky-bar is no longer tied to Window Managers only. With the addition +of ``without colours'', the output can be shown in any program, just +bear in mind that the more options you've supplied the more system +information will be shown. + +The tmux status bar in action: + +@float +@image{img/pic4,,,,png} +@end float + +The installation steps: + +@verbatim +perl set.pl "distro" +autoreconf --install --force + +./configure --prefix=$HOME/.cache --without-x11 --without-colours +make +make install +@end verbatim + +By choosing this 3rd installation method it is up to you where, how to +start and use the system information that's produced by pinky-bar. + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex +Replace @strong{distro} with archlinux, debian, gentoo, slackware, rhel, +frugalware, angstrom. Here's some short distros list of some popular +distros that are based on another one: + +@itemize +@item +[x] archlinux based distros: parabola, chakra, manjaro +@item +[x] debian based distros: ubuntu, linux mint, trisquel, back track, kali +linux, peppermint linux, solusos, crunchbang, deepin, elementary os, and +the rest *buntu based distros +@item +[x] gentoo based distros: funtoo, sabayon, calculate linux +@item +[x] slackware +@item +[x] rhel based distros: opensuse (uses rpm), fedora, fuduntu, mandriva, +mandrake, viperr, mageia +@item +[x] frugalware +@item +[x] angstrom +@end itemize + +Cannot list the *BSD flavours as ``distros'', so they deserve own +options: + +@itemize +@item +[x] freebsd +@item +[x] openbsd +@end itemize + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex + +@node Using configuration file +@section Using configuration file +@anchor{#using-configuration-file} +@strong{~/.pinky} is the location of the configuration file. It uses the +same short and long command line options. + +I do advise you to use the long options syntax. + +If any option depends on argument, don't put any space between the +option and the argument. + +Use one option per line. Contrary to your shell, the ``parser'' won't +expand ~/my_script.pl to point to /home/sweethome/my_script.pl + +@verbatim +--weather=London,uk +--coresload +--cputemp +--ramperc +--driveperc +--packages +--kernel +--voltage +--fans +--mobo +--mobotemp +--perl=/home/sweethome/my_script.pl +@end verbatim + +Execute the program without supplying any command line options and it +will parse the configuration file. + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex + +@node Linux Mandatory requirements +@section Linux Mandatory requirements +@anchor{#linux-mandatory-requirements} +@itemize +@item +gcc/clang +@item +glibc +@item +autoconf +@item +automake +@item +m4 +@item +gawk +@item +perl +@end itemize + +@node *BSD Mandatory requirements +@section *BSD Mandatory requirements +@anchor{#bsd-mandatory-requirements} +@itemize +@item +gcc/clang +@item +autoconf +@item +automake +@item +autoconf-wrapper +@item +automake-wrapper +@item +autoconf-archive +@item +argp-standalone +@item +libtool +@item +m4 +@item +gawk +@item +perl +@end itemize + +Some llvm and gcc versions will not check for headers and libraries in +/usr/local, if that's the case for you, you should export the following +environment variables: + +@verbatim +export LDFLAGS='-L/usr/local/lib' +export CFLAGS='-I/usr/local/include' +@end verbatim + +After editing the wrong prototype I managed to stumble upon a bug in +OpenBSD's own libc. + +@strong{Warning !!! OpenBSD users !!!} + +The majority of SCN* macros differs from their PRI* cousins. And I +cannot guarantee the accuracy of fixed width integers when OpenBSD own +libc managed to use different format specifiers. Read +extra/misc/openbsd_bugs.md for more details. + +@node Opt-in requirements +@section Opt-in requirements +@anchor{#opt-in-requirements} +Linux camp: + +The internet related options rely on headers provided iproute2. By +default the program will try to compile with those headers included. If +for any reason you would like to compile the program without internet +related options, then pass @strong{--without-net} to configure. + +@itemize +@item +iproute2 +@end itemize + +wifi/wireless chipsets supporting mac80211/cfg80211: + +@itemize +@item +libnl (>= 3.0) +@item +pkg-config +@end itemize + +In Gentoo there are two versions of pkg-config. The first one is named +dev-util/pkgconfig and the second one is dev-ruby/pkg-config. In order +to use the first one, you'll have to export the pkg-config path to the +following environment variable: + +@verbatim +export PKG_CONFIG_PATH=/usr/bin/pkg-config +@end verbatim + +Then pass @strong{--with-libnl} to configure. + +To get the NIC vendor and model names: + +@itemize +@item +pciutils +@end itemize + +Alternative way to obtain data from the sensors: + +@itemize +@item +lm_sensors +@end itemize + +To read the drive temperature from S.M.A.R.T @strong{--with-drivetemp}: + +@itemize +@item +hddtemp +@item +curl +@end itemize + +To read the drive temperature from S.M.A.R.T +@strong{--with-drivetemp-light}: + +@itemize +@item +hddtemp +@end itemize + +The ``light'' version does not rely on curl, and will not force -O0 +CFLAGS. + +@verbatim +# --with-drivetemp-light +0.00s user 0.00s system 15% cpu 0.006 + +# --with-drivetemp +0.01s user 0.00s system 72% cpu 0.008 +@end verbatim + +Try running hddtemp to see if it detects your drive, depending if it has +temperature sensor in first place: + +@verbatim +sudo hddtemp /dev/sda + +WARNING: Drive /dev/sda doesn't appear in the database of supported drives +WARNING: But using a common value, it reports something. +WARNING: Note that the temperature shown could be wrong. +WARNING: See --help, --debug and --drivebase options. +WARNING: And don't forget you can add your drive to hddtemp.db +/dev/sda: Corsair Force GT: 23°C or °F +@end verbatim + +The message is pretty clear ``don't forget to add your drive to +hddtemp.db'', first run the debug command to see which field is +responsible to report your drive temperature, it should be in the range +of 190 - 200: + +@verbatim +# Copy the Model: line + +sudo hddtemp --debug /dev/sda + +================= hddtemp 0.3-beta15 ================== +Model: Corsair Force GT + +field(1) = 0 +field(5) = 0 +field(9) = 253 +field(12) = 237 +field(171) = 0 +field(172) = 0 +field(174) = 147 +field(177) = 1 +field(181) = 0 +field(182) = 0 +field(187) = 0 +field(194) = 22 +field(195) = 0 +field(196) = 0 +field(201) = 0 +field(204) = 0 +field(230) = 100 +field(231) = 0 +field(233) = 130 +field(234) = 216 +field(241) = 216 +field(242) = 151 +@end verbatim + +Open up @strong{/usr/share/hddtemp/hddtemp.db} and append the Model: +line that you copied earlier with the correct field that reports your +drive temperature. + +@verbatim +"Corsair Force GT" 194 C "Corsair Force GT 120GB SSD" +@end verbatim + +Next run hddtemp in daemon mode so we can request the temperature back: + +@verbatim +sudo hddtemp -d /dev/sda +@end verbatim + +Open up your browser and navigate to 127.0.0.1:7634 and you'll get +instant temperature report back to you. + +The ``init'' lock-in for those of you that cannot choose between udev or +eudev puts me in position not rely on libatasmart, regardless how neat +the library is. There is stripped example program in extra/misc/skdump.c +if you are curious to check and test libatasmart. + +Linux camp end. + +To read the drive temperature from S.M.A.R.T @strong{--with-smartemp}: + +@itemize +@item +smartmontools +@end itemize + +smartmontools are not mandatory in OpenBSD, @code{atactl} does the same +job. + +Execute the following command as root @code{visudo} and append: + +@verbatim +# 'frost' is my computer username +frost ALL=NOPASSWD:/usr/sbin/smartctl +@end verbatim + +Copy the code from extra/scripts/drive-temperature.sh or @code{exec} it +from @strong{xinitrc} or the script used to start your DE/WM. + +To extend pinkybar with your own crafted perl/python/ruby/lua script: + +@itemize +@item +perl +@item +python == 2.7 (--with-python2) +@item +python >= 3.3 (--with-python3) +@item +lua >= 5.1 +@item +ruby >= 2.0 and pkg-config +@end itemize + +Have a look at extra/scripts/pinky.@{py,pl,ruby,lua@}, they serve as +examples how to write the most basic scripts in order to extend pinkybar +in python/perl/ruby/lua. You can use the 3 languages simultaneously. + +Please, please do @strong{NOT} export or set PYTHONPATH on it's own +line. + +@code{WRONG}: + +@verbatim +export PYTHONPATH=/meh +pinkybar --python my_script +@end verbatim + +@code{WRONG}: + +@verbatim +PYTHONPATH=/meh +pinkybar --python my_script +@end verbatim + +Correct PYTHONPATH usage: + +@verbatim +# ~/chewbacca is the path where pinky.py resides +# ~/chewbacca/pinky.py + +# python2 +PYTHONPATH=~/chewbacca ~/pinkybar --python pinky + +# python3 +# executed only once +fuNky=$(python3 -c 'import sys;print(":".join([x for x in sys.path]))') + +# executed in a loop +PYTHONPATH=$fuNky:~/chewbacca ~/pinkybar --python pinky +@end verbatim + +@strong{--with-perl}: + +@verbatim +~/pinkybar --perl ~/chewbacca/pinky.pl +@end verbatim + +@strong{--with-ruby}: + +@verbatim +~/pinkybar --ruby ~/chewbacca/pinky.rb +@end verbatim + +@strong{--with-lua}: + +Non byte-compiled script: + +@verbatim +~/pinkybar --lua ~/chewbacca/pinky.lua +@end verbatim + +Once done editing your script, you can byte-compile it: + +@verbatim +luac -o pinky.luac pinky.lua +~/pinkybar --lua ~/chewbacca/pinky.luac # <-- .luac and not .lua +@end verbatim + +To get the sound volume level: + +@itemize +@item +alsa-utils +@item +alsa-lib +@end itemize + +Then pass @strong{--with-alsa} to configure. + +*BSD users can use the baked OSS instead, pass @strong{--without-alsa +--with-oss} to configure instead. + +To output the data to the terminal using the ncurses library: + +@itemize +@item +ncurses +@end itemize + +To get the vendor and model name of your cdrom/dvdrom/blu-ray: + +@itemize +@item +libcdio +@item +libcddb +@end itemize + +In linux @strong{--without-dvd} will still compile the program with dvd +support. Except it will be limited only to dvd support, it will try to +parse the sr0 vendor and model name detected by the kernel. + +The weather related options, please go back and read @strong{Don't just +rush to register yourself}: + +@itemize +@item +curl +@item +gzip +@end itemize + +@strong{Warning, I'm not responsible for any lawsuit towards you, +neither encourage you to pirate content that is not licensed as free +and/or for fair use.} + +To see the currently played song name @strong{--with-mpd}: + +Server side: + +@itemize +@item +mpd (can be build with soundcloud support) +@end itemize + +Client side: + +@itemize +@item +libmpdclient +@item +mpc/ncmpc/ncmpcpp, @uref{http://mpd.wikia.com/wiki/Clients,and the rest} +@end itemize + +To see the currently played song name @strong{--without-mpd}: + +@itemize +@item +cmus +@end itemize + +The ``soundcloud'' alternative that is supported in cmus and your mpd +client will be to download @strong{.m3u/.pls} files according to the +@uref{https://www.internet-radio.com,radio stream station} that you are +interested to listen. + +The FreeBSD users will notice that ``mpd'' is named ``musicpd''. + +If you've never used mpd before copy the example configuration from +extra/mpd according to your OS. + +Keep an eye on the @strong{log file size} if you are using raspberry pi +(or equivalent device) that streams the music, make sure that it's +deleted automatically if it exceeds some pre-defined size. + +@iftex +@bigskip@hrule@bigskip +@end iftex +@ifnottex +------------------------------------------------------------------------ +@end ifnottex + +@node WM specific requirements +@section WM specific requirements +@anchor{#wm-specific-requirements} +If you would like the output to be shown in your Window Manager, those +are the following requirements: + +for non-dwm WM: + +@itemize +@item +dzen2 +@end itemize + +for dwm: + +@itemize +@item +libx11 +@item +xorg-server +@end itemize + +use @strong{--without-colours} to skip the following step: + +@itemize +@item +dwm compiled with statuscolor patch. The colours in use are specified in +your dwm config.h +@end itemize + +@node Wish list +@section Wish list +@anchor{#wish-list} +It would be great if I had *BSD compatible usb wifi dongle or wireless +pci adapter to add wifi options in pinky-bar. + +@node REPORTING BUGS +@chapter REPORTING BUGS +@anchor{#reporting-bugs} +Report bugs to https://gitlab.com/void0/pinky-bar + +@node COPYRIGHT +@chapter COPYRIGHT +@anchor{#copyright} +Copyright (c) 2016 Aaron Caffrey@* +Free use of this software is granted under the terms of the GNU General +Public License (GPL). + +@bye diff --git a/extra/FreeBSD/Makefile b/extra/FreeBSD/Makefile new file mode 100644 index 0000000..c26795f --- /dev/null +++ b/extra/FreeBSD/Makefile @@ -0,0 +1,53 @@ +# Created by: Aaron Caffrey +# $FreeBSD$ + +PORTNAME= pinky-bar +PORTVERSION= 1.0.0 +CATEGORIES= sysutils + +MAINTAINER= wifiextender@null.horse +COMMENT= Gather some system information + +USE_GITHUB= yes +GH_ACCOUNT= wifiextender +GH_PROJECT= pinky-bar +GH_TAGNAME= 4252f74 + +GNU_CONFIGURE= yes +USE_XORG+= x11 +LDFLAGS+= -L${LOCALBASE}/lib +CFLAGS+= -I${LOCALBASE}/include +CONFIGURE_ARGS= --without-pci --without-sensors +CONFIGURE_ARGS+= --prefix=/usr/local icons=/usr/local/share/icons/xbm_icons +LIB_DEPENDS= libargp.so:devel/argp-standalone +BUILD_DEPENDS= git:devel/git tar:archivers/gtar gzip:archivers/gzip +BUILD_DEPENDS+= gm4:devel/m4 libtool:devel/libtool autoconf:devel/autoconf +BUILD_DEPENDS+= automake:devel/automake bash:shells/bash + +OPTIONS_DEFINE= X11 ALSA OSS NET DVD MPD COLOURS NCURSES +OPTIONS_DEFAULT= OSS +X11_CONFIGURE_WITH= x11 +ALSA_CONFIGURE_WITH= alsa +OSS_CONFIGURE_WITH= oss +NET_CONFIGURE_WITH= net +DVD_CONFIGURE_WITH= dvd +MPD_CONFIGURE_WITH= mpd +NCURSES_CONFIGURE_WITH= ncurses +COLOURS_CONFIGURE_WITH= colours + +X11_DESC= Enable it if you are using dwm +ALSA_DESC= To get the sound volume level +OSS_DESC= The default way to get the sound volume level +NET_DESC= Enable the internet related options +DVD_DESC= To get the cdrom/dvdrom vendor and model names +MPD_DESC= To see the currently played song name +NCURSES_DESC= Output the data to the terminal using ncurses +COLOURS_DESC= Colorize the output data + +X11_LIB_DEPENDS= libX11.so:x11/xorg +ALSA_LIB_DEPENDS= libasound.so:audio/alsa-lib +DVD_LIB_DEPENDS= libcdio.so:sysutils/libcdio libcddb.so:audio/libcddb +NCURSES_LIB_DEPENDS= libncurses.so:devel/ncurses +MPD_LIB_DEPENDS= libmpdclient.so:audio/libmpdclient + +.include diff --git a/extra/FreeBSD/pkg-descr b/extra/FreeBSD/pkg-descr new file mode 100644 index 0000000..bbc8c3a --- /dev/null +++ b/extra/FreeBSD/pkg-descr @@ -0,0 +1 @@ +Gather some system information and show it in this statusbar program, not tied to any Window Manager, terminal multiplexer, etc. diff --git a/extra/FreeBSD/scripts/post-extract b/extra/FreeBSD/scripts/post-extract new file mode 100644 index 0000000..9ff3239 --- /dev/null +++ b/extra/FreeBSD/scripts/post-extract @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Copyright 08/26/2016 +# Aaron Caffrey https://github.com/wifiextender + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +cd work/pinky-bar-* + +chmod +x bootstrap +./bootstrap freebsd + +mkdir -p -m 755 '/usr/local/share/icons/xbm_icons' +install -D -m644 xbm_icons/* '/usr/local/share/icons/xbm_icons' + +cd ../.. diff --git a/extra/FreeBSD/scripts/post-fetch b/extra/FreeBSD/scripts/post-fetch new file mode 100644 index 0000000..7af2827 --- /dev/null +++ b/extra/FreeBSD/scripts/post-fetch @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Copyright 08/26/2016 +# Aaron Caffrey https://github.com/wifiextender + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +make makesum diff --git a/extra/FreeBSD/scripts/post-install b/extra/FreeBSD/scripts/post-install new file mode 100644 index 0000000..8a877d7 --- /dev/null +++ b/extra/FreeBSD/scripts/post-install @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# Copyright 08/26/2016 +# Aaron Caffrey https://github.com/wifiextender + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +echo +echo +echo 'Please read the README' +echo 'https://github.com/wifiextender/pinky-bar/blob/master/README.md' +echo +echo diff --git a/extra/Gentoo/app-admin/pinky-curses/pinky-curses-9999.ebuild b/extra/Gentoo/app-admin/pinky-curses/pinky-curses-9999.ebuild new file mode 100644 index 0000000..c7452b3 --- /dev/null +++ b/extra/Gentoo/app-admin/pinky-curses/pinky-curses-9999.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2016 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +EAPI=6 + +EGIT_REPO_URI="https://gitlab.com/void0/pinky-bar.git" + +inherit git-r3 + +DESCRIPTION="Standalone statusbar program utilizing ncurses" +HOMEPAGE="https://gitlab.com/void0/pinky-bar" + +LICENSE="GPL-2" +SLOT="0" + +DEPEND=" + sys-devel/m4 + sys-apps/gawk + sys-devel/autoconf + >=sys-devel/automake-1.14.1 +" +RDEPEND=" + sys-libs/ncurses +" + +src_prepare() { + default + + einfo 'Generating Makefiles' + chmod +x bootstrap + ./bootstrap 'gentoo' +} + +src_configure() { + econf \ + --without-alsa \ + --without-x11 \ + --without-mpd \ + --without-net \ + --without-pci \ + --without-dvd \ + --without-sensors \ + --without-weather \ + --with-ncurses \ + --with-colours +} + +src_compile() { + emake 'ncurses' +} + +src_install() { + newbin "${S}"/src/ncurses pinky-curses +} + +pkg_postinst() { + einfo 'The program is not tied to pinky-bar. Heres some short introduction:' + einfo 'Depending whether you enabled the colours: ^B - Blue , ^M - Magenta , ^Y - Yellow' + einfo 'And here is the complete usage, copy and paste ready. Press CTRL + C to stop the program.' + einfo 'while true; do echo "^BOh ^Mhello ^Ydear";sleep 1;done | /usr/bin/pinky-curses' +} diff --git a/extra/Gentoo/app-admin/pinky/metadata.xml b/extra/Gentoo/app-admin/pinky/metadata.xml new file mode 100644 index 0000000..d82fc32 --- /dev/null +++ b/extra/Gentoo/app-admin/pinky/metadata.xml @@ -0,0 +1,29 @@ + + + + + office@gentoo.org + Gentoo Office project + + + pinky-bar + + + Enable it if you are using dwm. + To get the sound volume level. + Enable the internet related options + Enable the wifi related options regarding chipsets supporting the cfg80211,mac80211 modules + To get the NIC vendor and model names + To get the cdrom dvdrom vendor and model names + Alternative way to obtain data from the sensors + Output the data to the terminal using the ncurses library + Colorize the output data + The temperature outside + To see the currently played song name + Read the drive temperature from S.M.A.R.T + Read the drive temperature from S.M.A.R.T light version + Read the drive temperature from S.M.A.R.T + Extend pinkybar with your own crafted scripts written in perl, stored in /usr/share/pinkysc/pinky.pl + Extend pinkybar with your own crafted scripts written in python, stored in /usr/share/pinkysc/pinky.py + + diff --git a/extra/Gentoo/app-admin/pinky/pinky-bar-9999.ebuild b/extra/Gentoo/app-admin/pinky/pinky-bar-9999.ebuild new file mode 100644 index 0000000..6244270 --- /dev/null +++ b/extra/Gentoo/app-admin/pinky/pinky-bar-9999.ebuild @@ -0,0 +1,123 @@ +# Copyright 1999-2016 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +EAPI=6 + +EGIT_REPO_URI="https://gitlab.com/void0/pinky-bar.git" + +inherit git-r3 + +DESCRIPTION="Gather some system information and show it in this statusbar program" +HOMEPAGE="https://gitlab.com/void0/pinky-bar" + +LICENSE="GPL-2" +SLOT="0" +IUSE="x11 alsa +net libnl +pci dvd sensors ncurses colours weather mpd drivetemp drivetemp-light smartemp perl python2" + +DEPEND=" + sys-devel/m4 + sys-apps/gawk + sys-devel/autoconf + >=sys-devel/automake-1.14.1 +" +RDEPEND=" + alsa? ( media-libs/alsa-lib ) + x11? ( x11-libs/libX11 ) + net? ( sys-apps/iproute2 ) + libnl? ( >=dev-libs/libnl-3.2.27 dev-util/pkgconfig ) + pci? ( sys-apps/pciutils ) + dvd? ( dev-libs/libcdio ) + sensors? ( sys-apps/lm_sensors ) + ncurses? ( sys-libs/ncurses ) + weather? ( net-misc/curl app-arch/gzip ) + mpd? ( media-sound/mpd media-libs/libmpdclient ) + drivetemp? ( net-misc/curl app-admin/hddtemp ) + drivetemp-light? ( app-admin/hddtemp ) + smartemp? ( sys-apps/smartmontools ) + python2? ( dev-lang/python:2.7= ) +" +REQUIRED_USE=" + x11? ( !ncurses ) + ncurses? ( !x11 ) + drivetemp? ( !smartemp ) + drivetemp-light? ( !smartemp ) + smartemp? ( !drivetemp !drivetemp-light ) +" + +pkg_setup() { + if use weather + then + einfo 'Currently, the weather USE flag will default to London,uk' + einfo 'To specify other country and town youll have to supply them as variable.' + einfo 'Here is how: # TWN="London,uk" USE="weather" emerge -a ...' + fi +} + +src_prepare() { + default + + einfo 'Generating Makefiles' + chmod +x bootstrap + ./bootstrap 'gentoo' +} + +src_configure() { + export PKG_CONFIG_PATH=/usr/bin/pkg-config + + econf \ + $(use_with x11) \ + $(use_with alsa) \ + $(use_with net) \ + $(use_with libnl) \ + $(use_with pci) \ + $(use_with dvd) \ + $(use_with sensors) \ + $(use_with ncurses) \ + $(use_with colours) \ + $(use_with weather) \ + $(use_with mpd) \ + $(use_with drivetemp) \ + $(use_with drivetemp-light) \ + $(use_with smartemp) \ + $(use_with perl) \ + $(use_with python2) \ + perl_script='/usr/share/pinkysc/pinky.pl' \ + python_script='/usr/share/pinkysc/pinky.py' \ + api_town="${TWN:-London,uk}" \ + api_key='28459ae16e4b3a7e5628ff21f4907b6f' \ + icons='/usr/share/icons/xbm_icons' +} + +src_compile() { + emake 'all' +} + +src_install() { + if use colours && ! use x11 && ! use ncurses + then + insinto /usr/share/icons/xbm_icons + doins "${S}"/extra/xbm_icons/* + fi + + if use perl || use python2 + then + insinto /usr/share/pinkysc + doins "${S}"/extra/scripts/pinky.{py,pl} + fi + + emake DESTDIR="${D}" install +} + +pkg_postinst() { + use ncurses && \ + einfo 'You can combine the output from this program with pinky-curses' + + use perl && \ + einfo 'The perl script resides in /usr/share/pinkysc/pinky.pl' + + use python2 && \ + einfo 'The python2 script resides in /usr/share/pinkysc/pinky.py' + + einfo 'Please read the program man page' +} diff --git a/extra/bash_zsh/_pinkybar b/extra/bash_zsh/_pinkybar new file mode 100644 index 0000000..e18eda0 --- /dev/null +++ b/extra/bash_zsh/_pinkybar @@ -0,0 +1,90 @@ +#compdef pinkybar + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# zsh completion +# Cross-platform supported opts: + +_arguments -s -S -A '-*' : \ +'-M[song filename]' \ +'-W[song track name]' \ +'-x[song artists names]' \ +'-X[song title]' \ +'-y[song album name]' \ +'-Y[song date]' \ +'-c[summed up cores load]' \ +'-L[individual core load]' \ +'-T[cpu temp]' \ +'-C[max cpu clock speed]' \ +'-I[long and detailed cpu info]' \ +'-r[used ram]' \ +'-J[total ram]' \ +'-K[free ram]' \ +'-l[shared ram]' \ +'-o[buffered ram]' \ +'-s[used drive storage]' \ +'-n[total drive storage]' \ +'-N[free drive storage]' \ +'-O[available drive storage]' \ +'-g[remaining battery charge]' \ +'-z[dvdrom vendor and model names]' \ +'-S[disk I/O, requires argument: sda]' \ +'-p[num of installed packages]' \ +'-P[kern name]' \ +'-Q[network node hostname]' \ +'-R[kern release]' \ +'-u[kern version]' \ +'-k[machine arch.]' \ +'-q[combined kern name and version]' \ +'-U[uptime]' \ +'-w[average load]' \ +'-v[voltage]' \ +'-f[fans speed in RPM]' \ +'-m[mobo name and vendor]' \ +'-d[mobo temp.]' \ +'-V[sound volume level]' \ +'-t[current time]' \ +'-a[ip addr, requires argument eth0]' \ +'-b[consumed internet so far, requires argument eth0]' \ +'-i[current download and upload speeds, requires argument eth0]' \ +'-A[mac addr, requires argument eth0]' \ +'-B[subnet mask, requires argument eth0]' \ +'-D[broadcast addr, requires argument eth0]' \ +'-E[website ip lookup, requires argument eth0]' + + +# Linux opts +# +# '-F[vendor and model name of ur drive, requires argument sda]' \ +# '-G[NIC vendor and model names, requires argument eth0]' \ +# '--nicinfo[NIC driver, requires argument eth0]' \ +# '-H[NIC version, requires argument eth0]' \ +# '-e[NIC links speed, requires argument eth0]' \ +# '-j[NIC firmware, requires argument eth0]' \ +# '-h[wifi essid, requires argument eth0]' + + +# FreeBSD and OpenBSD opts +# +# '-j[NIC gateway addr, requires argument re0]' \ +# '-Z[used drive swap in MB]' \ +# '-F[used drive swap in percentage]' \ +# '-h[total drive swap]' \ +# '-H[available drive swap]' + +# OpenBSD opts +# +#'-l[used ram in MB]' diff --git a/extra/bash_zsh/pinkybar b/extra/bash_zsh/pinkybar new file mode 100644 index 0000000..27f2341 --- /dev/null +++ b/extra/bash_zsh/pinkybar @@ -0,0 +1,40 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# bash completion + +_pinky() { + local cur + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + + opts1='-a -b -c -d -e -f -g -h -i -j -k -l -m -n -o -p -q -r -s -t -u -v -w -x -y -z' + opts2='-A -B -C -D -E -F -G -H -I -J -K -L -M -N -O -P -Q -R -S -T -U -V -W -X -Y -Z' + opts3='--mpd --mpdtrack --mpdartist --mpdalbum --cpu --coresload --cputemp --cpuspeed' + opts3+='--cpuinfo --ramperc --ramtotal --ramfree --ramshared --rambuffer --driveperc' + opts3+='--drivetemp --drivetotal --drivefree --driveavail --battery --dvdstr --statio' + opts3+='--packages --kernsys --kernode --kernrel --kernver --kernarch --kern --perl' + opts3+='--python --weather --uptime --loadavg --voltage --fans --mobo --mobotemp --time' + opts3+='--ipaddr --bandwidth --iface --ipmac --ipmask --ipcase --iplookup --drivemodel' + opts3+='--nicinfo --nicdrv --nicver --iplink --nicfw --wifiname' + + case "$cur" in + -*) COMPREPLY=( $(compgen -W "${opts1} ${opts2} ${opts3}" -- "${cur}") ) + ;; + esac + + return 0 +} +complete -F _pinky -o filenames pinkybar diff --git a/extra/deprecated/Makefile.skel b/extra/deprecated/Makefile.skel new file mode 100644 index 0000000..3b05ba8 --- /dev/null +++ b/extra/deprecated/Makefile.skel @@ -0,0 +1,87 @@ +# 10/29/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# The GNU/Make use in here is to +# the cover our back and do most of +# the heavy lifting for us. +# When dealing with different operating +# systems the things get pretty ugly quickly. +# I did learned my lesson with the previous bash +# bootstrap script, including the difference +# between BSD and GNU sed versions. + + +define stay_portable + $(shell perl -Mstrict -Mwarnings -e $(1)) +endef + +define stay_portable2 + $(shell perl -Mstrict -Mwarnings -pi -e $(1) $(2)) +endef + +define reflace + $(call stay_portable2,'if ($$. == 10) {$$_="";print "$(1)\n";}',$(2)) +endef + +define reflace2 + $(call stay_portable2,'s|$(1)|$(2)|;',$(3)) +endef + +define reflace3 + $(call stay_portable2,'s|$(1)|$(2)|;s|$(3)|$(4)|;',$(5)) +endef + + +BSDCF := -D_DEFAULT_SOURCE -L/usr/local/lib +POSIXCF := -D_POSIX_C_SOURCE=200112L +BSDLIBS := +AMCF := +SRCTOAPPEND := +OSENTERED := $(strip $(call stay_portable,'print uc "${ARG1}";')) +DEFTITS := m4_define\(\[OSENTERED\], \[$(OSENTERED)\]\) + + +# make ARG1=bar logic +ifeq ($(findstring FREE,$(OSENTERED)),FREE) + BSDLIBS += -largp -ldevstat + AMCF += $(BSDCF) + DEFTITS += m4_define\(\[FREEBZD\], \[tits\]\) + SRCTOAPPEND += freebsd_functions.c include/freebzd.h + +else + ifeq ($(findstring OPEN,$(OSENTERED)),OPEN) + BSDLIBS += -largp -lossaudio + AMCF += $(BSDCF) + DEFTITS += m4_define\(\[OPENBZD\], \[forSure\]\) + SRCTOAPPEND += openbsd_functions.c include/openbzd.h + + else + AMCF += $(POSIXCF) + DEFTITS += m4_define\(\[LINUKS\], \[cryMeAriver\]\) + SRCTOAPPEND += linux_functions.c + + endif +endif + + +all: + $(call reflace,$(DEFTITS),configure.ac) + $(call reflace3,{amCF},$(AMCF),{srcFiles},$(SRCTOAPPEND),src/Makefile.am) + $(call reflace2,{bzdlibs},$(BSDLIBS),src/Makefile.am) + # ... + +.PHONY: all diff --git a/extra/deprecated/README.md b/extra/deprecated/README.md new file mode 100644 index 0000000..ee6d4cf --- /dev/null +++ b/extra/deprecated/README.md @@ -0,0 +1,5 @@ +The bash bootstrip script served well until I ported pinky-bar to \*BSD, as I had to make bash as dependency. + +Second attemp was with GNU make and sed, and the difference between GNU and BSD sed version made me to pull out my hair. So I re-wrote the sed macros to use perl instead. + +The third and last attemp - deprecate GNU make, and use only perl. Since it high-level language it will be portable across different operating systems, and the bonus is that perl will be most likely installed out of the box. diff --git a/extra/deprecated/bootstrap b/extra/deprecated/bootstrap new file mode 100644 index 0000000..4b7431e --- /dev/null +++ b/extra/deprecated/bootstrap @@ -0,0 +1,262 @@ +#!/usr/bin/env bash + +# 07/06/2015, 07/18/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +declare -a _bases=( + 'archlinux' + 'debian' + 'gentoo' + 'slackware' + 'rhel' + 'frugalware' + 'angstrom' + 'freebsd' + 'openbsd' +) + +_printf_err() { + printf '%s\n' "try again with: bash ${0} basedistro" + printf '%s ' "Bases: ${_bases[@]}" + printf '\n' +} + +_gen_files() { + progName='pinkybar' + progVer='1.0.0' + bsdLibs='' + osEntered="${1,,}" + bsdCF='-D_DEFAULT_SOURCE -L/usr/local/lib' + posixCF='-D_POSIX_C_SOURCE=200112L' + declare -a srcToAppend configure_ac main_makefile + declare -a src_makefile src_libs_to_add src_files + + case "${osEntered}" in + freebsd) + bsdLibs='-largp -ldevstat' + amCF="${bsdCF}" + defTits='m4_define([FREEBZD], [tits])' + srcToAppend=( + 'freebsd_functions.c' + 'include/freebzd.h' + ) + ;; + openbsd) + bsdLibs='-largp -lossaudio' + amCF="${bsdCF}" + defTits='m4_define([OPENBZD], [forSure])' + srcToAppend=( + 'openbsd_functions.c' + 'include/openbzd.h' + ) + ;; + *) + amCF="${posixCF}" + defTits='m4_define([LINUKS], [cryMeAriver])' + srcToAppend=( + 'linux_functions.c' + ) + ;; + esac + + + # to strip get_packs() at compile time, + # also instead using more hard-coded macros + # let the shell enumerate them for us + declare -a enumDistros=() + for x in {0..8} + do + enumDistros[${x}]="AC_DEFINE_UNQUOTED([${_bases[${x}]^^}],[${x}],[trololo enum generator])" + + [[ "${osEntered}" == "${_bases[${x}]}" ]] && { + distroNum="AC_DEFINE_UNQUOTED([DISTRO],[${x}],[da monster])" + } + done + + # configure.ac + configure_ac=("# This file is processed by autoconf to create a configure script + AC_INIT(["${progName}"], ["${progVer}"]) + AC_CONFIG_AUX_DIR([temp_dir]) + AC_CONFIG_MACRO_DIR([m4]) + AC_CONFIG_HEADERS([src/config.h]) + # -Werror -Wportability + AM_INIT_AUTOMAKE([1.13 -Wall no-define foreign subdir-objects dist-xz no-dist-gzip std-options]) + + AM_SILENT_RULES([yes]) + "${defTits}" + + # With the addition of more runtime compile and + # link tests, this option is no longer necessary. + # Any compiler and C library succeeding to pass the + # tests will be able to compile and run the + # program flawlessly. + # If you use OpenBSD uncomment the AC_PROG_CC([]) + # line below. Make sure that you have the latest gcc/llvm + # AC_PROG_CC([egcc clang llvm-gcc gcc]) + + AC_PROG_CC_C99 + AC_C_CONST + AC_HEADER_STDC + AM_PROG_CC_C_O + + # AM_EXTRA_RECURSIVE_TARGETS([ncurses]) + + # The linker flags tests in m4 dir + TEST_SOME_FUNCS + TEST_NET + TEST_PCI + TEST_X11 + TEST_ALSA + TEST_MPD + TEST_DVD + TEST_SENSORS + TEST_TYPEZ + TEST_WEATHER + TEST_PERL + TEST_PYTHON + TEST_CFLAGZ + + # Definitions + "${distroNum}" + "${enumDistros[@]}" + + AC_CONFIG_FILES([ + Makefile + src/Makefile + ]) + + AC_OUTPUT + + echo + echo 'Now type \"make\" and \"make install\" afterwards' + echo") + + + # Makefile.am + main_makefile=(' + SUBDIRS = src + + dist_man_MANS = doc/pinkybar.1 + + # Optional, create and install + # the pinkybar info document + # info_TEXINFOS = doc/pinkybar.texi + # MAKEINFOFLAGS = --no-validate --no-warn --force + + # To satisfy make dist + EXTRA_DIST = \ + src/ncurses.c \ + bootstrap \ + README.md \ + .gitignore \ + m4 \ + doc \ + extra + +# using 1 tab +ncurses: + @cd src && $(MAKE) ncurses + +man: + @cd doc && $(MAKE) man + +info: + @cd doc && $(MAKE) info + ') + + + # src/Makefile.am + src_files=( + 'main.c' + 'cpu.c' + 'common.c' + 'sound.c' + 'options.c' + 'net.c' + 'weather.c' + 'smart.c' + 'perl.c' + 'python.c' + + 'prototypes/cpu.h' + 'prototypes/common.h' + 'prototypes/sound.h' + 'prototypes/net.h' + 'prototypes/functions.h' + 'prototypes/options.h' + 'prototypes/weather.h' + 'prototypes/smart.h' + 'prototypes/perl.h' + 'prototypes/python.h' + + 'include/headers.h' + 'include/options_constants.h' + 'include/functions_constants.h' + 'include/non_x11_colours.h' + 'include/x11_colours.h' + 'include/options_generator.h' + + "${srcToAppend[@]}" + ) + + # The syntax is autotools specific + src_libs_to_add=( + '$(X_LIBS) $(ALSA_LIBS)' + '$(MPD_LIBS) $(PCI_LIBS)' + '$(DVD_LIBS) $(SENSORS_LIBS)' + '$(CURL_LIBS) $(LIBNL_LZ)' + '$(PERL_LZ) $(PYTHON_LZ)' + ) + + # Do not pass more definitions to AM_CFLAGS + # Think of the line limit + src_makefile=('AM_CFLAGS = '${amCF}' \ + -I/usr/local/include $(LIBNL_CF) $(PERL_CF) $(PYTHON_CF) + + bin_PROGRAMS = '${progName}' + + EXTRA_PROGRAMS = ncurses + ncurses_SOURCES = ncurses.c + ncurses_LDADD = -lncurses + + '${progName}'_LDADD = '${src_libs_to_add[@]}' '${bsdLibs}' + '${progName}'_SOURCES = '${src_files[@]}' + ') + + + cat < configure.ac +${configure_ac[@]} +EOF + + cat < Makefile.am +${main_makefile[@]} +EOF + + cat < src/Makefile.am +${src_makefile[@]} +EOF + + + # do not remove nor edit + autoreconf --install --force +} + + +[[ -z "${1}" ]] && _printf_err "$@" || { + [[ " ${_bases[@]} " =~ " ${1,,} " ]] && \ + _gen_files "$@" || _printf_err "$@" +} diff --git a/extra/misc/openbsd_bugs.md b/extra/misc/openbsd_bugs.md new file mode 100644 index 0000000..07f2384 --- /dev/null +++ b/extra/misc/openbsd_bugs.md @@ -0,0 +1,62 @@ +The majority of SCN* macros differs from their PRI* cousins. When you define unsigned int you should always follow the C standards that made it clear what format specifier unsigned int should use, unfortunately the majority of OpenBSD's own libc SCN* macros managed not to follow the standard. "hu" and "hhu" are not unsigned int format specifiers, tried to get in touch with OpenBSD devs, reported this bug but no one responded. + +If they wanted to use specific integer type, then they should define it as such earlier. 8 bit integer is the smallest integer type in existance and for sure it cannot represent the 32 bit UINT_MAX number. glibc uses the maximum unsigned char and signed char for all int8_t, int_least8_t, int_fast8_t and uint8_t, uint_least8_t, uint_fast8_t , and yes glibc defines corrent PRI* and SCN* format specifier macros to match that integer type. + +It's not like to mistake the float format specifier with the "double" one. + +It's dirty trick to let the complier do the conversion for you to lower the integer type and not follow the standards to define it as such earlier. + +Go ahead and read sections 13.2 and 13.2.1 https://www.gnu.org/software/autoconf/manual/autoconf.html#Integer-Overflow + +The definitions in OpenBSD own libc: + +```cpp +/* machine/_types.h */ +typedef unsigned int __uint32_t; + +typedef __uint32_t __uint_fast8_t; +typedef __uint32_t __uint_fast16_t; + +/* stdint.h */ +typedef __uint_fast8_t uint_fast8_t; +typedef __uint_fast16_t uint_fast16_t; + +/* inttypes.h */ +#define PRIuFAST8 "u" /* uint_fast8_t */ +#define SCNuFAST8 "hhu" /* uint_fast8_t */ + +#define PRIuFAST16 "u" /* uint_fast16_t */ +#define SCNuFAST16 "hu" /* uint_fast16_t */ +``` + +Sample program to simulate the bug: + +```cpp +#include +#include +#include + +int main(void) { + char acc[] = "Remaining: 99000"; + uint_fast8_t cur = 0, started = 99000; + + printf("%s\n", acc); + if (EOF == (sscanf(acc, "%*s %"SCNuFAST8, &cur))) { + return EXIT_FAILURE; + } + printf("%s " "%"PRIuFAST8 " %s " "%"PRIuFAST8 "\n", + "Started with: $", started, + "The current balance now: $", cur + ); + + return EXIT_SUCCESS; +} +``` + +Amusing representation of the above code: + +```cpp +unsigned long long int small_int = 240; + +printf("%hhu\n", small_int); +``` diff --git a/extra/misc/skdump.c b/extra/misc/skdump.c new file mode 100644 index 0000000..eed1762 --- /dev/null +++ b/extra/misc/skdump.c @@ -0,0 +1,38 @@ +/* + * Sample program to demonstate the usage of libatasmart +*/ + +#include +#include +#include + +#include + +int main(void) { + uint64_t mkelvin = 0; + const char *device = "/dev/sda"; + SkDisk *d = NULL; + + if (-1 == (sk_disk_open(device, &d))) { + fprintf(stderr, "Failed to open disk %s: %s\n", device, strerror(errno)); + return 1; + } + + if (-1 == (sk_disk_smart_read_data(d))) { + fprintf(stderr, "Failed to read SMART data: %s\n", strerror(errno)); + goto finish; + } + + if (-1 == (sk_disk_smart_get_temperature(d, &mkelvin))) { + fprintf(stderr, "Failed to get temperature: %s\n", strerror(errno)); + goto finish; + } + + printf("%llu\n", (unsigned long long)mkelvin); + +finish: + if (NULL != d) { + sk_disk_free(d); + } + return 0; +} diff --git a/extra/mpd/README.md b/extra/mpd/README.md new file mode 100644 index 0000000..e8453db --- /dev/null +++ b/extra/mpd/README.md @@ -0,0 +1 @@ +\*BSD users should add the "musicpd" daemon user on their own diff --git a/extra/mpd/freebsd.conf b/extra/mpd/freebsd.conf new file mode 100644 index 0000000..5aa9bbf --- /dev/null +++ b/extra/mpd/freebsd.conf @@ -0,0 +1,17 @@ +music_directory "/home/frost/music" +playlist_directory "/home/frost/music" +db_file "/tmp/mpddb" +log_file "/tmp/mpdlog" +state_file "/tmp/mpdstate" +pid_file "/tmp/mpdpid" +log_level "default" +user "musicpd" + +audio_output { + type "oss" + name "My sound card" + mixer_type "software" +} + +port "6600" +bind_to_address "127.0.0.1" diff --git a/extra/mpd/linux.conf b/extra/mpd/linux.conf new file mode 100644 index 0000000..f6a7500 --- /dev/null +++ b/extra/mpd/linux.conf @@ -0,0 +1,17 @@ +music_directory "/home/frost/music" +playlist_directory "/home/frost/music" +db_file "/tmp/mpddb" +log_file "/tmp/mpdlog" +state_file "/tmp/mpdstate" +pid_file "/tmp/mpdpid" +log_level "default" +user "mpd" + +audio_output { + type "alsa" + name "My sound card" + mixer_type "software" +} + +port "6600" +bind_to_address "127.0.0.1" diff --git a/extra/mpd/openbsd.conf b/extra/mpd/openbsd.conf new file mode 100644 index 0000000..da54218 --- /dev/null +++ b/extra/mpd/openbsd.conf @@ -0,0 +1,17 @@ +music_directory "/home/frost/music" +playlist_directory "/home/frost/music" +db_file "/tmp/mpddb" +log_file "/tmp/mpdlog" +state_file "/tmp/mpdstate" +pid_file "/tmp/mpdpid" +log_level "default" +user "musicpd" + +audio_output { + type "ao" + name "My sound card" + mixer_type "software" +} + +port "6600" +bind_to_address "127.0.0.1" diff --git a/extra/ported_or_not_included/cpu_brand.S b/extra/ported_or_not_included/cpu_brand.S new file mode 100644 index 0000000..25a55fd --- /dev/null +++ b/extra/ported_or_not_included/cpu_brand.S @@ -0,0 +1,64 @@ +/* source - https://en.wikipedia.org/wiki/CPUID */ +/* used it to port it to pinky-bar */ + +.section .data + +s0 : .asciz "Processor Brand String: %.48s\n" +err : .asciz "Feature unsupported.\n" + +.section .text + +.global main +.type main,@function +.align 32 +main: + pushq %rbp + movq %rsp, %rbp + subq $48, %rsp + pushq %rbx + + movl $0x80000000, %eax + cpuid + + cmpl $0x80000004, %eax + jl error + + movl $0x80000002, %esi + movq %rsp, %rdi + +.align 16 +get_brand: + movl %esi, %eax + cpuid + + movl %eax, (%rdi) + movl %ebx, 4(%rdi) + movl %ecx, 8(%rdi) + movl %edx, 12(%rdi) + + addl $1, %esi + addq $16, %rdi + cmpl $0x80000004, %esi + jle get_brand + +print_brand: + movq $s0, %rdi + movq %rsp, %rsi + xorb %al, %al + call printf + + jmp end + +.align 16 +error: + movq $err, %rdi + xorb %al, %al + call printf + +.align 16 +end: + popq %rbx + movq %rbp, %rsp + popq %rbp + xorl %eax, %eax + ret diff --git a/extra/ported_or_not_included/cpu_cache.S b/extra/ported_or_not_included/cpu_cache.S new file mode 100644 index 0000000..4e953ca --- /dev/null +++ b/extra/ported_or_not_included/cpu_cache.S @@ -0,0 +1,60 @@ +/* source - https://en.wikipedia.org/wiki/CPUID */ +/* used it to port it to pinky-bar */ + +.section .data + +info : .ascii "L2 Cache Size : %u KB\nLine size : %u bytes\n" +.asciz "Associativity : %02xh\n" +err : .asciz "Feature unsupported.\n" + +.section .text + +.global main +.type main,@function +.align 32 +main: + pushq %rbp + movq %rsp, %rbp + pushq %rbx + + movl $0x80000000, %eax + cpuid + + cmpl $0x80000006, %eax + jl error + + movl $0x80000006, %eax + cpuid + + movl %ecx, %eax + + movl %eax, %edx + andl $0xff, %edx + + movl %eax, %ecx + shrl $12, %ecx + andl $0xf, %ecx + + movl %eax, %esi + shrl $16, %esi + andl $0xffff,%esi + + movq $info, %rdi + xorb %al, %al + call printf + + jmp end + +.align 16 +error: + movq $err, %rdi + xorb %al, %al + call printf + +.align 16 +end: + popq %rbx + movq %rbp, %rsp + popq %rbp + xorl %eax, %eax + ret diff --git a/extra/ported_or_not_included/not_included.c b/extra/ported_or_not_included/not_included.c new file mode 100644 index 0000000..56d0167 --- /dev/null +++ b/extra/ported_or_not_included/not_included.c @@ -0,0 +1,267 @@ +/* "borrowed" from the Hacked Team */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct device_info { + struct { + char vendor[128]; + char model[128]; + char cpu[128]; + unsigned char ncpu; + } hw; + struct { + unsigned int memt; + unsigned int memf; + unsigned int diskt; + unsigned int diskf; + } stat; + struct { + char ac[16]; + unsigned char battery; + } power; + struct { + char ver[128]; + char arch[16]; + char lang[16]; + char tzname[8]; + char tzoff[8]; + } os; + struct { + char name[16]; + unsigned int uid; + unsigned int gid; + char gecos[64]; + char home[64]; + } user; + struct { + char list[1024]; + } mount; +}; + +int main(void); +void device_hw(struct device_info *di); +void device_stat(struct device_info *di); +void device_power(struct device_info *di); +void device_os(struct device_info *di); +void device_user(struct device_info *di); +void device_mount(struct device_info *di); + +int main(void) +{ + struct device_info di; + + memset(&di, 0x00, sizeof(di)); + device_hw(&di); + device_stat(&di); + device_power(&di); + device_os(&di); + device_user(&di); + device_mount(&di); + + printf("Device: %s %s\n", di.hw.vendor, di.hw.model); + printf("Processor: %u x %s\n", di.hw.ncpu, di.hw.cpu); + printf("Memory: %uMB (%u%% used)\n", di.stat.memt, 100 - di.stat.memf * 100 / di.stat.memt); + printf("Disk: %uGB (%u%% used)\n", di.stat.diskt, 100 - di.stat.diskf * 100 / di.stat.diskt); + printf("Power: AC %s - battery %%\n", di.power.ac); + printf("\n"); + printf("OS Version: Linux %s (%s)\n", di.os.ver, di.os.arch); + printf("Locale settings: %s - %s (UTC %s)\n", di.os.lang, di.os.tzname, di.os.tzoff); + printf("\n"); + printf("Mounted filesystems:\n"); + printf("%s\n", di.mount.list); + + return 0; +} + +void device_hw(struct device_info *di) +{ + FILE *fp = NULL; + char buf[128], *ptr = NULL; + + if(!(fp = fopen("/sys/devices/virtual/dmi/id/sys_vendor", "r")) || !fgets(di->hw.vendor, sizeof(di->hw.vendor), fp)) { + strncpy(di->hw.vendor, "(unknown)", sizeof(di->hw.vendor) - 1); + } + if(fp) fclose(fp); + + if(!(fp = fopen("/sys/devices/virtual/dmi/id/product_name", "r")) || !fgets(di->hw.model, sizeof(di->hw.model), fp)) { + di->hw.model[0] = '\n'; + } + if(fp) fclose(fp); + + if(di->hw.vendor[strlen(di->hw.vendor) - 1] == '\n') di->hw.vendor[strlen(di->hw.vendor) - 1] = '\0'; + while(di->hw.vendor[strlen(di->hw.vendor) - 1] == ' ') di->hw.vendor[strlen(di->hw.vendor) - 1] = '\0'; + if(di->hw.model[strlen(di->hw.model) - 1] == '\n') di->hw.model[strlen(di->hw.model) - 1] = '\0'; + while(di->hw.model[strlen(di->hw.model) - 1] == ' ') di->hw.model[strlen(di->hw.model) - 1] = '\0'; + + if(!(fp = fopen("/proc/cpuinfo", "r"))) return; + while(fgets(buf, sizeof(buf), fp)) { + if(!strncasecmp(buf, "model name", strlen("model name"))) { + if((ptr = strstr(buf, ": ") + 2)) strncpy(di->hw.cpu, ptr, sizeof(di->hw.cpu) - 1); + } else if(!strncasecmp(buf, "processor", strlen("processor"))) { + if((ptr = strstr(buf, ": ") + 2)) di->hw.ncpu = atoi(ptr) + 1; + } + } + fclose(fp); + + if((di->hw.cpu[0]) && (di->hw.cpu[strlen(di->hw.cpu) - 1] == '\n')) di->hw.cpu[strlen(di->hw.cpu) - 1] = '\0'; + + return; +} + +void device_stat(struct device_info *di) +{ + FILE *fp = NULL; + struct statvfs s; + char buf[128], *ptr = NULL; + + if((fp = fopen("/proc/meminfo", "r"))) { + while(fgets(buf, sizeof(buf), fp)) { + if(!strncasecmp(buf, "MemTotal:", strlen("MemTotal:"))) { + ptr = buf + strlen("MemTotal:"); + while(*ptr && (*ptr == ' ')) ptr++; + di->stat.memt = atoll(ptr) / 1024; + } else if(!strncasecmp(buf, "MemFree:", strlen("MemFree:"))) { + ptr = buf + strlen("MemFree:"); + while(*ptr && (*ptr == ' ')) ptr++; + di->stat.memf += atoll(ptr) / 1024; + } else if(!strncasecmp(buf, "Cached:", strlen("Cached:"))) { + ptr = buf + strlen("Cached:"); + while(*ptr && (*ptr == ' ')) ptr++; + di->stat.memf += atoll(ptr) / 1024; + } + } + fclose(fp); + } + + if(di->stat.memf > di->stat.memt) di->stat.memf = di->stat.memt; + + if((ptr = getcwd(NULL, 0))) { + if(statvfs(ptr, &s)) return; + di->stat.diskt = (unsigned int)((unsigned long long)s.f_blocks * (unsigned long long)s.f_bsize / (unsigned long long)1073741824); + di->stat.diskf = (unsigned int)((unsigned long long)s.f_bavail * (unsigned long long)s.f_bsize / (unsigned long long)1073741824); + free(ptr); + } + + return; +} + +void device_power(struct device_info *di) +{ + FILE *fp = NULL; + char buf[128], *ptr = NULL; + + strncpy(di->power.ac, "(unavailable)", sizeof(di->power.ac) - 1); + if(!(fp = fopen("/proc/acpi/ac_adapter/ADP1/state", "r"))) return; + while(fgets(buf, sizeof(buf), fp)) { + if(!strncasecmp(buf, "state:", strlen("state:"))) { + ptr = buf + strlen("state:"); + while(*ptr && (*ptr == ' ')) ptr++; + strncpy(di->power.ac, ptr, sizeof(di->power.ac) - 1); + } + } + fclose(fp); + + if(di->power.ac[strlen(di->power.ac) - 1] == '\n') di->power.ac[strlen(di->power.ac) - 1] = '\0'; + + return; +} + +void device_os(struct device_info *di) +{ + FILE *fp = NULL; + struct utsname u; + char buf[128], *ptr = NULL; + time_t t; + struct tm ts; + + do { + strncpy(di->os.ver, "(unknown)", sizeof(di->os.ver) - 1); + + if((fp = fopen("/etc/lsb-release", "r"))) { + while(fgets(buf, sizeof(buf), fp)) { + if(!strncasecmp(buf, "DISTRIB_DESCRIPTION=", strlen("DISTRIB_DESCRIPTION="))) { + ptr = buf + strlen("DISTRIB_DESCRIPTION="); + while(*ptr && ((*ptr == ' ') || (*ptr == '"'))) ptr++; + strncpy(di->os.ver, ptr, sizeof(di->os.ver) - 1); + while((di->os.ver[strlen(di->os.ver) - 1] == '"') || (di->os.ver[strlen(di->os.ver) - 1] == '\n')) di->os.ver[strlen(di->os.ver) - 1] = '\0'; + } + } + } else if((fp = fopen("/etc/slackware-version", "r"))) { + if(fgets(di->os.ver, sizeof(di->os.ver), fp)) break; + } else if((fp = fopen("/etc/redhat-release", "r"))) { + if(fgets(di->os.ver, sizeof(di->os.ver), fp)) break; + } else if((fp = fopen("/etc/gentoo-release", "r"))) { + if(fgets(di->os.ver, sizeof(di->os.ver), fp)) break; + } + } while(0); + if(fp) fclose(fp); + + if(di->os.ver[strlen(di->os.ver) - 1] == '\n') di->os.ver[strlen(di->os.ver) - 1] = '\0'; + + if(!uname(&u)) strncpy(di->os.arch, u.machine, sizeof(di->os.arch) - 1); + + if(!(ptr = getenv("LANG"))) ptr = "(unknown)"; + strncpy(di->os.lang, ptr, sizeof(di->os.lang) - 1); + + t = time(NULL); + localtime_r(&t, &ts); + strftime(di->os.tzname, sizeof(di->os.tzname), "%Z", &ts); + strftime(di->os.tzoff, sizeof(di->os.tzoff), "%z", &ts); + di->os.tzoff[6] = '\0'; + di->os.tzoff[5] = di->os.tzoff[4]; + di->os.tzoff[4] = di->os.tzoff[3]; + di->os.tzoff[3] = ':'; + + return; +} + +void device_user(struct device_info *di) +{ + FILE *fp = NULL; + char buf[128], *name, *gecos, *home, *ptr = NULL; + unsigned int uid; + + di->user.uid = (unsigned int)getuid(); + di->user.gid = (unsigned int)getuid(); + + if(!(fp = fopen("/etc/passwd", "r"))) return; + while(fgets(buf, sizeof(buf), fp)) { + if(!(ptr = strchr(buf, ':')) || !(ptr = strchr(++ptr, ':')) || (atoi(++ptr) != di->user.uid)) continue; + if((gecos = strchr(ptr, ':')) && (gecos = strchr(++gecos, ':'))) *gecos++ = '\0'; + if((home = strchr(gecos, ':'))) *home++ = '\0'; + if((ptr = strchr(home, ':'))) *ptr = '\0'; + printf("%s %s\n", gecos, home); + } + fclose(fp); + + return; +} + +void device_mount(struct device_info *di) +{ + FILE *fp = NULL; + char buf[512], *device = NULL, *mountpoint = NULL, *type = NULL, *ptr = NULL; + + if(!(fp = fopen("/etc/mtab", "r"))) return; + while(fgets(buf, sizeof(buf), fp)) { + device = buf; + if((mountpoint = strchr(device, ' '))) *mountpoint++ = '\0'; + if((type = strchr(mountpoint, ' '))) *type++ = '\0'; + if((ptr = strchr(type, ' '))) *ptr = '\0'; + ptr = &di->mount.list[strlen(di->mount.list)]; + snprintf(ptr, sizeof(di->mount.list) - strlen(di->mount.list), "%s %s (%s)\n", device, mountpoint, type); + } + fclose(fp); + + if(di->mount.list[strlen(di->mount.list) - 1] == '\n') di->mount.list[strlen(di->mount.list) - 1] = '\0'; + + return; +} diff --git a/extra/scripts/drive-temperature.sh b/extra/scripts/drive-temperature.sh new file mode 100644 index 0000000..a175cac --- /dev/null +++ b/extra/scripts/drive-temperature.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# 10/23/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# Edit /dev/sda according to +# your operating system drive naming +# convention + +# To use atactl replace "smartctl" with +# atactl sd0 readattr +# replace $arr[9] with $arr[3] +while true; do + sudo smartctl -a /dev/sd0a | \ + perl -Mstrict -Mwarnings -ne ' + my @arr = split(" ", $_); + my $tempnum = 0; + + if ($arr[1] and lc $arr[1] =~ /temperature/i) { + $tempnum = $arr[9] || 0; + printf("%d\n",$tempnum); + }' > /tmp/pinkytemp + + sleep 20 + +done & diff --git a/extra/scripts/dwm.sh b/extra/scripts/dwm.sh new file mode 100644 index 0000000..b7740e5 --- /dev/null +++ b/extra/scripts/dwm.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# 10/23/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# Execute the "statusbar" program every 2 secs +while true; do + "${HOME}"/.cache/bin/pinkybar -LTrspkvfmdVt + sleep 2 +done & diff --git a/extra/scripts/pinky-curses.sh b/extra/scripts/pinky-curses.sh new file mode 100644 index 0000000..f59b96b --- /dev/null +++ b/extra/scripts/pinky-curses.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# 10/23/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +pinky() { + location="${HOME}/.cache/bin" + + while true; do + "${location}"/pinkybar -LTrspkvfmdVt + sleep 2 + done | "${location}"/ncurses +} diff --git a/extra/scripts/pinky.lua b/extra/scripts/pinky.lua new file mode 100644 index 0000000..5907684 --- /dev/null +++ b/extra/scripts/pinky.lua @@ -0,0 +1,33 @@ +-- 11/18/2016 + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +-- MA 02110-1301, USA. + + +-- Your script should always return a single string. +-- Read the above line again. +-- +-- pinky-bar will always call uzer_func, +-- you can write other subroutines/functions +-- but they should be called inside uzer_func +-- +-- Dont worry about the colorization, it's +-- handled by pinky-bar. +-- +-- The entire language is in your hands. +function uzer_func() + local rett = string.format("%s %s %d", "Hello", os.date(), 123) + return rett +end diff --git a/extra/scripts/pinky.pl b/extra/scripts/pinky.pl new file mode 100644 index 0000000..ba6edfe --- /dev/null +++ b/extra/scripts/pinky.pl @@ -0,0 +1,40 @@ +# 10/24/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + + +# Your script should always return a single string. +# Read the above line again. +# +# pinky-bar will always call uzer_func, +# you can write other subroutines/functions +# but they should be called inside uzer_func +# +# Dont worry about the colorization, it's +# handled by pinky-bar. +# +# The entire language is in your hands. +use strict; +use warnings; + +use Time::Piece; + +sub uzer_func { + my $t = localtime; + my $rett = sprintf("%s %s %d", "Hello", $t->cdate, 123); + + return $rett; +} diff --git a/extra/scripts/pinky.py b/extra/scripts/pinky.py new file mode 100644 index 0000000..ae5bd9b --- /dev/null +++ b/extra/scripts/pinky.py @@ -0,0 +1,41 @@ +# 10/24/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + + +# Your script should always return a single string. +# Read the above line again. +# +# pinky-bar will always call uzer_func, +# you can write other subroutines/functions +# but they should be called inside uzer_func +# +# Dont worry about the colorization, it's +# handled by pinky-bar. +# +# Semicolins are only mandatory when you write "one liners" +# python2 -c 'import time;print("{0}".format(time.tzname))' +# +# Dont blame me if you have the following environment variable +# export PYTHONOPTIMIZE=3 +# The only way to describe it is caching nightmare. +# +# The entire language is in your hands. +import time + +def uzer_func(): + rett = '{0} {1} {2}'.format("Hello", time.ctime(), 123) + return rett diff --git a/extra/scripts/pinky.rb b/extra/scripts/pinky.rb new file mode 100644 index 0000000..27aa151 --- /dev/null +++ b/extra/scripts/pinky.rb @@ -0,0 +1,33 @@ +# 11/18/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + + +# Your script should always return a single string. +# Read the above line again. +# +# pinky-bar will always call uzer_func, +# you can write other subroutines/functions +# but they should be called inside uzer_func +# +# Dont worry about the colorization, it's +# handled by pinky-bar. +# +# The entire language is in your hands. +def uzer_func + rett = sprintf("%s %s %d", "Hello", Time.now, 123) + return rett +end diff --git a/extra/scripts/xmonad.sh b/extra/scripts/xmonad.sh new file mode 100644 index 0000000..efd5b3f --- /dev/null +++ b/extra/scripts/xmonad.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# 10/23/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# Execute the "statusbar" program every 2 secs +while true; do + "${HOME}"/.cache/bin/pinkybar -LTrspkvfmdVt + sleep 2 +done | dzen2 -w 1800 -x 130 -ta r -fn \ + '-*-dejavusans-*-r-*-*-11-*-*-*-*-*-*-*' & diff --git a/extra/xbm_icons/arch.xbm b/extra/xbm_icons/arch.xbm new file mode 100644 index 0000000..d00cad8 --- /dev/null +++ b/extra/xbm_icons/arch.xbm @@ -0,0 +1,4 @@ +#define arch1_width 8 +#define arch1_height 8 +static unsigned char arch1_bits[] = { + 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x66, 0xe7, 0xc3}; diff --git a/extra/xbm_icons/bat.xbm b/extra/xbm_icons/bat.xbm new file mode 100644 index 0000000..701149e --- /dev/null +++ b/extra/xbm_icons/bat.xbm @@ -0,0 +1,4 @@ +#define bat_full_width 8 +#define bat_full_height 8 +static unsigned char bat_full_bits[] = { + 0x18, 0x7E, 0x42, 0x5A, 0x5A, 0x5A, 0x42, 0x7E }; diff --git a/extra/xbm_icons/clock.xbm b/extra/xbm_icons/clock.xbm new file mode 100644 index 0000000..d4f64c0 --- /dev/null +++ b/extra/xbm_icons/clock.xbm @@ -0,0 +1,4 @@ +#define clock5_width 8 +#define clock5_height 8 +static unsigned char clock5_bits[] = { + 0x00, 0x7c, 0xee, 0xee, 0x8e, 0xfe, 0xfe, 0x7c}; diff --git a/extra/xbm_icons/cpu.xbm b/extra/xbm_icons/cpu.xbm new file mode 100644 index 0000000..2ea0b8e --- /dev/null +++ b/extra/xbm_icons/cpu.xbm @@ -0,0 +1,4 @@ +#define cpu13_width 8 +#define cpu13_height 8 +static unsigned char cpu13_bits[] = { + 0xdb, 0xc3, 0x3c, 0xbd, 0xbd, 0x3c, 0xc3, 0xdb}; diff --git a/extra/xbm_icons/diskette.xbm b/extra/xbm_icons/diskette.xbm new file mode 100644 index 0000000..48e641b --- /dev/null +++ b/extra/xbm_icons/diskette.xbm @@ -0,0 +1,4 @@ +#define diskette_width 8 +#define diskette_height 8 +static unsigned char diskette_bits[] = { + 0xFF, 0x81, 0x81, 0x81, 0xBD, 0xB5, 0xB5, 0xFE }; diff --git a/extra/xbm_icons/fan.xbm b/extra/xbm_icons/fan.xbm new file mode 100644 index 0000000..6136aa5 --- /dev/null +++ b/extra/xbm_icons/fan.xbm @@ -0,0 +1,4 @@ +#define cpu15_width 8 +#define cpu15_height 8 +static unsigned char cpu15_bits[] = { + 0x02, 0xf2, 0x3e, 0x26, 0x64, 0x7c, 0x4f, 0x40}; diff --git a/extra/xbm_icons/fox.xbm b/extra/xbm_icons/fox.xbm new file mode 100755 index 0000000..46735c3 --- /dev/null +++ b/extra/xbm_icons/fox.xbm @@ -0,0 +1,4 @@ +#define fox_width 8 +#define fox_height 8 +static unsigned char fox_bits[] = { + 0x81, 0xC3, 0xBD, 0xFF, 0x99, 0xDB, 0x7E, 0x18 }; diff --git a/extra/xbm_icons/mem.xbm b/extra/xbm_icons/mem.xbm new file mode 100644 index 0000000..a4880d3 --- /dev/null +++ b/extra/xbm_icons/mem.xbm @@ -0,0 +1,4 @@ +#define mem1_width 8 +#define mem1_height 8 +static unsigned char mem1_bits[] = { + 0xaa, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0xaa}; diff --git a/extra/xbm_icons/mobo.xbm b/extra/xbm_icons/mobo.xbm new file mode 100644 index 0000000..69bdbdf --- /dev/null +++ b/extra/xbm_icons/mobo.xbm @@ -0,0 +1,4 @@ +#define grid_width 8 +#define grid_height 8 +static unsigned char grid_bits[] = { + 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb}; diff --git a/extra/xbm_icons/mpd.xbm b/extra/xbm_icons/mpd.xbm new file mode 100644 index 0000000..6589361 --- /dev/null +++ b/extra/xbm_icons/mpd.xbm @@ -0,0 +1,6 @@ +#define cpu_width 16 +#define cpu_height 15 +static unsigned char cpu_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x40, 0x10, 0x40, 0x10, + 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x70, 0x1c, 0x78, 0x1e, 0x30, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/extra/xbm_icons/net.xbm b/extra/xbm_icons/net.xbm new file mode 100644 index 0000000..0acf813 --- /dev/null +++ b/extra/xbm_icons/net.xbm @@ -0,0 +1,4 @@ +#define net_width 8 +#define net_height 8 +static unsigned char net_wired_bits[] = { + 0x00, 0x1C, 0x1C, 0x7F, 0x7F, 0x7F, 0x55, 0x7F }; diff --git a/extra/xbm_icons/sm4tik-icon-pack.tar.bz2 b/extra/xbm_icons/sm4tik-icon-pack.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..25b16986b6675cbabf18cb3fce0aebf392f24a6f GIT binary patch literal 5228 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 literal 0 HcmV?d00001 diff --git a/img/mobo-temp.png b/img/mobo-temp.png new file mode 100644 index 0000000000000000000000000000000000000000..69ab3377cbac24763ff25cc20d28dfbc1ba6fb89 GIT binary patch literal 34586 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 literal 0 HcmV?d00001 diff --git a/img/pic5.png b/img/pic5.png new file mode 100644 index 0000000000000000000000000000000000000000..5f5a6d9b2683e77926dba47e2eb59b38dcadcfe6 GIT binary patch literal 6595 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 ByYc`4 literal 0 HcmV?d00001 diff --git a/img/pic6.png b/img/pic6.png new file mode 100644 index 0000000000000000000000000000000000000000..afea1c14a2b036d88960ba40fcd2345edb54922e GIT binary patch literal 8463 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 Hu0mjfr`W|B literal 0 HcmV?d00001 diff --git a/m4/1errs.m4 b/m4/1errs.m4 new file mode 100644 index 0000000..300042c --- /dev/null +++ b/m4/1errs.m4 @@ -0,0 +1,74 @@ +dnl 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + +dnl All funcs below are internal + +dnl Error message when smth is wrong +AC_DEFUN([ERR],[ + AC_MSG_ERROR($1) +]) + +dnl What have to be installed in order to compile the program. +AC_DEFUN([ERR_MUST_INSTALL],[ + ERR([Install $1 in order to compile the program.]) +]) + +dnl Failed to compile and linking some test(s) +AC_DEFUN([LINK_FAILED], [ + ERR([Failed to compile and link the $1 test.]) +]) + +dnl Failed to compile some test(s) +AC_DEFUN([COMPILE_FAILED], [ + ERR([Failed to compile the $1 test.]) +]) + +dnl Missing library function(s) +AC_DEFUN([MISSING_FUNC], [ + ERR([Missing core library functions.]) +]) + +dnl Missing header file(s) +AC_DEFUN([MISSING_HEADER], [ + ERR([Missing core header files.]) +]) + + + +dnl Not error related funcs, +dnl neither fall in any of the test +dnl categories listed in this folder + +dnl When using AC_CHECK_LIB in a loop, +dnl it will substitute the same linker flag +dnl several times, which may cause to +dnl exceed the line limit +AC_DEFUN([UPDATE_LIBS_VAR],[ + LIBS="$1" + AC_SUBST(LIBS) +]) + +dnl Same description as the above func, +dnl except it saves the LIBS var before +dnl invoking AC_CHECK_LIB +AC_DEFUN([SAVE_LIBS_VAR],[ + m4_ifdef([ZaVeD], [ + m4_undefine([ZaVeD]) + ]) + + m4_define([ZaVeD],[$1]) +]) diff --git a/m4/alsa.m4 b/m4/alsa.m4 new file mode 100644 index 0000000..34d2795 --- /dev/null +++ b/m4/alsa.m4 @@ -0,0 +1,134 @@ +dnl 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_ALSA() function in configure.ac +dnl +dnl Check for the presence of ALSA headers and +dnl substitute the linker flags -lasound to the +dnl the variable 'ALSA_LIBS' if they are available. +AC_DEFUN([TEST_ALSA],[ + ALSA_LIBS="" + + AC_ARG_WITH([alsa], + AS_HELP_STRING([--with-alsa], + [ALSA linker flag for sound support]), + [], + [with_alsa=no] + ) + + AC_ARG_WITH([oss], + AS_HELP_STRING([--with-oss], + [BSD OSS flag for sound support]), + [], + [with_oss=no] + ) + + AS_IF([test "x$with_alsa" = "xyes"], [ + AC_CHECK_HEADERS([alsa/asoundlib.h], [ + ALSA_LIBS="-lasound" + ],[ + ERR_MUST_INSTALL([alsa-utils and alsa-lib]) + ]) + + m4_foreach([LiB], [ + snd_mixer_open , + snd_mixer_attach , + snd_mixer_selem_register , + snd_mixer_load , + snd_mixer_selem_id_malloc , + snd_mixer_selem_id_set_name , + snd_mixer_find_selem , + snd_mixer_selem_get_playback_volume , + snd_mixer_selem_get_playback_volume_range , + snd_mixer_selem_id_free , + snd_mixer_close + ],[ + AC_CHECK_LIB(asound,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + + AC_SUBST(ALSA_LIBS) + + AS_IF([test "x$with_alsa" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + snd_mixer_t *handle = NULL; + snd_mixer_elem_t *elem = NULL; + snd_mixer_selem_id_t *s_elem = NULL; + return 0; + } + ]]) + ],[],[ + LINK_FAILED([alsa]) + ] + ) + ]) + + + ifdef([FREEBZD],[ + AS_IF([test "x$with_alsa" = "xno"], [ + AS_IF([test "x$with_oss" = "xyes"], [ + TEST_OZZ([sys/soundcard.h]) + ]) + ]) + ],[]) + + + ifdef([OPENBZD],[ + AS_IF([test "x$with_alsa" = "xno"], [ + AS_IF([test "x$with_oss" = "xyes"], [ + TEST_OZZ([soundcard.h]) + ]) + ]) + ],[]) + + +]) + + +dnl Internal function to check the BSD +dnl OSS headers and perfom some tests +AC_DEFUN([TEST_OZZ],[ + + AC_CHECK_HEADERS([$1], [ + ],[ + ERR([Homie, where is $1 ?]) + ]) + + NOTIFY([fcntl]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + int fd = 0; + if (-1 == (fd = open("elo", O_RDONLY))) { + return 0; + } + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([fcntl]) + ] + ) + +]) diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000..08f2e07 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/cflagz.m4 b/m4/cflagz.m4 new file mode 100644 index 0000000..e2dfc15 --- /dev/null +++ b/m4/cflagz.m4 @@ -0,0 +1,145 @@ +dnl 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl Internal function to perform +dnl explicit compiler CFLAGS support test +AC_DEFUN([CHECK_CFLAGZ],[ + m4_foreach([fLaG], [$1], [ + + AX_APPEND_FLAG([fLaG], [CFLAGS]) + + AC_MSG_CHECKING([whether fLaG will compile flawlessly]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ int main(void) { return 0; } ]]) + ],[cflagz_ok=yes],[cflagz_ok=no]) + + AC_MSG_RESULT([$cflagz_ok]) + + AS_IF([test "x$cflagz_ok" = "xno"], [ + ERR([Failed to compile a simple test with the above fLaG CFLAG.]) + ] + ) + + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ int main(void) { return 0; } ]]) + ],[],[ + ERR([Failed to compile and link a simple test with the above fLaG CFLAG.]) + ] + ) + + ])dnl + +]) + +dnl Internal function to check +dnl the compiler for assembly support +AC_DEFUN([TEST_ASSEMBLY],[ + + AC_MSG_CHECKING([for assembly support]) + + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include ]],[[ + unsigned int x = 1, z = 2; + __asm__ __volatile__ ( + "addl %%ebx, %%eax" + : "=a"(x) + : "a"(x), "b"(z) + ); + ]]) + ],[supportz_assembly=yes],[supportz_assembly=no]) + + AC_MSG_RESULT([$supportz_assembly]) + + AS_IF([test "x$supportz_assembly" = "xno"], [ + ERR([Your compiler does not support assembly.]) + ] + ) + +]) + +dnl TEST_CFLAGZ() function in configure.ac +dnl +dnl Check for the presence and whether +dnl the given FLAG will work flawlessly +dnl with the currently used compiler. +dnl Will substitute each successful flag +dnl and bail out with pre-defined error msg +dnl when some FLAG is unsupported. +AC_DEFUN([TEST_CFLAGZ],[ + + dnl Only useful when developing + dnl pinky-bar + dnl -Wdeclaration-after-statement, + dnl -Wno-unused-function, + + dnl Shame on you c++lang, err clang + dnl Keeping this flag for historical + dnl reasons just to remind myself and + dnl anyone reading this file about the + dnl clangs inabillity to distinguish + dnl C from C++ + dnl https://llvm.org/bugs/show_bug.cgi?id=21689 + dnl -Wno-missing-field-initializers + + dnl The twisted gcc vision + dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 + dnl They say its "glibc" fault + dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 + dnl -Wno-unused-result, + + dnl For very first time I stumble upon GCC -O2 bug. + dnl It hangs on pci_init and sensors_init with -O2 + dnl net.m4 will append -O2 or -O0 + dnl according whether --with-pci and --with-sensors + dnl are used or not. Another "newer" GCC release + dnl that I just installed hangs on sensors_init. + dnl One more snafu GCC, and I'll drop -02 in linux + + AC_MSG_NOTICE([checking all CFLAGS]) + CHECK_CFLAGZ([ + -pipe, + -std=c99, + -Wextra, + -Wall, + -pedantic, + -Wundef, + -Wshadow, + -W, + -Wwrite-strings, + -Wcast-align, + -Wstrict-overflow=5, + -Wconversion, + -Wpointer-arith, + -Wstrict-prototypes, + -Wformat=0, + -Wsign-compare, + -Wendif-labels, + -Wredundant-decls, + -Wmissing-prototypes, + -Winit-self, + -Wno-unused-variable + ]) + + TEST_ASSEMBLY() + + LIBS='' + AC_SUBST(LIBS) + + AC_DEFINE_UNQUOTED([cuRos],[1],[da monster]) +]) diff --git a/m4/dvd.m4 b/m4/dvd.m4 new file mode 100644 index 0000000..7c2e34e --- /dev/null +++ b/m4/dvd.m4 @@ -0,0 +1,85 @@ +dnl 08/23/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_DVD() function in configure.ac +dnl +dnl Substitute the linker flags -lcdio to the +dnl the variable 'DVD_LIBS' if the user enabled +dnl the --with-dvd switch +AC_DEFUN([TEST_DVD],[ + DVD_LIBS="" + + AC_ARG_WITH([dvd], + AS_HELP_STRING([--with-dvd], + [dvd linker flag to show the vendor and model name of your cd/dvdrom]), + [], + [with_dvd=no] + ) + + AS_IF([test "x$with_dvd" = "xyes"], [ + AC_CHECK_HEADERS([ \ + cdio/cdio.h \ + cdio/mmc.h \ + ], [ + DVD_LIBS="-lcdio" + ],[ + ERR_MUST_INSTALL([libcdio]) + ]) + + m4_foreach([LiB], [ + cdio_open , + mmc_get_hwinfo , + cdio_destroy + ],[ + AC_CHECK_LIB(cdio,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + + AC_SUBST(DVD_LIBS) + + AS_IF([test "x$with_dvd" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + int main(void) { + CdIo_t *p_cdio = cdio_open(NULL, DRIVER_DEVICE); + cdio_hwinfo_t hwinfo; + if (NULL == p_cdio) { + return 0; + } + if (mmc_get_hwinfo(p_cdio, &hwinfo)) { + printf("%s %s\n", hwinfo.psz_vendor, hwinfo.psz_model); + } + if (NULL != p_cdio) { + cdio_destroy(p_cdio); + } + return 0; + } + ]]) + ],[],[ + LINK_FAILED([cdio]) + ] + ) + ]) + +]) diff --git a/m4/extend.m4 b/m4/extend.m4 new file mode 100644 index 0000000..c739895 --- /dev/null +++ b/m4/extend.m4 @@ -0,0 +1,309 @@ +dnl 10/24/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + +dnl TEST_PERL() function in configure.ac +dnl +dnl Substitute perl related linker and +dnl cflags to the variables PERL_CF and +dnl PERL_LZ if the user enabled the +dnl --with-perl switch +AC_DEFUN([TEST_PERL],[ + PERL_LZ="" + PERL_CF="" + WITH_PERL=0 + + AC_ARG_WITH([perl], + AS_HELP_STRING([--with-perl], + [Extend the program via perl scripts]), + [], + [with_perl=no] + ) + + AS_IF([test "x$with_perl" = "xyes"], [ + CHECK_CFLAGZ([-O0]) + + AC_PATH_PROG(perlcf,perl,no) + AS_IF([test "x$perlcf" = "xno"], [ + ERR([Couldnt find perl.]) + ]) + + PERL_LZ=`$perlcf -MExtUtils::Embed -e ldopts` + PERL_CF=`$perlcf -MExtUtils::Embed -e ccopts` + + dnl m4_foreach([LiB], [ + dnl perl_construct, + dnl perl_parse, + dnl perl_run, + dnl perl_destruct, + dnl perl_alloc, + dnl perl_free + dnl ],[ + dnl AC_CHECK_LIB(perl,LiB,[],[ + dnl MISSING_FUNC() + dnl ]) + dnl ]) + + WITH_PERL=1 + ]) + + AC_SUBST(PERL_LZ) + AC_SUBST(PERL_CF) + AC_DEFINE_UNQUOTED([WITH_PERL],[$WITH_PERL],[Extend the program via perl scripts]) + + dnl AS_IF([test "x$with_perl" = "xyes"], [ + dnl AC_LINK_IFELSE([ + dnl AC_LANG_SOURCE([[ + dnl #include + dnl #include + dnl #include + dnl #include + dnl int main(void) { + dnl static PerlInterpreter *my_perl = NULL; + dnl PERL_SYS_INIT3((int *)NULL, (char ***)NULL, (char ***)NULL); + dnl my_perl = perl_alloc(); + dnl if (NULL == my_perl) { + dnl PERL_SYS_TERM(); + dnl return -1; + dnl } + dnl perl_construct(my_perl); + dnl perl_parse(my_perl, NULL, 0, (char **)NULL, (char **)NULL); + dnl PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + dnl perl_run(my_perl); + dnl perl_destruct(my_perl); + dnl perl_free(my_perl); + dnl PERL_SYS_TERM(); + dnl return 0; + dnl } + dnl ]]) + dnl ],[],[ + dnl LINK_FAILED([perl]) + dnl ] + dnl ) + dnl ]) + +]) + + +dnl TEST_python() function in configure.ac +dnl +dnl Substitute python related linker and +dnl cflags to the variables PYTHON_CF and +dnl PYTHON_LZ if the user enabled the +dnl --with-python switch +AC_DEFUN([TEST_PYTHON],[ + PYTHON_LZ="" + PYTHON_CF="" + WITH_PYTHON2=0 + WITH_PYTHON=0 + curpycfver="none" + + AC_ARG_WITH([python2], + AS_HELP_STRING([--with-python2], + [Extend the program via python scripts]), + [], + [with_python2=no] + ) + + AC_ARG_WITH([python3], + AS_HELP_STRING([--with-python3], + [Extend the program via python scripts]), + [], + [with_python3=no] + ) + + AS_IF([test "x$with_python2" = "xyes" || test "x$with_python3" = "xyes"], [ + CHECK_CFLAGZ([-O0]) + + AS_IF([test "x$with_python2" = "xyes"], [ + AM_PATH_PYTHON([2],[ + ],[ + ERR([Couldnt find any python 2 version.]) + ]) + WITH_PYTHON2=1 + ]) + + AS_IF([test "x$with_python3" = "xyes"], [ + AM_PATH_PYTHON([3],[ + ],[ + ERR([Couldnt find any python 3 version.]) + ]) + ]) + + dnl What a python versioning mess. + dnl We have to check back and forth different scenarious + dnl to make sure we can find appropriate CFLAGS and LDFLAGS + dnl for the requested python version. + dnl When there is only 1 python version installed the file + dnl naming is one, when there are 2 or more different + dnl python version installed, the file naming is other. + dnl Still reading or get bored ? + m4_define([testveR],[python$PYTHON_VERSION]) + m4_define([testveR2],[python-config-$PYTHON_VERSION]) + + dnl First check whether python and python-9.9 exist + AC_PATH_PROG(pyvf1,testveR,no) + AC_PATH_PROG(pyvf2,python,no) + + dnl Next check whether python-config and python-config-9.9 exist + AC_PATH_PROG(pycf1,testveR2,no) + AC_PATH_PROG(pycf2,python-config,no) + + dnl Check whether any of the python versions was found + AS_IF([test "x$pyvf1" = "xno" && test "x$pyvf2" = "xno"], [ + ERR([Couldnt find python]) + ]) + + dnl Check whether any of the python-config versions was found + AS_IF([test "x$pycf1" = "xno" && test "x$pycf2" = "xno"], [ + ERR([Couldnt find python-config]) + ]) + + dnl We firts check for the python-config-9.9 version + AS_IF([test "x$pycf1" != "xno"], [ + curpycfver="${pycf1}" + ]) + + dnl We now know that python-config is the only version available + AS_IF([test "x$pycf2" != "xno" && test "x$curpycfver" = "xnone"], [ + curpycfver="${pycf2}" + ]) + + WITH_PYTHON=1 + PYTHON_LZ=`${curpycfver} --ldflags` + PYTHON_CF=`${curpycfver} --cflags` + + dnl m4_foreach([LiB], [ + dnl Py_GetPath, + dnl Py_Initialize, + dnl PyImport_Import, + dnl PyObject_GetAttrString, + dnl PyCallable_Check, + dnl PyObject_CallObject, + dnl Py_Finalize + dnl ],[ + dnl AC_CHECK_LIB(testveR,LiB,[],[ + dnl MISSING_FUNC() + dnl ]) + dnl ]) + + ]) + + + AC_SUBST(PYTHON_LZ) + AC_SUBST(PYTHON_CF) + AC_DEFINE_UNQUOTED([WITH_PYTHON],[$WITH_PYTHON],[Extend the program via python scripts]) + AC_DEFINE_UNQUOTED([WITH_PYTHON2],[$WITH_PYTHON2],[Extend the program via python scripts]) + + dnl AS_IF([test "x$with_python2" = "xyes" || test "x$with_python3" = "xyes"], [ + dnl AC_CHECK_HEADERS([testveR/Python.h],[],[ + dnl MISSING_HEADER() + dnl ]) + dnl AC_LINK_IFELSE([ + dnl AC_LANG_SOURCE([[ + dnl #include + dnl #include + dnl #include + dnl int main(void) { + dnl Py_Initialize(); + dnl PyRun_SimpleString("from time import time,ctime\n" + dnl "print(ctime(time()))\n"); + dnl Py_Finalize(); + dnl return 0; + dnl } + dnl ]]) + dnl ],[],[ + dnl LINK_FAILED([python]) + dnl ] + dnl ) + dnl ]) + +]) + + +dnl TEST_LUA() function in configure.ac +dnl +dnl Substitute lua related linker and +dnl cflags to the variables LUA_LIBS +dnl if the user enabled the --with-lua switch +AC_DEFUN([TEST_LUA],[ + LUA_LIBS="" + WITH_LUA=0 + + AC_ARG_WITH([lua], + AS_HELP_STRING([--with-lua], + [Extend the program via lua scripts]), + [], + [with_lua=no] + ) + + AS_IF([test "x$with_lua" = "xyes"], [ + CHECK_CFLAGZ([-O0]) + + LUA_LIBS="-llua" + WITH_LUA=1 + ]) + + AC_SUBST(LUA_LIBS) + AC_DEFINE_UNQUOTED([WITH_LUA],[$WITH_LUA],[Extend the program via lua scripts]) +]) + + +dnl TEST_RUBY() function in configure.ac +dnl +dnl Substitute ruby related linker and +dnl cflags to the variables RUBY_CF and +dnl RUBY_LZ if the user enabled the +dnl --with-ruby switch +AC_DEFUN([TEST_RUBY],[ + RUBY_LZ="" + RUBY_CF="" + WITH_RUBY=0 + + AC_ARG_WITH([ruby], + AS_HELP_STRING([--with-ruby], + [Extend the program via ruby scripts]), + [], + [with_ruby=no] + ) + + AS_IF([test "x$with_ruby" = "xyes"], [ + CHECK_CFLAGZ([-O0]) + + m4_ifndef([PKG_PROG_PKG_CONFIG], [ + AC_MSG_ERROR([Either you dont have pkg-config installed, or pkg.m4 is not in 'ls /usr/share/aclocal | grep pkg', if thats so try exporting the following env var: execute 'aclocal --print-ac-dir' without quotes, then: 'export ACLOCAL_PATH=/tmp' where /tmp is the directory printed from the previous command.]) + ]) + PKG_PROG_PKG_CONFIG() + + PKG_CHECK_MODULES([RUBY], [ruby-2.0 >= 2.0], [ + dnl AC_CHECK_LIB(ruby_init,[],[ + dnl MISSING_FUNC() + dnl ]) + + ],[ + AC_MSG_ERROR([Your ruby version is too old, consider upgrade.]) + + ]) + RUBY_CF=$RUBY_CFLAGS + RUBY_LZ=$RUBY_LIBS + WITH_RUBY=1 + + ]) + + AC_SUBST(RUBY_LZ) + AC_SUBST(RUBY_CF) + AC_DEFINE_UNQUOTED([WITH_RUBY],[$WITH_RUBY],[Extend the program via ruby scripts]) +]) diff --git a/m4/mpd.m4 b/m4/mpd.m4 new file mode 100644 index 0000000..4f50dbf --- /dev/null +++ b/m4/mpd.m4 @@ -0,0 +1,78 @@ +dnl 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_MPD() function in configure.ac +dnl +dnl Substitute the linker flags -lmpdclient to the +dnl the variable 'MPD_LIBS' if the user enabled +dnl the --with-mpd switch +AC_DEFUN([TEST_MPD],[ + MPD_LIBS="" + + AC_ARG_WITH([mpd], + AS_HELP_STRING([--with-mpd], + [mpd linker flag to show the currently played song]), + [], + [with_mpd=no] + ) + + AS_IF([test "x$with_mpd" = "xyes"], [ + AC_CHECK_HEADERS([mpd/client.h], [ + MPD_LIBS="-lmpdclient" + ],[ + ERR_MUST_INSTALL([libmpdclient]) + ]) + + m4_foreach([LiB], [ + mpd_connection_new , + mpd_send_command , + mpd_recv_song , + mpd_connection_get_error , + mpd_connection_free , + mpd_song_free , + mpd_song_get_uri + ],[ + AC_CHECK_LIB(mpdclient,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + + AC_SUBST(MPD_LIBS) + + AS_IF([test "x$with_mpd" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + struct mpd_connection *conn = NULL; + struct mpd_song *song; + if (NULL == (conn = mpd_connection_new(NULL, 0, 0))) { + return 0; + } + mpd_connection_free(conn); + return 0; + } + ]]) + ],[],[ + LINK_FAILED([mpd]) + ] + ) + ]) + +]) diff --git a/m4/net.m4 b/m4/net.m4 new file mode 100644 index 0000000..59d8d46 --- /dev/null +++ b/m4/net.m4 @@ -0,0 +1,301 @@ +dnl 08/10/2015 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_NET() function in configure.ac +dnl +dnl Allow the user to compile the program +dnl without net related functions, thus +dnl decreasing the required dependencies. +dnl +dnl Did not included tests for some of the Net +dnl headers as they fail to compile just by including +dnl them in gcc, but pass the tests in clang. Is there +dnl are any _POSIX_SOURCE m4 alternative to compile a +dnl test case on the fly ? +dnl +dnl --with-net will check for the presence of iproute2 headers +dnl used in the net functions and substitute appropriate macro +dnl so the program to be compiled with/out net functions support. +AC_DEFUN([TEST_NET],[ + WITH_NET=1 + WITH_LIBNL=0 + LIBNL_CF="" + LIBNL_LZ="" + + AC_ARG_WITH([net], + AS_HELP_STRING([--with-net], + [Net funcs]), + [], + [with_net=yes] + ) + + AC_ARG_WITH([libnl], + AS_HELP_STRING([--with-libnl], + [wifi funcs]), + [], + [with_libnl=no] + ) + + AS_IF([test "x$with_net" = "xno"], [ + WITH_NET=0 + ]) + + AS_IF([test "x$with_net" = "xyes"], [ + + AC_CHECK_HEADERS([ \ + ifaddrs.h \ + arpa/inet.h \ + sys/socket.h \ + sys/ioctl.h \ + netdb.h \ + ],[],[ + MISSING_HEADER() + ]) + + ifdef([FREEBZD], [ + AC_CHECK_HEADERS([ \ + arpa/nameser.h \ + netinet/in.h \ + net/if.h \ + net/if_dl.h \ + ],[],[ + MISSING_HEADER() + ]) + + ],[ + ]) + + ifdef([LINUKS], [ + AC_CHECK_HEADERS([ \ + linux/if_link.h \ + netpacket/packet.h \ + linux/sockios.h \ + linux/ethtool.h \ + ],[],[ + MISSING_HEADER() + ]) + + AS_IF([test "x$with_libnl" = "xyes"], [ + + m4_ifndef([PKG_PROG_PKG_CONFIG], [ + AC_MSG_ERROR([Either you dont have pkg-config installed, or pkg.m4 is not in 'ls /usr/share/aclocal | grep pkg', if thats so try exporting the following env var: execute 'aclocal --print-ac-dir' without quotes, then: 'export ACLOCAL_PATH=/tmp' where /tmp is the directory printed from the previous command.]) + ]) + PKG_PROG_PKG_CONFIG() + + PKG_CHECK_MODULES([LIBNL], [libnl-3.0 >= 3.0 libnl-genl-3.0 >= 3.0], [ + AC_CHECK_LIB(nl-3,nlmsg_data,[],[ + MISSING_FUNC() + ]) + AC_CHECK_LIB(nl-genl-3,genlmsg_put,[],[ + MISSING_FUNC() + ]) + + ],[ + AC_MSG_ERROR([Your libnl version is too old, consider updating to version three at least]) + + ]) + LIBNL_CF=$LIBNL_CFLAGS + LIBNL_LZ=$LIBNL_LIBS + WITH_LIBNL=1 + + ]) + + ],[ + ]) + + AC_CHECK_FUNCS([ \ + getifaddrs \ + freeifaddrs \ + getaddrinfo \ + freeaddrinfo \ + socket \ + ioctl \ + inet_ntop \ + ],[],[ + MISSING_FUNC() + ]) + + NOTIFY([addrinfo]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + int main(void) { + struct addrinfo *rp = NULL, *result = NULL; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([addrinfo]) + ] + ) + + NOTIFY([getifaddrs-lite]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + struct ifaddrs *ifaddr; + if (-1 == getifaddrs(&ifaddr)) { + return 0; + } + freeifaddrs(ifaddr); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([getifaddrs-lite]) + ] + ) + + ifdef([FREEBZD],[ + NOTIFY([getifaddrs-heavy]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + #include + int main(void) { + struct ifaddrs *ifaddr = NULL, *ifa = NULL; + struct if_data *stats = NULL; + struct sockaddr_dl *mac = NULL; + if (-1 == getifaddrs(&ifaddr)) { + return 0; + } + freeifaddrs(ifaddr); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([getifaddrs-heavy]) + ] + ) + ],[]) + + + ]) + + AC_SUBST(LIBNL_CF) + AC_SUBST(LIBNL_LZ) + AC_DEFINE_UNQUOTED([WITH_NET],[$WITH_NET],[Net funcs]) + AC_DEFINE_UNQUOTED([WITH_LIBNL],[$WITH_LIBNL],[wifi funcs]) + +]) + +dnl TEST_PCI() function in configure.ac +dnl +dnl Allow the user to compile the program +dnl without pci related functions, thus +dnl decreasing the required dependencies. +dnl +dnl --with-pci will check for the presence of pci headers and +dnl substitute the linker flags -lpci to the variable PCI_LIBS +dnl as well will mitigate the GCC -O2 bug. +AC_DEFUN([TEST_PCI],[ + WITH_PCI=1 + PCI_LIBS="" + + AC_ARG_WITH([pci], + AS_HELP_STRING([--with-pci], + [PCI funcs]), + [], + [with_pci=yes] + ) + + ifdef([LINUKS],[],[ + WITH_PCI=0 + CHECK_CFLAGZ([-O2]) + ]) + + ifdef([LINUKS],[ + AS_IF([test "x$with_pci" = "xno"], [ + WITH_PCI=0 + ifdef([GOT_SENSR],[ + CHECK_CFLAGZ([-O0]) + ],[ + CHECK_CFLAGZ([-O2]) + ]) + m4_define([NO_PCI],[thenFryAGP]) + ]) + + AS_IF([test "x$with_pci" = "xyes"], [ + + dnl For very first time I stumble upon GCC -O2 bug. + dnl It hangs on pci_init with -O2 + CHECK_CFLAGZ([-O0]) + + AC_CHECK_HEADERS([pci/pci.h], [ + PCI_LIBS="-lpci" + ],[ + ERR_MUST_INSTALL([pciutils]) + ]) + + m4_foreach([LiB], [ + pci_alloc , + pci_init , + pci_scan_bus , + pci_fill_info , + pci_lookup_name , + pci_cleanup + ],[ + AC_CHECK_LIB(pci,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + + AC_SUBST(PCI_LIBS) + + AS_IF([test "x$with_pci" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + struct pci_access *pacc= NULL; + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); + if (NULL != pacc) { + pci_cleanup(pacc); + } + return 0; + } + ]]) + ],[],[ + LINK_FAILED([pci]) + ] + ) + ]) + + ],[ + ]) + + AC_DEFINE_UNQUOTED([WITH_PCI],[$WITH_PCI],[PCI funcs]) + +]) diff --git a/m4/sensors.m4 b/m4/sensors.m4 new file mode 100644 index 0000000..e781d25 --- /dev/null +++ b/m4/sensors.m4 @@ -0,0 +1,193 @@ +dnl 08/23/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_SENSORS() function in configure.ac +dnl +dnl Substitute the linker flags -lsensors to the +dnl the variable 'SENSORS_LIBS' if the user enabled +dnl the --with-sensors switch +AC_DEFUN([TEST_SENSORS],[ + SENSORS_LIBS="" + GOT_APM=0 + + AC_ARG_WITH([sensors], + AS_HELP_STRING([--with-sensors], + [lm sensors linker flag to obtain voltage, mobo temp and fans]), + [], + [with_sensors=no] + ) + + AC_ARG_WITH([apm], + AS_HELP_STRING([--with-apm], + [APM power and resource management for laptops]), + [], + [with_apm=no] + ) + + AC_ARG_VAR(mobo_sensor, [mobo sensors module name to use in sysctl calls]) + AC_ARG_VAR(cpu_sensor, [cpu sensors module name to use in sysctl calls]) + + ifdef([LINUKS],[ + AS_IF([test "x$with_sensors" = "xyes"], [ + AC_CHECK_HEADERS([sensors/sensors.h], [ + SENSORS_LIBS="-lsensors" + ],[ + ERR_MUST_INSTALL([lm_sensors]) + ]) + + m4_foreach([LiB], [ + sensors_init, + sensors_get_value, + sensors_get_label, + sensors_get_detected_chips, + sensors_get_features, + sensors_get_all_subfeatures, + sensors_cleanup + ],[ + AC_CHECK_LIB(sensors,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + ],[ + ]) + + ifdef([FREEBZD],[ + if [[ ! -z "${mobo_sensor}" ]] + then + MOBO_MODL=\""${mobo_sensor}"\" + AC_DEFINE_UNQUOTED([MOBO_MODL],[$MOBO_MODL],[mobo sensors module]) + fi + + if [[ ! -z "${cpu_sensor}" ]] + then + CPU_MODL=\""${cpu_sensor}"\" + AC_DEFINE_UNQUOTED([CPU_MODL],[$CPU_MODL],[cpu sensors module]) + fi + + AS_IF([test "x$with_apm" = "xyes"], [ + AC_CHECK_HEADERS([machine/apm_bios.h], [ + GOT_APM=1 + ],[ + MISSING_HEADER() + ]) + ]) + AC_DEFINE_UNQUOTED([GOT_APM],[$GOT_APM],[APM power and resource management for laptops]) + + ],[ + ]) + + AC_SUBST(SENSORS_LIBS) + + ifdef([LINUKS],[ + AS_IF([test "x$with_sensors" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + int main(void) { + int nr = 0, nr2 = 0, nr3 = 0; + const sensors_chip_name *chip; + const sensors_feature *features; + const sensors_subfeature *subfeatures; + double value = 0.0; + char *label = NULL; + + if (0 != (sensors_init(NULL))) { + return 0; + } + + while (NULL != (chip = sensors_get_detected_chips(NULL, &nr))) { + nr2 = 0; + while (NULL != (features = sensors_get_features(chip, &nr2))) { + nr3 = 0; + while (NULL != (subfeatures = sensors_get_all_subfeatures(chip, features, &nr3))) { + switch(subfeatures->type) { + + case SENSORS_SUBFEATURE_IN_INPUT: + case SENSORS_SUBFEATURE_TEMP_INPUT: + case SENSORS_SUBFEATURE_FAN_INPUT: + { + if (0 != (sensors_get_value(chip, subfeatures->number, &value))) { + break; + } + if (NULL == (label = sensors_get_label(chip, features))) { + break; + } + printf("%f\n", (float)value); + if (NULL != label) { + free(label); + } + } + break; + default: + continue; + } + } + } + } + sensors_cleanup(); + + return 0; + } + ]]) + ],[],[ + ERR([Either you miss lm_sensors or your lm_sensors API version is unsupported by pinky-bar.]) + ] + ) + ]) + + ],[ + ]) + + + ifdef([OPENBZD], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + int main(void) { + struct sensordev dev; + struct sensor sens; + SENSOR_VOLTS_DC; + SENSOR_TEMP; + SENSOR_FANRPM; + SENSOR_FINVALID; + SENSOR_FUNKNOWN; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([sensors]) + ] + ) + ],[ + ]) + + AS_IF([test "x$with_sensors" = "xyes"], [ + ifdef([NO_PCI],[ + CHECK_CFLAGZ([-O0]) + ],[]) + m4_define([GOT_SENSR],[meltCPU]) + ]) + +]) diff --git a/m4/the_rest_funcs.m4 b/m4/the_rest_funcs.m4 new file mode 100644 index 0000000..0f7c714 --- /dev/null +++ b/m4/the_rest_funcs.m4 @@ -0,0 +1,482 @@ +dnl 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl Internal function to let the user know +dnl when some of the compile tests is about to begin +AC_DEFUN([NOTIFY],[ + AC_MSG_NOTICE([performing $1 compile test.]) +]) + + +dnl TEST_SOME_FUNCS() function in configure.ac +dnl +dnl The tests are simple enough, just to +dnl catch misbehaving compiler and/or +dnl installed C libraries. +AC_DEFUN([TEST_SOME_FUNCS],[ + + NOTIFY([strftime]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + char test[200]; + time_t t = time(NULL); + strftime(test, 190, "%I:%M %p", localtime(&t)); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([strftime]) + ] + ) + + + NOTIFY([statvfs]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + struct statvfs ssd; + statvfs(getenv("HOME"), &ssd); + ssd.f_blocks; + ssd.f_bsize; + ssd.f_bavail; + ssd.f_bfree; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([statvfs storage]) + ] + ) + + + NOTIFY([uname]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + struct utsname KerneL; + uname(&KerneL); + KerneL.sysname; + KerneL.nodename; + KerneL.release; + KerneL.version; + KerneL.machine; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([uname Kernel]) + ] + ) + + + ifdef([LINUKS],[ + NOTIFY([sysinfo]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + struct sysinfo inf; + sysinfo(&inf); + inf.totalram; + inf.freeram; + inf.sharedram; + inf.bufferram; + inf.loads[0]; + inf.loads[1]; + inf.loads[2]; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([sysinfo RAM and average load]) + ] + ) + + ],[]) + + + NOTIFY([openNreadFile]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + FILE *test = fopen("/proc/stat", "r"); + if (NULL == test) { + return 0; + } + fclose(test); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([openNreadFile]) + ] + ) + + + NOTIFY([memset]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + uintmax_t test[5]; + memset(test, 0, sizeof(test)); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([memset]) + ] + ) + + + ifdef([LINUKS],[ + NOTIFY([glob]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + glob_t gl; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([glob]) + ] + ) + + ],[]) + + + NOTIFY([sysconf]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + if (-1 == (sysconf(_SC_CLK_TCK))) { + return 0; + } + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([sysconf]) + ] + ) + + + NOTIFY([snprintf]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + char test[10]; + snprintf(test, 8, "%s", "hi"); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([snprintf]) + ] + ) + + + NOTIFY([getopt]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #define NULL ((void *)0) + int main(void) { + const struct option options[] = { + { "mpd", no_argument, NULL, 'M' }, + { "statio", required_argument, NULL, 'S' }, + { NULL, 0, NULL, 0 } + }; + + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([getopt]) + ] + ) + + + NOTIFY([timespec]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + struct timespec tc = {0}; + tc.tv_nsec = 85000L; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([timespec]) + ] + ) + + + NOTIFY([popen]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + char hi[30]; + FILE *test = popen("echo elo", "r"); + fscanf(test, "%s", hi); + pclose(test); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([popen]) + ] + ) + + + NOTIFY([clock_gettime]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + struct timespec tc1 = {0}, tc2 = {0}; + clock_gettime(CLOCK_MONOTONIC, &tc1); + + #if defined(__linux__) + clock_gettime(CLOCK_BOOTTIME, &tc2); + #endif + + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([clock_gettime]) + ] + ) + + + ifdef([FREEBZD],[ + NOTIFY([getloadavg]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + double up[3]; + getloadavg(up, 3); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([getloadavg]) + ] + ) + + + NOTIFY([sysctl]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + #define SYSCTLVAL(x, y, z) \ + if (0 != sysctlbyname(x, y, z, NULL, 0)) { \ + return 0; \ + } + int main(void) { + u_int dummy = 0; + size_t len = sizeof(dummy); + SYSCTLVAL("vm.stats.vm.v_page_size", &dummy, &len); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([sysctl]) + ] + ) + + + NOTIFY([malloc]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + char *a = (char *)malloc(10); + if (NULL == a) { + return 0; + } + free(a); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([malloc]) + ] + ) + + m4_foreach([LiB], [ + devstat_checkversion , + devstat_getdevs , + devstat_selectdevs + ],[ + AC_CHECK_LIB(devstat,LiB,[],[ + MISSING_FUNC() + ]) + ]) + + NOTIFY([devstat]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + int main(void) { + struct statinfo stats; + struct device_selection *dev_select = NULL; + struct devstat *d = NULL; + devstat_checkversion(NULL); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([devstat]) + ] + ) + + m4_foreach([LiB], [ + argp_parse , + argp_usage + ],[ + AC_CHECK_LIB(argp,LiB,[],[ + MISSING_FUNC() + ]) + ]) + + + NOTIFY([xswdev-swap]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + #include + #include + #include + #include + #include + int main(void) { + struct xswdev xsw; + u_int pagesize = 4096, dummy = 0; + uintmax_t total = 0, used = 0, pz = 0; + int mib[20]; + memset(mib, 0, sizeof(mib)); + size_t mibi = sizeof(mib) / sizeof(mib[0]); + size_t len = sizeof(dummy), sisi = sizeof(struct xswdev); + + pz = (uintmax_t)pagesize; + if (0 != (sysctlnametomib("vm.swap_info", mib, &mibi))) { + return 0; + } + if (0 != (sysctl(mib, (u_int)(mibi + 1), &xsw, &sisi, NULL, 0))) { + return 0; + } + if (xsw.xsw_version != XSWDEV_VERSION) { + return 0; + } + used = (uintmax_t)xsw.xsw_used; + total = (uintmax_t)xsw.xsw_nblks; + + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([xswdev-swap]) + ] + ) + + ],[]) + + + ifdef([OPENBZD],[ + NOTIFY([swapctl]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + struct swapent *dev = NULL; + swapctl(SWAP_NSWAP, 0, 0); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([swapctl]) + ] + ) + + NOTIFY([apm battery]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + #include + #include + int main(void) { + struct apm_power_info bstate; + int fd = 0; + uintmax_t dummy = 0; + memset(&bstate, 0, sizeof(struct apm_power_info)); + if (0 != (fd = open("/dev/apm", O_RDONLY))) { + return 0; + } + if (0 != (ioctl(fd, APM_IOC_GETPOWER, &bstate))) { + close(fd); + return 0; + } + close(fd); + if (APM_BATT_UNKNOWN == bstate.battery_state || + APM_BATTERY_ABSENT == bstate.battery_state) { + return 0; + } + dummy = (uintmax_t)bstate.battery_life; + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([apm battery]) + ] + ) + + ],[]) + + + +]) diff --git a/m4/typez.m4 b/m4/typez.m4 new file mode 100644 index 0000000..8136c2b --- /dev/null +++ b/m4/typez.m4 @@ -0,0 +1,168 @@ +dnl 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl Internal function to perform +dnl explicit data check type +AC_DEFUN([CHECK_TYPEZ],[ + AC_CHECK_TYPES([$1],[],[ + AC_MSG_WARN([Some C data type failed, checking which one.]) + m4_foreach([tYpe], [$1],[ + AC_CHECK_SIZEOF(tYpe) + ])dnl + ERR([Your compiler does not understand C data types.]) + ]) +]) + + +dnl TEST_TYPEZ() function in configure.ac +dnl +dnl Check for the presence of all used +dnl library functions, their header files +dnl and some int types. 64bit is not +dnl mandatory since uintmax makes it +dnl easy for us. +AC_DEFUN([TEST_TYPEZ],[ + + CHECK_TYPEZ([ + size_t, + time_t, + float, + double, + signed char, + unsigned char, + signed short int, + int8_t, + signed int, + int16_t, + signed long int, + int32_t, + intmax_t, + unsigned short int, + uint8_t, + unsigned int, + uint16_t, + unsigned long int, + uint32_t, + uintmax_t, + int_least8_t, + int_least16_t, + int_least32_t, + uint_least8_t, + uint_least16_t, + uint_least32_t, + int_fast8_t, + int_fast16_t, + int_fast32_t, + uint_fast8_t, + uint_fast16_t, + uint_fast32_t + ]) + + AC_CHECK_HEADERS([ \ + time.h \ + stdio.h \ + stdbool.h \ + string.h \ + inttypes.h \ + sys/statvfs.h \ + sys/utsname.h \ + unistd.h \ + getopt.h \ + sys/socket.h \ + ],[],[ + MISSING_HEADER() + ]) + + ifdef([FREEBZD], [ + AC_CHECK_HEADERS([ \ + sys/types.h \ + sys/sysctl.h \ + sys/param.h \ + sys/stat.h \ + vm/vm_param.h \ + ],[],[ + MISSING_HEADER() + ]) + + ], [ + ifdef([LINUKS],[ + AC_CHECK_HEADERS([ \ + argp.h \ + sys/sysinfo.h \ + glob.h \ + ],[],[ + MISSING_HEADER() + ]) + ],[ + ]) + + ]) + + AC_CHECK_FUNCS([ \ + memset \ + printf \ + snprintf \ + nanosleep \ + sysconf \ + strcmp \ + fscanf \ + fclose \ + fopen \ + statvfs \ + getenv \ + popen \ + uname \ + strftime \ + exit \ + getopt \ + getopt_long \ + + ],[],[ + MISSING_FUNC() + ]) + + ifdef([FREEBZD], [ + AC_CHECK_FUNCS([ \ + sysctl \ + sysctlbyname \ + sysctlnametomib \ + getloadavg \ + malloc \ + free \ + ],[],[ + MISSING_FUNC() + ]) + + ], [ + + ifdef([LINUKS],[ + AC_CHECK_FUNCS([ \ + sysinfo \ + glob \ + globfree \ + argp_parse \ + argp_usage \ + ],[],[ + MISSING_FUNC() + ]) + ],[ + ]) + + ]) + +]) diff --git a/m4/weather.m4 b/m4/weather.m4 new file mode 100644 index 0000000..e28e188 --- /dev/null +++ b/m4/weather.m4 @@ -0,0 +1,232 @@ +dnl 10/07/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_WEATHER() function in configure.ac +dnl +dnl Substitute the linker flags -lcurl to the +dnl the variable 'CURL_LIBS' if the user enabled +dnl the --with-weather switch +AC_DEFUN([TEST_WEATHER],[ + CURL_LIBS="" + API_KEY=\""g0tm1lf"\" + DRIVE_PORT=\""7634"\" + WITH_WEATHER=0 + WITH_DRIVETEMP=0 + WITH_DRIVETEMP_LIGHT=0 + + AC_ARG_WITH([weather], + AS_HELP_STRING([--with-weather], + [weather linker flag to show the todays temperature]), + [], + [with_weather=no] + ) + + AC_ARG_WITH([drivetemp], + AS_HELP_STRING([--with-drivetemp], + [Read the drive temperature from S.M.A.R.T]), + [], + [with_drivetemp=no] + ) + + AC_ARG_WITH([drivetemp-light], + AS_HELP_STRING([--with-drivetemp-light], + [Read the drive temperature from S.M.A.R.T]), + [], + [with_drivetemp_light=no] + ) + + AC_ARG_WITH([smartemp], + AS_HELP_STRING([--with-smartemp], + [Read the drive temperature from S.M.A.R.T]), + [], + [with_smartemp=no] + ) + + AC_ARG_VAR(drive_port, [TCP port to listen to]) + AC_ARG_VAR(api_key, [weather api key]) + + AS_IF([test "x$with_drivetemp" = "xyes" && test "x$with_drivetemp_light" = "xyes"],[ + with_drivetemp=no + ]) + + ifdef([LINUKS],[ + AS_IF([test "x$with_drivetemp_light" = "xyes"],[ + WITH_DRIVETEMP_LIGHT=1 + + AC_CHECK_HEADERS([ \ + sys/socket.h \ + netdb.h \ + ],[],[ + MISSING_HEADER() + ]) + + NOTIFY([drivetemp-light]) + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + #include + #include + #include + #include + + #define CLOSE_FD2(fd, res) \ + if (-1 == (close(fd))) { \ + freeaddrinfo(res); \ + exit(EXIT_FAILURE); \ + } + + int main(void) { + struct addrinfo *rp = NULL, *result = NULL, hints; + int sock = 0; + char buf[200]; + bool got_conn = false; + ssize_t len = 0; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (0 != (getaddrinfo("127.0.0.1", "7634", &hints, &result))) { + return EXIT_FAILURE; + } + + for (rp = result; NULL != rp; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (-1 == sock) { + continue; + } + if (NULL == rp->ai_addr) { + CLOSE_FD2(sock, result); + continue; + } + if (0 == (connect(sock, rp->ai_addr, rp->ai_addrlen))) { + len = recv(sock, buf, sizeof(buf), 0); + got_conn = true; + break; + } + CLOSE_FD2(sock, result); + } + + if (true == got_conn) { + CLOSE_FD2(sock, result); + if (0 < len) { + printf("%s\n", buf); + } + } + + if (NULL != result) { + freeaddrinfo(result); + } + return EXIT_SUCCESS; + } + ]]) + ],[],[ + COMPILE_FAILED([drivetemp-light]) + ] + ) + + ]) + + AS_IF([test "x$with_drivetemp" = "xyes"],[ + WITH_DRIVETEMP=1 + ]) + + if [[ ! -z "${drive_port}" ]] + then + DRIVE_PORT=\""${drive_port}"\" + fi + + ],[ + ]) + + AS_IF([test "x$with_weather" = "xyes" || test "x$with_drivetemp" = "xyes"], [ + CHECK_CFLAGZ([-O0]) + + AC_CHECK_HEADERS([curl/curl.h], [ + CURL_LIBS="-lcurl" + ],[ + ERR_MUST_INSTALL([curl and or libcurl]) + ]) + + m4_foreach([LiB], [ + curl_global_init , + curl_easy_init , + curl_easy_setopt , + curl_easy_perform , + curl_easy_cleanup , + curl_global_cleanup + ],[ + AC_CHECK_LIB(curl,LiB,[],[ + MISSING_FUNC() + ]) + ]) + + if [[ ! -z "${api_key}" ]] + then + API_KEY=\""${api_key}"\" + fi + + AS_IF([test "x$with_weather" = "xyes"],[ + WITH_WEATHER=1 + AC_DEFINE_UNQUOTED([API_KEY],[$API_KEY],[weather api key]) + ]) + + ]) + + AC_SUBST(CURL_LIBS) + AC_DEFINE_UNQUOTED([WITH_WEATHER],[$WITH_WEATHER],[Santa is here]) + AC_DEFINE_UNQUOTED([DRIVE_PORT],[$DRIVE_PORT],[TCP port to listen to]) + AC_DEFINE_UNQUOTED([WITH_DRIVETEMP],[$WITH_DRIVETEMP],[Gettin hot in here]) + AC_DEFINE_UNQUOTED([WITH_DRIVETEMP_LIGHT],[$WITH_DRIVETEMP_LIGHT],[Gettin hot in here]) + + AS_IF([test "x$with_weather" = "xyes" || test "x$with_drivetemp" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + int main(void) { + CURL *curl = NULL; + CURLcode res; + curl_global_init(CURL_GLOBAL_ALL); + if (NULL == (curl = curl_easy_init())) { + goto error; + } + curl_easy_setopt(curl, CURLOPT_URL, "http://google.com"); + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip"); + res = curl_easy_perform(curl); + if (CURLE_OK != res) { + goto error; + } + error: + if (NULL != curl) { + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return 0; + } + ]]) + ],[],[ + LINK_FAILED([curl]) + ] + ) + ]) + +]) diff --git a/m4/x11.m4 b/m4/x11.m4 new file mode 100644 index 0000000..ec0c242 --- /dev/null +++ b/m4/x11.m4 @@ -0,0 +1,186 @@ +dnl Copyright 07/06/2015, 08/03/2016 + +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +dnl MA 02110-1301, USA. + + +dnl TEST_X11() function in configure.ac +dnl +dnl Check for the presence of X11 headers and +dnl substitute the linker flags -lX11 to the +dnl the variable 'X_LIBS' if they are available. +AC_DEFUN([TEST_X11],[ + X_LIBS="" + WITH_COLOURS=0 + + AC_ARG_WITH([x11], + AS_HELP_STRING([--with-x11], + [X11 linker flag for dwm support]), + [], + [with_x11=no] + ) + + AC_ARG_WITH([colours], + AS_HELP_STRING([--with-colours], + [Colorize the output]), + [], + [with_colours=no] + ) + + AC_ARG_VAR(icons, [path to xbm icons for non-dwm WM]) + + AS_IF([test "x$with_colours" = "xyes"], [ + WITH_COLOURS=1 + ]) + + AS_IF([test "x$with_x11" = "xyes"], [ + AC_CHECK_HEADERS([X11/Xlib.h], [ + X_LIBS="-lX11" + ],[ + ERR_MUST_INSTALL([xorg and libx11]) + ]) + + m4_foreach([LiB], [ + XOpenDisplay, + XStoreName, + XSync, + XCloseDisplay + ],[ + AC_CHECK_LIB(X11,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + + dnl xbm icons for non-dwm window manager + if [[ ! -z "${icons}" ]] + then + dnl Da stupid shell expansion only works on "UNQUOTED" + ICONZ=\""${icons}"\" + AC_DEFINE_UNQUOTED([ICONS_DIR],[$ICONZ],[xbm icons for non-dwm WM]) + fi + + AC_SUBST(X_LIBS) + AC_DEFINE_UNQUOTED([WITH_COLOURS],[$WITH_COLOURS],[Colorize the output]) + + AS_IF([test "x$with_x11" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + Display *display; + Window window; + XEvent evt; + return 0; + } + ]]) + ],[],[ + LINK_FAILED([X11]) + ] + ) + ]) + + AS_IF([test "x$with_x11" = "xno"], [ + TEST_NCURSES() + ]) + +]) + + +dnl Test for the presence of the ncurses library +dnl and substitute macro to determine whether the +dnl program to be compiled with/out ncurses colours +AC_DEFUN([TEST_NCURSES], [ + WITH_NCURSES=0 + + AC_ARG_WITH([ncurses], + AS_HELP_STRING([--with-ncurses], + [Output the data to your terminal using the ncurses library.]), + [], + [with_ncurses=no] + ) + + AS_IF([test "x$with_ncurses" = "xyes"], [ + AC_CHECK_HEADERS([ncurses.h], [ + WITH_NCURSES=1 + ],[ + ERR_MUST_INSTALL([ncurses]) + ]) + + m4_foreach([LiB], [ + initscr , + noecho , + cbreak , + halfdelay , + nonl , + intrflush , + curs_set , + start_color , + init_pair , + refresh , + clear , + endwin , + has_colors , + pair_content , + wattrset , + waddch + ],[ + AC_CHECK_LIB(ncurses,LiB,[],[ + MISSING_FUNC() + ]) + ]) + ]) + + AS_IF([test "x$with_ncurses" = "xyes"], [ + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #include + int main(void) { + initscr(); + printw("elo"); + refresh(); + endwin(); + return 0; + } + ]]) + ],[],[ + LINK_FAILED([ncurses]) + ] + ) + + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + #include + #include + void sighandler(int num); + void sighandler(int num) { + exit(1); + } + int main(void) { + signal(SIGINT, sighandler); + return 0; + } + ]]) + ],[],[ + COMPILE_FAILED([signal]) + ] + ) + + ]) + + AC_DEFINE_UNQUOTED([WITH_NCURSES],[$WITH_NCURSES],[Where to output the data]) + +]) diff --git a/set.pl b/set.pl new file mode 100644 index 0000000..6e2517b --- /dev/null +++ b/set.pl @@ -0,0 +1,144 @@ +# 11/01/2016 + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +use strict; +use warnings; + +use File::Copy; +use List::Util qw(any); + +sub re_read { + my ($filename) = @_; + my $derefs = $$filename; + my $fh; + + open($fh, '<:encoding(UTF-8)', $derefs) + or die "Could not open file '$derefs' $!"; + local $/ = undef; # <--- slurp mode + my $concatArr = <$fh>; + close($fh); + + return \$concatArr; +} + +sub re_write { + my ($filename,$concatArr) = @_; + my $derefs = $$filename; + my $fh; + + open($fh, '>:encoding(UTF-8)', $derefs) + or die "Could not open file '$derefs' $!"; + + print $fh $$concatArr; + close($fh); + return; +} + +sub reflace_configure { + my ($new) = @_; + my $filename = "configure.ac"; + my @arr = split("\n",${re_read(\$filename)}); + + if ($arr[9]) { + $arr[9] = $$new; + } + my $concatArr = join("\n", @arr); + + re_write(\$filename,\$concatArr); + return; +} + +sub reflace_many { + my ($arr,$filename) = @_; + my $derefFilename = $$filename; + my @arr2 = @$arr; + my ($x,$arrLen) = (0,$#arr2); + my $derefs = ${re_read(\$derefFilename)}; + + for (; $x <= $arrLen; $x++) { + $derefs =~ s/${$arr2[$x][0]}/${$arr2[$x][1]}/g; + } + re_write(\$derefFilename,\$derefs); + return; +} + +sub reflace_single { + my ($ag1,$ag2,$filename) = @_; + my $derefFilename = $$filename; + my $derefs = ${re_read(\$derefFilename)}; + + $derefs =~ s/$$ag1/$$ag2/g; + re_write(\$derefFilename,\$derefs); + return; +} + + +{ + + if (-1 == $#ARGV) { + die "No OS/Distro supplied."; + } + + my $osEntered = uc $ARGV[0]; + my @osArr = ( + "ARCHLINUX","DEBIAN", + "GENTOO","SLACKWARE", + "RHEL","FRUGALWARE", + "ANGSTROM","FREEBSD","OPENBSD" + ); + my $hasMatch = any { $_ eq $osEntered } @osArr; + if ($hasMatch eq "") { + die "Invalid OS/Distro supplied."; + } + + my $srcMake = "src/Makefile.am"; + my $defTits = "m4_define([cuRos],[$osEntered])"; + my $bsdCF = "-D_DEFAULT_SOURCE -L/usr/local/lib"; + my $posixCF = "-D_POSIX_C_SOURCE=200112L"; + my ($amStr, $srcStr, $bsdStr) = ("{amCF}","{srcFiles}","{bzdlibs}"); + my ($amCF, $srcToAppend, $bsdLibs) = ("", "", ""); + + if ($osEntered eq "FREEBSD") { + $bsdLibs = "-largp -ldevstat"; + $amCF = \$bsdCF; + $defTits = "$defTits m4_define([FREEBZD], [tits])"; + $srcToAppend = "freebsd_functions.c include/freebzd.h"; + } + elsif ($osEntered eq "OPENBSD") { + $bsdLibs = "-largp -lossaudio"; + $amCF = \$bsdCF; + $defTits = "$defTits m4_define([OPENBZD], [forSure])"; + $srcToAppend = "openbsd_functions.c include/openbzd.h"; + } + else { + $amCF = \$posixCF; + $defTits = "$defTits m4_define([LINUKS], [cryMeAriver])"; + $srcToAppend = "linux_functions.c"; + } + + copy("src/Makefail.skel",$srcMake) + or die "Could not copy src/Makefail.skel $!"; + + reflace_configure(\$defTits); + + my @hugeArr = ( + [\$amStr, \$$amCF], + [\$srcStr, \$srcToAppend], + [\$bsdStr, \$bsdLibs] + ); + reflace_many(\@hugeArr,\$srcMake); +} diff --git a/src/Makefail.skel b/src/Makefail.skel new file mode 100644 index 0000000..f8fe218 --- /dev/null +++ b/src/Makefail.skel @@ -0,0 +1,37 @@ +AM_CFLAGS = {amCF} \ + -I/usr/local/include $(LIBNL_CF) $(PERL_CF) $(PYTHON_CF) $(RUBY_CF) + +bin_PROGRAMS = pinkybar + +pinkybar_LDADD = $(X_LIBS) $(ALSA_LIBS) $(MPD_LIBS) $(PCI_LIBS) $(DVD_LIBS) $(SENSORS_LIBS) $(CURL_LIBS) $(LIBNL_LZ) $(PERL_LZ) $(LUA_LIBS) $(PYTHON_LZ) $(RUBY_LZ) {bzdlibs} +pinkybar_SOURCES = main.c \ + cpu.c \ + common.c \ + sound.c \ + options.c \ + net.c \ + weather.c \ + smart.c \ + perl.c \ + lua.c \ + ruby.c \ + python.c \ + prototypes/cpu.h \ + prototypes/common.h \ + prototypes/sound.h \ + prototypes/net.h \ + prototypes/functions.h \ + prototypes/options.h \ + prototypes/weather.h \ + prototypes/smart.h \ + prototypes/perl.h \ + prototypes/lua.h \ + prototypes/ruby.h \ + prototypes/python.h \ + include/headers.h \ + include/options_constants.h \ + include/functions_constants.h \ + include/non_x11_colours.h \ + include/x11_colours.h \ + include/options_generator.h \ + {srcFiles} diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..1aea6df --- /dev/null +++ b/src/common.c @@ -0,0 +1,474 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +/* Functions shared between different operating + * zyztemz or are short enough that doesn't meet the + * 100 lines requirement to be put in standalone module */ + +#include "config.h" /* Auto-generated */ + +#include + +#include +#include + +#if defined(__linux__) +#include +#endif /* __linux__ */ + +#if defined (HAVE_X11_XLIB_H) +#include +#endif + +#if defined(HAVE_CDIO_CDIO_H) +#include +#include +#endif /* HAVE_CDIO_CDIO_H */ + +#include "include/headers.h" + +#if defined(__FreeBSD__) +#include "include/freebzd.h" +#endif /* __FreeBSD__ */ + +#if defined(__OpenBSD__) +#include "include/openbzd.h" +#endif /* __OpenBSD__ */ + + +#if defined(__linux__) +static uint_fast16_t glob_packages(const char *); +#endif /* __linux__ */ + +void +exit_with_err(const char *str1, const char *str2) { + FPRINTF("%s %s\n", str1, str2); + exit(EXIT_FAILURE); +} + + +#if defined(__linux__) +void +get_temp(const char *str1, char *str2) { + uint_least32_t temp = 0; + FILE *fp = NULL; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, str1, SCAN_ULINT, &temp); +#pragma GCC diagnostic pop + + if (99999 < temp) { /* > 99C */ + FILL_ARR(str2, ULINT, temp / 10000); + } else { + FILL_ARR(str2, ULINT, ((9999 < temp) ? + temp / 1000 : temp / 100)); /* > 9C || < 9C */ + } +} + +#endif /* __linux__ */ + +#if defined(__FreeBSD__) +void +get_temp(char *str1, uint_least32_t temp) { + if (9999 < temp) { /* > 99C */ + FILL_ARR(str1, ULINT, temp / 1000); + } else { + FILL_ARR(str1, ULINT, ((999 < temp) ? + temp / 100 : temp / 10)); /* > 9C || < 9C */ + } +} +#endif /* __FreeBSD__ */ + + +void +check_fan_vals(char *str1, uint_fast16_t *rpm, uint_fast16_t iterz) { + uint_fast16_t x = 0, y = 0; + char buffer[VLA]; + char *all_fans = buffer; + + for (x = 0; x < iterz; x++) { + if (0 != rpm[x]) { + GLUE2(all_fans, UFINT" ", rpm[x]); + } else { + ++y; /* non-spinning | removed | failed fan */ + } + } + FILL_STR_ARR(1, str1, (y != x ? buffer : NOT_FOUND)); + +} + + +void +get_ssd(char *str1, uint8_t num) { + uintmax_t val = 0; + struct statvfs ssd; + memset(&ssd, 0, sizeof(struct statvfs)); + + if (-1 == (statvfs(getenv("HOME"), &ssd))) { + FUNC_FAILED("statvfs()"); + } + + switch(num) { + case 1: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)(ssd.f_blocks * ssd.f_bsize) / GB, "GB"); + break; + case 2: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)(ssd.f_bfree * ssd.f_bsize) / GB, "GB"); + break; + case 3: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)(ssd.f_bavail * ssd.f_bsize) / GB, "GB"); + break; + case 4: + { + val = (uintmax_t)(( + ssd.f_blocks - ssd.f_bfree) * ssd.f_bsize) / GB; + FILL_UINT_ARR(str1, val); + } + break; + } +} + + +void +get_kernel(char *str1, uint8_t num) { + struct utsname KerneL; + memset(&KerneL, 0, sizeof(struct utsname)); + + if (-1 == (uname(&KerneL))) { + FUNC_FAILED("uname()"); + } + + switch(num) { + case 1: + FILL_STR_ARR(1, str1, KerneL.sysname); + break; + case 2: + FILL_STR_ARR(1, str1, KerneL.nodename); + break; + case 3: + FILL_STR_ARR(1, str1, KerneL.release); + break; + case 4: + FILL_STR_ARR(1, str1, KerneL.version); + break; + case 5: + FILL_STR_ARR(1, str1, KerneL.machine); + break; + case 6: + FILL_STR_ARR(2, str1, KerneL.sysname, KerneL.release); + break; + } +} + + +#if defined(__linux__) +/* Source (my improved screenfetch-c fork): + * https://github.com/wifiextender/screenfetch-c/blob/master/src/plat/linux/detect.c */ +static uint_fast16_t +glob_packages(const char *str1) { + uint_fast16_t packs_num = 0; + glob_t gl; + + if (0 == (glob(str1, GLOB_NOSORT, NULL, &gl))) { + packs_num = gl.gl_pathc; + } else { + exit_with_err("Could not traverse", str1); + } + globfree(&gl); + + return packs_num; +} +#endif /* __linux__ */ + + +/* Let the compiler strip the code + * instead conditionally checking + * each time the program is executed */ +void +get_packs(char *str1) { + uint_fast16_t packages = 0; + FILE *pkgs_file = NULL; + +#if defined(ARCHLINUX) + packages = glob_packages("/var/lib/pacman/local/*"); + +#elif defined(FRUGALWARE) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_POPEN(pkgs_file, "pacman-g2 -Q 2> /dev/null | wc -l", &packages); +#pragma GCC diagnostic pop + +#elif defined(DEBIAN) + packages = glob_packages("/var/lib/dpkg/info/*.list"); + +#elif defined(SLACKWARE) + packages = glob_packages("/var/log/packages/*"); + +#elif defined(GENTOO) + packages = glob_packages("/var/db/pkg/*/*"); + +#elif defined(RHEL) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_POPEN(pkgs_file, "rpm -qa 2> /dev/null | wc -l", &packages); +#pragma GCC diagnostic pop + +#elif defined(ANGSTROM) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_POPEN(pkgs_file, "opkg list-installed 2> /dev/null | wc -l", &packages); +#pragma GCC diagnostic pop + +#elif defined(FREEBSD) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_POPEN(pkgs_file, "pkg info | wc -l", &packages); +#pragma GCC diagnostic pop + +#elif defined(OPENBSD) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_POPEN(pkgs_file, "pkg_info | wc -l", &packages); +#pragma GCC diagnostic pop + + +#endif + + FILL_ARR(str1, UFINT, packages); +} + + +void +get_uptime(char *str1) { + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + struct timespec tc = {0}; +#pragma GCC diagnostic pop + + uintmax_t now = 0; + +#if defined(__linux__) + if (-1 == (clock_gettime(CLOCK_BOOTTIME, &tc))) { + FUNC_FAILED("clock_gettime()"); + } + + now = (uintmax_t)tc.tv_sec; +#else + int mib[] = { CTL_KERN, KERN_BOOTTIME }; + time_t t; + size_t len = sizeof(tc); + + if (0 != (sysctl(mib, 2, &tc, &len, NULL, 0))) { + FUNC_FAILED("sysctl()"); + } + + if (-1 == (t = time(NULL))) { + FUNC_FAILED("time()"); + } + + now = (uintmax_t)t - (uintmax_t)tc.tv_sec; +#endif /* __linux__ */ + + if (0 != (now / 86400)) { /* days */ + FILL_ARR(str1, FMT_UINT "d " FMT_UINT "h " FMT_UINT "m", + (now / 86400), + ((now / 3600) % 24), + ((now / 60) % 60)); + return; + } + if (59 < (now / 60)) { /* hours */ + FILL_ARR(str1, FMT_UINT "h " FMT_UINT "m", + ((now / 3600) % 24), + ((now / 60) % 60)); + return; + } + + FILL_ARR(str1, FMT_UINT "m", ((now / 60) % 60)); +} + + +/* The `strftime' man page showed potential bugs */ +void +get_taim(char *str1) { + char time_str[VLA]; + time_t t = 0; + struct tm *taim = NULL; + + if (-1 == (t = time(NULL)) || + NULL == (taim = localtime(&t)) || + 0 == (strftime(time_str, VLA, "%I:%M %p", taim))) { + exit_with_err(ERR, "time() or localtime() or strftime() failed"); + } + FILL_STR_ARR(1, str1, time_str); +} + + +#if defined (HAVE_X11_XLIB_H) +void +set_status(const char *str1) { + Display *display = XOpenDisplay(NULL); + + if (display) { + XStoreName(display, DefaultRootWindow(display), str1); + XSync(display, 0); + XCloseDisplay(display); + + } else { + exit_with_err(CANNOT_OPEN, "X server"); + } +} +#endif /* HAVE_X11_XLIB_H */ + + +#if !defined(HAVE_SENSORS_SENSORS_H) && !defined(__OpenBSD__) +void +get_fans(char *str1) { + bool found_fans = true; + char tempstr[VLA]; + uint_fast16_t x = 0, y = 0, z = 0, rpm[MAX_FANS+1]; + + memset(rpm, 0, sizeof(rpm)); + +#if defined(__linux__) + FILE *fp = NULL; + for (x = 1; x < MAX_FANS; x++, z++) { + FILL_ARR(tempstr, FAN_FILE, x); + + if (NULL == (fp = fopen(tempstr, "r"))) { + if (1 == x) { /* no system fans at all */ + FILL_STR_ARR(1, str1, NOT_FOUND); + found_fans = false; + } + break; + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_FSCANF(fp, SCAN_UFINT, &rpm[z]); +#pragma GCC diagnostic pop + CLOSE_X(fp); + } + +#else + + u_int fan[3]; + memset(fan, 0, sizeof(fan)); + size_t len = sizeof(fan); + + for (x = 0; x < MAX_FANS; x++, z++) { + FAN_STR(tempstr, x); + memset(fan, 0, len); + + if (0 != (sysctlbyname(tempstr, &fan, &len, NULL, 0))) { + if (0 == x) { /* no system fans at all */ + FILL_STR_ARR(1, str1, NOT_FOUND); + found_fans = false; + } + break; + } + rpm[x] = (uint_fast16_t)fan[0]; + } + +#endif /* __linux__ */ + + if (true == found_fans) { + check_fan_vals(str1, rpm, z); + } +} +#endif /* !HAVE_SENSORS_SENSORS_H && !__OpenBSD__ */ + + +#if defined(HAVE_CDIO_CDIO_H) +void +get_dvd(char *str1) { + CdIo_t *p_cdio = cdio_open(NULL, DRIVER_DEVICE); + cdio_hwinfo_t hwinfo; + + FILL_STR_ARR(1, str1, "Null"); + if (NULL == p_cdio) { + return; + } + if (true == (mmc_get_hwinfo(p_cdio, &hwinfo))) { + FILL_STR_ARR(2, str1, hwinfo.psz_vendor, hwinfo.psz_model); + } + if (NULL != p_cdio) { + cdio_destroy(p_cdio); + } +} +#else + +#if defined(__linux__) +void +get_dvd(char *str1) { + FILE *fp = NULL; + char vendor[100], model[100]; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, DVD_VEND, "%s", vendor); +#pragma GCC diagnostic pop + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, DVD_MODEL, "%s", model); +#pragma GCC diagnostic pop + + FILL_STR_ARR(2, str1, vendor, model); +} +#endif /* __linux__ */ + +#endif /* HAVE_CDIO_CDIO_H */ + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +void +get_loadavg(char *str1) { + double up[3]; + memset(up, 0, sizeof(up)); + + if (-1 == (getloadavg(up, 3))) { + FUNC_FAILED("getloadavg()"); + } + FILL_ARR(str1, "%.2f %.2f %.2f", + (float)up[0], (float)up[1], (float)up[2]); +} +#endif /* __FreeBSD__ || __OpenBSD__ */ + + +void +split_n_index(char *str1) { + char *ptr = str1; + for (; *ptr; ptr++) { + if (0 != (isspace((unsigned char) *ptr))) { + break; + } + *str1++ = *ptr; + } + *str1 = '\0'; +} diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 0000000..e3c38e9 --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,466 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#include "include/headers.h" +#include "prototypes/cpu.h" + +#if defined(__FreeBSD__) +#include "include/freebzd.h" +#endif /* __FreeBSD__ */ + +#if defined(__OpenBSD__) +#include "include/openbzd.h" +#endif /* __OpenBSD__ */ + +void +get_cpu(char *str1) { + static uintmax_t previous_total = 0, previous_idle = 0; + uintmax_t total = 0, percent = 0, diff_total = 0, diff_idle = 0; + uintmax_t cpu_active[LOOP_ITERZ]; + uint8_t x = 0; + + memset(cpu_active, 0, sizeof(cpu_active)); + +#if defined(__FreeBSD__) + size_t len = sizeof(cpu_active); + SYSCTLVAL("kern.cp_time", &cpu_active); +#endif /* __FreeBSD__ */ + +#if defined(__OpenBSD__) + int mib[] = { CTL_KERN, KERN_CPTIME }; + size_t len = sizeof(cpu_active); + SYSCTLVAL(mib, 2, &cpu_active, &len); +#endif /* __OpenBSD__ */ + +#if defined(__linux__) + FILE *fp = fopen("/proc/stat", "r"); + CHECK_FP(fp); + + /* Some kernels will produce 7, 8 and 9 columns + * We rely on 10, refer to `man proc' for more details */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + if (EOF == (fscanf(fp, "%*s " FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT, + &cpu_active[0], &cpu_active[1], &cpu_active[2], &cpu_active[3], + &cpu_active[4], &cpu_active[5], &cpu_active[6], &cpu_active[7], + &cpu_active[8], &cpu_active[9]))) { + CLOSE_X(fp); + exit_with_err(ERR, "Upgrade to a newer kernel"); + } +#pragma GCC diagnostic pop + CLOSE_X(fp); +#endif /* __linux__ */ + + for (x = 0; x < LOOP_ITERZ; x++) { + total += cpu_active[x]; + } + + diff_total = total - previous_total; + diff_idle = cpu_active[IDLE_NUM] - previous_idle; + + previous_total = total; + previous_idle = cpu_active[IDLE_NUM]; + + percent = 0; + if (0 != diff_total) { + percent = ((uintmax_t)TICKZ * (diff_total - diff_idle)) / diff_total; + } + + FILL_UINT_ARR(str1, percent); +} + + +void +get_cores_load(char *str1) { + static uintmax_t previous_total[MAX_CORES], previous_idle[MAX_CORES]; + static bool test_flag = false; + uint8_t x = 0, y = 0, z = 0; + uintmax_t percent[MAX_CORES], diff_total[MAX_CORES], core_active[MAX_CORES][LOOP_ITERZ]; + uintmax_t diff_idle[MAX_CORES], total[MAX_CORES]; + char buf[VLA], temp[VLA]; + char *all = temp; + + memset(percent, 0, sizeof(percent)); + memset(diff_total, 0, sizeof(diff_total)); + memset(diff_idle, 0, sizeof(diff_idle)); + memset(total, 0, sizeof(total)); + memset(core_active, 0, sizeof(core_active)); + + if (false == test_flag) { + memset(previous_idle, 0, sizeof(previous_idle)); + memset(previous_total, 0, sizeof(previous_total)); + } + +#if defined(__FreeBSD__) + size_t len = sizeof(core_active); + SYSCTLVAL("kern.cp_times", &core_active); +#endif /* __FreeBSD__ */ + +#if defined(__OpenBSD__) + uintmax_t ncpu = 0; + int mib[] = { CTL_KERN, KERN_CPTIME2, 0 }; + int mib2[] = { CTL_HW, HW_NCPU }; + size_t len = sizeof(core_active), len2 = sizeof(ncpu); + + SYSCTLVAL(mib2, 2, &ncpu, &len2); + for (x = 0; x < ncpu; x++, mib[2]++) { + if (0 != (sysctl(mib, 3, &core_active[x], &len, NULL, 0))) { + break; + } + } +#endif /* __OpenBSD__ */ + +#if defined(__linux__) + FILE *fp = fopen("/proc/stat", "r"); + CHECK_FP(fp); + + if (NULL == (fgets(buf, VLA-1, fp))) { + CLOSE_X(fp); + exit_with_err(ERR, "reached /proc/stat EOF"); + } + + for (x = 0; x < MAX_CORES; x++, z++) { + if (NULL == (fgets(buf, VLA-1, fp))) { + CLOSE_X(fp); + exit_with_err(ERR, "reached /proc/stat EOF"); + } + + if ('c' != buf[0] && 'p' != buf[1] && 'u' != buf[2]) { + break; + } + + if (EOF == (sscanf(buf, "%*s " FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT, + &core_active[x][0], &core_active[x][1], &core_active[x][2], &core_active[x][3], + &core_active[x][4], &core_active[x][5], &core_active[x][6], &core_active[x][7], + &core_active[x][8], &core_active[x][9]))) { + CLOSE_X(fp); + exit_with_err(ERR, "Upgrade to a newer kernel"); + } + } + CLOSE_X(fp); + + for (x = 0; x < z; x++) { + +#else /* FreeBSD || OpenBSD */ + for (x = 0; x < MAX_CORES; x++) { + if (0 == core_active[x][0] && 0 == + core_active[x][1] && 0 == + core_active[x][2]) { + break; + } +#endif /* __linux__ */ + + for (y = 0; y < LOOP_ITERZ; y++) { + total[x] += core_active[x][y]; + } + + diff_total[x] = total[x] - previous_total[x]; + diff_idle[x] = core_active[x][IDLE_NUM] - previous_idle[x]; + + previous_total[x] = total[x]; + previous_idle[x] = core_active[x][IDLE_NUM]; + + percent[x] = 0; + if (0 != diff_total[x]) { + percent[x] = ((uintmax_t)TICKZ * (diff_total[x] - diff_idle[x])) + / diff_total[x]; + } + + GLUE2(all, FMT_UINT"%% ", percent[x]); + } + test_flag = true; + + FILL_STR_ARR(1, str1, temp); +} + + +#if defined(__i386__) || defined(__i686__) || defined(__x86_64__) +uint8_t has_tsc_reg(void) { + uint_fast16_t vend = 0, leafs = 0; + uint_fast16_t eax = 0, ecx = 0, edx = 0, ebx = 0; + + CPU_REGS(0x00000000, vend, leafs); + if (0x00000001 > leafs) { + return 1; + } + if (vend != AmD && vend != InteL) { + return 1; + } + + CPU_STR2(0x00000001, eax, ebx, ecx, edx); + if (0 == (edx & (1 << 4))) { + return 1; + } + return 0; +} +#endif /* __i386__ || __i686__ || __x86_64__ */ + + +/* Taken from the gcc documentation + * https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html + * + * other useful resources: + * http://www.felixcloutier.com/x86/RDTSC.html + * http://ref.x86asm.net/coder32.html#x0F31 +*/ + +/* Not going to test for i486 and i586 */ +#if defined(__i386__) || defined(__i686__) +static __inline__ uintmax_t +rdtsc(void) { + uintmax_t x = 0; + if (0 == (has_tsc_reg())) { + __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x)); + } + return x; +} + +void +get_cpu_clock_speed(char *str1) { + uintmax_t x = 0, y = 0, z[2]; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + struct timespec start = {0}, stop = {0}, tc = {0}; +#pragma GCC diagnostic pop + + tc.tv_nsec = TICKZ * 1000000L; + + x = rdtsc(); + if (-1 == (clock_gettime(CLOCK_MONOTONIC, &start))) { + FUNC_FAILED("clock_gettime()"); + } + z[0] = (uintmax_t)(start.tv_nsec - start.tv_sec); + + if (-1 == (nanosleep(&tc, NULL))) { + FUNC_FAILED("nanosleep()"); + } + + y = rdtsc(); + if (-1 == (clock_gettime(CLOCK_MONOTONIC, &stop))) { + FUNC_FAILED("clock_gettime()"); + } + z[1] = (uintmax_t)(stop.tv_nsec - stop.tv_sec); + + if (0 != (z[1] - z[0])) { + FILL_ARR(str1, FMT_UINT " MHz", + (1000 * (y - x) / (z[1] - z[0]))); + } +} + + +#elif defined(__x86_64__) +/* + * Thanks to Intel docs for pointing out + * "Out of Order Execution", added + * cpuid after reading it and edited the rdtscp + * code according to the docs + * https://www-ssl.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf */ +static __inline__ uintmax_t +rdtsc(void) { + unsigned int tickhi = 0, ticklo = 0; + uint_fast16_t eax = 0, ecx = 0, edx = 0, ebx = 0; + uint_fast16_t vend = 0, regz = 0, x = 0; + + if (0 != (has_tsc_reg())) { + goto seeya; + } + __asm__ __volatile__ ( + "cpuid\n\t" + "rdtsc\n\t" + : "=a"(ticklo), "=d"(tickhi) + :: "%rbx", "%rcx" + ); + + CPU_FEATURE(0x80000000, regz); + if (0x80000001 > regz) { + goto seeya; + } + CPU_STR2(0x80000001, eax, ebx, ecx, edx); + + if (0 != (edx & (1 << 27))) { + for (x = 0; x < 6; x++) { + __asm__ __volatile__ ( + "rdtscp\n\t" + "mov %%edx, %0\n\t" + "mov %%eax, %1\n\t" + "cpuid\n\t" + : "=r"(tickhi), "=r"(ticklo) + :: "%rax", "%rbx", "%rcx", "%rdx" + ); + } + } + +seeya: + return (((uintmax_t)tickhi << 32) | (uintmax_t)ticklo); +} + +void +get_cpu_clock_speed(char *str1) { + uintmax_t x = 0, z = 0; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + struct timespec tc = {0}; +#pragma GCC diagnostic pop + + tc.tv_nsec = TICKZ * 1000000L; + + x = rdtsc(); + if (-1 == (nanosleep(&tc, NULL))) { + FUNC_FAILED("nanosleep()"); + } + z = rdtsc(); + + FILL_ARR(str1, FMT_UINT " MHz", ((z - x) / 100000)); +} +#endif /* __i386__ || __i686__ || __x86_64__ */ + + +#if defined(__i386__) || defined(__i686__) || defined(__x86_64__) +void +get_cpu_info(char *str1) { + uint_fast16_t vend = 0, x = 0, z = 0, corez = 0, leafB = 0, bitz[2]; + uint_fast16_t eax = 0, ecx = 0, edx = 0, ebx = 0, eax_old = 0, leafs = 0; + uint_fast16_t line_size = 0, regz = 0, clflu6 = 0, caches[3]; + char buffer[VLA], vend_id[13], vend_chars[17]; + char *all = buffer; + bool got_leafB = false; + + memset(caches, 0, sizeof(caches)); + memset(bitz, 0, sizeof(bitz)); + FILL_STR_ARR(1, str1, "Null"); + + CPU_REGS(0x00000000, vend, leafs); /* movl $0x00000000, %eax */ + if (0x00000001 > leafs) { + return; + } + if (vend != AmD && vend != InteL) { + return; + } + + CPU_FEATURE(0x80000000, regz); /* movl $0x80000000, %eax */ + if (0x80000004 > regz) { + return; + } + CPU_FEATURE(0x00000001, eax_old); /* movl $0x00000001, %eax */ + + for (x = 0x80000002; x <= 0x80000004; x++) { /* movl $0x80000002, %esi */ + CPU_STR2(x, eax, ebx, ecx, edx); /* cmpl $0x80000004, %eax */ + memset(vend_chars, 0, sizeof(vend_chars)); + + for (z = 0; z < 4; z++) { + vend_chars[z] = (char)(eax >> (z * 8)); /* movl %eax, 0 */ + vend_chars[z+4] = (char)(ebx >> (z * 8)); /* movl %ebx, 4 */ + vend_chars[z+8] = (char)(ecx >> (z * 8)); /* movl %ecx, 8 */ + vend_chars[z+12] = (char)(edx >> (z * 8)); /* movl %edx, 12 */ + } + vend_chars[16] = '\0'; + GLUE2(all, "%s", vend_chars); + } + + CPU_ID_STR(0x00000000, ebx, ecx, edx); /* movl $0x00000000, %ebx */ + for (x = 0; x < 4; x++) { + vend_id[x] = (char)(ebx >> (x * 8)); /* movl %ebx, 0 */ + vend_id[x+4] = (char)(edx >> (x * 8)); /* movl %edx, 4 */ + vend_id[x+8] = (char)(ecx >> (x * 8)); /* movl %ecx, 8 */ + } + vend_id[12] = '\0'; + + if (vend == AmD) { + if (0x80000005 <= regz) { + CPU_STR2(0x80000005, eax, ebx, ecx, edx); /* movl $0x80000005, %eax */ + caches[0] = SHFT2(ecx >> (3 * 8)); /* movl %ecx, 24 */ + } + CPU_STR2(0x00000001, eax, ebx, ecx, edx); /* movl $0x00000001, %eax */ + corez = SHFT2(ebx >> (2 * 8)); /* movl %ebx, 16 */ + } + + if (vend == InteL) { + if (0x0000000B <= leafs) { + CPU_STR2(0x0000000B, eax, ebx, ecx, edx); /* movl $0x0000000B, %eax */ + corez = SHFT2(ebx); /* movl %ebx, 0 */ + leafB = SHFT2(edx); /* movl %edx, 0 */ + got_leafB = true; + + } else { + if (0x00000004 <= leafs) { + CPU_STR2(0x00000004, eax, ebx, ecx, edx); /* movl $0x00000004, %eax */ + corez = SHFT2(eax >> 26); /* movl %eax, 26 */ + } + } + } + + if (0x80000006 <= regz) { + CPU_STR2(0x80000006, eax, ebx, ecx, edx); /* movl $0x80000006, %eax */ + /* L2, line size */ + caches[1] = (ecx >> (2 * 8)) & 0xffff; /* movl %ecx, 16 */ + caches[2] = SHFT2(ecx); /* movl %ecx, 0 */ + } + + /* 100 mhz steps for the majority of AMD cpu's + * movl $0x80000007 %edx, 6 + */ + + if (0x80000008 <= regz) { + CPU_STR2(0x80000008, eax, ebx, ecx, edx); /* movl $0x80000008, %eax */ + /* physical, virtual */ + bitz[0] = SHFT2(eax); /* movl %eax, 0 */ + bitz[1] = SHFT2(eax >> 8); /* movl %eax, 8 */ + + if (vend == AmD) { + corez = SHFT2(ecx) + 1; /* movl %ecx, 0 */ + } + } + + CPU_STR2(0x00000001, eax, ebx, ecx, edx); /* movl $0x00000001, %eax */ + if (0 != (edx & (1 << 19))) { + clflu6 = SHFT2(ebx >> 8) * 8; /* movl %ebx, 8 */ + } + + FILL_ARR(str1, + UFINT "x %s ID %s" + " CLFLUSH/Line size " UFINT " " UFINT + " L1/L2 caches KB " UFINT " " UFINT + " Stepping " UFINT " Family " UFINT + " Model " UFINT + " Bits " UFINT " " UFINT + " apicid " UFINT, + + /* cores, vendor, vendor id */ + corez, buffer, vend_id, + /* clflush, line size */ + clflu6, caches[2], + /* L1, L2 */ + caches[0], caches[1], + /* stepping, family */ + SHFT(eax_old), (SHFT(eax_old >> 8) + + ((IZMAX(eax_old)) ? SHFT2(eax_old >> 20) : 0)), + /* model */ + (SHFT(eax_old >> 4) | + ((IZMAX(eax_old)) ? ((eax_old >> 12) & 0xf0) : 0)), + /* physical and virtual bits */ + bitz[0], bitz[1], + /* apicid */ + (true == got_leafB) ? leafB : SHFT2(ebx >> 24) + ); +} +#endif /* __i386__ || __i686__ || __x86_64__ */ diff --git a/src/freebsd_functions.c b/src/freebsd_functions.c new file mode 100644 index 0000000..4db2af5 --- /dev/null +++ b/src/freebsd_functions.c @@ -0,0 +1,293 @@ +/* + 08/16/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#include +#include +#include +#include +#include + +#if GOT_APM == 1 && defined(HAVE_MACHINE_APM_BIOS_H) +#include +#include +#include +#endif /* GOT_APM && HAVE_MACHINE_APM_BIOS_H */ + +#include "include/headers.h" +#include "include/freebzd.h" + + +void +get_ram(char *str1, uint8_t num) { + u_int total = 0, freeram = 0, inactive = 0, pagesize = 0; + u_int cache = 0, bufferram = 0, dummy = 0; + uintmax_t utotal = 0, used = 0, pz = 0; + size_t len = sizeof(dummy); + + SYSCTLVAL("vm.stats.vm.v_page_size", &pagesize); + SYSCTLVAL("vm.stats.vm.v_page_count", &total); + SYSCTLVAL("vm.stats.vm.v_inactive_count", &inactive); + SYSCTLVAL("vm.stats.vm.v_free_count", &freeram); + SYSCTLVAL("vm.stats.vm.v_cache_count", &cache); + SYSCTLVAL("vfs.bufspace", &bufferram); + + pz = (uintmax_t)pagesize; + used = ((uintmax_t)total * pz - (uintmax_t)freeram * pz + - (uintmax_t)inactive * pz + - (uintmax_t)cache * pz - (uintmax_t)bufferram) / MB; + utotal = ((uintmax_t)total * pz) / MB; + + switch(num) { + case 1: + FILL_ARR(str1, FMT_UINT "%s", utotal, "MB"); + break; + case 2: + FILL_ARR(str1, FMT_UINT "%s", + ((uintmax_t)freeram * pz) / MB, "MB"); + break; + case 3: + FILL_ARR(str1, FMT_UINT "%s", + ((uintmax_t)inactive * pz) / MB, "MB"); + break; + case 4: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)bufferram / MB, "MB"); + break; + case 5: + FILL_UINT_ARR(str1, + ((0 != utotal) ? ((used * 100) / utotal) : 0)); + break; + } +} + + +void +get_voltage(char *str1) { + u_int vol0[3], vol1[3], vol2[3], vol3[3]; + + memset(vol0, 0, sizeof(vol0)); + memset(vol1, 0, sizeof(vol1)); + memset(vol2, 0, sizeof(vol2)); + memset(vol3, 0, sizeof(vol3)); + + size_t len = sizeof(vol0); + + SYSCTLVAL(VOLTAGE_FILE("0"), &vol0); + SYSCTLVAL(VOLTAGE_FILE("1"), &vol1); + SYSCTLVAL(VOLTAGE_FILE("2"), &vol2); + SYSCTLVAL(VOLTAGE_FILE("3"), &vol3); + + FILL_ARR(str1, "%.2f %.2f %.2f %.2f", + (float)vol0[0] / 1000.0f, + (float)vol1[0] / 1000.0f, + (float)vol2[0] / 1000.0f, + (float)vol3[0] / 1000.0f); +} + + +void +get_cpu_temp(char *str1) { + u_int temp = 0; + size_t len = sizeof(temp); + + SYSCTLVAL(CPU_TEMP, &temp); + get_temp(str1, (uint_least32_t)temp); +} + + +void +get_mobo_temp(char *str1) { + u_int temp[3]; + memset(temp, 0, sizeof(temp)); + size_t len = sizeof(temp); + + SYSCTLVAL(MOBO_VAL("temp.1"), &temp); + get_temp(str1, (uint_least32_t)temp[0]); +} + + +void +get_mobo(char *str1) { + char temp[VLA]; + size_t len = sizeof(temp); + + SYSCTLVAL(MOBO_VAL("%desc"), &temp); + FILL_STR_ARR(1, str1, temp); +} + + +/* + Couldn't add this option on my own. + Used the following resources to make this function happen: + http://ftp.stu.edu.tw/FreeBSD/branches/3.0-stable/src/libexec/rpc.rstatd/rstat_proc.c + https://github.com/giampaolo/psutil/blob/master/psutil/arch/bsd/freebsd.c + http://opensource.apple.com/source/net_snmp/net_snmp-16/net-snmp/agent/mibgroup/ucd-snmp/diskio.c + https://searchcode.com/codesearch/view/29835031/ + http://fossies.org/linux/pcp/src/pmdas/freebsd/disk.c + Had to use Valgrind since we allocate memory with malloc. +*/ +void +get_statio(char *str1, char *str2) { + struct statinfo stats; + struct device_selection *dev_select = NULL; + struct devstat *d = NULL; + long int select_generation = 0; + int x = 0, num_devices = 0, num_selected = 0, num_selections = 0; + + FILL_STR_ARR(1, str1, "Null"); + if(0 != devstat_checkversion(NULL)) { + return; + } + + memset(&stats, 0, sizeof(struct statinfo)); + stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); + if (NULL == stats.dinfo) { + return; + } + + if(-1 == (devstat_getdevs(NULL, &stats))) { + goto error; + } + + num_devices = stats.dinfo->numdevs; + if (-1 == (devstat_selectdevs(&dev_select, &num_selected, &num_selections, + &select_generation, stats.dinfo->generation, stats.dinfo->devices, num_devices, + NULL, 0, NULL, 0, DS_SELECT_ADD, 16, 0))) { + goto error; + } + + for (x = 0; x < 16; x++) { + d = &stats.dinfo->devices[x]; + if (STREQ(str2, d->device_name)) { + + if (d->device_type != DEVSTAT_TYPE_DIRECT && + d->device_type != DEVSTAT_TYPE_IF_SCSI && + d->device_type != DEVSTAT_TYPE_IF_IDE) { + break; + } + + FILL_ARR(str1, "Read " FMT_UINT " MB, Written " FMT_UINT " MB", + (uintmax_t)d->bytes[DEVSTAT_READ] / MB, + (uintmax_t)d->bytes[DEVSTAT_WRITE] / MB); + break; + } + } + +error: + if (NULL != dev_select) { + free(dev_select); + } + if (NULL != stats.dinfo) { + if (stats.dinfo->mem_ptr) { + free(stats.dinfo->mem_ptr); + } + free(stats.dinfo); + } + return; +} + + +/* https://www.freebsd.org/doc/handbook/acpi-overview.html + ACPI_BATT_STAT_NOT_PRESENT +*/ +#if GOT_APM == 1 && defined(HAVE_MACHINE_APM_BIOS_H) +void +get_battery(char *str1) { + struct apm_info bstate; + int fd = 0; + uintmax_t dummy = 0; + + FILL_STR_ARR(1, str1, "Null"); + memset(&bstate, 0, sizeof(struct apm_info)); + + if (0 != (fd = open("/dev/apm", O_RDONLY))) { + return; + } + if (0 != (ioctl(fd, APMIO_GETINFO, &bstate))) { + CLOSE_FD(fd); + return; + } + CLOSE_FD(fd); + + dummy = (uintmax_t)bstate.ai_batt_life; + FILL_UINT_ARR(str1, (101 < dummy ? 0 : dummy)); +} + +#else + +void +get_battery(char *str1) { + u_int dummy = 0; + uint_least32_t perc = 0; + size_t len = sizeof(dummy); + SYSCTLVAL("hw.acpi.battery.life", &dummy); + + perc = (uint_least32_t)dummy; + FILL_ARR(str1, ULINT, (101 < perc ? 0 : perc)); +} +#endif /* GOT_APM && HAVE_MACHINE_APM_BIOS_H */ + + +void +get_swapp(char *str1, uint8_t num) { + struct xswdev xsw; + u_int pagesize = 0, dummy = 0; + uintmax_t total = 0, used = 0, pz = 0; + int mib[20]; + + memset(mib, 0, sizeof(mib)); + memset(&xsw, 0, sizeof(struct xswdev)); + size_t mibi = sizeof(mib) / sizeof(mib[0]); + size_t len = sizeof(dummy), sisi = sizeof(struct xswdev); + + FILL_STR_ARR(1, str1, "0 MB"); + SYSCTLVAL("vm.stats.vm.v_page_size", &pagesize); + pz = (uintmax_t)pagesize; + + if (0 != (sysctlnametomib("vm.swap_info", mib, &mibi))) { + return; + } + if (0 != (sysctl(mib, (u_int)(mibi + 1), &xsw, &sisi, NULL, 0))) { + return; + } + if (xsw.xsw_version != XSWDEV_VERSION) { + return; + } + used = (uintmax_t)xsw.xsw_used; + total = (uintmax_t)xsw.xsw_nblks; + + switch(num) { + case 1: + FILL_ARR(str1, FMT_UINT" %s", ((total * pz) / MB), "MB"); + break; + case 2: + FILL_ARR(str1, FMT_UINT" %s", + (((total - used) * pz) / MB), "MB"); + break; + case 3: + FILL_ARR(str1, FMT_UINT" %s", ((used * pz) / MB), "MB"); + break; + case 4: + FILL_ARR(str1, FMT_UINT"%%", + ((0 != total) ? ((used * 100) / total) : 0)); + break; + } +} diff --git a/src/include/freebzd.h b/src/include/freebzd.h new file mode 100644 index 0000000..b03b862 --- /dev/null +++ b/src/include/freebzd.h @@ -0,0 +1,31 @@ +/* + 08/17/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef INCLUDE_FREEBZD_HEADERZ_H_ +#define INCLUDE_FREEBZD_HEADERZ_H_ + +#include +#include + +#define SYSCTLVAL(x, y) \ + if (0 != sysctlbyname(x, y, &len, NULL, 0)) { \ + FUNC_FAILED("sysctlbyname()"); \ + } + +#endif /* INCLUDE_FREEBZD_HEADERZ_H_ */ diff --git a/src/include/functions_constants.h b/src/include/functions_constants.h new file mode 100644 index 0000000..dac4e58 --- /dev/null +++ b/src/include/functions_constants.h @@ -0,0 +1,156 @@ +/* + 07/29/2015, 07/17/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef CONSTANTS2_H_ +#define CONSTANTS2_H_ + +#define KB 1024 +#define MB 1048576 /* 1024 * 1024 */ +#define GB 1073741824 /* MB * 1024 */ +#define Mb 131072 /* 1024 * 1024 / 8 */ +#define BYTES_TO_MB(x) (x/2/1024) /* block bytes */ + +#define FMT_UINT "%"PRIuMAX +#define UFINT "%"PRIuFAST16 +#define ULINT "%"PRIuLEAST32 +#define USINT "%"PRIu8 +#define SCAN_UFINT "%"SCNuFAST16 +#define SCAN_ULINT "%"SCNuLEAST32 +#define SCAN_UINTX "%"SCNxMAX /* hex */ + +/* stay away from va_list */ +#define FILL_ARR(x, z, ...) (snprintf(x, VLA, z, __VA_ARGS__)) +#define FILL_UINT_ARR(x, z) (FILL_ARR(x, FMT_UINT, z)) +#define FILL_STR_ARR(x, z, ...) (FILL_ARR(z, (1 == x ? "%s" : "%s %s"), __VA_ARGS__)) +#define GLUE2(x, z, ...) (x+=snprintf(x, VLA, z, __VA_ARGS__)) + +/* temperature sensors */ +#define HWMON_DIR "/sys/class/hwmon/hwmon0" +#define TEMPERATURE(x) (HWMON_DIR"/temp"x"_input") +#define CPU_TEMP_FILE TEMPERATURE("1") +#define MOBO_TEMP_FILE TEMPERATURE("2") + +/* motherboard model and vendor */ +#define MOTHERBOARD(x) ("/sys/class/dmi/id/board_"x) +#define MOBO_NAME MOTHERBOARD("name") +#define MOBO_VENDOR MOTHERBOARD("vendor") + +/* voltage and fans */ +#if defined(__linux__) +#define VOLTAGE_FILE(x) (HWMON_DIR"/in"x"_input") +#define FAN_FILE HWMON_DIR"/fan"UFINT"_input" +#endif /* __linux__ */ + +#if defined(__FreeBSD__) + +#if defined(MOBO_MODL) && defined(CPU_MODL) +#define MOBO_VAL(x) MOBO_MODL "." x +#define CPU_TEMP CPU_MODL +#else +#define MOBO_VAL(x) "dev.aibs.0."x +#define CPU_TEMP "dev.cpu.0.temperature" + +#endif /* MOBO_MODL && CPU_MODL */ + +#define VOLTAGE_FILE(x) MOBO_VAL("volt") "." x +#define FAN_STR(x, z) (FILL_ARR(x, "%s"UFINT, MOBO_VAL("fan") ".", z)) +#endif /* __FreeBSD__ */ + +/* battery reports */ +#define BATTERY_NUM(x, y, z) (FILL_ARR(x, "%s"USINT"%s%s", \ + "/sys/class/power_supply/BAT", y, "/charge_", z)) +#define BATTERY_USED(x, z) (BATTERY_NUM(x, z, "now")) +#define BATTERY_TOTAL(x, z) (BATTERY_NUM(x, z, "full")) + +/* NIC model and vendor */ +#define NIC_NUM(x, y, z) (FILL_ARR(x, "%s%s%s%s", \ + "/sys/class/net/", y, "/device/", z)) +#define NIC_VEND(x, z) (NIC_NUM(x, z, "vendor")) +#define NIC_MODEL(x, z) (NIC_NUM(x, z, "device")) + +/* The cdrom/dvdrom vendor and model */ +#define DVD_DIR(x) ("/sys/class/block/sr0/device/"x) +#define DVD_VEND DVD_DIR("vendor") +#define DVD_MODEL DVD_DIR("model") + +/* exit with error */ +#define CANNOT_OPEN "Could not open" +#define CANNOT_CLOSE "Could not close a file handle" +#define CANNOT_OPEN_FP "Could not open a file handle" +#define FSCANF_FAILED "fscanf() failed" +#define ERR "Error:" +#define NOT_FOUND "Not found, " +#define FUNC_FAILED(x) (exit_with_err(ERR, x " failed")) +#define RECOMPILE_WITH(x) (exit_with_err(ERR, "recompile the program --with-" x)) + +/* Let the preprocessor Do Repeat Myself */ +#define CHECK_SSCANF(buf, x, z) \ + if (EOF == (sscanf(buf, x, z))) { \ + exit_with_err(ERR, "sscanf() EOF"); \ + } + +#define CHECK_FSCANF(fp, x, z) \ + if (EOF == (fscanf(fp, x, z))) { \ + exit_with_err(ERR, FSCANF_FAILED); \ + } + +#define CHECK_FP(fp) \ + if (NULL == fp) { \ + exit_with_err(ERR, CANNOT_OPEN_FP); \ + } + +#define CLOSE_X(fp) \ + if (EOF == (fclose(fp))) { \ + exit_with_err(ERR, CANNOT_CLOSE); \ + } + +#define OPEN_X(fp, x, y, z) \ + if (NULL == (fp = fopen(x, "r"))) { \ + exit_with_err(CANNOT_OPEN, x); \ + } \ + CHECK_FSCANF(fp, y, z); \ + CLOSE_X(fp); + +#define CHECK_POPEN(fp, x, packs) \ + if (NULL == (fp = popen(x, "r"))) { \ + exit_with_err(CANNOT_OPEN, x); \ + } \ + CHECK_FSCANF(fp, SCAN_UFINT, packs); \ + if (-1 == (pclose(fp))) { \ + exit_with_err(CANNOT_CLOSE, x); \ + } + +#define CLOSE_FD(fd) \ + if (-1 == (close(fd))) { \ + exit_with_err(ERR, CANNOT_CLOSE); \ + } + +#define CLOSE_FD2(fd, res) \ + if (-1 == (close(fd))) { \ + freeaddrinfo(res); \ + exit_with_err(ERR, CANNOT_CLOSE); \ + } + +/* How many fans to try for detection */ +#define MAX_FANS 20 + +#define STREQ(x, z) (0 == (strcmp(x, z))) +#define FPRINTF(...) (fprintf(stderr, __VA_ARGS__)) + +#endif /* CONSTANTS2_H_ */ diff --git a/src/include/headers.h b/src/include/headers.h new file mode 100644 index 0000000..89b8230 --- /dev/null +++ b/src/include/headers.h @@ -0,0 +1,37 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef INCLUDE_HEADERZ_H_ +#define INCLUDE_HEADERZ_H_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "options_constants.h" +#include "functions_constants.h" +#include "../prototypes/functions.h" +#include "../prototypes/common.h" + +#endif /* INCLUDE_HEADERZ_H_ */ diff --git a/src/include/ncurses_colours.h b/src/include/ncurses_colours.h new file mode 100644 index 0000000..3dbe49c --- /dev/null +++ b/src/include/ncurses_colours.h @@ -0,0 +1,42 @@ +/* + 09/03/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef NCURSES_COLOURS_H_ +#define NCURSES_COLOURS_H_ + + +#if WITH_COLOURS == 1 +#define PINK "^M" +#define BLUE "^B" +#define YELLOW "^Y" + +#else +#define PINK "" +#define BLUE "" +#define YELLOW "" + +#endif /* WITH_COLOURS */ + +#define NAME_VAL BLUE STR_SPEC " " PINK STR_SPEC /* STR1 STR2 */ +#define TEMP YELLOW STR_SPEC "C " /* 32C */ +#define FMT_KERN YELLOW KERN_ORIG /* Kernel Version */ +#define FMT_SONG PINK SONG_ORIG /* Song */ + + +#endif /* NCURSES_COLOURS_H_ */ diff --git a/src/include/non_x11_colours.h b/src/include/non_x11_colours.h new file mode 100644 index 0000000..966ccfc --- /dev/null +++ b/src/include/non_x11_colours.h @@ -0,0 +1,69 @@ +/* + 07/24/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef COLOURS_H_ +#define COLOURS_H_ + + +#if WITH_COLOURS == 1 +#define XBM_ICON(given_icon) "^i("ICONS_DIR"/"given_icon")" +#define YELLOW "^fg(#f0c674)" +#define BLUE "^fg(#1793D1)" +#define PINK "^fg(#b294bb)" + +#define NAME_VAL BLUE STR_SPEC " " PINK STR_SPEC /* STR1 STR2 */ +#define TEMP YELLOW "%s" XBM_ICON("temp.xbm") " " /* 32C */ +#define FMT_KERN YELLOW KERN_ORIG /* Kernel Version */ +#define FMT_SONG PINK SONG_ORIG /* Song */ + +#define CPU_STR XBM_ICON("cpu.xbm") +#define RAM_STR XBM_ICON("mem.xbm") +#define SSD_STR XBM_ICON("diskette.xbm") +#define PKG_STR XBM_ICON("arch.xbm") +#define VOLT_STR XBM_ICON("voltage.xbm") +#define FANS_STR XBM_ICON("fan.xbm") +#define MOBO_STR XBM_ICON("mobo.xbm") +#define VOL_STR XBM_ICON("vol.xbm") +#define TIME_STR XBM_ICON("clock.xbm") +#define MPD_ICON XBM_ICON("mpd.xbm") +#define NET_STR XBM_ICON("net.xbm") +#define SPEED_STR XBM_ICON("net.xbm") +#define STATIO_STR XBM_ICON("statio.xbm") +#define BATT_STR XBM_ICON("bat.xbm") +#define LOAD_STR CPU_STR +#define UP_STR XBM_ICON("uptime.xbm") + +/* Only for the weather */ +#define OUT_STR BLUE XBM_ICON("fox.xbm")" " + +/* tmux or other program that can spice + * the output on it's own */ +#else + +#define PINK "" +#define YELLOW "" +#define NAME_VAL STR_SPEC " " STR_SPEC /* STR1 STR2 */ +#define TEMP STR_SPEC "C " /* 32C */ +#define FMT_KERN KERN_ORIG /* Kernel Version */ +#define FMT_SONG SONG_ORIG /* Song */ + +#endif /* WITH_COLOURS */ + + +#endif /* COLOURS_H_ */ diff --git a/src/include/openbzd.h b/src/include/openbzd.h new file mode 100644 index 0000000..aea8c0d --- /dev/null +++ b/src/include/openbzd.h @@ -0,0 +1,31 @@ +/* + 09/08/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef INCLUDE_OPENBZD_HEADERZ_H_ +#define INCLUDE_OPENBZD_HEADERZ_H_ + +#include +#include + +#define SYSCTLVAL(w, x, y, z) \ + if (0 != (sysctl(w, x, y, z, NULL, 0))) { \ + FUNC_FAILED("sysctl()"); \ + } + +#endif /* INCLUDE_OPENBZD_HEADERZ_H_ */ diff --git a/src/include/options_constants.h b/src/include/options_constants.h new file mode 100644 index 0000000..2be4863 --- /dev/null +++ b/src/include/options_constants.h @@ -0,0 +1,100 @@ +/* + 07/29/2015, 07/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef CONSTANTS_H_ +#define CONSTANTS_H_ + +#define VLA 200 +#define WHOLE_MAIN_ARR_LEN VLA*16 +#define GLUE(x, z, ...) (x+=snprintf(x, WHOLE_MAIN_ARR_LEN, z, __VA_ARGS__)) + +#if defined(__FreeBSD__) +/* The clock ticks in FreeBSD are 133 */ +#define TICKZ 100 +#else +#define TICKZ sysconf(_SC_CLK_TCK) +#endif + +#include "options_generator.h" + +#define STR_SPEC "%s" +#define SONG_ORIG STR_SPEC " " +#define KERN_ORIG STR_SPEC " " + +#ifndef WITH_NCURSES +#define WITH_NCURSES 6 +#endif +#if defined (HAVE_X11_XLIB_H) || WITH_NCURSES == 1 || WITH_COLOURS == 0 + +#define CPU_STR "CPU" +#define RAM_STR "RAM" +#define SSD_STR "SSD" +#define PKG_STR "Pkgs" +#define VOLT_STR "Voltage" +#define FANS_STR "Fans/RPM" +#define MOBO_STR "Mobo" +#define VOL_STR "Volume" +#define TIME_STR "Time" +#define NET_STR "Used Net" +#define STATIO_STR "Statio" +#define SPEED_STR "Speed" +#define BATT_STR "BATT" +#define UP_STR "Up" +#define LOAD_STR "Load/avg" +#define OUT_STR "Out " + +#endif /* HAVE_X11_XLIB_H || WITH_NCURSES || WITH_COLOURS */ + + +#if defined (HAVE_X11_XLIB_H) +#include "x11_colours.h" + +#elif WITH_NCURSES == 1 +#include "ncurses_colours.h" + +#else +#include "non_x11_colours.h" + +#endif /* HAVE_X11_XLIB_H */ + + +/* options.c format constants */ +#define FMT NAME_VAL"%% " /* STR1 10% */ +#define FMT_TIME NAME_VAL /* Time 10:00 PM */ +#define FMT_MOBO FMT_TIME" " /* VEND NAME */ +#define FMT_CPU FMT_TIME"%% " /* CPU 10% */ +#define FMT_CORES FMT_TIME /* CPU varying */ +#define FMT_RAM FMT /* RAM 10% */ +#define FMT_RAM2 FMT_TIME" " /* RAM 10MB */ +#define FMT_SSD FMT /* SSD 10% */ +#define FMT_SSD2 FMT_RAM2 /* SSD 10MB */ +#define FMT_PKGS FMT_TIME" " /* Pkgs 123 */ +#define FMT_VOLT FMT_PKGS /* Voltage 1 2 3 4 */ +#define FMT_FANS FMT_TIME /* Fans varying */ +#define FMT_VOL FMT /* Volume 10% */ +#define FMT_NET FMT_PKGS /* Down 123 Up 123 */ +#define FMT_STATIO FMT_NET /* Read 123 Written 123 */ +#define FMT_CPUSPEED PINK STR_SPEC " " /* 1234 MHz */ +#define FMT_TEMP TEMP /* 32C */ +#define FMT_BATT FMT /* BATT 10% */ +#define FMT_UP FMT_TIME" " /* Up 10 min */ +#define FMT_LOAD FMT_TIME" " /* Load/avg 0.01 0.01 0.01 */ + + +#endif /* CONSTANTS_H_ */ diff --git a/src/include/options_generator.h b/src/include/options_generator.h new file mode 100644 index 0000000..b0e269f --- /dev/null +++ b/src/include/options_generator.h @@ -0,0 +1,109 @@ +/* + 08/12/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef GENERATOR_H_ +#define GENERATOR_H_ + +/* Employ the preprocessor */ +#define GET_N_FMT(func, ...) \ + get_##func(func); \ + GLUE(__VA_ARGS__); + +/* Remember vanilla ice ? */ +#define SLEEP_SLEEP_BABY(x) \ + tc.tv_nsec = x; \ + if (-1 == (nanosleep(&tc, NULL))) { \ + printf("%s\n", "Error: nanosleep() failed"); \ + return EXIT_FAILURE; \ + } + +#define GET_NET_N_FMT(arg1, arg2, arg3, ...) \ + get_net(arg1, arg2, arg3); \ + if (2 == arg3) { \ + SLEEP_SLEEP_BABY(850000000L); \ + get_net(arg1, arg2, arg3); \ + } \ + GLUE(__VA_ARGS__); + +/* Let the platform ticks decide how much + * time is needed to sleep + * 100 in linux and openbsd, 133 in freebsd */ +#define NEW_CPU_LABEL(lbl, declareVar, useVar, ...) \ + case lbl: \ + { \ + declareVar; \ + get_##useVar(useVar); \ + SLEEP_SLEEP_BABY(sysconf(_SC_CLK_TCK) * 1000000L); \ + GET_N_FMT(useVar, arguments->all, __VA_ARGS__, useVar); \ + } \ + break; + +#define NEW_LABEL(lbl, declareVar, useVar, ...) \ + case lbl: \ + { \ + declareVar; \ + GET_N_FMT(useVar, arguments->all, __VA_ARGS__, useVar); \ + } \ + break; + +#define NEW_NET_LABEL(lbl, declareVar, useVar, num, ...) \ + case lbl: \ + { \ + declareVar; \ + GET_NET_N_FMT(useVar, arg, num, arguments->all, __VA_ARGS__, useVar); \ + } \ + break; + +#define NEW_ARG_LABEL(lbl, declareVar, useVar, ...) \ + case lbl: \ + { \ + declareVar; \ + get_##useVar(useVar, arg); \ + GLUE(arguments->all, __VA_ARGS__, useVar); \ + } \ + break; + +#define LABEL_WITH_NUM_GENERATOR(func, lbl, declareVar, useVar, num, ...) \ + case lbl: \ + { \ + declareVar; \ + get_##func(useVar, num); \ + GLUE(arguments->all, __VA_ARGS__, useVar); \ + } \ + break; + +#define NEW_RAM_LABEL(...) \ + LABEL_WITH_NUM_GENERATOR(ram, __VA_ARGS__); + +#define NEW_SSD_LABEL(...) \ + LABEL_WITH_NUM_GENERATOR(ssd, __VA_ARGS__); + +#define NEW_KERNEL_LABEL(...) \ + LABEL_WITH_NUM_GENERATOR(kernel, __VA_ARGS__); + +#define NEW_SWAPP_LABEL(...) \ + LABEL_WITH_NUM_GENERATOR(swapp, __VA_ARGS__); + +#define NEW_MPD_LABEL(...) \ + LABEL_WITH_NUM_GENERATOR(song, __VA_ARGS__); + +/* Fire the preprocessor */ + + +#endif /* GENERATOR_H_ */ diff --git a/src/include/x11_colours.h b/src/include/x11_colours.h new file mode 100644 index 0000000..03995e7 --- /dev/null +++ b/src/include/x11_colours.h @@ -0,0 +1,45 @@ +/* + 07/24/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef X_COLOURS_H_ +#define X_COLOURS_H_ + + +/* The dwm colours are specified + * in your dwm config.h +*/ +#if WITH_COLOURS == 1 +#define PINK "\x0b" +#define BLUE "\x0a" +#define YELLOW "\x09" + +#else +#define PINK "" +#define BLUE "" +#define YELLOW "" + +#endif /* WITH_COLOURS */ + +#define NAME_VAL BLUE STR_SPEC " " PINK STR_SPEC /* STR1 STR2 */ +#define TEMP YELLOW STR_SPEC "C " /* 32C */ +#define FMT_KERN YELLOW KERN_ORIG /* Kernel Version */ +#define FMT_SONG PINK SONG_ORIG /* Song */ + + +#endif /* X_COLOURS_H_ */ diff --git a/src/linux_functions.c b/src/linux_functions.c new file mode 100644 index 0000000..003b71a --- /dev/null +++ b/src/linux_functions.c @@ -0,0 +1,373 @@ +/* + 07/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +/* The pragma directives are here + * to mute the gcc twisted vision, + * and clangs inabillity to distinguish + * C from C++ + * + * https://llvm.org/bugs/show_bug.cgi?id=21689 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 + * + * Do not add any -Wno flags just to mute the compilers snafus + * */ + +#include "config.h" /* Auto-generated */ + +#include + +#if defined(HAVE_SENSORS_SENSORS_H) +#include +#endif /* HAVE_SENSORS_SENSORS_H */ + +#include "include/headers.h" + +void +get_ram(char *str1, uint8_t num) { + uintmax_t used = 0, total = 0; + struct sysinfo mem; + memset(&mem, 0, sizeof(struct sysinfo)); + + if (-1 == (sysinfo(&mem))) { + FUNC_FAILED("sysinfo()"); + } + + switch(num) { + case 1: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)mem.totalram / MB, "MB"); + break; + case 2: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)mem.freeram / MB, "MB"); + break; + case 3: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)mem.sharedram / MB, "MB"); + break; + case 4: + FILL_ARR(str1, FMT_UINT "%s", + (uintmax_t)mem.bufferram / MB, "MB"); + break; + case 5: + { + total = (uintmax_t) mem.totalram / MB; + used = (uintmax_t) (mem.totalram - mem.freeram - + mem.bufferram - mem.sharedram) / MB; + FILL_UINT_ARR(str1, + ((0 != total) ? ((used * 100) / total) : 0)); + } + break; + } +} + + +void +get_ssd_model(char *str1, char *str2) { + FILE *fp = NULL; + char model[VLA]; + FILL_ARR(model, "%s%s%s", "/sys/block/", str2, "/device/model"); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, model, "%[^\n]", model); +#pragma GCC diagnostic pop + + FILL_STR_ARR(1, str1, model); +} + + +void +get_loadavg(char *str1) { + struct sysinfo up; + memset(&up, 0, sizeof(struct sysinfo)); + + if (-1 == (sysinfo(&up))) { + FUNC_FAILED("sysinfo()"); + } + FILL_ARR(str1, "%.2f %.2f %.2f", + (float)up.loads[0] / 65535.0f, + (float)up.loads[1] / 65535.0f, + (float)up.loads[2] / 65535.0f); +} + + +/* My inital attempt was to make this code FreeBSD exclusive as the + * sensors parsing there is much more difficult than it is in linux. + */ +#if defined(HAVE_SENSORS_SENSORS_H) +void +match_feature(char *str1, uint8_t num) { +#if SENSORS_API_VERSION >= 0x400 && SENSORS_API_VERSION <= 0x499 + const sensors_chip_name *chip; + const sensors_feature *features; + const sensors_subfeature *subfeatures; + char buffer[VLA]; + char *label = NULL, *all = buffer; + double value = 0.0; + int nr = 0, nr2 = 0, nr3 = 0; + uint8_t x = 0, y = 0, z = 0, dummy = 0; + uint_fast16_t rpm[MAX_FANS+1]; + bool found_fans = false; + const char *temp_sens[] = { "MB Temperature", "CPU Temperature" }; + size_t len = 0; + + if (3 == num) { + memset(rpm, 0, sizeof(rpm)); + } + + /* In case I need to parse the rest + * min, max, input values */ + /* struct stats_pwr_in *st_pwr_in_i; */ + /* struct stats_pwr_temp *st_pwr_temp_i; */ + /* struct stats_pwr_fan *st_pwr_fan_i; */ + + FILL_STR_ARR(1, str1, "Null"); + if (0 != (sensors_init(NULL))) { + FUNC_FAILED("sensors_init()"); + } + + while (NULL != (chip = sensors_get_detected_chips(NULL, &nr))) { + nr2 = 0; + while (NULL != (features = sensors_get_features(chip, &nr2))) { + nr3 = 0; + while (NULL != (subfeatures = sensors_get_all_subfeatures(chip, features, &nr3))) { + switch(subfeatures->type) { + + case SENSORS_SUBFEATURE_IN_INPUT: + { + if (1 == num) { + if (0 != (sensors_get_value(chip, subfeatures->number, &value))) { + break; + } + GLUE2(all, "%.2f ", (float)value); + } + } + break; + + case SENSORS_SUBFEATURE_TEMP_INPUT: + { + if (2 == num || 4 == num) { + dummy = (2 == num ? 0 : 1); + if (0 != (sensors_get_value(chip, subfeatures->number, &value))) { + break; + } + if (NULL == (label = sensors_get_label(chip, features))) { + break; + } + if (STREQ(temp_sens[dummy], label)) { + FILL_ARR(str1, UFINT, (uint_fast16_t)value); + } + if (NULL != label) { + free(label); + } + } + } + break; + + case SENSORS_SUBFEATURE_FAN_INPUT: + { + if (3 == num) { + if (0 != (sensors_get_value(chip, subfeatures->number, &value))) { + break; + } + if (MAX_FANS != z) { + rpm[z++] = (uint_fast16_t)value; + } + found_fans = true; + } + } + break; + + default: + continue; + } + } + } + } + sensors_cleanup(); + + if (1 == num && '\0' != buffer[0]) { + len = strlen(buffer); + buffer[len-1] = '\0'; + + FILL_STR_ARR(1, str1, buffer); + return; + } + + if (true == found_fans) { + check_fan_vals(str1, rpm, z); + } + +#else + exit_with_err(ERR, "The version of your sensors API is not supported by this program."); +#endif /* SENSORS_API_VERSION >= 0x400 && SENSORS_API_VERSION <= 0x499 */ +} + + +void +get_voltage(char *str1) { + match_feature(str1, 1); +} + + +void +get_mobo_temp(char *str1) { + match_feature(str1, 2); +} + + +void +get_fans(char *str1) { + match_feature(str1, 3); +} + + +void +get_cpu_temp(char *str1) { + match_feature(str1, 4); +} + + +#else /* fall back */ +void +get_voltage(char *str1) { + float voltage[4]; + FILE *fp = NULL; + uint8_t x = 0; + memset(voltage, 0, sizeof(voltage)); + + const char *voltage_files[] = { + VOLTAGE_FILE("0"), + VOLTAGE_FILE("1"), + VOLTAGE_FILE("2"), + VOLTAGE_FILE("3") + }; + + for (x = 0; x < 4; x++) { + if (NULL == (fp = fopen(voltage_files[x], "r"))) { + exit_with_err(CANNOT_OPEN, voltage_files[x]); + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_FSCANF(fp, "%f", &voltage[x]); +#pragma GCC diagnostic pop + CLOSE_X(fp); + + voltage[x] /= 1000.0f; + } + FILL_ARR(str1, "%.2f %.2f %.2f %.2f", + voltage[0], voltage[1], voltage[2], voltage[3]); +} + + +void +get_mobo_temp(char *str1) { + get_temp(MOBO_TEMP_FILE, str1); +} + + +void +get_cpu_temp(char *str1) { + get_temp(CPU_TEMP_FILE, str1); +} +#endif /* HAVE_SENSORS_SENSORS_H */ + + +void +get_mobo(char *str1) { + FILE *fp = NULL; + char vendor[100], name[100]; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, MOBO_VENDOR, "%s", vendor); +#pragma GCC diagnostic pop + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, MOBO_NAME, "%s", name); +#pragma GCC diagnostic pop + + FILL_STR_ARR(2, str1, vendor, name); +} + + +void +get_statio(char *str1, char *str2) { + uintmax_t statio[7]; + char stat_file[VLA]; + FILL_ARR(stat_file, "%s%s%s", "/sys/block/", str2, "/stat"); + + memset(statio, 0, sizeof(statio)); + + FILE *fp = fopen(stat_file, "r"); + CHECK_FP(fp); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + if (EOF == (fscanf(fp, FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT FMT_UINT, + &statio[0], &statio[1], &statio[2], &statio[3], + &statio[4], &statio[5], &statio[6]))) { + CLOSE_X(fp); + exit_with_err(ERR, "reading the stat file failed"); + } +#pragma GCC diagnostic pop + CLOSE_X(fp); + + FILL_ARR(str1, "Read " FMT_UINT " MB, Written " FMT_UINT " MB", + BYTES_TO_MB(statio[2]), BYTES_TO_MB(statio[6])); +} + + +/* Thanks to https://bugzilla.kernel.org/show_bug.cgi?id=83411 */ +void +get_battery(char *str1) { + uintmax_t used = 0, total = 0; + uint8_t num = 0; + char temp[VLA]; + BATTERY_TOTAL(temp, num); + + FILE *fp = fopen(temp, "r"); + if (NULL == fp) { + num = 1; + BATTERY_TOTAL(temp, num); + + if (NULL == (fp = fopen(temp, "r"))) { + exit_with_err(CANNOT_OPEN, "BAT0 and BAT1"); + } + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_FSCANF(fp, FMT_UINT, &total); +#pragma GCC diagnostic pop + CLOSE_X(fp); + + BATTERY_USED(temp, num); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, temp, FMT_UINT, &used); +#pragma GCC diagnostic pop + + FILL_UINT_ARR(str1, + ((0 != total) ? ((used * 100) / total) : 0)); +} diff --git a/src/lua.c b/src/lua.c new file mode 100644 index 0000000..d1dc5a7 --- /dev/null +++ b/src/lua.c @@ -0,0 +1,92 @@ +/* + 11/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if WITH_LUA == 1 + +#include +#include +#include +#include "include/headers.h" + +#endif /* WITH_LUA */ + +#include "prototypes/lua.h" + +#if WITH_LUA == 1 +/* + Docs: + http://www.lua.org/manual/ + http://www.dcc.ufrj.br/~fabiom/lua/ + + Books: + http://www.lua.org/pil/index.html + + The first edition is free to be read: + http://www.lua.org/pil/contents.html + + "isfunction": + http://www.lua.org/pil/25.3.html +*/ +void +get_lua(char *str1, char *str2) { + const char *temp = NULL; + lua_State *L = NULL; + + FILL_STR_ARR(1, str1, "0"); + +#if LUA_VERSION_NUM < 501 + if (NULL == (L = lua_open())) { + return; + } +#else + if (NULL == (L = luaL_newstate())) { + return; + } +#endif /* LUA_VERSION_NUM == 501 */ + + luaL_openlibs(L); + if (0 != (luaL_loadfile(L, str2))) { + goto error; + } + + if (0 != (lua_pcall(L, 0, 0, 0))) { + goto error; + } + + lua_getglobal(L, "uzer_func"); + if (0 != (lua_pcall(L, 0, 1, 0))) { + goto error; + } + + if (NULL != (temp = lua_tostring(L, -1))) { + FILL_STR_ARR(1, str1, temp); + } + +error: + if (NULL != L) { + lua_pop(L, 1); + lua_close(L); + } + return; +} +#else +char *lua5; +#endif /* WITH_LUA */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..d591e50 --- /dev/null +++ b/src/main.c @@ -0,0 +1,48 @@ +/* + Copyright 02/22/2015, 07/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ +#include "include/headers.h" +#include "prototypes/options.h" + +int main(int argc, char *argv[]) { + char combined[WHOLE_MAIN_ARR_LEN]; + char *all = combined; + + if (-1 == (sysconf(_SC_CLK_TCK))) { + FPRINTF("%s\n", "Error: sysconf() failed"); + return EXIT_FAILURE; + } + + if (1 == argc) { + parse_konf(all); + } else { + parse_opts(argc, argv, all); + } + + if ('\0' != combined[0]) { +#if defined (HAVE_X11_XLIB_H) + set_status(combined); +#else + fprintf(stdout, "%s\n", combined); +#endif + } + + return EXIT_SUCCESS; +} diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..1210c4c --- /dev/null +++ b/src/net.c @@ -0,0 +1,697 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if WITH_NET == 1 + +#if defined(__linux__) +#include +#include +/* #include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if WITH_LIBNL == 1 +#include +#include +#include +#include +#include + +#else +#include +#endif /* WITH_LIBNL */ + +#if WITH_PCI == 1 +#include +#endif /* WITH_PCI */ + +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include +/* #include */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#endif /* __FreeBSD__ || __OpenBSD__ */ + +#endif /* WITH_NET */ + +#include "include/headers.h" +#include "prototypes/net.h" + +#if defined(__FreeBSD__) +#include "include/freebzd.h" +#endif /* __FreeBSD__ */ + +#if defined(__OpenBSD__) +#include "include/openbzd.h" +#endif /* __OpenBSD__ */ + + +#if defined(__linux__) + +#if WITH_LIBNL == 1 && WITH_NET == 1 +static int call_back(struct nl_msg *, void *); +#endif /* WITH_LIBNL && WITH_NET */ + +#endif /* __linux__ */ + + +/* Thanks to http://www.matisse.net/bitcalc/?source=print + * and `man netdevice' */ +void +get_net(char *str1, char *str2, uint8_t num) { +#if WITH_NET == 1 + +#if defined(__linux__) + struct rtnl_link_stats *stats = NULL; + struct sockaddr_ll *mac = NULL; +#else + struct if_data *stats = NULL; + struct sockaddr_dl *mac = NULL; +#endif /* __linux__ */ + + struct ifaddrs *ifaddr = NULL, *ifa = NULL; + static uintmax_t prev_recv = 0, prev_sent = 0; + uintmax_t cur_recv = 0, cur_sent = 0; + unsigned char *umac = NULL; + void *temp_void = NULL; + char temp[VLA]; + + if (-1 == (getifaddrs(&ifaddr))) { + FUNC_FAILED("getifaddrs()"); + } + FILL_STR_ARR(1, str1, "Null"); + + for (ifa = ifaddr; NULL != ifa; ifa = ifa->ifa_next) { + if ((IFF_UP | IFF_BROADCAST) != (ifa->ifa_flags & ( + IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | + IFF_LOOPBACK | IFF_NOARP))) { + continue; + } + if (NULL == ifa->ifa_addr) { + continue; + } + if (3 == num || 5 == num || 6 == num) { /* ip | netmask | broadcast */ + if (AF_INET == ifa->ifa_addr->sa_family) { + if (STREQ(str2, ifa->ifa_name)) { + switch(num) { + case 3: + temp_void = ifa->ifa_addr; + break; + case 5: + temp_void = ifa->ifa_netmask; + break; + case 6: + temp_void = ifa->ifa_broadaddr; + break; + } + inet_ntop(AF_INET, &(((struct sockaddr_in *)temp_void)->sin_addr), + temp, INET_ADDRSTRLEN); + FILL_STR_ARR(1, str1, temp); + break; + } + } + } else if (NETFAM == ifa->ifa_addr->sa_family && + NULL != ifa->ifa_data) { + if (STREQ(str2, ifa->ifa_name)) { + +#if defined(__linux__) + stats = ifa->ifa_data; +#else + stats = (struct if_data *)ifa->ifa_data; +#endif /* __linux__ */ + + if (2 == num) { /* upload and download speeds */ + cur_recv = (uintmax_t)stats->RECVBYTS - prev_recv; + cur_sent = (uintmax_t)stats->SENTBYTS - prev_sent; + + FILL_ARR(str1, "Down " FMT_UINT " KB, Up " FMT_UINT " KB", + (cur_recv / KB), (cur_sent / KB)); + + prev_recv = cur_recv; + prev_sent = cur_sent; + } else if (1 == num) { /* consumed internet so far */ + + FILL_ARR(str1, "Down " FMT_UINT " MB, Up " FMT_UINT " MB", + ((uintmax_t)stats->RECVBYTS / MB), + ((uintmax_t)stats->SENTBYTS / MB)); + +#if defined(__linux__) + } else if (4 == num) { /* mac address */ + + temp_void = ifa->ifa_addr; + mac = (struct sockaddr_ll *)temp_void; + /* + 6 == ether + 20 == infiniband + */ + if (6 != mac->sll_halen) { + break; + } + FILL_ARR(str1, "%02x:%02x:%02x:%02x:%02x:%02x", + mac->sll_addr[0], mac->sll_addr[1], + mac->sll_addr[2], mac->sll_addr[3], + mac->sll_addr[4], mac->sll_addr[5]); + + } else if (11 == num) { /* wifi name */ + get_wifi(str1, str2, (uint8_t)(num - 10)); + + } else { /* link speed | driver | version | firmware */ + switch(num) { + case 7: + case 8: + case 9: + case 10: + get_nic_info2(str1, str2, (uint8_t)(num - 6)); + break; + default: + break; + } + } +#else + } else if (4 == num) { /* mac address */ + temp_void = ifa->ifa_addr; + mac = (struct sockaddr_dl *)temp_void; + /* + 6 == ether + 20 == infiniband + */ + if (6 != mac->sdl_alen) { + break; + } + umac = (unsigned char *)LLADDR(mac); + FILL_ARR(str1, "%02x:%02x:%02x:%02x:%02x:%02x", + *umac, *(umac + 1), *(umac + 2), + *(umac + 3), *(umac + 4), *(umac + 5)); + } else if (7 == num) { /* gateway */ + get_nic_info(str1, str2); + } +#endif /* __linux__ */ + break; + } + } + } + if (NULL != ifaddr) { + freeifaddrs(ifaddr); + } + +#else + (void)str1; + (void)str2; + (void)num; + RECOMPILE_WITH("net"); +#endif /* WITH_NET */ +} + + +void +get_ip_lookup(char *str1, char *str2) { +#if WITH_NET == 1 + + struct addrinfo *rp = NULL, *result = NULL, hints; + void *temp_void = NULL; + char temp[VLA]; + + memset(&hints, 0, sizeof(struct addrinfo)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; /* udp | tcp */ + + if (0 != (getaddrinfo(str2, NULL, &hints, &result))) { + FUNC_FAILED("getaddrinfo()"); + } + + for (rp = result; NULL != rp; rp = rp->ai_next) { + if (NULL == rp->ai_addr) { + continue; + } + /* check ipv4 again, despite the "hints" */ + if (AF_INET == rp->ai_family) { + temp_void = rp->ai_addr; + + inet_ntop(AF_INET, &(((struct sockaddr_in *)temp_void)->sin_addr), + temp, INET_ADDRSTRLEN); + FILL_STR_ARR(1, str1, temp); + + break; + } + } + if (NULL != result) { + freeaddrinfo(result); + } + +#else + (void)str1; + (void)str2; + RECOMPILE_WITH("net"); +#endif /* WITH_NET */ +} + + +#if defined(__linux__) +void +get_nic_info2(char *str1, char *str2, uint8_t num) { +#if WITH_NET == 1 + + struct ethtool_cmd ecmd; + struct ethtool_drvinfo drvinfo; + struct ifreq ifr; + int sock = 0; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (-1 == sock) { + return; + } + + memset(&ecmd, 0, sizeof(struct ethtool_cmd)); + memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + memset(&ifr, 0, sizeof(struct ifreq)); + + switch(num) { + case 1: + ecmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (char *)&ecmd; + break; + case 2: + case 3: + case 4: + drvinfo.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (char *)&drvinfo; + break; + } + snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", str2); + + if (0 != (ioctl(sock, SIOCETHTOOL, &ifr))) { + CLOSE_FD(sock); + return; + } + + switch(num) { + case 1: + FILL_ARR(str1, "%d%s", ecmd.speed, "Mbps"); + break; + case 2: + FILL_STR_ARR(1, str1, drvinfo.driver); + break; + case 3: + FILL_STR_ARR(1, str1, drvinfo.version); + break; + case 4: + FILL_STR_ARR(1, str1, drvinfo.fw_version); + break; + } + CLOSE_FD(sock); + +#else + (void)str1; + (void)str2; + (void)num; + RECOMPILE_WITH("net"); +#endif /* WITH_NET */ +} + + +/* + Quick spot the bug game. + code begin: + struct pci_access *pacc= NULL; + pacc = pci_alloc(); + pci_init(pacc); + pci_cleanup(pacc); + code end; + Spotted the bug - no ? Well, + GCC -O2 hangs on pci_init, + while -O0 executes flawlessly. + Disclaimer: the code is perfectly valid. +*/ +void +get_nic_info(char *str1, char *str2) { +#if WITH_PCI == 1 && WITH_NET == 1 + + uintmax_t vendor = 0, model = 0; + char temp[VLA]; + struct pci_access *pacc = NULL; + struct pci_dev *dev = NULL; + FILE *fp = NULL; + + FILL_STR_ARR(1, str1, "Null"); + NIC_VEND(temp, str2); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, temp, SCAN_UINTX, &vendor); /* hex */ +#pragma GCC diagnostic pop + + NIC_MODEL(temp, str2); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + OPEN_X(fp, temp, SCAN_UINTX, &model); /* hex */ +#pragma GCC diagnostic pop + + pacc = pci_alloc(); + if (NULL == pacc) { + goto error; + } + + pci_init(pacc); + if (NULL == pacc) { + goto error; + } + pci_scan_bus(pacc); + + for (dev = pacc->devices; NULL != dev; dev = dev->next) { + pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); + + if ((uintmax_t)vendor == (uintmax_t)dev->vendor_id && + (uintmax_t)model == (uintmax_t)dev->device_id) { + + pci_lookup_name(pacc, temp, VLA, + PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, + (uintmax_t)vendor, (uintmax_t)model); + + FILL_STR_ARR(1, str1, temp); + break; + } + } + +error: + if (NULL != pacc) { + pci_cleanup(pacc); + } + return; + +#else + (void)str1; + (void)str2; + RECOMPILE_WITH("pci"); +#endif /* WITH_PCI && WITH_NET */ +} + +#endif /* __linux__ */ + + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#define ROUNDUP(x) ((x) > 0 ? \ + (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +/* Based on: + http://fossies.org/linux/misc/old/mrt-2.2.2a-src.tar.gz/mrt-2.2.2a/src/lib/kernel/bsd.c + https://svn.nmap.org/nmap/libdnet-stripped/src/route-bsd.c +*/ +void +get_nic_info(char *str1, char *str2) { +#if WITH_NET == 1 + + struct rt_msghdr *rtm = NULL; + struct sockaddr *sa = NULL, *addrs[RTAX_MAX]; + char *buf = NULL, *next = NULL, *lim = NULL, temp[VLA]; + uint8_t x = 0; + size_t needed = 0; + void *temp_void = NULL; + + /* No, it's not Men In Black acronym */ + int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 }; + if (0 != (sysctl(mib, 6, NULL, &needed, NULL, 0))) { + return; + } + + if (0 == needed) { + return; + } + + buf = (char *)malloc(needed); + if (NULL == buf) { + return; + } + if (0 != (sysctl(mib, 6, buf, &needed, NULL, 0))) { + goto error; + } + + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)(void *)next; + sa = (struct sockaddr *)(rtm + 1); + if (NULL == sa || NULL == rtm) { + continue; + } + if (AF_INET == sa->sa_family) { + for (x = 0; x < RTAX_MAX; x++) { + if (rtm->rtm_addrs & (1 << x)) { + addrs[x] = sa; + sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); + } else { + addrs[x] = NULL; + } + } + if (((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) + && AF_INET == addrs[RTAX_DST]->sa_family + && AF_INET == addrs[RTAX_GATEWAY]->sa_family) { + + temp_void = addrs[RTAX_GATEWAY]; + inet_ntop(AF_INET, &(((struct sockaddr_in *)temp_void)->sin_addr), + temp, INET_ADDRSTRLEN); + FILL_STR_ARR(1, str1, temp); + break; + } + } + } + (void)str2; + +error: + if (NULL != buf) { + free(buf); + } + return; + +#else + (void)str1; + (void)str2; + RECOMPILE_WITH("net"); +#endif /* WITH_NET */ +} +#endif /* __FreeBSD__ || __OpenBSD__ */ + + +#if defined(__linux__) +/* + + Entirely based on iw.c, link.c, genl.c, scan.c (print_bss_handler) + (v3.17) + + Docs, return vals, and tips: + https://www.infradead.org/~tgr/libnl/doc/core.html + https://www.infradead.org/~tgr/libnl/doc/api/group__send__recv.html + http://lists.shmoo.com/pipermail/hostap/2011-October/024315.html + https://bugzilla.kernel.org/show_bug.cgi?id=78481 +*/ +#if WITH_LIBNL == 1 + +#if WITH_NET == 1 +static int call_back(struct nl_msg *msg, void *str1) { + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *bss[NL80211_BSS_MAX + 1]; + struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_BSSID] = {.type = NLA_UNSPEC}, + [NL80211_BSS_INFORMATION_ELEMENTS] = {.type = NLA_UNSPEC} + }; + uint32_t len = 0, x = 0, z = 0; + char elo = '\0', *ssid = NULL, *ptr = (char *)str1; + + if (0 != (nla_parse(tb, + NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL))) { + return NL_SKIP; + } + + if (NULL == tb[NL80211_ATTR_BSS]) { + return NL_SKIP; + } + if (0 != (nla_parse_nested(bss, + NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy))) { + return NL_SKIP; + } + if (NULL == bss[NL80211_BSS_STATUS]) { + return NL_SKIP; + } + + switch(nla_get_u32(bss[NL80211_BSS_STATUS])) { + case NL80211_BSS_STATUS_ASSOCIATED: + case NL80211_BSS_STATUS_AUTHENTICATED: + case NL80211_BSS_STATUS_IBSS_JOINED: + break; + default: + return NL_SKIP; + } + + if (NULL == bss[NL80211_BSS_BSSID]) { + return NL_SKIP; + } + + if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { + ssid = (char *)(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS])); + len = (uint32_t)nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + + if (NULL != ssid && 0 != len) { + ssid += 2; + for (x = 0; x < len; x++) { + elo = ssid[x]; + if (0 == (isprint((unsigned char)elo))) { + break; + } + if (VLA > x) { + *ptr++ = elo; + } + } + *ptr = '\0'; + } + } + return NL_SKIP; +} +#endif /* WITH_NET */ + +void +get_wifi(char *str1, char *str2, uint8_t num) { +#if WITH_NET == 1 + + struct nl_sock *sock = NULL; + struct nl_msg *msg = NULL; + int fam = 0; + uint32_t dev = 0; + void *scan_ret = NULL; + + if (NULL == (sock = nl_socket_alloc())) { + return; + } + if (0 != (genl_connect(sock))) { + goto error; + } + + if (0 != (nl_socket_modify_cb(sock, + NL_CB_VALID, NL_CB_CUSTOM, call_back, str1))) { + goto error; + } + if (0 > (fam = genl_ctrl_resolve(sock, "nl80211"))) { + goto error; + } + + dev = if_nametoindex(str2); + msg = nlmsg_alloc(); + if (0 == dev || NULL == msg) { + goto error_msg; + } + + scan_ret = genlmsg_put(msg, 0, 0, fam, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0); + if (NULL == scan_ret || + 0 != (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev))) { + goto error_msg; + } + + if (0 != (nl_send_sync(sock, msg))) { + goto error; + } + (void)num; + +error: + if (NULL != sock) { + nl_socket_free(sock); + } + return; + +error_msg: + if (NULL != msg) { + nlmsg_free(msg); + } + if (NULL != sock) { + nl_socket_free(sock); + } + return; + +#else + (void)str1; + (void)str2; + (void)num; + RECOMPILE_WITH("net"); +#endif /* WITH_NET */ +} + +#else +void +get_wifi(char *str1, char *str2, uint8_t num) { +#if WITH_NET == 1 + + struct iwreq iwr; + int sock = 0; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (-1 == sock) { + return; + } + + memset(&iwr, 0, sizeof(struct iwreq)); + + iwr.u.essid.pointer = str2; + iwr.u.essid.length = IW_ESSID_MAX_SIZE + 1; + iwr.u.essid.flags = 0; + + snprintf(iwr.ifr_name, IF_NAMESIZE, "%s", str2); + + if (0 != (ioctl(sock, SIOCGIWESSID, &iwr))) { + CLOSE_FD(sock); + return; + } + + switch(num) { + case 1: + FILL_STR_ARR(1, str1, str2); + break; + } + CLOSE_FD(sock); + +#else + (void)str1; + (void)str2; + (void)num; + RECOMPILE_WITH("net"); +#endif /* WITH_NET */ +} +#endif /* WITH_LIBNL */ +#endif /* __linux__ */ diff --git a/src/openbsd_functions.c b/src/openbsd_functions.c new file mode 100644 index 0000000..8c7e8fa --- /dev/null +++ b/src/openbsd_functions.c @@ -0,0 +1,310 @@ +/* + 09/08/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/headers.h" +#include "include/openbzd.h" + +/* + Used resources: + $OpenBSD: uvm_meter.c,v 1.36 2015/03/14 03:38:53 jsg Exp $ + $OpenBSD: machine.c,v 1.63 2007/11/01 19:19:48 otto Exp $ +*/ + +void +get_ram(char *str1, uint8_t num) { + uintmax_t total = 0, freeram = 0, pz = 0; + + pz = (uintmax_t)sysconf(_SC_PAGESIZE); + total = ((uintmax_t)sysconf(_SC_PHYS_PAGES) * pz) / MB; + freeram = ((uintmax_t)sysconf(_SC_AVPHYS_PAGES) * pz) / MB; + + switch(num) { + case 1: + case 2: + FILL_ARR(str1, FMT_UINT "%s", + ((1 == num) ? total: freeram), "MB"); + break; + case 3: + FILL_ARR(str1, FMT_UINT "%s", (total - freeram), "MB"); + break; + case 5: + FILL_UINT_ARR(str1, + ((0 != total) ? (((total - freeram) * 100) / total) : 0)); + break; + } +} + + +void +match_feature(char *str1, int8_t sens_type, int8_t sens_num) { + int mib[] = { CTL_HW, HW_SENSORS, 0, sens_type, 0 }; + struct sensordev dev; + struct sensor sens; + uint_fast16_t z = 0, rpm[MAX_FANS+1]; + int8_t x = 0, y = 0; + uintmax_t temp = 0; + char buffer[VLA]; + char *all = buffer; + bool found_fans = false; + size_t len = 0; + + memset(rpm, 0, sizeof(rpm)); + memset(&dev, 0, sizeof(struct sensordev)); + memset(&sens, 0, sizeof(struct sensor)); + + size_t dev_len = sizeof(dev), sens_len = sizeof(sens); + SYSCTLVAL(mib, 3, &dev, &dev_len); + + for (mib[4] = 0; mib[4] < dev.maxnumt[sens_type]; mib[4]++) { + if (0 != (sysctl(mib, 5, &sens, &sens_len, NULL, 0))) { + break; + } + if (0 != sens_len && + !(sens.flags & (SENSOR_FINVALID | SENSOR_FUNKNOWN))) { + + switch(sens_type) { + case SENSOR_VOLTS_DC: + GLUE2(all, "%.2f ", ((float)sens.value / 1000000.0f)); + break; + + case SENSOR_TEMP: + { + if (x == sens_num) { + temp = (uintmax_t)sens.value; + } + x++; + } + break; + + case SENSOR_FANRPM: + { + if (MAX_FANS != z) { + rpm[z++] = (uint_fast16_t)sens.value; + } + found_fans = true; + } + break; + + default: + continue; + } + } + } + + if (SENSOR_VOLTS_DC == sens_type && '\0' != buffer[0]) { + len = strlen(buffer); + buffer[len-1] = '\0'; + + FILL_STR_ARR(1, str1, buffer); + return; + } + if (SENSOR_TEMP == sens_type) { + if (999999999 < temp) { /* > 99C */ + FILL_UINT_ARR(str1, temp / 100000000); + } else { + FILL_UINT_ARR(str1, ((99999999 < temp) ? + temp / 10000000 : temp / 1000000)); /* > 9C || < 9C */ + } + return; + } + if (true == found_fans) { + check_fan_vals(str1, rpm, z); + } +} + + +void +get_voltage(char *str1) { + match_feature(str1, SENSOR_VOLTS_DC, 0); +} + + +void +get_mobo_temp(char *str1) { + match_feature(str1, SENSOR_TEMP, 1); +} + + +void +get_fans(char *str1) { + match_feature(str1, SENSOR_FANRPM, 0); +} + + +void +get_cpu_temp(char *str1) { + match_feature(str1, SENSOR_TEMP, 0); +} + + +void +get_mobo(char *str1) { + int mib[] = { CTL_HW, HW_VENDOR }; + int mib2[] = { CTL_HW, HW_PRODUCT }; + char vendor[100], model[100]; + size_t len = sizeof(vendor); + + SYSCTLVAL(mib, 2, &vendor, &len); + SYSCTLVAL(mib2, 2, &model, &len); + + split_n_index(vendor); + split_n_index(model); + + FILL_STR_ARR(2, str1, vendor, model); +} + + +/* + * Entirely based on: + * $OpenBSD: apmd.c,v 1.49 2007/11/24 14:58:44 deraadt Exp $ + * The source mentioned different values when + * using Crapple machine that is charging the battery +*/ +void +get_battery(char *str1) { + struct apm_power_info bstate; + int fd = 0; + uintmax_t dummy = 0; + + FILL_STR_ARR(1, str1, "Null"); + memset(&bstate, 0, sizeof(struct apm_power_info)); + + if (0 != (fd = open("/dev/apm", O_RDONLY))) { + return; + } + if (0 != (ioctl(fd, APM_IOC_GETPOWER, &bstate))) { + CLOSE_FD(fd); + return; + } + CLOSE_FD(fd); + + if (APM_BATT_UNKNOWN == bstate.battery_state || + APM_BATTERY_ABSENT == bstate.battery_state) { + return; + } + + dummy = (uintmax_t)bstate.battery_life; + FILL_UINT_ARR(str1, (101 < dummy ? 0 : dummy)); +} + + +/* + * Based on: + * $OpenBSD: swap.c,v 1.27 2015/08/20 22:32:42 deraadt Exp $ +*/ +void +get_swapp(char *str1, uint8_t num) { + struct swapent *dev = NULL; + int count = 0, stats = 0, x = 0; + uintmax_t total = 0, used = 0; + + FILL_STR_ARR(1, str1, "0 MB"); + if (-1 == (count = swapctl(SWAP_NSWAP, 0, 0))) { + return; + } + + dev = (struct swapent *)malloc( + (unsigned long)count * sizeof(struct swapent)); + if (NULL == dev) { + return; + } + + stats = swapctl(SWAP_STATS, dev, count); + if (-1 == stats || stats != count) { + goto error; + } + + for (x = 0; x < count; x++) { + total += (uintmax_t)dev->se_nblks; + used += (uintmax_t)dev->se_inuse; + } + + switch(num) { + case 1: + FILL_ARR(str1, FMT_UINT" %s", BYTES_TO_MB(total), "MB"); + break; + case 2: + FILL_ARR(str1, FMT_UINT" %s", + BYTES_TO_MB((total - used)), "MB"); + break; + case 3: + FILL_ARR(str1, FMT_UINT" %s", BYTES_TO_MB(used), "MB"); + break; + case 4: + FILL_ARR(str1, FMT_UINT"%%", + ((0 != total) ? ((used * 100) / total) : 0)); + break; + } + +error: + if (NULL != dev) { + free(dev); + } + return; +} + + +void +get_statio(char *str1, char *str2) { + struct diskstats *ds = NULL; + int mib[] = { CTL_HW, HW_DISKSTATS }; + size_t len = 0, drivez = 0, x = 0; + + FILL_STR_ARR(1, str1, "Null"); + SYSCTLVAL(mib, 2, NULL, &len); + + if (0 == (drivez = (len / sizeof(*ds)))) { + return; + } + + ds = (struct diskstats *)malloc(drivez * sizeof(char *)); + if (NULL == ds) { + return; + } + if (0 != (sysctl(mib, 2, ds, &len, NULL, 0))) { + goto error; + } + + for (x = 0; x < drivez; x++) { + if (STREQ(str2, ds[x].ds_name)) { + FILL_ARR(str1, "Read " FMT_UINT " MB, Written " FMT_UINT " MB", + (uintmax_t)ds[x].ds_rbytes / MB, + (uintmax_t)ds[x].ds_wbytes / MB); + break; + } + } + +error: + if (NULL != ds) { + free(ds); + } + return; +} diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..578c556 --- /dev/null +++ b/src/options.c @@ -0,0 +1,408 @@ +/* + 08/08/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include +#include + +#include "config.h" /* Auto-generated */ +#include "include/headers.h" +#include "prototypes/cpu.h" +#include "prototypes/sound.h" +#include "prototypes/net.h" +#include "prototypes/options.h" +#include "prototypes/weather.h" +#include "prototypes/smart.h" +#include "prototypes/perl.h" +#include "prototypes/lua.h" +#include "prototypes/ruby.h" +#include "prototypes/python.h" + +/* Because we ran out of a-z A-Z options, + * only long ones will be supported from now on. + * The enumerated argp_option keys below will be used as + * case labels by the parse_opt switch */ +enum { + NICDRV = CHAR_MAX + 1, + KERNODE, + DRIVETEMP, + PERLSCRIPT, + PYTHONSCRIPT, + LUASCRIPT, + RUBYSCRIPT, + BULLSHIFT +}; +const char *argp_program_version = PACKAGE_STRING; +const char *argp_program_bug_address = "https://notabug.org/void0/pinky-bar "; +static const char doc[] = "Statusbar program for anything (Window Manager, terminal multiplexer, etc..)"; +static const struct argp_option options[] = { + { .doc = "Available options:" }, + { .name = "mpd", .key = 'M', .doc = "The song filename." }, + { .name = "mpdartist", .key = 'x', .doc = "The song artist(s) name(s)." }, + { .name = "mpdtitle", .key = 'X', .doc = "The song title." }, + { .name = "mpdalbum", .key = 'y', .doc = "The song album name." }, + { .name = "mpddate", .key = 'Y', .doc = "The song date." }, + { .name = "cpu", .key = 'c', .doc = "The current cpu load (summed up all cores/threads)." }, + { .name = "coresload", .key = 'L', .doc = "Show the load regarding each individual cpu core/thread." }, + { .name = "cpuspeed", .key = 'C', .doc = "The current cpu temperature." }, + { .name = "cpuinfo", .key = 'I', .doc = "Show your maximum cpu clock speed in MHz." }, + { .name = "cputemp", .key = 'T', .doc = "Detect your CPU vendor, stepping, family." }, + { .name = "ramperc", .key = 'r', .doc = "The used ram in percentage." }, + { .name = "ramtotal", .key = 'J', .doc = "The total ram." }, + { .name = "ramfree", .key = 'K', .doc = "The free ram." }, + { .name = "driveperc", .key = 's', .doc = "The used drive storage in percentage." }, + { .name = "drivetotal", .key = 'n', .doc = "The total drive storage." }, + { .name = "drivefree", .key = 'N', .doc = "The free drive storage." }, + { .name = "driveavail", .key = 'O', .doc = "The available drive storage." }, + { .name = "drivetemp", .key = DRIVETEMP, .doc = "Read the drive temperature from S.M.A.R.T" }, + { .name = "dvdstr", .key = 'z', .doc = "The vendor and model name of your cdrom/dvdrom." }, + { .name = "battery", .key = 'g', .doc = "The remaining battery charge." }, + { .name = "packages", .key = 'p', .doc = "The number of installed packages." }, + { .name = "kernsys", .key = 'P', .doc = "The kernel name." }, + { .name = "kernode", .key = KERNODE, .doc = "The network node hostname." }, + { .name = "kernrel", .key = 'Q', .doc = "The kernel release." }, + { .name = "kernver", .key = 'R', .doc = "The kernel version." }, + { .name = "kernarch", .key = 'u', .doc = "The machine architecture." }, + { .name = "kernel", .key = 'k', .doc = "Combined kernel name and version." }, + { .name = "uptime", .key = 'U', .doc = "The system uptime" }, + { .name = "loadavg", .key = 'w', .doc = "The system average load for past 1, 5 and 15 minutes" }, + { .name = "voltage", .key = 'v', .doc = "The system voltage" }, + { .name = "fans", .key = 'f', .doc = "All system fans and their speed in RPM." }, + { .name = "mobo", .key = 'm', .doc = "The motherboard vendor and model names." }, + { .name = "mobotemp", .key = 'd', .doc = "The motherboard temperature." }, + { .name = "volume", .key = 'V', .doc = "The volume." }, + { .name = "time", .key = 't', .doc = "The current time." }, + { .name = "ipaddr", .key = 'a', .arg = "eth0", .doc = "The local IP address." }, + { .name = "iface", .key = 'i', .arg = "eth0", .doc = "The consumed internet bandwidth so far." }, + { .name = "bandwidth", .key = 'b', .arg = "eth0", .doc = "The current download and upload speeds." }, + { .name = "ipmac", .key = 'A', .arg = "eth0", .doc = "The NIC mac address." }, + { .name = "ipmask", .key = 'B', .arg = "eth0", .doc = "The NIC subnet mask address." }, + { .name = "ipcast", .key = 'D', .arg = "eth0", .doc = "The NIC broadcast address." }, + { .name = "iplookup", .key = 'E', .arg = "site", .doc = "Mini website IP lookup." }, + { .name = "statio", .key = 'S', .arg = "sda", .doc = "Read and written MBs to the drive so far." }, + +#if WITH_PERL == 1 + { .name = "perl", .key = PERLSCRIPT, .arg = "script", .doc = "Extend the program with perl, read README." }, +#endif /* WITH_PERL */ + +#if WITH_LUA == 1 + { .name = "lua", .key = LUASCRIPT, .arg = "script", .doc = "Extend the program with lua, read README." }, +#endif /* WITH_LUA */ + +#if WITH_RUBY == 1 + { .name = "ruby", .key = RUBYSCRIPT, .arg = "script", .doc = "Extend the program with ruby, read README." }, +#endif /* WITH_RUBY */ + +#if WITH_PYTHON == 1 + { .name = "python", .key = PYTHONSCRIPT, .arg = "script", .doc = "Extend the program with python, read README." }, +#endif /* WITH_PYTHON */ + +#if WITH_WEATHER == 1 + { .name = "weather", .key = 'q', .arg = "London,uk", .doc = "The temperature outside." }, +#endif /* WITH_WEATHER */ + +#if defined(HAVE_MPD_CLIENT_H) + { .name = "mpdtrack", .key = 'W', .doc = "The song track name." }, +#endif /* HAVE_MPD_CLIENT_H */ + +#if !defined(__OpenBSD__) + { .name = "ramshared", .key = 'l', .doc = "The shared ram." }, + { .name = "rambuffer", .key = 'o', .doc = "The buffered ram." }, +#endif /* !__OpenBSD__ */ + + +#if defined(__OpenBSD__) + { .name = "ramused", .key = 'l', .doc = "The used ram in MB." }, +#endif /* __OpenBSD__ */ + +#if defined(__linux__) + { .name = "nicfw", .key = 'j', .arg = "eth0", .doc = "The NIC firmware." }, + { .name = "drivemodel", .key = 'F', .arg = "sda", .doc = "The vendor name of your drive." }, + { .name = "nicdrv", .key = NICDRV, .arg = "eth0", .doc = "The NIC driver." }, + { .name = "nicver", .key = 'H', .arg = "eth0", .doc = "The NIC version." }, + { .name = "iplink", .key = 'e', .arg = "eth0", .doc = "The NIC link speed (useful for wireless/wifi)." }, + { .name = "nicinfo", .key = 'G', .arg = "eth0", .doc = "The NIC vendor and model." }, + { .name = "wifiname", .key = 'h', .arg = "eth0", .doc = "The name of currently connected wireless/wifi network." }, +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + { .name = "swapused", .key = 'Z', .doc = "The used drive swap in MB." }, + { .name = "swaperc", .key = 'F', .doc = "The used drive swap in percentage." }, + { .name = "swaptotal", .key = 'h', .doc = "The total drive swap." }, + { .name = "swapavail", .key = 'H', .doc = "The available drive swap." }, + { .name = "nicgw", .key = 'j', .arg = "re0", .doc = "The NIC gateway address." }, +#endif /* __FreeBSD__ || __OpenBSD__ */ + + { .doc = NULL } +}; +struct arguments { + char *all; +}; + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) { + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + struct timespec tc = {0}; +#pragma GCC diagnostic pop + + struct arguments *arguments = state->input; + switch(key) { + + NEW_MPD_LABEL('x', char song_artist[VLA], song_artist, 2, FMT_SONG); + + NEW_MPD_LABEL('X', char song_title[VLA], song_title, 3, FMT_SONG); + + NEW_MPD_LABEL('y', char song_album[VLA], song_album, 4, FMT_SONG); + + NEW_MPD_LABEL('Y', char song_date[VLA], song_date, 5, FMT_SONG); + + NEW_MPD_LABEL('M', char song[VLA], song, 6, FMT_SONG); + + NEW_CPU_LABEL('c', char cpu[VLA], cpu, FMT_CPU, CPU_STR); + + NEW_CPU_LABEL('L', char cores_load[VLA], cores_load, FMT_CORES, CPU_STR); + + NEW_LABEL('T', char cpu_temp[VLA], cpu_temp, FMT_TEMP); + + NEW_RAM_LABEL('J', char ram_total[VLA], ram_total, 1, FMT_RAM2, RAM_STR); + + NEW_RAM_LABEL('K', char ram_free[VLA], ram_free, 2, FMT_RAM2, RAM_STR); + + NEW_RAM_LABEL('r', char ram_perc[VLA], ram_perc, 5, FMT_RAM, RAM_STR); + + NEW_SSD_LABEL('n', char ssd_total[VLA], ssd_total, 1, FMT_SSD2, SSD_STR); + + NEW_SSD_LABEL('N', char ssd_free[VLA], ssd_free, 2, FMT_SSD2, SSD_STR); + + NEW_SSD_LABEL('O', char ssd_avail[VLA], ssd_avail, 3, FMT_SSD2, SSD_STR); + + NEW_SSD_LABEL('s', char ssd_perc[VLA], ssd_perc, 4, FMT_SSD, SSD_STR); + + NEW_LABEL('p', char packs[VLA], packs, FMT_PKGS, PKG_STR); + + NEW_KERNEL_LABEL('P', char kernel_sys[VLA], kernel_sys, 1, FMT_KERN); + + NEW_KERNEL_LABEL(KERNODE, char kernel_node[VLA], kernel_node, 2, FMT_KERN); + + NEW_KERNEL_LABEL('Q', char kernel_rel[VLA], kernel_rel, 3, FMT_KERN); + + NEW_KERNEL_LABEL('R', char kernel_ver[VLA], kernel_ver, 4, FMT_KERN); + + NEW_KERNEL_LABEL('u', char kernel_arch[VLA], kernel_arch, 5, FMT_KERN); + + NEW_KERNEL_LABEL('k', char kernel[VLA], kernel, 6, FMT_KERN); + + NEW_LABEL('U', char uptime[VLA], uptime, FMT_UP, UP_STR); + + NEW_LABEL('w', char loadavg[VLA], loadavg, FMT_LOAD, LOAD_STR); + + NEW_LABEL('v', char voltage[VLA], voltage, FMT_VOLT, VOLT_STR); + + NEW_LABEL('m', char mobo[VLA], mobo, FMT_MOBO, MOBO_STR); + + NEW_LABEL('d', char mobo_temp[VLA], mobo_temp, FMT_TEMP); + + NEW_LABEL('f', char fans[VLA], fans, FMT_FANS, FANS_STR); + + NEW_LABEL('t', char taim[VLA], taim, FMT_TIME" ", TIME_STR); + + NEW_NET_LABEL('b', char net[VLA], net, 1, FMT_NET, NET_STR); + + NEW_NET_LABEL('i', char net_speed[VLA], net_speed, 2, FMT_NET, SPEED_STR); + + NEW_NET_LABEL('a', char net_addr[VLA], net_addr, 3, FMT_KERN); + + NEW_NET_LABEL('A', char mac[VLA], mac, 4, FMT_KERN); + + NEW_NET_LABEL('B', char mask[VLA], mask, 5, FMT_KERN); + + NEW_NET_LABEL('D', char net_cast[VLA], net_cast, 6, FMT_KERN); + + NEW_ARG_LABEL('E', char ip_lookup[VLA], ip_lookup, FMT_KERN); + + NEW_RAM_LABEL('l', char ram_shared[VLA], ram_shared, 3, FMT_RAM2, RAM_STR); + + NEW_LABEL('g', char battery[VLA], battery, FMT_BATT, BATT_STR); + + NEW_ARG_LABEL('S', char statio[VLA], statio, FMT_STATIO, STATIO_STR); + + NEW_LABEL(DRIVETEMP, char drivetemp[VLA], drivetemp, FMT_TEMP); + + +#if WITH_PERL == 1 + NEW_ARG_LABEL(PERLSCRIPT, char perl[VLA], perl, FMT_KERN); +#endif /* WITH_PERL */ + + +#if WITH_LUA == 1 + NEW_ARG_LABEL(LUASCRIPT, char lua[VLA], lua, FMT_KERN); +#endif /* WITH_LUA */ + + +#if WITH_RUBY == 1 + NEW_ARG_LABEL(RUBYSCRIPT, char ruby[VLA], ruby, FMT_KERN); +#endif /* WITH_RUBY */ + + +#if WITH_PYTHON == 1 + NEW_ARG_LABEL(PYTHONSCRIPT, char python[VLA], python, FMT_KERN); +#endif /* WITH_PYTHON */ + + +#if WITH_WEATHER == 1 + NEW_ARG_LABEL('q', char weather[VLA], weather, OUT_STR YELLOW STR_SPEC" "); +#endif /* WITH_WEATHER */ + + +#if defined(HAVE_MPD_CLIENT_H) + NEW_MPD_LABEL('W', char song_track[VLA], song_track, 1, FMT_SONG); +#endif /* HAVE_MPD_CLIENT_H */ + + +#if defined(HAVE_CDIO_CDIO_H) || defined(__linux__) + NEW_LABEL('z', char dvd[VLA], dvd, FMT_KERN); +#endif /* HAVE_CDIO_CDIO_H || __linux__ */ + + +#if !defined(__OpenBSD__) + NEW_RAM_LABEL('o', char ram_buffer[VLA], ram_buffer, 4, FMT_RAM2, RAM_STR); +#endif /* !__OpenBSD__ */ + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + NEW_SWAPP_LABEL('h', char swapp_total[VLA], swapp_total, 1, FMT_SSD2, SSD_STR); + + NEW_SWAPP_LABEL('H', char swapp_avail[VLA], swapp_avail, 2, FMT_SSD2, SSD_STR); + + NEW_SWAPP_LABEL('Z', char swapp_used[VLA], swapp_used, 3, FMT_SSD2, SSD_STR); + + NEW_SWAPP_LABEL('F', char swapp_perc[VLA], swapp_perc, 4, FMT_SSD2, SSD_STR); + + NEW_NET_LABEL('j', char nic_info[VLA], nic_info, 7, FMT_KERN); +#endif /* __FreeBSD__ || __OpenBSD__ */ + + +#if defined(__linux__) + NEW_NET_LABEL('j', char nic_info[VLA], nic_info, 10, FMT_KERN); + + NEW_NET_LABEL('h', char wifiname[VLA], wifiname, 11, FMT_KERN); + + NEW_ARG_LABEL('F', char ssd_model[VLA], ssd_model, FMT_KERN); + + NEW_NET_LABEL(NICDRV, char nic_drv[VLA], nic_drv, 8, FMT_KERN); + + NEW_NET_LABEL('H', char nic_ver[VLA], nic_ver, 9, FMT_KERN); + + NEW_ARG_LABEL('G', char nic_info[VLA], nic_info, FMT_KERN); + + NEW_NET_LABEL('e', char link_speed[VLA], link_speed, 7, FMT_KERN); +#endif /* __linux__ */ + + + case 'V': +#if defined(HAVE_ALSA_ASOUNDLIB_H) || defined(HAVE_SYS_SOUNDCARD_H) || \ + defined(HAVE_SOUNDCARD_H) + { + char volume[VLA]; + GET_N_FMT(volume, arguments->all, FMT_VOL, VOL_STR, volume); + } + break; +#else + FPRINTF("%s\n", "recompile the program --with-alsa or --with-oss"); + return ARGP_KEY_ERROR; +#endif /* HAVE_ALSA_ASOUNDLIB_H || HAVE_SYS_SOUNDCARD_H || HAVE_SOUNDCARD_H */ + + case 'C': +#if defined(__i386__) || defined(__i686__) || defined(__x86_64__) + { + char cpu_clock_speed[VLA]; + GET_N_FMT(cpu_clock_speed, arguments->all, FMT_CPUSPEED, cpu_clock_speed); + } + break; +#else + FPRINTF("%s\n", "This option is not supported " + "by your CPU architecture"); + return ARGP_KEY_ERROR; +#endif /* __i386__ || __i686__ || __x86_64__ */ + + case 'I': +#if defined(__i386__) || defined(__i686__) || defined(__x86_64__) + { + char cpu_info[VLA]; + GET_N_FMT(cpu_info, arguments->all, FMT_CPUSPEED, cpu_info); + } + break; +#else + FPRINTF("%s\n", "This option is not supported " + "by your CPU architecture"); + return ARGP_KEY_ERROR; +#endif /* __i386__ || __i686__ || __x86_64__ */ + + default: + return ARGP_ERR_UNKNOWN; + } + return EXIT_SUCCESS; +} + +static const struct argp arg_parser = { + .parser = parse_opt, + .options = options, + .doc = doc +}; + + +void +parse_opts(int argc, char *argv[], char *combined) { + struct arguments arguments = { + .all = combined + }; + argp_parse(&arg_parser, argc, argv, ARGP_IN_ORDER, NULL, &arguments); +} + + +void +parse_konf(char *combined) { + FILE *fp = NULL; + char *ptr = NULL; + char *ello[] = { (char *)"pinkybar", NULL }; + char buf[100], conf[50], temp[100]; + struct arguments arguments = { + .all = combined + }; + + snprintf(conf, 49, "%s%s", getenv("HOME"), "/.pinky"); + if (NULL == (fp = fopen(conf, "r"))) { + exit_with_err(ERR, "~/.pinky doesn't exist."); + } + + while (NULL != (fgets(buf, 99, fp))) { + if (EOF == (sscanf(buf, "%s", temp))) { + CLOSE_X(fp); + exit_with_err(ERR, "empty line(s) detected."); + } + ptr = temp; + while (0 != (isspace((unsigned char) *ptr))) { + ptr++; + } + ello[1] = ptr; + argp_parse(&arg_parser, 2, ello, ARGP_IN_ORDER, NULL, &arguments); + } + CLOSE_X(fp); +} diff --git a/src/perl.c b/src/perl.c new file mode 100644 index 0000000..49660c6 --- /dev/null +++ b/src/perl.c @@ -0,0 +1,121 @@ +/* + 10/24/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if WITH_PERL == 1 + +#include +#include + +#include "include/headers.h" + +#endif /* WITH_PERL */ + +#include "prototypes/perl.h" + +#if WITH_PERL == 1 +static void xs_init(pTHX); +static void call_user_subroutine(char *); +extern void boot_DynaLoader(pTHX_ CV* cv); + +/* Update with: + * perl -MExtUtils::Embed -e xsinit -- -o sample.c +*/ +static void +xs_init(pTHX) { + static const char file[] = __FILE__; + dXSUB_SYS; + PERL_UNUSED_CONTEXT; + newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); +} + +static void +call_user_subroutine(char *str1) { + SV *sva = NULL; + STRLEN len = 0; + int count = 0; + + dSP; /* initialize stack pointer */ + ENTER; /* everything created after here */ + SAVETMPS; /* ...is a temporary variable. */ + + PUSHMARK(SP); /* remember the stack pointer */ + PUTBACK; /* make local stack pointer global */ + + count = call_pv("uzer_func", G_SCALAR); /* call the function */ + SPAGAIN; /* refresh stack pointer */ + + if (1 == count) { /* the Adder returned 1 item */ + sva = POPs; /* pop the return value from stack */ + if (NULL != sva) { + FILL_STR_ARR(1, str1, (char *)SvPV(sva, len)); /* SvPVutf8 needs some testing */ + } + } + + PUTBACK; /* leave the Perl stack in a consistent state */ + FREETMPS; /* free that return value */ + LEAVE; /* ...and the XPUSHed "mortal" args.*/ +} + + +/* Docs: + * http://perldoc.perl.org/perlembed.html + * http://perldoc.perl.org/perlcall.html + * http://docstore.mik.ua/orelly/perl/prog3/ch21_04.htm + */ +void +get_perl(char *str1, char *str2) { + /* The 4th arg to perl_parse is not const */ + char *my_argv[] = { (char *)"", str2 }; + static PerlInterpreter *my_perl = NULL; + int status = 0; + + FILL_STR_ARR(1, str1, "0"); + PERL_SYS_INIT3((int *)NULL, (char ***)NULL, (char ***)NULL); + + my_perl = perl_alloc(); + if (NULL == my_perl) { + PERL_SYS_TERM(); + return; + } + + perl_construct(my_perl); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + + status = perl_parse(my_perl, xs_init, 2, my_argv, (char **)NULL); + if (0 != status) { + goto error; + } + + status = perl_run(my_perl); + if (0 != status) { + goto error; + } + call_user_subroutine(str1); + +error: + perl_destruct(my_perl); + perl_free(my_perl); + PERL_SYS_TERM(); + return; +} +#else +char *p3rL; +#endif /* WITH_PERL */ diff --git a/src/prototypes/common.h b/src/prototypes/common.h new file mode 100644 index 0000000..dd2addf --- /dev/null +++ b/src/prototypes/common.h @@ -0,0 +1,56 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef COMMON_H_ +#define COMMON_H_ + +void exit_with_err(const char *, const char *); +void get_ssd(char *, uint8_t num); +void get_kernel(char *, uint8_t num); +void get_packs(char *); +void get_taim(char *); +void get_uptime(char *); +void check_fan_vals(char *, uint_fast16_t *, uint_fast16_t iterz); +void split_n_index(char *); + +#if !defined(HAVE_SENSORS_SENSORS_H) && !defined(__OpenBSD__) +void get_fans(char *); +#endif /* !HAVE_SENSORS_SENSORS_H && !__OpenBSD__ */ + +#if defined(__linux__) +void get_temp(const char *, char *); +#endif /* __linux__ */ + +#if defined(__FreeBSD__) +void get_temp(char *, uint_least32_t temp); +#endif /* __FreeBSD__ */ + +#if defined (HAVE_X11_XLIB_H) +void set_status(const char *); +#endif + +#if defined(HAVE_CDIO_CDIO_H) || defined(__linux__) +void get_dvd(char *); +#endif /* HAVE_CDIO_CDIO_H || __linux__ */ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +void get_loadavg(char *); +#endif + +#endif /* COMMON_H_ */ diff --git a/src/prototypes/cpu.h b/src/prototypes/cpu.h new file mode 100644 index 0000000..d790dbe --- /dev/null +++ b/src/prototypes/cpu.h @@ -0,0 +1,79 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef CPU_H_ +#define CPU_H_ + +/* Inspired from https://en.wikipedia.org/wiki/CPUID and + * llvm Host.cpp, as hilarious as it sounds, llvm 3.7 + * wants __volatile__ */ +#define CPU_VENDOR(x, z) __asm__ __volatile__ ("cpuid": "=b" (z) : "a" (x)) +#define CPU_FEATURE(x, z) __asm__ __volatile__("cpuid": "=a" (z) : "a" (x)) +#define CPU_REGS(x, y, z) __asm__ __volatile__ ( \ + "cpuid": \ + "=a" (z), \ + "=b" (y) \ + : "a" (x) \ +) +#define CPU_STR2(regizter, a, b, c, d) __asm__ __volatile__ ( \ + "cpuid": \ + "=a" (a), \ + "=b" (b), \ + "=c" (c), \ + "=d" (d) \ + : "a" (regizter) \ +) +#define CPU_ID_STR(regizter, b, c, d) __asm__ __volatile__ ( \ + "cpuid": \ + "=b" (b), \ + "=c" (c), \ + "=d" (d) \ + : "a" (regizter) \ +) +#define IZMAX(x) (((x >> 8) & 0x0f) == 0x0f) + +#define SHFT(x) ((x) & 0x0f) +#define SHFT2(x) ((x) & 0xff) +#define AmD 0x68747541 +#define InteL 0x756e6547 + +#if defined(__linux__) +#define IDLE_NUM 3 +#define LOOP_ITERZ 10 + +#else /* FreeBSD || OpenBSD */ +#define IDLE_NUM 4 +#define LOOP_ITERZ 5 +#endif /* __linux__ */ + +/* --coresload related constant to determine + * how many cpu cores/threads to try for detection */ +#define MAX_CORES 40 + +void get_cpu(char *); +void get_cores_load(char *); + +#if defined(__i386__) || defined(__i686__) || defined(__x86_64__) +void get_cpu_clock_speed(char *); +void get_cpu_info(char *); +uint8_t has_tsc_reg(void); +#endif + + +#endif /* CPU_H_ */ diff --git a/src/prototypes/functions.h b/src/prototypes/functions.h new file mode 100644 index 0000000..addf303 --- /dev/null +++ b/src/prototypes/functions.h @@ -0,0 +1,52 @@ +/* + 07/06/2015, 07/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef FUNCTIONS_H_ +#define FUNCTIONS_H_ + +void get_ram(char *, uint8_t num); +void get_voltage(char *); +void get_mobo(char *); +void get_mobo_temp(char *); +void get_cpu_temp(char *); +void get_battery(char *); +void get_statio(char *, char *); + +#if defined(__linux__) +void get_ssd_model(char *, char *); +void get_loadavg(char *); + +#if defined(HAVE_SENSORS_SENSORS_H) +void get_fans(char *); +void match_feature(char *, uint8_t num); +#endif /* HAVE_SENSORS_SENSORS_H */ + +#endif /* __linux__ */ + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +void get_swapp(char *, uint8_t num); +#endif /* __FreeBSD__ || __OpenBSD__ */ + +#if defined(__OpenBSD__) +void get_fans(char *); +void match_feature(char *str1, int8_t sens_type, int8_t sens_num); +#endif /* __OpenBSD__ */ + +#endif /* FUNCTIONS_H_ */ diff --git a/src/prototypes/lua.h b/src/prototypes/lua.h new file mode 100644 index 0000000..376723e --- /dev/null +++ b/src/prototypes/lua.h @@ -0,0 +1,27 @@ +/* + 11/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef LUA_H_ +#define LUA_H_ + +#if WITH_LUA == 1 +void get_lua(char *, char *); +#endif /* WITH_LUA */ + +#endif /* LUA_H_ */ diff --git a/src/prototypes/net.h b/src/prototypes/net.h new file mode 100644 index 0000000..1e5e53b --- /dev/null +++ b/src/prototypes/net.h @@ -0,0 +1,43 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef NET_H_ +#define NET_H_ + +#if defined(__linux__) +#define NETFAM AF_PACKET +#define RECVBYTS rx_bytes +#define SENTBYTS tx_bytes +#else + +#define NETFAM AF_LINK +#define RECVBYTS ifi_ibytes +#define SENTBYTS ifi_obytes +#endif /* __linux__ */ + +void get_net(char *, char *, uint8_t num); +void get_nic_info2(char *, char *, uint8_t num); +void get_ip_lookup(char *, char *); +void get_nic_info(char *, char *); + +#if defined(__linux__) +void get_wifi(char *, char *, uint8_t num); +#endif /* __linux__ */ + +#endif /* NET_H_ */ diff --git a/src/prototypes/options.h b/src/prototypes/options.h new file mode 100644 index 0000000..ef4aa39 --- /dev/null +++ b/src/prototypes/options.h @@ -0,0 +1,26 @@ +/* + 08/08/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef OPTIONS_H_ +#define OPTIONS_H_ + +void parse_opts(int argc, char *argv[], char *combined); +void parse_konf(char *combined); + +#endif /* OPTIONS_H_ */ diff --git a/src/prototypes/perl.h b/src/prototypes/perl.h new file mode 100644 index 0000000..fe97587 --- /dev/null +++ b/src/prototypes/perl.h @@ -0,0 +1,27 @@ +/* + 10/24/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef PERL_H_ +#define PERL_H_ + +#if WITH_PERL == 1 +void get_perl(char *, char *); +#endif /* WITH_PERL */ + +#endif /* PERL_H_ */ diff --git a/src/prototypes/python.h b/src/prototypes/python.h new file mode 100644 index 0000000..34de891 --- /dev/null +++ b/src/prototypes/python.h @@ -0,0 +1,36 @@ +/* + 10/24/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef PYTHON_H_ +#define PYTHON_H_ + +#if WITH_PYTHON == 1 + +#if WITH_PYTHON2 == 1 +#define PYFON_ZTR PyString_AsString +#else +#define PYFON_ZTR PyUnicode_AsUTF8 +#endif /* WITH_PYTHON2 */ + +#define RET_PY_STR(x) (NULL != PYFON_ZTR(x) ? PYFON_ZTR(x) : "0") + +void get_python(char *, char *); +#endif /* WITH_PYTHON */ + +#endif /* PYTHON_H_ */ diff --git a/src/prototypes/ruby.h b/src/prototypes/ruby.h new file mode 100644 index 0000000..8bb84cc --- /dev/null +++ b/src/prototypes/ruby.h @@ -0,0 +1,27 @@ +/* + 11/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef RUBY_H_ +#define RUBY_H_ + +#if WITH_RUBY == 1 +void get_ruby(char *, char *); +#endif /* WITH_RUBY */ + +#endif /* RUBY_H_ */ diff --git a/src/prototypes/smart.h b/src/prototypes/smart.h new file mode 100644 index 0000000..62cb21b --- /dev/null +++ b/src/prototypes/smart.h @@ -0,0 +1,25 @@ +/* + 10/23/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef SMART_H_ +#define SMART_H_ + +void get_drivetemp(char *); + +#endif /* SMART_H_ */ diff --git a/src/prototypes/sound.h b/src/prototypes/sound.h new file mode 100644 index 0000000..4e83bd9 --- /dev/null +++ b/src/prototypes/sound.h @@ -0,0 +1,31 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef SOUND_H_ +#define SOUND_H_ + +#if defined (HAVE_ALSA_ASOUNDLIB_H) || defined(HAVE_SYS_SOUNDCARD_H) || \ + defined(HAVE_SOUNDCARD_H) +void get_volume(char *); +#endif + +const char *shorten_stream(const char *); +void get_song(char *, int8_t num); + +#endif /* SOUND_H_ */ diff --git a/src/prototypes/weather.h b/src/prototypes/weather.h new file mode 100644 index 0000000..f230a1f --- /dev/null +++ b/src/prototypes/weather.h @@ -0,0 +1,27 @@ +/* + 10/07/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#ifndef WEATHER_H_ +#define WEATHER_H_ + +#if WITH_WEATHER == 1 +void get_weather(char *, char *); +#endif /* WITH_WEATHER */ + +#endif /* WEATHER_H_ */ diff --git a/src/python.c b/src/python.c new file mode 100644 index 0000000..8d4d512 --- /dev/null +++ b/src/python.c @@ -0,0 +1,90 @@ +/* + 10/24/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if WITH_PYTHON == 1 + +#include +#include "include/headers.h" + +#endif /* WITH_PYTHON */ + +#include "prototypes/python.h" + +#if WITH_PYTHON == 1 +/* + * Huge thanks to: + * https://wiki.blender.org/index.php/Dev:2.5/Source/Python/API/Py3.1_Migration +*/ +void +get_python(char *str1, char *str2) { + PyObject *pName = NULL, *pModule = NULL; + PyObject *pFunc = NULL, *pValue = NULL; + + FILL_STR_ARR(1, str1, "0"); + if (NULL == (char *)Py_GetPath()) { + return; + } + + Py_Initialize(); + +#if WITH_PYTHON2 == 1 + pName = PyString_FromString(str2); +#else + pName = PyUnicode_DecodeFSDefault(str2); +#endif /* WITH_PYTHON2 */ + + if (NULL == pName) { + goto error; + } + + pModule = PyImport_Import(pName); + Py_DECREF(pName); + if (NULL == pModule) { + goto error; + } + + pFunc = PyObject_GetAttrString(pModule, (char *)"uzer_func"); + if (NULL == pFunc || 0 == PyCallable_Check(pFunc)) { + goto error; + } + + pValue = PyObject_CallObject(pFunc, NULL); + if (NULL != pValue) { + FILL_STR_ARR(1, str1, RET_PY_STR(pValue)); + } + +error: + if (NULL != pValue) { + Py_XDECREF(pValue); + } + if (NULL != pFunc) { + Py_XDECREF(pFunc); + } + if (NULL != pModule) { + Py_XDECREF(pModule); + } + + Py_Finalize(); + return; +} +#else +char *py7h0n; +#endif /* WITH_PYTHON */ diff --git a/src/ruby.c b/src/ruby.c new file mode 100644 index 0000000..c5f3199 --- /dev/null +++ b/src/ruby.c @@ -0,0 +1,73 @@ +/* + 11/18/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if WITH_RUBY == 1 + +#include +#include "include/headers.h" + +#endif /* WITH_RUBY */ + +#include "prototypes/ruby.h" + +#if WITH_RUBY == 1 +static VALUE catch_snap(VALUE dummy); + +static VALUE catch_snap(VALUE dummy) { + (void)dummy; + VALUE obj = rb_funcall(rb_gv_get("$!"), rb_intern("uzer_func"), 0); + + return obj; +} + +/* + Docs: + https://silverhammermba.github.io/emberb/c/ + + Other resources that helped me: + https://www.ruby-forum.com/topic/184811 + https://opensource.apple.com/source/vim/vim-6/vim/src/if_ruby.c +*/ +void +get_ruby(char *str1, char *str2) { + int status = 0, state = 0; + + FILL_STR_ARR(1, str1, "0"); + + ruby_init(); + ruby_init_loadpath(); + + VALUE src = rb_str_new_cstr(str2), obj; + rb_load_protect(src, 0, &status); + + if (0 == status) { + obj = rb_protect(catch_snap, (VALUE)"dummy", &state); + if (0 == state) { + if (T_STRING == (TYPE(obj))) { + FILL_STR_ARR(1, str1, (StringValuePtr(obj))); + } + } + } + ruby_cleanup(0); +} +#else +char *ruby6; +#endif /* WITH_RUBY */ diff --git a/src/smart.c b/src/smart.c new file mode 100644 index 0000000..c7f4814 --- /dev/null +++ b/src/smart.c @@ -0,0 +1,208 @@ +/* + 10/23/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if defined(__linux__) +#if WITH_DRIVETEMP == 1 || WITH_DRIVETEMP_LIGHT == 1 +#include + +#if WITH_DRIVETEMP_LIGHT == 1 +#include +#include +#else +#include +#endif /* WITH_DRIVETEMP_LIGHT */ + +#endif /* WITH_DRIVETEMP || WITH_DRIVETEMP_LIGHT */ +#endif /* __linux__ */ + +#include "include/headers.h" +#include "prototypes/smart.h" + +#if defined(__linux__) && (WITH_DRIVETEMP == 1 || WITH_DRIVETEMP_LIGHT == 1) +static size_t read_temp_data_cb(char *, size_t size, size_t nmemb, char *); +/* + * The data that we parse: + * |/dev/sda|Corsair Force GT|24|C| */ +static size_t +read_temp_data_cb(char *data, size_t size, size_t nmemb, char *str1) { + static uint8_t one_run = 0, cols = 0; + char *ptr = data; + size_t sz = size * nmemb, x = 0; + + if (0 != one_run) { + return sz; + } + + for (; *ptr; ptr++, x++) { + if ((x+4) < sz) { + + if ('|' == *ptr) { + ++cols; + if (('C' == *(ptr+3) || 'C' == *(ptr+4)) && 3 == cols) { + if (0 != (isdigit((unsigned char) *(ptr+1)))) { + *str1++ = *(ptr+1); + if (0 != (isdigit((unsigned char) *(ptr+2)))) { + *str1++ = *(ptr+2); + } + } + *str1 = '\0'; + break; + } + } + + } + } + + one_run = 1; + if ('\0' != *str1) { + *str1++ = '\0'; + } + return sz; +} +#endif /* __linux__ && (WITH_DRIVETEMP || WITH_DRIVETEMP_LIGHT) */ + + +#if defined(__linux__) && WITH_DRIVETEMP == 1 +/* Most of the time it takes 32 bytes to complete, + * except sometimes the connection gets terminated + * when only 31 bytes was received, so we dont check + * the curl_easy_perform return value for that purpose. + * Due to that, the call back function is called twice to + * finish the left 1 byte, but we already have parsed the + * drive temperature. +*/ +void +get_drivetemp(char *str1) { + const char *da_url = "http://127.0.0.1:" DRIVE_PORT; + CURL *curl = NULL; + + FILL_STR_ARR(1, str1, "0"); + curl_global_init(CURL_GLOBAL_ALL); + + if (NULL == (curl = curl_easy_init())) { + goto error; + } + + curl_easy_setopt(curl, CURLOPT_URL, da_url); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, read_temp_data_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, str1); + + curl_easy_perform(curl); + +error: + if (NULL != curl) { + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return; +} + + +#elif defined(__linux__) && WITH_DRIVETEMP_LIGHT == 1 +/* + * hddtemp/daemon.c + * void daemon_send_msg(struct disk *ldisks, int cfd) { + * struct disk * dsk; + * daemon_update(ldisks, 0); + * for(dsk = ldisks; dsk; dsk = dsk->next) { + * char msg[128]; + * + * We know what the max msg size might be. +*/ +void +get_drivetemp(char *str1) { + struct addrinfo *rp = NULL, *result = NULL, hints; + int sock = 0; + char buf[VLA]; + bool got_conn = false; + ssize_t len = 0; + + FILL_STR_ARR(1, str1, "0"); + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (0 != (getaddrinfo("127.0.0.1", DRIVE_PORT, &hints, &result))) { + FUNC_FAILED("getaddrinfo()"); + } + + for (rp = result; NULL != rp; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (-1 == sock) { + continue; + } + if (NULL == rp->ai_addr) { + CLOSE_FD2(sock, result); + continue; + } + if (0 == (connect(sock, rp->ai_addr, rp->ai_addrlen))) { + /* len, bytes received or -1 on err + * We intentionally do not call + * recv() in a loop, read the + * comment in the curl version + * of get_drivetemp + */ + len = recv(sock, buf, sizeof(buf), 0); + got_conn = true; + CLOSE_FD2(sock, result); + break; + } + CLOSE_FD2(sock, result); + } + + if (true == got_conn) { + if (0 < len) { + /* the 3rd arg is dummy placeholder */ + read_temp_data_cb(buf, (size_t)len, 1, str1); + } + } + + if (NULL != result) { + freeaddrinfo(result); + } +} + + +#else + +void +get_drivetemp(char *str1) { + FILE *fp = NULL; + uint_fast16_t temp = 0; + const char *pinkytemp = "/tmp/pinkytemp"; + + FILL_STR_ARR(1, str1, "0"); + if (NULL == (fp = fopen(pinkytemp, "r"))) { + return; + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + CHECK_FSCANF(fp, SCAN_UFINT, &temp); +#pragma GCC diagnostic pop + CLOSE_X(fp); + + FILL_ARR(str1, UFINT, temp); +} + +#endif /* __linux__ && WITH_DRIVETEMP || __linux__ && WITH_DRIVETEMP_LIGHT || with smartemp */ diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 0000000..14569d5 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,250 @@ +/* + 08/06/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if defined (HAVE_MPD_CLIENT_H) +#include +#endif /* HAVE_MPD_CLIENT_H */ + +#if defined (HAVE_ALSA_ASOUNDLIB_H) +#include +#endif /* HAVE_ALSA_ASOUNDLIB_H */ + +#if defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_SOUNDCARD_H) +#include +#include + +#if defined(HAVE_SOUNDCARD_H) +#include +#else +#include +#endif /* HAVE_SOUNDCARD_H */ + +#endif /* HAVE_SYS_SOUNDCARD_H || HAVE_SOUNDCARD_H */ + +#include "include/headers.h" +#include "prototypes/sound.h" + +#if defined (HAVE_ALSA_ASOUNDLIB_H) +/* http://www.alsa-project.org/alsa-doc/alsa-lib/group___mixer.html + * http://www.alsa-project.org/alsa-doc/alsa-lib/group___simple_mixer.html + * for the return values */ +void +get_volume(char *str1) { + snd_mixer_t *handle = NULL; + snd_mixer_elem_t *elem = NULL; + snd_mixer_selem_id_t *s_elem = NULL; + long int vol = 0L, max = 0L, min = 0L; + + if (0 != (snd_mixer_open(&handle, 0))) { + FUNC_FAILED("alsa"); + } + + if (0 != (snd_mixer_attach(handle, "default"))) { + goto error; + } + + if (0 != (snd_mixer_selem_register(handle, NULL, NULL))) { + goto error; + } + + if (0 != (snd_mixer_load(handle))) { + goto error; + } + + snd_mixer_selem_id_malloc(&s_elem); + if (NULL == s_elem) { + goto error; + } + + snd_mixer_selem_id_set_name(s_elem, "Master"); + if (NULL == (elem = snd_mixer_find_selem(handle, s_elem))) { + goto error; + } + + if (0 != (snd_mixer_selem_get_playback_volume(elem, 0, &vol))) { + goto error; + } + snd_mixer_selem_get_playback_volume_range(elem, &min, &max); + + snd_mixer_selem_id_free(s_elem); + snd_mixer_close(handle); + + FILL_ARR(str1, "%ld", + ((0 != max) ? ((vol * 100) / max) : 0L)); + return; + +error: + if (NULL != s_elem) { + snd_mixer_selem_id_free(s_elem); + } + if (NULL != handle) { + snd_mixer_close(handle); + } + FUNC_FAILED("alsa"); +} +#endif /* HAVE_ALSA_ASOUNDLIB_H */ + + +#if defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_SOUNDCARD_H) +/* Used the following resource: + sources.freebsd.org/RELENG_9/src/usr.sbin/mixer/mixer.c +*/ +void +get_volume(char *str1) { + int devmask = 0, volume = 0, fd = 0; + + if (-1 == (fd = open("/dev/mixer", O_RDONLY))) { + exit_with_err(CANNOT_OPEN, "/dev/mixer"); + } + if (-1 == (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask))) { + CLOSE_FD(fd); + exit_with_err(ERR, "SOUND_MIXER_READ_DEVMASK"); + } + if (-1 == (ioctl(fd, MIXER_READ(0), &volume))) { + CLOSE_FD(fd); + exit_with_err(ERR, "MIXER_READ()"); + } + CLOSE_FD(fd); + + FILL_ARR(str1, "%d", ((volume >> 8) & 0x7f)); +} +#endif /* HAVE_SYS_SOUNDCARD_H || HAVE_SOUNDCARD_H */ + + +const char * +shorten_stream(const char *str1) { + /* Dont submit pull request + * if you dont know the difference + * between the two examples below. + * + * const char *stream = "elo"; + * char *const stream = "elo"; */ + const char *stream = str1; + + if (5 < (strlen(stream))) { + if (0 == (strncmp(stream, "http", 4))) { + stream = ".."; + } + } + return stream; +} + + +#if defined (HAVE_MPD_CLIENT_H) +void +get_song(char *str1, int8_t num) { + + struct mpd_connection *conn = NULL; + struct mpd_song *song = NULL; + const char *stream = NULL, *taggy = NULL; + static const int8_t tagz_arr[] = { + 0, + MPD_TAG_TRACK, + MPD_TAG_ARTIST, + MPD_TAG_TITLE, + MPD_TAG_ALBUM, + MPD_TAG_DATE + }; + + *str1 = '\0'; + if (NULL == (conn = mpd_connection_new(NULL, 0, 0))) { + return; + } + if (!(mpd_send_command(conn, "currentsong", NULL)) || + 0 != (mpd_connection_get_error(conn))) { + goto error; + } + if (NULL == (song = mpd_recv_song(conn))) { + goto error; + } + + if (6 != num) { + taggy = mpd_song_get_tag(song, tagz_arr[num], 0); + if (NULL != taggy) { + FILL_STR_ARR(1, str1, taggy); + } + } else { + if (NULL != (stream = mpd_song_get_uri(song))) { + FILL_STR_ARR(1, str1, (shorten_stream(stream))); + } + } + +error: + if (NULL != song) { + mpd_song_free(song); + } + if (NULL != conn) { + mpd_connection_free(conn); + } + return; +} + +#else + +void +get_song(char *str1, int8_t num) { + FILE *fp = NULL; + static bool got_stream = false; + char *ptr = NULL, buf[100], temp[100]; + const char *tagz[] = { "artist", "title", "album", "date" }; + const char *idx_tagz = ((6 != num) ? tagz[num-2] : "ohsnap"); + + if (NULL == (fp = popen("cmus-remote -Q 2> /dev/null", "r"))) { + return; + } + + while (NULL != (fgets(buf, 99, fp))) { + if (6 == num) { + if ('f' == buf[0] && 'i' == buf[1] && 'l' == buf[2]) { + CHECK_SSCANF(buf, "%*s %[^\n]", temp); + if (NULL != (ptr = strrchr(temp, '/'))) { + for (; *ptr; ptr++) { + if ('/' != *ptr) { + *str1++ = *ptr; + } + } + *str1 = '\0'; + } + break; + } + } else { + if ('t' == buf[0] && 'a' == buf[1] && 'g' == buf[2]) { + CHECK_SSCANF(buf, "%*s %s", temp); + if (STREQ(idx_tagz, temp)) { + CHECK_SSCANF(buf, "%*s %*s %[^\n]", str1); + break; + } + } + if ('s' == buf[0] && 't' == buf[1] && 'r' == buf[2]) { + if (1 != (num-2) && false == got_stream) { + CHECK_SSCANF(buf, "%*s %[^\n]", str1); + got_stream = true; + break; + } + } + } + } + + if (-1 == (pclose(fp))) { + exit_with_err(CANNOT_CLOSE, "popen()"); + } +} +#endif /* HAVE_MPD_CLIENT_H */ diff --git a/src/weather.c b/src/weather.c new file mode 100644 index 0000000..023d95b --- /dev/null +++ b/src/weather.c @@ -0,0 +1,171 @@ +/* + 10/07/2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +#include "config.h" /* Auto-generated */ + +#if WITH_WEATHER == 1 + +#include +#include +#include "include/headers.h" + +#endif /* WITH_WEATHER */ + +#include "prototypes/weather.h" + +#if WITH_WEATHER == 1 +static size_t read_curl_data_cb(char *, size_t size, size_t nmemb, char *); + +/* + The 4th arg: + https://curl.haxx.se/libcurl/c/CURLOPT_WRITEDATA.html + + The JSON data that we are parsing, that's how it's returned: + +{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"stations","main":{"temp":12.05,"pressure":1030.73,"humidity":70,"temp_min":12.05,"temp_max":12.05,"sea_level":1038.34,"grnd_level":1030.73},"wind":{"speed":3.82,"deg":8.50131},"clouds":{"all":64},"dt":1476114783,"sys":{"message":0.011,"country":"GB","sunrise":1476080264,"sunset":1476119749},"id":2643743,"name":"London","cod":200} + + You can parse anything in the above example. +*/ +static size_t +read_curl_data_cb(char *data, size_t size, size_t nmemb, char *str1) { + uint8_t got_main = 0, got_temp = 0; + uint8_t y = 0, z = 0; + char *ptr = NULL; + const char wind[] = " Wind ", kmh[] = " km/h"; + size_t sz = nmemb * size, x = 0; + + for (ptr = data; *ptr; ptr++, x++) { + if ((x+7) < sz) { /* Verifying up to *(ptr+7) */ + + if ('m' == *ptr) { /* "main":"Clouds" */ + if (0 == got_main) { + if ('a' == *(ptr+1) && 'i' == *(ptr+2) && 'n' == *(ptr+3)) { + if ((x+40) < sz) { + for (; *ptr && *(ptr+7) && z < 29; z++, ptr++) { + if ('"' == *(ptr+7)) { + *str1++ = ' '; + break; + } + if (0 != (isalpha((unsigned char) *(ptr+7)))) { + *str1++ = *(ptr+7); + } + } + got_main = 1; + } + } + } + } + + if ('t' == *ptr) { /* "temp":12.05 */ + if (0 == got_temp) { + if ('e' == *(ptr+1) && 'm' == *(ptr+2) && 'p' == *(ptr+3)) { + if (0 != (isdigit((unsigned char) *(ptr+6)))) { + *str1++ = *(ptr+6); + if (0 != (isdigit((unsigned char) *(ptr+7)))) { + *str1++ = *(ptr+7); + } + *str1++ = 'C'; + got_temp = 1; + } + } + } + } + + if ('s' == *ptr) { /* "speed":3.82 */ + if ('p' == *(ptr+1) && 'e' == *(ptr+2) && 'e' == *(ptr+3)) { + if ((x+9) < sz) { + if (0 != (isdigit((unsigned char) *(ptr+7)))) { + for (y = 0; y < 6; y++) { + *str1++ = wind[y]; + } + *str1++ = *(ptr+7); + + if (0 != (isdigit((unsigned char) *(ptr+8)))) { + *str1++ = *(ptr+8); + } + + for (y = 0; y < 5; y++) { + *str1++ = kmh[y]; + } + } + *str1 = '\0'; + break; + } + } + } + + } + } + + if ('\0' != *str1) { + *str1++ = '\0'; + } + return sz; +} + + +/* + API docs - http://openweathermap.org/current + Register yourself, create a new API key: + https://home.openweathermap.org/api_keys + Comply with your account limits. + + cURL related docs and examples + https://curl.haxx.se/libcurl/c/curl_easy_setopt.html + https://github.com/curl/curl/tree/master/docs/examples +*/ +void +get_weather(char *str1, char *str2) { + const char *da_url = "http://api.openweathermap.org/data/2.5/weather?q="; + char temp[VLA]; + + FILL_ARR(temp, "%s%s%s%s", da_url, str2, "&units=metric&APPID=", API_KEY); + + CURL *curl = NULL; + CURLcode res; + + FILL_STR_ARR(1, str1, "0"); + curl_global_init(CURL_GLOBAL_ALL); + + if (NULL == (curl = curl_easy_init())) { + goto error; + } + + curl_easy_setopt(curl, CURLOPT_URL, temp); + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip"); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, read_curl_data_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, str1); + + res = curl_easy_perform(curl); + if (CURLE_OK != res) { + goto error; + } + +error: + if (NULL != curl) { + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return; +} + +#else +char *l33t; +#endif /* WITH_WEATHER */ -- 2.11.0