From 609664bb77874990e10f8073e54bb7f1645c8d72 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Orsini Date: Thu, 21 Apr 2011 08:00:29 +0000 Subject: [PATCH] import psensor trunk from private svn --- ABOUT-NLS | 1101 ++++++++++++++ AUTHORS | 4 + COPYING | 340 +++++ ChangeLog | 0 INSTALL | 365 +++++ Makefile.am | 9 + NEWS | 248 ++++ README | 113 ++ configure.ac | 221 +++ debian/changelog | 94 ++ debian/control | 54 + debian/copyright | 32 + debian/docs | 2 + debian/psensor-common.install | 1 + debian/psensor-server.install | 3 + debian/psensor-server.manpages | 1 + debian/psensor.install | 8 + debian/psensor.manpages | 2 + debian/rules | 13 + debian/watch | 3 + pixmaps/16x16/psensor.png | Bin 0 -> 423 bytes pixmaps/22x22/psensor.png | Bin 0 -> 511 bytes pixmaps/24x24/psensor.png | Bin 0 -> 575 bytes pixmaps/32x32/psensor.png | Bin 0 -> 646 bytes pixmaps/48x48/Makefile.am | 6 + pixmaps/48x48/psensor.png | Bin 0 -> 914 bytes pixmaps/48x48/psensor_hot.png | Bin 0 -> 1734 bytes pixmaps/scalable/Makefile.am | 6 + pixmaps/scalable/psensor.svg | 276 ++++ pixmaps/scalable/psensor_hot.svg | 276 ++++ po/LINGUAS | 10 + po/Makefile.in.in | 403 +++++ po/Makevars | 41 + po/POTFILES.in | 12 + po/Rules-quot | 47 + po/boldquot.sed | 10 + po/en@boldquot.header | 25 + po/en@quot.header | 22 + po/fr.po | 329 +++++ po/insert-header.sin | 23 + po/psensor.pot | 281 ++++ po/quot.sed | 6 + po/remove-potcdate.sin | 19 + po/zh_CN.po | 366 +++++ psensor.desktop | 10 + src/Makefile.am | 81 ++ src/cfg.c | 456 ++++++ src/cfg.h | 80 + src/compat.h | 26 + src/description.txt | 32 + src/glade/Makefile.am | 6 + src/glade/psensor-pref.glade | 534 +++++++ src/glade/sensor-edit.glade | 329 +++++ src/graph.c | 331 +++++ src/graph.h | 30 + src/httpd/Makefile.am | 41 + src/httpd/httpd.c | 426 ++++++ src/httpd/httpd.h | 26 + src/lib/Makefile.am | 15 + src/lib/color.c | 99 ++ src/lib/color.h | 57 + src/lib/hdd.c | 256 ++++ src/lib/hdd.h | 30 + src/lib/lmsensor.c | 172 +++ src/lib/lmsensor.h | 31 + src/lib/measure.c | 48 + src/lib/measure.h | 39 + src/lib/nvidia.c | 150 ++ src/lib/nvidia.h | 44 + src/lib/psensor.c | 422 ++++++ src/lib/psensor.h | 155 ++ src/libpsensor_json/Makefile.am | 12 + src/libpsensor_json/psensor_json.c | 99 ++ src/libpsensor_json/psensor_json.h | 32 + src/main.c | 420 ++++++ src/plib/Makefile.am | 21 + src/plib/plib_io.c | 297 ++++ src/plib/plib_io.h | 71 + src/plib/plib_luatpl.c | 157 ++ src/plib/plib_luatpl.h | 78 + src/plib/url.c | 75 + src/plib/url.h | 26 + src/rsensor.c | 221 +++ src/rsensor.h | 32 + src/server/Makefile.am | 42 + src/server/description.txt | 33 + src/server/server.c | 428 ++++++ src/server/server.h | 36 + src/server/server_lua.c | 163 +++ src/server/server_lua.h | 27 + src/server/sysinfo.c | 60 + src/server/sysinfo.h | 34 + src/ui.c | 126 ++ src/ui.h | 77 + src/ui_appindicator.c | 131 ++ src/ui_appindicator.h | 28 + src/ui_color.c | 54 + src/ui_color.h | 32 + src/ui_graph.c | 94 ++ src/ui_graph.h | 29 + src/ui_notify.c | 80 + src/ui_notify.h | 28 + src/ui_pref.c | 182 +++ src/ui_pref.h | 28 + src/ui_sensorlist.c | 492 +++++++ src/ui_sensorlist.h | 42 + src/unity/Makefile.am | 14 + src/unity/ui_unity.c | 43 + src/unity/ui_unity.h | 27 + tests/Makefile.am | 5 + tests/checkpatch.pl | 2823 ++++++++++++++++++++++++++++++++++++ www/Makefile.am | 4 + www/favicon.ico | Bin 0 -> 9662 bytes www/index.lua | 28 + www/monitor.lua | 188 +++ www/style.css | 23 + 116 files changed, 15640 insertions(+) create mode 100644 ABOUT-NLS create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 configure.ac create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/docs create mode 100644 debian/psensor-common.install create mode 100644 debian/psensor-server.install create mode 100644 debian/psensor-server.manpages create mode 100644 debian/psensor.install create mode 100644 debian/psensor.manpages create mode 100755 debian/rules create mode 100644 debian/watch create mode 100644 pixmaps/16x16/psensor.png create mode 100644 pixmaps/22x22/psensor.png create mode 100644 pixmaps/24x24/psensor.png create mode 100644 pixmaps/32x32/psensor.png create mode 100644 pixmaps/48x48/Makefile.am create mode 100644 pixmaps/48x48/psensor.png create mode 100644 pixmaps/48x48/psensor_hot.png create mode 100644 pixmaps/scalable/Makefile.am create mode 100644 pixmaps/scalable/psensor.svg create mode 100644 pixmaps/scalable/psensor_hot.svg create mode 100644 po/LINGUAS create mode 100644 po/Makefile.in.in create mode 100644 po/Makevars create mode 100644 po/POTFILES.in create mode 100644 po/Rules-quot create mode 100644 po/boldquot.sed create mode 100644 po/en@boldquot.header create mode 100644 po/en@quot.header create mode 100644 po/fr.po create mode 100644 po/insert-header.sin create mode 100644 po/psensor.pot create mode 100644 po/quot.sed create mode 100644 po/remove-potcdate.sin create mode 100644 po/zh_CN.po create mode 100644 psensor.desktop create mode 100644 src/Makefile.am create mode 100644 src/cfg.c create mode 100644 src/cfg.h create mode 100644 src/compat.h create mode 100644 src/description.txt create mode 100644 src/glade/Makefile.am create mode 100644 src/glade/psensor-pref.glade create mode 100644 src/glade/sensor-edit.glade create mode 100644 src/graph.c create mode 100644 src/graph.h create mode 100644 src/httpd/Makefile.am create mode 100644 src/httpd/httpd.c create mode 100644 src/httpd/httpd.h create mode 100644 src/lib/Makefile.am create mode 100644 src/lib/color.c create mode 100644 src/lib/color.h create mode 100644 src/lib/hdd.c create mode 100644 src/lib/hdd.h create mode 100644 src/lib/lmsensor.c create mode 100644 src/lib/lmsensor.h create mode 100644 src/lib/measure.c create mode 100644 src/lib/measure.h create mode 100644 src/lib/nvidia.c create mode 100644 src/lib/nvidia.h create mode 100644 src/lib/psensor.c create mode 100644 src/lib/psensor.h create mode 100644 src/libpsensor_json/Makefile.am create mode 100644 src/libpsensor_json/psensor_json.c create mode 100644 src/libpsensor_json/psensor_json.h create mode 100644 src/main.c create mode 100644 src/plib/Makefile.am create mode 100644 src/plib/plib_io.c create mode 100644 src/plib/plib_io.h create mode 100644 src/plib/plib_luatpl.c create mode 100644 src/plib/plib_luatpl.h create mode 100644 src/plib/url.c create mode 100644 src/plib/url.h create mode 100644 src/rsensor.c create mode 100644 src/rsensor.h create mode 100644 src/server/Makefile.am create mode 100644 src/server/description.txt create mode 100644 src/server/server.c create mode 100644 src/server/server.h create mode 100644 src/server/server_lua.c create mode 100644 src/server/server_lua.h create mode 100644 src/server/sysinfo.c create mode 100644 src/server/sysinfo.h create mode 100644 src/ui.c create mode 100644 src/ui.h create mode 100644 src/ui_appindicator.c create mode 100644 src/ui_appindicator.h create mode 100644 src/ui_color.c create mode 100644 src/ui_color.h create mode 100644 src/ui_graph.c create mode 100644 src/ui_graph.h create mode 100644 src/ui_notify.c create mode 100644 src/ui_notify.h create mode 100644 src/ui_pref.c create mode 100644 src/ui_pref.h create mode 100644 src/ui_sensorlist.c create mode 100644 src/ui_sensorlist.h create mode 100644 src/unity/Makefile.am create mode 100644 src/unity/ui_unity.c create mode 100644 src/unity/ui_unity.h create mode 100644 tests/Makefile.am create mode 100755 tests/checkpatch.pl create mode 100644 www/Makefile.am create mode 100644 www/favicon.ico create mode 100644 www/index.lua create mode 100644 www/monitor.lua create mode 100644 www/style.css diff --git a/ABOUT-NLS b/ABOUT-NLS new file mode 100644 index 0000000..ec20977 --- /dev/null +++ b/ABOUT-NLS @@ -0,0 +1,1101 @@ +1 Notes on the Free Translation Project +*************************************** + +Free software is going international! The Free Translation Project is +a way to get maintainers of free software, translators, and users all +together, so that free software will gradually become able to speak many +languages. A few packages already provide translations for their +messages. + + If you found this `ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU `gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU `gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work on translations can contact the appropriate team. + + When reporting bugs in the `intl/' directory or bugs which may be +related to internationalization, you should tell about the version of +`gettext' which is used. The information can be found in the +`intl/VERSION' file, in internationalized packages. + +1.1 Quick configuration advice +============================== + +If you want to exploit the full power of internationalization, you +should configure it using + + ./configure --with-included-gettext + +to force usage of internationalizing routines provided within this +package, despite the existence of internationalizing capabilities in the +operating system where this package is being installed. So far, only +the `gettext' implementation in the GNU C library version 2 provides as +many features (such as locale alias, message inheritance, automatic +charset conversion or plural form handling) as the implementation here. +It is also not possible to offer this additional functionality on top +of a `catgets' implementation. Future versions of GNU `gettext' will +very likely convey even more functionality. So it might be a good idea +to change to GNU `gettext' as soon as possible. + + So you need _not_ provide this option if you are using GNU libc 2 or +you have installed a recent copy of the GNU gettext package with the +included `libintl'. + +1.2 INSTALL Matters +=================== + +Some packages are "localizable" when properly installed; the programs +they contain can be made to speak your own native language. Most such +packages use GNU `gettext'. Other packages have their own ways to +internationalization, predating GNU `gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU `gettext' functions. If not, the included GNU +`gettext' library will be used. This library is wholly contained +within this package, usually in the `intl/' subdirectory, so prior +installation of the GNU `gettext' package is _not_ required. +Installers may use special options at configuration time for changing +the default behaviour. The commands: + + ./configure --with-included-gettext + ./configure --disable-nls + +will, respectively, bypass any pre-existing `gettext' to use the +internationalizing routines provided within this package, or else, +_totally_ disable translation of messages. + + When you already have GNU `gettext' installed on your system and run +configure without an option for your new package, `configure' will +probably detect the previously built and installed `libintl.a' file and +will decide to use this. This might not be desirable. You should use +the more recent version of the GNU `gettext' library. I.e. if the file +`intl/VERSION' shows that the library which comes with this package is +more recent, you should use + + ./configure --with-included-gettext + +to prevent auto-detection. + + The configuration process will not test for the `catgets' function +and therefore it will not be used. The reason is that even an +emulation of `gettext' on top of `catgets' could not provide all the +extensions of the GNU `gettext' library. + + Internationalized packages usually have many `po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at `configure' time by using the +`--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable `LINGUAS' +may be set, prior to configuration, to limit the installed set. +`LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +1.3 Using This Package +====================== + +As a user, if your language has been installed for this package, you +only have to set the `LANG' environment variable to the appropriate +`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, +and `CC' is an ISO 3166 two-letter country code. For example, let's +suppose that you speak German and live in Germany. At the shell +prompt, merely execute `setenv LANG de_DE' (in `csh'), +`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). +This can be done from your `.login' or `.profile' file, once and for +all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of `LL_CC', with `LL' denoting the +language and `CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are +used, such as `LL' or `LL_CC.ENCODING'. You can get the list of +locales supported by your system for your language by running the +command `locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' +for the purpose of message handling, but you still need to have `LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather +read translations in German than English for when Swedish is not +available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. + + Special advice for Norwegian users: The language code for Norwegian +bokma*l changed from `no' to `nb' recently (in 2003). During the +transition period, while some message catalogs for this language are +installed under `nb' and some older ones under `no', it's recommended +for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and +older translations are used. + + In the `LANGUAGE' environment variable, but not in the `LANG' +environment variable, `LL_CC' combinations can be abbreviated as `LL' +to denote the language's main dialect. For example, `de' is equivalent +to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' +(Portuguese as spoken in Portugal) in this context. + +1.4 Translating Teams +===================== + +For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" +area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +`-request' appended. For example, speakers of Swedish can send a +message to `sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate +_actively_ in translations, or at solving translational difficulties, +rather than merely lurking around. If your team does not exist yet and +you want to start one, or if you are unsure about what to do or how to +get started, please write to `translation@iro.umontreal.ca' to reach the +coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skills are praised more than +programming skills, here. + +1.5 Available Packages +====================== + +Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of October +2006. The matrix shows, in regard of each package, for which languages +PO files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo + +----------------------------------------------------+ + GNUnet | [] | + a2ps | [] [] [] [] [] | + aegis | () | + ant-phone | () | + anubis | [] | + ap-utils | | + aspell | [] [] [] [] [] | + bash | [] [] [] | + batchelor | [] | + bfd | | + bibshelf | [] | + binutils | [] | + bison | [] [] | + bison-runtime | | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | [] [] | + coreutils | [] [] [] | + cpio | | + cpplib | [] [] [] | + cryptonit | [] | + darkstat | [] () [] | + dialog | [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] | + doodle | [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] | + error | [] [] [] [] | + fetchmail | [] [] () [] | + fileutils | [] [] | + findutils | [] [] [] | + flex | [] [] [] | + fslint | [] | + gas | | + gawk | [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] [] [] | + gip | [] | + gliv | [] | + glunarclock | [] | + gmult | [] [] | + gnubiff | () | + gnucash | () () [] | + gnucash-glossary | [] () | + gnuedu | | + gnulib | [] [] [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] | + gpe-conf | [] [] | + gpe-contacts | | + gpe-edit | [] | + gpe-filemanager | | + gpe-go | [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] | + gpe-package | | + gpe-sketchbook | [] [] | + gpe-su | [] [] | + gpe-taskmanager | [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | | + gphoto2 | [] [] [] [] | + gprof | [] [] | + gpsdrive | () () | + gramadoir | [] [] | + grep | [] [] [] [] [] [] | + gretl | | + gsasl | | + gss | | + gst-plugins | [] [] [] [] | + gst-plugins-base | [] [] [] | + gst-plugins-good | [] [] [] [] [] [] [] | + gstreamer | [] [] [] [] [] [] [] | + gtick | () | + gtkam | [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] | + id-utils | [] [] | + impost | | + indent | [] [] [] | + iso_3166 | [] [] | + iso_3166_2 | | + iso_4217 | [] | + iso_639 | [] [] | + jpilot | [] | + jtag | | + jwhois | | + kbd | [] [] [] [] | + keytouch | | + keytouch-editor | | + keytouch-keyboa... | | + latrine | () | + ld | [] | + leafpad | [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] | + libgpg-error | [] | + libgphoto2 | [] [] | + libgphoto2_port | [] [] | + libgsasl | | + libiconv | [] [] | + libidn | [] [] | + lifelines | [] () | + lilypond | [] | + lingoteach | | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | [] | + make | [] [] | + man-db | [] () [] [] | + minicom | [] [] [] | + mysecretdiary | [] [] | + nano | [] [] [] | + nano_1_0 | [] () [] [] | + opcodes | [] | + parted | | + pilot-qof | [] | + psmisc | [] | + pwdutils | | + python | | + qof | | + radius | [] | + recode | [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] [] | + sed | [] [] [] | + sh-utils | [] [] | + shared-mime-info | [] [] [] [] | + sharutils | [] [] [] [] [] [] | + shishi | | + silky | | + skencil | [] () | + sketch | [] () | + solfege | | + soundtracker | [] [] | + sp | [] | + stardict | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] | + texinfo | [] [] [] | + textutils | [] [] [] | + tin | () () | + tp-robot | [] | + tuxpaint | [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + vorbis-tools | [] [] [] [] | + wastesedge | () | + wdiff | [] [] [] [] | + wget | [] [] | + xchat | [] [] [] [] [] [] | + xkeyboard-config | | + xpad | [] [] | + +----------------------------------------------------+ + af am ar az be bg bs ca cs cy da de el en en_GB eo + 10 0 1 2 9 22 1 42 41 2 60 95 16 1 17 16 + + es et eu fa fi fr ga gl gu he hi hr hu id is it + +--------------------------------------------------+ + GNUnet | | + a2ps | [] [] [] () | + aegis | | + ant-phone | [] | + anubis | [] | + ap-utils | [] [] | + aspell | [] [] [] | + bash | [] [] [] | + batchelor | [] [] | + bfd | [] | + bibshelf | [] [] [] | + binutils | [] [] [] | + bison | [] [] [] [] [] [] | + bison-runtime | [] [] [] [] [] | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | | + coreutils | [] [] [] [] [] [] | + cpio | [] [] [] | + cpplib | [] [] | + cryptonit | [] | + darkstat | [] () [] [] [] | + dialog | [] [] [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] [] | + enscript | [] [] [] | + error | [] [] [] [] [] | + fetchmail | [] | + fileutils | [] [] [] [] [] [] | + findutils | [] [] [] [] | + flex | [] [] [] | + fslint | [] | + gas | [] [] | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] | + gettext-tools | [] [] [] | + gimp-print | [] [] | + gip | [] [] [] | + gliv | () | + glunarclock | [] [] [] | + gmult | [] [] [] | + gnubiff | () () | + gnucash | () () () | + gnucash-glossary | [] [] | + gnuedu | [] | + gnulib | [] [] [] [] [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] [] [] | + gpe-conf | [] | + gpe-contacts | [] [] | + gpe-edit | [] [] [] [] | + gpe-filemanager | [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] [] [] [] | + gpe-package | [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] [] | + gpe-taskmanager | [] [] [] | + gpe-timesheet | [] [] [] [] | + gpe-today | [] [] [] [] | + gpe-todo | [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] [] | + gpsdrive | () () [] () | + gramadoir | [] [] | + grep | [] [] [] [] [] [] [] [] [] [] [] [] | + gretl | [] [] [] | + gsasl | [] [] | + gss | [] | + gst-plugins | [] [] [] | + gst-plugins-base | [] [] | + gst-plugins-good | [] [] [] | + gstreamer | [] [] [] | + gtick | [] | + gtkam | [] [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] [] | + impost | [] [] | + indent | [] [] [] [] [] [] [] [] [] [] | + iso_3166 | [] [] [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] [] | + iso_639 | [] [] [] [] [] | + jpilot | [] [] | + jtag | [] | + jwhois | [] [] [] [] [] | + kbd | [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | [] [] [] | + ld | [] [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] [] [] | + libgpg-error | | + libgphoto2 | [] [] [] | + libgphoto2_port | [] [] | + libgsasl | [] [] | + libiconv | [] [] | + libidn | [] [] | + lifelines | () | + lilypond | [] | + lingoteach | [] [] [] | + lynx | [] [] [] | + m4 | [] [] [] [] | + mailutils | [] [] | + make | [] [] [] [] [] [] [] [] | + man-db | () | + minicom | [] [] [] [] | + mysecretdiary | [] [] [] | + nano | [] [] [] [] [] [] | + nano_1_0 | [] [] [] [] [] | + opcodes | [] [] [] [] | + parted | [] [] [] [] | + pilot-qof | | + psmisc | [] [] [] | + pwdutils | | + python | | + qof | [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] | + sed | [] [] [] [] [] | + sh-utils | [] [] [] [] [] [] [] | + shared-mime-info | [] [] [] [] [] [] | + sharutils | [] [] [] [] [] [] [] [] | + shishi | | + silky | [] | + skencil | [] [] | + sketch | [] [] | + solfege | [] | + soundtracker | [] [] [] | + sp | [] | + stardict | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] [] [] | + texinfo | [] [] | + textutils | [] [] [] [] [] | + tin | [] () | + tp-robot | [] [] [] [] | + tuxpaint | [] [] | + unicode-han-tra... | | + unicode-transla... | [] [] | + util-linux | [] [] [] [] [] [] [] | + vorbis-tools | [] [] | + wastesedge | () | + wdiff | [] [] [] [] [] [] [] [] | + wget | [] [] [] [] [] [] [] [] | + xchat | [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] | + xpad | [] [] [] | + +--------------------------------------------------+ + es et eu fa fi fr ga gl gu he hi hr hu id is it + 88 22 14 2 40 115 61 14 1 8 1 6 59 31 0 52 + + ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no + +-------------------------------------------------+ + GNUnet | | + a2ps | () [] [] () | + aegis | () | + ant-phone | [] | + anubis | [] [] [] | + ap-utils | [] | + aspell | [] [] | + bash | [] | + batchelor | [] [] | + bfd | | + bibshelf | [] | + binutils | | + bison | [] [] [] | + bison-runtime | [] [] [] | + bluez-pin | [] [] [] | + cflow | | + clisp | [] | + console-tools | | + coreutils | [] | + cpio | | + cpplib | [] | + cryptonit | [] | + darkstat | [] [] | + dialog | [] [] | + diffutils | [] [] [] | + doodle | | + e2fsprogs | [] | + enscript | [] | + error | [] | + fetchmail | [] [] | + fileutils | [] [] | + findutils | [] | + flex | [] [] | + fslint | [] [] | + gas | | + gawk | [] [] | + gbiff | [] | + gcal | | + gcc | | + gettext-examples | [] [] | + gettext-runtime | [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] | + gip | [] [] | + gliv | [] | + glunarclock | [] [] | + gmult | [] [] | + gnubiff | | + gnucash | () () | + gnucash-glossary | [] | + gnuedu | | + gnulib | [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] | + gpe-beam | [] | + gpe-calendar | [] | + gpe-clock | [] [] [] | + gpe-conf | [] [] | + gpe-contacts | [] | + gpe-edit | [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] | + gpe-taskmanager | [] [] [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | [] | + gphoto2 | [] [] | + gprof | | + gpsdrive | () () () | + gramadoir | () | + grep | [] [] [] [] | + gretl | | + gsasl | [] | + gss | | + gst-plugins | [] | + gst-plugins-base | | + gst-plugins-good | [] | + gstreamer | [] | + gtick | | + gtkam | [] | + gtkorphan | [] | + gtkspell | [] [] | + gutenprint | | + hello | [] [] [] [] [] [] | + id-utils | [] | + impost | | + indent | [] [] | + iso_3166 | [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] | + iso_639 | [] [] | + jpilot | () () () | + jtag | | + jwhois | [] | + kbd | [] | + keytouch | [] | + keytouch-editor | | + keytouch-keyboa... | | + latrine | [] | + ld | | + leafpad | [] [] | + libc | [] [] [] [] [] | + libexif | | + libextractor | | + libgpewidget | [] | + libgpg-error | | + libgphoto2 | [] | + libgphoto2_port | [] | + libgsasl | [] | + libiconv | | + libidn | [] [] | + lifelines | [] | + lilypond | | + lingoteach | [] | + lynx | [] [] | + m4 | [] [] | + mailutils | | + make | [] [] [] | + man-db | () | + minicom | [] | + mysecretdiary | [] | + nano | [] [] [] | + nano_1_0 | [] [] [] | + opcodes | [] | + parted | [] [] | + pilot-qof | | + psmisc | [] [] [] | + pwdutils | | + python | | + qof | | + radius | | + recode | [] | + rpm | [] [] | + screem | [] | + scrollkeeper | [] [] [] [] | + sed | [] [] | + sh-utils | [] [] | + shared-mime-info | [] [] [] [] [] | + sharutils | [] [] | + shishi | | + silky | [] | + skencil | | + sketch | | + solfege | | + soundtracker | | + sp | () | + stardict | [] [] | + system-tools-ba... | [] [] [] [] | + tar | [] [] [] | + texinfo | [] [] [] | + textutils | [] [] [] | + tin | | + tp-robot | [] | + tuxpaint | [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] | + vorbis-tools | [] | + wastesedge | [] | + wdiff | [] [] | + wget | [] [] | + xchat | [] [] [] [] | + xkeyboard-config | [] | + xpad | [] [] [] | + +-------------------------------------------------+ + ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no + 52 24 2 2 1 3 0 2 3 21 0 15 1 97 5 1 + + nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + +------------------------------------------------------+ + GNUnet | | + a2ps | () [] [] [] [] [] [] | + aegis | () () | + ant-phone | [] [] | + anubis | [] [] [] | + ap-utils | () | + aspell | [] [] | + bash | [] [] [] | + batchelor | [] [] | + bfd | | + bibshelf | [] | + binutils | [] [] | + bison | [] [] [] [] [] | + bison-runtime | [] [] [] [] | + bluez-pin | [] [] [] [] [] [] [] [] [] | + cflow | [] | + clisp | [] | + console-tools | [] | + coreutils | [] [] [] [] | + cpio | [] [] [] | + cpplib | [] | + cryptonit | [] [] | + darkstat | [] [] [] [] [] [] | + dialog | [] [] [] [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] [] | + error | [] [] [] [] | + fetchmail | [] [] [] | + fileutils | [] [] [] [] [] | + findutils | [] [] [] [] [] [] | + flex | [] [] [] [] [] | + fslint | [] [] [] [] | + gas | | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] [] [] | + gimp-print | [] [] | + gip | [] [] [] [] | + gliv | [] [] [] [] | + glunarclock | [] [] [] [] [] [] | + gmult | [] [] [] [] | + gnubiff | () | + gnucash | () [] | + gnucash-glossary | [] [] [] | + gnuedu | | + gnulib | [] [] [] [] [] | + gnunet-gtk | [] | + gnutls | [] [] | + gpe-aerial | [] [] [] [] [] [] [] | + gpe-beam | [] [] [] [] [] [] [] | + gpe-calendar | [] | + gpe-clock | [] [] [] [] [] [] [] [] | + gpe-conf | [] [] [] [] [] [] [] | + gpe-contacts | [] [] [] [] [] | + gpe-edit | [] [] [] [] [] [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] [] [] [] | + gpe-login | [] [] [] [] [] [] [] [] | + gpe-ownerinfo | [] [] [] [] [] [] [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] [] [] [] [] [] [] | + gpe-su | [] [] [] [] [] [] [] [] | + gpe-taskmanager | [] [] [] [] [] [] [] [] | + gpe-timesheet | [] [] [] [] [] [] [] [] | + gpe-today | [] [] [] [] [] [] [] [] | + gpe-todo | [] [] [] [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] | + gpsdrive | [] [] [] | + gramadoir | [] [] | + grep | [] [] [] [] [] [] [] [] | + gretl | [] | + gsasl | [] [] [] | + gss | [] [] [] | + gst-plugins | [] [] [] [] | + gst-plugins-base | [] | + gst-plugins-good | [] [] [] [] | + gstreamer | [] [] [] | + gtick | [] | + gtkam | [] [] [] [] | + gtkorphan | [] | + gtkspell | [] [] [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] | + impost | [] | + indent | [] [] [] [] [] [] | + iso_3166 | [] [] [] [] [] [] | + iso_3166_2 | | + iso_4217 | [] [] [] [] | + iso_639 | [] [] [] [] | + jpilot | | + jtag | [] | + jwhois | [] [] [] [] | + kbd | [] [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | [] [] | + ld | [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] [] | + libgpewidget | [] [] [] [] [] [] [] | + libgpg-error | [] [] | + libgphoto2 | [] | + libgphoto2_port | [] [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] | + libidn | [] [] () | + lifelines | [] [] | + lilypond | | + lingoteach | [] | + lynx | [] [] [] | + m4 | [] [] [] [] [] | + mailutils | [] [] [] [] | + make | [] [] [] [] | + man-db | [] [] | + minicom | [] [] [] [] [] | + mysecretdiary | [] [] [] [] | + nano | [] [] [] | + nano_1_0 | [] [] [] [] | + opcodes | [] [] | + parted | [] | + pilot-qof | [] | + psmisc | [] [] | + pwdutils | [] [] | + python | | + qof | [] [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] | + rpm | [] [] [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] | + sed | [] [] [] [] [] [] [] [] [] | + sh-utils | [] [] [] | + shared-mime-info | [] [] [] [] [] | + sharutils | [] [] [] [] | + shishi | [] | + silky | [] | + skencil | [] [] [] | + sketch | [] [] [] | + solfege | [] | + soundtracker | [] [] | + sp | | + stardict | [] [] [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] | + texinfo | [] [] [] [] | + textutils | [] [] [] | + tin | () | + tp-robot | [] | + tuxpaint | [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + vorbis-tools | [] [] | + wastesedge | | + wdiff | [] [] [] [] [] [] | + wget | [] [] [] [] | + xchat | [] [] [] [] [] [] [] | + xkeyboard-config | [] [] | + xpad | [] [] [] | + +------------------------------------------------------+ + nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + 0 2 3 58 30 54 5 73 72 4 40 46 11 50 128 2 + + tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + +---------------------------------------------------+ + GNUnet | [] | 2 + a2ps | [] [] [] | 19 + aegis | | 0 + ant-phone | [] [] | 6 + anubis | [] [] [] | 11 + ap-utils | () [] | 4 + aspell | [] [] [] | 15 + bash | [] | 11 + batchelor | [] [] | 9 + bfd | | 1 + bibshelf | [] | 7 + binutils | [] [] [] | 9 + bison | [] [] [] | 19 + bison-runtime | [] [] [] | 15 + bluez-pin | [] [] [] [] [] [] | 28 + cflow | [] [] | 5 + clisp | | 6 + console-tools | [] [] | 5 + coreutils | [] [] | 16 + cpio | [] [] [] | 9 + cpplib | [] [] [] [] | 11 + cryptonit | | 5 + darkstat | [] () () | 15 + dialog | [] [] [] [] [] | 30 + diffutils | [] [] [] [] | 28 + doodle | [] | 6 + e2fsprogs | [] [] | 10 + enscript | [] [] [] | 16 + error | [] [] [] [] | 18 + fetchmail | [] [] | 12 + fileutils | [] [] [] | 18 + findutils | [] [] [] | 17 + flex | [] [] | 15 + fslint | [] | 9 + gas | [] | 3 + gawk | [] [] | 15 + gbiff | [] | 5 + gcal | [] | 5 + gcc | [] [] [] | 6 + gettext-examples | [] [] [] [] [] [] | 27 + gettext-runtime | [] [] [] [] [] [] | 28 + gettext-tools | [] [] [] [] [] | 19 + gimp-print | [] [] | 12 + gip | [] [] | 12 + gliv | [] [] | 8 + glunarclock | [] [] [] | 15 + gmult | [] [] [] [] | 15 + gnubiff | [] | 1 + gnucash | () | 2 + gnucash-glossary | [] [] | 9 + gnuedu | [] | 2 + gnulib | [] [] [] [] [] | 28 + gnunet-gtk | | 1 + gnutls | | 2 + gpe-aerial | [] [] | 14 + gpe-beam | [] [] | 14 + gpe-calendar | [] | 3 + gpe-clock | [] [] [] [] | 21 + gpe-conf | [] [] | 14 + gpe-contacts | [] [] | 10 + gpe-edit | [] [] [] [] | 20 + gpe-filemanager | [] | 6 + gpe-go | [] [] | 15 + gpe-login | [] [] [] [] [] | 21 + gpe-ownerinfo | [] [] [] [] | 21 + gpe-package | [] | 6 + gpe-sketchbook | [] [] | 16 + gpe-su | [] [] [] | 20 + gpe-taskmanager | [] [] [] | 20 + gpe-timesheet | [] [] [] [] | 18 + gpe-today | [] [] [] [] [] | 21 + gpe-todo | [] | 7 + gphoto2 | [] [] [] [] | 20 + gprof | [] [] | 11 + gpsdrive | | 4 + gramadoir | [] | 7 + grep | [] [] [] [] | 34 + gretl | | 4 + gsasl | [] [] | 8 + gss | [] | 5 + gst-plugins | [] [] [] | 15 + gst-plugins-base | [] [] [] | 9 + gst-plugins-good | [] [] [] [] [] | 20 + gstreamer | [] [] [] | 17 + gtick | [] | 3 + gtkam | [] | 13 + gtkorphan | [] | 7 + gtkspell | [] [] [] [] [] [] | 26 + gutenprint | | 3 + hello | [] [] [] [] [] | 37 + id-utils | [] [] | 14 + impost | [] | 4 + indent | [] [] [] [] | 25 + iso_3166 | [] [] [] [] | 16 + iso_3166_2 | | 2 + iso_4217 | [] [] | 14 + iso_639 | [] | 14 + jpilot | [] [] [] [] | 7 + jtag | [] | 3 + jwhois | [] [] [] | 13 + kbd | [] [] | 12 + keytouch | [] | 4 + keytouch-editor | | 2 + keytouch-keyboa... | [] | 3 + latrine | [] [] | 8 + ld | [] [] [] [] | 8 + leafpad | [] [] [] [] | 23 + libc | [] [] [] | 23 + libexif | [] | 4 + libextractor | [] | 5 + libgpewidget | [] [] [] | 19 + libgpg-error | [] | 4 + libgphoto2 | [] | 8 + libgphoto2_port | [] [] [] | 11 + libgsasl | [] | 8 + libiconv | [] | 7 + libidn | [] [] | 10 + lifelines | | 4 + lilypond | | 2 + lingoteach | [] | 6 + lynx | [] [] [] | 15 + m4 | [] [] [] | 18 + mailutils | [] | 8 + make | [] [] [] | 20 + man-db | [] | 6 + minicom | [] | 14 + mysecretdiary | [] [] | 12 + nano | [] [] | 17 + nano_1_0 | [] [] [] | 18 + opcodes | [] [] | 10 + parted | [] [] [] | 10 + pilot-qof | [] | 3 + psmisc | [] | 10 + pwdutils | [] | 3 + python | | 0 + qof | [] | 4 + radius | [] | 6 + recode | [] [] [] | 25 + rpm | [] [] [] [] | 14 + screem | [] | 2 + scrollkeeper | [] [] [] [] | 26 + sed | [] [] [] | 22 + sh-utils | [] | 15 + shared-mime-info | [] [] [] [] | 24 + sharutils | [] [] [] | 23 + shishi | | 1 + silky | [] | 4 + skencil | [] | 7 + sketch | | 6 + solfege | | 2 + soundtracker | [] [] | 9 + sp | [] | 3 + stardict | [] [] [] [] | 11 + system-tools-ba... | [] [] [] [] [] [] [] | 37 + tar | [] [] [] [] | 20 + texinfo | [] [] [] | 15 + textutils | [] [] [] | 17 + tin | | 1 + tp-robot | [] [] [] | 10 + tuxpaint | [] [] [] | 16 + unicode-han-tra... | | 0 + unicode-transla... | | 2 + util-linux | [] [] [] | 20 + vorbis-tools | [] [] | 11 + wastesedge | | 1 + wdiff | [] [] | 22 + wget | [] [] [] | 19 + xchat | [] [] [] [] | 29 + xkeyboard-config | [] [] [] [] | 11 + xpad | [] [] [] | 14 + +---------------------------------------------------+ + 77 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + 170 domains 0 1 1 77 39 0 136 10 1 48 5 54 0 2028 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and +distributed as such by its maintainer. There might be an observable +lag between the mere existence a PO file and its wide availability in a +distribution. + + If October 2006 seems to be old, you may fetch a more recent copy of +this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date +matrix with full percentage details can be found at +`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. + +1.6 Using `gettext' in new packages +=================================== + +If you are writing a freely available program and want to +internationalize it you are welcome to use GNU `gettext' in your +package. Of course you have to respect the GNU Library General Public +License which covers the use of the GNU `gettext' library. This means +in particular that even non-free programs can use `libintl' as a shared +library, whereas only free software can use `libintl' as a static +library or use modified versions of `libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of `gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +`translation@iro.umontreal.ca' to make the `.pot' files available to +the translation teams. + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5850e46 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Authors of psensor. + +wpitchoune@gmail.com all files. +linux.dabao@gmail.com po/zh_CN.po \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..c5611e4 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..7d1c323 --- /dev/null +++ b/INSTALL @@ -0,0 +1,365 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..b60ef2a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS = po src pixmaps/scalable pixmaps/48x48 www tests +dist_doc_DATA = README COPYING NEWS AUTHORS INSTALL + +desktopdir = $(datadir)/applications +desktop_DATA = psensor.desktop + +EXTRA_DIST = $(desktop_DATA) + + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..4cdefcd --- /dev/null +++ b/NEWS @@ -0,0 +1,248 @@ +* v0.6.2.8 + +** psensor: escaped - in manpage +** psensor-server: escaped - in manpage +** psensor: add support of libnotify 0.7 + +* v0.6.2.7 + +** psensor: src/glade/psensor-pref.glade, added button separator. +** psensor: src/glade/sensor-edit.glade, fixed horiz/vert padding. +** psensor: src/lib/measure.c, initialize time. +** psensor: fixed freeze when click on preferences appindicator with + natty. + +* v0.6.2.6 + +** psensor: fixed min temp/fan of the graph +** psensor: very minor optimization (graph.c) + +* v0.6.2.5 + +** psensor: dialog box for editing psensor preferences is using Glade +** psensor: dialog box for editing sensor preferences is using Glade +** psensor: added support of negative temperatures (lm-sensors) + +* v0.6.2.4 + +** psensor, graph: fixed padding bugs +** psensor, graph: drawing code refactored +** psensor: the value of the first detected sensor is displayed in the +unity launcher entry of psensor (requires unity >=3.4.2). + +* v0.6.2.3 + +** psensor-server: new global variable 'psensor_version' for lua template +** psensor-server: /index.html replaced by /index.lua +** avoid useless lib linkage by using --as-needed + +* v0.6.2.2 + +** psensor-server: web server support binary files +** psensor-server: added favicon.ico +** psensor-server: moved index.lua to monitor.lua +** psensor-server: added index.html (welcome page) + +* v0.6.2.1 + +** added uptime/memory information (psensor-server web) +** added debug mode for psensor-server (--debug) +** when used in debug mode, psensor-server can be stopped remotely + using http://hostname:port/api/1.0/server/stop +** fixed memory leak (label of lmsensor) +** some code cleanup/refactoring + +* v0.6.1.7 + +** psensor: add support of libnotify 0.7 + +* v0.6.1.6 + +** psensor: escaped - in manpage +** psensor-server: escaped - in manpage + +* v0.6.1.5 + +** added multi-language for hdd.c/nvidia.c/lmsensor.c +** some code cleanup/refactoring + +* v0.6.1.4 + +** fixed manpage formatting in 'REPORTING BUGS' section +** improved manpages +** removed few useless translations (fr/zh_CN) +** improved error messages for remote sensors + multilanguages support + +* v0.6.1.3 + +** fixed compilation error of psensor when libcurl is present but not + libjson0 +** suppress pointer to Textinfo manual (psensor/psensor-server). +** added --name to help2man call (psensor/psensor-server manpages). +** added more information in the psensor/psensor-server manpages. +** added warning about psensor-server and security in README. + +* v0.6.1.1 + +** application icon is loaded using GtkIconTheme +** appindicator icon is now the psensor one +** added appindicator icon for status 'attention' + +* v0.6.1 + +** added style.css for psensor-server +** use some styling in index.lua +** fixed typo in README +** fixed psensor-server short option -p +** multi-language support for psensor-server +** added some translation for French language0 +** fixed psensor-server bug: first sensor was not displayed + +* v0.6.0.14 + +** psensor (gtk client): + +*** added global preference: graph update interval +*** added global preference: graph monitoring duration +*** added global preference: sensor update interval +*** standard gnu command line interface for psensor +*** new psensor options: --help, --version, --url +*** added generation and installation of the psensor man +*** added remote monitoring it requires a new optionnal dependencies + (libjson0 and libcurl) +*** added internationnalization support for the UI +*** added Simplified Chinese Language (from DaBao ) + +** psensor-server: + +*** psensor-server is now a minimal webserver based on microhttpd. + Lua5.1 is used to generate HTML pages to display temperatures and + gtop2 information +*** temperature information can be retrieved using a webservice based + on json +*** added cpu information (requires optional libgtop-2.0) +*** psensor-server +*** psensor-server options: --port, --help, --version +*** added generation and installation of the psensor-server man + +** common news for psensor and psensor-server: + +*** moved to autoconf/automake +*** gnu standard: use NEWS instead of CHANGES file +*** moved LICENSE to COPYING + +* v0.5.1 + +** Makefile: avoid debug compilation by default +** Makefile: fixed duplicate server.o in OBJS_SERVER +** moved LICENSE to copyright +** moved CHANGES to NEWS +** Fixed creation of directories for the target 'install' + +* v0.5.0 + +** Added double buffering of the graph to avoid flickering +** Fixed README error gconf package name +** Refactoring makefile +** Added desktop notification support +** Added application indicator support +** Fixed MT issue (UI freeze, refresh_thread) +** Added global preferences editor (right click on the graph) +** Added sensor preferences editor (right click on the sensor table) +** Displayed name of each sensor can be changed +** Position of the sensor table can be changed +** Window decoration can be hidden +** Added 'keep window below' setting + +* v0.4.5 + +** Makefile: fixed duplicate server.o in OBJS_SERVER + +v0.4.4 +Added README.debian + +v0.4.3 +Fixed foreground graph color first time psensor is started +Added support of gtk 2.12 (used by Debian 5.0.6 Lenny) by redefining +gtk_dialog_get_content_area which exist since 2.14 + +v0.4.2 +Fixed potential MT issue (refresh_thread) +Added double buffering of the graph to avoid flickering +Fixed minor graph code bugs + +v0.4.1 +Fixed README error gconf package name +Refactoring makefile + +v0.4.0 +Added FAN support +Added HDD support (using hddtemp daemon) +Added popup menu for changing graph bg/fg colors and opacity +Graph background can be transparent, opacity can be changed +Fixed BR3: sensors with the same name but different chips share the same color configuration +Fixed BR4: wrong OBJS variable and gconf when calling pkg-config in Makefile.distrib for compiling with NVidia support +Changed website URL +Fixed BR5: Psensor crashes during startup with "You forgot to call g_type_init()" + +v0.3.3 +Fixed potential MT issue (refresh_thread) +Improved Makefile + +v0.3.2 +Fixed BR4: wrong OBJS variable and gconf when calling pkg-config in Makefile.distrib for compiling with NVidia support +Changed website URL +Fixed BR5: Psensor crashes during startup with "You forgot to call g_type_init()" + +v0.3.1 +Fixed BR3: sensors with the same name but different chips share the same color configuration + +v0.3.0 +Sensor graph colors can be changed: click on the colored sensor cell in the information table) +Background color of the graph can be changed: click on the graph +Configuration is stored using GConf +Fixed not initialized memory bug (min/max) in nvidia support + +v0.2.7 +Updated the website URL +Added contact information in the README +Backported Makefile improvement from trunk +Removed pwiki styling of the README +Backport: Fixed not initialized memory bug (min/max) in nvidia support + + +v0.2.6 +Changed default graph colors and background +Added vertical padding for the graph canvas +Disabled row selection of the sensor table +Fixed BR2: nvidia gpu is always using black color + +v0.2.5 +Added a basic server to retrieve remotely temperatures + +v0.2.4 +Added application icon +Added .desktop file + +v0.2.3 +Added max and min temperature information for each sensor +Fixed a missing #include in nvidia.c +Small UI improvements (scrollbar for the right panel + slider) + +v0.2.2 +Fixed compilation warning when NVidia support is disabled +Fixed BR1: crash when no temperature sensor is available + +v0.2.1 +Compilation dependance to Nvidia lib is optional + +v0.2.0 +Added support of NVidia GPUs + +v0.1.1 +Improved right panel (list of sensors) + ability to disable each sensor graph + +v0.1.0 +Initial release + + diff --git a/README b/README new file mode 100644 index 0000000..9f2cf4c --- /dev/null +++ b/README @@ -0,0 +1,113 @@ +Psensor - Temperature Monitoring For Linux +------------------------------------------ + +Psensor is a graphical temperature monitor for Linux. + +It can monitor: + + * the temperature of the motherboard and CPU sensors (using + lm-sensors). + * the temperature of the NVidia GPUs (using XNVCtrl). + * the temperature of the Hard Disk Drives (using hddtemp). + * the rotation speed of the fans (using lm-sensors). + * the temperature of a remote computer. + +Alarms using Desktop Notification can be set to each sensor to notify +high temperatures. + +For Ubuntu users, Psensor is providing an Application Indicator to +alert users when a temperature is too high. + +To monitor the temperature of a remote computer: + + * start psensor-server on the remote computer. The default port is + 3131 and can be changed by using the '--port=PORT' command line + option. + + * start psensor with the '--url' option: + psensor --url=http://hostname:3131 + +WARNING: +psensor-server does not provide any way to restrict the connection to +the HTTP server, worst, no effort has been made against malicious HTTP +attacks. You should make the psensor-server port available only to a +network or computer you trust by using the usual network security +tools of the system (for example, iptables). + + +Installation +------------ + +Ubuntu +------ + +For Ubuntu, the easy way to install Psensor and Psensor-server is to +use the dedicated PPA. + +For the last stable version: +sudo apt-get apt-add-repository ppa:/jfi/psensor +sudo apt-get update +sudo apt-get install psensor + +For the last development version: +sudo apt-get apt-add-repository ppa:/jfi/psensor-unstable +sudo apt-get update +sudo apt-get install psensor +sudo apt-get install psensor-server + +Alternatively, you can download Ubuntu binary packages from: +http://wpitchoune.net/psensor/files/ubuntu/ +The manual installation of the psensor and psensor-server packages +requires also the installation of psensor-common which contains +the multiple languages support. + +Installation from source archive +-------------------------------- + +Psensor compilation requires: + + * make/gcc + * lm-sensors + * library sensors4 + * library gtk2 + * library gconf2 + * help2man + * library libnotify (optional) + * library libappindicator (optional) + * library libXNVCtrl (optional) + * library json0 and curl (optional, required for remote monitoring) + * library unity (>=v3.4.2, optional) + +Psensor-server compilation requires: + * make/gcc + * lm-sensors + * library sensors4 + * help2man + * library libmicrohttpd + * library json0 + * library LUA5.1 (optional, required to enable HTML page generation + of the psensor-server webserver) + * library gtop2 (optional, required for CPU usage) + +Compilation and Installation Steps +---------------------------------- + + * Extract files from the source archive + * Compilation: + ./configure + make clean all + + * Installation: + make install + + * Start the sensor detection script: 'sensors-detect' and follows the +instructions + + * Verify the sensor detection by running: 'sensors' + + * Run 'psensor' + +Contact +------- +Bugs and comments can be sent to wpitchoune@gmail.com +Home page: http://wpitchoune.net/psensor \ No newline at end of file diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..17410da --- /dev/null +++ b/configure.ac @@ -0,0 +1,221 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.64]) +AC_INIT([psensor], [0.6.2.8],[wpitchoune@gmail.com],[psensor],[http://wpitchoune.net/psensor]) + +AM_INIT_AUTOMAKE([-Wall -Werror gnu]) + +AC_CONFIG_SRCDIR([src/compat.h]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_C_O + +# Checks lib build +AC_PROG_RANLIB + +# Checks for header files. +AC_PATH_X +AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h getopt.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([gettimeofday memmove socket strdup strtol]) + +AM_GNU_GETTEXT_VERSION([0.16]) +AM_GNU_GETTEXT([external]) + +############### common + +# Checks sensors, required by psensor and psensor-server +AC_CHECK_LIB(sensors, sensors_init) +AC_CHECK_HEADERS([sensors/sensors.h sensors/errors.h]) +SENSORS_LIBS=-lsensors +AC_SUBST(SENSORS_LIBS) + +############### psensor + +### Required + +PKG_CHECK_MODULES(X11, x11) +AC_SUBST(X11_CFLAGS) +AC_SUBST(X11_LIBS) + +PKG_CHECK_MODULES(XEXT, xext) +AC_SUBST(XEXT_CFLAGS) +AC_SUBST(XEXT_LIBS) + +# Checks GTK +PKG_CHECK_MODULES(GTK, gtk+-2.0 ) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) + +# Check GCONF +PKG_CHECK_MODULES(GCONF, gconf-2.0) +AC_SUBST(GCONF_CFLAGS) +AC_SUBST(GCONF_LIBS) + +### Optional + +# Check libnotify +LIBNOTIFY_LIBS= +PKG_CHECK_MODULES(LIBNOTIFY, + libnotify, + [AC_DEFINE([HAVE_LIBNOTIFY],[1],[Use desktop notification])], + [AC_MSG_WARN("Desktop notification disabled")]) +AM_CONDITIONAL(LIBNOTIFY, test -n "$LIBNOTIFY_LIBS") +AC_SUBST(LIBNOTIFY_CFLAGS) +AC_SUBST(LIBNOTIFY_LIBS) + +# Checks AppIndicator +APPINDICATOR_LIBS= +PKG_CHECK_MODULES(APPINDICATOR, + appindicator-0.1 = 0.2.9 , + [AC_DEFINE([HAVE_APPINDICATOR],[1],[Use AppIndicator 0.2.9]) + AC_DEFINE([HAVE_APPINDICATOR_029],[1],[Use AppIndicator 0.2.9]) + ], + [AC_MSG_WARN(AppIndicator 0.2.9 not present")]) + +if test "$APPINDICATOR_LIBS" == ""; then + PKG_CHECK_MODULES(APPINDICATOR, + appindicator-0.1 > 0.2.9, + [AC_DEFINE([HAVE_APPINDICATOR],[1],[Use AppIndicator > 0.2.9])], + [AC_MSG_WARN("AppIndicator > 0.2.9 not present")]) +fi +AM_CONDITIONAL(APPINDICATOR, test -n "$APPINDICATOR_LIBS") +AC_SUBST(APPINDICATOR_CFLAGS) +AC_SUBST(APPINDICATOR_LIBS) + +# Check CURL, needed for remote monitoring +CURL_LIBS= +PKG_CHECK_MODULES(CURL, + libcurl, + [AC_DEFINE([HAVE_CURL],[1],[Use CURL])], + [AC_MSG_WARN("Remote monitoring disabled, curl missing")]) +AM_CONDITIONAL(CURL, test -n "$CURL_LIBS") +AC_SUBST(CURL_CFLAGS) +AC_SUBST(CURL_LIBS) + +# Check JSON, needed for remote monitoring +JSON_LIBS= +PKG_CHECK_MODULES(JSON, + json, + [AC_DEFINE([HAVE_JSON],[1],[Use JSON])], + [AC_MSG_WARN("Remote monitoring disabled, json missing")]) +AM_CONDITIONAL(JSON, test -n "$JSON_LIBS") +AC_SUBST(JSON_CFLAGS) +AC_SUBST(JSON_LIBS) + +# Enables remote monitoring if JSON and CURL is present +if test -n "$JSON_LIBS"; then + if test -n "$CURL_LIBS"; then + AC_DEFINE([HAVE_REMOTE_SUPPORT],[1],[Remote monitoring enabled]) + fi +fi + +# Checks NVIDIA +# following code from sensors-applet +# sensors-applet.sourceforge.net/ +AC_CHECK_HEADERS(NVCtrl/NVCtrl.h NVCtrl/NVCtrlLib.h, + [ HAVE_NVIDIA=true ], [], + [ + #include + ]) +if test -n "${X11_LIBS}"; then +LIBS="${LIBS} -lX11 -lXext" + +if test "${HAVE_NVIDIA}" = "true"; then + AC_CHECK_LIB(XNVCtrl,XNVCTRLQueryExtension, + [NVIDIA_LIBS="-lXNVCtrl -lX11 -lXext" + AC_DEFINE(HAVE_NVIDIA,1,[NVidia support enabled]) + ]) +fi +fi +AM_CONDITIONAL(NVIDIA, test -n "$NVIDIA_LIBS") +AC_SUBST(NVIDIA_CFLAGS) +AC_SUBST(NVIDIA_LIBS) + +# Checks Unity +PKG_CHECK_MODULES(UNITY, + unity >= 3.4.2, + [AC_DEFINE([HAVE_UNITY],[1],[Use Unity])], + [AC_MSG_WARN(Unity not present)]) +AC_SUBST(UNITY_CFLAGS) +AC_SUBST(UNITY_LIBS) +AM_CONDITIONAL(UNITY, test -n "$UNITY_LIBS") + +############### psensor-server + +# Checks Lua 5.1 +LUA_LIBS= +PKG_CHECK_MODULES(LUA, + lua, + [AC_DEFINE([HAVE_LUA],[1],[Use Lua])], + [AC_MSG_WARN(Lua not present, checks Lua5.1)]) + +# Ubuntu pkg module is lua5.1 not lua +if test "$LUA_LIBS" == ""; then + PKG_CHECK_MODULES(LUA, + lua5.1, + [AC_DEFINE([HAVE_LUA],[1],[Use Lua5.1])], + [AC_MSG_WARN(Lua5.1 not present, psensor-server will NOT be built")]) +fi +AM_CONDITIONAL(LUA, test -n "$LUA_LIBS") +AC_SUBST(LUA_CFLAGS) +AC_SUBST(LUA_LIBS) + +# libmicrohttpd, mandatory for psensor-server +LIBMICROHTTPD_LIBS= +PKG_CHECK_MODULES(LIBMICROHTTPD, + libmicrohttpd, + [AC_DEFINE([HAVE_LIBMICROHTTPD],[1],[Use libmicrohttpd])], + [AC_MSG_WARN("libmicrohttpd not present, psensor-server will NOT be built")]) +AM_CONDITIONAL(LIBMICROHTTPD, test -n "$LIBMICROHTTPD_LIBS") +AC_SUBST(LIBMICROHTTPD_CFLAGS) +AC_SUBST(LIBMICROHTTPD_LIBS) + +# GTop, optional + +AC_ARG_WITH(gtop, +[ --with-gtop[=yes|no] use gtop],[ + with_gtop=$withval],[ + with_gtop="yes" +]) + +GTOP_LIBS= +if test "$with_gtop" = "yes"; then +PKG_CHECK_MODULES(GTOP, + libgtop-2.0, + [AC_DEFINE([HAVE_GTOP],[1],[Use GTOP])], + [AC_MSG_WARN("gtop not present, CPU/Memory information will NOT be available")]) +fi +AM_CONDITIONAL(GTOP, test -n "$GTOP_LIBS") +AC_SUBST(GTOP_CFLAGS) +AC_SUBST(GTOP_LIBS) + +AC_CONFIG_FILES([ + Makefile + src/Makefile + src/glade/Makefile + src/plib/Makefile + src/lib/Makefile + src/unity/Makefile + src/libpsensor_json/Makefile + src/server/Makefile + pixmaps/scalable/Makefile + pixmaps/48x48/Makefile + www/Makefile + po/Makefile.in + tests/Makefile +]) + +AC_CHECK_PROGS([HELP2MAN], [help2man]) + +AC_OUTPUT diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..4bca628 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,94 @@ +psensor (0.6.1.3-3) lucid; urgency=low + + * bump lucid + + -- Jean-Philippe Orsini Wed, 16 Feb 2011 10:13:55 +0100 + +psensor (0.6.1.3-2) natty; urgency=low + + * bump natty + + -- Jean-Philippe Orsini Wed, 16 Feb 2011 10:13:08 +0100 + +psensor (0.6.1.3-1) maverick; urgency=low + + * upgrade upstream + * removed debian/tmp in .install files + * improved long description of the packages + * fixed debian/copyright(add real name and license preamble) + * use dh_installman + * added debian/watch file + + -- Jean-Philippe Orsini Wed, 16 Feb 2011 09:56:05 +0100 + +psensor (0.6.1.1-3) lucid; urgency=low + + * bump lucid + + -- jeanfi Tue, 15 Feb 2011 12:10:08 +0100 + +psensor (0.6.1.1-2) natty; urgency=low + + * bump natty + + -- jeanfi Tue, 15 Feb 2011 12:09:19 +0100 + +psensor (0.6.1.1-1) maverick; urgency=low + + * upgrade upstream + + -- jeanfi Tue, 15 Feb 2011 11:41:38 +0100 + +psensor (0.6.1-4) natty; urgency=low + + * bump natty + + -- jeanfi Mon, 14 Feb 2011 12:18:28 +0100 + +psensor (0.6.1-3) lucid; urgency=low + + * bump lucid + + -- jeanfi Mon, 14 Feb 2011 12:17:37 +0100 + +psensor (0.6.1-2) maverick; urgency=low + + * fixed file conflicts concerning doc dir + + -- jeanfi Mon, 14 Feb 2011 11:47:16 +0100 + +psensor (0.6.1-1) maverick; urgency=low + + * upgrade upstream + + -- jeanfi Mon, 14 Feb 2011 10:52:24 +0100 + +psensor (0.6.0.14-5) karmic; urgency=low + + * bump karmic + + -- jeanfi Sun, 13 Feb 2011 14:05:07 +0100 + +psensor (0.6.0.14-4) maverick; urgency=low + + * www/index.lua in the psensor-server package + + -- jeanfi Sun, 13 Feb 2011 13:30:30 +0100 + +psensor (0.6.0.14-3) lucid; urgency=low + + * bump lucid + + -- jeanfi Sat, 12 Feb 2011 21:18:22 +0100 + +psensor (0.6.0.14-2) natty; urgency=low + + * bump natty + + -- jeanfi Sat, 12 Feb 2011 21:16:38 +0100 + +psensor (0.6.0.14-1) maverick; urgency=low + + * upgrade upstream + + -- jeanfi Sat, 12 Feb 2011 14:34:42 +0100 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..a670a4f --- /dev/null +++ b/debian/control @@ -0,0 +1,54 @@ +Source: psensor +Section: utils +Priority: optional +Maintainer: Jean-Philippe Orsini +Build-Depends: debhelper (>= 7.0.50~),libgtk2.0-dev,libgconf2-dev,libnotify-dev,libsensors4-dev,nvidia-settings,help2man,libcurl4-openssl-dev,libjson0-dev,liblua5.1-0-dev,libmicrohttpd-dev,libgtop2-dev,perl,libappindicator-dev +Standards-Version: 3.9.1 +Homepage: http://wpitchoune.net/psensor + +Package: psensor +Architecture: any +Depends: psensor-common (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends} +Recommends: hddtemp +Description: Display graphs for monitoring hardware temperature. + Psensor is a GTK application for monitoring hardware sensors, + including temperatures and fan speeds. + . + It displays a curve for each sensor, alerts user using Desktop Notification + and Application Indicator when a temperature is too high. + . + It can monitor: + * the temperature of the motherboard and CPU sensors (using lm-sensors). + * the temperature of the NVidia GPUs (using XNVCtrl). + * the temperature of the Hard Disk Drives (using hddtemp). + * the rotation speed of the fans (using lm-sensors). + * the sensors of a remote computer (using psensor-server). + . + +Package: psensor-server +Architecture: any +Depends: psensor-common (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends} +Recommends: hddtemp +Description: Psensor server for monitoring hardware sensors remotely. + . + Psensor server is an HTTP server providing a JSON Web service which can be + used by Psensor GTK Application to monitor remotely the hardware sensors + of a computer. + . + It can provide information about: + * the temperature of the motherboard and CPU sensors (using lm-sensors). + * the temperature of the NVidia GPUs (using XNVCtrl). + * the temperature of the Hard Disk Drives (using hddtemp). + * the rotation speed of the fans (using lm-sensors). + . + It is also possible to connect to Psensor server with a browser, a simple + Web page is displaying the information. + . + +Package: psensor-common +Architecture: all +Depends: ${misc:Depends} +Description: Common files for Psensor and Psensor server. + . + It contains languages packs for both Psensor and Psensor server. + . \ No newline at end of file diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7be00c5 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,32 @@ +This package was debianized by Jean-Philippe Orsini +Tue, 15 Feb 18:33:41 CET 2011. + +It was downloaded from: http://wpitchoune.net/psensor + +Upstream Author(s): Jean-Philippe Orsini + +Copyright: + Copyright (C) 2010-2011 by Jean-Philippe Orsini + +License: + + This package 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; version 2 dated June, 1991. + + This package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301, USA. + +On Debian/Ubuntu systems, the complete text of the GNU General Public +License can be found in `/usr/share/common-licenses/GPL-2'. + +Packaging: + Copyright (C) 2010-2011 by Jean-Philippe Orsini + released under GNU General Public License version 2. \ No newline at end of file diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..139597f --- /dev/null +++ b/debian/docs @@ -0,0 +1,2 @@ + + diff --git a/debian/psensor-common.install b/debian/psensor-common.install new file mode 100644 index 0000000..94125c7 --- /dev/null +++ b/debian/psensor-common.install @@ -0,0 +1 @@ +/usr/share/locale diff --git a/debian/psensor-server.install b/debian/psensor-server.install new file mode 100644 index 0000000..7bcc095 --- /dev/null +++ b/debian/psensor-server.install @@ -0,0 +1,3 @@ +/usr/bin/psensor-server +/usr/share/psensor/www/index.lua + diff --git a/debian/psensor-server.manpages b/debian/psensor-server.manpages new file mode 100644 index 0000000..4d121e6 --- /dev/null +++ b/debian/psensor-server.manpages @@ -0,0 +1 @@ +debian/tmp/usr/share/man/man1/psensor-server.1 \ No newline at end of file diff --git a/debian/psensor.install b/debian/psensor.install new file mode 100644 index 0000000..8f69a68 --- /dev/null +++ b/debian/psensor.install @@ -0,0 +1,8 @@ +/usr/bin/psensor +/usr/share/icons/hicolor/scalable/apps/psensor.svg +/usr/share/icons/hicolor/scalable/apps/psensor_hot.svg +/usr/share/icons/hicolor/48x48/apps/psensor.png +/usr/share/icons/hicolor/48x48/apps/psensor_hot.png +/usr/share/applications/psensor.desktop + + diff --git a/debian/psensor.manpages b/debian/psensor.manpages new file mode 100644 index 0000000..16e0814 --- /dev/null +++ b/debian/psensor.manpages @@ -0,0 +1,2 @@ +debian/tmp/usr/share/man/man1/psensor.1 + diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..b760bee --- /dev/null +++ b/debian/rules @@ -0,0 +1,13 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +%: + dh $@ diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..8833e44 --- /dev/null +++ b/debian/watch @@ -0,0 +1,3 @@ +version=3 + +http://wpitchoune.net/psensor/files/psensor-(\d.*)\.tar\.gz \ No newline at end of file diff --git a/pixmaps/16x16/psensor.png b/pixmaps/16x16/psensor.png new file mode 100644 index 0000000000000000000000000000000000000000..d06f18796f9a0a15f480be3a3cffd3b9359775ae GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ zFqeTaW9`+ZGeAMf64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<_&RXklB zLo9liPCV$<>LAg2ero-hUZ?W80nyuw91l&^UE(SozwqoH=l%=KJ2eEF#NL&Pa&S7j ztVo#{>z*6@u-EYAz0I?Y?eEX|d_GBnt){!UPLAautJ;**o667sRJ^(PW5MfRmrCz0 zUZfE)O;sX!#cQc$nTHH`1O$KchNkFqDqhfFd*yii^==0d*NFAkFNLU-GRE8!kh*oe zv#>w-cH62|mn<`zHtt&IJV|9TXBuOVp+(>3+NOQ)FPfZv@>j=!qtT-8|NbNM8I{(& zxtb?>$)r^v$+}^Y#s(d3mron4>mR@2Gx2SH|NAm$>a*gzi~c6rhkSZh&y=^BPxd84 z!|rbaYhS1{N{g;qb?UG|4?n}4%#-&{v(MNWvnMt_k)grn{Cu19w;5`f+P)MsS6Z=y PqJhEF)z4*}Q$iB}HxjEw literal 0 HcmV?d00001 diff --git a/pixmaps/22x22/psensor.png b/pixmaps/22x22/psensor.png new file mode 100644 index 0000000000000000000000000000000000000000..be45344fe8619eb2804628dbd2a078a31c49a6a7 GIT binary patch literal 511 zcmV)WYRY6GCt=^%svKv5LJ;qWiETrO`~ITX8zgb-+&hNfvu zCKKxQy8UA~5gV@`bngwi_Xftxghr!5u~@VfTUIfhKg}{4AE%x{}WF~ zN=dujcEq|80}KWOZ>pG%5Q20%O(K!7WnE7^9*-SyuEeHk(rh-VR;#wGt11*lAs&l+ zzZC$%V31HKN9lO;uHNUAJWy>exwKuUoBF^Zw2A`Fv!v zSx4-j6Pr@<{Pu%981sLdg~UhacMO)dzOQdYlG3I9M%aq?cSFSdUDnJe0_G!$m0R|b zsw1&w$CXOutkr4-0CoWUUkC4Sdh(kc4u_T>=ue7%e$NrUi>v?u002ovPDHLkV1hNe B-AVue literal 0 HcmV?d00001 diff --git a/pixmaps/24x24/psensor.png b/pixmaps/24x24/psensor.png new file mode 100644 index 0000000000000000000000000000000000000000..93f2d79ac8636a1be76972935e51932f31ea931a GIT binary patch literal 575 zcmV-F0>J%=P)K~zYIwUj}t5>Xh2pQARK$h|}&LZpIij9Lg%t|VyX&ZWCn z?S$G0{)2vm3&BN5tNuY~dl#;XL9iP*a4)rRMm#Vyr^T(QYa?f7m|i%GneRP3XWnnV zBa~7cYd9RfZnxY0e+nmLn&#)xX!IhemI-=UDwQ5|yWOV%uIpl1mR~argL1ii!=Fy4 zjZ^TH?sS%AQK?k?C8cDwT5&iWbX&s#j^%kCrfITVE|F4d{ecl3>&^QMtogQ>|9XX0zJ8kt2$#P+#!3lu|4f3jq54K7~RdS%46N zX0u77(IB7CYyGhz+U<6Do)^j+8K9J6yyH&tr_-TUt6>-?2iRAvh@_MR z-C>CVa=BcnA&Uk0{hLmw)Bo3ldc97o)zZ!Y#Ehs|EQV@uEPzsq`FzfJJjS+dtv_-^ zsZ@%=U=ZFP6%bWgfO+X+|M+v~Y@7o2!A%bE?$a4==FETIWvfg+Y?A}L>STC$`+_^_ zlCrRPa{h&v&+ml>1U7lI*?gQ#CjPPS|5^ZC!R+l#|8~1w_j?qY((v)$`^ z&Og2H-Rm=F+csWOKA+Er!{IM4PIyI{rkxZDg~GHs%hMi4B9Yx>GWm@apj<8!0PFzI z)$Mj+7{*v^G#WvcWq7?_dO{WeMN!6L!{HG1dL5D^As&xY1GuOi6GR9BA%w|Gl>q=a z{?mqTSWn}iz@b{L;&C%)G8u$Iq1gc(G%d95*Pq7Q?lXMd+k+^Ih(@Ed%Q;g5(==h4 zCX?3@003~g*p{L$!6emcHQ2U|N~JRUJupe>bQ*y`005{@gCiwqHk)WP8sK>z9LG_4 z9mzm27=$EAOkPI-dc7Vz9uJe(krJq?ic+bBTrP)pyG`YFBm;>=0)D?Au~>}SJNIwF zVsyfOzYks4p{gndg8`M-kv%{N0nhUQFrPl)cDo@6!u&2IZ_#1^%)Jq1vsuWp%;a5+ z61*G0(LWQqu@8)|)+m)-v$(Y7?WSm9eb%707*qoM6N<$f&wNI`~Uy| literal 0 HcmV?d00001 diff --git a/pixmaps/48x48/Makefile.am b/pixmaps/48x48/Makefile.am new file mode 100644 index 0000000..7d09bac --- /dev/null +++ b/pixmaps/48x48/Makefile.am @@ -0,0 +1,6 @@ +themedir = $(datadir)/icons/hicolor +size = 48x48 +context = apps +EXTRA_DIST = psensor.png psensor_hot.png +psensordistpixdir = $(themedir)/$(size)/$(context) +psensordistpix_DATA = $(EXTRA_DIST) diff --git a/pixmaps/48x48/psensor.png b/pixmaps/48x48/psensor.png new file mode 100644 index 0000000000000000000000000000000000000000..3acb429e049b9bfe1e0264afbebc497bf387b34d GIT binary patch literal 914 zcmV;D18w|?P)(^b8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10}n|=K~!jg?V7(&8etg6KPPbE5Rfz?YSl{`bRjVYt6`~QH{En; z*j?MHYo{i+B_;t119+D#vr}yTMP2n0u>pfnCL0}z(qc%>pnqBz8e31;FR?b#@v}CX>w1 z&tGX?(joS8>0uT;|NhA`t;w=RrpU<8dtsw%p! z0~e*WNJ(4N9~>M2Ff}zre}BI)Zz%wNzyJSBqpPc{L?RK}-gjxV9Tf_N&Q7Bahl4;M z(D*J=QUKg;H{;{uK!@&17>3cn)JN}624&ZM~2tciFQfqPCte7>7 zve;9Z%d!oyo&3SetzPzx>rY$G96nwo?z8$fZ8y}lvJJ4ZrBHF*e0Xnmxpv1q1;jF02C{KxA_))&BtF0zEhkeMuc?D6#Gol76LRsHddaAnd~2W}A_$0z?(AIGC?oSw7s`*|@UruFRHkESU@_D6kVq8$- zIK9w)#C7~+Nkc>`r)~C^lDiM8!|(sl@+-10vF&ALUS(u$Kz{zYI4h)uxz%~B-p#I~ zCkXQ!FQbAIra!uW=1UO0S(C3cCXT>aes`9h=AFa=GxS zHUG>Y>R=P!5+w(~kF56h_nQolREO3v9+RbsBJufw`0J{fp??6R-CyDHcvUGmw87T! zWOyw^3mH{Hik_K(sdo#GDRoH|qxYDE&oKr5_M4Dn^;f*wEmS&*Dy>Wq$5peli-0b1vu&hC(%Y{eNt91ei;GT0fvmUfW?*AksE#cyaxyY9td>6H zcj_6unmdhYh<039qRNbWgMkjI{zAX-Kj!#HPkiF*JxA@5iGqIq}R8{%eobB#tdOwq6B=yF> z)aX{F10O!wNKXeH7~iip#X^Wgw}2%!@lq93K{ZfeEbZSz^G}PWVJ3)8R%*AIXcYJb z4&R*Dr6(4T0L+IL+m$u+;tPK^hCDA$XjIA_xa3muIC6jJcL&Y@?s`{ZMDE}IMAt@X5v zKc3`nH9W%j@tsTe=;eGsMEKDZuq7V1cxUxC8k>FjBAZfGpf5|CzmK604`b+4bTmd- zyTQ!!g_pF8iaqJ;H~Wn4{ZF#A=df0ol9F<*Wo2cD&F(jIb93+r*R0~aeK5R}dA3v0 zrR%a6bf>_Yd@aHPI-Y|DBgx=w!Gy7WzVE5p6?o`$LuF`FQ`5aL!&BeNd)(i|&FZDMUn#hQU_f>` zMj$0DcN-Qe=;+uB9p0Bq`?ayLQNMPSSu@;M85#_L^)kUM9U((!FoUOtm@-G_)VOOD zj2YDa6jWu+FI!tX1G=97{yR8|h?u4`0O6D6d$&tmCv+OER(n{*jMLagqb{ccEONVg z_SUL>p->LtV$gw4H!t=N4i2Km>gC(oH%bG2qOShXx4#B4ul{}n;l4`)5Uu61g1vkn z37`-H6e)Y`A4C=HanJm>FStQI_aIx_+S+bN<4IrPNkmU){7w=cKT;e!{kH%f zpUH_o{Qm^^HNfmOScuo?Fgu~(3d>#vzDBuf4oMa9zjW6Wl z(gYmwAvQlXnS~Qcl5qkND_O)B;>5z#WG+s?N$151L^#o**reFFB-UTc(QLlh6;$}o S;C=!q2nG0r&>E;Q*?$6m& + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pixmaps/scalable/psensor_hot.svg b/pixmaps/scalable/psensor_hot.svg new file mode 100644 index 0000000..c4e9e60 --- /dev/null +++ b/pixmaps/scalable/psensor_hot.svg @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..12a5907 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,10 @@ +# Set of available languages. +# +# Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +# 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +fr +zh_CN diff --git a/po/Makefile.in.in b/po/Makefile.in.in new file mode 100644 index 0000000..5022b8b --- /dev/null +++ b/po/Makefile.in.in @@ -0,0 +1,403 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. +# +# Origin: gettext-0.16 + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +localedir = @localedir@ +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# We use $(mkdir_p). +# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as +# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, +# @install_sh@ does not start with $(SHELL), so we add it. +# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined +# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake +# versions, $(mkinstalldirs) and $(install_sh) are unused. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +mkdir_p = @mkdir_p@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in remove-potcdate.sin \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: all-@USE_NLS@ + +all-yes: stamp-po +all-no: + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test ! -f $(srcdir)/$(DOMAIN).pot || \ + test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) + @test ! -f $(srcdir)/$(DOMAIN).pot || { \ + echo "touch stamp-po" && \ + echo timestamp > stamp-poT && \ + mv stamp-poT stamp-po; \ + } + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +# This target rebuilds $(DOMAIN).pot; it is an expensive operation. +# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed + if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ + msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ + else \ + msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ + fi; \ + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + --msgid-bugs-address="$$msgid_bugs_address" + test ! -f $(DOMAIN).po || { \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ + sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ + if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ + else \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + else \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + } + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + if test -f "$(srcdir)/$${lang}.po"; then \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ + else \ + $(MAKE) $${lang}.po-create; \ + fi + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkdir_p) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkdir_p) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: stamp-po $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + dists="$$dists $(DOMAIN).pot stamp-po"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir) || exit 1; \ + else \ + cp -p $(srcdir)/$$file $(distdir) || exit 1; \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for creating PO files. + +.nop.po-create: + @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ + echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ + exit 1 + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ + cd $(top_builddir) \ + && $(SHELL) ./config.status $(subdir)/$@.in po-directories + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 0000000..32692ab --- /dev/null +++ b/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Free Software Foundation, Inc. + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..e04b4b2 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,12 @@ +src/main.c +src/ui_sensorlist.c +src/ui_appindicator.c +src/ui_color.c +src/ui_notify.c +src/ui_pref.c +src/rsensor.c +src/plib/plib_luatpl.c +src/server/server.c +src/lib/hdd.c +src/lib/nvidia.c +src/lib/lmsensor.c diff --git a/po/Rules-quot b/po/Rules-quot new file mode 100644 index 0000000..9c2a995 --- /dev/null +++ b/po/Rules-quot @@ -0,0 +1,47 @@ +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-create: + $(MAKE) en@quot.po-update +en@boldquot.po-create: + $(MAKE) en@boldquot.po-update + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/po/boldquot.sed b/po/boldquot.sed new file mode 100644 index 0000000..4b937aa --- /dev/null +++ b/po/boldquot.sed @@ -0,0 +1,10 @@ +s/"\([^"]*\)"/“\1”/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“”/""/g +s/“/“/g +s/”/”/g +s/‘/‘/g +s/’/’/g diff --git a/po/en@boldquot.header b/po/en@boldquot.header new file mode 100644 index 0000000..fedb6a0 --- /dev/null +++ b/po/en@boldquot.header @@ -0,0 +1,25 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# +# This catalog furthermore displays the text between the quotation marks in +# bold face, assuming the VT100/XTerm escape sequences. +# diff --git a/po/en@quot.header b/po/en@quot.header new file mode 100644 index 0000000..a9647fc --- /dev/null +++ b/po/en@quot.header @@ -0,0 +1,22 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..feeede7 --- /dev/null +++ b/po/fr.po @@ -0,0 +1,329 @@ +# Oriya translations for psensor package. +# Copyright (C) 2011 Free Software Foundation, Inc. +# This file is distributed under the same license as the psensor package. +# wpitchoune , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: psensor 0.6.0.9\n" +"Report-Msgid-Bugs-To: wpitchoune@gmail.com\n" +"POT-Creation-Date: 2011-04-03 18:46+0200\n" +"PO-Revision-Date: 2011-02-07 21:18+0100\n" +"Last-Translator: wpitchoune \n" +"Language-Team: Oriya\n" +"Language: or\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8-bit\n" + +#: src/main.c:73 src/server/server.c:80 +#, c-format +msgid "" +"Copyright (C) %s wpitchoune@gmail.com\n" +"License GPLv2: GNU GPL version 2 or later \n" +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n" +msgstr "" + +#: src/main.c:83 src/server/server.c:90 +#, c-format +msgid "Usage: %s [OPTION]...\n" +msgstr "" + +#: src/main.c:85 +msgid "" +"psensor is a GTK application for monitoring hardware sensors, including " +"temperatures and fan speeds." +msgstr "" + +#: src/main.c:89 +msgid "Options:" +msgstr "" + +#: src/main.c:90 src/server/server.c:97 +msgid "" +" -h, --help display this help and exit\n" +" -v, --version display version information and exit" +msgstr "" + +#: src/main.c:96 +msgid "" +" -u, --url=URL the URL of the psensor-server, example: http://" +"hostname:3131" +msgstr "" + +#: src/main.c:102 src/server/server.c:110 +#, c-format +msgid "Report bugs to: %s\n" +msgstr "" + +#: src/main.c:104 src/server/server.c:112 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "" + +#: src/main.c:327 src/server/server.c:376 +#, c-format +msgid "Try `%s --help' for more information.\n" +msgstr "" + +#: src/main.c:350 +#, fuzzy, c-format +msgid "ERROR: lmsensor init failure: %s\n" +msgstr "ERREUR: Echec de l'initialisation de 'lm-sensors'\n" + +#: src/main.c:361 +#, c-format +msgid "ERROR: Not compiled with remote sensor support.\n" +msgstr "" + +#: src/ui_sensorlist.c:285 +msgid "Preferences" +msgstr "" + +#: src/ui_sensorlist.c:318 +msgid "Select foreground color" +msgstr "" + +#: src/ui_sensorlist.c:401 +msgid "Sensor" +msgstr "Sonde" + +#: src/ui_sensorlist.c:407 +msgid "Current" +msgstr "Actuelle" + +#: src/ui_sensorlist.c:413 +msgid "Min" +msgstr "" + +#: src/ui_sensorlist.c:419 +msgid "Max" +msgstr "" + +#: src/ui_sensorlist.c:426 +msgid "Color" +msgstr "Couleur" + +#: src/ui_sensorlist.c:439 +msgid "Enabled" +msgstr "Activée" + +#: src/ui_sensorlist.c:468 src/ui_sensorlist.c:469 src/ui_sensorlist.c:470 +msgid "N/A" +msgstr "" + +#: src/ui_notify.c:36 +#, c-format +msgid "ERROR: failed gettimeofday\n" +msgstr "" + +#: src/ui_notify.c:64 +msgid "Temperature alert" +msgstr "" + +#: src/rsensor.c:131 +#, c-format +msgid "ERROR: Fail to connect to: %s\n" +msgstr "" + +#: src/rsensor.c:166 +#, c-format +msgid "ERROR: Invalid content: %s\n" +msgstr "" + +#: src/rsensor.c:204 +#, c-format +msgid "ERROR: Invalid JSON: %s\n" +msgstr "" + +#: src/plib/plib_luatpl.c:121 +#, c-format +msgid "LUATPL Error: failed to load Lua script: %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:127 +#, c-format +msgid "LUATPL Error: failed to call init function: %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:133 +#, c-format +msgid "LUATPL Error:failed to execute Lua script (%s): %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:140 +#, c-format +msgid "LUATPL Error:lua script (%s) returned a wrong type.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:147 +#, c-format +msgid "LUATPL Error:failed to open lua state.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:154 +#, c-format +msgid "LUATPL Error: code: %d.\n" +msgstr "" + +#: src/server/server.c:56 +msgid "" +"

Page not found - Go to Main page

" +msgstr "" + +#: src/server/server.c:92 +msgid "" +"psensor-server is an HTTP server for monitoring hardware sensors remotely." +msgstr "" + +#: src/server/server.c:103 +msgid "" +" -d,--debug run in debug mode\n" +" -p,--port=PORT webserver port\n" +" -w,--wdir=DIR directory containing webserver pages" +msgstr "" + +#: src/server/server.c:184 +msgid "

Server stop requested

" +msgstr "" + +#: src/server/server.c:315 +#, c-format +msgid "HTTP Request: %s\n" +msgstr "" + +#: src/server/server.c:382 +#, c-format +msgid "ERROR: failed to init lm-sensors\n" +msgstr "ERREUR: Echec de l'initialisation de 'lm-sensors'\n" + +#: src/server/server.c:389 +#, c-format +msgid "ERROR: no sensors detected\n" +msgstr "ERREUR: Aucune sonde detectee\n" + +#: src/server/server.c:396 +#, c-format +msgid "ERROR: Fail to create web server\n" +msgstr "ERREUR: Echec de la creation du serveur Web\n" + +#: src/server/server.c:400 +#, c-format +msgid "Web server started on port: %d\n" +msgstr "Server Web demarre sur le port: %d\n" + +#: src/server/server.c:401 +#, c-format +msgid "WWW directory: %s\n" +msgstr "WWW repertoire: %s\n" + +#: src/server/server.c:402 +#, c-format +msgid "URL: http://localhost:%d\n" +msgstr "" + +#: src/lib/hdd.c:59 +#, c-format +msgid "ERROR: hdd_fetch, failed to open socket\n" +msgstr "" + +#: src/lib/hdd.c:73 +#, c-format +msgid "ERROR: hdd_fetch, failed to open connection\n" +msgstr "" + +#: src/lib/hdd.c:182 +#, c-format +msgid "ERROR: wrong hdd string: %s" +msgstr "" + +#: src/lib/hdd.c:252 +#, c-format +msgid "ERROR: wrong hdd string: %s\n" +msgstr "" + +#: src/lib/nvidia.c:53 +#, c-format +msgid "ERROR: failed to retrieve nvidia temperature\n" +msgstr "" + +#: src/lib/nvidia.c:85 +#, c-format +msgid "ERROR: nvidia initialization failure\n" +msgstr "" + +#: src/lib/nvidia.c:99 +#, c-format +msgid "ERROR: nvidia initialization failure: %d\n" +msgstr "" + +#: src/lib/nvidia.c:132 +#, c-format +msgid "ERROR: no nvidia chips or initialization failure\n" +msgstr "" + +#: src/lib/lmsensor.c:43 +#, c-format +msgid "ERROR: Can't get value of subfeature %s: %s\n" +msgstr "" + +#: src/lib/lmsensor.c:122 +#, c-format +msgid "ERROR: create_sensor, wrong feature type\n" +msgstr "" + +#: src/lib/lmsensor.c:166 +#, c-format +msgid "ERROR: lm-sensors initialization failure: %s\n" +msgstr "" + +#~ msgid "Graph Colors" +#~ msgstr "Couleurs du graphe" + +#~ msgid "Background:" +#~ msgstr "Fond:" + +#~ msgid "Background opacity:" +#~ msgstr "Opacite du fond:" + +#~ msgid "Position of sensors table:" +#~ msgstr "Position de la table des sondes:" + +#~ msgid "Right" +#~ msgstr "Droite" + +#~ msgid "Left" +#~ msgstr "Gauche" + +#~ msgid "Top" +#~ msgstr "Haut" + +#~ msgid "Bottom" +#~ msgstr "Bas" + +#~ msgid "Name:" +#~ msgstr "Nom:" + +#~ msgid "Draw sensor curve" +#~ msgstr "Dessiner la courbe de la sonde" + +#, fuzzy +#~ msgid "Color:" +#~ msgstr "Couleur" + +#~ msgid "Alarm" +#~ msgstr "Alarme" + +#~ msgid "Activate desktop notifications" +#~ msgstr "Activer les notifications du bureau" + +#~ msgid "Show" +#~ msgstr "Montrer" + +#~ msgid "ERROR: Lua support not enabled\n" +#~ msgstr "ERREUR: Le support de Lua n'est pas active\n" + +#~ msgid "Psensor - Temperature Monitor" +#~ msgstr "Psensor - Surveillance Des Temperatures" diff --git a/po/insert-header.sin b/po/insert-header.sin new file mode 100644 index 0000000..b26de01 --- /dev/null +++ b/po/insert-header.sin @@ -0,0 +1,23 @@ +# Sed script that inserts the file called HEADER before the header entry. +# +# At each occurrence of a line starting with "msgid ", we execute the following +# commands. At the first occurrence, insert the file. At the following +# occurrences, do nothing. The distinction between the first and the following +# occurrences is achieved by looking at the hold space. +/^msgid /{ +x +# Test if the hold space is empty. +s/m/m/ +ta +# Yes it was empty. First occurrence. Read the file. +r HEADER +# Output the file's contents by reading the next line. But don't lose the +# current line while doing this. +g +N +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/po/psensor.pot b/po/psensor.pot new file mode 100644 index 0000000..6c7f32a --- /dev/null +++ b/po/psensor.pot @@ -0,0 +1,281 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: wpitchoune@gmail.com\n" +"POT-Creation-Date: 2011-04-03 18:46+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/main.c:73 src/server/server.c:80 +#, c-format +msgid "" +"Copyright (C) %s wpitchoune@gmail.com\n" +"License GPLv2: GNU GPL version 2 or later \n" +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n" +msgstr "" + +#: src/main.c:83 src/server/server.c:90 +#, c-format +msgid "Usage: %s [OPTION]...\n" +msgstr "" + +#: src/main.c:85 +msgid "" +"psensor is a GTK application for monitoring hardware sensors, including " +"temperatures and fan speeds." +msgstr "" + +#: src/main.c:89 +msgid "Options:" +msgstr "" + +#: src/main.c:90 src/server/server.c:97 +msgid "" +" -h, --help display this help and exit\n" +" -v, --version display version information and exit" +msgstr "" + +#: src/main.c:96 +msgid "" +" -u, --url=URL the URL of the psensor-server, example: http://" +"hostname:3131" +msgstr "" + +#: src/main.c:102 src/server/server.c:110 +#, c-format +msgid "Report bugs to: %s\n" +msgstr "" + +#: src/main.c:104 src/server/server.c:112 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "" + +#: src/main.c:327 src/server/server.c:376 +#, c-format +msgid "Try `%s --help' for more information.\n" +msgstr "" + +#: src/main.c:350 +#, c-format +msgid "ERROR: lmsensor init failure: %s\n" +msgstr "" + +#: src/main.c:361 +#, c-format +msgid "ERROR: Not compiled with remote sensor support.\n" +msgstr "" + +#: src/ui_sensorlist.c:285 +msgid "Preferences" +msgstr "" + +#: src/ui_sensorlist.c:318 +msgid "Select foreground color" +msgstr "" + +#: src/ui_sensorlist.c:401 +msgid "Sensor" +msgstr "" + +#: src/ui_sensorlist.c:407 +msgid "Current" +msgstr "" + +#: src/ui_sensorlist.c:413 +msgid "Min" +msgstr "" + +#: src/ui_sensorlist.c:419 +msgid "Max" +msgstr "" + +#: src/ui_sensorlist.c:426 +msgid "Color" +msgstr "" + +#: src/ui_sensorlist.c:439 +msgid "Enabled" +msgstr "" + +#: src/ui_sensorlist.c:468 src/ui_sensorlist.c:469 src/ui_sensorlist.c:470 +msgid "N/A" +msgstr "" + +#: src/ui_notify.c:36 +#, c-format +msgid "ERROR: failed gettimeofday\n" +msgstr "" + +#: src/ui_notify.c:64 +msgid "Temperature alert" +msgstr "" + +#: src/rsensor.c:131 +#, c-format +msgid "ERROR: Fail to connect to: %s\n" +msgstr "" + +#: src/rsensor.c:166 +#, c-format +msgid "ERROR: Invalid content: %s\n" +msgstr "" + +#: src/rsensor.c:204 +#, c-format +msgid "ERROR: Invalid JSON: %s\n" +msgstr "" + +#: src/plib/plib_luatpl.c:121 +#, c-format +msgid "LUATPL Error: failed to load Lua script: %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:127 +#, c-format +msgid "LUATPL Error: failed to call init function: %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:133 +#, c-format +msgid "LUATPL Error:failed to execute Lua script (%s): %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:140 +#, c-format +msgid "LUATPL Error:lua script (%s) returned a wrong type.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:147 +#, c-format +msgid "LUATPL Error:failed to open lua state.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:154 +#, c-format +msgid "LUATPL Error: code: %d.\n" +msgstr "" + +#: src/server/server.c:56 +msgid "" +"

Page not found - Go to Main page

" +msgstr "" + +#: src/server/server.c:92 +msgid "" +"psensor-server is an HTTP server for monitoring hardware sensors remotely." +msgstr "" + +#: src/server/server.c:103 +msgid "" +" -d,--debug run in debug mode\n" +" -p,--port=PORT webserver port\n" +" -w,--wdir=DIR directory containing webserver pages" +msgstr "" + +#: src/server/server.c:184 +msgid "

Server stop requested

" +msgstr "" + +#: src/server/server.c:315 +#, c-format +msgid "HTTP Request: %s\n" +msgstr "" + +#: src/server/server.c:382 +#, c-format +msgid "ERROR: failed to init lm-sensors\n" +msgstr "" + +#: src/server/server.c:389 +#, c-format +msgid "ERROR: no sensors detected\n" +msgstr "" + +#: src/server/server.c:396 +#, c-format +msgid "ERROR: Fail to create web server\n" +msgstr "" + +#: src/server/server.c:400 +#, c-format +msgid "Web server started on port: %d\n" +msgstr "" + +#: src/server/server.c:401 +#, c-format +msgid "WWW directory: %s\n" +msgstr "" + +#: src/server/server.c:402 +#, c-format +msgid "URL: http://localhost:%d\n" +msgstr "" + +#: src/lib/hdd.c:59 +#, c-format +msgid "ERROR: hdd_fetch, failed to open socket\n" +msgstr "" + +#: src/lib/hdd.c:73 +#, c-format +msgid "ERROR: hdd_fetch, failed to open connection\n" +msgstr "" + +#: src/lib/hdd.c:182 +#, c-format +msgid "ERROR: wrong hdd string: %s" +msgstr "" + +#: src/lib/hdd.c:252 +#, c-format +msgid "ERROR: wrong hdd string: %s\n" +msgstr "" + +#: src/lib/nvidia.c:53 +#, c-format +msgid "ERROR: failed to retrieve nvidia temperature\n" +msgstr "" + +#: src/lib/nvidia.c:85 +#, c-format +msgid "ERROR: nvidia initialization failure\n" +msgstr "" + +#: src/lib/nvidia.c:99 +#, c-format +msgid "ERROR: nvidia initialization failure: %d\n" +msgstr "" + +#: src/lib/nvidia.c:132 +#, c-format +msgid "ERROR: no nvidia chips or initialization failure\n" +msgstr "" + +#: src/lib/lmsensor.c:43 +#, c-format +msgid "ERROR: Can't get value of subfeature %s: %s\n" +msgstr "" + +#: src/lib/lmsensor.c:122 +#, c-format +msgid "ERROR: create_sensor, wrong feature type\n" +msgstr "" + +#: src/lib/lmsensor.c:166 +#, c-format +msgid "ERROR: lm-sensors initialization failure: %s\n" +msgstr "" diff --git a/po/quot.sed b/po/quot.sed new file mode 100644 index 0000000..0122c46 --- /dev/null +++ b/po/quot.sed @@ -0,0 +1,6 @@ +s/"\([^"]*\)"/“\1”/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“”/""/g diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin new file mode 100644 index 0000000..2436c49 --- /dev/null +++ b/po/remove-potcdate.sin @@ -0,0 +1,19 @@ +# Sed script that remove the POT-Creation-Date line in the header entry +# from a POT file. +# +# The distinction between the first and the following occurrences of the +# pattern is achieved by looking at the hold space. +/^"POT-Creation-Date: .*"$/{ +x +# Test if the hold space is empty. +s/P/P/ +ta +# Yes it was empty. First occurrence. Remove the line. +g +d +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/po/zh_CN.po b/po/zh_CN.po new file mode 100644 index 0000000..a85f583 --- /dev/null +++ b/po/zh_CN.po @@ -0,0 +1,366 @@ +# Chinese translations for psensor package. +# Copyright (C) 2011 Free Software Foundation, Inc. +# This file is distributed under the same license as the psensor package. +# wpitchoune , 2011. +# Chinese translation from 大宝 +msgid "" +msgstr "" +"Project-Id-Version: psensor 0.6.0.10\n" +"Report-Msgid-Bugs-To: wpitchoune@gmail.com\n" +"POT-Creation-Date: 2011-04-03 18:46+0200\n" +"PO-Revision-Date: 2011-02-07 22:21+0100\n" +"Last-Translator: 大宝 \n" +"Language-Team: Chinese (simplified)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/main.c:73 src/server/server.c:80 +#, c-format +msgid "" +"Copyright (C) %s wpitchoune@gmail.com\n" +"License GPLv2: GNU GPL version 2 or later \n" +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n" +msgstr "" + +#: src/main.c:83 src/server/server.c:90 +#, c-format +msgid "Usage: %s [OPTION]...\n" +msgstr "" + +#: src/main.c:85 +msgid "" +"psensor is a GTK application for monitoring hardware sensors, including " +"temperatures and fan speeds." +msgstr "" + +#: src/main.c:89 +msgid "Options:" +msgstr "" + +#: src/main.c:90 src/server/server.c:97 +msgid "" +" -h, --help display this help and exit\n" +" -v, --version display version information and exit" +msgstr "" + +#: src/main.c:96 +msgid "" +" -u, --url=URL the URL of the psensor-server, example: http://" +"hostname:3131" +msgstr "" + +#: src/main.c:102 src/server/server.c:110 +#, c-format +msgid "Report bugs to: %s\n" +msgstr "" + +#: src/main.c:104 src/server/server.c:112 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "" + +#: src/main.c:327 src/server/server.c:376 +#, c-format +msgid "Try `%s --help' for more information.\n" +msgstr "" + +#: src/main.c:350 +#, c-format +msgid "ERROR: lmsensor init failure: %s\n" +msgstr "" + +#: src/main.c:361 +#, c-format +msgid "ERROR: Not compiled with remote sensor support.\n" +msgstr "" + +#: src/ui_sensorlist.c:285 +msgid "Preferences" +msgstr "选项" + +#: src/ui_sensorlist.c:318 +msgid "Select foreground color" +msgstr "" + +#: src/ui_sensorlist.c:401 +msgid "Sensor" +msgstr "监视设备" + +#: src/ui_sensorlist.c:407 +msgid "Current" +msgstr "当前" + +#: src/ui_sensorlist.c:413 +msgid "Min" +msgstr "最小值" + +#: src/ui_sensorlist.c:419 +msgid "Max" +msgstr "最大值" + +#: src/ui_sensorlist.c:426 +msgid "Color" +msgstr "颜色" + +#: src/ui_sensorlist.c:439 +msgid "Enabled" +msgstr "激活" + +#: src/ui_sensorlist.c:468 src/ui_sensorlist.c:469 src/ui_sensorlist.c:470 +msgid "N/A" +msgstr "" + +#: src/ui_notify.c:36 +#, c-format +msgid "ERROR: failed gettimeofday\n" +msgstr "" + +#: src/ui_notify.c:64 +msgid "Temperature alert" +msgstr "" + +#: src/rsensor.c:131 +#, c-format +msgid "ERROR: Fail to connect to: %s\n" +msgstr "" + +#: src/rsensor.c:166 +#, c-format +msgid "ERROR: Invalid content: %s\n" +msgstr "" + +#: src/rsensor.c:204 +#, c-format +msgid "ERROR: Invalid JSON: %s\n" +msgstr "" + +#: src/plib/plib_luatpl.c:121 +#, c-format +msgid "LUATPL Error: failed to load Lua script: %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:127 +#, c-format +msgid "LUATPL Error: failed to call init function: %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:133 +#, c-format +msgid "LUATPL Error:failed to execute Lua script (%s): %s.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:140 +#, c-format +msgid "LUATPL Error:lua script (%s) returned a wrong type.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:147 +#, c-format +msgid "LUATPL Error:failed to open lua state.\n" +msgstr "" + +#: src/plib/plib_luatpl.c:154 +#, c-format +msgid "LUATPL Error: code: %d.\n" +msgstr "" + +#: src/server/server.c:56 +msgid "" +"

Page not found - Go to Main page

" +msgstr "" + +#: src/server/server.c:92 +msgid "" +"psensor-server is an HTTP server for monitoring hardware sensors remotely." +msgstr "" + +#: src/server/server.c:103 +msgid "" +" -d,--debug run in debug mode\n" +" -p,--port=PORT webserver port\n" +" -w,--wdir=DIR directory containing webserver pages" +msgstr "" + +#: src/server/server.c:184 +msgid "

Server stop requested

" +msgstr "" + +#: src/server/server.c:315 +#, c-format +msgid "HTTP Request: %s\n" +msgstr "" + +#: src/server/server.c:382 +#, c-format +msgid "ERROR: failed to init lm-sensors\n" +msgstr "" + +#: src/server/server.c:389 +#, c-format +msgid "ERROR: no sensors detected\n" +msgstr "" + +#: src/server/server.c:396 +#, c-format +msgid "ERROR: Fail to create web server\n" +msgstr "" + +#: src/server/server.c:400 +#, c-format +msgid "Web server started on port: %d\n" +msgstr "" + +#: src/server/server.c:401 +#, c-format +msgid "WWW directory: %s\n" +msgstr "" + +#: src/server/server.c:402 +#, c-format +msgid "URL: http://localhost:%d\n" +msgstr "" + +#: src/lib/hdd.c:59 +#, c-format +msgid "ERROR: hdd_fetch, failed to open socket\n" +msgstr "" + +#: src/lib/hdd.c:73 +#, c-format +msgid "ERROR: hdd_fetch, failed to open connection\n" +msgstr "" + +#: src/lib/hdd.c:182 +#, c-format +msgid "ERROR: wrong hdd string: %s" +msgstr "" + +#: src/lib/hdd.c:252 +#, c-format +msgid "ERROR: wrong hdd string: %s\n" +msgstr "" + +#: src/lib/nvidia.c:53 +#, c-format +msgid "ERROR: failed to retrieve nvidia temperature\n" +msgstr "" + +#: src/lib/nvidia.c:85 +#, c-format +msgid "ERROR: nvidia initialization failure\n" +msgstr "" + +#: src/lib/nvidia.c:99 +#, c-format +msgid "ERROR: nvidia initialization failure: %d\n" +msgstr "" + +#: src/lib/nvidia.c:132 +#, c-format +msgid "ERROR: no nvidia chips or initialization failure\n" +msgstr "" + +#: src/lib/lmsensor.c:43 +#, c-format +msgid "ERROR: Can't get value of subfeature %s: %s\n" +msgstr "" + +#: src/lib/lmsensor.c:122 +#, c-format +msgid "ERROR: create_sensor, wrong feature type\n" +msgstr "" + +#: src/lib/lmsensor.c:166 +#, c-format +msgid "ERROR: lm-sensors initialization failure: %s\n" +msgstr "" + +#~ msgid "Graph Colors" +#~ msgstr "图表颜色" + +#~ msgid "Foreground:" +#~ msgstr "坐标栏:" + +#~ msgid "Background:" +#~ msgstr "背景:" + +#~ msgid "Background opacity:" +#~ msgstr "背景亮度:" + +#~ msgid "Min" +#~ msgstr "最小值" + +#~ msgid "Max" +#~ msgstr "最大值" + +#~ msgid "Graph" +#~ msgstr "图表" + +#~ msgid "Interface" +#~ msgstr "界面" + +#~ msgid "Position of sensors table:" +#~ msgstr "监视设备列表位置:" + +#~ msgid "Right" +#~ msgstr "右侧" + +#~ msgid "Left" +#~ msgstr "左侧" + +#~ msgid "Top" +#~ msgstr "顶部" + +#~ msgid "Bottom" +#~ msgstr "底部" + +#~ msgid "Hide window decoration" +#~ msgstr "隐藏窗口标题栏" + +#~ msgid "Keep window below" +#~ msgstr "保持在最底层" + +#, fuzzy +#~ msgid "Edit Preferences" +#~ msgstr "监视设备选项" + +#~ msgid "Edit Sensor Preferences" +#~ msgstr "监视设备选项" + +#~ msgid "Sensor Information" +#~ msgstr "设备信息" + +#~ msgid "Id:" +#~ msgstr "标识:" + +#~ msgid "Type:" +#~ msgstr "类型:" + +#~ msgid "Name:" +#~ msgstr "名称:" + +#~ msgid "Draw sensor curve" +#~ msgstr "绘制监视曲线" + +#, fuzzy +#~ msgid "Color:" +#~ msgstr "颜色:" + +#~ msgid "Alarm" +#~ msgstr "警告信息" + +#~ msgid "Activate desktop notifications" +#~ msgstr "激活桌面气泡提示" + +#~ msgid "Temperature limit:" +#~ msgstr "温度警戒线:" + +#~ msgid "Show" +#~ msgstr "显示主窗口" + +#~ msgid "Quit" +#~ msgstr "退出" diff --git a/psensor.desktop b/psensor.desktop new file mode 100644 index 0000000..ecc02db --- /dev/null +++ b/psensor.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Version=1.0 +Name=Psensor +GenericName=Psensor +Comment=Psensor is a graphical temperature monitor for Linux +Icon=psensor +TryExec=psensor +Exec=psensor +Categories=Application;System; diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..e567c83 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,81 @@ +SUBDIRS = plib lib unity glade + +AM_LDFLAGS = -Wl,--as-needed + +if JSON +SUBDIRS += libpsensor_json +endif + +if LIBMICROHTTPD +if JSON +if LUA +SUBDIRS += server +endif +endif +endif + +AM_CPPFLAGS = -Wall -pedantic -Werror -DDEFAULT_WWW_DIR=\""$(pkgdatadir)/www"\"\ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/unity \ + $(GTK_CFLAGS)\ + $(GCONF_CFLAGS)\ + $(SENSORS_CFLAGS) + +DEFS = -DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" -DLOCALEDIR=\"$(localedir)\" @DEFS@ + +LIBS = \ + plib/libplib.a \ + lib/libpsensor.a \ + $(GTK_LIBS)\ + $(GCONF_LIBS)\ + $(SENSORS_LIBS) + +bin_PROGRAMS = psensor +psensor_SOURCES = \ + compat.h \ + cfg.h cfg.c \ + graph.h graph.c \ + main.c \ + ui.h ui.c \ + ui_color.h ui_color.c \ + ui_graph.h ui_graph.c \ + ui_pref.h ui_pref.c \ + ui_sensorlist.h ui_sensorlist.c + +if LIBNOTIFY +psensor_SOURCES += ui_notify.h ui_notify.c +LIBS += $(LIBNOTIFY_LIBS) +AM_CPPFLAGS += $(LIBNOTIFY_CFLAGS) +endif + +if APPINDICATOR +psensor_SOURCES += ui_appindicator.h ui_appindicator.c +LIBS += $(APPINDICATOR_LIBS) +AM_CPPFLAGS += $(APPINDICATOR_CFLAGS) +endif + +if NVIDIA +AM_CPPFLAGS += $(NVIDIA_CFLAGS) +LIBS += $(NVIDIA_LIBS) +endif + +if UNITY +AM_CPPFLAGS += $(UNITY_CFLAGS) +LIBS += unity/libpsensor_unity.a $(UNITY_LIBS) +endif + +if CURL +if JSON +psensor_SOURCES += rsensor.h rsensor.c plib/url.c plib/url.h +LIBS += $(CURL_LIBS) $(JSON_LIBS) +AM_CPPFLAGS += $(CURL_CFLAGS) $(JSON_CFLAGS) +endif +endif + +dist_man_MANS = psensor.1 + + +psensor.1: main.c $(top_srcdir)/configure.ac + $(MAKE) $(AM_MAKEFLAGS) psensor$(EXEEXT) + help2man --include=description.txt -N --name="Temperature monitoring application" --output=psensor.1 ./psensor$(EXEEXT) + diff --git a/src/cfg.c b/src/cfg.c new file mode 100644 index 0000000..24dedf0 --- /dev/null +++ b/src/cfg.c @@ -0,0 +1,456 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#include + +#include + +#include "cfg.h" + +#define KEY_SENSOR_UPDATE_INTERVAL "/apps/psensor/sensor/update_interval" + +#define KEY_GRAPH_UPDATE_INTERVAL "/apps/psensor/graph/update_interval" +#define KEY_GRAPH_MONITORING_DURATION "/apps/psensor/graph/monitoring_duration" + +#define KEY_GRAPH_BACKGROUND_COLOR "/apps/psensor/graph/background_color" +#define DEFAULT_GRAPH_BACKGROUND_COLOR "#e8f4e8f4a8f5" + +#define KEY_GRAPH_BACKGROUND_ALPHA "/apps/psensor/graph/background_alpha" +#define DEFAULT_GRAPH_BACKGROUND_ALPHA "1.0" + +#define KEY_GRAPH_FOREGROUND_COLOR "/apps/psensor/graph/foreground_color" +#define DEFAULT_GRAPH_FOREGROUND_COLOR "#000000000000" + +#define KEY_ALPHA_CHANNEL_ENABLED "/apps/psensor/graph/alpha_channel_enabled" +#define DEFAULT_ALPHA_CHANNEL_ENABLED 0 + +#define KEY_INTERFACE_SENSORLIST_POSITION \ +"/apps/psensor/interface/sensorlist_position" + +#define KEY_INTERFACE_WINDOW_DECORATION_DISABLED \ +"/apps/psensor/interface/window_decoration_disabled" + +#define KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED \ +"/apps/psensor/interface/window_keep_below_enabled" + +GConfClient *client; + +char *config_get_string(char *key, char *default_value) +{ + char *value = gconf_client_get_string(client, + key, + NULL); + + if (!value) { + value = strdup(default_value); + + gconf_client_set_string(client, key, default_value, NULL); + } + + return value; +} + +struct color *config_get_background_color() +{ + + char *scolor = config_get_string(KEY_GRAPH_BACKGROUND_COLOR, + DEFAULT_GRAPH_BACKGROUND_COLOR); + + struct color *c = string_to_color(scolor); + + free(scolor); + + if (c == NULL) + return color_new(0xffff, 0xffff, 0xffff); + + return c; +} + +struct color *config_get_foreground_color() +{ + char *scolor = config_get_string(KEY_GRAPH_FOREGROUND_COLOR, + DEFAULT_GRAPH_FOREGROUND_COLOR); + + struct color *c = string_to_color(scolor); + + free(scolor); + + if (c == NULL) + return color_new(0x0000, 0x0000, 0x0000); + + return c; +} + +int config_is_alpha_channel_enabled() +{ + gboolean b = gconf_client_get_bool(client, + KEY_ALPHA_CHANNEL_ENABLED, + NULL); + + return b == TRUE; +} + +void config_set_alpha_channel_enabled(int enabled) +{ + if (enabled) + gconf_client_set_bool(client, + KEY_ALPHA_CHANNEL_ENABLED, TRUE, NULL); + else + gconf_client_set_bool(client, + KEY_ALPHA_CHANNEL_ENABLED, FALSE, NULL); +} + +int config_get_sensorlist_position() +{ + return gconf_client_get_int(client, + KEY_INTERFACE_SENSORLIST_POSITION, NULL); +} + +void config_set_sensorlist_position(int pos) +{ + gconf_client_set_int(client, + KEY_INTERFACE_SENSORLIST_POSITION, pos, NULL); +} + +double config_get_graph_background_alpha() +{ + double a = gconf_client_get_float(client, + KEY_GRAPH_BACKGROUND_ALPHA, + NULL); + + if (a == 0) + gconf_client_set_float(client, + KEY_GRAPH_BACKGROUND_ALPHA, 1.0, NULL); + return a; +} + +void config_set_graph_background_alpha(double alpha) +{ + gconf_client_set_float(client, KEY_GRAPH_BACKGROUND_ALPHA, alpha, NULL); +} + +void config_set_background_color(struct color *color) +{ + char *scolor = color_to_string(color); + + if (!scolor) + scolor = strdup(DEFAULT_GRAPH_BACKGROUND_COLOR); + + gconf_client_set_string(client, + KEY_GRAPH_BACKGROUND_COLOR, scolor, NULL); + + free(scolor); +} + +void config_set_foreground_color(struct color *color) +{ + char *scolor = color_to_string(color); + + if (!scolor) + scolor = strdup(DEFAULT_GRAPH_FOREGROUND_COLOR); + + gconf_client_set_string(client, + KEY_GRAPH_FOREGROUND_COLOR, scolor, NULL); + + free(scolor); +} + +char *config_get_sensor_key(char *sensor_name) +{ + char *escaped_name = gconf_escape_key(sensor_name, -1); + /* /apps/psensor/sensors/[sensor_name]/color */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 6 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/color", escaped_name); + + free(escaped_name); + + return key; +} + +struct color *config_get_sensor_color(char *sensor_name, + struct color *default_color) +{ + char *key = config_get_sensor_key(sensor_name); + + char *scolor = gconf_client_get_string(client, + key, + NULL); + + struct color *color = NULL; + + if (scolor) + color = string_to_color(scolor); + + if (!scolor || !color) { + color = color_new(default_color->red, + default_color->green, default_color->blue); + + scolor = color_to_string(color); + + gconf_client_set_string(client, key, scolor, NULL); + } + + free(scolor); + free(key); + + return color; +} + +void config_set_sensor_color(char *sensor_name, struct color *color) +{ + char *key = config_get_sensor_key(sensor_name); + + char *scolor = color_to_string(color); + + gconf_client_set_string(client, key, scolor, NULL); + + free(scolor); +} + +int config_get_sensor_alarm_limit(char *sensor_name, int def) +{ + int res; + char *escaped_name = gconf_escape_key(sensor_name, -1); + /* /apps/psensor/sensors/[sensor_name]/alarmlimit */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 10 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/alarmlimit", escaped_name); + + res = gconf_client_get_int(client, key, NULL); + + free(escaped_name); + + return res ? res : def; +} + +void config_set_sensor_alarm_limit(char *sensor_name, int alarm_limit) +{ + char *escaped_name = gconf_escape_key(sensor_name, -1); + /* /apps/psensor/sensors/[sensor_name]/alarmlimit */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 10 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/alarmlimit", escaped_name); + + gconf_client_set_int(client, key, alarm_limit, NULL); + + free(escaped_name); +} + +int config_get_sensor_alarm_enabled(char *sid) +{ + gboolean res; + char *escaped_name = gconf_escape_key(sid, -1); + /* /apps/psensor/sensors/[sensor_name]/alarmenabled */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 12 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/alarmenabled", escaped_name); + + res = gconf_client_get_bool(client, key, NULL); + + free(escaped_name); + + return res == TRUE; +} + +void config_set_sensor_alarm_enabled(char *sid, int enabled) +{ + char *escaped_name = gconf_escape_key(sid, -1); + /* /apps/psensor/sensors/[sensor_name]/alarmenabled */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 12 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/alarmenabled", escaped_name); + + gconf_client_set_bool(client, key, enabled, NULL); + + free(escaped_name); +} + +int config_is_sensor_enabled(char *sid) +{ + gboolean res; + char *escaped_name = gconf_escape_key(sid, -1); + /* /apps/psensor/sensors/[sensor_name]/enabled */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 7 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/enabled", escaped_name); + + res = gconf_client_get_bool(client, key, NULL); + + free(escaped_name); + + return res == TRUE; + +} + +void config_set_sensor_enabled(char *sid, int enabled) +{ + char *escaped_name = gconf_escape_key(sid, -1); + /* /apps/psensor/sensors/[sensor_name]/enabled */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 7 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/enabled", escaped_name); + + gconf_client_set_bool(client, key, enabled, NULL); + + free(escaped_name); +} + +char *config_get_sensor_name(char *sid) +{ + char *res; + char *escaped_name = gconf_escape_key(sid, -1); + /* /apps/psensor/sensors/[sensor_name]/name */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 4 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/name", escaped_name); + + res = gconf_client_get_string(client, key, NULL); + + free(escaped_name); + + return res; +} + +void config_set_sensor_name(char *sid, const char *name) +{ + char *escaped_name = gconf_escape_key(sid, -1); + /* /apps/psensor/sensors/[sensor_name]/name */ + char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 4 + 1); + + sprintf(key, "/apps/psensor/sensors/%s/name", escaped_name); + + gconf_client_set_string(client, key, name, NULL); + + free(escaped_name); +} + +int config_is_window_decoration_enabled() +{ + gboolean b; + + b = gconf_client_get_bool(client, + KEY_INTERFACE_WINDOW_DECORATION_DISABLED, + NULL); + + return b == FALSE; +} + +int config_is_window_keep_below_enabled() +{ + gboolean b; + + b = gconf_client_get_bool(client, + KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED, + NULL); + + return b == TRUE; +} + +void config_set_window_decoration_enabled(int enabled) +{ + if (enabled) + gconf_client_set_bool + (client, + KEY_INTERFACE_WINDOW_DECORATION_DISABLED, FALSE, NULL); + else + gconf_client_set_bool + (client, + KEY_INTERFACE_WINDOW_DECORATION_DISABLED, TRUE, NULL); +} + +void config_set_window_keep_below_enabled(int enabled) +{ + if (enabled) + gconf_client_set_bool(client, + KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED, + TRUE, NULL); + else + gconf_client_set_bool(client, + KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED, + FALSE, NULL); +} + +void config_init() +{ + client = gconf_client_get_default(); +} + +struct config *config_load() +{ + struct config *cfg = malloc(sizeof(struct config)); + + cfg->graph_bgcolor = config_get_background_color(); + cfg->graph_fgcolor = config_get_foreground_color(); + cfg->graph_bg_alpha = config_get_graph_background_alpha(); + cfg->alpha_channel_enabled = config_is_alpha_channel_enabled(); + cfg->sensorlist_position = config_get_sensorlist_position(); + cfg->window_decoration_enabled = config_is_window_decoration_enabled(); + cfg->window_keep_below_enabled = config_is_window_keep_below_enabled(); + + cfg->sensor_update_interval + = gconf_client_get_int(client, KEY_SENSOR_UPDATE_INTERVAL, NULL); + if (cfg->sensor_update_interval < 1) + cfg->sensor_update_interval = 1; + + cfg->graph_update_interval + = gconf_client_get_int(client, KEY_GRAPH_UPDATE_INTERVAL, NULL); + if (cfg->graph_update_interval < 1) + cfg->graph_update_interval = 1; + + cfg->graph_monitoring_duration + = gconf_client_get_int(client, KEY_GRAPH_MONITORING_DURATION, NULL); + + if (cfg->graph_monitoring_duration < 1) + cfg->graph_monitoring_duration = 10; + + cfg->sensor_values_max_length + = + (cfg->graph_monitoring_duration * 60) / cfg->sensor_update_interval; + if (cfg->sensor_values_max_length < 3) + cfg->sensor_values_max_length = 3; + + return cfg; +} + +void config_save(struct config *cfg) +{ + config_set_background_color(cfg->graph_bgcolor); + config_set_foreground_color(cfg->graph_fgcolor); + config_set_graph_background_alpha(cfg->graph_bg_alpha); + config_set_sensorlist_position(cfg->sensorlist_position); + config_set_window_decoration_enabled(cfg->window_decoration_enabled); + config_set_window_keep_below_enabled(cfg->window_keep_below_enabled); + + gconf_client_set_int(client, + KEY_GRAPH_UPDATE_INTERVAL, + cfg->graph_update_interval, NULL); + + gconf_client_set_int(client, + KEY_GRAPH_MONITORING_DURATION, + cfg->graph_monitoring_duration, NULL); + + gconf_client_set_int(client, + KEY_SENSOR_UPDATE_INTERVAL, + cfg->sensor_update_interval, NULL); + +} diff --git a/src/cfg.h b/src/cfg.h new file mode 100644 index 0000000..f6c46e3 --- /dev/null +++ b/src/cfg.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_CONFIG_H_ +#define _PSENSOR_CONFIG_H_ + +#include "color.h" + +#define SENSORLIST_POSITION_RIGHT 0 +#define SENSORLIST_POSITION_LEFT 1 +#define SENSORLIST_POSITION_TOP 2 +#define SENSORLIST_POSITION_BOTTOM 3 + +struct config { + struct color *graph_bgcolor; + struct color *graph_fgcolor; + + double graph_bg_alpha; + + int alpha_channel_enabled; + + /* + Position of the sensors list table + */ + int sensorlist_position; + + int window_decoration_enabled; + + int window_keep_below_enabled; + + int graph_update_interval; + int graph_monitoring_duration; + + int sensor_values_max_length; + int sensor_update_interval; +}; + +/* + Loads config from GConf +*/ +struct config *config_load(); + +void config_save(struct config *); + +void config_init(); + +struct color *config_get_sensor_color(char *sensor_name, + struct color *default_color); + +void config_set_sensor_color(char *sensor_name, struct color *color); + +int config_get_sensor_alarm_limit(char *, int); +void config_set_sensor_alarm_limit(char *sensor_name, int alarm_limit); + +int config_get_sensor_alarm_enabled(char *); +void config_set_sensor_alarm_enabled(char *, int); + +int config_is_sensor_enabled(char *); +void config_set_sensor_enabled(char *, int); + +char *config_get_sensor_name(char *); +void config_set_sensor_name(char *, const char *); + +#endif diff --git a/src/compat.h b/src/compat.h new file mode 100644 index 0000000..243c46f --- /dev/null +++ b/src/compat.h @@ -0,0 +1,26 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +*/ + +/* + gtk_dialog_get_content_area exists since gtk 2.14 As debian 5.0.6 + (lenny) is using gtk 2.12 defines the function by using a macro. +*/ +#if !defined(gtk_dialog_get_content_area) +#define gtk_dialog_get_content_area(dialog) (GTK_DIALOG(dialog)->vbox) +#endif diff --git a/src/description.txt b/src/description.txt new file mode 100644 index 0000000..27d3db9 --- /dev/null +++ b/src/description.txt @@ -0,0 +1,32 @@ +[description] + +/psensor is a/ + +It displays a curve for each sensor, and uses Desktop Notification to +raise an alarm when a temperature is too high. On Ubuntu an +Application Indicator is also available, its icon changes when a +temperature alert is raised. + +It can monitor: + * the temperature of the motherboard and CPU sensors (using lm\-sensors). + * the temperature of the NVidia GPUs (using XNVCtrl). + * the temperature of the Hard Disk Drives (using hddtemp). + * the rotation speed of the fans (using lm\-sensors). + * the sensors of a remote computer (using psensor\-server). + +Psensor requires lm\-sensors to be correctly installed and configured, +it can be checked by running the command 'sensors'. If it has never be +done, you may need to run the command 'sensors\-detect' and follow the +instruction. See the manpages of sensors(1) and sensors\-detect(8) for +more information. + +To retrieve the temperature of the Hard Disk Drives, the hddtemp +daemon must be running. + +For remote monitoring: + * start psensor\-server(1) on the remote computer + * run psensor with '\-\-url' option: 'psensor \-\-url=http://localhost:3131' + +[SEE ALSO] + +psensor\-server(1), sensors(1), sensors\-detect(8), hddtemp(8) diff --git a/src/glade/Makefile.am b/src/glade/Makefile.am new file mode 100644 index 0000000..58d1551 --- /dev/null +++ b/src/glade/Makefile.am @@ -0,0 +1,6 @@ +gladedir = $(pkgdatadir) +glade_DATA = \ + sensor-edit.glade \ + psensor-pref.glade + +EXTRA_DIST = $(glade_DATA) diff --git a/src/glade/psensor-pref.glade b/src/glade/psensor-pref.glade new file mode 100644 index 0000000..1501644 --- /dev/null +++ b/src/glade/psensor-pref.glade @@ -0,0 +1,534 @@ + + + + + + 5 + Edit Preferences + True + True + normal + True + + + True + 2 + + + True + 16 + 3 + + + True + 0 + Graph Colors + + + + + + 3 + 4 + 4 + + + + + True + 0 + Foreground: + + + 1 + 2 + 14 + 4 + + + + + True + 0 + Background: + + + 2 + 3 + 14 + 4 + + + + + True + 0 + Background opacity: + + + 3 + 3 + 4 + 14 + 4 + + + + + True + True + True + #000000000000 + + + 1 + 3 + 1 + 2 + + 4 + 4 + + + + + True + True + True + #000000000000 + + + 1 + 3 + 2 + 3 + + 4 + 4 + + + + + True + 0 + Graph + + + + + + 3 + 5 + 6 + 4 + 4 + + + + + True + 0 + Update interval: + + + 6 + 7 + 14 + 4 + + + + + True + 0 + Monitoring duration: + + + 7 + 8 + 14 + 4 + + + + + True + second(s) + + + 2 + 3 + 6 + 7 + 4 + 4 + + + + + True + minute(s) + + + 2 + 3 + 7 + 8 + 4 + 4 + + + + + True + 0 + Sensor + + + + + + 3 + 8 + 9 + 4 + 4 + + + + + True + 0 + Measure update interval: + + + 9 + 10 + 14 + 4 + + + + + True + second(s) + + + 2 + 3 + 9 + 10 + 4 + 4 + + + + + True + 0 + Interface + + + + + + 3 + 10 + 11 + 4 + 4 + + + + + True + 0 + Position of sensors table: + + + 11 + 12 + 14 + 4 + + + + + Hide window decoration + True + True + False + 0 + True + + + 3 + 12 + 13 + 14 + 4 + + + + + Keep window below + True + True + False + 0 + True + + + 3 + 13 + 14 + 14 + 4 + + + + + True + True + • + secs + + + 1 + 2 + 6 + 7 + 4 + 4 + + + + + True + True + • + mins + + + 1 + 2 + 7 + 8 + 4 + 4 + + + + + True + True + • + secs2 + + + 1 + 2 + 9 + 10 + 4 + 4 + + + + + True + liststore1 + + + + 0 + + + + + 1 + 3 + 11 + 12 + 4 + 4 + + + + + True + 8 + + + True + 0 + <i>Min</i> + True + + + False + 0 + + + + + True + True + opacity + False + + + 1 + + + + + True + 0 + <i>Max</i> + True + + + False + 2 + + + + + 3 + 4 + 5 + 14 + 4 + + + + + Enable menu + True + True + False + True + + + 3 + 14 + 15 + 14 + 4 + + + + + Enable Unity Launcher counter + True + True + False + 0 + True + + + 3 + 15 + 16 + 14 + 4 + + + + + 1 + + + + + True + end + + + gtk-ok + True + True + True + True + + + False + False + 0 + + + + + gtk-cancel + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + button1 + button2 + + + + 1 + 0.01 + 0.10000000000000001 + + + + + + + + + Right + + + Left + + + Top + + + Bottom + + + + + 1 + 1 + 256 + 1 + 10 + + + 10 + 1 + 65535 + 1 + 10 + + + 1 + 256 + 1 + 10 + + diff --git a/src/glade/sensor-edit.glade b/src/glade/sensor-edit.glade new file mode 100644 index 0000000..fd5acea --- /dev/null +++ b/src/glade/sensor-edit.glade @@ -0,0 +1,329 @@ + + + + + + 5 + Edit Sensor Preferences + True + True + dialog + True + + + True + 2 + + + True + 10 + 2 + + + True + 0 + N/A + + + 1 + 2 + 1 + 2 + 4 + 4 + + + + + True + 0 + 10 + Name: + + + 3 + 4 + GTK_FILL + 4 + 4 + + + + + True + True + • + + + 1 + 2 + 3 + 4 + 4 + 4 + + + + + True + 0 + Type: + + + 2 + 3 + 14 + 4 + + + + + True + 0 + N/A + + + 1 + 2 + 2 + 3 + 4 + 4 + + + + + True + 0 + Id: + + + 1 + 2 + GTK_FILL + 14 + 4 + + + + + True + 0 + Graph + + + + + + 2 + 4 + 5 + 4 + 4 + + + + + True + 0 + Color: + + + 6 + 7 + 14 + 4 + + + + + True + 0 + Alarm + + + + + + 2 + 7 + 8 + 4 + 4 + + + + + Activate desktop notifications + True + True + False + True + + + 2 + 8 + 9 + 14 + 4 + + + + + True + 0 + Temperature limit: + + + 9 + 10 + GTK_FILL + 14 + 4 + + + + + True + 0 + Sensor Information + + + + + + 2 + 4 + 4 + + + + + Draw sensor curve + True + True + False + 0.41999998688697815 + True + + + 2 + 5 + 6 + 14 + 4 + + + + + True + + + True + True + 3 + • + temp_limit + 1 + True + True + if-valid + + + False + 0 + + + + + True + 0 + °C + + + 1 + + + + + 1 + 2 + 9 + 10 + + + + + True + True + True + 0 + #000000000000 + + + 1 + 2 + 6 + 7 + + 4 + 4 + + + + + 1 + + + + + True + end + + + gtk-ok + True + True + True + True + + + False + False + 0 + + + + + gtk-cancel + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + + + + + btn_ok + btn_cancel + + + + 256 + 1 + 10 + + diff --git a/src/graph.c b/src/graph.c new file mode 100644 index 0000000..3b70d3e --- /dev/null +++ b/src/graph.c @@ -0,0 +1,331 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 + +#include "cfg.h" +#include "psensor.h" + +/* horizontal padding */ +#define GRAPH_H_PADDING 4 +/* vertical padding */ +#define GRAPH_V_PADDING 4 + +static time_t get_graph_end_time_s() +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) + return tv.tv_sec; + else + return 0; +} + +static time_t get_graph_begin_time_s(struct config *cfg) +{ + int ct; + + ct = get_graph_end_time_s(); + + if (!ct) + return 0; + + return ct - cfg->graph_monitoring_duration * 60; +} + +static int compute_y(double value, double min, double max, int height, int off) +{ + double t = value - min; + return height - ((double)height * (t / (max - min))) + off; +} + +static char *time_to_str(time_t s) +{ + char *str; + /* note: localtime returns a static field, no free required */ + struct tm *tm = localtime(&s); + + if (!tm) + return NULL; + + str = malloc(6); + strftime(str, 6, "%H:%M", tm); + + return str; +} + +static void +draw_graph_background(cairo_t *cr, + int width, int height, struct config *config) +{ + struct color *bgcolor = config->graph_bgcolor; + + /* draw background */ + if (config->alpha_channel_enabled) + cairo_set_source_rgba(cr, + bgcolor->f_red, + bgcolor->f_green, + bgcolor->f_blue, config->graph_bg_alpha); + else + cairo_set_source_rgb(cr, + bgcolor->f_red, + bgcolor->f_green, bgcolor->f_blue); + + cairo_rectangle(cr, 0, 0, width, height); + cairo_fill(cr); +} + +/* setup dash style */ +static double dashes[] = { + 1.0, /* ink */ + 1.0, /* skip */ + 1.0, /* ink */ + 1.0 /* skip */ +}; +static int ndash = sizeof(dashes) / sizeof(dashes[0]); + +static void draw_background_lines(cairo_t *cr, + struct color *color, + int g_width, int g_height, + int g_xoff, int g_yoff, + int min, int max) +{ + int i; + + /* draw background lines */ + cairo_set_dash(cr, dashes, ndash, 0); + cairo_set_line_width(cr, 1); + cairo_set_source_rgb(cr, + color->f_red, color->f_green, color->f_blue); + + /* vertical lines representing time steps */ + for (i = 0; i <= 5; i++) { + int x = i * (g_width / 5) + g_xoff; + cairo_move_to(cr, x, g_yoff); + cairo_line_to(cr, x, g_yoff + g_height); + cairo_stroke(cr); + } + + /* horizontal lines draws a line for each 10C step */ + for (i = min; i < max; i++) { + if (i % 10 == 0) { + int y = compute_y(i, min, max, g_height, g_yoff); + + cairo_move_to(cr, g_xoff, y); + cairo_line_to(cr, g_xoff + g_width, y); + cairo_stroke(cr); + } + } + + /* back to normal line style */ + cairo_set_dash(cr, 0, 0, 0); + +} + +static void draw_sensor_curve(struct psensor *s, + cairo_t *cr, + double min, + double max, + int bt, + int et, + int g_width, + int g_height, + int g_xoff, + int g_yoff) +{ + int first = 1; + int i; + + cairo_set_source_rgb(cr, + s->color->f_red, + s->color->f_green, + s->color->f_blue); + cairo_set_line_width(cr, 1); + + for (i = 0; i < s->values_max_length; i++) { + int x, y, t; + double v; + + t = s->measures[i].time.tv_sec; + v = s->measures[i].value; + + if (v == UNKNOWN_VALUE || !t || (t - bt) < 0) + continue; + + x = (t - bt) * g_width / (et - bt) + g_xoff; + + y = compute_y(v, min, max, g_height, g_yoff); + + if (first) { + cairo_move_to(cr, x, y); + first = 0; + } else { + cairo_line_to(cr, x, y); + } + + } + cairo_stroke(cr); +} + + +void +graph_update(struct psensor **sensors, + GtkWidget *w_graph, struct config *config) +{ + struct color *fgcolor = config->graph_fgcolor; + int et, bt; + double min_rpm = get_min_rpm(sensors); + double max_rpm = get_max_rpm(sensors); + + double mint = get_min_temp(sensors); + char *strmin = psensor_value_to_string(SENSOR_TYPE_TEMP, mint); + + double maxt = get_max_temp(sensors); + char *strmax = psensor_value_to_string(SENSOR_TYPE_TEMP, maxt); + + int width = w_graph->allocation.width; + int height = w_graph->allocation.height; + + int g_width, g_height; + + /* horizontal and vertical offset of the graph */ + int g_xoff, g_yoff; + + cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + width, + height); + cairo_t *cr = cairo_create(cst); + cairo_t *cr_pixmap; + + char *str_btime = time_to_str(get_graph_begin_time_s(config)); + cairo_text_extents_t te_btime; + + char *str_etime = time_to_str(get_graph_end_time_s()); + cairo_text_extents_t te_etime; + + cairo_text_extents_t te_max, te_min; + + struct psensor **sensor_cur; + + draw_graph_background(cr, width, height, config); + + cairo_select_font_face(cr, + "sans-serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, 10.0); + + cairo_text_extents(cr, str_etime, &te_etime); + cairo_text_extents(cr, str_btime, &te_btime); + cairo_text_extents(cr, strmax, &te_max); + cairo_text_extents(cr, strmin, &te_min); + + g_yoff = GRAPH_V_PADDING; + + g_height = height - GRAPH_V_PADDING; + if (te_etime.height > te_btime.height) + g_height -= GRAPH_V_PADDING + te_etime.height + GRAPH_V_PADDING; + else + g_height -= GRAPH_V_PADDING + te_btime.height + GRAPH_V_PADDING; + + if (te_min.width > te_max.width) + g_xoff = (2 * GRAPH_H_PADDING) + te_max.width; + else + g_xoff = (2 * GRAPH_H_PADDING) + te_min.width; + + g_width = width - g_xoff - GRAPH_H_PADDING; + + cairo_set_source_rgb(cr, + fgcolor->f_red, fgcolor->f_green, fgcolor->f_blue); + + /* draw graph begin time */ + cairo_move_to(cr, g_xoff, height - GRAPH_V_PADDING); + cairo_show_text(cr, str_btime); + free(str_btime); + + /* draw graph end time */ + cairo_move_to(cr, + width - te_etime.width - GRAPH_H_PADDING, + height - GRAPH_V_PADDING); + cairo_show_text(cr, str_etime); + free(str_etime); + + /* draw min and max temp */ + cairo_move_to(cr, GRAPH_H_PADDING, te_max.height + GRAPH_V_PADDING); + cairo_show_text(cr, strmax); + free(strmax); + + cairo_move_to(cr, + GRAPH_H_PADDING, height - (te_min.height / 2) - g_yoff); + cairo_show_text(cr, strmin); + free(strmin); + + draw_background_lines(cr, fgcolor, + g_width, g_height, + g_xoff, g_yoff, + mint, maxt); + + /* .. and finaly draws the temperature graphs */ + bt = get_graph_begin_time_s(config); + et = get_graph_end_time_s(); + + if (bt && et) { + sensor_cur = sensors; + while (*sensor_cur) { + struct psensor *s = *sensor_cur; + + if (s->enabled) { + double min, max; + + if (is_fan_type(s->type)) { + min = min_rpm; + max = max_rpm; + } else { + min = mint; + max = maxt; + } + + draw_sensor_curve(s, cr, + min, max, + bt, et, + g_width, g_height, + g_xoff, g_yoff); + } + + sensor_cur++; + } + } + + cr_pixmap = gdk_cairo_create(w_graph->window); + + if (cr_pixmap) { + + if (config->alpha_channel_enabled) + cairo_set_operator(cr_pixmap, CAIRO_OPERATOR_SOURCE); + + cairo_set_source_surface(cr_pixmap, cst, 0, 0); + cairo_paint(cr_pixmap); + } + + cairo_destroy(cr_pixmap); + cairo_surface_destroy(cst); + cairo_destroy(cr); +} diff --git a/src/graph.h b/src/graph.h new file mode 100644 index 0000000..77ed5ed --- /dev/null +++ b/src/graph.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_GRAPH_H_ +#define _PSENSOR_GRAPH_H_ + +#include + +#include "psensor.h" +#include "cfg.h" + +void graph_update(struct psensor **, GtkWidget *, struct config *config); + +#endif diff --git a/src/httpd/Makefile.am b/src/httpd/Makefile.am new file mode 100644 index 0000000..34c10fc --- /dev/null +++ b/src/httpd/Makefile.am @@ -0,0 +1,41 @@ +AM_CPPFLAGS = -pedantic -Werror -DDEFAULT_WWW_DIR=\""$(pkgdatadir)/www"\"\ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/lib \ + $(LUA_CFLAGS)\ + $(GTK_CFLAGS)\ + $(APPINDICATOR_CFLAGS)\ + $(GCONF_CFLAGS)\ + $(SENSORS_CFLAGS)\ + $(NVIDIA_CFLAGS)\ + $(CURL_CFLAGS)\ + $(JSON_CFLAGS)\ + $(GTOP_CFLAGS)\ + $(LIBMICROHTTPD_CFLAGS) + +LIBS = \ + $(top_srcdir)/src/plib/libplib.a \ + $(top_srcdir)/src/lib/libpsensor.a \ + $(LUA_LIBS)\ + $(GTK_LIBS)\ + $(APPINDICATOR_LIBS)\ + $(GCONF_LIBS)\ + $(SENSORS_LIBS)\ + $(NVIDIA_LIBS)\ + $(CURL_LIBS)\ + $(JSON_LIBS)\ + $(GTOP_LIBS)\ + $(LIBMICROHTTPD_LIBS) + +bin_PROGRAMS = psensor-server + +psensor_server_SOURCES = httpd.c httpd.h + + + + +dist_man_MANS = psensor-server.1 + + +psensor-server.1: httpd.c $(top_srcdir)/configure.ac + $(MAKE) $(AM_MAKEFLAGS) psensor-server$(EXEEXT) + help2man --output=psensor-server.1 ./psensor-server$(EXEEXT) \ No newline at end of file diff --git a/src/httpd/httpd.c b/src/httpd/httpd.c new file mode 100644 index 0000000..fccccac --- /dev/null +++ b/src/httpd/httpd.c @@ -0,0 +1,426 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GTOP +#include +#endif + +#define lua_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +#include "plib/url.h" +#include "httpd.h" +#include "psensor.h" +#include "hdd.h" +#include "nvidia.h" +#include "lmsensor.h" + +#define DEFAULT_PORT 3131 + + +#define PAGE_NOT_FOUND \ +"

Page not found - Go to Main page\ +

" + + +#define PSENSOR_SERVER_OPTIONS " --help display this help and exit\n\ + --version output version information and exit\n\ + --port=PORT webserver port\n\ + --wdir=DIR directory containing webserver pages" + +#define PSENSOR_SERVER_USAGE "Usage: psensor-server [OPTION]" + +#define PSENSOR_SERVER_DESCRIPTION \ +"HTTP server for retrieving hardware temperatures." + +#define PSENSOR_SERVER_CONTACT "Report bugs to: psensor@wpitchoune.net\n\ +Psensor home page: " + +#define PSENSOR_SERVER_COPYRIGHT \ +"Copyright (C) 2010-2011 wpitchoune@gmail.com\n\ +License GPLv2: GNU GPL version 2 or later \ +\n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law." + +#define OPT_PORT "port" +#define OPT_HELP "help" +#define OPT_VERSION "version" +#define OPT_WWW_DIR "wdir" + +static struct option long_options[] = { + {OPT_VERSION, no_argument, 0, 'v'}, + {OPT_HELP, no_argument, 0, 'h'}, + {OPT_PORT, required_argument, 0, 'p'}, + {OPT_WWW_DIR, required_argument, 0, 'w'}, + {0, 0, 0, 0} +}; + +static char *www_dir = DEFAULT_WWW_DIR; + +#ifdef HAVE_GTOP +static float cpu_rate; +static glibtop_cpu *cpu; +#endif + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +json_object *sensor_to_json_object(struct psensor *s) +{ + json_object *mo; + json_object *obj = json_object_new_object(); + struct measure *m; + + json_object_object_add(obj, "id", json_object_new_string(s->id)); + json_object_object_add(obj, "name", json_object_new_string(s->name)); + json_object_object_add(obj, "type", json_object_new_int(s->type)); + json_object_object_add(obj, "min", json_object_new_double(s->min)); + json_object_object_add(obj, "max", json_object_new_double(s->max)); + + m = psensor_get_current_measure(s); + mo = json_object_new_object(); + json_object_object_add(mo, "value", json_object_new_double(m->value)); + json_object_object_add(mo, "time", + json_object_new_int((m->time).tv_sec)); + json_object_object_add(obj, "last_measure", mo); + + return obj; +} + +char *sensor_to_json_string(struct psensor *s) +{ + char *str; + json_object *obj = sensor_to_json_object(s); + + str = strdup(json_object_to_json_string(obj)); + + json_object_put(obj); + + return str; +} + +char *sensors_to_json_string(struct psensor **sensors) +{ + struct psensor **sensors_cur; + char *str; + + json_object *obj = json_object_new_array(); + + sensors_cur = sensors; + + while (*sensors_cur) { + struct psensor *s = *sensors_cur; + + json_object_array_add(obj, sensor_to_json_object(s)); + + sensors_cur++; + } + + str = strdup(json_object_to_json_string(obj)); + + json_object_put(obj); + + return str; +} + +char *lua_to_html_page(struct psensor **sensors, const char *url) +{ + struct psensor **s_cur; + char *page = NULL; + int i; + char *lua_fpath; + + lua_State *L = lua_open(); /* create state */ + + if (!L) + return NULL; + + luaL_openlibs(L); + +#ifdef HAVE_GTOP + lua_newtable(L); + lua_pushstring(L, "load"); + lua_pushnumber(L, cpu_rate); + lua_settable(L, -3); + lua_setglobal(L, "cpu"); +#endif + + lua_newtable(L); + + s_cur = sensors; + i = 0; + while (*s_cur) { + + lua_pushinteger(L, i); + + lua_newtable(L); + + lua_pushstring(L, "name"); + lua_pushstring(L, (*s_cur)->name); + lua_settable(L, -3); + + lua_pushstring(L, "measure_last"); + lua_pushnumber(L, psensor_get_current_value(*s_cur)); + lua_settable(L, -3); + + lua_pushstring(L, "measure_min"); + lua_pushnumber(L, (*s_cur)->min); + lua_settable(L, -3); + + lua_pushstring(L, "measure_max"); + lua_pushnumber(L, (*s_cur)->max); + lua_settable(L, -3); + + lua_pushstring(L, "id"); + lua_pushstring(L, (*s_cur)->id); + lua_settable(L, -3); + + lua_settable(L, -3); + + s_cur++; + i++; + } + + lua_setglobal(L, "sensors"); + + lua_fpath = malloc(strlen(www_dir) + strlen(url) + 1); + strcpy(lua_fpath, www_dir); + strcat(lua_fpath, url); + + if (!luaL_loadfile(L, lua_fpath) && !lua_pcall(L, 0, 1, 0)) + page = strdup(lua_tostring(L, -1)); + + lua_close(L); + + free(lua_fpath); + + return page; +} + +static int cbk_http_request(void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, void **ptr) +{ + struct psensor **sensors = cls; + static int dummy; + struct MHD_Response *response; + int ret; + char *nurl; + unsigned int resp_code; + char *page = NULL; + + if (strcmp(method, "GET")) + return MHD_NO; /* unexpected method */ + + if (&dummy != *ptr) { + /* The first time only the headers are valid, do not + respond in the first round... */ + *ptr = &dummy; + return MHD_YES; + } + + if (*upload_data_size) + return MHD_NO; /* upload data in a GET!? */ + + *ptr = NULL; /* clear context pointer */ + + nurl = url_normalize(url); + + pthread_mutex_lock(&mutex); + + if (!strcmp(nurl, URL_BASE_API_1_0_SENSORS)) { + page = sensors_to_json_string(sensors); + + } else if (!strncmp(nurl, URL_BASE_API_1_0_SENSORS, + strlen(URL_BASE_API_1_0_SENSORS)) + && nurl[strlen(URL_BASE_API_1_0_SENSORS)] == '/') { + + char *sid = nurl + strlen(URL_BASE_API_1_0_SENSORS) + 1; + struct psensor *s = psensor_list_get_by_id(sensors, sid); + + if (s) + page = sensor_to_json_string(s); + + } else { + page = lua_to_html_page(sensors, nurl); + } + + if (page) { + resp_code = MHD_HTTP_OK; + } else { + page = strdup(PAGE_NOT_FOUND); + resp_code = MHD_HTTP_NOT_FOUND; + } + + pthread_mutex_unlock(&mutex); + + response = MHD_create_response_from_data(strlen(page), + (void *)page, MHD_YES, MHD_NO); + + ret = MHD_queue_response(connection, resp_code, response); + MHD_destroy_response(response); + + free(nurl); + + return ret; +} + +int main(int argc, char *argv[]) +{ + float last_used = 0; + float last_total = 0; + struct MHD_Daemon *d; + struct psensor **sensors; + int port = DEFAULT_PORT; + + while (1) { + int c, option_index = 0; + + c = getopt_long(argc, argv, "vhpw:", long_options, + &option_index); + + if (c == -1) + break; + + switch (c) { + + case 0: + break; + + case 'w': + if (optarg) + www_dir = strdup(optarg); + break; + + case 'p': + if (optarg) + port = atoi(optarg); + + break; + + case 'h': + printf("%s\n%s\n\n%s\n\n%s\n", + PSENSOR_SERVER_USAGE, + PSENSOR_SERVER_DESCRIPTION, + PSENSOR_SERVER_OPTIONS, PSENSOR_SERVER_CONTACT); + exit(EXIT_SUCCESS); + + case 'v': + printf("psensor-server %s\n", VERSION); + printf("%s\n", PSENSOR_SERVER_COPYRIGHT); + + exit(EXIT_SUCCESS); + + case '?': + break; + + default: + abort(); + } + } + + if (optind != argc) { + fprintf(stderr, "Invalid usage.\n"); + exit(EXIT_FAILURE); + } + + if (!lmsensor_init()) { + fprintf(stderr, "failed to init lm-sensors\n"); + exit(EXIT_FAILURE); + } + + sensors = get_all_sensors(1); + + if (!sensors || !*sensors) { + fprintf(stderr, "no sensors detected\n"); + exit(EXIT_FAILURE); + } + + d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, + port, + NULL, NULL, &cbk_http_request, sensors, + MHD_OPTION_END); + if (!d) { + fprintf(stderr, "Fail to create web server\n"); + exit(EXIT_FAILURE); + } + + printf("Web server started on port: %d\n", port); + printf("Psensor URL: http://localhost:%d\n", port); + + while (1) { + unsigned long int used = 0; + unsigned long int dt; + + pthread_mutex_lock(&mutex); + +#ifdef HAVE_GTOP + if (!cpu) + cpu = malloc(sizeof(glibtop_cpu)); + + glibtop_get_cpu(cpu); + + used = cpu->user + cpu->nice + cpu->sys; + + dt = cpu->total - last_total; + + if (dt) + cpu_rate = (used - last_used) / dt; + + last_used = used; + last_total = cpu->total; + + psensor_list_update_measures(sensors); +#endif + + pthread_mutex_unlock(&mutex); + sleep(5); + } + + MHD_stop_daemon(d); + +#ifdef HAVE_GTOP + free(cpu); +#endif + + return 0; +} diff --git a/src/httpd/httpd.h b/src/httpd/httpd.h new file mode 100644 index 0000000..c493c2b --- /dev/null +++ b/src/httpd/httpd.h @@ -0,0 +1,26 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_HTTPD_H_ +#define _PSENSOR_HTTPD_H_ + +#define URL_BASE_API_1_0 "/api/1.0" +#define URL_BASE_API_1_0_SENSORS "/api/1.0/sensors" + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..eb10b2f --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,15 @@ +noinst_LIBRARIES = libpsensor.a + +libpsensor_a_CFLAGS = -pedantic -Werror + +libpsensor_a_SOURCES = \ + measure.h measure.c \ + color.h color.c \ + psensor.h psensor.c\ + hdd.h hdd.c\ + nvidia.h \ + lmsensor.h lmsensor.c + +if NVIDIA +libpsensor_a_SOURCES += nvidia.c +endif diff --git a/src/lib/color.c b/src/lib/color.c new file mode 100644 index 0000000..e747701 --- /dev/null +++ b/src/lib/color.c @@ -0,0 +1,99 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#include + +#include "color.h" + +void +color_set(struct color *color, + unsigned int red, unsigned int green, unsigned int blue) +{ + color->red = red; + color->green = green; + color->blue = blue; + + color->f_red = ((double)color->red) / 65535; + color->f_green = ((double)color->green) / 65535; + color->f_blue = ((double)color->blue) / 65535; +} + +struct color *color_new(unsigned int red, unsigned int green, unsigned int blue) +{ + struct color *color = malloc(sizeof(struct color)); + + color_set(color, red, green, blue); + + return color; +} + +struct color *color_dup(struct color *color) +{ + return color_new(color->red, color->green, color->blue); +} + +int is_color(const char *str) +{ + int n = strlen(str); + int i; + + if (n != 13 || str[0] != '#') + return 0; + + for (i = 1; i < n; i++) + if (isxdigit(str[i]) == 0) + return 0; + + return 1; +} + +struct color *string_to_color(const char *str) +{ + char tmp[5]; + unsigned int red, green, blue; + + if (!is_color(str)) + return NULL; + + strncpy(tmp, str + 1, 4); + tmp[4] = '\0'; + red = strtol(tmp, NULL, 16); + + strncpy(tmp, str + 5, 4); + tmp[4] = '\0'; + green = strtol(tmp, NULL, 16); + + strncpy(tmp, str + 9, 4); + tmp[4] = '\0'; + blue = strtol(tmp, NULL, 16); + + return color_new(red, green, blue); +} + +char *color_to_string(struct color *color) +{ + char *str = malloc(1 + 12 + 1); + + sprintf(str, "#%.4x%.4x%.4x", color->red, color->green, color->blue); + + return str; +} diff --git a/src/lib/color.h b/src/lib/color.h new file mode 100644 index 0000000..2ac5525 --- /dev/null +++ b/src/lib/color.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_COLOR_H_ +#define _PSENSOR_COLOR_H_ + +/* Represents a RGB color. + + Contains integer and floating RGB representation to avoid useless +conversion. + + Uses color_set to maintain the coherence of the both + representation. +*/ +struct color { + /* rgb 0..65535 */ + unsigned int red; + unsigned int green; + unsigned int blue; + + /* rgb floating 0..1 */ + double f_red; + double f_green; + double f_blue; +}; + +struct color *color_new(unsigned int red, + unsigned int green, unsigned int blue); + +struct color *color_dup(struct color *); + +void color_set(struct color *, + unsigned int red, unsigned int green, unsigned int blue); + +int is_color(const char *str); + +struct color *string_to_color(const char *str); + +char *color_to_string(struct color *color); + +#endif diff --git a/src/lib/hdd.c b/src/lib/hdd.c new file mode 100644 index 0000000..27fd296 --- /dev/null +++ b/src/lib/hdd.c @@ -0,0 +1,256 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#define _(str) gettext(str) + +/* + Following code is based on GNOME sensors applet code hddtemp-plugin.c + see http://sensors-applet.sourceforge.net/ +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psensor.h" + +#define HDDTEMP_SERVER_IP_ADDRESS "127.0.0.1" +#define HDDTEMP_PORT_NUMBER 7634 +#define HDDTEMP_OUTPUT_BUFFER_LENGTH 4048 + +struct hdd_info { + char *name; + int temp; +}; + +char *hdd_fetch() +{ + int sockfd; + ssize_t n = 1; + int output_length = 0; + char *pc; + char *buffer; + struct sockaddr_in address; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) { + fprintf(stderr, _("ERROR: hdd_fetch, failed to open socket\n")); + return NULL; + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr(HDDTEMP_SERVER_IP_ADDRESS); + address.sin_port = htons(HDDTEMP_PORT_NUMBER); + + buffer = NULL; + + if (connect(sockfd, + (struct sockaddr *)&address, + (socklen_t) sizeof(address)) == -1) { + fprintf(stderr, + _("ERROR: hdd_fetch, failed to open connection\n")); + } else { + buffer = malloc(HDDTEMP_OUTPUT_BUFFER_LENGTH); + + pc = buffer; + while ((n = read(sockfd, + pc, + HDDTEMP_OUTPUT_BUFFER_LENGTH - + output_length)) > 0) { + + output_length += n; + pc = &pc[n]; + } + + buffer[output_length] = '\0'; + } + + close(sockfd); + + return buffer; +} + +int str_index(char *str, char d) +{ + char *c; + int i; + + if (!str || *str == '\0') + return -1; + + c = str; + + i = 0; + while (*c) { + if (*c == d) + return i; + i++; + c++; + } + + return -1; +} + +struct psensor *hdd_create_sensor(char *id, char *name, int values_max_length) +{ + return psensor_create(id, name, SENSOR_TYPE_HDD_TEMP, + values_max_length); +} + +char *next_hdd_info(char *string, struct hdd_info *info) +{ + char *c; + int idx_name_n, i, temp; + + if (!string || strlen(string) <= 5 /* at least 5 pipes */ + || string[0] != '|') + return NULL; + + /* skip first pipe */ + c = string + 1; + + /* name */ + idx_name_n = str_index(c, '|'); + + if (idx_name_n == -1) + return NULL; + c = c + idx_name_n + 1; + + /* skip label */ + i = str_index(c, '|'); + if (i == -1) + return NULL; + c = c + i + 1; + + /* temp */ + i = str_index(c, '|'); + if (i == -1) + return NULL; + temp = atoi(c); + c = c + i + 1; + + /* skip unit */ + i = str_index(c, '|'); + if (i == -1) + return NULL; + c = c + i + 1; + + info->name = malloc(idx_name_n + 1); + strncpy(info->name, string + 1, idx_name_n); + info->name[idx_name_n] = '\0'; + + info->temp = temp; + + return c; +} + +struct psensor **hdd_psensor_list_add(struct psensor **sensors, + int values_max_length) +{ + char *hddtemp_output = hdd_fetch(); + char *c; + struct hdd_info info; + struct psensor **result; + + if (!hddtemp_output) + return sensors; + + if (hddtemp_output[0] != '|') { + fprintf(stderr, + _("ERROR: wrong hdd string: %s"), hddtemp_output); + + free(hddtemp_output); + + return sensors; + } + + c = hddtemp_output; + + result = sensors; + + while (c && (c = next_hdd_info(c, &info))) { + struct psensor *sensor; + struct psensor **tmp_sensors; + + char *id = malloc(strlen("hdd ") + strlen(info.name) + 1); + strcpy(id, "hdd "); + strcat(id, info.name); + + sensor = hdd_create_sensor(id, info.name, values_max_length); + + tmp_sensors = psensor_list_add(result, sensor); + + if (result != sensors) + free(result); + + result = tmp_sensors; + } + + free(hddtemp_output); + + return result; +} + +void hdd_psensor_update(struct psensor **sensors, struct hdd_info *info) +{ + struct psensor **sensor_cur = sensors; + + while (*sensor_cur) { + if ((*sensor_cur)->type == SENSOR_TYPE_HDD_TEMP + && !strcmp((*sensor_cur)->id + 4, info->name)) + psensor_set_current_value(*sensor_cur, + (float)info->temp); + + sensor_cur++; + } +} + +void hdd_psensor_list_update(struct psensor **sensors) +{ + char *hddtemp_output = hdd_fetch(); + + if (!hddtemp_output) + return; + + if (hddtemp_output[0] == '|') { + + char *c = hddtemp_output; + struct hdd_info info; + info.name = NULL; + info.temp = 0; + + while (c && (c = next_hdd_info(c, &info))) { + + hdd_psensor_update(sensors, &info); + + free(info.name); + } + } else { + fprintf(stderr, + _("ERROR: wrong hdd string: %s\n"), hddtemp_output); + } + + free(hddtemp_output); +} diff --git a/src/lib/hdd.h b/src/lib/hdd.h new file mode 100644 index 0000000..0e31b49 --- /dev/null +++ b/src/lib/hdd.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_HDD_H_ +#define _PSENSOR_HDD_H_ + +#include "psensor.h" + +struct psensor **hdd_psensor_list_add(struct psensor **sensors, + int values_max_length); + +void hdd_psensor_list_update(struct psensor **sensors); + +#endif diff --git a/src/lib/lmsensor.c b/src/lib/lmsensor.c new file mode 100644 index 0000000..5149e80 --- /dev/null +++ b/src/lib/lmsensor.c @@ -0,0 +1,172 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#define _(str) gettext(str) + +#include +#include +#include + +#include +#include + +#include "psensor.h" + +double +lmsensor_get_value(const sensors_chip_name *name, + const sensors_subfeature *sub) +{ + double val; + int err; + + err = sensors_get_value(name, sub->number, &val); + if (err) { + fprintf(stderr, + _("ERROR: Can't get value of subfeature %s: %s\n"), + sub->name, sensors_strerror(err)); + val = UNKNOWN_VALUE; + } + return val; +} + +double lmsensor_get_temp_input(struct psensor *sensor) +{ + const sensors_chip_name *chip = sensor->iname; + const sensors_feature *feature = sensor->feature; + + const sensors_subfeature *sf; + + sf = sensors_get_subfeature(chip, + feature, SENSORS_SUBFEATURE_TEMP_INPUT); + if (sf) + return lmsensor_get_value(chip, sf); + else + return UNKNOWN_VALUE; +} + +double lmsensor_get_fan_input(struct psensor *sensor) +{ + const sensors_chip_name *chip = sensor->iname; + const sensors_feature *feature = sensor->feature; + + const sensors_subfeature *sf; + + sf = sensors_get_subfeature(chip, + feature, SENSORS_SUBFEATURE_FAN_INPUT); + if (sf) + return lmsensor_get_value(chip, sf); + else + return UNKNOWN_VALUE; +} + +void lmsensor_psensor_list_update(struct psensor **sensors) +{ + struct psensor **s_ptr = sensors; + + while (*s_ptr) { + struct psensor *sensor = *s_ptr; + + if (sensor->type == SENSOR_TYPE_LMSENSOR_TEMP) + psensor_set_current_value + (sensor, lmsensor_get_temp_input(sensor)); + else if (sensor->type == SENSOR_TYPE_LMSENSOR_FAN) + psensor_set_current_value + (sensor, lmsensor_get_fan_input(sensor)); + + s_ptr++; + } +} + +struct psensor * +lmsensor_psensor_create(const sensors_chip_name *chip, + const sensors_feature *feature, + int values_max_length) +{ + char name[200]; + const sensors_subfeature *sf; + char *label; + int type; + char *id; + struct psensor *psensor; + sensors_subfeature_type fault_subfeature; + + if (sensors_snprintf_chip_name(name, 200, chip) < 0) + return NULL; + + if (feature->type == SENSORS_FEATURE_TEMP) { + fault_subfeature = SENSORS_SUBFEATURE_TEMP_FAULT; + + } else if (feature->type == SENSORS_FEATURE_FAN) { + fault_subfeature = SENSORS_SUBFEATURE_FAN_FAULT; + + } else { + fprintf(stderr, + _("ERROR: create_sensor, wrong feature type\n")); + return NULL; + } + + sf = sensors_get_subfeature(chip, feature, fault_subfeature); + if (sf && lmsensor_get_value(chip, sf)) + return NULL; + + label = sensors_get_label(chip, feature); + if (!label) + return NULL; + + type = 0; + if (feature->type == SENSORS_FEATURE_TEMP) + type = SENSOR_TYPE_LMSENSOR_TEMP; + else if (feature->type == SENSORS_FEATURE_FAN) + type = SENSOR_TYPE_LMSENSOR_FAN; + else + return NULL; + + id = malloc(strlen("lmsensor ") + 1 + strlen(name) + 1 + strlen(label) + + 1); + sprintf(id, "lmsensor %s %s", name, label); + + psensor = psensor_create(id, label, type, values_max_length); + + psensor->iname = chip; + psensor->feature = feature; + + if (feature->type == SENSORS_FEATURE_TEMP + && (lmsensor_get_temp_input(psensor) == UNKNOWN_VALUE)) { + free(psensor); + return NULL; + } + + return psensor; +} + +int lmsensor_init() +{ + int err = sensors_init(NULL); + + if (err) { + fprintf(stderr, + _("ERROR: lm-sensors initialization failure: %s\n"), + sensors_strerror(err)); + return 0; + } else { + return 1; + } +} diff --git a/src/lib/lmsensor.h b/src/lib/lmsensor.h new file mode 100644 index 0000000..3efe6ed --- /dev/null +++ b/src/lib/lmsensor.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_LMSENSOR_H_ +#define _PSENSOR_LMSENSOR_H_ + +#include + +struct psensor *lmsensor_psensor_create(const sensors_chip_name *chip, + const sensors_feature *feature, + int values_max_length); +int lmsensor_init(); +void lmsensor_psensor_list_update(struct psensor **sensors); + +#endif diff --git a/src/lib/measure.c b/src/lib/measure.c new file mode 100644 index 0000000..7dcacc3 --- /dev/null +++ b/src/lib/measure.c @@ -0,0 +1,48 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "measure.h" + +struct measure *measures_create(int size) +{ + int i; + struct measure *result; + + result = malloc(size * sizeof(struct measure)); + + for (i = 0; i < size; i++) { + result[i].value = UNKNOWN_VALUE; + timerclear(&result[i].time); + } + + return result; +} + +void measures_free(struct measure *measures) +{ + free(measures); +} + +void measure_copy(struct measure *src, struct measure *dst) +{ + dst->time = src->time; + dst->value = src->value; +} diff --git a/src/lib/measure.h b/src/lib/measure.h new file mode 100644 index 0000000..f1380a5 --- /dev/null +++ b/src/lib/measure.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_MEASURE_H_ +#define _PSENSOR_MEASURE_H_ + +#include +#include + +#define UNKNOWN_VALUE DBL_MIN + +struct measure { + double value; + struct timeval time; +}; + +void measure_copy(struct measure *src, struct measure *dst); + +struct measure *measures_create(int size); + +void measures_free(struct measure *measures); + +#endif diff --git a/src/lib/nvidia.c b/src/lib/nvidia.c new file mode 100644 index 0000000..4a74bbf --- /dev/null +++ b/src/lib/nvidia.c @@ -0,0 +1,150 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#define _(str) gettext(str) + +#include +#include +#include + +#include + +#include +#include + + +#include "psensor.h" + +Display *nvidia_sensors_dpy; + +int nvidia_get_sensor_temp(struct psensor *sensor) +{ + int temp; + Bool res; + + res = XNVCTRLQueryTargetAttribute(nvidia_sensors_dpy, + NV_CTRL_TARGET_TYPE_GPU, + sensor->nvidia_id, + 0, + NV_CTRL_GPU_CORE_TEMPERATURE, &temp); + + if (res == True) { + return temp; + } else { + fprintf(stderr, + _("ERROR: failed to retrieve nvidia temperature\n")); + return 0; + } +} + +struct psensor *nvidia_create_sensor(int id, int values_max_length) +{ + char name[200]; + char *sid; + struct psensor *s; + + sprintf(name, "GPU%d", id); + + sid = malloc(strlen("nvidia") + 1 + strlen(name) + 1); + sprintf(sid, "nvidia %s", name); + + s = psensor_create(sid, strdup(name), + SENSOR_TYPE_NVIDIA, values_max_length); + + s->nvidia_id = id; + + return s; +} + +int nvidia_init() +{ + int event_base, error_base; + int num_gpus; + + nvidia_sensors_dpy = XOpenDisplay(NULL); + + if (!nvidia_sensors_dpy) { + fprintf(stderr, _("ERROR: nvidia initialization failure\n")); + return 0; + } + + if (XNVCTRLQueryExtension(nvidia_sensors_dpy, &event_base, + &error_base)) { + if (XNVCTRLQueryTargetCount(nvidia_sensors_dpy, + NV_CTRL_TARGET_TYPE_GPU, + &num_gpus)) { + return num_gpus; + } + + } + + fprintf(stderr, _("ERROR: nvidia initialization failure: %d\n"), + error_base); + + return 0; +} + +void nvidia_psensor_list_update(struct psensor **sensors) +{ + struct psensor **s_ptr = sensors; + + while (*s_ptr) { + struct psensor *sensor = *s_ptr; + + if (sensor->type == SENSOR_TYPE_NVIDIA) { + int val = nvidia_get_sensor_temp(sensor); + + psensor_set_current_value(sensor, (double)val); + } + + s_ptr++; + } +} + +struct psensor **nvidia_psensor_list_add(struct psensor **sensors, + int values_max_length) +{ + int i; + int nvidia_gpus_count = nvidia_init(); + struct psensor **res = sensors; + + + if (!nvidia_gpus_count) { + fprintf(stderr, + _("ERROR: " + "no nvidia chips or initialization failure\n")); + } + + for (i = 0; i < nvidia_gpus_count; i++) { + struct psensor *sensor + = nvidia_create_sensor(i, values_max_length); + + struct psensor **tmp_psensors = psensor_list_add(res, + sensor); + + if (res != sensors) + free(res); + + res = tmp_psensors; + } + + return res; +} diff --git a/src/lib/nvidia.h b/src/lib/nvidia.h new file mode 100644 index 0000000..8a9e4e7 --- /dev/null +++ b/src/lib/nvidia.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_NVIDIA_H_ +#define _PSENSOR_NVIDIA_H_ + +#include "psensor.h" + +int nvidia_get_sensor_temp(struct psensor *); + +struct psensor *nvidia_create_sensor(int id, int values_max_length); + +int nvidia_init(); + +void nvidia_psensor_list_update(struct psensor **sensors); + + +/* + Adds NVIDIA sensors to a given list of sensors. + + Returns the new allocated list of sensors if sensors have been added otherwise + returns 'sensors'. The list is 'NULL' terminated. + */ +struct psensor **nvidia_psensor_list_add(struct psensor **sensors, + int values_max_length); + + +#endif diff --git a/src/lib/psensor.c b/src/lib/psensor.c new file mode 100644 index 0000000..f735a5e --- /dev/null +++ b/src/lib/psensor.c @@ -0,0 +1,422 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#include + +#include "hdd.h" +#include "psensor.h" +#include "lmsensor.h" + +struct psensor *psensor_create(char *id, char *name, + unsigned int type, int values_max_length) +{ + struct psensor *psensor + = (struct psensor *)malloc(sizeof(struct psensor)); + + psensor->id = id; + psensor->name = name; + psensor->enabled = 1; + psensor->min = UNKNOWN_VALUE; + psensor->max = UNKNOWN_VALUE; + + psensor->type = type; + + psensor->values_max_length = values_max_length; + psensor->measures = measures_create(values_max_length); + + psensor->alarm_limit = 0; + + psensor->cb_alarm_raised = NULL; + psensor->cb_alarm_raised_data = NULL; + psensor->alarm_raised = 0; + + psensor->alarm_enabled = 0; + + psensor->url = NULL; + + psensor->color = NULL; + + return psensor; +} + +void psensor_values_resize(struct psensor *s, int new_size) +{ + struct measure *new_ms, *cur_ms; + int cur_size; + + cur_size = s->values_max_length; + cur_ms = s->measures; + new_ms = measures_create(new_size); + + if (cur_ms) { + int i; + for (i = 0; i < new_size - 1 && i < cur_size - 1; i++) + measure_copy(&cur_ms[cur_size - i - 1], + &new_ms[new_size - i - 1]); + + measures_free(s->measures); + } + + s->values_max_length = new_size; + s->measures = new_ms; +} + +void psensor_free(struct psensor *sensor) +{ + if (sensor) { + free(sensor->name); + free(sensor->id); + + if (sensor->color) + free(sensor->color); + + measures_free(sensor->measures); + + free(sensor->url); + + free(sensor); + } +} + +void psensor_list_free(struct psensor **sensors) +{ + struct psensor **sensor_cur; + + if (sensors) { + sensor_cur = sensors; + + while (*sensor_cur) { + psensor_free(*sensor_cur); + + sensor_cur++; + } + + free(sensors); + + sensors = NULL; + } +} + +int psensor_list_size(struct psensor **sensors) +{ + int size; + struct psensor **sensor_cur; + + if (!sensors) + return 0; + + size = 0; + sensor_cur = sensors; + + while (*sensor_cur) { + size++; + sensor_cur++; + } + return size; +} + +int psensor_list_contains_type(struct psensor **sensors, unsigned int type) +{ + struct psensor **s; + + if (!sensors) + return 0; + + s = sensors; + while (*s) { + if ((*s)->type == type) + return 1; + s++; + } + + return 0; +} + +struct psensor **psensor_list_add(struct psensor **sensors, + struct psensor *sensor) +{ + int size = psensor_list_size(sensors); + + struct psensor **result + = malloc((size + 1 + 1) * sizeof(struct psensor *)); + + if (sensors) + memcpy(result, sensors, size * sizeof(struct psensor *)); + + result[size] = sensor; + result[size + 1] = NULL; + + return result; +} + +struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id) +{ + struct psensor **sensors_cur = sensors; + + while (*sensors_cur) { + if (!strcmp((*sensors_cur)->id, id)) + return *sensors_cur; + + sensors_cur++; + } + + return NULL; +} + +int is_temp_type(unsigned int type) +{ + return type & SENSOR_TYPE_TEMP; +} + +int is_fan_type(unsigned int type) +{ + return type & SENSOR_TYPE_FAN; +} + +char *psensor_value_to_string(unsigned int type, double value) +{ + /* should not be possible to exceed 20 characters with temp or + rpm values the .x part is never displayed */ + char *str = malloc(20); + + char *unit; + + if (is_temp_type(type)) + unit = "C"; + else + unit = ""; + + sprintf(str, "%.0f%s", value, unit); + + return str; +} + +void psensor_set_current_value(struct psensor *sensor, double value) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) + timerclear(&tv); + + psensor_set_current_measure(sensor, value, tv); +} + +void +psensor_set_current_measure(struct psensor *s, + double v, struct timeval tv) +{ + memmove(s->measures, + &s->measures[1], + (s->values_max_length - 1) * sizeof(struct measure)); + + s->measures[s->values_max_length - 1].value = v; + s->measures[s->values_max_length - 1].time = tv; + + if (s->min == UNKNOWN_VALUE || v < s->min) + s->min = v; + + if (s->max == UNKNOWN_VALUE || v > s->max) + s->max = v; + + if (s->alarm_limit && s->alarm_enabled) { + if (v > s->alarm_limit) { + if (!s->alarm_raised && s->cb_alarm_raised) + s->cb_alarm_raised(s, + s->cb_alarm_raised_data); + + s->alarm_raised = 1; + } else { + s->alarm_raised = 0; + } + } +} + +double psensor_get_current_value(struct psensor *sensor) +{ + return sensor->measures[sensor->values_max_length - 1].value; +} + +struct measure *psensor_get_current_measure(struct psensor *sensor) +{ + return &sensor->measures[sensor->values_max_length - 1]; +} + +/* + Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or + SENSOR_TYPE_FAN) + */ +double get_min_value(struct psensor **sensors, int type) +{ + double m = UNKNOWN_VALUE; + struct psensor **s = sensors; + + while (*s) { + struct psensor *sensor = *s; + + if (sensor->enabled && (sensor->type & type)) { + int i; + double t; + + for (i = 0; i < sensor->values_max_length; i++) { + t = sensor->measures[i].value; + + if (t == UNKNOWN_VALUE) + continue; + + if (m == UNKNOWN_VALUE || t < m) + m = t; + } + } + s++; + } + + return m; +} + +/* + Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or + SENSOR_TYPE_FAN) + */ +static double get_max_value(struct psensor **sensors, int type) +{ + double m = UNKNOWN_VALUE; + struct psensor **s = sensors; + + while (*s) { + struct psensor *sensor = *s; + + if (sensor->enabled && (sensor->type & type)) { + int i; + double t; + for (i = 0; i < sensor->values_max_length; i++) { + t = sensor->measures[i].value; + + if (t == UNKNOWN_VALUE) + continue; + + if (m == UNKNOWN_VALUE || t > m) + m = t; + } + } + s++; + } + + return m; +} + +double get_min_temp(struct psensor **sensors) +{ + return get_min_value(sensors, SENSOR_TYPE_TEMP); +} + +double get_min_rpm(struct psensor **sensors) +{ + return get_min_value(sensors, SENSOR_TYPE_FAN); +} + +double get_max_rpm(struct psensor **sensors) +{ + return get_max_value(sensors, SENSOR_TYPE_FAN); +} + +double get_max_temp(struct psensor **sensors) +{ + return get_max_value(sensors, SENSOR_TYPE_TEMP); +} + +struct psensor **get_all_sensors(int values_max_length) +{ + struct psensor **psensors = NULL; + int count = 0; + const sensors_chip_name *chip; + int chip_nr = 0; + struct psensor **tmp_psensors; + const sensors_feature *feature; + struct psensor *psensor; + int i; + + while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) { + i = 0; + while ((feature = sensors_get_features(chip, &i))) { + + if (feature->type == SENSORS_FEATURE_TEMP + || feature->type == SENSORS_FEATURE_FAN) { + + psensor = lmsensor_psensor_create + (chip, feature, values_max_length); + + if (psensor) { + tmp_psensors + = psensor_list_add(psensors, + psensor); + + free(psensors); + + psensors = tmp_psensors; + + count++; + } + } + } + } + + tmp_psensors = hdd_psensor_list_add(psensors, values_max_length); + + if (tmp_psensors != psensors) { + free(psensors); + psensors = tmp_psensors; + } + + if (!psensors) { /* there is no detected sensors */ + psensors = malloc(sizeof(struct psensor *)); + *psensors = NULL; + } + + return psensors; +} + +const char *psensor_type_to_str(unsigned int type) +{ + if (type & SENSOR_TYPE_REMOTE) + return "Remote"; + + if (type & SENSOR_TYPE_LMSENSOR_TEMP) + return "Temperature"; + + if (type & SENSOR_TYPE_LMSENSOR_FAN) + return "Fan"; + + if (type & SENSOR_TYPE_NVIDIA) + return "NVidia GPU Temperature"; + + if (type & SENSOR_TYPE_HDD_TEMP) + return "HDD Temperature"; + + return "N/A"; /* should not be possible */ +} + +void psensor_list_update_measures(struct psensor **sensors) +{ + lmsensor_psensor_list_update(sensors); + hdd_psensor_list_update(sensors); +} diff --git a/src/lib/psensor.h b/src/lib/psensor.h new file mode 100644 index 0000000..ad7364e --- /dev/null +++ b/src/lib/psensor.h @@ -0,0 +1,155 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_PSENSOR_H_ +#define _PSENSOR_PSENSOR_H_ + +#include "config.h" +#include + +#include "color.h" +#include "measure.h" + +enum psensor_type { + SENSOR_TYPE_TEMP = 0x0001, + SENSOR_TYPE_FAN = 0x0002, + SENSOR_TYPE_REMOTE = 0x0004, + + SENSOR_TYPE_LMSENSOR_TEMP = 0x0100 | SENSOR_TYPE_TEMP, + SENSOR_TYPE_NVIDIA = 0x0200 | SENSOR_TYPE_TEMP, + SENSOR_TYPE_HDD_TEMP = 0x0300 | SENSOR_TYPE_TEMP, + SENSOR_TYPE_LMSENSOR_FAN = 0x0400 | SENSOR_TYPE_FAN +}; + +struct psensor { + /* Human readable name of the sensor. It may not be uniq. */ + char *name; + + /* Uniq id of the sensor */ + char *id; + + /* lm-sensor */ + const sensors_chip_name *iname; + const sensors_feature *feature; + + /* Maximum length of 'values' */ + int values_max_length; + + /* Last registered measures of the sensor. Index 0 for the + oldest measure. */ + struct measure *measures; + + /* Color of the sensor used for the graph */ + struct color *color; + + /* Whether the sensor is displayed in the graph */ + int enabled; + + /* see psensor_type */ + unsigned int type; + + /* The maximum detected value of the sensor */ + double max; + + /* The minimum detected value of the sensor */ + double min; + + /* + Whether alarm alerts is enabled for this sensor + */ + int alarm_enabled; + + /* + An alarm is raised if the current sensor value is bigger. 0 + means no limit + */ + double alarm_limit; + + /* Whether the current value is bigger than 'alarm_limit'. */ + int alarm_raised; + + void (*cb_alarm_raised) (struct psensor *, void *); + void *cb_alarm_raised_data; + +#ifdef HAVE_NVIDIA + /* Nvidia id for the nvctrl */ + int nvidia_id; +#endif + + char *url; + +}; + +struct psensor *psensor_create(char *id, + char *name, unsigned int type, + int values_max_length); + +void psensor_values_resize(struct psensor *s, int new_size); + +void psensor_free(struct psensor *sensor); + +void psensor_list_free(struct psensor **sensors); +int psensor_list_size(struct psensor **sensors); + +struct psensor *psensor_list_get_by_id(struct psensor **sensors, + const char *id); + +/* + Return 1 if there is at least one sensor of a given type, else + returns 0 */ +int psensor_list_contains_type(struct psensor **sensors, unsigned int type); + +int is_temp_type(unsigned int type); +int is_fan_type(unsigned int type); + +double get_min_temp(struct psensor **sensors); +double get_max_temp(struct psensor **sensors); + +double get_min_rpm(struct psensor **sensors); +double get_max_rpm(struct psensor **sensors); + +/* + Converts the value of a sensor to a string. + + parameter 'type' is SENSOR_TYPE_LMSENSOR_TEMP, SENSOR_TYPE_NVIDIA, + or SENSOR_TYPE_LMSENSOR_FAN +*/ +char *psensor_value_to_string(unsigned int type, double value); + +struct psensor **get_all_sensors(int values_max_length); + +struct psensor **psensor_list_add(struct psensor **sensors, + struct psensor *sensor); + +void psensor_set_current_value(struct psensor *sensor, double value); +void psensor_set_current_measure(struct psensor *sensor, double value, + struct timeval tv); + +double psensor_get_current_value(struct psensor *sensor); + +struct measure *psensor_get_current_measure(struct psensor *sensor); + +/* + Returns a string representation of a psensor type. +*/ +const char *psensor_type_to_str(unsigned int type); + +void psensor_list_update_measures(struct psensor **sensors); + +#endif diff --git a/src/libpsensor_json/Makefile.am b/src/libpsensor_json/Makefile.am new file mode 100644 index 0000000..a85c829 --- /dev/null +++ b/src/libpsensor_json/Makefile.am @@ -0,0 +1,12 @@ +noinst_LIBRARIES = libpsensor_json.a + +libpsensor_json_a_CFLAGS = -pedantic -Werror + +libpsensor_json_a_SOURCES = \ + psensor_json.h psensor_json.c + +LIBS = ../lib/libpsensor.a \ + $(JSON_LIBS) + +AM_CPPFLAGS = $(JSON_CFLAGS) -I$(top_srcdir)/src/lib + diff --git a/src/libpsensor_json/psensor_json.c b/src/libpsensor_json/psensor_json.c new file mode 100644 index 0000000..b476439 --- /dev/null +++ b/src/libpsensor_json/psensor_json.c @@ -0,0 +1,99 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "psensor_json.h" + +#define ATT_SENSOR_ID "id" +#define ATT_SENSOR_NAME "name" +#define ATT_SENSOR_TYPE "type" +#define ATT_SENSOR_MIN "min" +#define ATT_SENSOR_MAX "max" +#define ATT_SENSOR_LAST_MEASURE "last_measure" +#define ATT_MEASURE_VALUE "value" +#define ATT_MEASURE_TIME "time" + +json_object *sensor_to_json_object(struct psensor *s) +{ + json_object *mo; + json_object *obj = json_object_new_object(); + struct measure *m; + + json_object_object_add(obj, + ATT_SENSOR_ID, + json_object_new_string(s->id)); + json_object_object_add(obj, + ATT_SENSOR_NAME, + json_object_new_string(s->name)); + json_object_object_add(obj, + ATT_SENSOR_TYPE, json_object_new_int(s->type)); + json_object_object_add(obj, + ATT_SENSOR_MIN, json_object_new_double(s->min)); + json_object_object_add(obj, + ATT_SENSOR_MAX, json_object_new_double(s->max)); + + m = psensor_get_current_measure(s); + mo = json_object_new_object(); + json_object_object_add(mo, + ATT_MEASURE_VALUE, + json_object_new_double(m->value)); + json_object_object_add(mo, ATT_MEASURE_TIME, + json_object_new_int((m->time).tv_sec)); + json_object_object_add(obj, ATT_SENSOR_LAST_MEASURE, mo); + + return obj; +} + +char *sensor_to_json_string(struct psensor *s) +{ + char *str; + json_object *obj = sensor_to_json_object(s); + + str = strdup(json_object_to_json_string(obj)); + + json_object_put(obj); + + return str; +} + +char *sensors_to_json_string(struct psensor **sensors) +{ + struct psensor **sensors_cur; + char *str; + + json_object *obj = json_object_new_array(); + + sensors_cur = sensors; + + while (*sensors_cur) { + struct psensor *s = *sensors_cur; + + json_object_array_add(obj, sensor_to_json_object(s)); + + sensors_cur++; + } + + str = strdup(json_object_to_json_string(obj)); + + json_object_put(obj); + + return str; +} + diff --git a/src/libpsensor_json/psensor_json.h b/src/libpsensor_json/psensor_json.h new file mode 100644 index 0000000..c97e6f6 --- /dev/null +++ b/src/libpsensor_json/psensor_json.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_PSENSOR_JSON_H_ +#define _PSENSOR_PSENSOR_JSON_H_ + +#include + +#include "psensor.h" + +json_object *sensor_to_json_object(struct psensor *s); +char *sensor_to_json_string(struct psensor *s); +char *sensors_to_json_string(struct psensor **sensors); + + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3a092a8 --- /dev/null +++ b/src/main.c @@ -0,0 +1,420 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#include +#include +#include + +#include + +#include +#include + +#include "config.h" + +#include "cfg.h" +#include "hdd.h" +#include "psensor.h" +#include "graph.h" +#include "ui.h" +#include "ui_sensorlist.h" +#include "ui_color.h" +#include "lmsensor.h" +#include "ui_pref.h" +#include "ui_graph.h" + +#ifdef HAVE_UNITY +#include "ui_unity.h" +#endif + +#ifdef HAVE_NVIDIA +#include "nvidia.h" +#endif + +#ifdef HAVE_REMOTE_SUPPORT +#include "rsensor.h" +#endif + +#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029) +#include "ui_appindicator.h" +#endif + +#ifdef HAVE_LIBNOTIFY +#include "ui_notify.h" +#endif + +#include "compat.h" + +static const char *program_name; + +void print_version() +{ + printf("psensor %s\n", VERSION); + printf(_("Copyright (C) %s wpitchoune@gmail.com\n\ +License GPLv2: GNU GPL version 2 or later \ +\n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n"), + "2010-2011"); +} + +void print_help() +{ + printf(_("Usage: %s [OPTION]...\n"), program_name); + + puts(_("psensor is a GTK application for monitoring hardware sensors, " + "including temperatures and fan speeds.")); + + puts(""); + puts(_("Options:")); + puts(_("\ + -h, --help display this help and exit\n\ + -v, --version display version information and exit")); + + puts(""); + + puts(_("\ + -u, --url=URL \ +the URL of the psensor-server, example: http://hostname:3131")); + + puts(""); + + printf(_("Report bugs to: %s\n"), PACKAGE_BUGREPORT); + puts(""); + printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); +} + +/* + Updates the size of the sensor values if different than the + configuration. + */ +void +update_psensor_values_size(struct psensor **sensors, struct config *cfg) +{ + struct psensor **cur; + + cur = sensors; + while (*cur) { + struct psensor *s = *cur; + + if (s->values_max_length != cfg->sensor_values_max_length) + psensor_values_resize(s, + cfg->sensor_values_max_length); + + cur++; + } +} + +void update_psensor_measures(struct ui_psensor *ui) +{ + struct psensor **sensors = ui->sensors; + struct config *cfg = ui->config; + + while (1) { + /*gdk_threads_enter();*/ + g_mutex_lock(ui->sensors_mutex); + + if (!sensors) + return; + + update_psensor_values_size(sensors, ui->config); + + psensor_list_update_measures(sensors); +#ifdef HAVE_REMOTE_SUPPORT + remote_psensor_list_update(sensors); +#endif +#ifdef HAVE_NVIDIA + nvidia_psensor_list_update(sensors); +#endif + + /*gdk_threads_leave();*/ + g_mutex_unlock(ui->sensors_mutex); + + sleep(cfg->sensor_update_interval); + } +} + +gboolean ui_refresh_thread(gpointer data) +{ + struct config *cfg; + gboolean ret; + struct ui_psensor *ui = (struct ui_psensor *)data; + + ret = TRUE; + cfg = ui->config; + + g_mutex_lock(ui->sensors_mutex); + /*gdk_threads_enter();*/ + + graph_update(ui->sensors, ui->w_graph, ui->config); + + ui_sensorlist_update(ui->ui_sensorlist); + +#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029) + ui_appindicator_update(ui); +#endif + +#ifdef HAVE_UNITY + ui_unity_launcher_entry_update(ui->sensors); +#endif + + if (ui->graph_update_interval != cfg->graph_update_interval) { + ui->graph_update_interval = cfg->graph_update_interval; + ret = FALSE; + } + + g_mutex_unlock(ui->sensors_mutex); + /*gdk_threads_leave();*/ + + if (ret == FALSE) + g_timeout_add(1000 * ui->graph_update_interval, + ui_refresh_thread, ui); + + return ret; +} + +void cb_alarm_raised(struct psensor *sensor, void *data) +{ +#ifdef HAVE_LIBNOTIFY + if (sensor->enabled) + ui_notify(sensor, (struct ui_psensor *)data); +#endif +} + +void associate_colors(struct psensor **sensors) +{ + /* number of uniq colors */ +#define COLORS_COUNT 8 + + unsigned int colors[COLORS_COUNT][3] = { + {0x0000, 0x0000, 0x0000}, /* black */ + {0xffff, 0x0000, 0x0000}, /* red */ + {0x0000, 0.0000, 0xffff}, /* blue */ + {0x0000, 0xffff, 0x0000}, /* green */ + + {0x7fff, 0x7fff, 0x7fff}, /* grey */ + {0x7fff, 0x0000, 0x0000}, /* dark red */ + {0x0000, 0x0000, 0x7fff}, /* dark blue */ + {0x0000, 0x7fff, 0x0000} /* dark green */ + }; + + struct psensor **sensor_cur = sensors; + int i = 0; + while (*sensor_cur) { + struct color default_color; + color_set(&default_color, + colors[i % COLORS_COUNT][0], + colors[i % COLORS_COUNT][1], + colors[i % COLORS_COUNT][2]); + + (*sensor_cur)->color + = config_get_sensor_color((*sensor_cur)->id, + &default_color); + + sensor_cur++; + i++; + } +} + +void +associate_cb_alarm_raised(struct psensor **sensors, struct ui_psensor *ui) +{ + struct psensor **sensor_cur = sensors; + while (*sensor_cur) { + struct psensor *s = *sensor_cur; + + s->cb_alarm_raised = cb_alarm_raised; + s->cb_alarm_raised_data = ui; + + if (is_temp_type(s->type)) { + s->alarm_limit + = config_get_sensor_alarm_limit(s->id, 60); + s->alarm_enabled + = config_get_sensor_alarm_enabled(s->id); + } else { + s->alarm_limit = 0; + s->alarm_enabled = 0; + } + + sensor_cur++; + } +} + +void associate_preferences(struct psensor **sensors) +{ + struct psensor **sensor_cur = sensors; + while (*sensor_cur) { + char *n; + struct psensor *s = *sensor_cur; + + s->enabled = config_is_sensor_enabled(s->id); + + n = config_get_sensor_name(s->id); + + if (n) + s->name = n; + + sensor_cur++; + } +} + + +static struct option long_options[] = { + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"url", required_argument, 0, 'u'}, + {0, 0, 0, 0} +}; + +int main(int argc, char **argv) +{ + struct ui_psensor ui; + GError *error; + GThread *thread; + int err, optc; + char *url = NULL; + int cmdok = 1; + + program_name = argv[0]; + + setlocale(LC_ALL, ""); + +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + + while ((optc = getopt_long(argc, argv, "vhu:", long_options, + NULL)) != -1) { + switch (optc) { + case 'u': + if (optarg) + url = strdup(optarg); + break; + case 'h': + print_help(); + exit(EXIT_SUCCESS); + case 'v': + print_version(); + exit(EXIT_SUCCESS); + default: + cmdok = 0; + break; + } + } + + if (!cmdok || optind != argc) { + fprintf(stderr, _("Try `%s --help' for more information.\n"), + program_name); + exit(EXIT_FAILURE); + } + + g_thread_init(NULL); + gdk_threads_init(); + /* gdk_threads_enter(); */ + + gtk_init(&argc, &argv); + +#ifdef HAVE_LIBNOTIFY + ui.notification_last_time = NULL; +#endif + + ui.sensors_mutex = g_mutex_new(); + + config_init(); + + ui.config = config_load(); + + err = lmsensor_init(); + if (!err) { + fprintf(stderr, _("ERROR: lmsensor init failure: %s\n"), + sensors_strerror(err)); + exit(EXIT_FAILURE); + } + + if (url) { +#ifdef HAVE_REMOTE_SUPPORT + rsensor_init(); + ui.sensors = get_remote_sensors(url, 600); +#else + fprintf(stderr, + _("ERROR: Not compiled with remote sensor support.\n")); + exit(EXIT_FAILURE); +#endif + } else { +#ifdef HAVE_NVIDIA + struct psensor **tmp; + + tmp = get_all_sensors(600); + ui.sensors = nvidia_psensor_list_add(tmp, 600); + + if (tmp != ui.sensors) + free(tmp); +#else + ui.sensors = get_all_sensors(600); +#endif + } + + associate_preferences(ui.sensors); + associate_colors(ui.sensors); + associate_cb_alarm_raised(ui.sensors, &ui); + + /* main window */ + ui.main_window = ui_window_create(&ui); + ui.main_box = NULL; + + /* drawing box */ + ui.w_graph = ui_graph_create(&ui); + + /* sensor list */ + ui.ui_sensorlist = ui_sensorlist_create(ui.sensors); + + ui_main_box_create(&ui); + + gtk_widget_show_all(ui.main_window); + + thread = g_thread_create((GThreadFunc) update_psensor_measures, + &ui, TRUE, &error); + + if (!thread) + g_error_free(error); + + ui.graph_update_interval = ui.config->graph_update_interval; + + g_timeout_add(1000 * ui.graph_update_interval, ui_refresh_thread, &ui); + +#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029) + ui_appindicator_init(&ui); +#endif + + /* main loop */ + gtk_main(); + + sensors_cleanup(); + + psensor_list_free(ui.sensors); + + /* gdk_threads_leave(); */ + + return 0; +} diff --git a/src/plib/Makefile.am b/src/plib/Makefile.am new file mode 100644 index 0000000..6b6dd69 --- /dev/null +++ b/src/plib/Makefile.am @@ -0,0 +1,21 @@ + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src + +noinst_LIBRARIES = libplib.a + +libplib_a_CFLAGS = -pedantic + +libplib_a_SOURCES = \ + url.c url.h \ + plib_io.h plib_io.c + +if LUA +noinst_LIBRARIES += libplib_luatpl.a + +libplib_luatpl_a_CFLAGS = -pedantic \ + $(LUA_CFLAGS) + +libplib_luatpl_a_SOURCES = \ + plib_luatpl.h plib_luatpl.c +endif \ No newline at end of file diff --git a/src/plib/plib_io.c b/src/plib/plib_io.c new file mode 100644 index 0000000..7396ad0 --- /dev/null +++ b/src/plib/plib_io.c @@ -0,0 +1,297 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#include +#include + +#include "plib_io.h" + +int is_dir(const char *path) +{ + struct stat st; + + int ret = lstat(path, &st); + + if (ret == 0 && S_ISDIR(st.st_mode)) + return 1; + + return 0; +} + +int is_file(const char *path) +{ + struct stat st; + + int ret = lstat(path, &st); + + if (ret == 0 && S_ISREG(st.st_mode)) + return 1; + + return 0; +} + +char *dir_normalize(const char *dpath) +{ + char *npath; + int n; + + if (!dpath || !strlen(dpath)) + return NULL; + + npath = strdup(dpath); + + n = strlen(npath); + + if (n > 1 && npath[n - 1] == '/') + npath[n - 1] = '\0'; + + return npath; +} + +char **dir_list(const char *dpath, int (*filter) (const char *path)) +{ + struct dirent *ent; + DIR *dir; + char **paths; + int n; + + dir = opendir(dpath); + + if (!dir) + return NULL; + + n = 1; + paths = malloc(sizeof(void *)); + *paths = NULL; + + while ((ent = readdir(dir)) != NULL) { + char *fpath; + char *name = ent->d_name; + + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + + fpath = malloc(strlen(dpath) + 1 + strlen(name) + 1); + + strcpy(fpath, dpath); + strcat(fpath, "/"); + strcat(fpath, name); + + if (!filter || filter(fpath)) { + char **npaths; + + n++; + npaths = malloc(n * sizeof(void *)); + memcpy(npaths + 1, paths, (n - 1) * sizeof(void *)); + free(paths); + paths = npaths; + *npaths = fpath; + + } else { + free(fpath); + } + } + + closedir(dir); + + return paths; +} + +void paths_free(char **paths) +{ + char **paths_cur; + + paths_cur = paths; + while (*paths_cur) { + free(*paths_cur); + + paths_cur++; + } + + free(paths); +} + +char *file_get_content(const char *fpath) +{ + long size; + + char *page; + + size = file_get_size(fpath); + + if (size == -1) { + page = NULL; + + } else if (size == 0) { + page = malloc(1); + *page = '\0'; + + } else { + FILE *fp = fopen(fpath, "rb"); + if (fp) { + page = malloc(size + 1); + if (!page || size != fread(page, 1, size, fp)) { + free(page); + return NULL; + } + + *(page + size) = '\0'; + + fclose(fp); + } else { + page = NULL; + } + } + + return page; +} + +long file_get_size(const char *path) +{ + FILE *fp; + + if (!is_file(path)) + return -1; + + fp = fopen(path, "rb"); + if (fp) { + long size; + + if (fseek(fp, 0, SEEK_END) == -1) + return -1; + + size = ftell(fp); + + fclose(fp); + + return size; + } + + return -1; +} + +#define FCOPY_BUF_SZ 4096 +static int FILE_copy(FILE *src, FILE *dst) +{ + int ret = 0; + char *buf = malloc(FCOPY_BUF_SZ); + int n; + + if (!buf) + return FILE_COPY_ERROR_ALLOC_BUFFER; + + while (!ret) { + n = fread(buf, 1, FCOPY_BUF_SZ, src); + if (n) { + if (fwrite(buf, 1, n, dst) != n) + ret = FILE_COPY_ERROR_WRITE; + } else { + if (!feof(src)) + ret = FILE_COPY_ERROR_READ; + else + break; + } + } + + free(buf); + + return ret; +} + +int +file_copy(const char *src, const char *dst) +{ + FILE *fsrc, *fdst; + int ret = 0; + + fsrc = fopen(src, "r"); + + if (fsrc) { + fdst = fopen(dst, "w+"); + + if (fdst) { + ret = FILE_copy(fsrc, fdst); + fclose(fdst); + } else { + ret = FILE_COPY_ERROR_OPEN_DST; + } + + fclose(fsrc); + } else { + ret = FILE_COPY_ERROR_OPEN_SRC; + } + + return ret; +} + +char *path_append(const char *dir, const char *path) +{ + char *ret, *ndir; + + ndir = dir_normalize(dir); + + if (!ndir && (!path || !strlen(path))) + ret = NULL; + + else if (!ndir) { + ret = strdup(path); + + } else if (!path || !strlen(path)) { + return ndir; + + } else { + ret = malloc(strlen(ndir) + 1 + strlen(path) + 1); + strcpy(ret, ndir); + strcat(ret, "/"); + strcat(ret, path); + } + + free(ndir); + + return ret; +} + +void +file_copy_print_error(int code, const char *src, const char *dst) +{ + switch (code) { + case 0: + break; + case FILE_COPY_ERROR_OPEN_SRC: + printf("File copy error: failed to open %s.\n", src); + break; + case FILE_COPY_ERROR_OPEN_DST: + printf("File copy error: failed to open %s.\n", dst); + break; + case FILE_COPY_ERROR_READ: + printf("File copy error: failed to read %s.\n", src); + break; + case FILE_COPY_ERROR_WRITE: + printf("File copy error: failed to write %s.\n", src); + break; + case FILE_COPY_ERROR_ALLOC_BUFFER: + printf("File copy error: failed to allocate buffer.\n"); + break; + default: + printf("File copy error: unknown error %d.\n", code); + } +} diff --git a/src/plib/plib_io.h b/src/plib/plib_io.h new file mode 100644 index 0000000..a20d76e --- /dev/null +++ b/src/plib/plib_io.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _P_IO_H +#define _P_IO_H + +/* Returns '1' if a given 'path' denotates a directory else returns + 0 */ +int is_dir(const char *path); + +/* Returns '1' if a given 'path' denotates a file else returns + 0 */ +int is_file(const char *path); + +/* Returns a normalized path */ +char *path_normalize(const char *dpath); + +/* Returns the null-terminated entries of a directory */ +char **dir_list(const char *dpath, int (*filter) (const char *path)); +void paths_free(char **paths); + +char *path_append(const char *dir, const char *path); + +/* + Returns the size of a file. + Returns '-1' if the size cannot be retrieved or not a file. +*/ +long file_get_size(const char *path); + +/* + Returns the content of a file. + Returns 'NULL' if the file cannot be read or failed to allocate + enough memory. + Returns an empty string if the file exists but is empty. +*/ +char *file_get_content(const char *path); + +enum file_copy_error { + FILE_COPY_ERROR_OPEN_SRC = 1, + FILE_COPY_ERROR_OPEN_DST, + FILE_COPY_ERROR_READ, + FILE_COPY_ERROR_WRITE, + FILE_COPY_ERROR_ALLOC_BUFFER +}; + +void file_copy_print_error(int code, const char *src, const char *dst); + +/* + Copy a file. + + Returns '0' if sucessfull, otherwise return the error code. +*/ +int file_copy(const char *src, const char *dst); + +#endif diff --git a/src/plib/plib_luatpl.c b/src/plib/plib_luatpl.c new file mode 100644 index 0000000..dd46213 --- /dev/null +++ b/src/plib/plib_luatpl.c @@ -0,0 +1,157 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#define _(str) gettext(str) + +#include +#include + +#include +#include + +#include "plib_luatpl.h" + +char * +luatpl_generate(const char *lua, + int (*init) (lua_State *, void *), + void *init_data, + struct luatpl_error *err) +{ + lua_State *L; + char *page = NULL; + + L = lua_open(); + if (!L) { + err->code = LUATPL_ERROR_LUA_STATE_OPEN; + return NULL; + } + + luaL_openlibs(L); + + if (!init || init(L, init_data)) { + + if (!luaL_loadfile(L, lua)) { + if (!lua_pcall(L, 0, 1, 0)) { + if (lua_isstring(L, -1)) + page = strdup(lua_tostring(L, -1)); + else + err->code = + LUATPL_ERROR_WRONG_RETURN_TYPE; + } else { + err->code = LUATPL_ERROR_LUA_EXECUTION; + err->message = strdup(lua_tostring(L, -1)); + } + } else { + err->code = LUATPL_ERROR_LUA_FILE_LOAD; + } + } else { + err->code = LUATPL_ERROR_INIT; + } + + lua_close(L); + + return page; +} + +int +luatpl_generate_file(const char *lua, + int (*init) (lua_State *, void *), + void *init_data, + const char *dst_path, + struct luatpl_error *err) +{ + FILE *f; + int ret; + char *content; + + ret = 1; + + content = luatpl_generate(lua, init, init_data, err); + + if (content) { + f = fopen(dst_path, "w"); + + if (f) { + if (fputs(content, f) == EOF) + ret = 0; + + if (fclose(f) == EOF) + ret = 0; + } else { + ret = 0; + } + + free(content); + } else { + ret = 0; + } + + return ret; +} + +void +luatpl_fprint_error(FILE *stream, + const struct luatpl_error *err, + const char *lua, + const char *dst_path) +{ + if (!err || !err->code) + return ; + + switch (err->code) { + case LUATPL_ERROR_LUA_FILE_LOAD: + fprintf(stream, + _("LUATPL Error: failed to load Lua script: %s.\n"), + lua); + break; + + case LUATPL_ERROR_INIT: + fprintf(stream, + _("LUATPL Error: failed to call init function: %s.\n"), + lua); + break; + + case LUATPL_ERROR_LUA_EXECUTION: + fprintf(stream, + _("LUATPL Error:" + "failed to execute Lua script (%s): %s.\n"), + lua, err->message); + break; + + case LUATPL_ERROR_WRONG_RETURN_TYPE: + fprintf(stream, + _("LUATPL Error:" + "lua script (%s) returned a wrong type.\n"), + lua); + break; + + case LUATPL_ERROR_LUA_STATE_OPEN: + fprintf(stream, + _("LUATPL Error:" + "failed to open lua state.\n")); + break; + + + default: + fprintf(stream, + _("LUATPL Error: code: %d.\n"), + err->code); + } +} diff --git a/src/plib/plib_luatpl.h b/src/plib/plib_luatpl.h new file mode 100644 index 0000000..4e36856 --- /dev/null +++ b/src/plib/plib_luatpl.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _P_LUATPL_H +#define _P_LUATPL_H + +#include + +#define LUATPL_ERROR_LUA_FILE_LOAD 1 +#define LUATPL_ERROR_INIT 2 +#define LUATPL_ERROR_LUA_EXECUTION 3 +#define LUATPL_ERROR_WRONG_RETURN_TYPE 4 +#define LUATPL_ERROR_LUA_STATE_OPEN 5 + +struct luatpl_error { + unsigned int code; + + char *message; +}; + +/* + Generates a string which is the result of a Lua script execution. + + The string is retrieved from the top element of the Lua stack + after the Lua script execution. + + If not 'NULL' the 'init' function is called after Lua environment + setup and before Lua script execution. This function typically puts + input information for the Lua script into the stack. + + 'init_data' is passed to the second parameter of 'init' function + + Returns the generated string on success, or NULL on error. + */ +char *luatpl_generate(const char *lua, + int (*init) (lua_State *, void *), + void *init_data, + struct luatpl_error *err); + +/* + Generates a file which is the result of a Lua script execution. + + See luatpl_generate function for 'init', 'init_data', and 'err' + parameters. + + 'dst_path' is the path of the generated file + + Returns '1' on success, or '0' on error. + + */ +int luatpl_generate_file(const char *lua, + int (*init) (lua_State *, void *), + void *init_data, + const char *dst_path, + struct luatpl_error *err); + +void luatpl_fprint_error(FILE *stream, + const struct luatpl_error *err, + const char *lua, + const char *dst_path); + +#endif diff --git a/src/plib/url.c b/src/plib/url.c new file mode 100644 index 0000000..7a87adf --- /dev/null +++ b/src/plib/url.c @@ -0,0 +1,75 @@ +/* + Copyright (C) 2010 wpitchoune@gmail.com + + 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 +*/ + +/* + Part of the following code is based on: + http://www.geekhideout.com/urlcode.shtml +*/ + +#include "plib/url.h" + +#include +#include +#include + +char *url_normalize(const char *url) +{ + int n = strlen(url); + char *ret = strdup(url); + + if (url[n - 1] == '/') + ret[n - 1] = '\0'; + + return ret; +} + +char to_hex(char code) +{ + static char hex[] = "0123456789abcdef"; + return hex[code & 0x0f]; +} + +/* + Returns a url-encoded version of str. +*/ +char *url_encode(const char *str) +{ + char *c, *buf, *pbuf; + + buf = malloc(strlen(str) * 3 + 1); + pbuf = buf; + + c = (char *)str; + + while (*c) { + + if (isalnum(*c) || + *c == '.' || *c == '_' || *c == '-' || *c == '~') + *pbuf++ = *c; + else { + *pbuf++ = '%'; + *pbuf++ = to_hex(*c >> 4); + *pbuf++ = to_hex(*c & 0x0f); + } + c++; + } + *pbuf = '\0'; + + return buf; +} diff --git a/src/plib/url.h b/src/plib/url.h new file mode 100644 index 0000000..53a1406 --- /dev/null +++ b/src/plib/url.h @@ -0,0 +1,26 @@ +/* + Copyright (C) 2010 wpitchoune@gmail.com + + 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 _PLIB_URL_H_ +#define _PLIB_URL_H_ + +char *url_encode(const char *str); +char *url_normalize(const char *url); + +#endif diff --git a/src/rsensor.c b/src/rsensor.c new file mode 100644 index 0000000..7f13c30 --- /dev/null +++ b/src/rsensor.c @@ -0,0 +1,221 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#define _(str) gettext(str) + +#include "plib/url.h" +#include "server/server.h" + +#include +#include +#include + +#include +#include + +#include "rsensor.h" + +struct ucontent { + char *data; + size_t len; +}; + +static CURL *curl; + +size_t cbk_curl(void *buffer, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct ucontent *mem = (struct ucontent *)userp; + + mem->data = realloc(mem->data, mem->len + realsize + 1); + + memcpy(&(mem->data[mem->len]), buffer, realsize); + mem->len += realsize; + mem->data[mem->len] = 0; + + return realsize; +} + +char *create_api_1_0_sensors_url(const char *base_url) +{ + char *nurl = url_normalize(base_url); + int n = strlen(nurl) + strlen(URL_BASE_API_1_0_SENSORS) + 1; + char *ret = malloc(n); + + strcpy(ret, nurl); + strcat(ret, URL_BASE_API_1_0_SENSORS); + + free(nurl); + + return ret; +} + +struct psensor *json_object_to_psensor(json_object * o, + const char *sensors_url, + int values_max_length) +{ + json_object *oid; + json_object *oname; + json_object *otype; + struct psensor *s; + char *eid; + char *url; + + oid = json_object_object_get(o, "id"); + oname = json_object_object_get(o, "name"); + otype = json_object_object_get(o, "type"); + + eid = url_encode(json_object_get_string(oid)); + url = malloc(strlen(sensors_url) + 1 + strlen(eid) + 1); + sprintf(url, "%s/%s", sensors_url, eid); + + s = psensor_create(strdup(url), + strdup(json_object_get_string(oname)), + json_object_get_int(otype) | SENSOR_TYPE_REMOTE, + values_max_length); + s->url = url; + + free(eid); + + return s; +} + +void rsensor_init() +{ + curl = curl_easy_init(); +} + +void rsensor_end() +{ + curl_easy_cleanup(curl); +} + +json_object *get_json_object(const char *url) +{ + + struct ucontent chunk; + json_object *obj = NULL; + + if (!curl) + return NULL; + + chunk.data = malloc(1); + chunk.len = 0; + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbk_curl); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); + + if (curl_easy_perform(curl) == CURLE_OK) + obj = json_tokener_parse(chunk.data); + else + fprintf(stderr, _("ERROR: Fail to connect to: %s\n"), url); + + free(chunk.data); + + return obj; +} + +struct psensor **get_remote_sensors(const char *server_url, + int values_max_length) +{ + struct psensor **sensors = NULL; + char *url; + json_object *obj; + + url = create_api_1_0_sensors_url(server_url); + + obj = get_json_object(url); + + if (obj && !is_error(obj)) { + int i; + int n = json_object_array_length(obj); + sensors = malloc((n + 1) * sizeof(struct psensor *)); + + for (i = 0; i < n; i++) { + struct psensor *s = json_object_to_psensor + (json_object_array_get_idx(obj, i), + url, + values_max_length); + sensors[i] = s; + } + + sensors[n] = NULL; + + json_object_put(obj); + } else { + fprintf(stderr, _("ERROR: Invalid content: %s\n"), url); + } + + free(url); + + if (!sensors) { + sensors = malloc(sizeof(struct psensor *)); + *sensors = NULL; + } + + return sensors; +} + +void remote_psensor_update(struct psensor *s) +{ + json_object *obj = get_json_object(s->url); + + if (obj && !is_error(obj)) { + json_object *om; + + om = json_object_object_get(obj, "last_measure"); + + if (!is_error(obj)) { + json_object *ov, *ot; + struct timeval tv; + + ov = json_object_object_get(om, "value"); + ot = json_object_object_get(om, "time"); + + tv.tv_sec = json_object_get_int(ot); + tv.tv_usec = 0; + + psensor_set_current_measure + (s, json_object_get_double(ov), tv);; + } + + json_object_put(obj); + } else { + printf(_("ERROR: Invalid JSON: %s\n"), s->url); + } + +} + +void remote_psensor_list_update(struct psensor **sensors) +{ + struct psensor **cur = sensors; + + while (*cur) { + struct psensor *s = *cur; + + if (s->type & SENSOR_TYPE_REMOTE) + remote_psensor_update(s); + + cur++; + } +} diff --git a/src/rsensor.h b/src/rsensor.h new file mode 100644 index 0000000..bd7a44b --- /dev/null +++ b/src/rsensor.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_RSENSOR_H_ +#define _PSENSOR_RSENSOR_H_ + +#include "psensor.h" + +struct psensor **get_remote_sensors(const char *server_url, + int values_max_length); + +void remote_psensor_list_update(struct psensor **sensors); + +void rsensor_init(); + +#endif diff --git a/src/server/Makefile.am b/src/server/Makefile.am new file mode 100644 index 0000000..73192bf --- /dev/null +++ b/src/server/Makefile.am @@ -0,0 +1,42 @@ +bin_PROGRAMS = psensor-server +psensor_server_SOURCES = server.c server.h + +AM_CPPFLAGS = -pedantic -Werror -DDEFAULT_WWW_DIR=\""$(pkgdatadir)/www"\"\ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/libpsensor_json \ + $(SENSORS_CFLAGS)\ + $(JSON_CFLAGS)\ + $(LIBMICROHTTPD_CFLAGS) + +DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ + +LIBS = \ + ../plib/libplib.a \ + ../lib/libpsensor.a \ + ../libpsensor_json/libpsensor_json.a \ + $(SENSORS_LIBS) \ + $(JSON_LIBS) \ + $(LIBMICROHTTPD_LIBS) + +if LUA +AM_CPPFLAGS += $(LUA_CFLAGS) +LIBS += ../plib/libplib_luatpl.a \ + $(LUA_LIBS) +psensor_server_SOURCES += server_lua.h server_lua.c +endif + +if GTOP +AM_CPPFLAGS += $(GTOP_CFLAGS) +LIBS += $(GTOP_LIBS) +psensor_server_SOURCES += sysinfo.h sysinfo.c +AM_LDFLAGS = -Wl,--as-needed +endif + + + +dist_man_MANS = psensor-server.1 +EXTRA_DIST = description.txt +psensor-server.1: server.c $(top_srcdir)/configure.ac + $(MAKE) $(AM_MAKEFLAGS) psensor-server$(EXEEXT) + help2man --include=description.txt -N --name="Temperature and system monitoring Web server" --output=psensor-server.1 ./psensor-server$(EXEEXT) \ No newline at end of file diff --git a/src/server/description.txt b/src/server/description.txt new file mode 100644 index 0000000..309bfed --- /dev/null +++ b/src/server/description.txt @@ -0,0 +1,33 @@ +[DESCRIPTION] + +/psensor-server is a/ + +It provides a JSON Web service which can be used by psensor(1) to +monitor remotely the hardware sensors of a computer. + +It can provide information about: + * the temperature of the motherboard and CPU sensors (using lm\-sensors). + * the temperature of the Hard Disk Drives (using hddtemp). + * the rotation speed of the fans (using lm\-sensors). + +The entry point of the JSON Web service is: +http://hostname:3131/api/1.0/sensors. + +It is also possible to connect to the psensor\-server with a browser, a +simple Web page is displaying the sensors information and the CPU +usage. + +If run in debug mode, psensor\-server can be stopped by sending an HTTP +request with the URL 'http://hostname:port/api/1.0/server/stop'. + +[WARNING] + +psensor\-server does not provide any way to restrict the connection to +the HTTP server, worst, no effort has been made against malicious HTTP +attacks. You should make the psensor\-server port available only to a +network or computer you trust by using the usual network security +tools of the system (for example, iptables(8) ). + +[SEE ALSO] + +psensor(1), sensors(1), sensors\-detect(8) diff --git a/src/server/server.c b/src/server/server.c new file mode 100644 index 0000000..673964c --- /dev/null +++ b/src/server/server.c @@ -0,0 +1,428 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 +#define _(str) gettext(str) + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GTOP +#include "sysinfo.h" +#endif + +#ifdef HAVE_LUA +#include "server_lua.h" +#endif + +#include "psensor_json.h" +#include "plib/url.h" +#include "plib/plib_io.h" +#include "server.h" + +static const char *program_name; + +#define DEFAULT_PORT 3131 + +#define PAGE_NOT_FOUND (_("

\ +Page not found - Go to Main page\ +

")) + +static struct option long_options[] = { + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"port", required_argument, 0, 'p'}, + {"wdir", required_argument, 0, 'w'}, + {"debug", no_argument, 0, 'd'}, + {0, 0, 0, 0} +}; + +static struct server_data server_data; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static int debug; + +static int server_stop_requested; + +void print_version() +{ + printf("psensor-server %s\n", VERSION); + printf(_("Copyright (C) %s wpitchoune@gmail.com\n\ +License GPLv2: GNU GPL version 2 or later \ +\n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n"), + "2010-2011"); +} + +void print_help() +{ + printf(_("Usage: %s [OPTION]...\n"), program_name); + + puts(_("psensor-server is an HTTP server " + "for monitoring hardware sensors remotely.")); + + puts(""); + puts("Options:"); + puts(_("\ + -h, --help display this help and exit\n\ + -v, --version display version information and exit")); + + puts(""); + + puts(_("\ + -d,--debug run in debug mode\n\ + -p,--port=PORT webserver port\n\ + -w,--wdir=DIR directory containing webserver pages")); + + puts(""); + + printf(_("Report bugs to: %s\n"), PACKAGE_BUGREPORT); + puts(""); + printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); +} + +/* + Returns '1' if the path denotates a Lua file, otherwise returns 0. + */ +int is_path_lua(const char *path) +{ + char *dot = rindex(path, '.'); + + if (dot && !strcasecmp(dot, ".lua")) + return 1; + + return 0; +} + +/* + Returns the file path corresponding to a given URL +*/ +char *get_path(const char *url, const char *www_dir) +{ + const char *p; + char *res; + + if (!strlen(url) || !strcmp(url, ".") || !strcmp(url, "/")) + p = "/index.lua"; + else + p = url; + + res = malloc(strlen(www_dir)+strlen(p)+1); + + strcpy(res, www_dir); + strcat(res, p); + + return res; +} + +static int +file_reader(void *cls, uint64_t pos, char *buf, int max) +{ + FILE *file = cls; + + fseek(file, pos, SEEK_SET); + return fread(buf, 1, max, file); +} + +struct MHD_Response * +create_response_api(const char *nurl, + const char *method, + unsigned int *rp_code) +{ + char *page = NULL; + + if (!strcmp(nurl, URL_BASE_API_1_0_SENSORS)) { + + page = sensors_to_json_string(server_data.sensors); + + } else if (!strncmp(nurl, URL_BASE_API_1_0_SENSORS, + strlen(URL_BASE_API_1_0_SENSORS)) + && nurl[strlen(URL_BASE_API_1_0_SENSORS)] == '/') { + + const char *sid = nurl + strlen(URL_BASE_API_1_0_SENSORS) + 1; + + struct psensor *s + = psensor_list_get_by_id(server_data.sensors, sid); + + if (s) + page = sensor_to_json_string(s); + + } else if (debug && !strcmp(nurl, URL_API_1_0_SERVER_STOP)) { + + server_stop_requested = 1; + page = strdup(_("

" + "Server stop requested

")); + } + + if (page) { + *rp_code = MHD_HTTP_OK; + + return MHD_create_response_from_data + (strlen(page), page, MHD_YES, MHD_NO); + } + + return NULL; +} + +struct MHD_Response * +create_response_lua(const char *nurl, + const char *method, + unsigned int *rp_code, + const char *fpath) +{ +#ifdef HAVE_LUA + char *page = lua_to_html_page(&server_data, fpath); + + if (page) { + *rp_code = MHD_HTTP_OK; + + return MHD_create_response_from_data + (strlen(page), page, MHD_YES, MHD_NO); + } +#endif + + return NULL; +} + +struct MHD_Response * +create_response_file(const char *nurl, + const char *method, + unsigned int *rp_code, + const char *fpath) +{ + if (is_file(fpath)) { + FILE *file = fopen(fpath, "rb"); + + if (file) { + struct stat buf; + + stat(fpath, &buf); + *rp_code = MHD_HTTP_OK; + + if (!buf.st_size) { + fclose(file); + return MHD_create_response_from_data + (0, NULL, MHD_NO, MHD_NO); + } + + return MHD_create_response_from_callback + (buf.st_size, + 32 * 1024, + &file_reader, + file, + (MHD_ContentReaderFreeCallback)&fclose); + + } + } + + return NULL; +} + +struct MHD_Response * +create_response(const char *nurl, const char *method, unsigned int *rp_code) +{ + struct MHD_Response *resp = NULL; + + if (!strncmp(nurl, URL_BASE_API_1_0, strlen(URL_BASE_API_1_0))) { + resp = create_response_api(nurl, method, rp_code); + } else { + char *fpath = get_path(nurl, server_data.www_dir); + + if (is_path_lua(fpath)) + resp = create_response_lua + (nurl, method, rp_code, fpath); + else + resp = create_response_file + (nurl, method, rp_code, fpath); + + free(fpath); + } + + if (resp) { + return resp; + } else { + char *page = strdup(PAGE_NOT_FOUND); + *rp_code = MHD_HTTP_NOT_FOUND; + + return MHD_create_response_from_data + (strlen(page), page, MHD_YES, MHD_NO); + } +} + +static int +cbk_http_request(void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, void **ptr) +{ + static int dummy; + struct MHD_Response *response; + int ret; + char *nurl; + unsigned int resp_code; + char *page = NULL; + + if (strcmp(method, "GET")) + return MHD_NO; + + if (&dummy != *ptr) { + /* The first time only the headers are valid, do not + respond in the first round... */ + *ptr = &dummy; + return MHD_YES; + } + + if (*upload_data_size) + return MHD_NO; + + *ptr = NULL; /* clear context pointer */ + + if (debug) + printf(_("HTTP Request: %s\n"), url); + + nurl = url_normalize(url); + + pthread_mutex_lock(&mutex); + response = create_response(nurl, method, &resp_code); + pthread_mutex_unlock(&mutex); + + ret = MHD_queue_response(connection, resp_code, response); + MHD_destroy_response(response); + + free(nurl); + + return ret; +} + +int main(int argc, char *argv[]) +{ + struct MHD_Daemon *d; + int port = DEFAULT_PORT; + int optc; + int cmdok = 1; + + program_name = argv[0]; + + setlocale(LC_ALL, ""); + +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + + server_data.www_dir = DEFAULT_WWW_DIR; + + while ((optc = getopt_long(argc, argv, + "vhp:w:d", long_options, NULL)) != -1) { + switch (optc) { + case 'w': + if (optarg) + server_data.www_dir = strdup(optarg); + break; + case 'p': + if (optarg) + port = atoi(optarg); + break; + case 'h': + print_help(); + exit(EXIT_SUCCESS); + case 'v': + print_version(); + exit(EXIT_SUCCESS); + case 'd': + debug = 1; + break; + default: + cmdok = 0; + break; + } + } + + if (!cmdok || optind != argc) { + fprintf(stderr, _("Try `%s --help' for more information.\n"), + program_name); + exit(EXIT_FAILURE); + } + + if (!lmsensor_init()) { + fprintf(stderr, _("ERROR: failed to init lm-sensors\n")); + exit(EXIT_FAILURE); + } + + server_data.sensors = get_all_sensors(1); + + if (!*server_data.sensors) + fprintf(stderr, _("ERROR: no sensors detected\n")); + + d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, + port, + NULL, NULL, &cbk_http_request, server_data.sensors, + MHD_OPTION_END); + if (!d) { + fprintf(stderr, _("ERROR: Fail to create web server\n")); + exit(EXIT_FAILURE); + } + + printf(_("Web server started on port: %d\n"), port); + printf(_("WWW directory: %s\n"), server_data.www_dir); + printf(_("URL: http://localhost:%d\n"), port); + + while (!server_stop_requested) { + pthread_mutex_lock(&mutex); + +#ifdef HAVE_GTOP + sysinfo_update(&server_data.psysinfo); +#endif + psensor_list_update_measures(server_data.sensors); + + pthread_mutex_unlock(&mutex); + sleep(5); + } + + MHD_stop_daemon(d); + + /* sanity cleanup for valgrind */ + psensor_list_free(server_data.sensors); + free(server_data.www_dir); + sensors_cleanup(); + +#ifdef HAVE_GTOP + sysinfo_cleanup(); +#endif + + return EXIT_SUCCESS; +} diff --git a/src/server/server.h b/src/server/server.h new file mode 100644 index 0000000..2770844 --- /dev/null +++ b/src/server/server.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_SERVER_H_ +#define _PSENSOR_SERVER_H_ + +#include "psensor.h" +#include "sysinfo.h" + +#define URL_BASE_API_1_0 "/api/1.0" +#define URL_BASE_API_1_0_SENSORS "/api/1.0/sensors" +#define URL_API_1_0_SERVER_STOP "/api/1.0/server/stop" + +struct server_data { + struct psensor **sensors; + struct psysinfo psysinfo; + char *www_dir; +}; + +#endif diff --git a/src/server/server_lua.c b/src/server/server_lua.c new file mode 100644 index 0000000..3d9eb38 --- /dev/null +++ b/src/server/server_lua.c @@ -0,0 +1,163 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "server_lua.h" + +#include "plib/plib_luatpl.h" + +int init_lua(lua_State *L, void *data) +{ + struct server_data *server_data = data; + struct psensor **s_cur; + struct psensor **sensors = server_data->sensors; + int i; + static float load_scale = 1 << SI_LOAD_SHIFT; + + lua_newtable(L); + +#ifdef HAVE_GTOP + lua_pushstring(L, "load"); + lua_pushnumber(L, server_data->psysinfo.cpu_rate); + lua_settable(L, -3); +#endif + + lua_pushstring(L, "uptime"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.uptime); + lua_settable(L, -3); + + lua_pushstring(L, "load_1mn"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.loads[0] / load_scale); + lua_settable(L, -3); + + lua_pushstring(L, "load_5mn"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.loads[1] / load_scale); + lua_settable(L, -3); + + lua_pushstring(L, "load_15mn"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.loads[2] / load_scale); + lua_settable(L, -3); + + lua_pushstring(L, "freeram"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.freeram); + lua_settable(L, -3); + + lua_pushstring(L, "sharedram"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.sharedram); + lua_settable(L, -3); + + lua_pushstring(L, "bufferram"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.bufferram); + lua_settable(L, -3); + + lua_pushstring(L, "totalswap"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.totalswap); + lua_settable(L, -3); + + lua_pushstring(L, "freeswap"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.freeswap); + lua_settable(L, -3); + + lua_pushstring(L, "procs"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.procs); + lua_settable(L, -3); + + lua_pushstring(L, "totalhigh"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.totalhigh); + lua_settable(L, -3); + + lua_pushstring(L, "freehigh"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.freehigh); + lua_settable(L, -3); + + lua_pushstring(L, "totalram"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.totalram); + lua_settable(L, -3); + + lua_pushstring(L, "mem_unit"); + lua_pushnumber(L, server_data->psysinfo.sysinfo.mem_unit); + lua_settable(L, -3); + + + lua_setglobal(L, "sysinfo"); + + + lua_newtable(L); + + s_cur = sensors; + i = 1; + while (*s_cur) { + lua_pushnumber(L, i); + + lua_newtable(L); + + lua_pushstring(L, "name"); + lua_pushstring(L, (*s_cur)->name); + lua_settable(L, -3); + + lua_pushstring(L, "measure_last"); + lua_pushnumber(L, psensor_get_current_value(*s_cur)); + lua_settable(L, -3); + + lua_pushstring(L, "measure_min"); + lua_pushnumber(L, (*s_cur)->min); + lua_settable(L, -3); + + lua_pushstring(L, "measure_max"); + lua_pushnumber(L, (*s_cur)->max); + lua_settable(L, -3); + + lua_settable(L, -3); + + s_cur++; + i++; + } + + lua_setglobal(L, "sensors"); + + lua_pushstring(L, VERSION); + lua_setglobal(L, "psensor_version"); + + return 1; +} + +char *lua_to_html_page(struct server_data *server_data, const char *fpath) +{ + char *page = NULL; + struct luatpl_error err; + + err.message = NULL; + + page = luatpl_generate(fpath, + init_lua, + server_data, + &err); + + if (!page) { + luatpl_fprint_error(stderr, + &err, + fpath, + "outstring"); + free(err.message); + } + + return page; +} diff --git a/src/server/server_lua.h b/src/server/server_lua.h new file mode 100644 index 0000000..d3e4e9f --- /dev/null +++ b/src/server/server_lua.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_SERVER_LUA_H_ +#define _PSENSOR_SERVER_LUA_H_ + +#include "server.h" + +char *lua_to_html_page(struct server_data *data, const char *fpath); + +#endif diff --git a/src/server/sysinfo.c b/src/server/sysinfo.c new file mode 100644 index 0000000..cef2872 --- /dev/null +++ b/src/server/sysinfo.c @@ -0,0 +1,60 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 + +#include "sysinfo.h" + +static glibtop_cpu *cpu; +static float last_used; +static float last_total; + + +void sysinfo_update(struct psysinfo *info) +{ + unsigned long int used = 0; + unsigned long int dt; + + /* cpu */ + if (!cpu) + cpu = malloc(sizeof(glibtop_cpu)); + + glibtop_get_cpu(cpu); + + used = cpu->user + cpu->nice + cpu->sys; + + dt = cpu->total - last_total; + + if (dt) + info->cpu_rate = (used - last_used) / dt; + + last_used = used; + last_total = cpu->total; + + /* memory */ + sysinfo(&info->sysinfo); +} + +void sysinfo_cleanup() +{ + if (cpu) + free(cpu); +} diff --git a/src/server/sysinfo.h b/src/server/sysinfo.h new file mode 100644 index 0000000..c62ec25 --- /dev/null +++ b/src/server/sysinfo.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_SYSINFO_H_ +#define _PSENSOR_SYSINFO_H_ + +#include + +struct psysinfo { + float cpu_rate; + + struct sysinfo sysinfo; +}; + +void sysinfo_update(struct psysinfo *sysinfo); +void sysinfo_cleanup(); + +#endif diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..5f038fd --- /dev/null +++ b/src/ui.c @@ -0,0 +1,126 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "cfg.h" +#include "ui.h" +#include "ui_graph.h" +#include "ui_sensorlist.h" + +void on_destroy(GtkWidget *widget, gpointer data) +{ + ui_psensor_exit(); +} + +void ui_psensor_exit() +{ + gtk_main_quit(); +} + +GtkWidget *ui_window_create(struct ui_psensor * ui) +{ + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + GdkScreen *screen; + GdkColormap *colormap; + GdkPixbuf *icon; + GtkIconTheme *icon_theme; + + gtk_window_set_default_size(GTK_WINDOW(window), 800, 200); + + gtk_window_set_title(GTK_WINDOW(window), + _("Psensor - Temperature Monitor")); + gtk_window_set_role(GTK_WINDOW(window), "psensor"); + + screen = gtk_widget_get_screen(window); + + if (ui->config->alpha_channel_enabled + && gdk_screen_is_composited(screen)) { + + colormap = gdk_screen_get_rgba_colormap(screen); + if (colormap) + gtk_widget_set_colormap(window, colormap); + else + ui->config->alpha_channel_enabled = 0; + } else { + ui->config->alpha_channel_enabled = 0; + } + + icon_theme = gtk_icon_theme_get_default(); + icon = gtk_icon_theme_load_icon(icon_theme, "psensor", 48, 0, NULL); + if (icon) + gtk_window_set_icon(GTK_WINDOW(window), icon); + else + fprintf(stderr, _("ERROR: Failed to load psensor icon.\n")); + + g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), ui); + + gtk_window_set_decorated(GTK_WINDOW(window), + ui->config->window_decoration_enabled); + + gtk_window_set_keep_below(GTK_WINDOW(window), + ui->config->window_keep_below_enabled); + + return window; +} + +void ui_main_box_create(struct ui_psensor *ui) +{ + struct config *cfg; + GtkWidget *w_sensorlist; + + cfg = ui->config; + + if (ui->main_box) { + ui_sensorlist_create_widget(ui->ui_sensorlist); + + gtk_container_remove(GTK_CONTAINER(ui->main_window), + ui->main_box); + + ui->w_graph = ui_graph_create(ui); + ui->w_sensorlist = ui->ui_sensorlist->widget; + } + + if (cfg->sensorlist_position == SENSORLIST_POSITION_RIGHT + || cfg->sensorlist_position == SENSORLIST_POSITION_LEFT) + ui->main_box = gtk_hpaned_new(); + else + ui->main_box = gtk_vpaned_new(); + + w_sensorlist = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w_sensorlist), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(w_sensorlist), + ui->ui_sensorlist->widget); + + gtk_container_add(GTK_CONTAINER(ui->main_window), ui->main_box); + + if (cfg->sensorlist_position == SENSORLIST_POSITION_RIGHT + || cfg->sensorlist_position == SENSORLIST_POSITION_BOTTOM) { + gtk_paned_pack1(GTK_PANED(ui->main_box), + GTK_WIDGET(ui->w_graph), TRUE, TRUE); + gtk_paned_pack2(GTK_PANED(ui->main_box), + w_sensorlist, FALSE, TRUE); + } else { + gtk_paned_pack1(GTK_PANED(ui->main_box), + w_sensorlist, FALSE, TRUE); + gtk_paned_pack2(GTK_PANED(ui->main_box), + GTK_WIDGET(ui->w_graph), TRUE, TRUE); + } + + gtk_widget_show_all(ui->main_box); +} diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 0000000..24778dd --- /dev/null +++ b/src/ui.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_H_ +#define _PSENSOR_UI_H_ + +#include "config.h" + +#include +#include + +#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029) +#include +#endif + +#include "psensor.h" + +struct ui_psensor { + struct psensor **sensors; + + GtkWidget *w_graph; + + struct ui_sensorlist *ui_sensorlist; + + struct config *config; + + GtkWidget *main_window; + + GtkWidget *main_box; + + GtkWidget *w_sensorlist; + + int graph_update_interval; + + GMutex *sensors_mutex; + +#ifdef HAVE_LIBNOTIFY + /* + * Time of the last notification + */ + struct timeval *notification_last_time; +#endif + +#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029) + AppIndicator *indicator; +#endif +}; + +void ui_main_box_create(struct ui_psensor *); + +/* + Must be called to terminate Psensor UI. +*/ +void ui_psensor_exit(); + +/* + Creates the main GTK window +*/ +GtkWidget *ui_window_create(struct ui_psensor * ui); + +#endif diff --git a/src/ui_appindicator.c b/src/ui_appindicator.c new file mode 100644 index 0000000..d68bc42 --- /dev/null +++ b/src/ui_appindicator.c @@ -0,0 +1,131 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 + +#include +#include + +#include "psensor.h" +#include "ui.h" +#include "ui_appindicator.h" +#include "ui_pref.h" + +static void cb_appindicator_show(gpointer data, + guint cb_action, + GtkWidget *item) +{ + struct ui_psensor *ui = (struct ui_psensor *)data; + + gtk_window_present(GTK_WINDOW(ui->main_window)); +} + +static void cb_appindicator_quit(gpointer data, + guint cb_action, + GtkWidget *item) +{ + ui_psensor_exit(data); +} + +static void cb_appindicator_preferences(gpointer data, + guint cb_action, + GtkWidget *item) +{ +#ifdef HAVE_APPINDICATOR_029 + gdk_threads_enter(); +#endif + + ui_pref_dialog_run((struct ui_psensor *)data); + +#ifdef HAVE_APPINDICATOR_029 + gdk_threads_leave(); +#endif +} + +static GtkItemFactoryEntry menu_items[] = { + {"/Show", + NULL, cb_appindicator_show, 0, ""}, + {"/Preferences", + NULL, cb_appindicator_preferences, 0, ""}, + {"/sep1", + NULL, NULL, 0, ""}, + {"/Quit", + "", cb_appindicator_quit, 0, "", GTK_STOCK_QUIT}, +}; + +static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); +GtkWidget *ui_appindicator_get_menu(struct ui_psensor *ui) +{ + GtkItemFactory *item_factory; + + item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "
", NULL); + + gtk_item_factory_create_items(item_factory, + nmenu_items, menu_items, ui); + return gtk_item_factory_get_widget(item_factory, "
"); +} + +void ui_appindicator_update(struct ui_psensor *ui) +{ + struct psensor **sensor_cur = ui->sensors; + AppIndicatorStatus status; + int attention = 0; + + if (!ui->indicator) + return; + + while (*sensor_cur) { + struct psensor *s = *sensor_cur; + + if (s->alarm_enabled && s->alarm_raised) { + attention = 1; + break; + } + + sensor_cur++; + } + + status = app_indicator_get_status(ui->indicator); + + if (!attention && status == APP_INDICATOR_STATUS_ATTENTION) + app_indicator_set_status + (ui->indicator, APP_INDICATOR_STATUS_ACTIVE); + + if (attention && status == APP_INDICATOR_STATUS_ACTIVE) + app_indicator_set_status + (ui->indicator, APP_INDICATOR_STATUS_ATTENTION); +} + +void ui_appindicator_init(struct ui_psensor *ui) +{ + GtkWidget *indicatormenu; + + ui->indicator + = app_indicator_new("psensor", + "psensor", + APP_INDICATOR_CATEGORY_APPLICATION_STATUS); + + app_indicator_set_status(ui->indicator, APP_INDICATOR_STATUS_ACTIVE); + app_indicator_set_attention_icon(ui->indicator, "psensor_hot"); + + indicatormenu = ui_appindicator_get_menu(ui); + app_indicator_set_menu(ui->indicator, GTK_MENU(indicatormenu)); +} diff --git a/src/ui_appindicator.h b/src/ui_appindicator.h new file mode 100644 index 0000000..409671b --- /dev/null +++ b/src/ui_appindicator.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_APPINDICATOR_H_ +#define _PSENSOR_UI_APPINDICATOR_H_ + +#include "ui.h" + +void ui_appindicator_init(struct ui_psensor *ui); +void ui_appindicator_update(struct ui_psensor *ui); + +#endif diff --git a/src/ui_color.c b/src/ui_color.c new file mode 100644 index 0000000..fa715a5 --- /dev/null +++ b/src/ui_color.c @@ -0,0 +1,54 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "ui_color.h" + +int ui_change_color(const char *title, struct color *col) +{ + GdkColor color; + GtkColorSelection *colorsel; + int res; + GtkColorSelectionDialog *colordlg; + + color.red = col->red; + color.green = col->green; + color.blue = col->blue; + + colordlg = (GtkColorSelectionDialog *) + gtk_color_selection_dialog_new(title); + + colorsel = GTK_COLOR_SELECTION(colordlg->colorsel); + + gtk_color_selection_set_previous_color(colorsel, &color); + gtk_color_selection_set_current_color(colorsel, &color); + + res = gtk_dialog_run(GTK_DIALOG(colordlg)); + + if (res == GTK_RESPONSE_OK) { + gtk_color_selection_get_current_color(colorsel, &color); + + color_set(col, color.red, color.green, color.blue); + } + + gtk_widget_destroy(GTK_WIDGET(colordlg)); + + return res == GTK_RESPONSE_OK; +} diff --git a/src/ui_color.h b/src/ui_color.h new file mode 100644 index 0000000..c20a4b5 --- /dev/null +++ b/src/ui_color.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_COLOR_H_ +#define _PSENSOR_UI_COLOR_H_ + +#include "color.h" + +/* + UI to change a given color. + + Returns 1 if the color has been modified. + */ +int ui_change_color(const char *title, struct color *col); + +#endif diff --git a/src/ui_graph.c b/src/ui_graph.c new file mode 100644 index 0000000..7c1a2c1 --- /dev/null +++ b/src/ui_graph.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "graph.h" +#include "ui_graph.h" +#include "ui_pref.h" + +static void +cb_preferences(gpointer data, guint callback_action, GtkWidget *item) +{ + ui_pref_dialog_run((struct ui_psensor *)data); +} + +static GtkItemFactoryEntry menu_items[] = { + {N_("/Preferences"), + NULL, cb_preferences, 0, ""}, + + {"/sep1", + NULL, NULL, 0, ""}, + + {N_("/Quit"), + "", ui_psensor_exit, 0, "", GTK_STOCK_QUIT}, +}; + +static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + +GtkWidget *ui_graph_create_popupmenu(struct ui_psensor *ui) +{ + GtkItemFactory *item_factory; + + item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "
", NULL); + gtk_item_factory_create_items(item_factory, + nmenu_items, menu_items, ui); + return gtk_item_factory_get_widget(item_factory, "
"); +} + +int on_graph_clicked(GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GtkWidget *menu; + + if (event->type != GDK_BUTTON_PRESS) + return FALSE; + + menu = ui_graph_create_popupmenu((struct ui_psensor *)data); + + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, + event->button, event->time); + + return TRUE; +} + +gboolean +on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + struct ui_psensor *ui_psensor = (struct ui_psensor *)data; + + graph_update(ui_psensor->sensors, + ui_psensor->w_graph, ui_psensor->config); + + return FALSE; +} + +GtkWidget *ui_graph_create(struct ui_psensor * ui) +{ + GtkWidget *w_graph; + + w_graph = gtk_drawing_area_new(); + + g_signal_connect(G_OBJECT(w_graph), + "expose-event", G_CALLBACK(on_expose_event), ui); + + gtk_widget_add_events(w_graph, GDK_BUTTON_PRESS_MASK); + gtk_signal_connect(GTK_OBJECT(w_graph), + "button_press_event", + (GCallback) on_graph_clicked, ui); + + return w_graph; +} diff --git a/src/ui_graph.h b/src/ui_graph.h new file mode 100644 index 0000000..4df9ef5 --- /dev/null +++ b/src/ui_graph.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_GRAPH_H_ +#define _PSENSOR_UI_GRAPH_H_ + +#include + +#include "ui.h" + +GtkWidget *ui_graph_create(struct ui_psensor * ui); + +#endif diff --git a/src/ui_notify.c b/src/ui_notify.c new file mode 100644 index 0000000..29d9636 --- /dev/null +++ b/src/ui_notify.c @@ -0,0 +1,80 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 + +#include + +#include "ui.h" +#include "ui_notify.h" + +void ui_notify(struct psensor *sensor, struct ui_psensor *ui) +{ + struct timeval *t = malloc(sizeof(struct timeval)); + char *name; + NotifyNotification *notif; + + if (gettimeofday(t, NULL) != 0) { + fprintf(stderr, _("ERROR: failed gettimeofday\n")); + free(t); + + return; + } + + if (!ui->notification_last_time) { + /* first notification */ + ui->notification_last_time = t; + } else { + + if (t->tv_sec - ui->notification_last_time->tv_sec < 60) { + /* last notification less than 1mn ago */ + free(t); + return; + } else { + /* last notification more than 1mn ago */ + free(ui->notification_last_time); + ui->notification_last_time = t; + } + } + + if (notify_is_initted() == FALSE) + notify_init("psensor"); + + if (notify_is_initted() == TRUE) { + name = strdup(sensor->name); + +#ifdef NOTIFY_VERSION_MAJOR + notif = notify_notification_new(_("Temperature alert"), + name, + NULL); +#else + notif = notify_notification_new(_("Temperature alert"), + name, + NULL, + GTK_WIDGET(ui->main_window)); +#endif + + + notify_notification_show(notif, NULL); + + g_object_unref(notif); + } +} diff --git a/src/ui_notify.h b/src/ui_notify.h new file mode 100644 index 0000000..94b37db --- /dev/null +++ b/src/ui_notify.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_NOTIFY_H_ +#define _PSENSOR_UI_NOTIFY_H_ + +#include "psensor.h" +#include "ui.h" + +void ui_notify(struct psensor *sensor, struct ui_psensor *ui); + +#endif diff --git a/src/ui_pref.c b/src/ui_pref.c new file mode 100644 index 0000000..809ee20 --- /dev/null +++ b/src/ui_pref.c @@ -0,0 +1,182 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "ui.h" +#include "cfg.h" +#include "ui_pref.h" +#include "ui_color.h" +#include "compat.h" + +GdkColor *color_to_gdkcolor(struct color *color) +{ + GdkColor *c = malloc(sizeof(GdkColor)); + + c->red = color->red; + c->green = color->green; + c->blue = color->blue; + + return c; +} + +void ui_pref_dialog_run(struct ui_psensor *ui) +{ + GtkDialog *diag; + gint result; + struct config *cfg; + GtkBuilder *builder; + guint ok; + GError *error = NULL; + GdkColor *color_fg, *color_bg; + GtkColorButton *w_color_fg, *w_color_bg; + GtkHScale *w_bg_opacity; + GtkSpinButton *w_update_interval, *w_monitoring_duration, + *w_s_update_interval; + GtkComboBox *w_sensorlist_pos; + GtkToggleButton *w_hide_window_decoration, *w_keep_window_below; + + cfg = ui->config; + + builder = gtk_builder_new(); + + ok = gtk_builder_add_from_file + (builder, + PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "psensor-pref.glade", + &error); + + if (!ok) { + g_warning("%s", error->message); + g_free(error); + return ; + } + + diag = GTK_DIALOG(gtk_builder_get_object(builder, "dialog1")); + + color_fg = color_to_gdkcolor(cfg->graph_fgcolor); + w_color_fg = GTK_COLOR_BUTTON(gtk_builder_get_object(builder, + "color_fg")); + gtk_color_button_set_color(w_color_fg, color_fg); + + color_bg = color_to_gdkcolor(cfg->graph_bgcolor); + w_color_bg = GTK_COLOR_BUTTON(gtk_builder_get_object(builder, + "color_bg")); + gtk_color_button_set_color(w_color_bg, color_bg); + + w_bg_opacity = GTK_HSCALE(gtk_builder_get_object(builder, + "bg_opacity")); + gtk_range_set_value(GTK_RANGE(w_bg_opacity), cfg->graph_bg_alpha); + + w_update_interval = GTK_SPIN_BUTTON(gtk_builder_get_object + (builder, "update_interval")); + gtk_spin_button_set_value(w_update_interval, + cfg->graph_update_interval); + + w_s_update_interval + = GTK_SPIN_BUTTON(gtk_builder_get_object + (builder, "sensor_update_interval")); + gtk_spin_button_set_value(w_s_update_interval, + cfg->sensor_update_interval); + + w_monitoring_duration + = GTK_SPIN_BUTTON(gtk_builder_get_object + (builder, "monitoring_duration")); + gtk_spin_button_set_value(w_monitoring_duration, + cfg->graph_monitoring_duration); + + w_sensorlist_pos = GTK_COMBO_BOX + (gtk_builder_get_object(builder, + "sensors_list_position")); + gtk_combo_box_set_active(w_sensorlist_pos, cfg->sensorlist_position); + + w_hide_window_decoration = GTK_TOGGLE_BUTTON + (gtk_builder_get_object(builder, + "hide_window_decoration")); + gtk_toggle_button_set_active(w_hide_window_decoration, + !cfg->window_decoration_enabled); + + w_keep_window_below = GTK_TOGGLE_BUTTON + (gtk_builder_get_object(builder, + "keep_window_below")); + gtk_toggle_button_set_active(w_keep_window_below, + cfg->window_keep_below_enabled); + + result = gtk_dialog_run(diag); + + if (result == GTK_RESPONSE_ACCEPT) { + double value; + GdkColor color; + + g_mutex_lock(ui->sensors_mutex); + + gtk_color_button_get_color(w_color_fg, &color); + color_set(cfg->graph_fgcolor, + color.red, color.green, color.blue); + + gtk_color_button_get_color(w_color_bg, &color); + color_set(cfg->graph_bgcolor, + color.red, color.green, color.blue); + + value = gtk_range_get_value(GTK_RANGE(w_bg_opacity)); + cfg->graph_bg_alpha = value; + + if (value == 1.0) + cfg->alpha_channel_enabled = 0; + else + cfg->alpha_channel_enabled = 1; + + cfg->sensorlist_position + = gtk_combo_box_get_active(w_sensorlist_pos); + + cfg->window_decoration_enabled = + !gtk_toggle_button_get_active(w_hide_window_decoration); + + cfg->window_keep_below_enabled + = gtk_toggle_button_get_active(w_keep_window_below); + + gtk_window_set_decorated(GTK_WINDOW(ui->main_window), + cfg->window_decoration_enabled); + + gtk_window_set_keep_below(GTK_WINDOW(ui->main_window), + cfg->window_keep_below_enabled); + + cfg->sensor_update_interval + = gtk_spin_button_get_value_as_int(w_s_update_interval); + + cfg->graph_update_interval = gtk_spin_button_get_value_as_int + (w_update_interval); + + cfg->graph_monitoring_duration + = gtk_spin_button_get_value_as_int + (w_monitoring_duration); + + cfg->sensor_values_max_length + = (cfg->graph_monitoring_duration * 60) / + cfg->sensor_update_interval; + + config_save(cfg); + + g_mutex_unlock(ui->sensors_mutex); + + ui_main_box_create(ui); + } + g_object_unref(G_OBJECT(builder)); + gtk_widget_destroy(GTK_WIDGET(diag)); +} diff --git a/src/ui_pref.h b/src/ui_pref.h new file mode 100644 index 0000000..f3cd95f --- /dev/null +++ b/src/ui_pref.h @@ -0,0 +1,28 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_PREF_H_ +#define _PSENSOR_UI_PREF_H_ + +#include "ui.h" + +void ui_pref_dialog_run(struct ui_psensor *); +GdkColor *color_to_gdkcolor(struct color *color); + +#endif diff --git a/src/ui_sensorlist.c b/src/ui_sensorlist.c new file mode 100644 index 0000000..0bade13 --- /dev/null +++ b/src/ui_sensorlist.c @@ -0,0 +1,492 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "ui.h" +#include "ui_pref.h" +#include "ui_sensorlist.h" +#include "cfg.h" +#include "ui_color.h" +#include "compat.h" + +enum { + COL_NAME = 0, + COL_TEMP, + COL_TEMP_MIN, + COL_TEMP_MAX, + COL_COLOR, + COL_COLOR_STR, + COL_ENABLED, + COL_EMPTY, + COLS_COUNT +}; + +struct cb_data { + struct ui_sensorlist *ui_sensorlist; + struct psensor *sensor; +}; + +int col_index_to_col(int idx) +{ + if (idx == 5) + return COL_ENABLED; + else if (idx > 5) + return -1; + + return idx; +} + +void ui_sensorlist_update(struct ui_sensorlist *list) +{ + GtkTreeIter iter; + GtkTreeModel *model + = gtk_tree_view_get_model(GTK_TREE_VIEW(list->widget)); + gboolean valid = gtk_tree_model_get_iter_first(model, &iter); + struct psensor **sensor = list->sensors; + + while (valid && *sensor) { + struct psensor *s = *sensor; + + char *str; + + str = psensor_value_to_string(s->type, + s->measures[s->values_max_length - + 1].value); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_TEMP, str, + -1); + free(str); + + str = psensor_value_to_string(s->type, s->min); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + COL_TEMP_MIN, str, -1); + free(str); + + str = psensor_value_to_string(s->type, s->max); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + COL_TEMP_MAX, str, -1); + free(str); + + valid = gtk_tree_model_iter_next(model, &iter); + sensor++; + } +} + +/* + * Returns the sensor corresponding to the x/y position + * in the table. + * + * if none. + */ +struct psensor *ui_sensorlist_get_sensor_at_pos(GtkTreeView * view, + int x, + int y, struct psensor **sensors) +{ + GtkTreePath *path; + + gtk_tree_view_get_path_at_pos(view, x, y, &path, NULL, NULL, NULL); + + if (path) { + gint *i = gtk_tree_path_get_indices(path); + if (i) + return *(sensors + *i); + } + return NULL; +} + +/* + * Returns the index of the column corresponding + * to the x position in the table. + * + * -1 if none + */ +int ui_sensorlist_get_col_index_at_pos(GtkTreeView *view, int x) +{ + GList *columns = gtk_tree_view_get_columns(view); + GList *node; + int colx = 0; + int coli = 0; + + for (node = columns; node; node = node->next) { + GtkTreeViewColumn *checkcol = (GtkTreeViewColumn *) node->data; + + if (x >= colx && x < (colx + checkcol->width)) + return coli; + else + colx += checkcol->width; + + coli++; + } + + return -1; +} + +void ui_sensorlist_update_sensors_preferences(struct ui_sensorlist *list) +{ + GtkTreeIter iter; + GtkTreeModel *model + = gtk_tree_view_get_model(GTK_TREE_VIEW(list->widget)); + gboolean valid = gtk_tree_model_get_iter_first(model, &iter); + struct psensor **sensor = list->sensors; + + while (valid && *sensor) { + GdkColor color; + gchar *scolor; + + color.red = (*sensor)->color->red; + color.green = (*sensor)->color->green; + color.blue = (*sensor)->color->blue; + + scolor = gdk_color_to_string(&color); + + gtk_list_store_set(GTK_LIST_STORE(model), + &iter, COL_NAME, (*sensor)->name, -1); + + gtk_list_store_set(GTK_LIST_STORE(model), + &iter, COL_COLOR_STR, scolor, -1); + + gtk_list_store_set(GTK_LIST_STORE(model), + &iter, COL_ENABLED, (*sensor)->enabled, -1); + + free(scolor); + + valid = gtk_tree_model_iter_next(model, &iter); + sensor++; + } +} + +static void cb_sensor_settings_activated(GtkWidget *menu_item, gpointer data) +{ + struct cb_data *cb_data = data; + struct psensor *sensor = cb_data->sensor; + GtkDialog *diag; + gint result; + GtkBuilder *builder; + GError *error = NULL; + GtkLabel *w_id, *w_type; + GtkEntry *w_name; + GtkToggleButton *w_draw, *w_alarm; + GtkColorButton *w_color; + GtkSpinButton *w_temp_limit; + GdkColor *color; + guint ok; + + builder = gtk_builder_new(); + + ok = gtk_builder_add_from_file + (builder, + PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "sensor-edit.glade", + &error); + + if (!ok) { + g_warning("%s", error->message); + g_free(error); + return ; + } + + w_id = GTK_LABEL(gtk_builder_get_object(builder, "sensor_id")); + gtk_label_set_text(w_id, sensor->id); + + w_type = GTK_LABEL(gtk_builder_get_object(builder, "sensor_type")); + gtk_label_set_text(w_type, psensor_type_to_str(sensor->type)); + + w_name = GTK_ENTRY(gtk_builder_get_object(builder, "sensor_name")); + gtk_entry_set_text(w_name, sensor->name); + + w_draw = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, + "sensor_draw")); + gtk_toggle_button_set_active(w_draw, sensor->enabled); + + color = color_to_gdkcolor(sensor->color); + w_color = GTK_COLOR_BUTTON(gtk_builder_get_object(builder, + "sensor_color")); + gtk_color_button_set_color(w_color, color); + + w_alarm = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, + "sensor_alarm")); + w_temp_limit + = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, + "sensor_temp_limit")); + + if (is_temp_type(sensor->type)) { + gtk_toggle_button_set_active(w_alarm, sensor->alarm_enabled); + gtk_spin_button_set_value(w_temp_limit, sensor->alarm_limit); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(w_alarm), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(w_temp_limit), FALSE); + } + + diag = GTK_DIALOG(gtk_builder_get_object(builder, "dialog1")); + result = gtk_dialog_run(diag); + + if (result == GTK_RESPONSE_ACCEPT) { + + free(sensor->name); + sensor->name = strdup(gtk_entry_get_text(w_name)); + config_set_sensor_name(sensor->id, sensor->name); + + sensor->enabled = gtk_toggle_button_get_active(w_draw); + config_set_sensor_enabled(sensor->id, sensor->enabled); + + sensor->alarm_limit = gtk_spin_button_get_value(w_temp_limit); + config_set_sensor_alarm_limit(sensor->id, sensor->alarm_limit); + + sensor->alarm_enabled = gtk_toggle_button_get_active(w_alarm); + config_set_sensor_alarm_enabled(sensor->id, + sensor->alarm_enabled); + + gtk_color_button_get_color(w_color, color); + color_set(sensor->color, color->red, color->green, color->blue); + config_set_sensor_color(sensor->id, sensor->color); + + ui_sensorlist_update_sensors_preferences + (cb_data->ui_sensorlist); + } + + g_object_unref(G_OBJECT(builder)); + + gtk_widget_destroy(GTK_WIDGET(diag)); +} + +GtkWidget *create_sensor_popup(struct ui_sensorlist *ui_sensorlist, + struct psensor *sensor) +{ + GtkWidget *menu; + GtkWidget *item; + GtkWidget *separator; + struct cb_data *data; + + menu = gtk_menu_new(); + + item = gtk_menu_item_new_with_label(sensor->name); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + separator = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator); + + item = gtk_menu_item_new_with_label(_("Preferences")); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + data = malloc(sizeof(struct cb_data)); + data->ui_sensorlist = ui_sensorlist; + data->sensor = sensor; + + g_signal_connect(item, + "activate", + G_CALLBACK(cb_sensor_settings_activated), data); + + gtk_widget_show_all(menu); + + return menu; +} + +int +cb_sensor_line_clicked(GtkWidget *widget, + GdkEventButton *event, gpointer data) +{ + struct ui_sensorlist *list = (struct ui_sensorlist *)data; + GtkTreeView *view = GTK_TREE_VIEW(list->widget); + + struct psensor *sensor = ui_sensorlist_get_sensor_at_pos(view, + event->x, + event->y, + list->sensors); + + if (sensor) { + int coli = col_index_to_col(ui_sensorlist_get_col_index_at_pos + (view, event->x)); + + if (coli == COL_COLOR) { + if (ui_change_color(_("Select foreground color"), + sensor->color)) { + ui_sensorlist_update_sensors_preferences(list); + config_set_sensor_color(sensor->id, + sensor->color); + } + } else if (coli >= 0 && coli != COL_ENABLED) { + GtkWidget *menu = create_sensor_popup(list, + sensor); + + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, + event->button, event->time); + + } + + } + return FALSE; +} + +void +ui_sensorlist_on_toggled(GtkCellRendererToggle *cell, + gchar *path_str, gpointer data) +{ + struct ui_sensorlist *list = (struct ui_sensorlist *)data; + GtkTreeModel *model + = gtk_tree_view_get_model(GTK_TREE_VIEW(list->widget)); + GtkTreeIter iter; + GtkTreePath *path = gtk_tree_path_new_from_string(path_str); + gboolean fixed; + gint *i; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, COL_ENABLED, &fixed, -1); + + fixed ^= 1; + + i = gtk_tree_path_get_indices(path); + if (i) { + int n = *i; + struct psensor **sensor = list->sensors; + while (n--) + sensor++; + (*sensor)->enabled = fixed; + config_set_sensor_enabled((*sensor)->id, (*sensor)->enabled); + } + + gtk_list_store_set(GTK_LIST_STORE(model), + &iter, COL_ENABLED, fixed, -1); + + gtk_tree_path_free(path); +} + +void ui_sensorlist_create_widget(struct ui_sensorlist *ui) +{ + GtkListStore *store; + GtkCellRenderer *renderer; + struct psensor **sensor_cur; + struct psensor **sensors; + + sensors = ui->sensors; + + store = gtk_list_store_new(COLS_COUNT, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_BOOLEAN, G_TYPE_STRING); + + if (ui->widget) + gtk_widget_destroy(ui->widget); + + ui->widget = + GTK_WIDGET(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store))); + + gtk_tree_selection_set_mode(gtk_tree_view_get_selection + (GTK_TREE_VIEW(ui->widget)), + GTK_SELECTION_NONE); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + _("Sensor"), + renderer, + "text", COL_NAME, NULL); + + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + _("Current"), + renderer, + "text", COL_TEMP, NULL); + + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + _("Min"), + renderer, + "text", COL_TEMP_MIN, NULL); + + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + _("Max"), + renderer, + "text", COL_TEMP_MAX, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + _("Color"), + renderer, + "text", COL_COLOR, + "background", COL_COLOR_STR, + NULL); + + g_signal_connect(ui->widget, + "button-press-event", + (GCallback) cb_sensor_line_clicked, ui); + + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + _("Enabled"), + renderer, + "active", COL_ENABLED, + NULL); + g_signal_connect(G_OBJECT(renderer), "toggled", + (GCallback) ui_sensorlist_on_toggled, ui); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget), + -1, + "", + renderer, + "text", COL_EMPTY, NULL); + + sensor_cur = sensors; + while (*sensor_cur) { + GtkTreeIter iter; + GdkColor color; + gchar *scolor; + + color.red = (*sensor_cur)->color->red; + color.green = (*sensor_cur)->color->green; + color.blue = (*sensor_cur)->color->blue; + + scolor = gdk_color_to_string(&color); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + COL_NAME, (*sensor_cur)->name, + COL_TEMP, _("N/A"), + COL_TEMP_MIN, _("N/A"), + COL_TEMP_MAX, _("N/A"), + COL_COLOR_STR, scolor, + COL_ENABLED, (*sensor_cur)->enabled, -1); + + free(scolor); + + sensor_cur++; + } +} + +struct ui_sensorlist *ui_sensorlist_create(struct psensor **sensors) +{ + struct ui_sensorlist *list; + + list = malloc(sizeof(struct ui_sensorlist)); + list->sensors = sensors; + list->widget = NULL; + + ui_sensorlist_create_widget(list); + + return list; + +} diff --git a/src/ui_sensorlist.h b/src/ui_sensorlist.h new file mode 100644 index 0000000..421550e --- /dev/null +++ b/src/ui_sensorlist.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_SENSORLIST_H_ +#define _PSENSOR_UI_SENSORLIST_H_ + +#include + +#include "psensor.h" + +struct ui_sensorlist { + GtkWidget *widget; + + struct psensor **sensors; +}; + +struct ui_sensorlist *ui_sensorlist_create(struct psensor **); + +/* Update values current/min/max */ +void ui_sensorlist_update(struct ui_sensorlist *list); + +void ui_sensorlist_update_sensors_preferences(struct ui_sensorlist *); + +void ui_sensorlist_create_widget(struct ui_sensorlist *ui); + +#endif diff --git a/src/unity/Makefile.am b/src/unity/Makefile.am new file mode 100644 index 0000000..2e7c8ea --- /dev/null +++ b/src/unity/Makefile.am @@ -0,0 +1,14 @@ +if UNITY +noinst_LIBRARIES = libpsensor_unity.a + +# no -pedantic because not supported by dee.h +libpsensor_unity_a_CFLAGS = -Wall -Werror + +libpsensor_unity_a_SOURCES = \ + ui_unity.h ui_unity.c + +AM_CPPFLAGS = $(UNITY_CFLAGS) \ + -I$(top_srcdir)/src/lib + +LIBS += $(UNITY_LIBS) +endif \ No newline at end of file diff --git a/src/unity/ui_unity.c b/src/unity/ui_unity.c new file mode 100644 index 0000000..aff0b7a --- /dev/null +++ b/src/unity/ui_unity.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 "psensor.h" + +static int initialized; +static UnityLauncherEntry *psensor_entry; + +void ui_unity_launcher_entry_update(struct psensor **sensors) +{ + if (!initialized) { + psensor_entry = unity_launcher_entry_get_for_desktop_file + ("psensor.desktop"); + unity_launcher_entry_set_count_visible(psensor_entry, TRUE); + unity_launcher_entry_set_count(psensor_entry, 0); + initialized = 1; + } + + if (sensors && *sensors) { + struct psensor *s = *sensors; + double v = psensor_get_current_value(s); + + unity_launcher_entry_set_count(psensor_entry, v); + } +} diff --git a/src/unity/ui_unity.h b/src/unity/ui_unity.h new file mode 100644 index 0000000..f4ddddc --- /dev/null +++ b/src/unity/ui_unity.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2010-2011 wpitchoune@gmail.com + + 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 _PSENSOR_UI_UNITY_H_ +#define _PSENSOR_UI_UNITY_H_ + +#include "psensor.h" + +void ui_unity_launcher_entry_update(struct psensor **sensors); + +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..1acf104 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,5 @@ +check-local: checkpatch.pl + find $(top_srcdir)/src -name \*.c -exec $(srcdir)/checkpatch.pl -q --no-tree -emacs -f {} \; + find $(top_srcdir)/src -name \*.h -exec $(srcdir)/checkpatch.pl -q --no-tree -emacs -f {} \; + +EXTRA_DIST = checkpatch.pl \ No newline at end of file diff --git a/tests/checkpatch.pl b/tests/checkpatch.pl new file mode 100755 index 0000000..0b0defa --- /dev/null +++ b/tests/checkpatch.pl @@ -0,0 +1,2823 @@ +#!/usr/bin/perl -w + +# This script has been copied from Linux Kernel sources. +# +# (c) 2001, Dave Jones. (the file handling bit) +# (c) 2005, Joel Schopp (the ugly bit) +# (c) 2007,2008, Andy Whitcroft (new conditions, test suite) +# (c) 2008,2009, Andy Whitcroft +# Licensed under the terms of the GNU GPL License version 2 + +use strict; + +my $P = $0; +$P =~ s@.*/@@g; + +my $V = '0.30'; + +use Getopt::Long qw(:config no_auto_abbrev); + +my $quiet = 0; +my $tree = 1; +my $chk_signoff = 1; +my $chk_patch = 1; +my $tst_only; +my $emacs = 0; +my $terse = 0; +my $file = 0; +my $check = 0; +my $summary = 1; +my $mailback = 0; +my $summary_file = 0; +my $root; +my %debug; +my $help = 0; + +sub help { + my ($exitcode) = @_; + + print << "EOM"; +Usage: $P [OPTION]... [FILE]... +Version: $V + +Options: + -q, --quiet quiet + --no-tree run without a kernel tree + --no-signoff do not check for 'Signed-off-by' line + --patch treat FILE as patchfile (default) + --emacs emacs compile window format + --terse one line per report + -f, --file treat FILE as regular source file + --subjective, --strict enable more subjective tests + --root=PATH PATH to the kernel tree root + --no-summary suppress the per-file summary + --mailback only produce a report in case of warnings/errors + --summary-file include the filename in summary + --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of + 'values', 'possible', 'type', and 'attr' (default + is all off) + --test-only=WORD report only warnings/errors containing WORD + literally + -h, --help, --version display this help and exit + +When FILE is - read standard input. +EOM + + exit($exitcode); +} + +GetOptions( + 'q|quiet+' => \$quiet, + 'tree!' => \$tree, + 'signoff!' => \$chk_signoff, + 'patch!' => \$chk_patch, + 'emacs!' => \$emacs, + 'terse!' => \$terse, + 'f|file!' => \$file, + 'subjective!' => \$check, + 'strict!' => \$check, + 'root=s' => \$root, + 'summary!' => \$summary, + 'mailback!' => \$mailback, + 'summary-file!' => \$summary_file, + + 'debug=s' => \%debug, + 'test-only=s' => \$tst_only, + 'h|help' => \$help, + 'version' => \$help +) or help(1); + +help(0) if ($help); + +my $exit = 0; + +if ($#ARGV < 0) { + print "$P: no input files\n"; + exit(1); +} + +my $dbg_values = 0; +my $dbg_possible = 0; +my $dbg_type = 0; +my $dbg_attr = 0; +for my $key (keys %debug) { + ## no critic + eval "\${dbg_$key} = '$debug{$key}';"; + die "$@" if ($@); +} + +if ($terse) { + $emacs = 1; + $quiet++; +} + +if ($tree) { + if (defined $root) { + if (!top_of_kernel_tree($root)) { + die "$P: $root: --root does not point at a valid tree\n"; + } + } else { + if (top_of_kernel_tree('.')) { + $root = '.'; + } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && + top_of_kernel_tree($1)) { + $root = $1; + } + } + + if (!defined $root) { + print "Must be run from the top-level dir. of a kernel tree\n"; + exit(2); + } +} + +my $emitted_corrupt = 0; + +our $Ident = qr{ + [A-Za-z_][A-Za-z\d_]* + (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* + }x; +our $Storage = qr{extern|static|asmlinkage}; +our $Sparse = qr{ + __user| + __kernel| + __force| + __iomem| + __must_check| + __init_refok| + __kprobes| + __ref + }x; + +# Notes to $Attribute: +# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check +our $Attribute = qr{ + const| + __read_mostly| + __kprobes| + __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)| + ____cacheline_aligned| + ____cacheline_aligned_in_smp| + ____cacheline_internodealigned_in_smp| + __weak + }x; +our $Modifier; +our $Inline = qr{inline|__always_inline|noinline}; +our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; +our $Lval = qr{$Ident(?:$Member)*}; + +our $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*}; +our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; +our $Compare = qr{<=|>=|==|!=|<|>}; +our $Operators = qr{ + <=|>=|==|!=| + =>|->|<<|>>|<|>|!|~| + &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% + }x; + +our $NonptrType; +our $Type; +our $Declare; + +our $UTF8 = qr { + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 +}x; + +our $typeTypedefs = qr{(?x: + (?:__)?(?:u|s|be|le)(?:8|16|32|64)| + atomic_t +)}; + +our $logFunctions = qr{(?x: + printk| + pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)| + dev_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)| + WARN| + panic +)}; + +our @typeList = ( + qr{void}, + qr{(?:unsigned\s+)?char}, + qr{(?:unsigned\s+)?short}, + qr{(?:unsigned\s+)?int}, + qr{(?:unsigned\s+)?long}, + qr{(?:unsigned\s+)?long\s+int}, + qr{(?:unsigned\s+)?long\s+long}, + qr{(?:unsigned\s+)?long\s+long\s+int}, + qr{unsigned}, + qr{float}, + qr{double}, + qr{bool}, + qr{struct\s+$Ident}, + qr{union\s+$Ident}, + qr{enum\s+$Ident}, + qr{${Ident}_t}, + qr{${Ident}_handler}, + qr{${Ident}_handler_fn}, +); +our @modifierList = ( + qr{fastcall}, +); + +sub build_types { + my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; + my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; + $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; + $NonptrType = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| + (?:$typeTypedefs\b)| + (?:${all}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $Type = qr{ + $NonptrType + (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? + (?:\s+$Inline|\s+$Modifier)* + }x; + $Declare = qr{(?:$Storage\s+)?$Type}; +} +build_types(); + +$chk_signoff = 0 if ($file); + +my @dep_includes = (); +my @dep_functions = (); +my $removal = "Documentation/feature-removal-schedule.txt"; +if ($tree && -f "$root/$removal") { + open(my $REMOVE, '<', "$root/$removal") || + die "$P: $removal: open failed - $!\n"; + while (<$REMOVE>) { + if (/^Check:\s+(.*\S)/) { + for my $entry (split(/[, ]+/, $1)) { + if ($entry =~ m@include/(.*)@) { + push(@dep_includes, $1); + + } elsif ($entry !~ m@/@) { + push(@dep_functions, $entry); + } + } + } + } + close($REMOVE); +} + +my @rawlines = (); +my @lines = (); +my $vname; +for my $filename (@ARGV) { + my $FILE; + if ($file) { + open($FILE, '-|', "diff -u /dev/null $filename") || + die "$P: $filename: diff failed - $!\n"; + } elsif ($filename eq '-') { + open($FILE, '<&STDIN'); + } else { + open($FILE, '<', "$filename") || + die "$P: $filename: open failed - $!\n"; + } + if ($filename eq '-') { + $vname = 'Your patch'; + } else { + $vname = $filename; + } + while (<$FILE>) { + chomp; + push(@rawlines, $_); + } + close($FILE); + if (!process($filename)) { + $exit = 1; + } + @rawlines = (); + @lines = (); +} + +exit($exit); + +sub top_of_kernel_tree { + my ($root) = @_; + + my @tree_check = ( + "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", + "README", "Documentation", "arch", "include", "drivers", + "fs", "init", "ipc", "kernel", "lib", "scripts", + ); + + foreach my $check (@tree_check) { + if (! -e $root . '/' . $check) { + return 0; + } + } + return 1; +} + +sub expand_tabs { + my ($str) = @_; + + my $res = ''; + my $n = 0; + for my $c (split(//, $str)) { + if ($c eq "\t") { + $res .= ' '; + $n++; + for (; ($n % 8) != 0; $n++) { + $res .= ' '; + } + next; + } + $res .= $c; + $n++; + } + + return $res; +} +sub copy_spacing { + (my $res = shift) =~ tr/\t/ /c; + return $res; +} + +sub line_stats { + my ($line) = @_; + + # Drop the diff line leader and expand tabs + $line =~ s/^.//; + $line = expand_tabs($line); + + # Pick the indent from the front of the line. + my ($white) = ($line =~ /^(\s*)/); + + return (length($line), length($white)); +} + +my $sanitise_quote = ''; + +sub sanitise_line_reset { + my ($in_comment) = @_; + + if ($in_comment) { + $sanitise_quote = '*/'; + } else { + $sanitise_quote = ''; + } +} +sub sanitise_line { + my ($line) = @_; + + my $res = ''; + my $l = ''; + + my $qlen = 0; + my $off = 0; + my $c; + + # Always copy over the diff marker. + $res = substr($line, 0, 1); + + for ($off = 1; $off < length($line); $off++) { + $c = substr($line, $off, 1); + + # Comments we are wacking completly including the begin + # and end, all to $;. + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { + $sanitise_quote = '*/'; + + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { + $sanitise_quote = ''; + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { + $sanitise_quote = '//'; + + substr($res, $off, 2, $sanitise_quote); + $off++; + next; + } + + # A \ in a string means ignore the next character. + if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && + $c eq "\\") { + substr($res, $off, 2, 'XX'); + $off++; + next; + } + # Regular quotes. + if ($c eq "'" || $c eq '"') { + if ($sanitise_quote eq '') { + $sanitise_quote = $c; + + substr($res, $off, 1, $c); + next; + } elsif ($sanitise_quote eq $c) { + $sanitise_quote = ''; + } + } + + #print "c<$c> SQ<$sanitise_quote>\n"; + if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { + substr($res, $off, 1, 'X'); + } else { + substr($res, $off, 1, $c); + } + } + + if ($sanitise_quote eq '//') { + $sanitise_quote = ''; + } + + # The pathname on a #include may be surrounded by '<' and '>'. + if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { + my $clean = 'X' x length($1); + $res =~ s@\<.*\>@<$clean>@; + + # The whole of a #error is a string. + } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { + my $clean = 'X' x length($1); + $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; + } + + return $res; +} + +sub ctx_statement_block { + my ($linenr, $remain, $off) = @_; + my $line = $linenr - 1; + my $blk = ''; + my $soff = $off; + my $coff = $off - 1; + my $coff_set = 0; + + my $loff = 0; + + my $type = ''; + my $level = 0; + my @stack = (); + my $p; + my $c; + my $len = 0; + + my $remainder; + while (1) { + @stack = (['', 0]) if ($#stack == -1); + + #warn "CSB: blk<$blk> remain<$remain>\n"; + # If we are about to drop off the end, pull in more + # context. + if ($off >= $len) { + for (; $remain > 0; $line++) { + last if (!defined $lines[$line]); + next if ($lines[$line] =~ /^-/); + $remain--; + $loff = $len; + $blk .= $lines[$line] . "\n"; + $len = length($blk); + $line++; + last; + } + # Bail if there is no further context. + #warn "CSB: blk<$blk> off<$off> len<$len>\n"; + if ($off >= $len) { + last; + } + } + $p = $c; + $c = substr($blk, $off, 1); + $remainder = substr($blk, $off); + + #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; + + # Handle nested #if/#else. + if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, [ $type, $level ]); + } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { + ($type, $level) = @{$stack[$#stack - 1]}; + } elsif ($remainder =~ /^#\s*endif\b/) { + ($type, $level) = @{pop(@stack)}; + } + + # Statement ends at the ';' or a close '}' at the + # outermost level. + if ($level == 0 && $c eq ';') { + last; + } + + # An else is really a conditional as long as its not else if + if ($level == 0 && $coff_set == 0 && + (!defined($p) || $p =~ /(?:\s|\}|\+)/) && + $remainder =~ /^(else)(?:\s|{)/ && + $remainder !~ /^else\s+if\b/) { + $coff = $off + length($1) - 1; + $coff_set = 1; + #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; + #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; + } + + if (($type eq '' || $type eq '(') && $c eq '(') { + $level++; + $type = '('; + } + if ($type eq '(' && $c eq ')') { + $level--; + $type = ($level != 0)? '(' : ''; + + if ($level == 0 && $coff < $soff) { + $coff = $off; + $coff_set = 1; + #warn "CSB: mark coff<$coff>\n"; + } + } + if (($type eq '' || $type eq '{') && $c eq '{') { + $level++; + $type = '{'; + } + if ($type eq '{' && $c eq '}') { + $level--; + $type = ($level != 0)? '{' : ''; + + if ($level == 0) { + last; + } + } + $off++; + } + # We are truly at the end, so shuffle to the next line. + if ($off == $len) { + $loff = $len + 1; + $line++; + $remain--; + } + + my $statement = substr($blk, $soff, $off - $soff + 1); + my $condition = substr($blk, $soff, $coff - $soff + 1); + + #warn "STATEMENT<$statement>\n"; + #warn "CONDITION<$condition>\n"; + + #print "coff<$coff> soff<$off> loff<$loff>\n"; + + return ($statement, $condition, + $line, $remain + 1, $off - $loff + 1, $level); +} + +sub statement_lines { + my ($stmt) = @_; + + # Strip the diff line prefixes and rip blank lines at start and end. + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_rawlines { + my ($stmt) = @_; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_block_size { + my ($stmt) = @_; + + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*{//; + $stmt =~ s/}\s*$//; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + my @stmt_statements = ($stmt =~ /;/g); + + my $stmt_lines = $#stmt_lines + 2; + my $stmt_statements = $#stmt_statements + 1; + + if ($stmt_lines > $stmt_statements) { + return $stmt_lines; + } else { + return $stmt_statements; + } +} + +sub ctx_statement_full { + my ($linenr, $remain, $off) = @_; + my ($statement, $condition, $level); + + my (@chunks); + + # Grab the first conditional/block pair. + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "F: c<$condition> s<$statement> remain<$remain>\n"; + push(@chunks, [ $condition, $statement ]); + if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { + return ($level, $linenr, @chunks); + } + + # Pull in the following conditional/block pairs and see if they + # could continue the statement. + for (;;) { + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "C: c<$condition> s<$statement> remain<$remain>\n"; + last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); + #print "C: push\n"; + push(@chunks, [ $condition, $statement ]); + } + + return ($level, $linenr, @chunks); +} + +sub ctx_block_get { + my ($linenr, $remain, $outer, $open, $close, $off) = @_; + my $line; + my $start = $linenr - 1; + my $blk = ''; + my @o; + my @c; + my @res = (); + + my $level = 0; + my @stack = ($level); + for ($line = $start; $remain > 0; $line++) { + next if ($rawlines[$line] =~ /^-/); + $remain--; + + $blk .= $rawlines[$line]; + + # Handle nested #if/#else. + if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, $level); + } elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { + $level = $stack[$#stack - 1]; + } elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) { + $level = pop(@stack); + } + + foreach my $c (split(//, $rawlines[$line])) { + ##print "C<$c>L<$level><$open$close>O<$off>\n"; + if ($off > 0) { + $off--; + next; + } + + if ($c eq $close && $level > 0) { + $level--; + last if ($level == 0); + } elsif ($c eq $open) { + $level++; + } + } + + if (!$outer || $level <= 1) { + push(@res, $rawlines[$line]); + } + + last if ($level == 0); + } + + return ($level, @res); +} +sub ctx_block_outer { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); + return @r; +} +sub ctx_block { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); + return @r; +} +sub ctx_statement { + my ($linenr, $remain, $off) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); + return @r; +} +sub ctx_block_level { + my ($linenr, $remain) = @_; + + return ctx_block_get($linenr, $remain, 0, '{', '}', 0); +} +sub ctx_statement_level { + my ($linenr, $remain, $off) = @_; + + return ctx_block_get($linenr, $remain, 0, '(', ')', $off); +} + +sub ctx_locate_comment { + my ($first_line, $end_line) = @_; + + # Catch a comment on the end of the line itself. + my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); + return $current_comment if (defined $current_comment); + + # Look through the context and try and figure out if there is a + # comment. + my $in_comment = 0; + $current_comment = ''; + for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { + my $line = $rawlines[$linenr - 1]; + #warn " $line\n"; + if ($linenr == $first_line and $line =~ m@^.\s*\*@) { + $in_comment = 1; + } + if ($line =~ m@/\*@) { + $in_comment = 1; + } + if (!$in_comment && $current_comment ne '') { + $current_comment = ''; + } + $current_comment .= $line . "\n" if ($in_comment); + if ($line =~ m@\*/@) { + $in_comment = 0; + } + } + + chomp($current_comment); + return($current_comment); +} +sub ctx_has_comment { + my ($first_line, $end_line) = @_; + my $cmt = ctx_locate_comment($first_line, $end_line); + + ##print "LINE: $rawlines[$end_line - 1 ]\n"; + ##print "CMMT: $cmt\n"; + + return ($cmt ne ''); +} + +sub raw_line { + my ($linenr, $cnt) = @_; + + my $offset = $linenr - 1; + $cnt++; + + my $line; + while ($cnt) { + $line = $rawlines[$offset++]; + next if (defined($line) && $line =~ /^-/); + $cnt--; + } + + return $line; +} + +sub cat_vet { + my ($vet) = @_; + my ($res, $coded); + + $res = ''; + while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { + $res .= $1; + if ($2 ne '') { + $coded = sprintf("^%c", unpack('C', $2) + 64); + $res .= $coded; + } + } + $res =~ s/$/\$/; + + return $res; +} + +my $av_preprocessor = 0; +my $av_pending; +my @av_paren_type; +my $av_pend_colon; + +sub annotate_reset { + $av_preprocessor = 0; + $av_pending = '_'; + @av_paren_type = ('E'); + $av_pend_colon = 'O'; +} + +sub annotate_values { + my ($stream, $type) = @_; + + my $res; + my $var = '_' x length($stream); + my $cur = $stream; + + print "$stream\n" if ($dbg_values > 1); + + while (length($cur)) { + @av_paren_type = ('E') if ($#av_paren_type < 0); + print " <" . join('', @av_paren_type) . + "> <$type> <$av_pending>" if ($dbg_values > 1); + if ($cur =~ /^(\s+)/o) { + print "WS($1)\n" if ($dbg_values > 1); + if ($1 =~ /\n/ && $av_preprocessor) { + $type = pop(@av_paren_type); + $av_preprocessor = 0; + } + + } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) { + print "DECLARE($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^($Modifier)\s*/) { + print "MODIFIER($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { + print "DEFINE($1,$2)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + if ($2 ne '') { + $av_pending = 'N'; + } + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { + print "UNDEF($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + + } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { + print "PRE_START($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { + print "PRE_RESTART($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $av_paren_type[$#av_paren_type]); + + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:endif))/o) { + print "PRE_END($1)\n" if ($dbg_values > 1); + + $av_preprocessor = 1; + + # Assume all arms of the conditional end as this + # one does, and continue as if the #endif was not here. + pop(@av_paren_type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\\\n)/o) { + print "PRECONT($1)\n" if ($dbg_values > 1); + + } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { + print "ATTR($1)\n" if ($dbg_values > 1); + $av_pending = $type; + $type = 'N'; + + } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { + print "SIZEOF($1)\n" if ($dbg_values > 1); + if (defined $2) { + $av_pending = 'V'; + } + $type = 'N'; + + } elsif ($cur =~ /^(if|while|for)\b/o) { + print "COND($1)\n" if ($dbg_values > 1); + $av_pending = 'E'; + $type = 'N'; + + } elsif ($cur =~/^(case)/o) { + print "CASE($1)\n" if ($dbg_values > 1); + $av_pend_colon = 'C'; + $type = 'N'; + + } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { + print "KEYWORD($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(\()/o) { + print "PAREN('$1')\n" if ($dbg_values > 1); + push(@av_paren_type, $av_pending); + $av_pending = '_'; + $type = 'N'; + + } elsif ($cur =~ /^(\))/o) { + my $new_type = pop(@av_paren_type); + if ($new_type ne '_') { + $type = $new_type; + print "PAREN('$1') -> $type\n" + if ($dbg_values > 1); + } else { + print "PAREN('$1')\n" if ($dbg_values > 1); + } + + } elsif ($cur =~ /^($Ident)\s*\(/o) { + print "FUNC($1)\n" if ($dbg_values > 1); + $type = 'V'; + $av_pending = 'V'; + + } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { + if (defined $2 && $type eq 'C' || $type eq 'T') { + $av_pend_colon = 'B'; + } elsif ($type eq 'E') { + $av_pend_colon = 'L'; + } + print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Ident|$Constant)/o) { + print "IDENT($1)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Assignment)/o) { + print "ASSIGN($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~/^(;|{|})/) { + print "END($1)\n" if ($dbg_values > 1); + $type = 'E'; + $av_pend_colon = 'O'; + + } elsif ($cur =~/^(,)/) { + print "COMMA($1)\n" if ($dbg_values > 1); + $type = 'C'; + + } elsif ($cur =~ /^(\?)/o) { + print "QUESTION($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(:)/o) { + print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); + + substr($var, length($res), 1, $av_pend_colon); + if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { + $type = 'E'; + } else { + $type = 'N'; + } + $av_pend_colon = 'O'; + + } elsif ($cur =~ /^(\[)/o) { + print "CLOSE($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { + my $variant; + + print "OPV($1)\n" if ($dbg_values > 1); + if ($type eq 'V') { + $variant = 'B'; + } else { + $variant = 'U'; + } + + substr($var, length($res), 1, $variant); + $type = 'N'; + + } elsif ($cur =~ /^($Operators)/o) { + print "OP($1)\n" if ($dbg_values > 1); + if ($1 ne '++' && $1 ne '--') { + $type = 'N'; + } + + } elsif ($cur =~ /(^.)/o) { + print "C($1)\n" if ($dbg_values > 1); + } + if (defined $1) { + $cur = substr($cur, length($1)); + $res .= $type x length($1); + } + } + + return ($res, $var); +} + +sub possible { + my ($possible, $line) = @_; + my $notPermitted = qr{(?: + ^(?: + $Modifier| + $Storage| + $Type| + DEFINE_\S+ + )$| + ^(?: + goto| + return| + case| + else| + asm|__asm__| + do + )(?:\s|$)| + ^(?:typedef|struct|enum)\b + )}x; + warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); + if ($possible !~ $notPermitted) { + # Check for modifiers. + $possible =~ s/\s*$Storage\s*//g; + $possible =~ s/\s*$Sparse\s*//g; + if ($possible =~ /^\s*$/) { + + } elsif ($possible =~ /\s/) { + $possible =~ s/\s*$Type\s*//g; + for my $modifier (split(' ', $possible)) { + if ($modifier !~ $notPermitted) { + warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); + push(@modifierList, $modifier); + } + } + + } else { + warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); + push(@typeList, $possible); + } + build_types(); + } else { + warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); + } +} + +my $prefix = ''; + +sub report { + if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) { + return 0; + } + my $line = $prefix . $_[0]; + + $line = (split('\n', $line))[0] . "\n" if ($terse); + + push(our @report, $line); + + return 1; +} +sub report_dump { + our @report; +} +sub ERROR { + if (report("ERROR: $_[0]\n")) { + our $clean = 0; + our $cnt_error++; + } +} +sub WARN { + if (report("WARNING: $_[0]\n")) { + our $clean = 0; + our $cnt_warn++; + } +} +sub CHK { + if ($check && report("CHECK: $_[0]\n")) { + our $clean = 0; + our $cnt_chk++; + } +} + +sub check_absolute_file { + my ($absolute, $herecurr) = @_; + my $file = $absolute; + + ##print "absolute<$absolute>\n"; + + # See if any suffix of this path is a path within the tree. + while ($file =~ s@^[^/]*/@@) { + if (-f "$root/$file") { + ##print "file<$file>\n"; + last; + } + } + if (! -f _) { + return 0; + } + + # It is, so see if the prefix is acceptable. + my $prefix = $absolute; + substr($prefix, -length($file)) = ''; + + ##print "prefix<$prefix>\n"; + if ($prefix ne ".../") { + WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr); + } +} + +sub process { + my $filename = shift; + + my $linenr=0; + my $prevline=""; + my $prevrawline=""; + my $stashline=""; + my $stashrawline=""; + + my $length; + my $indent; + my $previndent=0; + my $stashindent=0; + + our $clean = 1; + my $signoff = 0; + my $is_patch = 0; + + our @report = (); + our $cnt_lines = 0; + our $cnt_error = 0; + our $cnt_warn = 0; + our $cnt_chk = 0; + + # Trace the real file/line as we go. + my $realfile = ''; + my $realline = 0; + my $realcnt = 0; + my $here = ''; + my $in_comment = 0; + my $comment_edge = 0; + my $first_line = 0; + my $p1_prefix = ''; + + my $prev_values = 'E'; + + # suppression flags + my %suppress_ifbraces; + my %suppress_whiletrailers; + my %suppress_export; + + # Pre-scan the patch sanitizing the lines. + # Pre-scan the patch looking for any __setup documentation. + # + my @setup_docs = (); + my $setup_docs = 0; + + sanitise_line_reset(); + my $line; + foreach my $rawline (@rawlines) { + $linenr++; + $line = $rawline; + + if ($rawline=~/^\+\+\+\s+(\S+)/) { + $setup_docs = 0; + if ($1 =~ m@Documentation/kernel-parameters.txt$@) { + $setup_docs = 1; + } + #next; + } + if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + $in_comment = 0; + + # Guestimate if this is a continuing comment. Run + # the context looking for a comment "edge". If this + # edge is a close comment then we must be in a comment + # at context start. + my $edge; + my $cnt = $realcnt; + for (my $ln = $linenr + 1; $cnt > 0; $ln++) { + next if (defined $rawlines[$ln - 1] && + $rawlines[$ln - 1] =~ /^-/); + $cnt--; + #print "RAW<$rawlines[$ln - 1]>\n"; + last if (!defined $rawlines[$ln - 1]); + if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && + $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { + ($edge) = $1; + last; + } + } + if (defined $edge && $edge eq '*/') { + $in_comment = 1; + } + + # Guestimate if this is a continuing comment. If this + # is the start of a diff block and this line starts + # ' *' then it is very likely a comment. + if (!defined $edge && + $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) + { + $in_comment = 1; + } + + ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; + sanitise_line_reset($in_comment); + + } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { + # Standardise the strings and chars within the input to + # simplify matching -- only bother with positive lines. + $line = sanitise_line($rawline); + } + push(@lines, $line); + + if ($realcnt > 1) { + $realcnt-- if ($line =~ /^(?:\+| |$)/); + } else { + $realcnt = 0; + } + + #print "==>$rawline\n"; + #print "-->$line\n"; + + if ($setup_docs && $line =~ /^\+/) { + push(@setup_docs, $line); + } + } + + $prefix = ''; + + $realcnt = 0; + $linenr = 0; + foreach my $line (@lines) { + $linenr++; + + my $rawline = $rawlines[$linenr - 1]; + +#extract the line range in the file after the patch is applied + if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $is_patch = 1; + $first_line = $linenr + 1; + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + annotate_reset(); + $prev_values = 'E'; + + %suppress_ifbraces = (); + %suppress_whiletrailers = (); + %suppress_export = (); + next; + +# track the line number as we move through the hunk, note that +# new versions of GNU diff omit the leading space on completely +# blank context lines so we need to count that too. + } elsif ($line =~ /^( |\+|$)/) { + $realline++; + $realcnt-- if ($realcnt != 0); + + # Measure the line length and indent. + ($length, $indent) = line_stats($rawline); + + # Track the previous line. + ($prevline, $stashline) = ($stashline, $line); + ($previndent, $stashindent) = ($stashindent, $indent); + ($prevrawline, $stashrawline) = ($stashrawline, $rawline); + + #warn "line<$line>\n"; + + } elsif ($realcnt == 1) { + $realcnt--; + } + + my $hunk_line = ($realcnt != 0); + +#make up the handle for any error we report on this line + $prefix = "$filename:$realline: " if ($emacs && $file); + $prefix = "$filename:$linenr: " if ($emacs && !$file); + + $here = "#$linenr: " if (!$file); + $here = "#$realline: " if ($file); + + # extract the filename as it passes + if ($line=~/^\+\+\+\s+(\S+)/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@; + + $p1_prefix = $1; + if (!$file && $tree && $p1_prefix ne '' && + -e "$root/$p1_prefix") { + WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); + } + + if ($realfile =~ m@^include/asm/@) { + ERROR("do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n"); + } + next; + } + + $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); + + my $hereline = "$here\n$rawline\n"; + my $herecurr = "$here\n$rawline\n"; + my $hereprev = "$here\n$prevrawline\n$rawline\n"; + + $cnt_lines++ if ($realcnt != 0); + +#check the patch for a signoff: + if ($line =~ /^\s*signed-off-by:/i) { + # This is a signoff, if ugly, so do not double report. + $signoff++; + if (!($line =~ /^\s*Signed-off-by:/)) { + WARN("Signed-off-by: is the preferred form\n" . + $herecurr); + } + if ($line =~ /^\s*signed-off-by:\S/i) { + WARN("space required after Signed-off-by:\n" . + $herecurr); + } + } + +# Check for wrappage within a valid hunk of the file + if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { + ERROR("patch seems to be corrupt (line wrapped?)\n" . + $herecurr) if (!$emitted_corrupt++); + } + +# Check for absolute kernel paths. + if ($tree) { + while ($line =~ m{(?:^|\s)(/\S*)}g) { + my $file = $1; + + if ($file =~ m{^(.*?)(?::\d+)+:?$} && + check_absolute_file($1, $herecurr)) { + # + } else { + check_absolute_file($file, $herecurr); + } + } + } + +# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php + if (($realfile =~ /^$/ || $line =~ /^\+/) && + $rawline !~ m/^$UTF8*$/) { + my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); + + my $blank = copy_spacing($rawline); + my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; + my $hereptr = "$hereline$ptr\n"; + + ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); + } + +# ignore non-hunk lines and lines being removed + next if (!$hunk_line || $line =~ /^-/); + +#trailing whitespace + if ($line =~ /^\+.*\015/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + ERROR("DOS line endings\n" . $herevet); + + } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + ERROR("trailing whitespace\n" . $herevet); + } + +# check for Kconfig help text having a real description + if ($realfile =~ /Kconfig/ && + $line =~ /\+?\s*(---)?help(---)?$/) { + my $length = 0; + for (my $l = $linenr; defined($lines[$l]); $l++) { + my $f = $lines[$l]; + $f =~ s/#.*//; + $f =~ s/^\s+//; + next if ($f =~ /^$/); + last if ($f =~ /^\s*config\s/); + $length++; + } + WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($length < 4); + } + +# check we are in a valid source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); + +#80 column limit + if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && + $rawline !~ /^.\s*\*\s*\@$Ident\s/ && + $line !~ /^\+\s*$logFunctions\s*\(\s*(?:KERN_\S+\s*)?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ && + $length > 80) + { + WARN("line over 80 characters\n" . $herecurr); + } + +# check for spaces before a quoted newline + if ($rawline =~ /^.*\".*\s\\n/) { + WARN("unnecessary whitespace before a quoted newline\n" . $herecurr); + } + +# check for adding lines without a newline. + if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { + WARN("adding a line without newline at end of file\n" . $herecurr); + } + +# Blackfin: use hi/lo macros + if ($realfile =~ m@arch/blackfin/.*\.S$@) { + if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("use the LO() macro, not (... & 0xFFFF)\n" . $herevet); + } + if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("use the HI() macro, not (... >> 16)\n" . $herevet); + } + } + +# check we are in a valid source file C or perl if not then ignore this hunk + next if ($realfile !~ /\.(h|c|pl)$/); + +# at the beginning of a line any tabs must come first and anything +# more than 8 must use tabs. + if ($rawline =~ /^\+\s* \t\s*\S/ || + $rawline =~ /^\+\s* \s*/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + ERROR("code indent should use tabs where possible\n" . $herevet); + } + +# check for space before tabs. + if ($rawline =~ /^\+/ && $rawline =~ / \t/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + WARN("please, no space before tabs\n" . $herevet); + } + +# check we are in a valid C source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c)$/); + +# check for RCS/CVS revision markers + if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { + WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr); + } + +# Blackfin: don't use __builtin_bfin_[cs]sync + if ($line =~ /__builtin_bfin_csync/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("use the CSYNC() macro in asm/blackfin.h\n" . $herevet); + } + if ($line =~ /__builtin_bfin_ssync/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("use the SSYNC() macro in asm/blackfin.h\n" . $herevet); + } + +# Check for potential 'bare' types + my ($stat, $cond, $line_nr_next, $remain_next, $off_next, + $realline_next); + if ($realcnt && $line =~ /.\s*\S/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0); + $stat =~ s/\n./\n /g; + $cond =~ s/\n./\n /g; + + # Find the real next line. + $realline_next = $line_nr_next; + if (defined $realline_next && + (!defined $lines[$realline_next - 1] || + substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { + $realline_next++; + } + + my $s = $stat; + $s =~ s/{.*$//s; + + # Ignore goto labels. + if ($s =~ /$Ident:\*$/s) { + + # Ignore functions being called + } elsif ($s =~ /^.\s*$Ident\s*\(/s) { + + } elsif ($s =~ /^.\s*else\b/s) { + + # declarations always start with types + } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { + my $type = $1; + $type =~ s/\s+/ /g; + possible($type, "A:" . $s); + + # definitions in global scope can only start with types + } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { + possible($1, "B:" . $s); + } + + # any (foo ... *) is a pointer cast, and foo is a type + while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { + possible($1, "C:" . $s); + } + + # Check for any sort of function declaration. + # int foo(something bar, other baz); + # void (*store_gdt)(x86_descr_ptr *); + if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { + my ($name_len) = length($1); + + my $ctx = $s; + substr($ctx, 0, $name_len + 1, ''); + $ctx =~ s/\)[^\)]*$//; + + for my $arg (split(/\s*,\s*/, $ctx)) { + if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { + + possible($1, "D:" . $s); + } + } + } + + } + +# +# Checks which may be anchored in the context. +# + +# Check for switch () and associated case and default +# statements should be at the same indent. + if ($line=~/\bswitch\s*\(.*\)/) { + my $err = ''; + my $sep = ''; + my @ctx = ctx_block_outer($linenr, $realcnt); + shift(@ctx); + for my $ctx (@ctx) { + my ($clen, $cindent) = line_stats($ctx); + if ($ctx =~ /^\+\s*(case\s+|default:)/ && + $indent != $cindent) { + $err .= "$sep$ctx\n"; + $sep = ''; + } else { + $sep = "[...]\n"; + } + } + if ($err ne '') { + ERROR("switch and case should be at the same indent\n$hereline$err"); + } + } + +# if/while/etc brace do not go on next line, unless defining a do while loop, +# or if that brace on the next line is for something else + if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { + my $pre_ctx = "$1$2"; + + my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); + my $ctx_cnt = $realcnt - $#ctx - 1; + my $ctx = join("\n", @ctx); + + my $ctx_ln = $linenr; + my $ctx_skip = $realcnt; + + while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && + defined $lines[$ctx_ln - 1] && + $lines[$ctx_ln - 1] =~ /^-/)) { + ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; + $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); + $ctx_ln++; + } + + #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; + #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; + + if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { + ERROR("that open brace { should be on the previous line\n" . + "$here\n$ctx\n$lines[$ctx_ln - 1]\n"); + } + if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && + $ctx =~ /\)\s*\;\s*$/ && + defined $lines[$ctx_ln - 1]) + { + my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); + if ($nindent > $indent) { + WARN("trailing semicolon indicates no statements, indent implies otherwise\n" . + "$here\n$ctx\n$lines[$ctx_ln - 1]\n"); + } + } + } + +# Check relative indent for conditionals and blocks. + if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + my ($s, $c) = ($stat, $cond); + + substr($s, 0, length($c), ''); + + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + + # We want to check the first line inside the block + # starting at the end of the conditional, so remove: + # 1) any blank line termination + # 2) any opening brace { on end of the line + # 3) any do (...) { + my $continuation = 0; + my $check = 0; + $s =~ s/^.*\bdo\b//; + $s =~ s/^\s*{//; + if ($s =~ s/^\s*\\//) { + $continuation = 1; + } + if ($s =~ s/^\s*?\n//) { + $check = 1; + $cond_lines++; + } + + # Also ignore a loop construct at the end of a + # preprocessor statement. + if (($prevline =~ /^.\s*#\s*define\s/ || + $prevline =~ /\\\s*$/) && $continuation == 0) { + $check = 0; + } + + my $cond_ptr = -1; + $continuation = 0; + while ($cond_ptr != $cond_lines) { + $cond_ptr = $cond_lines; + + # If we see an #else/#elif then the code + # is not linear. + if ($s =~ /^\s*\#\s*(?:else|elif)/) { + $check = 0; + } + + # Ignore: + # 1) blank lines, they should be at 0, + # 2) preprocessor lines, and + # 3) labels. + if ($continuation || + $s =~ /^\s*?\n/ || + $s =~ /^\s*#\s*?/ || + $s =~ /^\s*$Ident\s*:/) { + $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; + if ($s =~ s/^.*?\n//) { + $cond_lines++; + } + } + } + + my (undef, $sindent) = line_stats("+" . $s); + my $stat_real = raw_line($linenr, $cond_lines); + + # Check if either of these lines are modified, else + # this is not this patch's fault. + if (!defined($stat_real) || + $stat !~ /^\+/ && $stat_real !~ /^\+/) { + $check = 0; + } + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; + + if ($check && (($sindent % 8) != 0 || + ($sindent <= $indent && $s ne ''))) { + WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); + } + } + + # Track the 'values' across context and added lines. + my $opline = $line; $opline =~ s/^./ /; + my ($curr_values, $curr_vars) = + annotate_values($opline . "\n", $prev_values); + $curr_values = $prev_values . $curr_values; + if ($dbg_values) { + my $outline = $opline; $outline =~ s/\t/ /g; + print "$linenr > .$outline\n"; + print "$linenr > $curr_values\n"; + print "$linenr > $curr_vars\n"; + } + $prev_values = substr($curr_values, -1); + +#ignore lines not being added + if ($line=~/^[^\+]/) {next;} + +# TEST: allow direct testing of the type matcher. + if ($dbg_type) { + if ($line =~ /^.\s*$Declare\s*$/) { + ERROR("TEST: is type\n" . $herecurr); + } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { + ERROR("TEST: is not type ($1 is)\n". $herecurr); + } + next; + } +# TEST: allow direct testing of the attribute matcher. + if ($dbg_attr) { + if ($line =~ /^.\s*$Modifier\s*$/) { + ERROR("TEST: is attr\n" . $herecurr); + } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { + ERROR("TEST: is not attr ($1 is)\n". $herecurr); + } + next; + } + +# check for initialisation to aggregates open brace on the next line + if ($line =~ /^.\s*{/ && + $prevline =~ /(?:^|[^=])=\s*$/) { + ERROR("that open brace { should be on the previous line\n" . $hereprev); + } + +# +# Checks which are anchored on the added line. +# + +# check for malformed paths in #include statements (uses RAW line) + if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { + my $path = $1; + if ($path =~ m{//}) { + ERROR("malformed #include filename\n" . + $herecurr); + } + } + +# no C99 // comments + if ($line =~ m{//}) { + ERROR("do not use C99 // comments\n" . $herecurr); + } + # Remove C99 comments. + $line =~ s@//.*@@; + $opline =~ s@//.*@@; + +# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider +# the whole statement. +#print "APW <$lines[$realline_next - 1]>\n"; + if (defined $realline_next && + exists $lines[$realline_next - 1] && + !defined $suppress_export{$realline_next} && + ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + my $name = $1; + if ($stat !~ /(?: + \n.}\s*$| + ^.DEFINE_$Ident\(\Q$name\E\)| + ^.DECLARE_$Ident\(\Q$name\E\)| + ^.LIST_HEAD\(\Q$name\E\)| + ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| + \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() + )/x) { +#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; + $suppress_export{$realline_next} = 2; + } else { + $suppress_export{$realline_next} = 1; + } + } + if (!defined $suppress_export{$linenr} && + $prevline =~ /^.\s*$/ && + ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { +#print "FOO B <$lines[$linenr - 1]>\n"; + $suppress_export{$linenr} = 2; + } + if (defined $suppress_export{$linenr} && + $suppress_export{$linenr} == 2) { + WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); + } + +# check for external initialisers. + if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { + ERROR("do not initialise externals to 0 or NULL\n" . + $herecurr); + } +# check for static initialisers. + if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { + ERROR("do not initialise statics to 0 or NULL\n" . + $herecurr); + } + +# check for new typedefs, only function parameters and sparse annotations +# make sense. + if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && + $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && + $line !~ /\b__bitwise(?:__|)\b/) { + WARN("do not add new typedefs\n" . $herecurr); + } + +# * goes on variable not on type + # (char*[ const]) + if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { + my ($from, $to) = ($1, $1); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + + #print "from<$from> to<$to>\n"; + if ($from ne $to) { + ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); + } + } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { + my ($from, $to, $ident) = ($1, $1, $2); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + # Modifiers should have spaces. + $to =~ s/(\b$Modifier$)/$1 /; + + #print "from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to && $ident !~ /^$Modifier$/) { + ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); + } + } + +# # no BUG() or BUG_ON() +# if ($line =~ /\b(BUG|BUG_ON)\b/) { +# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n"; +# print "$herecurr"; +# $clean = 0; +# } + + if ($line =~ /\bLINUX_VERSION_CODE\b/) { + WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); + } + +# printk should use KERN_* levels. Note that follow on printk's on the +# same line do not need a level, so we use the current block context +# to try and find and validate the current printk. In summary the current +# printk includes all preceeding printk's which have no newline on the end. +# we assume the first bad printk is the one to report. + if ($line =~ /\bprintk\((?!KERN_)\s*"/) { + my $ok = 0; + for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) { + #print "CHECK<$lines[$ln - 1]\n"; + # we have a preceeding printk if it ends + # with "\n" ignore it, else it is to blame + if ($lines[$ln - 1] =~ m{\bprintk\(}) { + if ($rawlines[$ln - 1] !~ m{\\n"}) { + $ok = 1; + } + last; + } + } + if ($ok == 0) { + WARN("printk() should include KERN_ facility level\n" . $herecurr); + } + } + +# function brace can't be on same line, except for #defines of do while, +# or if closed on same line + if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and + !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) { + ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr); + } + +# open braces for enum, union and struct go on the same line. + if ($line =~ /^.\s*{/ && + $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { + ERROR("open brace '{' following $1 go on the same line\n" . $hereprev); + } + +# check for spacing round square brackets; allowed: +# 1. with a type on the left -- int [] a; +# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, +# 3. inside a curly brace -- = { [0...10] = 5 } + while ($line =~ /(.*?\s)\[/g) { + my ($where, $prefix) = ($-[1], $1); + if ($prefix !~ /$Type\s+$/ && + ($where != 0 || $prefix !~ /^.\s+$/) && + $prefix !~ /{\s+$/) { + ERROR("space prohibited before open square bracket '['\n" . $herecurr); + } + } + +# check for spaces between functions and their parentheses. + while ($line =~ /($Ident)\s+\(/g) { + my $name = $1; + my $ctx_before = substr($line, 0, $-[1]); + my $ctx = "$ctx_before$name"; + + # Ignore those directives where spaces _are_ permitted. + if ($name =~ /^(?: + if|for|while|switch|return|case| + volatile|__volatile__| + __attribute__|format|__extension__| + asm|__asm__)$/x) + { + + # cpp #define statements have non-optional spaces, ie + # if there is a space between the name and the open + # parenthesis it is simply not a parameter group. + } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { + + # cpp #elif statement condition may start with a ( + } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { + + # If this whole things ends with a type its most + # likely a typedef for a function. + } elsif ($ctx =~ /$Type$/) { + + } else { + WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr); + } + } +# Check operator spacing. + if (!($line=~/\#\s*include/)) { + my $ops = qr{ + <<=|>>=|<=|>=|==|!=| + \+=|-=|\*=|\/=|%=|\^=|\|=|&=| + =>|->|<<|>>|<|>|=|!|~| + &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| + \?|: + }x; + my @elements = split(/($ops|;)/, $opline); + my $off = 0; + + my $blank = copy_spacing($opline); + + for (my $n = 0; $n < $#elements; $n += 2) { + $off += length($elements[$n]); + + # Pick up the preceeding and succeeding characters. + my $ca = substr($opline, 0, $off); + my $cc = ''; + if (length($opline) >= ($off + length($elements[$n + 1]))) { + $cc = substr($opline, $off + length($elements[$n + 1])); + } + my $cb = "$ca$;$cc"; + + my $a = ''; + $a = 'V' if ($elements[$n] ne ''); + $a = 'W' if ($elements[$n] =~ /\s$/); + $a = 'C' if ($elements[$n] =~ /$;$/); + $a = 'B' if ($elements[$n] =~ /(\[|\()$/); + $a = 'O' if ($elements[$n] eq ''); + $a = 'E' if ($ca =~ /^\s*$/); + + my $op = $elements[$n + 1]; + + my $c = ''; + if (defined $elements[$n + 2]) { + $c = 'V' if ($elements[$n + 2] ne ''); + $c = 'W' if ($elements[$n + 2] =~ /^\s/); + $c = 'C' if ($elements[$n + 2] =~ /^$;/); + $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); + $c = 'O' if ($elements[$n + 2] eq ''); + $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); + } else { + $c = 'E'; + } + + my $ctx = "${a}x${c}"; + + my $at = "(ctx:$ctx)"; + + my $ptr = substr($blank, 0, $off) . "^"; + my $hereptr = "$hereline$ptr\n"; + + # Pull out the value of this operator. + my $op_type = substr($curr_values, $off + 1, 1); + + # Get the full operator variant. + my $opv = $op . substr($curr_vars, $off, 1); + + # Ignore operators passed as parameters. + if ($op_type ne 'V' && + $ca =~ /\s$/ && $cc =~ /^\s*,/) { + +# # Ignore comments +# } elsif ($op =~ /^$;+$/) { + + # ; should have either the end of line or a space or \ after it + } elsif ($op eq ';') { + if ($ctx !~ /.x[WEBC]/ && + $cc !~ /^\\/ && $cc !~ /^;/) { + ERROR("space required after that '$op' $at\n" . $hereptr); + } + + # // is a comment + } elsif ($op eq '//') { + + # No spaces for: + # -> + # : when part of a bitfield + } elsif ($op eq '->' || $opv eq ':B') { + if ($ctx =~ /Wx.|.xW/) { + ERROR("spaces prohibited around that '$op' $at\n" . $hereptr); + } + + # , must have a space on the right. + } elsif ($op eq ',') { + if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { + ERROR("space required after that '$op' $at\n" . $hereptr); + } + + # '*' as part of a type definition -- reported already. + } elsif ($opv eq '*_') { + #warn "'*' is part of type\n"; + + # unary operators should have a space before and + # none after. May be left adjacent to another + # unary operator, or a cast + } elsif ($op eq '!' || $op eq '~' || + $opv eq '*U' || $opv eq '-U' || + $opv eq '&U' || $opv eq '&&U') { + if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { + ERROR("space required before that '$op' $at\n" . $hereptr); + } + if ($op eq '*' && $cc =~/\s*$Modifier\b/) { + # A unary '*' may be const + + } elsif ($ctx =~ /.xW/) { + ERROR("space prohibited after that '$op' $at\n" . $hereptr); + } + + # unary ++ and unary -- are allowed no space on one side. + } elsif ($op eq '++' or $op eq '--') { + if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { + ERROR("space required one side of that '$op' $at\n" . $hereptr); + } + if ($ctx =~ /Wx[BE]/ || + ($ctx =~ /Wx./ && $cc =~ /^;/)) { + ERROR("space prohibited before that '$op' $at\n" . $hereptr); + } + if ($ctx =~ /ExW/) { + ERROR("space prohibited after that '$op' $at\n" . $hereptr); + } + + + # << and >> may either have or not have spaces both sides + } elsif ($op eq '<<' or $op eq '>>' or + $op eq '&' or $op eq '^' or $op eq '|' or + $op eq '+' or $op eq '-' or + $op eq '*' or $op eq '/' or + $op eq '%') + { + if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { + ERROR("need consistent spacing around '$op' $at\n" . + $hereptr); + } + + # A colon needs no spaces before when it is + # terminating a case value or a label. + } elsif ($opv eq ':C' || $opv eq ':L') { + if ($ctx =~ /Wx./) { + ERROR("space prohibited before that '$op' $at\n" . $hereptr); + } + + # All the others need spaces both sides. + } elsif ($ctx !~ /[EWC]x[CWE]/) { + my $ok = 0; + + # Ignore email addresses + if (($op eq '<' && + $cc =~ /^\S+\@\S+>/) || + ($op eq '>' && + $ca =~ /<\S+\@\S+$/)) + { + $ok = 1; + } + + # Ignore ?: + if (($opv eq ':O' && $ca =~ /\?$/) || + ($op eq '?' && $cc =~ /^:/)) { + $ok = 1; + } + + if ($ok == 0) { + ERROR("spaces required around that '$op' $at\n" . $hereptr); + } + } + $off += length($elements[$n + 1]); + } + } + +# check for multiple assignments + if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { + CHK("multiple assignments should be avoided\n" . $herecurr); + } + +## # check for multiple declarations, allowing for a function declaration +## # continuation. +## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && +## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { +## +## # Remove any bracketed sections to ensure we do not +## # falsly report the parameters of functions. +## my $ln = $line; +## while ($ln =~ s/\([^\(\)]*\)//g) { +## } +## if ($ln =~ /,/) { +## WARN("declaring multiple variables together should be avoided\n" . $herecurr); +## } +## } + +#need space before brace following if, while, etc + if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) || + $line =~ /do{/) { + ERROR("space required before the open brace '{'\n" . $herecurr); + } + +# closing brace should have a space following it when it has anything +# on the line + if ($line =~ /}(?!(?:,|;|\)))\S/) { + ERROR("space required after that close brace '}'\n" . $herecurr); + } + +# check spacing on square brackets + if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { + ERROR("space prohibited after that open square bracket '['\n" . $herecurr); + } + if ($line =~ /\s\]/) { + ERROR("space prohibited before that close square bracket ']'\n" . $herecurr); + } + +# check spacing on parentheses + if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && + $line !~ /for\s*\(\s+;/) { + ERROR("space prohibited after that open parenthesis '('\n" . $herecurr); + } + if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && + $line !~ /for\s*\(.*;\s+\)/ && + $line !~ /:\s+\)/) { + ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr); + } + +#goto labels aren't indented, allow a single space however + if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and + !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { + WARN("labels should not be indented\n" . $herecurr); + } + +# Return is not a function. + if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { + my $spacing = $1; + my $value = $2; + + # Flatten any parentheses + $value =~ s/\)\(/\) \(/g; + while ($value =~ s/\[[^\{\}]*\]/1/ || + $value !~ /(?:$Ident|-?$Constant)\s* + $Compare\s* + (?:$Ident|-?$Constant)/x && + $value =~ s/\([^\(\)]*\)/1/) { + } + + if ($value =~ /^(?:$Ident|-?$Constant)$/) { + ERROR("return is not a function, parentheses are not required\n" . $herecurr); + + } elsif ($spacing !~ /\s+/) { + ERROR("space required before the open parenthesis '('\n" . $herecurr); + } + } + +# Need a space before open parenthesis after if, while etc + if ($line=~/\b(if|while|for|switch)\(/) { + ERROR("space required before the open parenthesis '('\n" . $herecurr); + } + +# Check for illegal assignment in if conditional -- and check for trailing +# statements after the conditional. + if ($line =~ /do\s*(?!{)/) { + my ($stat_next) = ctx_statement_block($line_nr_next, + $remain_next, $off_next); + $stat_next =~ s/\n./\n /g; + ##print "stat<$stat> stat_next<$stat_next>\n"; + + if ($stat_next =~ /^\s*while\b/) { + # If the statement carries leading newlines, + # then count those as offsets. + my ($whitespace) = + ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = + statement_rawlines($whitespace) - 1; + + $suppress_whiletrailers{$line_nr_next + + $offset} = 1; + } + } + if (!defined $suppress_whiletrailers{$linenr} && + $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { + my ($s, $c) = ($stat, $cond); + + if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { + ERROR("do not use assignment in if condition\n" . $herecurr); + } + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + $s =~ s/$;//g; # Remove any comments + if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && + $c !~ /}\s*while\s*/) + { + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + my $stat_real = ''; + + $stat_real = raw_line($linenr, $cond_lines) + . "\n" if ($cond_lines); + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real); + } + } + +# Check for bitwise tests written as boolean + if ($line =~ / + (?: + (?:\[|\(|\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\|) + | + (?:\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\||\)|\]) + )/x) + { + WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); + } + +# if and else should not have general statements after it + if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { + my $s = $1; + $s =~ s/$;//g; # Remove any comments + if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { + ERROR("trailing statements should be on next line\n" . $herecurr); + } + } +# if should not continue a brace + if ($line =~ /}\s*if\b/) { + ERROR("trailing statements should be on next line\n" . + $herecurr); + } +# case and default should not have general statements after them + if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && + $line !~ /\G(?: + (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| + \s*return\s+ + )/xg) + { + ERROR("trailing statements should be on next line\n" . $herecurr); + } + + # Check for }else {, these must be at the same + # indent level to be relevant to each other. + if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and + $previndent == $indent) { + ERROR("else should follow close brace '}'\n" . $hereprev); + } + + if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and + $previndent == $indent) { + my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + + if ($s =~ /^\s*;/) { + ERROR("while should follow close brace '}'\n" . $hereprev); + } + } + +#studly caps, commented out until figure out how to distinguish between use of existing and adding new +# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) { +# print "No studly caps, use _\n"; +# print "$herecurr"; +# $clean = 0; +# } + +#no spaces allowed after \ in define + if ($line=~/\#\s*define.*\\\s$/) { + WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr); + } + +#warn if is #included and is available (uses RAW line) + if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\}) { + my $file = "$1.h"; + my $checkfile = "include/linux/$file"; + if (-f "$root/$checkfile" && + $realfile ne $checkfile && + $1 ne 'irq') + { + if ($realfile =~ m{^arch/}) { + CHK("Consider using #include instead of \n" . $herecurr); + } else { + WARN("Use #include instead of \n" . $herecurr); + } + } + } + +# multi-statement macros should be enclosed in a do while loop, grab the +# first statement and ensure its the whole macro if its not enclosed +# in a known good container + if ($realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + + my $args = defined($1); + + # Find the end of the macro and limit our statement + # search to that. + while ($cnt > 0 && defined $lines[$ln - 1] && + $lines[$ln - 1] =~ /^(?:-|..*\\$)/) + { + $ctx .= $rawlines[$ln - 1] . "\n"; + $cnt-- if ($lines[$ln - 1] !~ /^-/); + $ln++; + } + $ctx .= $rawlines[$ln - 1]; + + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $ln - $linenr + 1, 0); + #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; + #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; + + # Extract the remainder of the define (if any) and + # rip off surrounding spaces, and trailing \'s. + $rest = ''; + while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { + #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; + if ($off != 0 || $lines[$ln - 1] !~ /^-/) { + $rest .= substr($lines[$ln - 1], $off) . "\n"; + $cnt--; + } + $ln++; + $off = 0; + } + $rest =~ s/\\\n.//g; + $rest =~ s/^\s*//s; + $rest =~ s/\s*$//s; + + # Clean up the original statement. + if ($args) { + substr($dstat, 0, length($dcond), ''); + } else { + $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//; + } + $dstat =~ s/$;//g; + $dstat =~ s/\\\n.//g; + $dstat =~ s/^\s*//s; + $dstat =~ s/\s*$//s; + + # Flatten any parentheses and braces + while ($dstat =~ s/\([^\(\)]*\)/1/ || + $dstat =~ s/\{[^\{\}]*\}/1/ || + $dstat =~ s/\[[^\{\}]*\]/1/) + { + } + + my $exceptions = qr{ + $Declare| + module_param_named| + MODULE_PARAM_DESC| + DECLARE_PER_CPU| + DEFINE_PER_CPU| + __typeof__\(| + union| + struct| + \.$Ident\s*=\s*| + ^\"|\"$ + }x; + #print "REST<$rest> dstat<$dstat>\n"; + if ($rest ne '') { + if ($rest !~ /while\s*\(/ && + $dstat !~ /$exceptions/) + { + ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n"); + } + + } elsif ($ctx !~ /;/) { + if ($dstat ne '' && + $dstat !~ /^(?:$Ident|-?$Constant)$/ && + $dstat !~ /$exceptions/ && + $dstat !~ /^\.$Ident\s*=/ && + $dstat =~ /$Operators/) + { + ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); + } + } + } + +# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... +# all assignments may have only one of the following with an assignment: +# . +# ALIGN(...) +# VMLINUX_SYMBOL(...) + if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { + WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); + } + +# check for redundant bracing round if etc + if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, 1); + #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; + #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; + if ($#chunks > 0 && $level == 0) { + my $allowed = 0; + my $seen = 0; + my $herectx = $here . "\n"; + my $ln = $linenr - 1; + for my $chunk (@chunks) { + my ($cond, $block) = @{$chunk}; + + # If the condition carries leading newlines, then count those as offsets. + my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = statement_rawlines($whitespace) - 1; + + #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; + + # We have looked at and allowed this specific line. + $suppress_ifbraces{$ln + $offset} = 1; + + $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; + $ln += statement_rawlines($block) - 1; + + substr($block, 0, length($cond), ''); + + $seen++ if ($block =~ /^\s*{/); + + #print "cond<$cond> block<$block> allowed<$allowed>\n"; + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed = 1; + } + } + if ($seen && !$allowed) { + WARN("braces {} are not necessary for any arm of this statement\n" . $herectx); + } + } + } + if (!defined $suppress_ifbraces{$linenr - 1} && + $line =~ /\b(if|while|for|else)\b/) { + my $allowed = 0; + + # Check the pre-context. + if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { + #print "APW: ALLOWED: pre<$1>\n"; + $allowed = 1; + } + + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, $-[0]); + + # Check the condition. + my ($cond, $block) = @{$chunks[0]}; + #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed = 1; + } + # Check the post-context. + if (defined $chunks[1]) { + my ($cond, $block) = @{$chunks[1]}; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if ($block =~ /^\s*\{/) { + #print "APW: ALLOWED: chunk-1 block<$block>\n"; + $allowed = 1; + } + } + if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { + my $herectx = $here . "\n";; + my $cnt = statement_rawlines($block); + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n";; + } + + WARN("braces {} are not necessary for single statement blocks\n" . $herectx); + } + } + +# don't include deprecated include files (uses RAW line) + for my $inc (@dep_includes) { + if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) { + ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr); + } + } + +# don't use deprecated functions + for my $func (@dep_functions) { + if ($line =~ /\b$func\b/) { + ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr); + } + } + +# no volatiles please + my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; + if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { + WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); + } + +# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated + if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) { + ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr); + } + +# warn about #if 0 + if ($line =~ /^.\s*\#\s*if\s+0\b/) { + CHK("if this code is redundant consider removing it\n" . + $herecurr); + } + +# check for needless kfree() checks + if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { + my $expr = $1; + if ($line =~ /\bkfree\(\Q$expr\E\);/) { + WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev); + } + } +# check for needless usb_free_urb() checks + if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { + my $expr = $1; + if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) { + WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev); + } + } + +# warn about #ifdefs in C files +# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { +# print "#ifdef in C files should be avoided\n"; +# print "$herecurr"; +# $clean = 0; +# } + +# warn about spacing in #ifdefs + if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { + ERROR("exactly one space required after that #$1\n" . $herecurr); + } + +# check for spinlock_t definitions without a comment. + if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || + $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { + my $which = $1; + if (!ctx_has_comment($first_line, $linenr)) { + CHK("$1 definition without comment\n" . $herecurr); + } + } +# check for memory barriers without a comment. + if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + CHK("memory barrier without comment\n" . $herecurr); + } + } +# check of hardware specific defines + if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { + CHK("architecture specific defines should be avoided\n" . $herecurr); + } + +# Check that the storage class is at the beginning of a declaration + if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { + WARN("storage class should be at the beginning of the declaration\n" . $herecurr) + } + +# check the location of the inline attribute, that it is between +# storage class and type. + if ($line =~ /\b$Type\s+$Inline\b/ || + $line =~ /\b$Inline\s+$Storage\b/) { + ERROR("inline keyword should sit between storage class and type\n" . $herecurr); + } + +# Check for __inline__ and __inline, prefer inline + if ($line =~ /\b(__inline__|__inline)\b/) { + WARN("plain inline is preferred over $1\n" . $herecurr); + } + +# check for sizeof(&) + if ($line =~ /\bsizeof\s*\(\s*\&/) { + WARN("sizeof(& should be avoided\n" . $herecurr); + } + +# check for new externs in .c files. + if ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) + { + my $function_name = $1; + my $paren_space = $2; + + my $s = $stat; + if (defined $cond) { + substr($s, 0, length($cond), ''); + } + if ($s =~ /^\s*;/ && + $function_name ne 'uninitialized_var') + { + WARN("externs should be avoided in .c files\n" . $herecurr); + } + + if ($paren_space =~ /\n/) { + WARN("arguments for function declarations should follow identifier\n" . $herecurr); + } + + } elsif ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*extern\s+/) + { + WARN("externs should be avoided in .c files\n" . $herecurr); + } + +# checks for new __setup's + if ($rawline =~ /\b__setup\("([^"]*)"/) { + my $name = $1; + + if (!grep(/$name/, @setup_docs)) { + CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr); + } + } + +# check for pointless casting of kmalloc return + if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) { + WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); + } + +# check for gcc specific __FUNCTION__ + if ($line =~ /__FUNCTION__/) { + WARN("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); + } + +# check for semaphores used as mutexes + if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) { + WARN("mutexes are preferred for single holder semaphores\n" . $herecurr); + } +# check for semaphores used as mutexes + if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) { + WARN("consider using a completion\n" . $herecurr); + + } +# recommend strict_strto* over simple_strto* + if ($line =~ /\bsimple_(strto.*?)\s*\(/) { + WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr); + } +# check for __initcall(), use device_initcall() explicitly please + if ($line =~ /^.\s*__initcall\s*\(/) { + WARN("please use device_initcall() instead of __initcall()\n" . $herecurr); + } +# check for various ops structs, ensure they are const. + my $struct_ops = qr{acpi_dock_ops| + address_space_operations| + backlight_ops| + block_device_operations| + dentry_operations| + dev_pm_ops| + dma_map_ops| + extent_io_ops| + file_lock_operations| + file_operations| + hv_ops| + ide_dma_ops| + intel_dvo_dev_ops| + item_operations| + iwl_ops| + kgdb_arch| + kgdb_io| + kset_uevent_ops| + lock_manager_operations| + microcode_ops| + mtrr_ops| + neigh_ops| + nlmsvc_binding| + pci_raw_ops| + pipe_buf_operations| + platform_hibernation_ops| + platform_suspend_ops| + proto_ops| + rpc_pipe_ops| + seq_operations| + snd_ac97_build_ops| + soc_pcmcia_socket_ops| + stacktrace_ops| + sysfs_ops| + tty_operations| + usb_mon_operations| + wd_ops}x; + if ($line !~ /\bconst\b/ && + $line =~ /\bstruct\s+($struct_ops)\b/) { + WARN("struct $1 should normally be const\n" . + $herecurr); + } + +# use of NR_CPUS is usually wrong +# ignore definitions of NR_CPUS and usage to define arrays as likely right + if ($line =~ /\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) + { + WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); + } + +# check for %L{u,d,i} in strings + my $string; + while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { + $string = substr($rawline, $-[1], $+[1] - $-[1]); + $string =~ s/%%/__/g; + if ($string =~ /(?mutex.\n" . $herecurr); + } + } + } + + # If we have no input at all, then there is nothing to report on + # so just keep quiet. + if ($#rawlines == -1) { + exit(0); + } + + # In mailback mode only produce a report in the negative, for + # things that appear to be patches. + if ($mailback && ($clean == 1 || !$is_patch)) { + exit(0); + } + + # This is not a patch, and we are are in 'no-patch' mode so + # just keep quiet. + if (!$chk_patch && !$is_patch) { + exit(0); + } + + if (!$is_patch) { + ERROR("Does not appear to be a unified-diff format patch\n"); + } + if ($is_patch && $chk_signoff && $signoff == 0) { + ERROR("Missing Signed-off-by: line(s)\n"); + } + + print report_dump(); + if ($summary && !($clean == 1 && $quiet == 1)) { + print "$filename " if ($summary_file); + print "total: $cnt_error errors, $cnt_warn warnings, " . + (($check)? "$cnt_chk checks, " : "") . + "$cnt_lines lines checked\n"; + print "\n" if ($quiet == 0); + } + + if ($clean == 1 && $quiet == 0) { + print "$vname has no obvious style problems and is ready for submission.\n" + } + if ($clean == 0 && $quiet == 0) { + print "$vname has style problems, please review. If any of these errors\n"; + print "are false positives report them to the maintainer, see\n"; + print "CHECKPATCH in MAINTAINERS.\n"; + } + + return $clean; +} diff --git a/www/Makefile.am b/www/Makefile.am new file mode 100644 index 0000000..60c1afa --- /dev/null +++ b/www/Makefile.am @@ -0,0 +1,4 @@ +defaultwwwdir = $(pkgdatadir)/www +defaultwww_DATA = monitor.lua style.css favicon.ico index.lua + +EXTRA_DIST=$(defaultwww_DATA) diff --git a/www/favicon.ico b/www/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c78647d165a7328a08457693f4249353c6ba98c7 GIT binary patch literal 9662 zcmeI2zmF0@6vxNb#?IQpOKeE4q41CJ3YEgfcom%?lqM>L7R1B^qY5Sce`7ZKV$JJ);yApkfvN+c4vSS%iHO5t$${wDpI&1SXPYz8d- z{GmgqkOutr5vVV3gR*}QzGPp)_pZV`pYf7^c(ERXb ztsQRgcVFCOGB4Zm%dkyv$c{F+!LP+{{1HE~NBi`VJN~Z+dC;C+ceLR!z61E(6GwKE z4{rFMe6C!T0KdM&w1LF_=bE&Z-A(>ltp<4iE|Y%{zY40Vdi?*P&#tQfp8w}P(XISl z=l^s%4L+Z5LHT^1$_ZZiMbF=IxeUo<(p0nAr2KBJg?RP9q9~y2x~cJaEF6EeT7^s| zW2)2X2*)pa{D_{vtom6hm8dx4HGf6-Kk>CyKilm#<#*oeXT4qrQg?_(qmgj@q<-dd zIa8XZ3CC}b9})Yn==sa4pWgcO@2`6vcmE~&`azcEqx#eD_l2uJ_WC~@4u#_vJ$^98 zX5S^f*V1%4rM?GV*KcI+;`jR(MEbF{?y*K*`9<$vl}hDk{pn;2ul~31e_O2<6*s)c zkLcGQM2MemDFbTiF(v%|DHy+3LM#?rP@~bH;>gYTw_=zz777K3MxzTNJz@D=Uin3c zpJiX#pG%SisZ`1oulp}M@A9#I{Vl6RqFM6E14~JGP=cYXZV+6 kkKcJu84L!)p-||-rW6PSE+6Cn8{{PjdI+8K#uN9$Z*O!z)Bpeg literal 0 HcmV?d00001 diff --git a/www/index.lua b/www/index.lua new file mode 100644 index 0000000..817535a --- /dev/null +++ b/www/index.lua @@ -0,0 +1,28 @@ + +function footer() + return "" +end + +str = "\ +\ + \ + Psensor Web Server\ + \ + \ +\ + \ +\ +

Welcome to the Psensor Web Server!

\ +\ +

Go to the Monitoring Page.

\ +\ +
" + .. footer() + .. "\ +\ +" + +return str \ No newline at end of file diff --git a/www/monitor.lua b/www/monitor.lua new file mode 100644 index 0000000..3042ad3 --- /dev/null +++ b/www/monitor.lua @@ -0,0 +1,188 @@ +-- +-- Convenient functions for HTML output +-- + +function td(content) + return "" .. content .. "" +end + +function th(style, content) + if style then + return ""..content.."" + else + return ""..content.."" + end +end + +function tr(style,...) + if style then + ret = "" + else + ret = "" + end + + for i,s in ipairs(arg) do + ret = ret .. s + end + + ret = ret .. "\n" + + return ret +end + +function h2(str) + return "

"..str.."

\n" +end + + +-- Formats sensor information to HTML 'tr' +function sensor_to_tr(id,sensor) + return tr(nil, + td(sensor["name"]), + td(sensor["measure_last"]), + td(sensor["measure_min"]), + td(sensor["measure_max"])) +end + + +-- Formats number of bytes to string +function format_mem_size(bytes) + if (bytes == 0) then + return "0" + end + + if (bytes < 1024) then + return bytes .. " o"; + end + + mo_bytes = 1024 * 1024; + + if (bytes < mo_bytes) then + return math.ceil(bytes / 1024) .. " Ko" + end + + go_bytes = 1024 * mo_bytes; + + if (bytes < go_bytes) then + return math.ceil(bytes / mo_bytes) .. " Mo" + end + + return math.ceil(bytes / go_bytes) .. " Go" +end + +-- Formats uptime to string +function format_uptime(uptime) + uptime_s = sysinfo["uptime"]%60 + uptime_mn = math.floor( (sysinfo["uptime"] / 60) % 60) + uptime_h = math.floor( (sysinfo["uptime"] / (60*60)) % 24) + uptime_d = math.floor(sysinfo["uptime"] / (60*60*24)) + + return uptime_d .. "d " .. + uptime_h .. "h " .. + string.format("%02.d",uptime_mn) .. "mn " .. + string.format("%02d",uptime_s) .. "s" +end + +str = "

Psensor Monitoring Server

" + +if sysinfo then + +-- +-- Uptime +-- + + str = str .. "

Uptime: " .. format_uptime(sysinfo["uptime"]) .. "

" + +-- +-- CPU +-- + + str = str .. h2("CPU") + + str = str .. "" + .. tr("title", + th(nil,"Current usage"), + th(nil,"Load 1mn"), + th(nil,"Load 5mn"), + th(nil,"Load 15mn")) + + str = str .. "" + + if sysinfo["load"] then + str = str .. td(math.ceil(100*sysinfo["load"]) .. "%") + else + str = str .. td("N/A") + end + + str = str .. td(string.format("%.2f",sysinfo["load_1mn"])) .. + td(string.format("%.2f",sysinfo["load_5mn"])) .. + td(string.format("%.2f",sysinfo["load_15mn"])) .. + "" .. + "
" + +-- +-- Memory +-- + + totalram = format_mem_size(sysinfo["totalram"] * sysinfo["mem_unit"]) + freeram = format_mem_size(sysinfo["freeram"] * sysinfo["mem_unit"]) + sharedram = format_mem_size(sysinfo["sharedram"] * sysinfo["mem_unit"]) + bufferram = format_mem_size(sysinfo["bufferram"] * sysinfo["mem_unit"]) + usedram = format_mem_size(sysinfo["totalram"] - sysinfo["freeram"]) + + totalswap = format_mem_size(sysinfo["totalswap"] * sysinfo["mem_unit"]) + freeswap = format_mem_size(sysinfo["freeswap"] * sysinfo["mem_unit"]) + usedswap = format_mem_size(sysinfo["totalswap"] - sysinfo["freeswap"]) + + str = str + .. h2("Memory") + + .. "" + + .. tr("title", + th(nil,""), + th(nil,"Total"), + th(nil,"Used"), + th(nil,"Free"), + th(nil,"Shared"), + th(nil,"Buffer")) + + .. tr(nil, + th(nil,"Memory"), + td(totalram), + td(usedram), + td(freeram), + td(sharedram), + td(bufferram)) + + .. tr(nil, + th(nil,"Swap"), + td(totalswap), + td(usedswap), + td(freeswap)) + + .. "
" + +end + +-- +-- Sensors +-- + +if sensors then + + str = str .. "

Sensors

" + .. "" + .. "" + + for i,sensor in ipairs(sensors) do + str = str .. sensor_to_tr(i,sensor) + end + + str = str .. "
NameValueMinMax

psensor-server" + +end + + +return str + diff --git a/www/style.css b/www/style.css new file mode 100644 index 0000000..90d4dab --- /dev/null +++ b/www/style.css @@ -0,0 +1,23 @@ +body { + font-family: Ubuntu, Verdana, Helvetica, Arial, sans-serif; + background: #fff; + color: Black; + margin: 1em 0em 0em 1em; + padding-left: 0em 0em 0em 0em; +} + +table { + border: 1px solid #ddd; +} + +tr.title { + background-color: #eee; +} + +th { + text-align: center; +} + +td { + text-align: right; +} \ No newline at end of file -- 2.7.4