pax_global_header00006660000000000000000000000064135312652410014514gustar00rootroot0000000000000052 comment=a9457622b3fa1a68bb3d554c9a1882c5884f662a uptimed-0.4.2/000077500000000000000000000000001353126524100131665ustar00rootroot00000000000000uptimed-0.4.2/.gitignore000066400000000000000000000015501353126524100151570ustar00rootroot00000000000000# stolen from https://github.com/rakshasa/rtorrent/blob/master/.gitignore and modified slightly # Compiled source # ################### *.o *.lo *.a *.la *.so *.in *.sub *.pc *.orig *.rej # Autoconf files # ################## .deps .libs Makefile aclocal.m4 autom4te.cache compile config.h config.guess config.status confdefs.h conftest.dir configure depcomp install-sh libtool ltmain.sh missing stamp-h1 # Editor poo # ############## .#* \#*# *~ # Packages # ############ # it's better to unpack these files and commit the raw source # git has its own built in compression methods *.gz *.tar *.zip # Logs and databases # ###################### *.log # OS generated files # ###################### .DS_Store? .dirstamp ehthumbs.db Icon? Thumbs.db TAGS # uptimed specific files # ########################## src/uptimed src/uprecords etc/uptimed.service uptimed.spec uptimed-0.4.2/AUTHORS000066400000000000000000000004561353126524100142430ustar00rootroot00000000000000Rob Kaper Radek Podgorny Marcus Spading Jan Engelhardt Gabriel Lavoie Jeroen van Meeuwen Thibaut Varene David Relson uptimed-0.4.2/COPYING000066400000000000000000000431071353126524100142260ustar00rootroot00000000000000 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) 19yy 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) 19yy 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. uptimed-0.4.2/CREDITS000066400000000000000000000031511353126524100142060ustar00rootroot00000000000000The following people have contributed to Uptime. Thanks a lot! Brett Pemberton (autoconf/automake/getopt support) (various patches) (RPM packages) Vitezslav Samel (patch to use sysinfo instead of /proc/uptime for Linux) (various other patches) Helge Deller (HP/UX support) Martijn Broenland (code for BSD uptime was taken from his upclient program) Alan Ford (manual pages) Ted Rolle (code for d/w/y postfix in milestone configuration) Ademar de Souza Reis Jr. (little bugfix in saving uprecords) Radek Podgorny (patch to add the "don't fork" option) Thibaut Varene (patch to add support for darwin) (output formatting patches) (formatting fix) (new backup database logic) Michael Ploujnikov (reminded me how much autotools suck ;-) ) Lassi Selander (mailspam fix) Peter Kerwien (time var width) Kacper Gutowski (tested on kfreebsd) Svante Signell (gnu hurd support) Tomasz Torcz (minor administrative updates) (systemd unit and systemd integration) David Relson (fix for bad output formatting of total uptime and downtime) Martin Natano (add support for bitrig) Baptiste Fontaine (fix for configure step on non-linux platforms) Elijah Zarezky (small legacy init and config fixes) uptimed-0.4.2/ChangeLog000066400000000000000000000166101353126524100147440ustar00rootroot000000000000000.4.2 ----- - support for android 0.4.1 ----- - updates for modern solaris 0.4.0 ----- - dropped pre-generated autotools stuff - fixed configure step on non-linux platforms (thanks to Baptiste Fontaine ) - updated systemd unit to restart daemon on failure 0.3.18 ------ - reintroduce reading of /proc/uptime on Linux (thanks to Tomasz Torcz ) - also try clock_gettime() on Linux (thanks to Tomasz Torcz ) - extended status for systemd/Linux (thanks to Tomasz Torcz ) 0.3.17 ------ - new backup database logic (thanks to Thibaut Varene ) - added support for kfreebsd (thanks to Kacper Gutowski ) - added support for gnu hurd (thanks to Svante Signell ) - various small patches from debian 0.3.16 ------ - nothing new, just cleaning the mess with tags and version numbers 0.3.15 ------ - returned back the configure script (oh how I hate the autotools!) 0.3.14 ------ - fixed wrong output in repetitive mode (thanks to David Relson ) 0.3.13 ------ - Makefile.am fix (thanks to Jan Engelhardt ) - autotools fixes and cleanups (thanks to Jeroen van Meeuwen ) - now reading from backup records file (thanks to Thibaut Varene ) 0.3.12 ------ - more stats (thanks to Marcus Spading ) 0.3.11 ------ - fixed old URLs 0.3.10 ------ - more formatting enhancements (thanks to Thibaud Varene ) 0.3.9 ----- - fixed bad formatting (thanks to Thibaud Varene ) 0.3.8 ----- - fixes with different time widths (thanks to Peter Kerwien ) 0.3.7 ----- - it should now build correctly (thanks to Michael Ploujnikov ) 0.3.6 ----- - patch by Thibaut Varene : add darwin support (define it as BSD system). 0.3.5 ----- - version numbers should now be correct. 0.3.4 ----- - patch by Radek Podgorny : add a "don't fork" option. - this is the first release under maintainership of Radek Podgorny. 0.3.3 ----- - patch by Brett: allow sorting uprecords output. 0.3.2 ----- - change SYSMAX to 24 characters to accomodate FreeBSD 4.8-RELEASE-p10 and up. - remove bootid functionality for BSD: it is not needed. Updated documentation. 0.3.1 ----- - accepted patch from Radim Kolar for bug in save_records that could cause data loss on a system crash with the records file opened for writing. 2002-11-05 (uptimed-0.3.0) ---------- - fixed log_threshold - added mail_threshold 2002-05-13 (cap) (uptimed-0.2.0 release) ---------- - various documentation updates 2002-03-16 (generica) ---------- - Add etc dir - Move uptimed.conf-dist to etc dir - Create template rc.uptimed in etc dir - Update spec file to use rc.uptimed 2001-12-21 (generica) ---------- - Update spec file to deal with sample-cgi dir properly, not overwrite /etc/uptimed.conf, warn user to add/remove lines to rc.(sysinit,local), create /var/spool/uptimed 2001-12-21 (generica) ---------- - Run 'libtoolize' in autogen.sh 2001-12-20 (generica) ---------- - Add rpm spec file 2001-12-19 (cap) ---------- - Added hostname to e-mail confirmation message and beautified the contents of the e-mail. 2001-12-17 (generica) ---------- - New directory (libuptimed) - Create libuptimed.a and libuptimed.so using libtool - Add uptimed.lsm to be included in `make dist` 2001-12-12 (generica) ---------- - Output location of binary when printing usage/help - Small typos in INSTALL, README, uptimed.8, uprecords.1 and urec.c 2001-12-05 (cap) (uptimed-0.1.7 release) ---------- - Change to getopt (generica) - Include local copy of getopt.[ch] for systems without (generica) - Small updates in README, INSTALL - Updated deprecated capsi.cx references - Replaced strcat/sprintf with their respective 'n' functions - uprecords -M works again (fixes Debian bug #107492) - no longer overwrite uptimed.conf upon installation 2001-07-30 (generica) ---------- - Added autoconf/automake support - New directory structure (src/man) 2001-07-27 (cap) ---------- - new ChangeLog syntax ;-) - Updated TODO - moved uptimed code to CVS 0.1.7 - not released ==================== * More checks to prevent bogus mail reported fixed in 0.1.5. 0.1.6 - Nov/06/2000 =================== * Manual pages. * Easier configuration of milestones in config file. * A few little bugfixes. 0.1.5 - Mar/30/2000 =================== * Bugfix for faulty interpretation of 0 (unlimited) entries in uptimed and uprecords. * Bugfix against startup crashes with corrupted startup files by adding a syntax check on input lines. * Phoney entries in old records file (version 0.03 and earlier) are now discarded by uptimed. * Bugfix to eliminate an odd congratulations mail on startup. * Improved 'make install' in Makefile, no longer overwrites existing configuration but instead install the template as /etc/uptimed.conf.dist 0.1.4 - Mar/09/2000 =================== * Linux uptime now retrieved from sysinfo() instead of /proc/uptime. (patch from Vitezslav Samel ) * Changed default email address in config from my own (stupid, stupid!) to root@localhost. * Configurable milestones. * Moved all .h declarations to header files. * New option -M to show next milestone in uprecords. 0.1.3 - Feb/28/2000 =================== * Partial HP/UX support. (patches from Helge Deller ) 0.1.2 - Dec/18/1999 =================== * Fixed -s and -v options in uprecords. * Fixed parsing of email address. * Added partial support for *BSD and Solaris. * Fixed wrong output in email. * Added sendmail location to configuration file. 0.1.1 - Dec/9/1999 ================== * Added commandline options to uptimed and uprecords. (see -?) * Option not to show ANSI codes in uprecords. (for inclusion into .signature files, for example) * Option not to show current entry, statistics. * Fixed instructions in INSTALL file. * Fixed formatting bug in uprecords for too long system info. * Option to mail records/milestones. 0.1.0 - Dec/6/1999 ================== Basically a complete rewrite of the code: * Created urec struct to put records in and using linked list instead of ugly static arrays. * Files now stored in /var/spool/uptimed/ * Made 'make uninstall' entry in Makefile. * Events such as moving up in the list, breaking the record or reaching a milestone get reported in syslog. * Compiles clean with -Wall -pedantic -ansi on my system :-) * Update interval and maximum amount of log entries are now configurable from configuration file /etc/uptimed.conf * Rewrote INSTALL and README files. * Added CGI functionality to uprecords and wrote INSTALL.cgi * Catching signals SIGHUP/SIGTERM to exit gracefully upon them. 0.03 - 01/14/1999 ================= * Added countdowns for milestones in uprecords. * Bugfixes. * Added -f option for uprecords. Runs the program in a loop and doesn't exit. Handy for spare monitors and/or terminals. * Added system recognition. Lost backwards compatibility in logfile. See README.upgrade 0.02 - 01/04/1999 ================= * Rewrote the code that is used to identify a unique boot id. See the INSTALL file for details on the method I have chosen, how it works and why I have chosen it. 0.01 - 12/13/1998 ================= * First release. uptimed-0.4.2/INSTALL000066400000000000000000000366101353126524100142250ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2013 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 command `./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. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. 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 limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/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. uptimed-0.4.2/INSTALL.cgi000066400000000000000000000041371353126524100147650ustar00rootroot00000000000000Contents -------- 1. Using uprecords as CGI program 2. Configuring the output of uprecords as CGI program 3. Inserting the output of uprecords into existing pages 1. Using uprecords as CGI program --------------------------------- Copy the uprecords binary to your CGI directory and rename it: cp uprecords /www/cgi-bin/uprecords.cgi Uprecords will automatically recognize it is being run as CGI program by it's .cgi filename and add the necessary Content-type header and some HTML tags. 2. Configuring the output of uprecords as CGI program ----------------------------------------------------- When run as CGI, uprecords.cgi checks for a file called uprecords.conf in the current (= cgi-bin) directory. This configuration file allows you to control the way uprecords.cgi will look. LAYOUT can be any of "pre", "list", or "table". "pre" uses the
 tag to
create output close to that of running uprecords from the console and is the
default option. "list" creates a list using the 
    and
  • tags and "table" creates a table using the , and \n"); if (pos) printf("\n", bold, pos, plain, current); else printf("\n", ident); printf("\n", bold, time2uptime(utime), plain); printf("\n", bold, sys, plain); printf("\n", bold, ctime(&btime), plain); printf("\n"); break; case LIST: if (pos>show_max) printf("
  • %s%s, %s, %s%s%s (position %d)", bold, time2uptime(utime), sys, ctime(&btime), plain, current, pos); else if (pos) printf("
  • %s%s, %s, %s%s%s", bold, time2uptime(utime), sys, ctime(&btime), plain, current); else printf("
  • %s%s %s %s %s%s", bold, ident, time2uptime(utime), sys, ctime(&btime), plain); break; default: if((ctimec = ctime(&btime))) ctimec[TIMEMAX-1] = '\0'; /* erase the ending '\n' */ if (!wide_out && strlen(sys) > SYSWIDTH) sys[SYSWIDTH] = '\0'; /* truncate for 80 cols */ if (pos) printf("%s%3s%3d%21s %s|%s %-*s %*s%s\n", bold, ident, pos, time2uptime(utime), plain, bold, SYSWIDTH, sys, TIMEMAX, ctimec, plain); else printf("%s%6s%21s %s|%s %-*s %*s%s\n", bold, ident, time2uptime(utime), plain, bold, SYSWIDTH, sys, TIMEMAX, ctimec, plain); } } void print_downtime_entry(time_t utime, time_t dtime, time_t btime, char *ident, int pos, int hilite) { char *bold = BOLD, *plain = PLAIN, *current = ""; char *ctimec = NULL; char timebuf[20] = "", dtimebuf[20] = ""; strcpy(timebuf, time2uptime(utime)); strcpy(dtimebuf, time2uptime(dtime)); if (runas_cgi) { bold = ""; plain = ""; if (hilite) current = " (current)"; if (!strcmp(ident, "-> ")) ident="-> "; } if (!hilite || no_ansi) { bold = ""; plain = ""; } switch(layout) { case TABLE: printf("
  • \n"); if (pos) printf("\n", bold, pos, plain, current); else printf("\n", ident); printf("\n", bold, timebuf, plain); printf("\n", bold, dtimebuf, plain); printf("\n", bold, ctime(&btime), plain); printf("\n"); break; case LIST: if (pos>show_max) printf("
  • %s%s, %s, %s%s%s (position %d)", bold, timebuf, dtimebuf, ctime(&btime), plain, current, pos); else if (pos) printf("
  • %s%s, %s, %s%s%s", bold, timebuf, dtimebuf, ctime(&btime), plain, current); else printf("
  • %s%s %s at %s%s", bold, ident, timebuf, ctime(&btime), plain); break; default: if((ctimec = ctime(&btime))) ctimec[TIMEMAX-1] = '\0'; /* erase the ending '\n' */ if (pos) { printf("%s%3s%3d%21s %s|%s %*s %*s%s\n", bold, ident, pos, timebuf, plain, bold, DOWNWIDTH, dtimebuf, DOWNTIMEMAXWIDTH, ctimec, plain); } else { printf("%s%6s%21s %s|%s %*s %*s%s\n", bold, ident, timebuf, plain, bold, DOWNWIDTH, dtimebuf, DOWNTIMEMAXWIDTH, ctimec, plain); } } } void print_availability(float percent, time_t since) { char *ctimec = NULL, *msg = "%up"; if (runas_cgi) { if (layout!=PRE) { msg = "Availability (%)"; } } switch(layout) { case TABLE: printf("
  • \n"); printf("\n", msg); printf("\n", percent); printf("\n"); printf("\n", ctime(&since)); printf("\n"); break; case LIST: printf("
  • %s %.3f since %s", msg, percent, ctime(&since)); break; default: if (ctimec = ctime(&since)) { ctimec[TIMEMAX-1] = '\0'; /* erase the ending '\n' */ } printf("%6s %20.3f | %-*s %*s\n", msg, percent, SYSWIDTH, "since", TIMEMAX, ctimec); } } void print_line(void) { printf("----------------------------+---------------------------------------------------\n"); } void scan_args(int argc, char *argv[]) { int i; while((i = getopt(argc, argv, "i:m:?acbdBkKfsMwv")) != EOF) { switch(i) { case '?': #ifdef __ANDROID__ fputc('\n', stderr); #endif print_help(argv); break; case 'a': no_ansi++; break; case 'b': sort_by = 1; no_stats++; break; case 'B': sort_by = -1; no_stats++; break; case 'k': sort_by = 2; no_stats++; break; case 'K': sort_by = -2; no_stats++; break; case 'd': show_downtime++; break; case 'c': no_current++; break; case 'f': run_loop++; break; case 's': no_stats++; break; case 'w': wide_out++; break; case 'v': print_version(); break; case 'M': show_milestone++; break; case 'i': if (isdigit(*optarg)) update_interval=atoi(optarg); else { printf("%s: option requires argument -- %c\n", argv[0], i); print_usage(argv); } run_loop++; break; case 'm': if (isdigit(*optarg)) show_max=atoi(optarg); else { printf("%s: option requires argument -- %c\n", argv[0], i); print_usage(argv); } break; } } } void print_usage(char *argv[]) { printf("usage: %s [-?acdfMswv] [-i interval] [-m count]\n", argv[0]); exit(1); } void print_help(char *argv[]) { printf("usage: %s [OPTION]...\n\n", argv[0]); printf(" -? this help\n"); printf(" -a do not print ansi codes\n"); printf(" -b sort by boottime\n"); printf(" -B reverse sort by boottime\n"); printf(" -k sort by sysinfo\n"); printf(" -K reverse sort by sysinfo\n"); printf(" -d print downtime seen before every uptimes instead of system\n"); printf(" -c do not show current entry if not in top entries\n"); printf(" -f run continuously in a loop\n"); printf(" -s do not print extra statistics\n"); printf(" -w wide output (more than 80 cols per line)\n"); printf(" -i INTERVAL use INTERVAL seconds for loop instead of 5, implies -f\n"); printf(" -m COUNT show a maximum of top COUNT entries instead of 10\n"); printf(" -M show next milestone\n"); printf(" -v version information\n"); exit(0); } void print_version(void) { printf("uprecords " VERSION " by Rob Kaper \n"); printf("enhanced and maintained by Radek Podgorny \n"); exit(0); } uptimed-0.4.2/src/uprecords.h000066400000000000000000000032441353126524100161370ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include "urec.h" #include "milestone.h" #include "misc.h" #define BOLD "" #define PLAIN "" #define CLS "" #define PRE 1 #define LIST 2 #define TABLE 3 /* ctime returns a pointer to a 26-character string of the form: Thu Nov 24 18:22:48 1986\n\0 of which we'll replace the \n by '\0', hence the 25 length */ #define TIMEMAX 25 #define DOWNTIMEMAXWIDTH 29 int main(int, char *[]); void displayrecords(int); void read_config(void); void read_config_cgi(void); void print_entry(time_t, char *, time_t, char *, int, int); void print_downtime_entry(time_t utime, time_t dtime, time_t btime, char *ident, int pos, int hilite); void print_line(void); void print_availability(float percent, time_t since); void scan_args(int, char *[]); void print_usage(char *[]); void print_help(char *[]); void print_version(void); uptimed-0.4.2/src/uptimed.c000066400000000000000000000273421353126524100156000ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "../config.h" #include "uptimed.h" #include "sd-daemon.h" #ifdef PLATFORM_HPUX #define SYSLOG_PREFIX "uptimed: " #else #define SYSLOG_PREFIX "" #endif #ifdef HAVE_GETOPT_H #include #endif #ifdef __ANDROID__ extern Urec *u_current; #else Urec *u_current = NULL; #endif int our_pos=0; int update_interval=60, create_bootid=0, send_email=0, foreground=0; time_t log_min_uptime = 0, mail_min_uptime = 0; unsigned int log_max_entries = 50, mail_min_position = 10; char email[EMAIL+1], sendmail[EMAIL+1], pidfile[EMAIL+1]; int main(int argc, char *argv[]) { Milestone *next_milestone = NULL, *cheer_milestone = NULL; time_t prev=0,tmp=0; int cheer_pos=0; void handler(int); /* Properly initialize these to an empty string */ email[0] = sendmail[0] = pidfile[0] = '\0'; /* Read configuration settings. */ read_config(); /* Scan arguments. */ scan_args(argc, argv); if(!pidfile[0]) { strncpy(pidfile, "/var/run/uptimed", EMAIL); pidfile[EMAIL] = '\0'; } { FILE *pidf; pid_t pid = 0; pidf = fopen(pidfile, "r"); if(pidf) { /* The pidfile exists. Now see if the process is * still running */ if(!fscanf(pidf, "%d", &pid)) pid = 0; fclose(pidf); if(pid && !kill(pid, 0)) { printf("uptimed is already running.\n"); exit(1); } } } /* Create bootid and exit. Should be done once on startup. */ if (create_bootid) { createbootid(); syslog(LOG_INFO, SYSLOG_PREFIX "created bootid: %d", readbootid()); exit(0); } if (update_interval<1) update_interval=1; if (log_max_entries < 0) log_max_entries = 1; /* Let's start with adding a nice entry for the current session. */ u_current=add_urec(read_uptime(),readbootid(),read_sysinfo()); /* How about adding the existing records as well? */ read_records(u_current->btime); /* Initialize the first milestone to look for. */ next_milestone = find_next_milestone(u_current->utime); /* Add signal handler for hangups/terminators. */ #ifndef PLATFORM_HPUX signal(SIGHUP,handler); #endif signal(SIGTERM,handler); /* Now run in the background. */ if (!foreground) bg(); { FILE *pidf; pidf = fopen(pidfile, "w"); if(pidf) { fprintf(pidf, "%d", getpid()); fclose(pidf); } else { pidfile[0] = '\0'; } } sd_notifyf(0, "MAINPID=%lu\n", (unsigned long)getpid()); sd_notify(0, "READY=1\n"); /* The main loop. */ while (1) { /* Update the uptime value of the current session. */ u_current->utime=read_uptime(); /* Find out if we're breaking existing records. */ if (u_current!=urec_list) { if (!prev) prev=get_prev(); /* Current uptime might break the old record. */ if (u_current->utime > urec_list->utime) { moveup(); /* We should be urec_list ourselves now. */ cheer_pos=1; /* Don't forget to cheer. */ } /* Current uptime might move up in the list. */ else if (prev && u_current->utime > prev) { moveup(); prev=get_prev(); /* We will have to re-init the prev entry. */ cheer_pos=our_pos; /* Don't forget to cheer. */ } } /* Find out if we are breaking any milestones. */ if (next_milestone && u_current->utime > next_milestone->time) { cheer_milestone = next_milestone; next_milestone = find_next_milestone(u_current->utime); } /* Celebrate good times! */ if (cheer_pos || cheer_milestone) { cheer(cheer_milestone, cheer_pos); cheer_pos = 0; cheer_milestone = NULL; } /* Update status for service manager */ if (next_milestone) { tmp = time(0) + next_milestone->time - u_current->utime; sd_notifyf(0, "STATUS=Next milestone (%s) at %s\n", next_milestone->desc, ctime(&tmp)); } /* Save all the records. */ save_records(log_max_entries, log_min_uptime); /* Save valueable CPU cycles. */ sleep(update_interval); } } void bg(void) { int i, fdmax; /* Simple fork to run proces in the background. */ switch(fork()) { case 0: break; case -1: perror("fork failed"); exit(1); default: exit(0); } if (-1==setsid()) { perror("setsid failed"); exit(1); } /* Close probably all file descriptors */ #ifdef HAVE_GETDTABLESIZE fdmax = getdtablesize(); #else fdmax = sysconf(_SC_OPEN_MAX); #endif if (fdmax <= 0) fdmax = 3; for (i = 0; i < fdmax; i++) close(i); /* Be nice to umount */ chdir("/"); } void cheer(Milestone *milestone, int position) { /* This function will do various sorts of recordbreaking celebrating. */ switch(position) { case 0: break; case 1: syslog(LOG_INFO, SYSLOG_PREFIX "new uptime record: %s", time2uptime(u_current->utime)); break; default: syslog(LOG_INFO, SYSLOG_PREFIX "moving up to position %d: %s", position, time2uptime(u_current->utime)); break; } if (milestone!=NULL && milestone->time>0) syslog(LOG_INFO, SYSLOG_PREFIX "milestone: %s (%s)", time2uptime(milestone->time), milestone->desc); /* Send email if it's requested. */ if ((u_current->utime > mail_min_uptime) && (!position || (position <= mail_min_position)) && (send_email==1 || (send_email==2 && milestone) || (send_email==3 && position)) && email[0]) mail(milestone, position); } time_t get_prev(void) { Urec *uprev=NULL, *u; our_pos=0; for (u=urec_list;u;u=u->next) { our_pos++; if (u==u_current) if (uprev) return uprev->utime; uprev=u; } return 0; } void read_config(void) { FILE *f; char str[256]; time_t milestone_time; char *milestone_str; f=fopen(FILE_CONFIG, "r"); if (!f) return; fgets(str, sizeof(str), f); while (!feof(f)) { if (!strncmp(str, "UPDATE_INTERVAL", 15)) update_interval=atoi(str+16); else if (!strncmp(str, "MAX_ENTRIES", 11)) log_max_entries = atoi(str+12); /* MAX_ENTRIES is deprecated now, keep for backward compat */ else if (!strncmp(str, "LOG_MAXIMUM_ENTRIES", 19)) log_max_entries = atoi(str+20); else if (!strncmp(str, "EMAIL", 5) && strstr(str+6, "@")) { strncpy(email, strtok(str+6, "\n"), EMAIL); email[EMAIL]='\0'; } else if (!strncmp(str, "SEND_EMAIL", 10)) send_email=atoi(str+11); else if (!strncmp(str, "SENDMAIL", 8)) { strncpy(sendmail, strtok(str+9, "\n"), EMAIL); sendmail[EMAIL]='\0'; } else if (!strncmp(str, "MILESTONE", 9)) { char *cp = strtok(str+10, ":"); milestone_time = scantime(cp); milestone_str = strtok(NULL, "\n"); add_milestone(milestone_time, milestone_str); } else if (!strncmp(str, "LOG_MINIMUM_UPTIME", 18)) log_min_uptime = scantime(strtok(str+19, "\n\0")); else if (!strncmp(str, "MAIL_MINIMUM_UPTIME", 19)) mail_min_uptime = scantime(strtok(str+20, "\n\0")); else if (!strncmp(str, "MAIL_MINIMUM_POSITION", 21)) mail_min_position = scantime(strtok(str+22, "\n\0")); else if (!strncmp(str, "PIDFILE", 7)) { strncpy(pidfile, strtok(str+8, "\n"), EMAIL); pidfile[EMAIL]='\0'; } fgets(str, sizeof(str), f); } fclose(f); } /* Handler does not care about sorting the list or cheering, there's no time for all that when we've received a SIGHUP or SIGTERM. When uptimed is restarted the list will be sorted automatically and we'll try not to shed any tears over any missing syslog messages that might have been printed at the end of the interval. */ void handler(int s) { /* Update the uptime value of the current session. */ u_current->utime=read_uptime(); /* Save all the records. */ save_records(log_max_entries, log_min_uptime); /* Exit gracefully. */ if(pidfile[0]) unlink(pidfile); exit(0); } void scan_args(int argc, char *argv[]) { int index; while((index = getopt(argc, argv, "e:i:m:p:t:?bfv")) != EOF) { switch(index) { case '?': #ifdef __ANDROID__ fputc('\n', stderr); #endif print_help(argv); break; case 'v': print_version(); break; case 'f': foreground = 1; break; case 'e': strcpy(email, optarg); send_email = 1; break; case 'p': strcpy(pidfile, optarg); break; case 'b': create_bootid++; break; case 'i': if(isdigit(*optarg)) update_interval=atoi(optarg); else { printf("%s: option requires argument -- %c\n", argv[0], index); print_usage(argv); } break; case 'm': if(isdigit(*optarg)) log_max_entries = atoi(optarg); else { printf("%s: option requires argument -- %c\n", argv[0], index); print_usage(argv); } break; case 't': if(isdigit(*optarg)) log_min_uptime = scantime(optarg); else { printf("%s: option requires argument -- %c\n", argv[0], index); print_usage(argv); } break; } } } void print_usage(char *argv[]) { printf("usage: %s [-?bv] [-e email] [-i interval] [-m count]\n", argv[0]); printf(" [-p pidfile] [-t log threshold]\n"); exit(1); } void print_help(char *argv[]) { printf("usage: %s [OPTION]...\n", argv[0]); printf("commandline options override settings from configuration file\n\n"); printf(" -? this help\n"); printf(" -b create bootid and exit [ignored on FreeBSD]\n"); printf(" -f run in foreground [don't fork]\n"); printf(" -e EMAIL send mail to EMAIL at milestones/records\n"); printf(" -i INTERVAL use INTERVAL seconds for loop\n"); printf(" -m COUNT log a maximum of COUNT entries\n"); printf(" -t TIMESPEC minimum uptime to be considered a record\n"); printf(" -p FILE write PID to FILE\n"); printf(" -v version information\n"); exit(0); } void print_version(void) { printf("uptimed " VERSION " by Rob Kaper \n"); printf("enhanced and maintained by Radek Podgorny \n"); exit(0); } /* Ugly mail hack, assumes sendmail compatible mail agent. */ void mail(Milestone *milestone, int position) { char buf[256], str[2048], cmd[2048], hostname[256]; gethostname(hostname, sizeof(hostname)-1); hostname[sizeof(hostname)-1] = 0; snprintf(str, sizeof(str)-1, "To: %s\nSubject: Congratulations (Uptimed@%s)\n\n", email, hostname); str[sizeof(str)-1] = 0; snprintf(buf, sizeof(buf)-1, "Uptimed noticed an uptime event!\n\n"); buf[sizeof(buf)-1] = 0; strncat(str, buf, sizeof(str)-1); str[sizeof(str)-1] = 0; if (milestone!=NULL && milestone->time>0) { snprintf(buf, sizeof(buf)-1, "The uptime of %s has reached a milestone:\n\t%s (%s)\n", hostname, time2uptime(milestone->time), milestone->desc); buf[sizeof(buf)-1] = 0; strncat(str, buf, sizeof(str)-1); str[sizeof(str)-1] = 0; } if (position>0) { if (position==1) snprintf(buf, sizeof(buf)-1, "The uptime is a new record for %s:\n\t%s\n", hostname, time2uptime(u_current->utime)); else snprintf(buf, sizeof(buf)-1, "The uptime of %s moved up to position %d:\n\t%s\n", hostname, position, time2uptime(u_current->utime)); buf[sizeof(buf)-1] = 0; strncat(str, buf, sizeof(str)-1); str[sizeof(str)-1] = 0; } strncat(str, "\nCongratulations!\n\nUptimed author,\nRob Kaper \n-- \nThis message was automatically generated by Uptimed.\nUptimed e-mail notifications can be configured from the uptimed.conf file.\n", sizeof(str)-1); str[sizeof(str)-1] = 0; snprintf(cmd, sizeof(cmd)-1, "printf \"%s\" | %s", str, sendmail); cmd[sizeof(cmd)-1] = 0; system(cmd); } uptimed-0.4.2/src/uptimed.h000066400000000000000000000024011353126524100155720ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "milestone.h" #include "misc.h" #include "urec.h" #define EMAIL 128 int main(int, char *[]); void bg(void); void cheer(Milestone *, int); time_t get_prev(void); void read_config(void); void handler(int); void scan_args(int, char *[]); void print_usage(char *[]); void print_help(char *[]); void print_version(void); void mail(Milestone *, int); uptimed-0.4.2/uptimed.spec.in000066400000000000000000000057271353126524100161310ustar00rootroot00000000000000%define release 1 Summary: A daemon to record and keep track of system uptimes Name: @PACKAGE@ Version: @VERSION@ Release: %{release} License: GPL Group: System Environment/Daemons Source: http://prdownloads.sourceforge.net/%{name}/%{name}-%{version}.tar.gz BuildRoot: /var/tmp/%{name}-%{version}-buildroot PreReq: chkconfig >= 0.9 %description Uptimed is an uptime record daemon keeping track of the highest uptimes the system ever had. Instead of using a pid file to keep sessions apart from each other, it uses the system boot time. Uptimed has the ability to inform you of records and milestones though syslog and e-mail, and comes with a console front end to parse the records, which can also easily be used to show your records on your Web page %prep %setup -q %build %configure make RPM_OPT_FLAGS="$RPM_OPT_FLAGS" %install rm -rf "$RPM_BUILD_ROOT" make DESTDIR="$RPM_BUILD_ROOT" install install -m 755 -d $RPM_BUILD_ROOT/%_docdir/%{name}-%{version}/sample-cgi install -m 644 sample-cgi/uprecords.* $RPM_BUILD_ROOT/%_docdir/%{name}-%{version}/sample-cgi install -m 755 -d $RPM_BUILD_ROOT/etc/rc.d/init.d install -m 755 etc/rc.uptimed $RPM_BUILD_ROOT/etc/rc.d/init.d/uptimed mv $RPM_BUILD_ROOT/etc/uptimed.conf-dist $RPM_BUILD_ROOT/etc/uptimed.conf %post /sbin/ldconfig install -m 755 -d /var/spool/uptimed /sbin/chkconfig --add uptimed if [ -f /etc/rc.d/rc.sysinit ] then if [ ! `grep "/sbin/service uptimed createbootid" /etc/rc.d/rc.sysinit > /dev/null` ] then echo "/sbin/service uptimed createbootid" >> /etc/rc.d/rc.sysinit fi else echo echo "Please add the following line to your rc.sysinit script" echo "/sbin/service uptimed createbootid" echo fi %postun /sbin/ldconfig %preun /sbin/chkconfig --del uptimed if [ -f /etc/rc.d/rc.sysinit ] then grep -v "/sbin/service uptimed createbootid" /etc/rc.d/rc.sysinit > /tmp/rc.sysinit.$$ && mv /tmp/rc.sysinit.$$ /etc/rc.d/rc.sysinit chmod 755 /etc/rc.d/rc.sysinit else echo echo "Please remove the following line to your rc.sysinit script" echo "/sbin/service uptimed createbootid" echo fi %clean rm -rf "$RPM_BUILD_ROOT" %files %defattr(-,root,root) %doc AUTHORS COPYING CREDITS ChangeLog INSTALL INSTALL.cgi INSTALL.upgrade README README.unsupported TODO sample-cgi/ %config(noreplace) /etc/uptimed.conf %config /etc/rc.d/init.d/uptimed %{_sbindir}/uptimed %{_bindir}/uprecords %{_mandir}/*/* %{_libdir}/libuptimed.* %changelog * Tue May 14 2002 Brett Pemberton - Reset release to 0 for uptimed-2.0 - Change source location * Sat Mar 16 2002 Brett Pemberton - Add /etc/rc.d/init.d/uptimed - Use chkconfig * Wed Mar 13 2002 Brett Pemberton - Automate rc.{sysinit,local} add/remove - Warn if rc.{sysinit,local} not found * Fri Dec 21 2001 Brett Pemberton - Handle sample-cgi dir properly - Install uptimed.conf properly - Install /var/spool/uptimed - Warn user to finish configuring * Thu Dec 20 2001 Brett Pemberton - Initial spec-file
  • tags. SHOW_MAX defines how many entries should be shown at maximum. If the file uprecords.header is present, it will be printed before the output. You can use this to create the most smashing looks, from a simple tag to change to background colour to a comprehensive page including all the latest CSS style-sheets. If the file uprecords.footer is present, it will be printed after the output. There are some sample files in the sample-cgi/ directory of this package. 3. Inserting the output of uprecords into existing pages -------------------------------------------------------- You can include the output within existing HTML pages to get the same lay-out as the rest of your site using server-side includes, PHP, etc. Example tags to put within your pages: SSI: PHP: For more information on SSI, read the Apache manuals (if Apache is your webserver) or contact your Internet Service/Presence Provider. For more information on PHP, visit http://www.php.net/ uptimed-0.4.2/INSTALL.upgrade000066400000000000000000000032141353126524100156450ustar00rootroot00000000000000Contents -------- 1. Upgrading from version 0.1.x and 0.2.x 2. Upgrading from version 0.03 3. Upgrading from version 0.02 1. Upgrading from version 0.1.x and 0.2.x ----------------------------------------- The uptimed configuration file has been expanded to support new options. You probably want to merge your custom configuration from 'uptimed.conf' with the sample file called 'uptimed.conf-dist'. 2. Upgrading from version 0.03 ------------------------------ The location of bootid and logfiles have changed to the /var/spool/uptimed/ directory. This directory has already been created by 'make install'. However, you also need to move the old logfiles to the new location. First, shut down any running uptimed daemons. killall uptimed (Note that the killall command might not have the desired effect on non-Linux systems.) Now move the old files: mv /etc/uptimed.log /var/spool/uptimed/records mv /var/run/uptimed.bootid /var/spool/uptimed/bootid Finally, start the (new) uptimed daemon: uptimed Now follow the instructions as if you were upgrading from version 0.1.0. 3. Upgrading from version 0.02 ------------------------------ Versions 0.03 and higher log system information into the logfile. You have to convert these logfiles manually: First, shut down any running uptimed daemons. killall uptimed (Note that the killall command might not have the desired effect on non-Linux systems.) Edit the file /etc/uptimed.log and change the entries from the format uptime:boottime to uptime:bootttime:systeminfo Example: 377428:943880710 to 377428:943880710:Linux 2.2.13 Now follow the instructions as if you were upgrading from version 0.03. uptimed-0.4.2/Makefile.am000066400000000000000000000011161353126524100152210ustar00rootroot00000000000000# Makefile.am for uptimed # this prevents automake from screaming at us about missing README AUTOMAKE_OPTIONS = foreign SUBDIRS = libuptimed src man etc EXTRA_DIST = CREDITS INSTALL.cgi INSTALL.upgrade README.unsupported \ sample-cgi/uprecords.conf sample-cgi/uprecords.header \ sample-cgi/uprecords.footer uptimed.spec depcomp AM_CFLAGS = @CFLAGS@ -DFILE_CONFIG=\"$(sysconfdir)/uptimed.conf\" install-data-local: $(INSTALL) -d $(DESTDIR)/var/spool/uptimed srpm: dist @(rpmbuild -ts uptimed-$(PACKAGE_VERSION).tar.gz) rpm: dist @(rpmbuild -ta uptimed-$(PACKAGE_VERSION).tar.gz) uptimed-0.4.2/NEWS000077700000000000000000000000001353126524100154322ChangeLogustar00rootroot00000000000000uptimed-0.4.2/README.md000066400000000000000000000025501353126524100144470ustar00rootroot00000000000000## 1. Introduction Uptimed is an uptime record daemon keeping track of the highest uptimes a computer system ever had. It uses the system boot time to keep sessions apart from each other. Uptimed comes with a console front-end to parse the records, which can also easily be used to show your records on a web page. The original author is Rob Kaper but since version 0.3.4 I (Radek Podgorny) took over the maintainership as Rob is overwhelmed by work (and so am I but I try my best). Remember, we're talking about about maintainance only. Still, feel free to contribute anything, branching and merging is not a problem. ## 2. Availability You can always get the latest release from the Uptimed github repository: https://github.com/rpodgorny/uptimed/ ## 3. Acknowledgments Uptimed was inspired by a similar utility called 'ud', but is completely different by design. Instead of using PID files to prevent multiple instances, Uptimed uses the system boot time to seperate log entries from each other. This is believed to be more reliable when switching runlevels or accidentely killing Uptimed or running multiple instances of it. For a list of contributors to Uptimed, please read the CREDITS file. ## 4. Contacting the author/maintainer Questions, comments, bugfixes, patches: Radek Podgorny Original maintainer and author: Rob Kaper uptimed-0.4.2/README.unsupported000066400000000000000000000044511353126524100164410ustar00rootroot00000000000000Contents ======== 1. My platform is listed as unsupported. What to do now? 2. Support status for various platforms 3. Getting the uptime on unsupported platforms 1. My platform is unsupported. What to do now? ============================================== First of all, do not panic. Chances are that uptimed will work on your platform with little or no modifications. There are basically three reasons why your platform could be unsupported: - I have insufficient knowledge to get my code to compile, - I have insufficient knowledge how to get your platform's uptime, - I have insufficient knowledge of your platforms startup process and files 2. Support status for various platforms ======================================= BSD (other than FreeBSD) ------------------------ If someone can tell me the /usr/local/etc/rc.d equivalent for other BSD systems, these can be officially supported. Thanks! HP/UX ----- Uptimed now works and compiles on HP/UX (at least under 10.20) with thanks to patches from Helge Deller . Not being an expert on HP/UX startup files, any help is very welcome here. Currently /sbin/rc is used: find the following part at the end of /sbin/rc and insert the lines commented with "insert me!". ---- /sbin/rc ---- # Output message to indicate completion # echo if [ $BOOT = 1 ]; then echo "Creating unique uptime daemon bootid..." # insert me ! /usr/local/sbin/uptimed -b # insert me ! echo "Start uptimed..." # insert me ! /usr/local/sbin/uptimed # insert me ! echo "The system is ready." else ---- /sbin/rc ---- 3. Getting the uptime on unsupported platforms ---------------------------------------------- I have written a quick and inaccurate hack calculating the uptime from the current time and the timestamp made at boottime. This is very portable and thus will also let uptimed run on platforms where I do not know of how to get the real uptime. However, this is also very inaccurate, because: 1) the boottime timestamp can be extremely delayed due to fscking etc. 2) when the system time changes (for example timezone changes) the boottime timestamp does not, creating even more inaccuracy. However, this hack should at least _work_. If you can send me any information on how to get the uptime on your platform, it will be appreciated very much. uptimed-0.4.2/TODO000066400000000000000000000026751353126524100136700ustar00rootroot00000000000000For 0.4.0 --------- - Add reason to save_records (SIGTERM/SIGHUP==reboot, none==CRASH??) - Include option to send e-mail directly after reboot if uptimed wasn't shut down properly (no mail on scheduled reboots, only for crashes) (cap) - Write ncurses uprecords and split uprecords into uprecords.cgi and ncurses uprecords if necessary - configurable layout (ability to make the headers centered) For 0.5.0 --------- - Optional KNotify support (cap) dcop knotify '' notify maximize kwin "new record" -1 -1 -1 -1 (requires changes in dcop server first, see http://lists.kde.org/?l=kde-core-devel&m=100783153324488&w=2) - Include KDE panel applet GUI (cap) - Cool Gnome/WM progs that play a happy sound or pop-up when breaking the record or reaching a milestone. Contributions in this area would be very much appreciated. For 0.x.0 --------- - More portability? (BSD, Solaris, Windoze??) - Networking, kinda like rwhod. Uptimed broadcasts to localnet (configurable??) and listens as well. Every machine has info for the entire broadcast range (/var/spool/uptimed/host.records). Uprecords can be called/configured to list: this machine only, a specified host or all. I might drop this option or delay it and instead code in support for the www.uptimes.net project, although I do like the idea of a rwhod alike implementation. For 1.0.0 --------- - Have all that included and still have the GPL as biggest file in the package. ;-) uptimed-0.4.2/autogen.sh000077500000000000000000000021001353126524100151600ustar00rootroot00000000000000#! /bin/sh # this is stolen from https://github.com/rakshasa/rtorrent/blob/master/autogen.sh and modified slightly echo aclocal... (aclocal --version) < /dev/null > /dev/null 2>&1 || { echo aclocal not found exit 1 } aclocal -I . ${ACLOCAL_FLAGS} || exit 1 echo autoheader... (autoheader --version) < /dev/null > /dev/null 2>&1 || { echo autoheader not found exit 1 } autoheader || exit 1 echo -n "libtoolize... " if ( (glibtoolize --version) < /dev/null > /dev/null 2>&1 ); then echo "using glibtoolize" glibtoolize --automake --copy --force || exit 1 elif ( (libtoolize --version) < /dev/null > /dev/null 2>&1 ) ; then echo "using libtoolize" libtoolize --automake --copy --force || exit 1 else echo "libtoolize nor glibtoolize not found" exit 1 fi echo automake... (automake --version) < /dev/null > /dev/null 2>&1 || { echo automake not found exit 1 } automake --add-missing --copy --gnu || exit 1 echo autoconf... (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo autoconf not found exit 1 } autoconf || exit 1 echo ready to configure exit 0 uptimed-0.4.2/configure.ac000066400000000000000000000041071353126524100154560ustar00rootroot00000000000000dnl configure.in for uptimed AC_INIT([uptimed], 0.4.2) AM_CONFIG_HEADER(config.h) AC_PROG_CC AM_PROG_LIBTOOL AM_INIT_AUTOMAKE case "$host" in *-linux*) AC_DEFINE(PLATFORM_LINUX, 1, [Define if you are compiling for Linux]) PKG_PROG_PKG_CONFIG AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) if test "x$with_systemdsystemunitdir" != xno; then AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) AC_OUTPUT([etc/uptimed.service]) fi ;; *-hpux*) AC_DEFINE(PLATFORM_HPUX, 1, [Define if you are compiling for HP/UX]) ;; *-solaris*) AC_DEFINE(PLATFORM_SOLARIS, 1, [Define if you are compiling for Solaris]) ;; *-freebsd*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-kfreebsd*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-bsdi*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-netbsd*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-openbsd*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-bitrig*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-darwin*) AC_DEFINE(PLATFORM_BSD, 1, [Define if you are compiling for *BSD]) ;; *-gnu*) AC_DEFINE(PLATFORM_GNU, 1, [Define if you are compiling for *GNU]) ;; *) AC_DEFINE(PLATFORM_UNKNOWN, 1, [Define if you are compiling for an unknown system]) ;; esac AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) AC_REPLACE_FUNCS(getopt) AC_CHECK_HEADERS(getopt.h) AC_CHECK_FUNCS([getdtablesize]) AC_OUTPUT([Makefile libuptimed/Makefile src/Makefile man/Makefile etc/Makefile uptimed.spec]) echo "" echo "--- Now type \"gmake\" to build Uptimed ---" echo "--- If gmake is not working, try \"make\" ---" echo "" uptimed-0.4.2/etc/000077500000000000000000000000001353126524100137415ustar00rootroot00000000000000uptimed-0.4.2/etc/Makefile.am000066400000000000000000000002141353126524100157720ustar00rootroot00000000000000sysconf_DATA = uptimed.conf-dist EXTRA_DIST = uptimed.conf-dist rc.uptimed if HAVE_SYSTEMD systemdsystemunit_DATA = uptimed.service endif uptimed-0.4.2/etc/rc.uptimed000066400000000000000000000044471353126524100157470ustar00rootroot00000000000000#!/bin/bash # # Init file for uptimed daemon # # chkconfig: 2345 95 05 # description: Uptimed is an uptime record daemon keeping track of the highest # uptimes a computer system ever had. It uses the system boot time # to keep sessions apart from each other. Uptimed comes with a # console front-end to parse the records, which can also easily be # used to show your records on a web page. # # config: /etc/uptimed.conf # ### BEGIN INIT INFO # Provides: uptimed # Required-Start: # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Uptimed is an uptime record daemon # Description: Uptimed is an uptime record daemon keeping track of the highest # uptimes a computer system ever had. It uses the system boot time # to keep sessions apart from each other. Uptimed comes with a # console front-end to parse the records, which can also easily be # used to show your records on a web page. ### END INIT INFO RETVAL=0 NAME="uptimed" UPTIMED="/usr/sbin/uptimed" if [ -f /etc/rc.d/init.d/functions ] then # Redhat . /etc/rc.d/init.d/functions START="daemon $UPTIMED" STOP="killproc $UPTIMED" STATUS="status $UPTIMED" CREATEBOOTID="action $\"Creating unique bootid for $NAME:\" $UPTIMED -b" POST="echo" elif [ -f /sbin/start-stop-daemon ] then # Debian START="start-stop-daemon --start --quiet --pidfile /var/run/uptimed.pid --exec $UPTIMED" STOP="start-stop-daemon --stop --quiet --pidfile /var/run/uptimed.pid --exec $UPTIMED" STATUS="echo \"Status not implemented\"" CREATEBOOTID="echo \"Creating unique bootid for $NAME:\"; $UPTIMED -b" POST="echo \"$NAME.\"" else # Eep. What do we do here ? START="$UPTIMED" STOP="killall $UPTIMED" STATUS="echo \"Status not implemented\"" CREATEBOOTID="$UPTIMED -b" POST="echo" fi start() { echo -n $"Starting $NAME:" $START RETVAL=$? $POST } stop() { echo -n $"Stopping $NAME:" $STOP RETVAL=$? $POST } showstatus() { $STATUS $UPTIMED RETVAL=$? } createbootid() { $CREATEBOOTID RETVAL=$? $POST } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; createbootid) createbootid ;; status) showstatus ;; *) echo $"Usage: $0 {start|stop|restart|createbootid|status}" RETVAL=1 esac exit $RETVAL uptimed-0.4.2/etc/uptimed.conf-dist000066400000000000000000000031711353126524100172220ustar00rootroot00000000000000# Uptimed configuration file. # Interval to write the logfile with in seconds. UPDATE_INTERVAL=60 # Maximum number of entries in logfile. Set to 0 for unlimited. LOG_MAXIMUM_ENTRIES=50 # Minimum uptime that must be reached for it to be considered a record. LOG_MINIMUM_UPTIME=1h # Minimum uptime before sending out e-mail. MAIL_MINIMUM_UPTIME=1d # Minimum position before sending out e-mail. MAIL_MINIMUM_POSITION=10 # Email address to mail milestones/records to. # Assumes sendmail compatible MTA installed as /usr/lib/sendmail. # You can enable this below or with the -e option on the commandline. EMAIL=root@localhost # Send email? (0 = no way, 1 = yes please!, 2 = only for milestones, # 3 = only for records) SEND_EMAIL=0 # We need a sendmail compatible mailer, though. SENDMAIL=/usr/lib/sendmail -t # Where to note our PID PIDFILE=/var/run/uptimed # Milestones are configurable now. # Syntax is pretty easy: MILESTONE=time:description # Default time is in seconds, but it can be postfixed with "d", "w" or "y" # for days/weeks/years. # Keep in mind that the description needs to fit in the window. MILESTONE=5d:five days MILESTONE=10d:ten days MILESTONE=25d:twenty-five days MILESTONE=50d:fifty days MILESTONE=10w:ten weeks MILESTONE=75d:seventy-five days MILESTONE=100d:hundred days MILESTONE=150d:hundred and fifty days MILESTONE=25w:twenty-five weeks MILESTONE=200d:two hundred days MILESTONE=250d:250 days MILESTONE=300d:three hundred days MILESTONE=50w:fifty weeks MILESTONE=1y:one year MILESTONE=400d:four hundred days MILESTONE=500d:five hundred days MILESTONE=100w:hundred weeks MILESTONE=750d:750 days MILESTONE=1000d:thousand days uptimed-0.4.2/etc/uptimed.service.in000066400000000000000000000003511353126524100173760ustar00rootroot00000000000000[Unit] Description=Uptime record tracking daemon Documentation=man:uptimed(8) man:uprecords(1) After=time-sync.target [Service] Type=notify ExecStart=@prefix@/sbin/uptimed -f Restart=on-failure [Install] WantedBy=multi-user.target uptimed-0.4.2/libuptimed/000077500000000000000000000000001353126524100153245ustar00rootroot00000000000000uptimed-0.4.2/libuptimed/Makefile.am000066400000000000000000000002531353126524100173600ustar00rootroot00000000000000lib_LTLIBRARIES = libuptimed.la libuptimed_la_SOURCES = misc.c milestone.c urec.c libuptimed_la_LDFLAGS = -version-info 0:0:0 noinst_HEADERS = milestone.h misc.h urec.h uptimed-0.4.2/libuptimed/milestone.c000066400000000000000000000057171353126524100175010ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper - read_uptime code for BSD and Solaris platforms taken from upclient package by Martijn Broenland. 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "milestone.h" Milestone *milestone_list = NULL; static Milestone *milestone_last = NULL; Milestone *add_milestone(time_t time, char *desc) { Milestone *m, *tmpm, *mprev=NULL; /* Allocate memory for the new entry. */ if ((m=malloc(sizeof(Milestone))) == NULL) { printf("error mallocing milestone struct. this is serious shit! exiting.\n"); exit(1); } /* Copy boottime, uptime and systeminfo into memory. */ m->time = time; strncpy(m->desc, desc, SYSMAX); m->desc[SYSMAX]='\0'; /* Add the entry to the linked list. */ for(tmpm=milestone_list;tmpm;tmpm=tmpm->next) { if (m->time < tmpm->time) { m->next=tmpm; if (tmpm==milestone_list) return milestone_list = m; else return mprev->next = m; } else mprev = tmpm; } m->next = NULL; if (milestone_last) milestone_last->next = m; else milestone_list = m; return milestone_last = m; } void del_milestone(Milestone *m) { Milestone *tmpm=milestone_list; if (m==milestone_list) { milestone_list=m->next; if (!milestone_list) milestone_last = NULL; } else { for (tmpm=milestone_list; tmpm->next && m!=tmpm->next; tmpm=tmpm->next); if (!m->next) milestone_last = tmpm; tmpm->next = m->next; } free(m); } Milestone *find_next_milestone(time_t offset) { Milestone *m; for (m=milestone_list;m && m->time < offset;m=m->next); if (m) return m; else return NULL; } time_t scantime(char *str) { char *end; size_t len; time_t multiplier; /* Find the last char in string. */ len = strlen(str); end = str + len - 1; if (isdigit(*end)) { /* It's a digit, so input was in seconds. */ multiplier = 1; } else { switch(tolower(*end)) { case 's': /* Seconds. */ multiplier = 1; break; case 'h': /* Hours */ multiplier = 3600; break; case 'd': /* Days. */ multiplier = 86400; break; case 'w': /* Weeks. */ multiplier = 7 * 86400; break; case 'y': /* Solar years. */ multiplier = (time_t) (365.24219 * 86400.00); break; default: /* Garbage. */ multiplier = 0; break; } *end = '\0'; /* remove the time factor byte. */ } return atol(str)*multiplier; } uptimed-0.4.2/libuptimed/milestone.h000066400000000000000000000031471353126524100175010ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #ifdef xPLATFORM_BSD #include #include #include #endif #ifdef xPLATFORM_SOLARIS #include #include #include #include #endif #ifdef xPLATFORM_HPUX #include #include extern void snprintf(char *,...); #define _INCLUDE_HPUX_SOURCE #include #endif #ifdef xPLATFORM_UNKNOWN #include #endif #include "misc.h" typedef struct milestone { time_t time; /* uptime to reach */ char desc[SYSMAX+1]; /* little description */ struct milestone *next; } Milestone; extern Milestone *milestone_list; Milestone *add_milestone(time_t, char *); void del_milestone(Milestone *milestone); Milestone *find_next_milestone(time_t); time_t scantime(char *); uptimed-0.4.2/libuptimed/misc.c000066400000000000000000000027431353126524100164310ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "misc.h" char hd[256]; char *time2uptime (time_t t) { static char timebuf[21] = ""; int sec, min, hour, day; sec = t % 60; t /= 60; min = t % 60; t /= 60; hour = t % 24; t /= 24; day = t; snprintf(timebuf, sizeof(timebuf)-1, "%d %s, %.2d:%.2d:%.2d", day, (day == 1 ? "day " : "days"), hour, min, sec); timebuf[sizeof(timebuf)-1] = 0; return timebuf; } void read_homedir(void) { strncpy(hd, getenv("HOME"), sizeof(hd)-1); hd[sizeof(hd)-1]='\0'; if(!hd[0]) { printf("Could not initialize your homedir, exiting.\n"); exit(-1); } } void cat(char *filename) { FILE *f; char str[512]; f=fopen(filename, "r"); if (!f) return; fgets(str, sizeof(str), f); while (!feof(f)) { printf("%s", str); fgets(str, sizeof(str), f); } fclose(f); } uptimed-0.4.2/libuptimed/misc.h000066400000000000000000000015721353126524100164350ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include #include #include #include #define SYSMAX 256 char *time2uptime (time_t t); void read_homedir(void); void cat(char *); uptimed-0.4.2/libuptimed/urec.c000066400000000000000000000277551353126524100164460ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper - read_uptime code for BSD and Solaris platforms taken from upclient package by Martijn Broenland. 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "../config.h" #include "urec.h" #ifdef __ANDROID__ Urec *u_current; #endif Urec *urec_list = NULL; static Urec *urec_last = NULL; Urec *add_urec(time_t utime, time_t btime, char *sys) { Urec *u, *tmpu, *uprev = NULL; /* Allocate memory for the new entry. */ if ((u=malloc(sizeof(Urec))) == NULL) { printf("error mallocing urec struct. this is serious shit! exiting.\n"); exit(1); } /* Copy boottime, uptime and systeminfo into memory. */ u->utime = utime; u->btime = btime; strncpy(u->sys, sys, SYSMAX); u->sys[SYSMAX]='\0'; /* Add the entry to the linked list. */ for(tmpu = urec_list; tmpu; tmpu = tmpu->next) { if (u->utime > tmpu->utime) { u->next=tmpu; if (tmpu == urec_list) return urec_list = u; return uprev->next = u; } else { uprev = tmpu; } } u->next = NULL; if (urec_last) { urec_last->next = u; } else { urec_list = u; } return urec_last = u; } void del_urec(Urec *u) { Urec *tmpu = urec_list; if (u == urec_list) { urec_list=u->next; if (!urec_list) urec_last = NULL; } else { for (tmpu = urec_list; tmpu->next && u != tmpu->next; tmpu = tmpu->next); if (!u->next) urec_last = tmpu; tmpu->next = u->next; } free(u); } void moveup(void) { /* Delete current session from the list. */ del_urec(u_current); /* Re-add it. (it should be urec_list now) */ u_current=add_urec(read_uptime(), readbootid(), read_sysinfo()); } char *read_sysinfo(void) { struct utsname temp_uname; static char sys[SYSMAX+1]; /* What kernel are we running at the moment? */ if (!uname(&temp_uname)) { /* Name and number.. */ snprintf(sys, SYSMAX, "%s %s", temp_uname.sysname, temp_uname.release); sys[SYSMAX]='\0'; return sys; } else { #ifdef PLATFORM_LINUX return "Linux"; #endif #ifdef PLATFORM_BSD return "BSD"; #endif #ifdef PLATFORM_SOLARIS return "Solaris"; #endif #ifdef PLATFORM_HPUX return "HP/UX"; #endif #ifdef PLATFORM_GNU return "GNU"; #endif #ifdef PLATFORM_UNKNOWN return "unknown"; #endif } } #ifdef PLATFORM_LINUX time_t read_uptime(void) { struct timespec ts; FILE *f; double upseconds = 0; struct sysinfo si; if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) return ts.tv_sec; /* clock_gettime() failed */ f=fopen("/proc/uptime", "r"); if (f > 0) { if (fscanf(f, "%lf", &upseconds) > 0) { fclose(f); return((time_t)upseconds); } fclose(f); } /* reading of /proc/uptime failed */ /* Until jiffies is declared to something different than unsigned long * in the kernel sources, this value will probably on all 32b platforms * wrap past approx. 497 days. This also applies to reading this value * through /proc/uptime. */ if (sysinfo(&si) != 0) { printf ("uptimed: error getting uptime!\n"); exit(-1); } return((time_t)si.uptime); } #endif #ifdef PLATFORM_BSD time_t read_uptime(void) { time_t now, up; struct timeval boottime; int mib[2]; size_t size; (void)time(&now); mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof (boottime); if (sysctl (mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec!= 0) { up = now - boottime.tv_sec; } return up; } #endif #ifdef PLATFORM_SOLARIS time_t read_uptime(void) { int fd; struct utmpx ut; int found=0; fd = open(UTMPX_FILE, O_RDONLY); if (fd >= 0) { while (!found) { if (read(fd, &ut, sizeof(ut)) < 0) { found = -1; } else if (ut.ut_type==BOOT_TIME) { found = 1; } } close(fd); } if (found == 1) return time(0) - ut.ut_tv.tv_sec; return 0; } #endif #ifdef PLATFORM_HPUX time_t read_uptime(void) { struct pst_static _pst_static; pstat_getstatic( &_pst_static, sizeof(_pst_static), (size_t)1, 0); return (time_t)(time(0) - _pst_static.boot_time); } #endif #if defined(PLATFORM_UNKNOWN) || defined(PLATFORM_GNU) time_t read_uptime(void) { /* * This is a quick and inaccurate hack calculating the uptime from the * current time and the timestamp made at boottime. * * This is inaccurate because: * 1) the boottime timestamp can be extremely delayed due to fscking etc. * 2) when the system time changes (for example timezone changes) the * boottime timestamp does not, creating even more inaccuracy. */ if (u_current) return time(0) - u_current->btime; return time(0) - readbootid(); } #endif void calculate_downtime(void) { Urec *u, *sorted_list = sort_urec(urec_list, -1); for (u = sorted_list; u; u = u->next) { if (u->next) { u->dtime = u->btime - (u->next->btime + u->next->utime); } else { /* First uptime recorded... No prior downtime data. */ u->dtime = 0; } } urec_list = sort_urec(sorted_list, 0); } void read_records(time_t current) { FILE *f; char str[256]; time_t utime, btime; long l_utime, l_btime; char buf[256], sys[SYSMAX+1]; struct stat filestat, filestatold; int useold = 0; if (stat(FILE_RECORDS, &filestat)) useold = 1; if (stat(FILE_RECORDS".old", &filestatold)) useold = -1; /* assume that backupdb larger than normal db means normal is corrupted */ if (!useold && (filestat.st_size < filestatold.st_size)) useold = 1; dbtry: switch (useold) { case 0: f = fopen(FILE_RECORDS, "r"); break; case 1: f = fopen(FILE_RECORDS".old", "r"); printf("uptimed: reading from backup database %s.old\n", FILE_RECORDS); break; default: /* this should probably terminate uptimed somehow */ printf("uptimed: no useable database found.\n"); return; } if (!f) { printf("uptimed: error opening database for reading.\n"); return; } fgets(str, sizeof(str), f); while (!feof(f)) { /* Check for validity of input string. */ if (sscanf(str, "%ld:%ld:%[^]\n]", &l_utime, &l_btime, buf) != 3) { /* database is corrupted */ fclose(f); useold++; goto dbtry; } else { utime = (time_t)l_utime; btime = (time_t)l_btime; strncpy(sys, buf, SYSMAX); sys[SYSMAX]='\0'; if (utime > 0 && btime != current) add_urec(utime, btime, sys); } fgets(str, sizeof(str), f); } fclose(f); calculate_downtime(); } void save_records(int max, time_t log_threshold) { FILE *f; Urec *u; int i = 0; f = fopen(FILE_RECORDS".tmp", "w"); if (!f) { printf("uptimed: cannot write to %s\n", FILE_RECORDS); return; } for (u = urec_list; u; u = u->next) { /* Ignore everything below the threshold */ if (u->utime >= log_threshold) { fprintf(f, "%lu:%lu:%s\n", (unsigned long)u->utime, (unsigned long)u->btime, u->sys); /* Stop processing when we've logged the max number specified. */ if ((max > 0) && (++i >= max)) break; } } fclose(f); rename(FILE_RECORDS, FILE_RECORDS".old"); rename(FILE_RECORDS".tmp", FILE_RECORDS); } #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) || defined(PLATFORM_GNU) int createbootid(void) { /* these platforms doesn't need to create a bootid file. * readbootid() fetches it directly from the system every time. */ return 0; } #endif #ifdef PLATFORM_SOLARIS int createbootid(void) { FILE *f; int fd; struct utmpx ut; int found = 0; time_t bootid = 0; fd = open (UTMPX_FILE, O_RDONLY); if (fd >= 0) { while(!found) { if (read(fd, &ut, sizeof(ut)) < 0) { found = -1; } else if (ut.ut_type==BOOT_TIME) { found = 1; } } close(fd); } if (found == 1) bootid = ut.ut_tv.tv_sec; f = fopen(FILE_BOOTID, "w"); if (!f) { printf("Error writing bootid file, exiting!\n"); exit(-1); } else { fprintf(f, "%ld\n", bootid); fclose(f); } return 0; } #endif #ifdef PLATFORM_HPUX int createbootid(void) { FILE *f; struct pst_static _pst_static; pstat_getstatic(&_pst_static, sizeof(_pst_static), (size_t)1, 0); f=fopen(FILE_BOOTID, "w"); if (!f) { printf("Error writing bootid file, exiting!\n"); exit(-1); } else { fprintf(f, "%ld\n", _pst_static.boot_time); fclose(f); } return 0; } #endif #ifdef PLATFORM_UNKNOWN int createbootid(void) { FILE *f; time_t bootid=0; bootid=time(0); f = fopen(FILE_BOOTID, "w"); if (!f) { printf("Error writing bootid file, exiting!\n"); exit(-1); } else { fprintf(f, "%ld\n", bootid); fclose(f); } return 0; } #endif time_t readbootid(void) { #ifdef PLATFORM_BSD time_t bootid = 0; struct timeval boottime; int mib[2]; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof (boottime); if (sysctl (mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) { bootid = boottime.tv_sec; } return bootid; #elif defined(PLATFORM_LINUX) || defined(PLATFORM_GNU) FILE *f; char str[256]; time_t bootid = 0; f=fopen("/proc/stat", "r"); if (!f) { printf ("Error opening /proc/stat file. Can not determine bootid, exiting!\n"); exit(-1); } else { fgets(str, sizeof(str), f); while (!feof(f)) { if (strstr(str, "btime")) { bootid=atoi(str+6); break; } fgets(str, sizeof(str), f); } fclose(f); } if (bootid == 0) { printf ("Parsing btime from /proc/stat failed. Can not determine bootid, exiting!\n"); exit(-1); } return bootid; #else FILE *f; char str[256]; f=fopen(FILE_BOOTID, "r"); if (!f) { printf("Error reading boot id from file, exiting!\n\nYou probably forgot to create a bootid with with the -b option.\nYou really want the system to do this on bootup, read the INSTALL file!\n"); exit(-1); } fgets(str, sizeof(str), f); fclose(f); return atoi(str); #endif } int compare_urecs(Urec *a, Urec *b, int sort_by) { if (sort_by == 0) { return b->utime - a->utime; } else if (sort_by == 1) { return a->btime - b->btime; } else if (sort_by == -1) { return b->btime - a->btime; } else if (sort_by == 2) { return strcmp(a->sys, b->sys); } else if (sort_by == -2) { return strcmp(b->sys, a->sys); } return 0; } Urec* sort_urec(Urec* list, int sort_by) { /* * sort_by: * 0: Nothing * 1: Boottime * -1: Reverse Boottime * 2: Sysinfo * -2: Reverse Sysinfo */ Urec *p, *q, *e, *tail; int insize, nmerges, psize, qsize, i; insize = 1; for (;;) { p = list; list = NULL; tail = NULL; nmerges = 0; /* count number of merges we do in this pass */ while (p) { nmerges++; /* there exists a merge to be done */ /* step `insize' places along from p */ q = p; psize = 0; for (i = 0; i < insize; i++) { psize++; q = q->next; if (!q) break; } /* if q hasn't fallen off end, we have two lists to merge */ qsize = insize; /* now we have two lists; merge them */ while (psize > 0 || (qsize > 0 && q)) { /* decide whether next element of merge comes from p or q */ if (psize == 0) { /* p is empty; e must come from q. */ e = q; q = q->next; qsize--; } else if (qsize == 0 || !q) { /* q is empty; e must come from p. */ e = p; p = p->next; psize--; } else if (compare_urecs(p,q,sort_by) <= 0) { /* First element of p is lower (or same); * e must come from p. */ e = p; p = p->next; psize--; } else { /* First element of q is lower; e must come from q. */ e = q; q = q->next; qsize--; } /* add the next element to the merged list */ if (tail) { tail->next = e; } else { list = e; } tail = e; } /* now p has stepped `insize' places along, and q has too */ p = q; } tail->next = NULL; /* If we have done only one merge, we're finished. */ if (nmerges <= 1) return list; /* allow for nmerges==0, the empty list case */ /* Otherwise repeat, merging lists twice the size */ insize *= 2; } } uptimed-0.4.2/libuptimed/urec.h000066400000000000000000000042151353126524100164350ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #ifdef PLATFORM_LINUX #include #endif #ifdef PLATFORM_BSD #include #include #include #endif #ifdef PLATFORM_SOLARIS #include #include #include #include #endif #ifdef PLATFORM_HPUX #include #include extern void snprintf(char *, ...); #define _INCLUDE_HPUX_SOURCE #include #endif #ifdef PLATFORM_UNKNOWN #include #endif #include "misc.h" #ifdef __ANDROID__ #define FILE_BOOTID "/data/uptimed/bootid" #define FILE_RECORDS "/data/uptimed/records" #else #define FILE_BOOTID "/var/spool/uptimed/bootid" #define FILE_RECORDS "/var/spool/uptimed/records" #endif typedef struct urec { time_t utime; /* uptime */ time_t btime; /* time of boot up */ time_t dtime; /* downtime */ char sys[SYSMAX+1]; /* system type */ struct urec *next; } Urec; extern Urec *urec_list; extern Urec *u_current; Urec *add_urec(time_t, time_t, char *); void del_urec(Urec *urec); void moveup(void); char *read_sysinfo(void); time_t read_uptime(void); void calculate_downtime(void); void read_records(time_t); void save_records(int, time_t); #ifndef PLATFORM_BSD int createbootid(void); #endif int compare_urecs(Urec *, Urec *, int); Urec *sort_urec(Urec *, int); time_t readbootid(void); uptimed-0.4.2/man/000077500000000000000000000000001353126524100137415ustar00rootroot00000000000000uptimed-0.4.2/man/Makefile.am000066400000000000000000000001061353126524100157720ustar00rootroot00000000000000 man_MANS = uptimed.8 uprecords.1 EXTRA_DIST = uptimed.8 uprecords.1 uptimed-0.4.2/man/uprecords.1000066400000000000000000000022741353126524100160360ustar00rootroot00000000000000.TH UPRECORDS 1 "June 20, 2004" .nh .SH NAME uprecords \- provides uptime records .SH SYNOPSIS .B uprecords [ \fB-?abBcfkKMsv\fP ] [ \fB-i\fP ] [ \fB-m\fP ] .SH DESCRIPTION This manual page documents the .B uprecords program. .PP .B uprecords is a program that provides record statistics from the .B uptimed(8) program. .SH OPTIONS .TP .B \-? Show usage .TP .B \-a Do not print ANSI codes .TP .B \-b -B Sort by time of bootup, oldest entry first. -B reverses. Option implies \-s. Do not print ANSI codes .TP .B \-c Do not show current entry if not in top entries .TP .B \-f Run continuously in a loop .TP .B \-k -K Sort by kernel/system name. -K reverses. Option implies \-s. .TP .B \-M Show next milestone .TP .B \-s Do not print extra statistics .TP \fB\-i\fP Use seconds for loop instead of 5, implies -f .TP \fB\-m\fP Show a maximum of top COUNT entries instead of 10 .TP .B \-v Show version information .SH SEE ALSO .BR uptimed (8) .br .SH AUTHOR Rob Kaper . This manual page was written by Alan Ford , for the Debian GNU/Linux system (but may be used by others). It was last modified for .B uptimed version 0.3.7. uptimed-0.4.2/man/uptimed.8000066400000000000000000000024331353126524100155030ustar00rootroot00000000000000.TH UPTIMED 8 "May 28, 2004" .nh .SH NAME uptimed \- daemon to record uptime records .SH SYNOPSIS .B uptimed [ \fB-?bv\fP ] [ \fB-e\fP ] [ \fB-i\fP ] [ \fB-m\fP ] .SH DESCRIPTION This manual page documents the .B uptimed program. .PP .B uptimed is a daemon that records statistics about a machine's uptime. Use the .B uprecords(1) program to get uptime record statistics. .SH OPTIONS These command-line options override settings in the configuration file .B /etc/uptimed.conf .TP .B \-? Show usage .TP .B \-b Create bootid and exit. This option is ignored on BSD systems, because the BSD kernel keeps a static boot time variable in memory so Uptimed does not need to cache this value. .TP \fB\-p\fP Write PID to pidfile .TP \fB\-e\fP Send mail to at milestones/records .TP \fB\-i\fP Use seconds for loop .TP \fB\-m\fP Log a maximum of entries .TP \fB\-t\fP Set the minimum uptime to be considered a record .TP .B \-v Show version information .SH SEE ALSO .BR uprecords (1) .br .SH AUTHOR Rob Kaper . This manual page was written by Alan Ford , for the Debian GNU/Linux system (but may be used by others). It was last modified for .B uptimed version 0.3.7. uptimed-0.4.2/sample-cgi/000077500000000000000000000000001353126524100152075ustar00rootroot00000000000000uptimed-0.4.2/sample-cgi/uprecords.conf000066400000000000000000000002751353126524100200700ustar00rootroot00000000000000# uprecords.cgi configuration file. # LAYOUT can be "pre", "list" or "table" LAYOUT=pre # TYPE can be "system" or "downtime" TYPE=system # Maximum number of entries to show. SHOW_MAX=10 uptimed-0.4.2/sample-cgi/uprecords.footer000066400000000000000000000001541353126524100204350ustar00rootroot00000000000000

    Cool eh?

    You can now go back to the main page of my site. uptimed-0.4.2/sample-cgi/uprecords.header000066400000000000000000000006241353126524100203710ustar00rootroot00000000000000 Uptime records for this host

    Uptime records for this host

    This host runs a cool program called uptimed to log uptime records. It comes with a nice program to examine the logs and display them in a humane manner. As you can see this program also runs as CGI!

    Here are the uptime records for this system:

    uptimed-0.4.2/src/000077500000000000000000000000001353126524100137555ustar00rootroot00000000000000uptimed-0.4.2/src/Makefile.am000066400000000000000000000012221353126524100160060ustar00rootroot00000000000000bin_PROGRAMS = uprecords sbin_PROGRAMS = uptimed uptimed_SOURCES = uptimed.c sd-daemon.c uprecords_SOURCES = uprecords.c uptimed_LDADD = @LIBOBJS@ $(top_builddir)/libuptimed/libuptimed.la uprecords_LDADD = @LIBOBJS@ $(top_builddir)/libuptimed/libuptimed.la AM_CPPFLAGS = -I$(top_srcdir)/libuptimed # On Linux with glibc 2.17, sd-daemon.c support for POSIX message queues # results in an otherwise unnecessary dependency on librt. Disable it. AM_CPPFLAGS += -DSD_DAEMON_DISABLE_MQ noinst_HEADERS = uprecords.h uptimed.h sd-daemon.h EXTRA_DIST = getopt.c getopt.h uptimed.o uprecords.o: AM_CFLAGS = @CFLAGS@ -DFILE_CONFIG=\"$(sysconfdir)/uptimed.conf\" uptimed-0.4.2/src/getopt.c000066400000000000000000000727071353126524100154400ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if defined HAVE_LIBINTL_H || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ uptimed-0.4.2/src/getopt.h000066400000000000000000000144631353126524100154400ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ uptimed-0.4.2/src/sd-daemon.c000066400000000000000000000326661353126524100160050ustar00rootroot00000000000000/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** Copyright 2010 Lennart Poettering Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ***/ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__linux__) && !defined(SD_DAEMON_DISABLE_MQ) # include #endif #include "sd-daemon.h" #if (__GNUC__ >= 4) # ifdef SD_EXPORT_SYMBOLS /* Export symbols */ # define _sd_export_ __attribute__ ((visibility("default"))) # else /* Don't export the symbols */ # define _sd_export_ __attribute__ ((visibility("hidden"))) # endif #else # define _sd_export_ #endif _sd_export_ int sd_listen_fds(int unset_environment) { #if defined(DISABLE_SYSTEMD) || !defined(__linux__) return 0; #else int r, fd; const char *e; char *p = NULL; unsigned long l; e = getenv("LISTEN_PID"); if (!e) { r = 0; goto finish; } errno = 0; l = strtoul(e, &p, 10); if (errno > 0) { r = -errno; goto finish; } if (!p || p == e || *p || l <= 0) { r = -EINVAL; goto finish; } /* Is this for us? */ if (getpid() != (pid_t) l) { r = 0; goto finish; } e = getenv("LISTEN_FDS"); if (!e) { r = 0; goto finish; } errno = 0; l = strtoul(e, &p, 10); if (errno > 0) { r = -errno; goto finish; } if (!p || p == e || *p) { r = -EINVAL; goto finish; } for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { int flags; flags = fcntl(fd, F_GETFD); if (flags < 0) { r = -errno; goto finish; } if (flags & FD_CLOEXEC) continue; if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { r = -errno; goto finish; } } r = (int) l; finish: if (unset_environment) { unsetenv("LISTEN_PID"); unsetenv("LISTEN_FDS"); } return r; #endif } _sd_export_ int sd_is_fifo(int fd, const char *path) { struct stat st_fd; if (fd < 0) return -EINVAL; if (fstat(fd, &st_fd) < 0) return -errno; if (!S_ISFIFO(st_fd.st_mode)) return 0; if (path) { struct stat st_path; if (stat(path, &st_path) < 0) { if (errno == ENOENT || errno == ENOTDIR) return 0; return -errno; } return st_path.st_dev == st_fd.st_dev && st_path.st_ino == st_fd.st_ino; } return 1; } _sd_export_ int sd_is_special(int fd, const char *path) { struct stat st_fd; if (fd < 0) return -EINVAL; if (fstat(fd, &st_fd) < 0) return -errno; if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) return 0; if (path) { struct stat st_path; if (stat(path, &st_path) < 0) { if (errno == ENOENT || errno == ENOTDIR) return 0; return -errno; } if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) return st_path.st_dev == st_fd.st_dev && st_path.st_ino == st_fd.st_ino; else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) return st_path.st_rdev == st_fd.st_rdev; else return 0; } return 1; } static int sd_is_socket_internal(int fd, int type, int listening) { struct stat st_fd; if (fd < 0 || type < 0) return -EINVAL; if (fstat(fd, &st_fd) < 0) return -errno; if (!S_ISSOCK(st_fd.st_mode)) return 0; if (type != 0) { int other_type = 0; socklen_t l = sizeof(other_type); if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) return -errno; if (l != sizeof(other_type)) return -EINVAL; if (other_type != type) return 0; } if (listening >= 0) { int accepting = 0; socklen_t l = sizeof(accepting); if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) return -errno; if (l != sizeof(accepting)) return -EINVAL; if (!accepting != !listening) return 0; } return 1; } union sockaddr_union { struct sockaddr sa; struct sockaddr_in in4; struct sockaddr_in6 in6; struct sockaddr_un un; struct sockaddr_storage storage; }; _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { int r; if (family < 0) return -EINVAL; r = sd_is_socket_internal(fd, type, listening); if (r <= 0) return r; if (family > 0) { union sockaddr_union sockaddr = {}; socklen_t l = sizeof(sockaddr); if (getsockname(fd, &sockaddr.sa, &l) < 0) return -errno; if (l < sizeof(sa_family_t)) return -EINVAL; return sockaddr.sa.sa_family == family; } return 1; } _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { union sockaddr_union sockaddr = {}; socklen_t l = sizeof(sockaddr); int r; if (family != 0 && family != AF_INET && family != AF_INET6) return -EINVAL; r = sd_is_socket_internal(fd, type, listening); if (r <= 0) return r; if (getsockname(fd, &sockaddr.sa, &l) < 0) return -errno; if (l < sizeof(sa_family_t)) return -EINVAL; if (sockaddr.sa.sa_family != AF_INET && sockaddr.sa.sa_family != AF_INET6) return 0; if (family > 0) if (sockaddr.sa.sa_family != family) return 0; if (port > 0) { if (sockaddr.sa.sa_family == AF_INET) { if (l < sizeof(struct sockaddr_in)) return -EINVAL; return htons(port) == sockaddr.in4.sin_port; } else { if (l < sizeof(struct sockaddr_in6)) return -EINVAL; return htons(port) == sockaddr.in6.sin6_port; } } return 1; } _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { union sockaddr_union sockaddr = {}; socklen_t l = sizeof(sockaddr); int r; r = sd_is_socket_internal(fd, type, listening); if (r <= 0) return r; if (getsockname(fd, &sockaddr.sa, &l) < 0) return -errno; if (l < sizeof(sa_family_t)) return -EINVAL; if (sockaddr.sa.sa_family != AF_UNIX) return 0; if (path) { if (length == 0) length = strlen(path); if (length == 0) /* Unnamed socket */ return l == offsetof(struct sockaddr_un, sun_path); if (path[0]) /* Normal path socket */ return (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && memcmp(path, sockaddr.un.sun_path, length+1) == 0; else /* Abstract namespace socket */ return (l == offsetof(struct sockaddr_un, sun_path) + length) && memcmp(path, sockaddr.un.sun_path, length) == 0; } return 1; } _sd_export_ int sd_is_mq(int fd, const char *path) { #if !defined(__linux__) || defined(SD_DAEMON_DISABLE_MQ) return 0; #else struct mq_attr attr; if (fd < 0) return -EINVAL; if (mq_getattr(fd, &attr) < 0) return -errno; if (path) { char fpath[PATH_MAX]; struct stat a, b; if (path[0] != '/') return -EINVAL; if (fstat(fd, &a) < 0) return -errno; strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); fpath[sizeof(fpath)-1] = 0; if (stat(fpath, &b) < 0) return -errno; if (a.st_dev != b.st_dev || a.st_ino != b.st_ino) return 0; } return 1; #endif } _sd_export_ int sd_notify(int unset_environment, const char *state) { #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) return 0; #else int fd = -1, r; struct msghdr msghdr; struct iovec iovec; union sockaddr_union sockaddr; const char *e; if (!state) { r = -EINVAL; goto finish; } e = getenv("NOTIFY_SOCKET"); if (!e) return 0; /* Must be an abstract socket, or an absolute path */ if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { r = -EINVAL; goto finish; } fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); if (fd < 0) { r = -errno; goto finish; } memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sa.sa_family = AF_UNIX; strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); if (sockaddr.un.sun_path[0] == '@') sockaddr.un.sun_path[0] = 0; memset(&iovec, 0, sizeof(iovec)); iovec.iov_base = (char*) state; iovec.iov_len = strlen(state); memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = &sockaddr; msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) msghdr.msg_namelen = sizeof(struct sockaddr_un); msghdr.msg_iov = &iovec; msghdr.msg_iovlen = 1; if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { r = -errno; goto finish; } r = 1; finish: if (unset_environment) unsetenv("NOTIFY_SOCKET"); if (fd >= 0) close(fd); return r; #endif } _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { #if defined(DISABLE_SYSTEMD) || !defined(__linux__) return 0; #else va_list ap; char *p = NULL; int r; va_start(ap, format); r = vasprintf(&p, format, ap); va_end(ap); if (r < 0 || !p) return -ENOMEM; r = sd_notify(unset_environment, p); free(p); return r; #endif } _sd_export_ int sd_booted(void) { #if defined(DISABLE_SYSTEMD) || !defined(__linux__) return 0; #else struct stat st; /* We test whether the runtime unit file directory has been * created. This takes place in mount-setup.c, so is * guaranteed to happen very early during boot. */ if (lstat("/run/systemd/system/", &st) < 0) return 0; return !!S_ISDIR(st.st_mode); #endif } uptimed-0.4.2/src/sd-daemon.h000066400000000000000000000256061353126524100160060ustar00rootroot00000000000000/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ #ifndef foosddaemonhfoo #define foosddaemonhfoo /*** Copyright 2010 Lennart Poettering Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ***/ #include #include #ifdef __cplusplus extern "C" { #endif /* Reference implementation of a few systemd related interfaces for writing daemons. These interfaces are trivial to implement. To simplify porting we provide this reference implementation. Applications are welcome to reimplement the algorithms described here if they do not want to include these two source files. The following functionality is provided: - Support for logging with log levels on stderr - File descriptor passing for socket-based activation - Daemon startup and status notification - Detection of systemd boots You may compile this with -DDISABLE_SYSTEMD to disable systemd support. This makes all those calls NOPs that are directly related to systemd (i.e. only sd_is_xxx() will stay useful). Since this is drop-in code we don't want any of our symbols to be exported in any case. Hence we declare hidden visibility for all of them. You may find an up-to-date version of these source files online: http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/sd-daemon.c This should compile on non-Linux systems, too, but with the exception of the sd_is_xxx() calls all functions will become NOPs. See sd-daemon(3) for more information. */ #ifndef _sd_printf_attr_ #if __GNUC__ >= 4 #define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b))) #else #define _sd_printf_attr_(a,b) #endif #endif /* Log levels for usage on stderr: fprintf(stderr, SD_NOTICE "Hello World!\n"); This is similar to printk() usage in the kernel. */ #define SD_EMERG "<0>" /* system is unusable */ #define SD_ALERT "<1>" /* action must be taken immediately */ #define SD_CRIT "<2>" /* critical conditions */ #define SD_ERR "<3>" /* error conditions */ #define SD_WARNING "<4>" /* warning conditions */ #define SD_NOTICE "<5>" /* normal but significant condition */ #define SD_INFO "<6>" /* informational */ #define SD_DEBUG "<7>" /* debug-level messages */ /* The first passed file descriptor is fd 3 */ #define SD_LISTEN_FDS_START 3 /* Returns how many file descriptors have been passed, or a negative errno code on failure. Optionally, removes the $LISTEN_FDS and $LISTEN_PID file descriptors from the environment (recommended, but problematic in threaded environments). If r is the return value of this function you'll find the file descriptors passed as fds SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative errno style error code on failure. This function call ensures that the FD_CLOEXEC flag is set for the passed file descriptors, to make sure they are not passed on to child processes. If FD_CLOEXEC shall not be set, the caller needs to unset it after this call for all file descriptors that are used. See sd_listen_fds(3) for more information. */ int sd_listen_fds(int unset_environment); /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is a FIFO in the file system stored under the specified path, 0 otherwise. If path is NULL a path name check will not be done and the call only verifies if the file descriptor refers to a FIFO. Returns a negative errno style error code on failure. See sd_is_fifo(3) for more information. */ int sd_is_fifo(int fd, const char *path); /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is a special character device on the file system stored under the specified path, 0 otherwise. If path is NULL a path name check will not be done and the call only verifies if the file descriptor refers to a special character. Returns a negative errno style error code on failure. See sd_is_special(3) for more information. */ int sd_is_special(int fd, const char *path); /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is a socket of the specified family (AF_INET, ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If family is 0 a socket family check will not be done. If type is 0 a socket type check will not be done and the call only verifies if the file descriptor refers to a socket. If listening is > 0 it is verified that the socket is in listening mode. (i.e. listen() has been called) If listening is == 0 it is verified that the socket is not in listening mode. If listening is < 0 no listening mode check is done. Returns a negative errno style error code on failure. See sd_is_socket(3) for more information. */ int sd_is_socket(int fd, int family, int type, int listening); /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is an Internet socket, of the specified family (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version check is not done. If type is 0 a socket type check will not be done. If port is 0 a socket port check will not be done. The listening flag is used the same way as in sd_is_socket(). Returns a negative errno style error code on failure. See sd_is_socket_inet(3) for more information. */ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port); /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is an AF_UNIX socket of the specified type (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0 a socket type check will not be done. If path is NULL a socket path check will not be done. For normal AF_UNIX sockets set length to 0. For abstract namespace sockets set length to the length of the socket name (including the initial 0 byte), and pass the full socket path in path (including the initial 0 byte). The listening flag is used the same way as in sd_is_socket(). Returns a negative errno style error code on failure. See sd_is_socket_unix(3) for more information. */ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length); /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is a POSIX Message Queue of the specified name, 0 otherwise. If path is NULL a message queue name check is not done. Returns a negative errno style error code on failure. */ int sd_is_mq(int fd, const char *path); /* Informs systemd about changed daemon state. This takes a number of newline separated environment-style variable assignments in a string. The following variables are known: READY=1 Tells systemd that daemon startup is finished (only relevant for services of Type=notify). The passed argument is a boolean "1" or "0". Since there is little value in signaling non-readiness the only value daemons should send is "READY=1". STATUS=... Passes a single-line status string back to systemd that describes the daemon state. This is free-from and can be used for various purposes: general state feedback, fsck-like programs could pass completion percentages and failing programs could pass a human readable error message. Example: "STATUS=Completed 66% of file system check..." ERRNO=... If a daemon fails, the errno-style error code, formatted as string. Example: "ERRNO=2" for ENOENT. BUSERROR=... If a daemon fails, the D-Bus error-style error code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut" MAINPID=... The main pid of a daemon, in case systemd did not fork off the process itself. Example: "MAINPID=4711" WATCHDOG=1 Tells systemd to update the watchdog timestamp. Services using this feature should do this in regular intervals. A watchdog framework can use the timestamps to detect failed services. Daemons can choose to send additional variables. However, it is recommended to prefix variable names not listed above with X_. Returns a negative errno-style error code on failure. Returns > 0 if systemd could be notified, 0 if it couldn't possibly because systemd is not running. Example: When a daemon finished starting up, it could issue this call to notify systemd about it: sd_notify(0, "READY=1"); See sd_notifyf() for more complete examples. See sd_notify(3) for more information. */ int sd_notify(int unset_environment, const char *state); /* Similar to sd_notify() but takes a format string. Example 1: A daemon could send the following after initialization: sd_notifyf(0, "READY=1\n" "STATUS=Processing requests...\n" "MAINPID=%lu", (unsigned long) getpid()); Example 2: A daemon could send the following shortly before exiting, on failure: sd_notifyf(0, "STATUS=Failed to start up: %s\n" "ERRNO=%i", strerror(errno), errno); See sd_notifyf(3) for more information. */ int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3); /* Returns > 0 if the system was booted with systemd. Returns < 0 on error. Returns 0 if the system was not booted with systemd. Note that all of the functions above handle non-systemd boots just fine. You should NOT protect them with a call to this function. Also note that this function checks whether the system, not the user session is controlled by systemd. However the functions above work for both user and system services. See sd_booted(3) for more information. */ int sd_booted(void); #ifdef __cplusplus } #endif #endif uptimed-0.4.2/src/uprecords.c000066400000000000000000000333631353126524100161370ustar00rootroot00000000000000/* uptimed - Copyright (c) 1998-2004 Rob Kaper 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; version 2 dated June, 1991. 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., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "../config.h" #include "uprecords.h" #ifdef HAVE_GETOPT_H #include #endif #define SYSWIDTH 24 #define DOWNWIDTH 20 #ifdef __ANDROID__ extern Urec *u_current; #else Urec *u_current; #endif time_t first, prev, tenth, second; int runas_cgi=0, show_max=10, show_milestone=0, layout=PRE, show_downtime=0, run_loop=0, update_interval=5; int sort_by=0, no_ansi=0, no_stats=0, no_current=0, wide_out=0; int main(int argc, char *argv[]) { /* Read config file. */ read_config(); /* Check if we are being run as CGI program. */ if (strstr(argv[0], ".cgi")) { runas_cgi=1; /* Print content-type header. */ printf("Content-type: text/html\n\n"); /* Read CGI config file. */ read_config_cgi(); } scan_args(argc, argv); #ifdef PLATFORM_HPUX no_ansi=1; #endif if (update_interval<1) update_interval=1; if (show_max<0) show_max=1; /* Print header file. */ if (runas_cgi) cat("/etc/uprecords-cgi/uprecords.header"); /* Read current uptime and entries from logfile. */ u_current=add_urec(read_uptime(), readbootid(), read_sysinfo()); read_records(u_current->btime); if (!runas_cgi && run_loop) { while(1) { /* Update current uptime. */ u_current->utime=read_uptime(); /* Current uptime might move up in the list. */ if ((prev && prev - u_current->utime < 0) || (first && first - u_current->utime < 0)) { moveup(); first=0; } displayrecords(1); sleep(update_interval); } } else displayrecords(0); /* Print footer file. */ if (runas_cgi) cat("/etc/uprecords-cgi/uprecords.footer"); return 0; } void displayrecords(int cls) { Urec *u, *uprev=NULL; time_t since, now, tmp, totalutime = 0, totaldtime = 0; float availability; int i=0, currentdone=0; now=time(0); /* Open output for CGI. */ if (runas_cgi) { if (layout==TABLE) printf("\n"); else if (layout==LIST) printf("
      \n"); else printf("
      \n");
      	}
      	/* Clear screen. */
      	else if (cls && !no_ansi)
      		printf(CLS);
      
      	if (layout==PRE)
      	{
      		if (!show_downtime) {
      			printf("   %3s%21s | %-*s %*s\n", "#", "Uptime", SYSWIDTH, "System", TIMEMAX, "Boot up");
      		} else {
      			printf("   %3s%21s | %*s %*s\n", "#", "Uptime", DOWNWIDTH, "Last downtime", DOWNTIMEMAXWIDTH, "Boot up");
      		}
      		print_line();
      	}
      	else if (runas_cgi && layout==TABLE)
      	{
      		printf("
    \n", "Position"); printf("\n", "Uptime"); if (!show_downtime) { printf("\n", "System"); } else { printf("\n", "Last downtime"); } printf("\n", "Boot up"); } urec_list = sort_urec(urec_list, sort_by); for ( u=urec_list; u ; u=u->next ) { if (++i<=show_max || show_max==0) { if (u==u_current) { if (!show_downtime) { print_entry(u->utime, u->sys, u->btime, "-> ", i, 1); } else { print_downtime_entry(u->utime, u->dtime, u->btime, "-> ", i, 1); } currentdone++; if (uprev) prev=uprev->utime; else { prev=0; first=0; tenth=0; second=0; } } else { if (!show_downtime) { print_entry(u->utime, u->sys, u->btime, " ", i, 0); } else { print_downtime_entry(u->utime, u->dtime, u->btime, " ", i, 0); } if (i==1) first=u->utime; if (i==2) second=u->utime; if (i==10) tenth=u->utime; } } else if (u==u_current) { if (uprev) prev=uprev->utime; break; } uprev=u; } if (runas_cgi && layout==LIST) { printf("\n"); printf("
      \n"); } if (!no_current && !currentdone) { if (layout==PRE) print_line(); print_entry(u_current->utime, u_current->sys, u_current->btime, "-> ", i, 1); if (uprev) prev=uprev->utime; } if (!no_stats) { if (layout==PRE) print_line(); if (prev && prev!=first) { tmp=now + prev - u_current->utime; print_entry(prev - u_current->utime + 1, "at", tmp, "1up in", 0, 0); } if (tenth && prev<=tenth && prev!=first) { tmp=now + tenth - u_current->utime; print_entry(tenth - u_current->utime + 1, "at", tmp, "t10 in", 0, 0); } if (first) { tmp=now + first - u_current->utime; print_entry(first - u_current->utime + 1, "at", tmp, "no1 in", 0, 0); } else { tmp=now + second - u_current->utime; print_entry(u_current->utime - second - 1, "since", tmp, "NewRec", 0, 0); } if (show_milestone) { Milestone *m; m = find_next_milestone(u_current->utime); if (m!=NULL) { tmp=now + m->time - u_current->utime; print_entry(m->time - u_current->utime + 1, m->desc, tmp, "mst in", 0, 0); } } /* Printing total uptime and downtime. */ for (u = urec_list; u; u = u->next){ if (u->dtime == 0) { since = u->btime; } totaldtime += u->dtime; totalutime += u->utime; } print_entry(totalutime, "since", since, "up", 0, 0); print_entry(totaldtime, "since", since, "down", 0, 0); /* Printing availability. */ availability = (float)totalutime / (float)(totalutime + totaldtime) * 100; print_availability(availability, since); } /* End output for CGI. */ if (runas_cgi) { if (layout==TABLE) printf("
    %s%s%s%s%s
    \n"); else if (layout==LIST) printf("\n"); else printf("\n"); printf("uptimed by Rob Kaper (rob@unixcode.org) - currently maintained by Radek Podgorny (radek@podgorny.cz)\n"); } } void read_config(void) { FILE *f; char str[256]; time_t milestone_time; char *milestone_str; f=fopen(FILE_CONFIG, "r"); if (!f) return; fgets(str, sizeof(str), f); while (!feof(f)) { if (!strncmp(str, "MILESTONE", 9)) { char *cp = strtok(str+10, ":"); milestone_time=scantime(cp); milestone_str=strtok(NULL, "\n"); add_milestone(milestone_time, milestone_str); } fgets(str, sizeof(str), f); } } void read_config_cgi(void) { FILE *f; char str[256]; f=fopen("/etc/uprecords-cgi/uprecords.conf", "r"); if (!f) return; fgets(str, sizeof(str), f); while(!feof(f)) { if (!strncmp(str, "LAYOUT", 6)) { if (!strncmp(str+7, "table", 5)) layout=TABLE; else if (!strncmp(str+7, "list", 4)) layout=LIST; else layout=PRE; } else if (!strncmp(str, "SHOW_MAX", 8)) show_max=atoi(str+9); else if (!strncmp(str, "TYPE", 4)) { if (!strncmp(str+5, "system", 6)) show_downtime = 0; else if (!strncmp(str+5, "downtime", 8)) show_downtime = 1; } fgets(str, sizeof(str), f); } fclose(f); } void print_entry(time_t utime, char *sys, time_t btime, char *ident, int pos, int hilite) { char *bold = BOLD, *plain = PLAIN, *current = ""; char *ctimec = NULL; if (runas_cgi) { bold = ""; plain = ""; if (hilite) current = " (current)"; if (!strcmp(ident, "-> ")) ident="-> "; if (layout!=PRE) { if (!strcmp(ident, "1up in")) ident="One up in"; else if (!strcmp(ident, "no1 in")) ident="Number one in"; } } if (!hilite || no_ansi) { bold = ""; plain = ""; } switch(layout) { case TABLE: printf("

    %s%d%s%s%s%s%s%s%s%s%s%s%s%s
    %s%d%s%s%s%s%s%s%s%s%s%s%s%s
    %s%.3fsince%s