├── COPYING ├── COPYRIGHT ├── README.md ├── examples ├── basicDB │ └── basicDB.ino └── psramDB │ └── psramDB.ino ├── flot └── LICENSE.txt ├── javascriptrrd └── LICENSE.txt ├── keywords.txt ├── library.properties └── src ├── fnv.h ├── get_ver.awk ├── gettext.h ├── hash_32.c ├── plbasename.c ├── plbasename.h ├── rrd.h ├── rrd_config.h ├── rrd_config_bottom.h ├── rrd_create.c ├── rrd_diff.c ├── rrd_dump.c ├── rrd_error.c ├── rrd_fetch.c ├── rrd_first.c ├── rrd_format.c ├── rrd_format.h ├── rrd_getopt.c ├── rrd_getopt.h ├── rrd_getopt1.c ├── rrd_hw.c ├── rrd_hw.h ├── rrd_hw_math.c ├── rrd_hw_math.h ├── rrd_hw_update.c ├── rrd_hw_update.h ├── rrd_i18n.h ├── rrd_info.c ├── rrd_is_thread_safe.h ├── rrd_last.c ├── rrd_lastupdate.c ├── rrd_nan_inf.c ├── rrd_open.c ├── rrd_parsetime.c ├── rrd_parsetime.h ├── rrd_resize.c ├── rrd_rpncalc.c ├── rrd_rpncalc.h ├── rrd_thread_safe.c ├── rrd_tool.c ├── rrd_tool.h ├── rrd_tune.c ├── rrd_update.c ├── rrd_version.c ├── rrd_xport.h ├── strftime.c ├── strftime.h └── unused.h /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for non-commercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | RRDTOOL - Round Robin Database Tool 2 | A tool for fast logging of numerical data graphical display 3 | of this data. 4 | 5 | Copyright (c) 1998-2008 Tobias Oetiker 6 | All rights reserved. 7 | 8 | GNU GPL License 9 | =============== 10 | 11 | This program is free software; you can redistribute it and/or modify it 12 | under the terms of the GNU General Public License as published by the Free 13 | Software Foundation; either version 2 of the License, or (at your option) 14 | any later version. 15 | 16 | This program is distributed in the hope that it will be useful, but WITHOUT 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | more details. 20 | 21 | You should have received a copy of the GNU General Public License along 22 | with this program; if not, write to the Free Software Foundation, Inc., 23 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 24 | 25 | FLOSS License Exception 26 | ======================= 27 | (Adapted from http://www.mysql.com/company/legal/licensing/foss-exception.html) 28 | 29 | I want specified Free/Libre and Open Source Software ("FLOSS") 30 | applications to be able to use specified GPL-licensed RRDtool 31 | libraries (the "Program") despite the fact that not all FLOSS licenses are 32 | compatible with version 2 of the GNU General Public License (the "GPL"). 33 | 34 | As a special exception to the terms and conditions of version 2.0 of the GPL: 35 | 36 | You are free to distribute a Derivative Work that is formed entirely from 37 | the Program and one or more works (each, a "FLOSS Work") licensed under one 38 | or more of the licenses listed below, as long as: 39 | 40 | 1. You obey the GPL in all respects for the Program and the Derivative 41 | Work, except for identifiable sections of the Derivative Work which are 42 | not derived from the Program, and which can reasonably be considered 43 | independent and separate works in themselves, 44 | 45 | 2. all identifiable sections of the Derivative Work which are not derived 46 | from the Program, and which can reasonably be considered independent and 47 | separate works in themselves, 48 | 49 | 1. are distributed subject to one of the FLOSS licenses listed 50 | below, and 51 | 52 | 2. the object code or executable form of those sections are 53 | accompanied by the complete corresponding machine-readable source 54 | code for those sections on the same medium and under the same FLOSS 55 | license as the corresponding object code or executable forms of 56 | those sections, and 57 | 58 | 3. any works which are aggregated with the Program or with a Derivative 59 | Work on a volume of a storage or distribution medium in accordance with 60 | the GPL, can reasonably be considered independent and separate works in 61 | themselves which are not derivatives of either the Program, a Derivative 62 | Work or a FLOSS Work. 63 | 64 | If the above conditions are not met, then the Program may only be copied, 65 | modified, distributed or used under the terms and conditions of the GPL. 66 | 67 | FLOSS License List 68 | ================== 69 | License name Version(s)/Copyright Date 70 | Academic Free License 2.0 71 | Apache Software License 1.0/1.1/2.0 72 | Apple Public Source License 2.0 73 | Artistic license From Perl 5.8.0 74 | BSD license "July 22 1999" 75 | Common Public License 1.0 76 | GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1 77 | IBM Public License, Version 1.0 78 | Jabber Open Source License 1.0 79 | MIT License (As listed in file MIT-License.txt) - 80 | Mozilla Public License (MPL) 1.0/1.1 81 | Open Software License 2.0 82 | OpenSSL license (with original SSLeay license) "2003" ("1998") 83 | PHP License 3.0 84 | Python license (CNRI Python License) - 85 | Python Software Foundation License 2.1.1 86 | Sleepycat License "1999" 87 | W3C License "2001" 88 | X11 License "2001" 89 | Zlib/libpng License - 90 | Zope Public License 2.0/2.1 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arduino RRD library 2 | =================== 3 | 4 | This is a port of the Round Robin Database Tool [rrdtool](https://oss.oetiker.ch/rrdtool/) to the ESP32 for use in simple web page delivery of graphs and data for IoT data sensors. 5 | 6 | The source library uses glib for graphics. ESP32 doesn't have a lot of core libraries needed for that, and doesn't really have the horsepower anyhow. Use [javascriptRRD](http://javascriptrrd.sourceforge.net/) to have the client present the data, delivering the raw rrd files. 7 | 8 | ## Notes on using rrdtool on ESP32 9 | 10 | 1) You must use FAT. rrdtool relies on seeking through a fixed data structure and replacing just the bits that have changed. The lseek on the other embedded filesystems (SPIFFS, LittleFS, etc) is not efficient enough to handle this, and your updates will never complete. 11 | 2) rrdtool is expecting posix-style vfs names. I recommend using vfs names and functions in all cases. 12 | 3) All the work you do in rrdtool is time based. If you don't have a synced time (eg you are not connected to the internet), your time will be very low. Since many defaults are relative (eg, the last update when you create an rrd), you can end up with negative times! This will cause things to crash and burn. 13 | 4) graph and xport require glib. I may at some point implement the needed pieces for that, but it ain't today. The only way to get your data out is directly as the rrd, or an xml dump. 14 | 5) I added a function rrd_create_str(const char\* CmdString)) to make it a bit easier to feed rrd_create. It tokenizes a single char array into the argv\*\* format of cli tools. 15 | 6) The larger your file is, the slower the seek. Keep It Simple, Stupid. One data source; keep it under 60k total. 16 | 7) I added a single global mutex to rrd_update. This means only one file can be written at a time. This should only be an issue if you are trying to do large, slow updates on multiple rrds. Don't do that. 17 | 18 | Thanks to Tobi Oetiker (http://www.oetiker.ch) for writing rrdtool 19 | Thanks to Frank Wuerthwein & Igor Sfiligoi (http://javascriptrrd.sourceforge.net) for javascriptRRD 20 | -------------------------------------------------------------------------------- /examples/basicDB/basicDB.ino: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * rrdtool example 3 | * (c)2020 Larry Bernstone 4 | * This example builds a couple sample databases (or uses existing files if uploaded). 5 | * It then sets up a webserver, which provides a sample webpage using javascriptRRD + flot 6 | * to display the data. You can also access /status, which provides the latest data in 7 | * json format. Internet access is necessary in order to sync network time. 8 | * Updates are entered into the database every minute through a ticker. 9 | ******************************************************************************************/ 10 | #include // rrdtool will not work on SPIFFS/LITTLEFS! 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define BUILD_TEST_DATA 17 | 18 | const char* myssid = "wifiname"; 19 | const char* mypasswd = "wifipassword"; 20 | const char ntpSrv[] = "pool.ntp.org"; 21 | 22 | const char* rrd_files[] = {"/ffat/rrd_0.rrd", "/ffat/rrd_1.rrd"}; // Must use full vfs path 23 | const char* rrd_0 = "-s60 -b1600000000 /ffat/rrd_0.rrd DS:bytesin:COUNTER:180:0:100000 RRA:AVERAGE:0.5:1:60 RRA:AVERAGE:0.5:10:2016 RRA:AVERAGE:0.5:360:2924"; 24 | const int argc = 10; 25 | const char* rrd_1[argc] = {"rrd_create", //Argv[0] will be ignored 26 | rrd_files[1], 27 | "--step", "60", //seconds 28 | "--start", "1600000000", // Sep 13, 2020 29 | "DS:wave:GAUGE:120:0:100", // range is 0-100, expected every 2 mins 30 | "RRA:AVERAGE:0.5:1:60", // 1 hour @ 1 minute 31 | "RRA:AVERAGE:0.5:10:2016", // 2 weeks @ 10 minutes 32 | "RRA:AVERAGE:0.5:360:2924" }; // 2 years @ 6 hours 33 | 34 | const char* indexHtml = R"rrdJ( 35 | 36 | 37 | RRD Example on ESP32 38 | 39 |

RRD Example on ESP32

40 | 41 | 42 |
Javascript needed for this page to work
43 |
44 |
45 |
46 | 56 | 57 | 58 | )rrdJ"; 59 | 60 | Ticker tkFillData; 61 | WebServer server(80); 62 | 63 | size_t lastStr(const char* rrdFile, String &returnStr, uint8_t ds=0) { 64 | char* argv[2] = {(char*)"a", (char*)rrdFile}; 65 | time_t last_update; 66 | unsigned long ds_cnt; 67 | char **ds_namv, **last_ds; 68 | if (rrd_lastupdate(2, (char**)&argv, &last_update, &ds_cnt, &ds_namv, &last_ds) == 0) { 69 | returnStr = "{\"data_store\":\"" + String(ds_namv[ds]); 70 | returnStr += "\",\"last_update\":" + String(last_update); 71 | returnStr += ",\"value\":" + String(last_ds[ds]) + "}"; 72 | for (int x=0; x now) c_time = now; 107 | counter0 += random(100000); 108 | filler0[y] = (char*) malloc(24); 109 | snprintf(filler0[y], 23, "%10u:%u", c_time, counter0); 110 | log_v("filler0[%d]: %s", x*chunk+y, filler0[y]); 111 | filler1[y] = (char*) malloc(18); 112 | snprintf(filler1[y], 17, "%10u:%5.2f", c_time, sin(c_time/600.0*2*M_PI)*50+50); 113 | log_v("filler1[%d]: %s", x*chunk+y, filler1[y]); 114 | } 115 | if (rrd_mask & 1) rrd_update_r(rrd_files[0], NULL, chunk, (const char**)&filler0); 116 | if (rrd_mask & 2) rrd_update_r(rrd_files[1], NULL, chunk, (const char**)&filler1); 117 | for (uint16_t y=0; y // https://github.com/tobozo/ESP32-PsRamFS/ 11 | #include // https://github.com/lorol/LITTLEFS 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define BUILD_TEST_DATA 18 | 19 | const char* myssid = "wifiname"; 20 | const char* mypasswd = "wifipassword"; 21 | const char ntpSrv[] = "pool.ntp.org"; 22 | 23 | const char* rrd_files[] = {"/psram/rrd_0.rrd", "/psram/rrd_1.rrd"}; // Must use full vfs path 24 | const char* backup_files[] = {"/littlefs/rrd_0.rrd", "/littlefs/rrd_1.rrd"}; 25 | const char* rrd_0 = "-s60 -b1600000000 /psram/rrd_0.rrd DS:bytesin:COUNTER:180:0:100000 RRA:AVERAGE:0.5:1:60 RRA:AVERAGE:0.5:10:2016 RRA:AVERAGE:0.5:360:2924"; 26 | const int argc = 10; 27 | const char* rrd_1[argc] = {"rrd_create", //Argv[0] will be ignored 28 | rrd_files[1], 29 | "--step", "60", //seconds 30 | "--start", "1600000000", // Sep 13, 2020 31 | "DS:wave:GAUGE:120:0:100", // range is 0-100, expected every 2 mins 32 | "RRA:AVERAGE:0.5:1:60", // 1 hour @ 1 minute 33 | "RRA:AVERAGE:0.5:10:2016", // 2 weeks @ 10 minutes 34 | "RRA:AVERAGE:0.5:360:2924" }; // 2 years @ 6 hours 35 | 36 | const char* indexHtml = R"rrdJ( 37 | 38 | 39 | RRD Example on ESP32 40 | 41 |

RRD Example on ESP32

42 | 43 | 44 |
Javascript needed for this page to work
45 |
46 |
47 |
48 | 58 | 59 | 60 | )rrdJ"; 61 | 62 | Ticker tkFillData; 63 | WebServer server(80); 64 | 65 | size_t lastStr(const char* rrdFile, String &returnStr, uint8_t ds=0) { 66 | char* argv[2] = {(char*)"a", (char*)rrdFile}; 67 | time_t last_update; 68 | unsigned long ds_cnt; 69 | char **ds_namv, **last_ds; 70 | if (rrd_lastupdate(2, (char**)&argv, &last_update, &ds_cnt, &ds_namv, &last_ds) == 0) { 71 | returnStr = "{\"data_store\":\"" + String(ds_namv[ds]); 72 | returnStr += "\",\"last_update\":" + String(last_update); 73 | returnStr += ",\"value\":" + String(last_ds[ds]) + "}"; 74 | for (int x=0; x now) c_time = now; 128 | counter0 += random(100000); 129 | filler0[y] = (char*) malloc(24); 130 | snprintf(filler0[y], 23, "%10u:%u", c_time, counter0); 131 | log_v("filler0[%d]: %s", x*chunk+y, filler0[y]); 132 | filler1[y] = (char*) malloc(18); 133 | snprintf(filler1[y], 17, "%10u:%5.2f", c_time, sin(c_time/600.0*2*M_PI)*50+50); 134 | log_v("filler1[%d]: %s", x*chunk+y, filler1[y]); 135 | } 136 | if (rrd_mask & 1) rrd_update_r(rrd_files[0], NULL, chunk, (const char**)&filler0); 137 | if (rrd_mask & 2) rrd_update_r(rrd_files[1], NULL, chunk, (const char**)&filler1); 138 | for (uint16_t y=0; y /\oo/\ 65 | * http://reality.sgi.com/chongo/ 66 | * EMail: chongo_fnv at prime dot engr dot sgi dot com 67 | * 68 | * Share and Enjoy! :-) 69 | */ 70 | 71 | #if !defined(__FNV_H__) 72 | #define __FNV_H__ 73 | 74 | 75 | /* 76 | * 32 bit FNV-0 hash type 77 | */ 78 | typedef unsigned long Fnv32_t; 79 | 80 | 81 | /* 82 | * 32 bit FNV-0 zero initial basis 83 | * 84 | * This historic hash is not recommended. One should use 85 | * the FNV-1 hash and inital basis instead. 86 | */ 87 | #define FNV0_32_INIT ((Fnv32_t)0) 88 | 89 | 90 | /* 91 | * 32 bit FNV-1 non-zero initial basis 92 | * 93 | * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: 94 | * 95 | * chongo /\../\ 96 | * 97 | * Note that the \'s above are not back-slashing escape characters. 98 | * They are literal ASCII backslash 0x5c characters. 99 | */ 100 | #define FNV1_32_INIT ((Fnv32_t)0x811c9dc5) 101 | 102 | Fnv32_t fnv_32_buf( 103 | const void *, 104 | size_t, 105 | Fnv32_t); 106 | 107 | Fnv32_t fnv_32_str( 108 | const char *, 109 | Fnv32_t); 110 | 111 | unsigned long FnvHash( 112 | const char *); 113 | 114 | #endif /* __FNV_H__ */ 115 | -------------------------------------------------------------------------------- /src/get_ver.awk: -------------------------------------------------------------------------------- 1 | # **************************************************************************** 2 | # RRDtool 1.2.19 Copyright by Tobi Oetiker, 1997-2007 3 | # **************************************************************************** 4 | # get_ver.awk AWK Script for non-configure builds 5 | # **************************************************************************** 6 | # $Id: get_ver.awk 1000 2007-14-02 05:51:34Z oetiker $ 7 | # **************************************************************************** 8 | BEGIN { 9 | # fetch rrdtool version number from input file and write them to STDOUT 10 | while ((getline < ARGV[1]) > 0) { 11 | if (match ($0, /^AC_INIT/)) { 12 | split($1, t, ","); 13 | my_ver_str = substr(t[2],2,length(t[2])-3); 14 | split(my_ver_str, v, "."); 15 | gsub("[^0-9].*$", "", v[3]); 16 | my_ver = v[1] "," v[2] "," v[3]; 17 | } 18 | if (match ($0, /^NUMVERS=/)) { 19 | split($1, t, "="); 20 | my_ver_num = t[2]; 21 | } 22 | } 23 | # read from from input file, replace placeholders, and write to STDOUT 24 | if (ARGV[2]) { 25 | while ((getline < ARGV[2]) > 0) { 26 | if (match ($0, /@@NUMVERS@@/)) { 27 | gsub("@@NUMVERS@@", my_ver_num, $0); 28 | } 29 | if (match ($0, /@@PACKAGE_VERSION@@/)) { 30 | gsub("@@PACKAGE_VERSION@@", "" my_ver_str "", $0); 31 | } 32 | print; 33 | } 34 | } else { 35 | print "RRD_VERSION = " my_ver ""; 36 | print "RRD_VERSION_STR = " my_ver_str ""; 37 | print "RRD_NUMVERS = " my_ver_num ""; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/gettext.h: -------------------------------------------------------------------------------- 1 | /* Convenience header for conditional use of GNU . 2 | Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU General Public License as published 6 | by the Free Software Foundation; either version 2, or (at your option) 7 | any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Library General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public 15 | License along with this program; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | USA. */ 18 | 19 | #ifndef _LIBGETTEXT_H 20 | #define _LIBGETTEXT_H 1 21 | 22 | /* NLS can be disabled through the configure --disable-nls option. */ 23 | #if ENABLE_NLS 24 | 25 | /* Get declarations of GNU message catalog functions. */ 26 | # include 27 | 28 | /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by 29 | the gettext() and ngettext() macros. This is an alternative to calling 30 | textdomain(), and is useful for libraries. */ 31 | # ifdef DEFAULT_TEXT_DOMAIN 32 | # undef gettext 33 | # define gettext(Msgid) \ 34 | dgettext (DEFAULT_TEXT_DOMAIN, Msgid) 35 | # undef ngettext 36 | # define ngettext(Msgid1, Msgid2, N) \ 37 | dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) 38 | # endif 39 | 40 | #else 41 | 42 | /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which 43 | chokes if dcgettext is defined as a macro. So include it now, to make 44 | later inclusions of a NOP. We don't include 45 | as well because people using "gettext.h" will not include , 46 | and also including would fail on SunOS 4, whereas 47 | is OK. */ 48 | #if defined(__sun) 49 | # include 50 | #endif 51 | 52 | /* Many header files from the libstdc++ coming with g++ 3.3 or newer include 53 | , which chokes if dcgettext is defined as a macro. So include 54 | it now, to make later inclusions of a NOP. */ 55 | #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) 56 | # include 57 | # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H 58 | # include 59 | # endif 60 | #endif 61 | 62 | /* Disabled NLS. 63 | The casts to 'const char *' serve the purpose of producing warnings 64 | for invalid uses of the value returned from these functions. 65 | On pre-ANSI systems without 'const', the config.h file is supposed to 66 | contain "#define const". */ 67 | # define gettext(Msgid) ((const char *) (Msgid)) 68 | # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) 69 | # define dcgettext(Domainname, Msgid, Category) \ 70 | ((void) (Category), dgettext (Domainname, Msgid)) 71 | # define ngettext(Msgid1, Msgid2, N) \ 72 | ((N) == 1 \ 73 | ? ((void) (Msgid2), (const char *) (Msgid1)) \ 74 | : ((void) (Msgid1), (const char *) (Msgid2))) 75 | # define dngettext(Domainname, Msgid1, Msgid2, N) \ 76 | ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) 77 | # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ 78 | ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) 79 | # define textdomain(Domainname) ((const char *) (Domainname)) 80 | # define bindtextdomain(Domainname, Dirname) \ 81 | ((void) (Domainname), (const char *) (Dirname)) 82 | # define bind_textdomain_codeset(Domainname, Codeset) \ 83 | ((void) (Domainname), (const char *) (Codeset)) 84 | 85 | #endif 86 | 87 | /* A pseudo function call that serves as a marker for the automated 88 | extraction of messages, but does not call gettext(). The run-time 89 | translation is done at a different place in the code. 90 | The argument, String, should be a literal string. Concatenated strings 91 | and other string expressions won't work. 92 | The macro's expansion is not parenthesized, so that it is suitable as 93 | initializer for static 'char[]' or 'const char[]' variables. */ 94 | #define gettext_noop(String) String 95 | 96 | /* The separator between msgctxt and msgid in a .mo file. */ 97 | #define GETTEXT_CONTEXT_GLUE "\004" 98 | 99 | /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a 100 | MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be 101 | short and rarely need to change. 102 | The letter 'p' stands for 'particular' or 'special'. */ 103 | #ifdef DEFAULT_TEXT_DOMAIN 104 | # define pgettext(Msgctxt, Msgid) \ 105 | pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 106 | #else 107 | # define pgettext(Msgctxt, Msgid) \ 108 | pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 109 | #endif 110 | #define dpgettext(Domainname, Msgctxt, Msgid) \ 111 | pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 112 | #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ 113 | pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) 114 | #ifdef DEFAULT_TEXT_DOMAIN 115 | # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ 116 | npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) 117 | #else 118 | # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ 119 | npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) 120 | #endif 121 | #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ 122 | npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) 123 | #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ 124 | npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) 125 | 126 | #ifdef __GNUC__ 127 | __inline 128 | #else 129 | #ifdef __cplusplus 130 | inline 131 | #endif 132 | #endif 133 | static const char * 134 | pgettext_aux (const char *domain, 135 | const char *msg_ctxt_id, const char *msgid, 136 | int category) 137 | { 138 | const char *translation = dcgettext (domain, msg_ctxt_id, category); 139 | if (translation == msg_ctxt_id) 140 | return msgid; 141 | else 142 | return translation; 143 | } 144 | 145 | #ifdef __GNUC__ 146 | __inline 147 | #else 148 | #ifdef __cplusplus 149 | inline 150 | #endif 151 | #endif 152 | static const char * 153 | npgettext_aux (const char *domain, 154 | const char *msg_ctxt_id, const char *msgid, 155 | const char *msgid_plural, unsigned long int n, 156 | int category) 157 | { 158 | const char *translation = 159 | dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); 160 | if (translation == msg_ctxt_id || translation == msgid_plural) 161 | return (n == 1 ? msgid : msgid_plural); 162 | else 163 | return translation; 164 | } 165 | 166 | /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID 167 | can be arbitrary expressions. But for string literals these macros are 168 | less efficient than those above. */ 169 | 170 | #include 171 | 172 | #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ 173 | (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ 174 | /* || __STDC_VERSION__ >= 199901L */ ) 175 | 176 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 177 | #include 178 | #endif 179 | 180 | #define pgettext_expr(Msgctxt, Msgid) \ 181 | dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) 182 | #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ 183 | dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) 184 | 185 | #ifdef __GNUC__ 186 | __inline 187 | #else 188 | #ifdef __cplusplus 189 | inline 190 | #endif 191 | #endif 192 | static const char * 193 | dcpgettext_expr (const char *domain, 194 | const char *msgctxt, const char *msgid, 195 | int category) 196 | { 197 | size_t msgctxt_len = strlen (msgctxt) + 1; 198 | size_t msgid_len = strlen (msgid) + 1; 199 | const char *translation; 200 | #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 201 | char msg_ctxt_id[msgctxt_len + msgid_len]; 202 | #else 203 | char buf[1024]; 204 | char *msg_ctxt_id = 205 | (msgctxt_len + msgid_len <= sizeof (buf) 206 | ? buf 207 | : (char *) malloc (msgctxt_len + msgid_len)); 208 | if (msg_ctxt_id != NULL) 209 | #endif 210 | { 211 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); 212 | msg_ctxt_id[msgctxt_len - 1] = '\004'; 213 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); 214 | translation = dcgettext (domain, msg_ctxt_id, category); 215 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 216 | if (msg_ctxt_id != buf) 217 | free (msg_ctxt_id); 218 | #endif 219 | if (translation != msg_ctxt_id) 220 | return translation; 221 | } 222 | return msgid; 223 | } 224 | 225 | #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ 226 | dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) 227 | #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ 228 | dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) 229 | 230 | #ifdef __GNUC__ 231 | __inline 232 | #else 233 | #ifdef __cplusplus 234 | inline 235 | #endif 236 | #endif 237 | static const char * 238 | dcnpgettext_expr (const char *domain, 239 | const char *msgctxt, const char *msgid, 240 | const char *msgid_plural, unsigned long int n, 241 | int category) 242 | { 243 | size_t msgctxt_len = strlen (msgctxt) + 1; 244 | size_t msgid_len = strlen (msgid) + 1; 245 | const char *translation; 246 | #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 247 | char msg_ctxt_id[msgctxt_len + msgid_len]; 248 | #else 249 | char buf[1024]; 250 | char *msg_ctxt_id = 251 | (msgctxt_len + msgid_len <= sizeof (buf) 252 | ? buf 253 | : (char *) malloc (msgctxt_len + msgid_len)); 254 | if (msg_ctxt_id != NULL) 255 | #endif 256 | { 257 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); 258 | msg_ctxt_id[msgctxt_len - 1] = '\004'; 259 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); 260 | translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); 261 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 262 | if (msg_ctxt_id != buf) 263 | free (msg_ctxt_id); 264 | #endif 265 | if (!(translation == msg_ctxt_id || translation == msgid_plural)) 266 | return translation; 267 | } 268 | return (n == 1 ? msgid : msgid_plural); 269 | } 270 | 271 | #endif /* _LIBGETTEXT_H */ 272 | -------------------------------------------------------------------------------- /src/hash_32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * hash_32 - 32 bit Fowler/Noll/Vo hash code 3 | * 4 | * 5 | *** 6 | * 7 | * Fowler/Noll/Vo hash 8 | * 9 | * The basis of this hash algorithm was taken from an idea sent 10 | * as reviewer comments to the IEEE POSIX P1003.2 committee by: 11 | * 12 | * Phong Vo (http://www.research.att.com/info/kpv/) 13 | * Glenn Fowler (http://www.research.att.com/~gsf/) 14 | * 15 | * In a subsequent ballot round: 16 | * 17 | * Landon Curt Noll (http://reality.sgi.com/chongo/) 18 | * 19 | * improved on their algorithm. Some people tried this hash 20 | * and found that it worked rather well. In an EMail message 21 | * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. 22 | * 23 | * FNV hashes are architected to be fast while maintaining a low 24 | * collision rate. The FNV speed allows one to quickly hash lots 25 | * of data while maintaining a reasonable collision rate. See: 26 | * 27 | * http://reality.sgi.com/chongo/tech/comp/fnv/ 28 | * 29 | * for more details as well as other forms of the FNV hash. 30 | *** 31 | * 32 | * NOTE: The FNV-0 historic hash is not recommended. One should use 33 | * the FNV-1 hash instead. 34 | * 35 | * To use the 32 bit FNV-0 historic hash, pass FNV0_32_INIT as the 36 | * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str(). 37 | * 38 | * To use the recommended 32 bit FNV-1 hash, pass FNV1_32_INIT as the 39 | * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str(). 40 | * 41 | *** 42 | * 43 | * Please do not copyright this code. This code is in the public domain. 44 | * 45 | * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 46 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 47 | * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR 48 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 49 | * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 50 | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 51 | * PERFORMANCE OF THIS SOFTWARE. 52 | * 53 | * By: 54 | * chongo /\oo/\ 55 | * http://reality.sgi.com/chongo/ 56 | * EMail: chongo_fnv at prime dot engr dot sgi dot com 57 | * 58 | * Share and Enjoy! :-) 59 | */ 60 | 61 | #include 62 | #include "fnv.h" 63 | 64 | 65 | /* 66 | * 32 bit magic FNV-0 and FNV-1 prime 67 | */ 68 | #define FNV_32_PRIME ((Fnv32_t)0x01000193) 69 | 70 | 71 | /* 72 | * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer 73 | * 74 | * input: 75 | * buf - start of buffer to hash 76 | * len - length of buffer in octets 77 | * hval - previous hash value or 0 if first call 78 | * 79 | * returns: 80 | * 32 bit hash as a static hash type 81 | * 82 | * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hval 83 | * argument on the first call to either fnv_32_buf() or fnv_32_str(). 84 | * 85 | * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval 86 | * argument on the first call to either fnv_32_buf() or fnv_32_str(). 87 | */ 88 | Fnv32_t fnv_32_buf( 89 | const void *buf, 90 | size_t len, 91 | Fnv32_t hval) 92 | { 93 | const unsigned char *bp = (const unsigned char *) buf; /* start of buffer */ 94 | const unsigned char *be = bp + len; /* beyond end of buffer */ 95 | 96 | /* 97 | * FNV-1 hash each octet in the buffer 98 | */ 99 | while (bp < be) { 100 | 101 | /* multiply by the 32 bit FNV magic prime mod 2^64 */ 102 | hval *= FNV_32_PRIME; 103 | 104 | /* xor the bottom with the current octet */ 105 | hval ^= (Fnv32_t) *bp++; 106 | } 107 | 108 | /* return our new hash value */ 109 | return hval; 110 | } 111 | 112 | 113 | /* 114 | * fnv_32_str - perform a 32 bit Fowler/Noll/Vo hash on a string 115 | * 116 | * input: 117 | * str - string to hash 118 | * hval - previous hash value or 0 if first call 119 | * 120 | * returns: 121 | * 32 bit hash as a static hash type 122 | * 123 | * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hval 124 | * argument on the first call to either fnv_32_buf() or fnv_32_str(). 125 | * 126 | * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval 127 | * argument on the first call to either fnv_32_buf() or fnv_32_str(). 128 | */ 129 | Fnv32_t fnv_32_str( 130 | const char *str, 131 | Fnv32_t hval) 132 | { 133 | const unsigned char *s = (const unsigned char *) str; /* unsigned string */ 134 | 135 | /* 136 | * FNV-1 hash each octet in the buffer 137 | */ 138 | while (*s) { 139 | 140 | /* multiply by the 32 bit FNV magic prime mod 2^64 */ 141 | hval *= FNV_32_PRIME; 142 | 143 | /* xor the bottom with the current octet */ 144 | hval ^= (Fnv32_t) *s++; 145 | } 146 | 147 | /* return our new hash value */ 148 | return hval; 149 | } 150 | 151 | /* a wrapper function for fnv_32_str */ 152 | unsigned long FnvHash( 153 | const char *str) 154 | { 155 | return fnv_32_str(str, FNV1_32_INIT); 156 | } 157 | -------------------------------------------------------------------------------- /src/plbasename.c: -------------------------------------------------------------------------------- 1 | #ifdef WIN32 2 | /* 3 | * 4 | * Cross-platform basename/dirname 5 | * 6 | * Copyright 2005 Syd Logan, All Rights Reserved 7 | * 8 | * This code is distributed without warranty. You are free to use this 9 | * code for any purpose, however, if this code is republished or 10 | * redistributed in its original form, as hardcopy or electronically, 11 | * then you must include this copyright notice along with the code. 12 | * 13 | */ 14 | 15 | // minor changes 2008 by Stefan Ludewig stefan.ludewig@exitgames.com for WIN32 version RRDtool 16 | 17 | #include 18 | #include 19 | #include "plbasename.h" 20 | #include 21 | #if defined(TEST) 22 | #include 23 | #endif 24 | 25 | #if defined(__cplusplus) 26 | 27 | extern "C" { 28 | 29 | #endif 30 | 31 | const char * 32 | PL_basename(const char *name) 33 | { 34 | const char *base; 35 | char *p; 36 | static char *tmp = NULL; 37 | int len; 38 | 39 | if (tmp) { 40 | free(tmp); 41 | tmp = NULL; 42 | } 43 | 44 | if (!name || !strcmp(name, "")) 45 | return ""; 46 | 47 | if (!strcmp(name, "/")) 48 | return "/"; 49 | 50 | len = strlen(name); 51 | if (name[len - 1] == '/') { 52 | // ditch the trailing '/' 53 | p = tmp = (char*)malloc(len); 54 | strncpy(p, name, len - 1); 55 | } else { 56 | p = (char *) name; 57 | } 58 | 59 | for (base = p; *p; p++) 60 | if (*p == '/') 61 | base = p + 1; 62 | 63 | return base; 64 | } 65 | 66 | const char * 67 | PL_dirname(const char *name) 68 | { 69 | static char *ret = NULL; 70 | int len; 71 | int size = 0; 72 | const char *p; 73 | 74 | if (ret) { 75 | free(ret); 76 | ret = NULL; 77 | } 78 | 79 | if (!name || !strcmp(name, "") || !strstr(name, "/")) 80 | return("."); 81 | 82 | if (!strcmp(name, "/")) 83 | return(name); 84 | 85 | // find the last slash in the string 86 | 87 | len = strlen(name); 88 | p = &name[len - 1]; 89 | 90 | if (*p == '/') p--; // skip the trailing / 91 | 92 | while (p != name && *p != '/') p--; 93 | 94 | size = p - name; 95 | if (size) { 96 | ret = (char*)malloc(size + 1); 97 | memcpy(ret, name, size); 98 | ret[size] = '\0'; 99 | } else if (*p == '/') 100 | return "/"; 101 | else 102 | return ""; 103 | 104 | return (const char *) ret; 105 | } 106 | 107 | #if defined(__cplusplus) 108 | 109 | } 110 | 111 | #endif 112 | 113 | #if defined(TEST) 114 | 115 | int 116 | main(int argc, char *argv[]) 117 | { 118 | /* run the following tests: 119 | 120 | path dirname basename 121 | "/usr/lib" "/usr" "lib" 122 | "/usr/" "/" "usr" 123 | "usr" "." "usr" 124 | "/" "/" "/" 125 | "." "." "." 126 | ".." "." ".." 127 | NULL "." "" 128 | "" "." "" 129 | "./.." "." ".." 130 | 131 | These results can be verified by running the unix commands 132 | basename(1) and dirname(1). One tweek to the test strategy 133 | used here would be, on darwin and linux, to shell out to 134 | get the expected results vs hardcoding. 135 | */ 136 | if (!strcmp(PL_basename("/usr/lib"), "lib")) 137 | printf("PL_basename /usr/lib passed\n"); 138 | else 139 | printf("PL_basename /usr/lib failed expected lib\n"); 140 | if (!strcmp(PL_dirname("/usr/lib"), "/usr")) 141 | printf("PL_dirname /usr/lib passed\n"); 142 | else 143 | printf("PL_dirname /usr/lib failed expected /usr\n"); 144 | if (!strcmp(PL_basename("/usr/"), "usr")) 145 | printf("PL_basename /usr/ passed\n"); 146 | else 147 | printf("PL_basename /usr/ failed expected usr\n"); 148 | if (!strcmp(PL_dirname("/usr/"), "/")) 149 | printf("PL_dirname /usr/ passed\n"); 150 | else 151 | printf("PL_dirname /usr/ failed expected /\n"); 152 | if (!strcmp(PL_basename("usr"), "usr")) 153 | printf("PL_basename usr passed\n"); 154 | else 155 | printf("PL_basename usr failed expected usr\n"); 156 | if (!strcmp(PL_dirname("usr"), ".")) 157 | printf("PL_dirname usr passed\n"); 158 | else 159 | printf("PL_dirname usr failed expected .\n"); 160 | if (!strcmp(PL_basename("/"), "/")) 161 | printf("PL_basename / passed\n"); 162 | else 163 | printf("PL_basename / failed expected /\n"); 164 | if (!strcmp(PL_dirname("/"), "/")) 165 | printf("PL_dirname / passed\n"); 166 | else 167 | printf("PL_dirname / failed expected /\n"); 168 | if (!strcmp(PL_basename("."), ".")) 169 | printf("PL_basename . passed\n"); 170 | else 171 | printf("PL_basename . failed\n"); 172 | if (!strcmp(PL_dirname("."), ".")) 173 | printf("PL_dirname . passed\n"); 174 | else 175 | printf("PL_dirname . failed expected .\n"); 176 | if (!strcmp(PL_basename(".."), "..")) 177 | printf("PL_basename .. passed\n"); 178 | else 179 | printf("PL_basename .. failed expected ..\n"); 180 | if (!strcmp(PL_dirname(".."), ".")) 181 | printf("PL_dirname .. passed\n"); 182 | else 183 | printf("PL_dirname .. failed expected .\n"); 184 | if (!strcmp(PL_basename(NULL), "")) 185 | printf("PL_basename NULL passed\n"); 186 | else 187 | printf("PL_basename NULL failed expected \"\"\n"); 188 | if (!strcmp(PL_dirname(NULL), ".")) 189 | printf("PL_dirname NULL passed\n"); 190 | else 191 | printf("PL_dirname NULL failed expected .\n"); 192 | if (!strcmp(PL_basename(""), "")) 193 | printf("PL_basename \"\" passed\n"); 194 | else 195 | printf("PL_basename \"\" failed expected \"\"\n"); 196 | if (!strcmp(PL_dirname(""), ".")) 197 | printf("PL_dirname \"\" passed\n"); 198 | else 199 | printf("PL_dirname \"\" failed expected .\n"); 200 | 201 | if (!strcmp(PL_basename("./.."), "..")) 202 | printf("PL_basename ./.. passed\n"); 203 | else 204 | printf("PL_basename ./.. failed expected ..\n"); 205 | if (!strcmp(PL_dirname("./.."), ".")) 206 | printf("PL_dirname ./.. passed\n"); 207 | else 208 | printf("PL_dirname ./.. failed expected .\n"); 209 | } 210 | #endif 211 | #endif // WIN32 212 | -------------------------------------------------------------------------------- /src/plbasename.h: -------------------------------------------------------------------------------- 1 | #ifdef WIN32 2 | /* 3 | * 4 | * Cross-platform basename/dirname 5 | * 6 | * Copyright 2005 Syd Logan, All Rights Reserved 7 | * 8 | * This code is distributed without warranty. You are free to use this 9 | * code for any purpose, however, if this code is republished or 10 | * redistributed in its original form, as hardcopy or electronically, 11 | * then you must include this copyright notice along with the code. 12 | * 13 | */ 14 | 15 | // minor changes 2008 by Stefan Ludewig stefan.ludewig@exitgames.com for WIN32 version RRDtool 16 | 17 | #if !defined(__PL_BASENAME_H__) 18 | #define __PL_BASENAME_H__ 19 | 20 | /* 21 | path dirname basename 22 | "/usr/lib" "/usr" "lib" 23 | "/usr/" "/" "usr" 24 | "usr" "." "usr" 25 | "/" "/" "/" 26 | "." "." "." 27 | ".." "." ".." 28 | */ 29 | 30 | #if defined(__cplusplus) 31 | extern "C" { 32 | #endif 33 | 34 | const char *PL_basename(const char *name); 35 | const char *PL_dirname(const char *name); 36 | 37 | #define basename(name) ((char*)PL_basename(name)) 38 | #define dirname(name) ((char*)PL_dirname(name)) 39 | 40 | #if defined(__cplusplus) 41 | } 42 | #endif 43 | 44 | #endif 45 | #endif // WIN32 46 | -------------------------------------------------------------------------------- /src/rrd.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrdlib.h Public header file for librrd 5 | ***************************************************************************** 6 | * $Id: rrd.h 1946 2009-10-24 10:46:42Z oetiker $ 7 | * $Log$ 8 | * Revision 1.9 2005/02/13 16:13:33 oetiker 9 | * let rrd_graph return the actual value range it picked ... 10 | * -- Henrik Stoerner 11 | * 12 | * Revision 1.8 2004/05/26 22:11:12 oetiker 13 | * reduce compiler warnings. Many small fixes. -- Mike Slifcak 14 | * 15 | * Revision 1.7 2003/11/12 22:14:26 oetiker 16 | * allow to pass an open filehandle into rrd_graph as an extra argument 17 | * 18 | * Revision 1.6 2003/11/11 19:46:21 oetiker 19 | * replaced time_value with rrd_time_value as MacOS X introduced a struct of that name in their standard headers 20 | * 21 | * Revision 1.5 2003/04/25 18:35:08 jake 22 | * Alternate update interface, updatev. Returns info about CDPs written to disk as result of update. Output format is similar to rrd_info, a hash of key-values. 23 | * 24 | * Revision 1.4 2003/04/01 22:52:23 jake 25 | * Fix Win32 build. VC++ 6.0 and 7.0 now use the thread-safe code. 26 | * 27 | * Revision 1.3 2003/02/13 07:05:27 oetiker 28 | * Find attached the patch I promised to send to you. Please note that there 29 | * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c 30 | * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This 31 | * library is identical to librrd, but it contains support code for per-thread 32 | * global variables currently used for error information only. This is similar 33 | * to how errno per-thread variables are implemented. librrd_th must be linked 34 | * alongside of libpthred 35 | * 36 | * There is also a new file "THREADS", holding some documentation. 37 | * 38 | * -- Peter Stamfest 39 | * 40 | * Revision 1.2 2002/05/07 21:58:32 oetiker 41 | * new command rrdtool xport integrated 42 | * -- Wolfgang Schrimm 43 | * 44 | * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker 45 | * checkin 46 | * 47 | *****************************************************************************/ 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | #ifndef _RRDLIB_H 53 | #define _RRDLIB_H 54 | 55 | #include /* for off_t */ 56 | 57 | #ifndef WIN32 58 | #include /* for off_t */ 59 | #else 60 | #include 61 | typedef size_t ssize_t; 62 | typedef long off_t; 63 | #endif 64 | 65 | #include 66 | #include /* for FILE */ 67 | 68 | 69 | /* Formerly rrd_nan_inf.h */ 70 | #ifndef DNAN 71 | # define DNAN rrd_set_to_DNAN() 72 | #endif 73 | 74 | #ifndef DINF 75 | # define DINF rrd_set_to_DINF() 76 | #endif 77 | double rrd_set_to_DNAN( 78 | void); 79 | double rrd_set_to_DINF( 80 | void); 81 | /* end of rrd_nan_inf.h */ 82 | 83 | /* Transplanted from rrd_format.h */ 84 | typedef double rrd_value_t; /* the data storage type is 85 | * double */ 86 | /* END rrd_format.h */ 87 | 88 | /* information about an rrd file */ 89 | typedef struct rrd_file_t { 90 | int fd; /* file descriptor if this rrd file */ 91 | char *file_start; /* start address of an open rrd file */ 92 | off_t header_len; /* length of the header of this rrd file */ 93 | off_t file_len; /* total size of the rrd file */ 94 | off_t pos; /* current pos in file */ 95 | } rrd_file_t; 96 | 97 | /* rrd info interface */ 98 | typedef struct rrd_blob_t { 99 | unsigned long size; /* size of the blob */ 100 | unsigned char *ptr; /* pointer */ 101 | } rrd_blob_t; 102 | 103 | typedef enum rrd_info_type { RD_I_VAL = 0, 104 | RD_I_CNT, 105 | RD_I_STR, 106 | RD_I_INT, 107 | RD_I_BLO 108 | } rrd_info_type_t; 109 | 110 | typedef union rrd_infoval { 111 | unsigned long u_cnt; 112 | rrd_value_t u_val; 113 | char *u_str; 114 | int u_int; 115 | rrd_blob_t u_blo; 116 | } rrd_infoval_t; 117 | 118 | typedef struct rrd_info_t { 119 | char *key; 120 | rrd_info_type_t type; 121 | rrd_infoval_t value; 122 | struct rrd_info_t *next; 123 | } rrd_info_t; 124 | 125 | 126 | /* main function blocks */ 127 | int rrd_create( 128 | int, 129 | char **); 130 | rrd_info_t *rrd_info( 131 | int, 132 | char **); 133 | rrd_info_t *rrd_info_push( 134 | rrd_info_t *, 135 | char *, 136 | rrd_info_type_t, 137 | rrd_infoval_t); 138 | void rrd_info_print( 139 | rrd_info_t * data); 140 | void rrd_info_free( 141 | rrd_info_t *); 142 | int rrd_update( 143 | int, 144 | char **); 145 | rrd_info_t *rrd_update_v( 146 | int, 147 | char **); 148 | int rrd_graph( 149 | int, 150 | char **, 151 | char ***, 152 | int *, 153 | int *, 154 | FILE *, 155 | double *, 156 | double *); 157 | rrd_info_t *rrd_graph_v( 158 | int, 159 | char **); 160 | 161 | int rrd_fetch( 162 | int, 163 | char **, 164 | time_t *, 165 | time_t *, 166 | unsigned long *, 167 | unsigned long *, 168 | char ***, 169 | rrd_value_t **); 170 | int rrd_restore( 171 | int, 172 | char **); 173 | int rrd_dump( 174 | int, 175 | char **); 176 | int rrd_tune( 177 | int, 178 | char **); 179 | time_t rrd_last( 180 | int, 181 | char **); 182 | int rrd_lastupdate( 183 | int argc, 184 | char **argv, 185 | time_t *last_update, 186 | unsigned long *ds_cnt, 187 | char ***ds_namv, 188 | char ***last_ds); 189 | time_t rrd_first( 190 | int, 191 | char **); 192 | int rrd_resize( 193 | int, 194 | char **); 195 | char *rrd_strversion( 196 | void); 197 | double rrd_version( 198 | void); 199 | int rrd_xport( 200 | int, 201 | char **, 202 | int *, 203 | time_t *, 204 | time_t *, 205 | unsigned long *, 206 | unsigned long *, 207 | char ***, 208 | rrd_value_t **); 209 | 210 | void rrd_freemem( 211 | void *mem); 212 | 213 | /* thread-safe (hopefully) */ 214 | int rrd_create_r( 215 | const char *filename, 216 | unsigned long pdp_step, 217 | time_t last_up, 218 | int argc, 219 | const char **argv); 220 | int rrd_create_str( 221 | const char *cmdString); 222 | /* NOTE: rrd_update_r are only thread-safe if no at-style time 223 | specifications get used!!! */ 224 | 225 | int rrd_update_r( 226 | const char *filename, 227 | const char *_template, 228 | int argc, 229 | const char **argv); 230 | int rrd_fetch_r( 231 | const char *filename, 232 | const char *cf, 233 | time_t *start, 234 | time_t *end, 235 | unsigned long *step, 236 | unsigned long *ds_cnt, 237 | char ***ds_namv, 238 | rrd_value_t **data); 239 | int rrd_dump_r( 240 | const char *filename, 241 | char *outname); 242 | time_t rrd_last_r( 243 | const char *filename); 244 | time_t rrd_first_r( 245 | const char *filename, 246 | int rraindex); 247 | 248 | /* Transplanted from rrd_parsetime.h */ 249 | typedef enum { 250 | ABSOLUTE_TIME, 251 | RELATIVE_TO_START_TIME, 252 | RELATIVE_TO_END_TIME 253 | } rrd_timetype_t; 254 | 255 | #define TIME_OK NULL 256 | 257 | typedef struct rrd_time_value { 258 | rrd_timetype_t type; 259 | long offset; 260 | struct tm tm; 261 | } rrd_time_value_t; 262 | 263 | char *rrd_parsetime( 264 | const char *spec, 265 | rrd_time_value_t * ptv); 266 | /* END rrd_parsetime.h */ 267 | 268 | typedef struct rrd_context { 269 | char lib_errstr[256]; 270 | char rrd_error[4096]; 271 | } rrd_context_t; 272 | 273 | /* returns the current per-thread rrd_context */ 274 | rrd_context_t *rrd_get_context( 275 | void); 276 | 277 | #ifdef WIN32 278 | rrd_context_t *rrd_force_new_context(void); 279 | #endif 280 | 281 | int rrd_proc_start_end( 282 | rrd_time_value_t *, 283 | rrd_time_value_t *, 284 | time_t *, 285 | time_t *); 286 | 287 | /* HELPER FUNCTIONS */ 288 | #if defined ESP32 || defined CONFIG_IDF_TARGET 289 | #include 290 | #include 291 | static SemaphoreHandle_t xRrdFlockSemaphore = NULL; 292 | #define rrd_set_error(...) ESP_LOGE(__FILE__, ##__VA_ARGS__) 293 | #else 294 | void rrd_set_error( 295 | char *, 296 | ...); 297 | #endif 298 | void rrd_clear_error( 299 | void); 300 | int rrd_test_error( 301 | void); 302 | char *rrd_get_error( 303 | void); 304 | 305 | /* rrd_strerror is thread safe, but still it uses a global buffer 306 | (but one per thread), thus subsequent calls within a single 307 | thread overwrite the same buffer */ 308 | const char *rrd_strerror( 309 | int err); 310 | 311 | /** MULTITHREADED HELPER FUNCTIONS */ 312 | rrd_context_t *rrd_new_context( 313 | void); 314 | void rrd_free_context( 315 | rrd_context_t * buf); 316 | 317 | /* void rrd_set_error_r (rrd_context_t *, char *, ...); */ 318 | /* void rrd_clear_error_r(rrd_context_t *); */ 319 | /* int rrd_test_error_r (rrd_context_t *); */ 320 | /* char *rrd_get_error_r (rrd_context_t *); */ 321 | 322 | /* 323 | * The following functions are _internal_ functions needed to read the raw RRD 324 | * files. Since they are _internal_ they may change with the file format and 325 | * will be replaced with a more general interface in RRDTool 1.4. Don't use 326 | * these functions unless you have good reasons to do so. If you do use these 327 | * functions you will have to adapt your code for RRDTool 1.4! 328 | * 329 | * To enable the deprecated functions define `RRD_EXPORT_DEPRECATED' before 330 | * including . You have been warned! If you come back to the 331 | * RRDTool mailing list and whine about your broken application, you will get 332 | * hit with something smelly! 333 | */ 334 | #if defined(_RRD_TOOL_H) || defined(RRD_EXPORT_DEPRECATED) 335 | 336 | # if defined(_RRD_TOOL_H) 337 | # include "rrd_format.h" 338 | # else 339 | # include 340 | # endif 341 | 342 | #if defined(__GNUC__) && defined (RRD_EXPORT_DEPRECATED) 343 | # define RRD_DEPRECATED __attribute__((deprecated)) 344 | #else 345 | # define RRD_DEPRECATED /**/ 346 | #endif 347 | void rrd_free( 348 | rrd_t *rrd) 349 | RRD_DEPRECATED; 350 | void rrd_init( 351 | rrd_t *rrd) 352 | RRD_DEPRECATED; 353 | 354 | rrd_file_t *rrd_open( 355 | const char *const file_name, 356 | rrd_t *rrd, 357 | unsigned rdwr) 358 | RRD_DEPRECATED; 359 | 360 | void rrd_dontneed( 361 | rrd_file_t *rrd_file, 362 | rrd_t *rrd) 363 | RRD_DEPRECATED; 364 | int rrd_close( 365 | rrd_file_t *rrd_file) 366 | RRD_DEPRECATED; 367 | ssize_t rrd_read( 368 | rrd_file_t *rrd_file, 369 | void *buf, 370 | size_t count) 371 | RRD_DEPRECATED; 372 | ssize_t rrd_write( 373 | rrd_file_t *rrd_file, 374 | const void *buf, 375 | size_t count) 376 | RRD_DEPRECATED; 377 | void rrd_flush( 378 | rrd_file_t *rrd_file) 379 | RRD_DEPRECATED; 380 | off_t rrd_seek( 381 | rrd_file_t *rrd_file, 382 | off_t off, 383 | int whence) 384 | RRD_DEPRECATED; 385 | off_t rrd_tell( 386 | rrd_file_t *rrd_file) 387 | RRD_DEPRECATED; 388 | int rrd_lock( 389 | rrd_file_t *file) 390 | RRD_DEPRECATED; 391 | #endif /* defined(_RRD_TOOL_H) || defined(RRD_EXPORT_DEPRECATED) */ 392 | 393 | #endif /* _RRDLIB_H */ 394 | 395 | #ifdef __cplusplus 396 | } 397 | #endif 398 | -------------------------------------------------------------------------------- /src/rrd_config_bottom.h: -------------------------------------------------------------------------------- 1 | #ifndef RRD_CONFIG_BOTTOM_H 2 | #define RRD_CONFIG_BOTTOM_H 3 | 4 | /* make sure that we pickup the correct stuff from all headers */ 5 | #ifdef HAVE_FEATURES_H 6 | # ifdef _XOPEN_SOURCE 7 | # undef _XOPEN_SOURCE 8 | # endif 9 | # ifdef _BSD_SOURCE 10 | # undef _BSD_SOURCE 11 | # endif 12 | # define _XOPEN_SOURCE 600 13 | # define _BSD_SOURCE 1 14 | # include 15 | #endif 16 | 17 | /* FreeBSD 4.8 wants this included BEFORE sys/types.h */ 18 | #ifdef HAVE_SYS_MMAN_H 19 | # include 20 | #endif 21 | 22 | #ifdef HAVE_SYS_TYPES_H 23 | # include 24 | #endif 25 | 26 | #ifdef HAVE_SYS_PARAM_H 27 | # include 28 | #endif 29 | #ifndef MAXPATH 30 | # ifdef PATH_MAX 31 | # define MAXPATH PATH_MAX 32 | # endif 33 | #endif 34 | #ifndef MAXPATH 35 | /* else try the BSD variant */ 36 | # ifdef MAXPATHLEN 37 | # define MAXPATH MAXPATHLEN 38 | # endif 39 | #endif 40 | 41 | #ifdef HAVE_ERRNO_H 42 | # include 43 | #endif 44 | 45 | #if !defined HAVE_MADVISE && defined HAVE_POSIX_MADVISE 46 | /* use posix_madvise family */ 47 | # define madvise posix_madvise 48 | # define MADV_NORMAL POSIX_MADV_NORMAL 49 | # define MADV_RANDOM POSIX_MADV_RANDOM 50 | # define MADV_SEQUENTIAL POSIX_MADV_SEQUENTIAL 51 | # define MADV_WILLNEED POSIX_MADV_WILLNEED 52 | # define MADV_DONTNEED POSIX_MADV_DONTNEED 53 | #endif 54 | #if defined HAVE_MADVISE || defined HAVE_POSIX_MADVISE 55 | # define USE_MADVISE 1 56 | #endif 57 | 58 | #ifdef HAVE_SYS_STAT_H 59 | # include 60 | #endif 61 | 62 | #ifdef HAVE_FCNTL_H 63 | #include 64 | #endif 65 | 66 | #ifdef HAVE_UNISTD_H 67 | # include 68 | #endif 69 | 70 | #ifdef TIME_WITH_SYS_TIME 71 | # include 72 | # include 73 | #else 74 | # ifdef HAVE_SYS_TIME_H 75 | # include 76 | # else 77 | # include 78 | # endif 79 | #endif 80 | 81 | #ifdef HAVE_SYS_TIMES_H 82 | # include 83 | #endif 84 | 85 | #ifdef HAVE_SYS_RESOURCE_H 86 | # include 87 | #if (defined(__svr4__) && defined(__sun__)) 88 | /* Solaris headers (pre 2.6) do not have a getrusage prototype. 89 | Use this instead. */ 90 | extern int getrusage(int, struct rusage *); 91 | #endif /* __svr4__ && __sun__ */ 92 | #endif 93 | 94 | 95 | /* define strrchr, strchr and memcpy, memmove in terms of bsd funcs 96 | make sure you are NOT using bcopy, index or rindex in the code */ 97 | 98 | #ifdef STDC_HEADERS 99 | # include 100 | #else 101 | # ifndef HAVE_STRCHR 102 | # define strchr index 103 | # define strrchr rindex 104 | # endif 105 | char *strchr (), *strrchr (); 106 | # ifndef HAVE_MEMMOVE 107 | # define memcpy(d, s, n) bcopy ((s), (d), (n)) 108 | # define memmove(d, s, n) bcopy ((s), (d), (n)) 109 | # endif 110 | #endif 111 | 112 | #ifdef NO_NULL_REALLOC 113 | # define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) )) 114 | #else 115 | # define rrd_realloc(a,b) realloc((a), (b)) 116 | #endif 117 | 118 | #ifdef HAVE_STDIO_H 119 | # include 120 | #endif 121 | 122 | #ifdef HAVE_STDLIB_H 123 | # include 124 | #endif 125 | 126 | #ifdef HAVE_CTYPE_H 127 | # include 128 | #endif 129 | 130 | #ifdef HAVE_DIRENT_H 131 | # include 132 | # define NAMLEN(dirent) strlen((dirent)->d_name) 133 | #else 134 | # define dirent direct 135 | # define NAMLEN(dirent) (dirent)->d_namlen 136 | # ifdef HAVE_SYS_NDIR_H 137 | # include 138 | # endif 139 | # ifdef HAVE_SYS_DIR_H 140 | # include 141 | # endif 142 | # ifdef HAVE_NDIR_H 143 | # include 144 | # endif 145 | #endif 146 | 147 | #ifdef MUST_DISABLE_SIGFPE 148 | # include 149 | #endif 150 | 151 | #ifdef MUST_DISABLE_FPMASK 152 | # include 153 | #endif 154 | 155 | 156 | #ifdef HAVE_MATH_H 157 | # include 158 | #endif 159 | 160 | #ifdef HAVE_FLOAT_H 161 | # include 162 | #endif 163 | 164 | #ifdef HAVE_IEEEFP_H 165 | # include 166 | #endif 167 | 168 | #ifdef HAVE_FP_CLASS_H 169 | # include 170 | #endif 171 | 172 | /* for Solaris */ 173 | #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS)) 174 | # define HAVE_ISINF 1 175 | # ifdef isinf 176 | # undef isinf 177 | # endif 178 | # define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF) 179 | #endif 180 | 181 | /* solaris 10 it defines isnan such that only forte can compile it ... bad bad */ 182 | #if (defined(HAVE_ISNAN) && defined(isnan) && defined(HAVE_FPCLASS)) 183 | # undef isnan 184 | # define isnan(a) (fpclass(a) == FP_SNAN || fpclass(a) == FP_QNAN) 185 | #endif 186 | 187 | /* for OSF1 Digital Unix */ 188 | #if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H)) 189 | # define HAVE_ISINF 1 190 | # define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF) 191 | #endif 192 | 193 | #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_PLUS_INF) && defined(FP_MINUS_INF)) 194 | # define HAVE_ISINF 1 195 | # define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF) 196 | #endif 197 | 198 | #if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_INFINITE)) 199 | # define HAVE_ISINF 1 200 | # define isinf(a) (fpclassify(a) == FP_INFINITE) 201 | #endif 202 | 203 | /* for AIX */ 204 | #if (! defined(HAVE_ISINF) && defined(HAVE_CLASS)) 205 | # define HAVE_ISINF 1 206 | # define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF) 207 | #endif 208 | 209 | #if (! defined (HAVE_FINITE) && defined (HAVE_ISFINITE)) 210 | # define HAVE_FINITE 1 211 | # define finite(a) isfinite(a) 212 | #endif 213 | 214 | #if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF)) 215 | # define HAVE_FINITE 1 216 | # define finite(a) (! isnan(a) && ! isinf(a)) 217 | #endif 218 | 219 | #ifndef HAVE_FINITE 220 | #error "Can't compile without finite function" 221 | #endif 222 | 223 | #ifndef HAVE_ISINF 224 | #error "Can't compile without isinf function" 225 | #endif 226 | 227 | #if (! defined(HAVE_FDATASYNC) && defined(HAVE_FSYNC)) 228 | #define fdatasync fsync 229 | #endif 230 | 231 | #if (!defined(HAVE_FDATASYNC) && !defined(HAVE_FSYNC)) 232 | #error "Can't compile with without fsync and fdatasync" 233 | #endif 234 | 235 | #endif /* RRD_CONFIG_BOTTOM_H */ 236 | 237 | -------------------------------------------------------------------------------- /src/rrd_diff.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | * This code is stolen from rateup (mrtg-2.x) by Dave Rand 4 | ***************************************************************************** 5 | * diff calculate the difference between two very long integers available as 6 | * strings 7 | ***************************************************************************** 8 | * $Id: rrd_diff.c 1946 2009-10-24 10:46:42Z oetiker $ 9 | * $Log$ 10 | * Revision 1.4 2003/03/10 00:30:34 oetiker 11 | * handle cases with two negative numbers 12 | * -- Sasha Mikheev 13 | * 14 | * Revision 1.3 2002/04/01 18:31:22 oetiker 15 | * "!" takes a higher preference than "||" this means rrd_update N:: would 16 | * segfault -- Oliver Cook 17 | * 18 | * Revision 1.2 2002/02/01 20:34:49 oetiker 19 | * fixed version number and date/time 20 | * 21 | * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker 22 | * checkin 23 | * 24 | * Revision 1.1 1998/10/08 18:21:45 oetiker 25 | * Initial revision 26 | * 27 | * Revision 1.3 1998/02/06 21:10:52 oetiker 28 | * removed max define .. it is now in rrd_tool.h 29 | * 30 | * Revision 1.2 1997/12/07 20:38:03 oetiker 31 | * ansified 32 | * 33 | * Revision 1.1 1997/11/28 23:31:59 oetiker 34 | * Initial revision 35 | * 36 | *****************************************************************************/ 37 | 38 | #include "rrd_tool.h" 39 | 40 | #ifdef WIN32 41 | #include 42 | #endif 43 | 44 | double rrd_diff( 45 | char *a, 46 | char *b) 47 | { 48 | char res[LAST_DS_LEN + 1], *a1, *b1, *r1, *fix; 49 | int c, x, m; 50 | char a_neg = 0, b_neg = 0; 51 | double result; 52 | 53 | while (!(isdigit((int) *a) || *a == 0)) { 54 | if (*a == '-') 55 | a_neg = 1; 56 | a++; 57 | } 58 | fix = a; 59 | while (isdigit((int) *fix)) 60 | fix++; 61 | *fix = 0; /* maybe there is some non digit data in the string */ 62 | while (!(isdigit((int) *b) || *b == 0)) { 63 | if (*b == '-') 64 | b_neg = 1; 65 | b++; 66 | } 67 | fix = b; 68 | while (isdigit((int) *fix)) 69 | fix++; 70 | *fix = 0; /* maybe there is some non digit data in the string */ 71 | if (!isdigit((int) *a) || !isdigit((int) *b)) 72 | return DNAN; 73 | if (a_neg + b_neg == 1) /* can not handle numbers with different signs yet */ 74 | return DNAN; 75 | a1 = &a[strlen(a) - 1]; 76 | m = max(strlen(a), strlen(b)); 77 | if (m > LAST_DS_LEN) 78 | return DNAN; /* result string too short */ 79 | 80 | r1 = &res[m + 1]; 81 | for (b1 = res; b1 <= r1; b1++) 82 | *b1 = ' '; 83 | b1 = &b[strlen(b) - 1]; 84 | r1[1] = 0; /* Null terminate result */ 85 | c = 0; 86 | for (x = 0; x < m; x++) { 87 | if (a1 >= a && b1 >= b) { 88 | *r1 = ((*a1 - c) - *b1) + '0'; 89 | } else if (a1 >= a) { 90 | *r1 = (*a1 - c); 91 | } else { 92 | *r1 = ('0' - *b1 - c) + '0'; 93 | } 94 | if (*r1 < '0') { 95 | *r1 += 10; 96 | c = 1; 97 | } else if (*r1 > '9') { /* 0 - 10 */ 98 | *r1 -= 10; 99 | c = 1; 100 | } else { 101 | c = 0; 102 | } 103 | a1--; 104 | b1--; 105 | r1--; 106 | } 107 | if (c) { 108 | r1 = &res[m + 1]; 109 | for (x = 0; isdigit((int) *r1) && x < m; x++, r1--) { 110 | *r1 = ('9' - *r1 + c) + '0'; 111 | if (*r1 > '9') { 112 | *r1 -= 10; 113 | c = 1; 114 | } else { 115 | c = 0; 116 | } 117 | } 118 | result = -atof(res); 119 | } else 120 | result = atof(res); 121 | 122 | if (a_neg + b_neg == 2) /* both are negatives, reverse sign */ 123 | result = -result; 124 | 125 | return result; 126 | } 127 | -------------------------------------------------------------------------------- /src/rrd_error.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_error.c Common Header File 5 | ***************************************************************************** 6 | * $Id: rrd_error.c 1946 2009-10-24 10:46:42Z oetiker $ 7 | * $Log$ 8 | * Revision 1.4 2003/02/22 21:57:03 oetiker 9 | * a patch to avoid a memory leak and a Makefile.am patch to 10 | * distribute all required source files -- Peter Stamfest 11 | * 12 | * Revision 1.3 2003/02/13 07:05:27 oetiker 13 | * Find attached the patch I promised to send to you. Please note that there 14 | * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c 15 | * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This 16 | * library is identical to librrd, but it contains support code for per-thread 17 | * global variables currently used for error information only. This is similar 18 | * to how errno per-thread variables are implemented. librrd_th must be linked 19 | * alongside of libpthred 20 | * 21 | * There is also a new file "THREADS", holding some documentation. 22 | * 23 | * -- Peter Stamfest 24 | * 25 | * Revision 1.2 2002/02/01 20:34:49 oetiker 26 | * fixed version number and date/time 27 | * 28 | * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker 29 | * checkin 30 | * 31 | *************************************************************************** */ 32 | 33 | #include "rrd_tool.h" 34 | #include 35 | 36 | #ifdef WIN32 37 | #include 38 | #endif 39 | 40 | #define MAXLEN 4096 41 | #define ERRBUFLEN 256 42 | #define CTX (rrd_get_context()) 43 | 44 | #if !defined ESP32 && !defined CONFIG_IDF_TARGET 45 | void rrd_set_error( 46 | char *fmt, 47 | ...) 48 | { 49 | va_list argp; 50 | 51 | rrd_clear_error(); 52 | va_start(argp, fmt); 53 | #ifdef HAVE_VSNPRINTF 54 | vsnprintf(CTX->rrd_error, sizeof(CTX->rrd_error), fmt, argp); 55 | #else 56 | vsprintf(CTX->rrd_error, fmt, argp); 57 | #endif 58 | va_end(argp); 59 | } 60 | #endif 61 | 62 | int rrd_test_error( 63 | void) 64 | { 65 | return CTX->rrd_error[0] != '\0'; 66 | } 67 | 68 | void rrd_clear_error( 69 | void) 70 | { 71 | CTX->rrd_error[0] = '\0'; 72 | } 73 | 74 | char *rrd_get_error( 75 | void) 76 | { 77 | return CTX->rrd_error; 78 | } 79 | 80 | #if 0 81 | /* PS: Keep this stuff around, maybe we want it again if we use 82 | rrd_contexts to really associate them with single RRD files and 83 | operations on them... Then a single thread may use more than one 84 | context. Using these functions would require to change each and 85 | every function containing any of the non _r versions... */ 86 | void rrd_set_error_r( 87 | rrd_context_t * rrd_ctx, 88 | char *fmt, 89 | ...) 90 | { 91 | va_list argp; 92 | 93 | rrd_clear_error_r(rrd_ctx); 94 | va_start(argp, fmt); 95 | #ifdef HAVE_VSNPRINTF 96 | vsnprintf(rrd_ctx->rrd_error, sizeof(rrd_ctx->rrd_error), fmt, argp); 97 | rrd_ctx->rrd_error[sizeof(rrd_ctx->rrd_error) - 1] = '\0'; 98 | #else 99 | vsprintf(rrd_ctx->rrd_error, fmt, argp); 100 | #endif 101 | va_end(argp); 102 | } 103 | 104 | int rrd_test_error_r( 105 | rrd_context_t * rrd_ctx) 106 | { 107 | return rrd_ctx->rrd_error[0] != '\0'; 108 | } 109 | 110 | void rrd_clear_error_r( 111 | rrd_context_t * rrd_ctx) 112 | { 113 | rrd_ctx->rrd_error[0] = '\0'; 114 | } 115 | 116 | char *rrd_get_error_r( 117 | rrd_context_t * rrd_ctx) 118 | { 119 | return rrd_ctx->rrd_error; 120 | } 121 | #endif 122 | 123 | /* PS: Should we move this to some other file? It is not really error 124 | related. */ 125 | rrd_context_t *rrd_new_context( 126 | void) 127 | { 128 | rrd_context_t *rrd_ctx = (rrd_context_t *) malloc(sizeof(rrd_context_t)); 129 | 130 | if (!rrd_ctx) { 131 | return NULL; 132 | } 133 | 134 | rrd_ctx->rrd_error[0] = '\0'; 135 | rrd_ctx->lib_errstr[0] = '\0'; 136 | return rrd_ctx; 137 | } 138 | 139 | void rrd_free_context( 140 | rrd_context_t * rrd_ctx) 141 | { 142 | if (rrd_ctx) { 143 | free(rrd_ctx); 144 | } 145 | } 146 | 147 | #if 0 148 | void rrd_globalize_error( 149 | rrd_context_t * rrd_ctx) 150 | { 151 | if (rrd_ctx) { 152 | rrd_set_error(rrd_ctx->rrd_error); 153 | } 154 | } 155 | #endif 156 | -------------------------------------------------------------------------------- /src/rrd_fetch.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_fetch.c read date from an rrd to use for further processing 5 | ***************************************************************************** 6 | * $Id: rrd_fetch.c 1946 2009-10-24 10:46:42Z oetiker $ 7 | * $Log$ 8 | * Revision 1.8 2004/05/18 18:53:03 oetiker 9 | * big spell checking patch -- slif@bellsouth.net 10 | * 11 | * Revision 1.7 2003/11/11 19:46:21 oetiker 12 | * replaced time_value with rrd_time_value as MacOS X introduced a struct of that name in their standard headers 13 | * 14 | * Revision 1.6 2003/01/16 23:27:54 oetiker 15 | * fix border condition in rra selection of rrd_fetch 16 | * -- Stanislav Sinyagin 17 | * 18 | * Revision 1.5 2002/06/23 22:29:40 alex 19 | * Added "step=1800" and such to "DEF" 20 | * Cleaned some of the signed vs. unsigned problems 21 | * 22 | * Revision 1.4 2002/02/01 20:34:49 oetiker 23 | * fixed version number and date/time 24 | * 25 | * Revision 1.3 2001/12/24 06:51:49 alex 26 | * A patch of size 44Kbytes... in short: 27 | * 28 | * Found and repaired the off-by-one error in rrd_fetch_fn(). 29 | * As a result I had to remove the hacks in rrd_fetch_fn(), 30 | * rrd_tool.c, vdef_calc(), data_calc(), data_proc() and 31 | * reduce_data(). There may be other places which I didn't 32 | * find so be careful. 33 | * 34 | * Enhanced debugging in rrd_fetch_fn(), it shows the RRA selection 35 | * process. 36 | * 37 | * Added the ability to print VDEF timestamps. At the moment it 38 | * is a hack, I needed it now to fix the off-by-one error. 39 | * If the format string is "%c" (and nothing else!), the time 40 | * will be printed by both ctime() and as a long int. 41 | * 42 | * Moved some code around (slightly altering it) from rrd_graph() 43 | * initializing now in rrd_graph_init() 44 | * options parsing now in rrd_graph_options() 45 | * script parsing now in rrd_graph_script() 46 | * 47 | * Revision 1.2 2001/12/17 12:48:43 oetiker 48 | * fix overflow error ... 49 | * 50 | * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker 51 | * checkin 52 | * 53 | *****************************************************************************/ 54 | 55 | #ifdef WIN32 56 | #include 57 | #endif 58 | 59 | #include "rrd_tool.h" 60 | 61 | #include "rrd_is_thread_safe.h" 62 | /*#define DEBUG*/ 63 | 64 | int rrd_fetch( 65 | int argc, 66 | char **argv, 67 | time_t *start, 68 | time_t *end, /* which time frame do you want ? 69 | * will be changed to represent reality */ 70 | unsigned long *step, /* which stepsize do you want? 71 | * will be changed to represent reality */ 72 | unsigned long *ds_cnt, /* number of data sources in file */ 73 | char ***ds_namv, /* names of data sources */ 74 | rrd_value_t **data) 75 | { /* two dimensional array containing the data */ 76 | long step_tmp = 1; 77 | time_t start_tmp = 0, end_tmp = 0; 78 | const char *cf; 79 | 80 | rrd_time_value_t start_tv, end_tv; 81 | char *parsetime_error = NULL; 82 | struct option long_options[] = { 83 | {"resolution", required_argument, 0, 'r'}, 84 | {"start", required_argument, 0, 's'}, 85 | {"end", required_argument, 0, 'e'}, 86 | {0, 0, 0, 0} 87 | }; 88 | 89 | optind = 0; 90 | opterr = 0; /* initialize getopt */ 91 | 92 | /* init start and end time */ 93 | rrd_parsetime("end-24h", &start_tv); 94 | rrd_parsetime("now", &end_tv); 95 | 96 | while (1) { 97 | int option_index = 0; 98 | int opt; 99 | 100 | opt = getopt_long(argc, argv, "r:s:e:", long_options, &option_index); 101 | 102 | if (opt == EOF) 103 | break; 104 | 105 | switch (opt) { 106 | case 's': 107 | if ((parsetime_error = rrd_parsetime(optarg, &start_tv))) { 108 | rrd_set_error("start time: %s", parsetime_error); 109 | return -1; 110 | } 111 | break; 112 | case 'e': 113 | if ((parsetime_error = rrd_parsetime(optarg, &end_tv))) { 114 | rrd_set_error("end time: %s", parsetime_error); 115 | return -1; 116 | } 117 | break; 118 | case 'r': 119 | step_tmp = atol(optarg); 120 | break; 121 | case '?': 122 | rrd_set_error("unknown option '-%c'", optopt); 123 | return (-1); 124 | } 125 | } 126 | 127 | 128 | if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) { 129 | return -1; 130 | } 131 | 132 | 133 | if (start_tmp < 3600 * 24 * 365 * 10) { 134 | rrd_set_error("the first entry to fetch should be after 1980"); 135 | return (-1); 136 | } 137 | 138 | if (end_tmp < start_tmp) { 139 | rrd_set_error("start (%ld) should be less than end (%ld)", start_tmp, 140 | end_tmp); 141 | return (-1); 142 | } 143 | 144 | *start = start_tmp; 145 | *end = end_tmp; 146 | 147 | if (step_tmp < 1) { 148 | rrd_set_error("step must be >= 1 second"); 149 | return -1; 150 | } 151 | *step = step_tmp; 152 | 153 | if (optind + 1 >= argc) { 154 | rrd_set_error("not enough arguments"); 155 | return -1; 156 | } 157 | 158 | cf = argv[optind + 1]; 159 | 160 | if (rrd_fetch_r(argv[optind], cf, start, end, step, ds_cnt, ds_namv, data) 161 | != 0) 162 | return (-1); 163 | return (0); 164 | } 165 | 166 | int rrd_fetch_r( 167 | const char *filename, /* name of the rrd */ 168 | const char *cf, /* which consolidation function ? */ 169 | time_t *start, 170 | time_t *end, /* which time frame do you want ? 171 | * will be changed to represent reality */ 172 | unsigned long *step, /* which stepsize do you want? 173 | * will be changed to represent reality */ 174 | unsigned long *ds_cnt, /* number of data sources in file */ 175 | char ***ds_namv, /* names of data_sources */ 176 | rrd_value_t **data) 177 | { /* two dimensional array containing the data */ 178 | enum cf_en cf_idx; 179 | 180 | if ((int) (cf_idx = cf_conv(cf)) == -1) { 181 | return -1; 182 | } 183 | 184 | return (rrd_fetch_fn 185 | (filename, cf_idx, start, end, step, ds_cnt, ds_namv, data)); 186 | } 187 | 188 | int rrd_fetch_fn( 189 | const char *filename, /* name of the rrd */ 190 | enum cf_en cf_idx, /* which consolidation function ? */ 191 | time_t *start, 192 | time_t *end, /* which time frame do you want ? 193 | * will be changed to represent reality */ 194 | unsigned long *step, /* which stepsize do you want? 195 | * will be changed to represent reality */ 196 | unsigned long *ds_cnt, /* number of data sources in file */ 197 | char ***ds_namv, /* names of data_sources */ 198 | rrd_value_t **data) 199 | { /* two dimensional array containing the data */ 200 | long i, ii; 201 | time_t cal_start, cal_end, rra_start_time, rra_end_time; 202 | long best_full_rra = 0, best_part_rra = 0, chosen_rra = 203 | 0, rra_pointer = 0; 204 | long best_full_step_diff = 0, best_part_step_diff = 205 | 0, tmp_step_diff = 0, tmp_match = 0, best_match = 0; 206 | long full_match, rra_base; 207 | long start_offset, end_offset; 208 | int first_full = 1; 209 | int first_part = 1; 210 | rrd_t rrd; 211 | rrd_file_t *rrd_file; 212 | rrd_value_t *data_ptr; 213 | unsigned long rows; 214 | 215 | #ifdef DEBUG 216 | fprintf(stderr, "Entered rrd_fetch_fn() searching for the best match\n"); 217 | fprintf(stderr, "Looking for: start %10lu end %10lu step %5lu\n", 218 | *start, *end, *step); 219 | #endif 220 | 221 | rrd_file = rrd_open(filename, &rrd, RRD_READONLY); 222 | if (rrd_file == NULL) 223 | goto err_free; 224 | 225 | /* when was the really last update of this file ? */ 226 | 227 | if (((*ds_namv) = 228 | (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) { 229 | rrd_set_error("malloc fetch ds_namv array"); 230 | goto err_close; 231 | } 232 | 233 | for (i = 0; (unsigned long) i < rrd.stat_head->ds_cnt; i++) { 234 | if ((((*ds_namv)[i]) = (char*)malloc(sizeof(char) * DS_NAM_SIZE)) == NULL) { 235 | rrd_set_error("malloc fetch ds_namv entry"); 236 | goto err_free_ds_namv; 237 | } 238 | strncpy((*ds_namv)[i], rrd.ds_def[i].ds_nam, DS_NAM_SIZE - 1); 239 | (*ds_namv)[i][DS_NAM_SIZE - 1] = '\0'; 240 | 241 | } 242 | 243 | /* find the rra which best matches the requirements */ 244 | for (i = 0; (unsigned) i < rrd.stat_head->rra_cnt; i++) { 245 | if (cf_conv(rrd.rra_def[i].cf_nam) == cf_idx) { 246 | 247 | cal_end = (rrd.live_head->last_up - (rrd.live_head->last_up 248 | % (rrd.rra_def[i].pdp_cnt 249 | * 250 | rrd.stat_head-> 251 | pdp_step))); 252 | cal_start = 253 | (cal_end - 254 | (rrd.rra_def[i].pdp_cnt * rrd.rra_def[i].row_cnt * 255 | rrd.stat_head->pdp_step)); 256 | 257 | full_match = *end - *start; 258 | #ifdef DEBUG 259 | fprintf(stderr, "Considering: start %10lu end %10lu step %5lu ", 260 | cal_start, cal_end, 261 | rrd.stat_head->pdp_step * rrd.rra_def[i].pdp_cnt); 262 | #endif 263 | /* we need step difference in either full or partial case */ 264 | tmp_step_diff = labs(*step - (rrd.stat_head->pdp_step 265 | * rrd.rra_def[i].pdp_cnt)); 266 | /* best full match */ 267 | if (cal_start <= *start) { 268 | if (first_full || (tmp_step_diff < best_full_step_diff)) { 269 | first_full = 0; 270 | best_full_step_diff = tmp_step_diff; 271 | best_full_rra = i; 272 | #ifdef DEBUG 273 | fprintf(stderr, "best full match so far\n"); 274 | } else { 275 | fprintf(stderr, "full match, not best\n"); 276 | #endif 277 | } 278 | 279 | } else { 280 | /* best partial match */ 281 | tmp_match = full_match; 282 | if (cal_start > *start) 283 | tmp_match -= (cal_start - *start); 284 | if (first_part || 285 | (best_match < tmp_match) || 286 | (best_match == tmp_match && 287 | tmp_step_diff < best_part_step_diff)) { 288 | #ifdef DEBUG 289 | fprintf(stderr, "best partial so far\n"); 290 | #endif 291 | first_part = 0; 292 | best_match = tmp_match; 293 | best_part_step_diff = tmp_step_diff; 294 | best_part_rra = i; 295 | } else { 296 | #ifdef DEBUG 297 | fprintf(stderr, "partial match, not best\n"); 298 | #endif 299 | } 300 | } 301 | } 302 | } 303 | 304 | /* lets see how the matching went. */ 305 | if (first_full == 0) 306 | chosen_rra = best_full_rra; 307 | else if (first_part == 0) 308 | chosen_rra = best_part_rra; 309 | else { 310 | rrd_set_error 311 | ("the RRD does not contain an RRA matching the chosen CF"); 312 | goto err_free_all_ds_namv; 313 | } 314 | 315 | /* set the wish parameters to their real values */ 316 | *step = rrd.stat_head->pdp_step * rrd.rra_def[chosen_rra].pdp_cnt; 317 | *start -= (*start % *step); 318 | *end += (*step - *end % *step); 319 | rows = (*end - *start) / *step + 1; 320 | 321 | #ifdef DEBUG 322 | fprintf(stderr, 323 | "We found: start %10lu end %10lu step %5lu rows %lu\n", 324 | *start, *end, *step, rows); 325 | #endif 326 | 327 | /* Start and end are now multiples of the step size. The amount of 328 | ** steps we want is (end-start)/step and *not* an extra one. 329 | ** Reasoning: if step is s and we want to graph from t to t+s, 330 | ** we need exactly ((t+s)-t)/s rows. The row to collect from the 331 | ** database is the one with time stamp (t+s) which means t to t+s. 332 | */ 333 | *ds_cnt = rrd.stat_head->ds_cnt; 334 | if (((*data) = (rrd_value_t *)malloc(*ds_cnt * rows * sizeof(rrd_value_t))) == NULL) { 335 | rrd_set_error("malloc fetch data area"); 336 | goto err_free_all_ds_namv; 337 | } 338 | 339 | data_ptr = (*data); 340 | 341 | /* find base address of rra */ 342 | rra_base = rrd_file->header_len; 343 | for (i = 0; i < chosen_rra; i++) 344 | rra_base += (*ds_cnt * rrd.rra_def[i].row_cnt * sizeof(rrd_value_t)); 345 | 346 | /* find start and end offset */ 347 | rra_end_time = (rrd.live_head->last_up 348 | - (rrd.live_head->last_up % *step)); 349 | rra_start_time = (rra_end_time 350 | - (*step * (rrd.rra_def[chosen_rra].row_cnt - 1))); 351 | /* here's an error by one if we don't be careful */ 352 | start_offset = (long) (*start + *step - rra_start_time) / (long) *step; 353 | end_offset = (long) (rra_end_time - *end) / (long) *step; 354 | #ifdef DEBUG 355 | fprintf(stderr, 356 | "rra_start %lu, rra_end %lu, start_off %li, end_off %li\n", 357 | rra_start_time, rra_end_time, start_offset, end_offset); 358 | #endif 359 | 360 | /* fill the gap at the start if needs be */ 361 | 362 | if (*start <= rra_end_time && *end >= rra_start_time - *step){ 363 | 364 | if (start_offset <= 0) 365 | rra_pointer = rrd.rra_ptr[chosen_rra].cur_row + 1; 366 | else 367 | rra_pointer = rrd.rra_ptr[chosen_rra].cur_row + 1 + start_offset; 368 | 369 | rra_pointer = rra_pointer % (signed) rrd.rra_def[chosen_rra].row_cnt; 370 | 371 | if (rrd_seek(rrd_file, (rra_base + (rra_pointer * (*ds_cnt) 372 | * sizeof(rrd_value_t))), 373 | SEEK_SET) != 0) { 374 | rrd_set_error("seek error in RRA"); 375 | goto err_free_data; 376 | } 377 | #ifdef DEBUG 378 | fprintf(stderr, "First Seek: rra_base %lu rra_pointer %lu\n", 379 | rra_base, rra_pointer); 380 | #endif 381 | } 382 | 383 | /* step trough the array */ 384 | 385 | for (i = start_offset; 386 | i < (signed) rrd.rra_def[chosen_rra].row_cnt - end_offset; i++) { 387 | /* no valid data yet */ 388 | if (i < 0) { 389 | #ifdef DEBUG 390 | fprintf(stderr, "pre fetch %li -- ", i); 391 | #endif 392 | for (ii = 0; (unsigned) ii < *ds_cnt; ii++) { 393 | *(data_ptr++) = DNAN; 394 | #ifdef DEBUG 395 | fprintf(stderr, "%10.2f ", *(data_ptr - 1)); 396 | #endif 397 | } 398 | } 399 | /* past the valid data area */ 400 | else if (i >= (signed) rrd.rra_def[chosen_rra].row_cnt) { 401 | #ifdef DEBUG 402 | fprintf(stderr, "past fetch %li -- ", i); 403 | #endif 404 | for (ii = 0; (unsigned) ii < *ds_cnt; ii++) { 405 | *(data_ptr++) = DNAN; 406 | #ifdef DEBUG 407 | fprintf(stderr, "%10.2f ", *(data_ptr - 1)); 408 | #endif 409 | } 410 | } else { 411 | /* OK we are inside the valid area but the pointer has to 412 | * be wrapped*/ 413 | if (rra_pointer >= (signed) rrd.rra_def[chosen_rra].row_cnt) { 414 | rra_pointer -= rrd.rra_def[chosen_rra].row_cnt; 415 | if (rrd_seek(rrd_file, (rra_base + rra_pointer * (*ds_cnt) 416 | * sizeof(rrd_value_t)), 417 | SEEK_SET) != 0) { 418 | rrd_set_error("wrap seek in RRA did fail"); 419 | goto err_free_data; 420 | } 421 | #ifdef DEBUG 422 | fprintf(stderr, "wrap seek ...\n"); 423 | #endif 424 | } 425 | 426 | if (rrd_read(rrd_file, data_ptr, sizeof(rrd_value_t) * (*ds_cnt)) 427 | != (ssize_t) (sizeof(rrd_value_t) * (*ds_cnt))) { 428 | rrd_set_error("fetching cdp from rra"); 429 | goto err_free_data; 430 | } 431 | #ifdef DEBUG 432 | fprintf(stderr, "post fetch %li -- ", i); 433 | for (ii = 0; ii < *ds_cnt; ii++) 434 | fprintf(stderr, "%10.2f ", *(data_ptr + ii)); 435 | #endif 436 | data_ptr += *ds_cnt; 437 | rra_pointer++; 438 | } 439 | #ifdef DEBUG 440 | fprintf(stderr, "\n"); 441 | #endif 442 | 443 | } 444 | 445 | rrd_close(rrd_file); 446 | rrd_free(&rrd); 447 | 448 | return (0); 449 | err_free_data: 450 | free(*data); 451 | *data = NULL; 452 | err_free_all_ds_namv: 453 | for (i = 0; (unsigned long) i < rrd.stat_head->ds_cnt; ++i) 454 | free((*ds_namv)[i]); 455 | err_free_ds_namv: 456 | free(*ds_namv); 457 | err_close: 458 | rrd_close(rrd_file); 459 | err_free: 460 | rrd_free(&rrd); 461 | return (-1); 462 | } 463 | -------------------------------------------------------------------------------- /src/rrd_first.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_first Return 5 | ***************************************************************************** 6 | * Initial version by Burton Strauss, ntopSupport.com - 3/2005 7 | *****************************************************************************/ 8 | 9 | #include "rrd_tool.h" 10 | 11 | #ifdef WIN32 12 | #include 13 | #endif 14 | 15 | time_t rrd_first( 16 | int argc, 17 | char **argv) 18 | { 19 | int target_rraindex = 0; 20 | char *endptr; 21 | struct option long_options[] = { 22 | {"rraindex", required_argument, 0, 129}, 23 | {0, 0, 0, 0} 24 | }; 25 | 26 | optind = 0; 27 | opterr = 0; /* initialize getopt */ 28 | 29 | while (1) { 30 | int option_index = 0; 31 | int opt; 32 | 33 | opt = getopt_long(argc, argv, "", long_options, &option_index); 34 | 35 | if (opt == EOF) 36 | break; 37 | 38 | switch (opt) { 39 | case 129: 40 | target_rraindex = strtol(optarg, &endptr, 0); 41 | if (target_rraindex < 0) { 42 | rrd_set_error("invalid rraindex number"); 43 | return (-1); 44 | } 45 | break; 46 | default: 47 | rrd_set_error("usage rrdtool %s [--rraindex number] file.rrd", 48 | argv[0]); 49 | return (-1); 50 | } 51 | } 52 | 53 | if (optind >= argc) { 54 | rrd_set_error("not enough arguments"); 55 | return -1; 56 | } 57 | 58 | return (rrd_first_r(argv[optind], target_rraindex)); 59 | } 60 | 61 | 62 | time_t rrd_first_r( 63 | const char *filename, 64 | const int rraindex) 65 | { 66 | off_t rra_start, timer; 67 | time_t then = -1; 68 | rrd_t rrd; 69 | rrd_file_t *rrd_file; 70 | 71 | rrd_file = rrd_open(filename, &rrd, RRD_READONLY); 72 | if (rrd_file == NULL) { 73 | goto err_free; 74 | } 75 | 76 | if ((rraindex < 0) || (rraindex >= (int) rrd.stat_head->rra_cnt)) { 77 | rrd_set_error("invalid rraindex number"); 78 | goto err_close; 79 | } 80 | 81 | rra_start = rrd_file->header_len; 82 | rrd_seek(rrd_file, 83 | (rra_start + 84 | (rrd.rra_ptr[rraindex].cur_row + 1) * 85 | rrd.stat_head->ds_cnt * sizeof(rrd_value_t)), SEEK_SET); 86 | timer = -(long)(rrd.rra_def[rraindex].row_cnt - 1); 87 | if (rrd.rra_ptr[rraindex].cur_row + 1 > rrd.rra_def[rraindex].row_cnt) { 88 | rrd_seek(rrd_file, rra_start, SEEK_SET); 89 | } 90 | then = (rrd.live_head->last_up - 91 | rrd.live_head->last_up % 92 | (rrd.rra_def[rraindex].pdp_cnt * rrd.stat_head->pdp_step)) + 93 | (timer * rrd.rra_def[rraindex].pdp_cnt * rrd.stat_head->pdp_step); 94 | err_close: 95 | rrd_close(rrd_file); 96 | err_free: 97 | rrd_free(&rrd); 98 | return (then); 99 | } 100 | -------------------------------------------------------------------------------- /src/rrd_format.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_format.c RRD Database Format helper functions 5 | ***************************************************************************** 6 | * $Id: rrd_format.c 1946 2009-10-24 10:46:42Z oetiker $ 7 | * $Log$ 8 | * Revision 1.5 2004/05/18 18:53:03 oetiker 9 | * big spell checking patch -- slif@bellsouth.net 10 | * 11 | * Revision 1.4 2003/02/13 07:05:27 oetiker 12 | * Find attached the patch I promised to send to you. Please note that there 13 | * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c 14 | * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This 15 | * library is identical to librrd, but it contains support code for per-thread 16 | * global variables currently used for error information only. This is similar 17 | * to how errno per-thread variables are implemented. librrd_th must be linked 18 | * alongside of libpthred 19 | * 20 | * There is also a new file "THREADS", holding some documentation. 21 | * 22 | * -- Peter Stamfest 23 | * 24 | * Revision 1.3 2002/02/01 20:34:49 oetiker 25 | * fixed version number and date/time 26 | * 27 | * Revision 1.2 2001/03/10 23:54:39 oetiker 28 | * Support for COMPUTE data sources (CDEF data sources). Removes the RPN 29 | * parser and calculator from rrd_graph and puts then in a new file, 30 | * rrd_rpncalc.c. Changes to core files rrd_create and rrd_update. Some 31 | * clean-up of aberrant behavior stuff, including a bug fix. 32 | * Documentation update (rrdcreate.pod, rrdupdate.pod). Change xml format. 33 | * -- Jake Brutlag 34 | * 35 | * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker 36 | * checkin 37 | * 38 | * Revision 1.3 1998/03/08 12:35:11 oetiker 39 | * checkpointing things because the current setup seems to work 40 | * according to the things said in the manpages 41 | * 42 | * Revision 1.2 1998/02/26 22:58:22 oetiker 43 | * fixed define 44 | * 45 | * Revision 1.1 1998/02/21 16:14:41 oetiker 46 | * Initial revision 47 | * 48 | * 49 | *****************************************************************************/ 50 | #include "rrd_tool.h" 51 | 52 | #define converter(VV,VVV) \ 53 | if (strcmp(#VV, string) == 0) return VVV; 54 | 55 | /* conversion functions to allow symbolic entry of enumerations */ 56 | enum dst_en dst_conv( 57 | char *string) 58 | { 59 | converter(COUNTER, DST_COUNTER) 60 | converter(ABSOLUTE, DST_ABSOLUTE) 61 | converter(GAUGE, DST_GAUGE) 62 | converter(DERIVE, DST_DERIVE) 63 | converter(COMPUTE, DST_CDEF) 64 | rrd_set_error("unknown data acquisition function '%s'", string); 65 | return (enum dst_en)(-1); 66 | } 67 | 68 | 69 | enum cf_en cf_conv( 70 | const char *string) 71 | { 72 | 73 | converter(AVERAGE, CF_AVERAGE) 74 | converter(MIN, CF_MINIMUM) 75 | converter(MAX, CF_MAXIMUM) 76 | converter(LAST, CF_LAST) 77 | converter(HWPREDICT, CF_HWPREDICT) 78 | converter(MHWPREDICT, CF_MHWPREDICT) 79 | converter(DEVPREDICT, CF_DEVPREDICT) 80 | converter(SEASONAL, CF_SEASONAL) 81 | converter(DEVSEASONAL, CF_DEVSEASONAL) 82 | converter(FAILURES, CF_FAILURES) 83 | rrd_set_error("unknown consolidation function '%s'", string); 84 | return (enum cf_en)(-1); 85 | } 86 | 87 | #undef converter 88 | 89 | long ds_match( 90 | rrd_t *rrd, 91 | char *ds_nam) 92 | { 93 | unsigned long i; 94 | 95 | for (i = 0; i < rrd->stat_head->ds_cnt; i++) 96 | if ((strcmp(ds_nam, rrd->ds_def[i].ds_nam)) == 0) 97 | return i; 98 | rrd_set_error("unknown data source name '%s'", ds_nam); 99 | return -1; 100 | } 101 | -------------------------------------------------------------------------------- /src/rrd_getopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. 3 | 4 | This file is part of the GNU C Library. Its master source is NOT part of 5 | the C library, however. The master source lives in /gd/gnu/lib. 6 | 7 | The GNU C Library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Library General Public License as 9 | published by the Free Software Foundation; either version 2 of the 10 | License, or (at your option) any later version. 11 | 12 | The GNU C Library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Library General Public License for more details. 16 | 17 | You should have received a copy of the GNU Library General Public 18 | License along with the GNU C Library; see the file COPYING.LIB. If not, 19 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 | Boston, MA 02111-1307, USA. */ 21 | 22 | #ifndef _GETOPT_H 23 | #define _GETOPT_H 1 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | /* For communication from `getopt' to the caller. 30 | When `getopt' finds an option that takes an argument, 31 | the argument value is returned here. 32 | Also, when `ordering' is RETURN_IN_ORDER, 33 | each non-option ARGV-element is returned here. */ 34 | 35 | extern char *optarg; 36 | 37 | /* Index in ARGV of the next element to be scanned. 38 | This is used for communication to and from the caller 39 | and for communication between successive calls to `getopt'. 40 | 41 | On entry to `getopt', zero means this is the first call; initialize. 42 | 43 | When `getopt' returns -1, this is the index of the first of the 44 | non-option elements that the caller should itself scan. 45 | 46 | Otherwise, `optind' communicates from one call to the next 47 | how much of ARGV has been scanned so far. */ 48 | 49 | extern int optind; 50 | 51 | /* Callers store zero here to inhibit the error message `getopt' prints 52 | for unrecognized options. */ 53 | 54 | extern int opterr; 55 | 56 | /* Set to an option character which was unrecognized. */ 57 | 58 | extern int optopt; 59 | 60 | /* Describe the long-named options requested by the application. 61 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 62 | of `struct option' terminated by an element containing a name which is 63 | zero. 64 | 65 | The field `has_arg' is: 66 | no_argument (or 0) if the option does not take an argument, 67 | required_argument (or 1) if the option requires an argument, 68 | optional_argument (or 2) if the option takes an optional argument. 69 | 70 | If the field `flag' is not NULL, it points to a variable that is set 71 | to the value given in the field `val' when the option is found, but 72 | left unchanged if the option is not found. 73 | 74 | To have a long-named option do something other than set an `int' to 75 | a compiled-in constant, such as set a value from `optarg', set the 76 | option's `flag' field to zero and its `val' field to a nonzero 77 | value (the equivalent single-letter option character, if there is 78 | one). For long options that have a zero `flag' field, `getopt' 79 | returns the contents of the `val' field. */ 80 | 81 | struct option { 82 | #if defined (__STDC__) && __STDC__ 83 | const char *name; 84 | #else 85 | char *name; 86 | #endif 87 | /* has_arg can't be an enum because some compilers complain about 88 | type mismatches in all the code that assumes it is an int. */ 89 | int has_arg; 90 | int *flag; 91 | int val; 92 | }; 93 | 94 | /* Names for the values of the `has_arg' field of `struct option'. */ 95 | 96 | #define no_argument 0 97 | #define required_argument 1 98 | #define optional_argument 2 99 | 100 | #if defined (__STDC__) && __STDC__ 101 | #ifdef __GNU_LIBRARY__ 102 | /* Many other libraries have conflicting prototypes for getopt, with 103 | differences in the consts, in stdlib.h. To avoid compilation 104 | errors, only prototype getopt for the GNU C library. */ 105 | extern int getopt( 106 | int argc, 107 | char *const *argv, 108 | const char *shortopts); 109 | #else /* not __GNU_LIBRARY__ */ 110 | extern int getopt( 111 | ); 112 | #endif /* __GNU_LIBRARY__ */ 113 | extern int getopt_long( 114 | int argc, 115 | char *const *argv, 116 | const char *shortopts, 117 | const struct option *longopts, 118 | int *longind); 119 | extern int getopt_long_only( 120 | int argc, 121 | char *const *argv, 122 | const char *shortopts, 123 | const struct option *longopts, 124 | int *longind); 125 | 126 | /* Internal only. Users should not call this directly. */ 127 | extern int _getopt_internal( 128 | int argc, 129 | char *const *argv, 130 | const char *shortopts, 131 | const struct option *longopts, 132 | int *longind, 133 | int long_only); 134 | #else /* not __STDC__ */ 135 | 136 | #ifdef WIN32 137 | int getopt_long(int argc, 138 | char **argv, 139 | const char *options, 140 | const struct option *long_options, 141 | int *opt_index); 142 | int _getopt_internal(int argc, 143 | char **argv, 144 | const char *shortopts, 145 | const struct option *longopts, 146 | int *longind, 147 | int long_only); 148 | #else // WIN32 149 | extern int getopt( 150 | ); 151 | extern int getopt_long( 152 | ); 153 | extern int getopt_long_only( 154 | ); 155 | 156 | extern int _getopt_internal( 157 | ); 158 | #endif // WIN32 159 | 160 | #endif /* __STDC__ */ 161 | 162 | #ifdef __cplusplus 163 | } 164 | #endif 165 | #endif /* _GETOPT_H */ 166 | -------------------------------------------------------------------------------- /src/rrd_getopt1.c: -------------------------------------------------------------------------------- 1 | /* getopt_long and getopt_long_only entry points for GNU getopt. 2 | Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. 3 | 4 | This file is part of the GNU C Library. Its master source is NOT part of 5 | the C library, however. The master source lives in /gd/gnu/lib. 6 | 7 | The GNU C Library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Library General Public License as 9 | published by the Free Software Foundation; either version 2 of the 10 | License, or (at your option) any later version. 11 | 12 | The GNU C Library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Library General Public License for more details. 16 | 17 | You should have received a copy of the GNU Library General Public 18 | License along with the GNU C Library; see the file COPYING.LIB. If not, 19 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 | Boston, MA 02111-1307, USA. */ 21 | 22 | #ifndef WIN32 23 | #if !defined (__STDC__) || !__STDC__ 24 | /* This is a separate conditional since some stdc systems 25 | reject `defined (const)'. */ 26 | #ifndef const 27 | #define const 28 | #endif 29 | #endif 30 | #endif // WIN32 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include "rrd_config.h" 34 | #endif 35 | 36 | #include "rrd_getopt.h" 37 | 38 | #include 39 | 40 | /* Comment out all this code if we are using the GNU C Library, and are not 41 | actually compiling the library itself. This code is part of the GNU C 42 | Library, but also included in many other GNU distributions. Compiling 43 | and linking in this code is a waste when using the GNU C library 44 | (especially if it is a shared library). Rather than having every GNU 45 | program understand `configure --with-gnu-libc' and omit the object files, 46 | it is simpler to just do this in the source for each such file. */ 47 | 48 | #define GETOPT_INTERFACE_VERSION 2 49 | #if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 50 | #include 51 | #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 52 | #define ELIDE_CODE 53 | #endif 54 | #endif 55 | 56 | #ifndef ELIDE_CODE 57 | 58 | 59 | /* This needs to come after some library #include 60 | to get __GNU_LIBRARY__ defined. */ 61 | #ifdef __GNU_LIBRARY__ 62 | #include 63 | #endif 64 | 65 | #ifndef NULL 66 | #define NULL 0 67 | #endif 68 | 69 | #ifdef WIN32 70 | int getopt_long(int argc, 71 | char** argv, 72 | const char* options, 73 | const struct option* long_options, 74 | int* opt_index) 75 | #else // WIN32 76 | int getopt_long( 77 | argc, 78 | argv, 79 | options, 80 | long_options, 81 | opt_index) 82 | int argc; 83 | char *const *argv; 84 | const char *options; 85 | const struct option *long_options; 86 | int *opt_index; 87 | #endif // WIN32 88 | { 89 | return _getopt_internal(argc, argv, options, long_options, opt_index, 0); 90 | } 91 | 92 | /* Like getopt_long, but '-' as well as '--' can indicate a long option. 93 | If an option that starts with '-' (not '--') doesn't match a long option, 94 | but does match a short option, it is parsed as a short option 95 | instead. */ 96 | 97 | #ifdef WIN32 98 | int getopt_long_only(int argc, 99 | char** argv, 100 | const char* options, 101 | const struct option* long_options, 102 | int* opt_index) 103 | #else // WIN32 104 | int getopt_long_only( 105 | argc, 106 | argv, 107 | options, 108 | long_options, 109 | opt_index) 110 | int argc; 111 | char *const *argv; 112 | const char *options; 113 | const struct option *long_options; 114 | int *opt_index; 115 | #endif // WIN32 116 | { 117 | return _getopt_internal(argc, argv, options, long_options, opt_index, 1); 118 | } 119 | 120 | 121 | #endif /* Not ELIDE_CODE. */ 122 | 123 | #ifdef TEST 124 | 125 | #include 126 | 127 | int main( 128 | argc, 129 | argv) 130 | int argc; 131 | char **argv; 132 | { 133 | int c; 134 | int digit_optind = 0; 135 | struct option long_options[] = { 136 | {"add", 1, 0, 0}, 137 | {"append", 0, 0, 0}, 138 | {"delete", 1, 0, 0}, 139 | {"verbose", 0, 0, 0}, 140 | {"create", 0, 0, 0}, 141 | {"file", 1, 0, 0}, 142 | {0, 0, 0, 0} 143 | }; 144 | 145 | while (1) { 146 | int this_option_optind = optind ? optind : 1; 147 | int option_index = 0; 148 | 149 | c = getopt_long(argc, argv, "abc:d:0123456789", 150 | long_options, &option_index); 151 | if (c == -1) 152 | break; 153 | 154 | switch (c) { 155 | case 0: 156 | printf("option %s", long_options[option_index].name); 157 | if (optarg) 158 | printf(" with arg %s", optarg); 159 | printf("\n"); 160 | break; 161 | 162 | case '0': 163 | case '1': 164 | case '2': 165 | case '3': 166 | case '4': 167 | case '5': 168 | case '6': 169 | case '7': 170 | case '8': 171 | case '9': 172 | if (digit_optind != 0 && digit_optind != this_option_optind) 173 | printf("digits occur in two different argv-elements.\n"); 174 | digit_optind = this_option_optind; 175 | printf("option %c\n", c); 176 | break; 177 | 178 | case 'a': 179 | printf("option a\n"); 180 | break; 181 | 182 | case 'b': 183 | printf("option b\n"); 184 | break; 185 | 186 | case 'c': 187 | printf("option c with value `%s'\n", optarg); 188 | break; 189 | 190 | case 'd': 191 | printf("option d with value `%s'\n", optarg); 192 | break; 193 | 194 | case '?': 195 | break; 196 | 197 | default: 198 | printf("?? getopt returned character code 0%o ??\n", c); 199 | } 200 | } 201 | 202 | if (optind < argc) { 203 | printf("non-option ARGV-elements: "); 204 | while (optind < argc) 205 | printf("%s ", argv[optind++]); 206 | printf("\n"); 207 | } 208 | 209 | exit(0); 210 | } 211 | 212 | #endif /* TEST */ 213 | -------------------------------------------------------------------------------- /src/rrd_hw.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_hw.h : Support for Holt-Winters Smoothing/ Aberrant Behavior Detection 5 | *****************************************************************************/ 6 | 7 | /* functions implemented in rrd_hw.c */ 8 | int update_aberrant_CF( 9 | rrd_t *rrd, 10 | rrd_value_t pdp_val, 11 | enum cf_en current_cf, 12 | unsigned long cdp_idx, 13 | unsigned long rra_idx, 14 | unsigned long ds_idx, 15 | unsigned short CDP_scratch_idx, 16 | rrd_value_t *seasonal_coef); 17 | int create_hw_contingent_rras( 18 | rrd_t *rrd, 19 | unsigned short period, 20 | unsigned long hashed_name); 21 | int lookup_seasonal( 22 | rrd_t *rrd, 23 | unsigned long rra_idx, 24 | unsigned long rra_start, 25 | rrd_file_t *rrd_file, 26 | unsigned long offset, 27 | rrd_value_t **seasonal_coef); 28 | void erase_violations( 29 | rrd_t *rrd, 30 | unsigned long cdp_idx, 31 | unsigned long rra_idx); 32 | int apply_smoother( 33 | rrd_t *rrd, 34 | unsigned long rra_idx, 35 | unsigned long rra_start, 36 | rrd_file_t *rrd_file); 37 | void reset_aberrant_coefficients( 38 | rrd_t *rrd, 39 | rrd_file_t *rrd_file, 40 | unsigned long ds_idx); 41 | void init_hwpredict_cdp( 42 | cdp_prep_t *); 43 | void init_seasonal_cdp( 44 | cdp_prep_t *); 45 | 46 | #define BURNIN_CYCLES 3 47 | 48 | /* a standard fixed-capacity FIFO queue implementation */ 49 | typedef struct FIFOqueue { 50 | rrd_value_t *queue; 51 | int capacity, head, tail; 52 | } FIFOqueue; 53 | 54 | int queue_alloc( 55 | FIFOqueue **q, 56 | int capacity); 57 | void queue_dealloc( 58 | FIFOqueue *q); 59 | void queue_push( 60 | FIFOqueue *q, 61 | rrd_value_t value); 62 | int queue_isempty( 63 | FIFOqueue *q); 64 | rrd_value_t queue_pop( 65 | FIFOqueue *q); 66 | -------------------------------------------------------------------------------- /src/rrd_hw_math.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * rrd_hw_math.c Math functions for Holt-Winters computations 3 | *****************************************************************************/ 4 | 5 | #include "rrd_tool.h" 6 | #include "rrd_hw_math.h" 7 | #ifndef WIN32 8 | #include "rrd_config.h" 9 | #endif 10 | 11 | /***************************************************************************** 12 | * RRDtool supports both the additive and multiplicative Holt-Winters methods. 13 | * The additive method makes predictions by adding seasonality to the baseline, 14 | * whereas the multiplicative method multiplies the seasonality coefficient by 15 | * the baseline to make a prediction. This file contains all the differences 16 | * between the additive and multiplicative methods, as well as a few math 17 | * functions common to them both. 18 | ****************************************************************************/ 19 | 20 | /***************************************************************************** 21 | * Functions for additive Holt-Winters 22 | *****************************************************************************/ 23 | 24 | rrd_value_t hw_additive_calculate_prediction( 25 | rrd_value_t intercept, 26 | rrd_value_t slope, 27 | int null_count, 28 | rrd_value_t seasonal_coef) 29 | { 30 | return intercept + slope * null_count + seasonal_coef; 31 | } 32 | 33 | rrd_value_t hw_additive_calculate_intercept( 34 | rrd_value_t hw_alpha, 35 | rrd_value_t observed, 36 | rrd_value_t seasonal_coef, 37 | unival *coefs) 38 | { 39 | return hw_alpha * (observed - seasonal_coef) 40 | + (1 - hw_alpha) * (coefs[CDP_hw_intercept].u_val 41 | + 42 | (coefs[CDP_hw_slope].u_val) * 43 | (coefs[CDP_null_count].u_cnt)); 44 | } 45 | 46 | rrd_value_t hw_additive_calculate_seasonality( 47 | rrd_value_t hw_gamma, 48 | rrd_value_t observed, 49 | rrd_value_t intercept, 50 | rrd_value_t seasonal_coef) 51 | { 52 | return hw_gamma * (observed - intercept) 53 | + (1 - hw_gamma) * seasonal_coef; 54 | } 55 | 56 | rrd_value_t hw_additive_init_seasonality( 57 | rrd_value_t seasonal_coef, 58 | rrd_value_t intercept) 59 | { 60 | return seasonal_coef - intercept; 61 | } 62 | 63 | /***************************************************************************** 64 | * Functions for multiplicative Holt-Winters 65 | *****************************************************************************/ 66 | 67 | rrd_value_t hw_multiplicative_calculate_prediction( 68 | rrd_value_t intercept, 69 | rrd_value_t slope, 70 | int null_count, 71 | rrd_value_t seasonal_coef) 72 | { 73 | return (intercept + slope * null_count) * seasonal_coef; 74 | } 75 | 76 | rrd_value_t hw_multiplicative_calculate_intercept( 77 | rrd_value_t hw_alpha, 78 | rrd_value_t observed, 79 | rrd_value_t seasonal_coef, 80 | unival *coefs) 81 | { 82 | if (seasonal_coef <= 0) { 83 | return DNAN; 84 | } 85 | 86 | return hw_alpha * (observed / seasonal_coef) 87 | + (1 - hw_alpha) * (coefs[CDP_hw_intercept].u_val 88 | + 89 | (coefs[CDP_hw_slope].u_val) * 90 | (coefs[CDP_null_count].u_cnt)); 91 | } 92 | 93 | rrd_value_t hw_multiplicative_calculate_seasonality( 94 | rrd_value_t hw_gamma, 95 | rrd_value_t observed, 96 | rrd_value_t intercept, 97 | rrd_value_t seasonal_coef) 98 | { 99 | if (intercept <= 0) { 100 | return DNAN; 101 | } 102 | 103 | return hw_gamma * (observed / intercept) 104 | + (1 - hw_gamma) * seasonal_coef; 105 | } 106 | 107 | rrd_value_t hw_multiplicative_init_seasonality( 108 | rrd_value_t seasonal_coef, 109 | rrd_value_t intercept) 110 | { 111 | if (intercept <= 0) { 112 | return DNAN; 113 | } 114 | 115 | return seasonal_coef / intercept; 116 | } 117 | 118 | /***************************************************************************** 119 | * Math functions common to additive and multiplicative Holt-Winters 120 | *****************************************************************************/ 121 | 122 | rrd_value_t hw_calculate_slope( 123 | rrd_value_t hw_beta, 124 | unival *coefs) 125 | { 126 | return hw_beta * (coefs[CDP_hw_intercept].u_val - 127 | coefs[CDP_hw_last_intercept].u_val) 128 | + (1 - hw_beta) * coefs[CDP_hw_slope].u_val; 129 | } 130 | 131 | rrd_value_t hw_calculate_seasonal_deviation( 132 | rrd_value_t hw_gamma, 133 | rrd_value_t prediction, 134 | rrd_value_t observed, 135 | rrd_value_t last) 136 | { 137 | return hw_gamma * fabs(prediction - observed) 138 | + (1 - hw_gamma) * last; 139 | } 140 | 141 | rrd_value_t hw_init_seasonal_deviation( 142 | rrd_value_t prediction, 143 | rrd_value_t observed) 144 | { 145 | return fabs(prediction - observed); 146 | } 147 | -------------------------------------------------------------------------------- /src/rrd_hw_math.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * rrd_hw_math.h Math functions for Holt-Winters computations 3 | *****************************************************************************/ 4 | 5 | #include "rrd.h" 6 | #include "rrd_format.h" 7 | 8 | /* since /usr/include/bits/mathcalls.h:265 defines gamma already */ 9 | #define gamma hw_gamma 10 | 11 | /***************************************************************************** 12 | * Functions for additive Holt-Winters 13 | *****************************************************************************/ 14 | 15 | rrd_value_t hw_additive_calculate_prediction( 16 | rrd_value_t intercept, 17 | rrd_value_t slope, 18 | int null_count, 19 | rrd_value_t seasonal_coef); 20 | 21 | rrd_value_t hw_additive_calculate_intercept( 22 | rrd_value_t alpha, 23 | rrd_value_t scratch, 24 | rrd_value_t seasonal_coef, 25 | unival *coefs); 26 | 27 | rrd_value_t hw_additive_calculate_seasonality( 28 | rrd_value_t gamma, 29 | rrd_value_t scratch, 30 | rrd_value_t intercept, 31 | rrd_value_t seasonal_coef); 32 | 33 | rrd_value_t hw_additive_init_seasonality( 34 | rrd_value_t seasonal_coef, 35 | rrd_value_t intercept); 36 | 37 | /***************************************************************************** 38 | * Functions for multiplicative Holt-Winters 39 | *****************************************************************************/ 40 | 41 | rrd_value_t hw_multiplicative_calculate_prediction( 42 | rrd_value_t intercept, 43 | rrd_value_t slope, 44 | int null_count, 45 | rrd_value_t seasonal_coef); 46 | 47 | rrd_value_t hw_multiplicative_calculate_intercept( 48 | rrd_value_t alpha, 49 | rrd_value_t scratch, 50 | rrd_value_t seasonal_coef, 51 | unival *coefs); 52 | 53 | rrd_value_t hw_multiplicative_calculate_seasonality( 54 | rrd_value_t gamma, 55 | rrd_value_t scratch, 56 | rrd_value_t intercept, 57 | rrd_value_t seasonal_coef); 58 | 59 | rrd_value_t hw_multiplicative_init_seasonality( 60 | rrd_value_t seasonal_coef, 61 | rrd_value_t intercept); 62 | 63 | /***************************************************************************** 64 | * Math functions common to additive and multiplicative Holt-Winters 65 | *****************************************************************************/ 66 | 67 | rrd_value_t hw_calculate_slope( 68 | rrd_value_t beta, 69 | unival *coefs); 70 | 71 | rrd_value_t hw_calculate_seasonal_deviation( 72 | rrd_value_t gamma, 73 | rrd_value_t prediction, 74 | rrd_value_t observed, 75 | rrd_value_t last); 76 | 77 | rrd_value_t hw_init_seasonal_deviation( 78 | rrd_value_t prediction, 79 | rrd_value_t observed); 80 | 81 | 82 | /* Function container */ 83 | 84 | typedef struct hw_functions_t { 85 | rrd_value_t ( 86 | *predict) ( 87 | rrd_value_t intercept, 88 | rrd_value_t slope, 89 | int null_count, 90 | rrd_value_t seasonal_coef); 91 | 92 | rrd_value_t ( 93 | *intercept) ( 94 | rrd_value_t alpha, 95 | rrd_value_t observed, 96 | rrd_value_t seasonal_coef, 97 | unival *coefs); 98 | 99 | rrd_value_t ( 100 | *slope) ( 101 | rrd_value_t beta, 102 | unival *coefs); 103 | 104 | rrd_value_t ( 105 | *seasonality) ( 106 | rrd_value_t gamma, 107 | rrd_value_t observed, 108 | rrd_value_t intercept, 109 | rrd_value_t seasonal_coef); 110 | 111 | rrd_value_t ( 112 | *init_seasonality) ( 113 | rrd_value_t seasonal_coef, 114 | rrd_value_t intercept); 115 | 116 | rrd_value_t ( 117 | *seasonal_deviation) ( 118 | rrd_value_t gamma, 119 | rrd_value_t prediction, 120 | rrd_value_t observed, 121 | rrd_value_t last); 122 | 123 | rrd_value_t ( 124 | *init_seasonal_deviation) ( 125 | rrd_value_t prediction, 126 | rrd_value_t observed); 127 | 128 | rrd_value_t identity; 129 | } hw_functions_t; 130 | 131 | 132 | #undef gamma 133 | -------------------------------------------------------------------------------- /src/rrd_hw_update.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * rrd_hw_update.h Functions for updating a Holt-Winters RRA 3 | ****************************************************************************/ 4 | 5 | int update_hwpredict( 6 | rrd_t *rrd, 7 | unsigned long cdp_idx, 8 | unsigned long rra_idx, 9 | unsigned long ds_idx, 10 | unsigned short CDP_scratch_idx, 11 | hw_functions_t * functions); 12 | 13 | int update_seasonal( 14 | rrd_t *rrd, 15 | unsigned long cdp_idx, 16 | unsigned long rra_idx, 17 | unsigned long ds_idx, 18 | unsigned short CDP_scratch_idx, 19 | rrd_value_t *seasonal_coef, 20 | hw_functions_t * functions); 21 | 22 | int update_devpredict( 23 | rrd_t *rrd, 24 | unsigned long cdp_idx, 25 | unsigned long rra_idx, 26 | unsigned long ds_idx, 27 | unsigned short CDP_scratch_idx); 28 | 29 | int update_devseasonal( 30 | rrd_t *rrd, 31 | unsigned long cdp_idx, 32 | unsigned long rra_idx, 33 | unsigned long ds_idx, 34 | unsigned short CDP_scratch_idx, 35 | rrd_value_t *seasonal_dev, 36 | hw_functions_t * functions); 37 | 38 | int update_failures( 39 | rrd_t *rrd, 40 | unsigned long cdp_idx, 41 | unsigned long rra_idx, 42 | unsigned long ds_idx, 43 | unsigned short CDP_scratch_idx, 44 | hw_functions_t * functions); 45 | -------------------------------------------------------------------------------- /src/rrd_i18n.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Takao Fujiwara, 2008 3 | ***************************************************************************** 4 | * rrd_i18n.h Common Header File 5 | *****************************************************************************/ 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | 11 | #ifndef _RRD_I18N_H 12 | #define _RRD_I18N_H 13 | 14 | #ifdef ENABLE_NLS 15 | # ifdef _LIBC 16 | # include 17 | # else 18 | # include "gettext.h" 19 | # define _(String) gettext (String) 20 | # endif 21 | #else 22 | # define _(String) (String) 23 | #endif 24 | 25 | #define N_(String) String 26 | 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /src/rrd_info.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_info Get Information about the configuration of an RRD 5 | *****************************************************************************/ 6 | 7 | #include "rrd_tool.h" 8 | #include "rrd_rpncalc.h" 9 | #include 10 | 11 | #ifdef WIN32 12 | #include 13 | #endif 14 | 15 | /* proto */ 16 | rrd_info_t *rrd_info( 17 | int, 18 | char **); 19 | rrd_info_t *rrd_info_r( 20 | char *filename); 21 | 22 | /* allocate memory for string */ 23 | char *sprintf_alloc( 24 | char *fmt, 25 | ...) 26 | { 27 | char *str = NULL; 28 | va_list argp; 29 | #ifdef HAVE_VASPRINTF 30 | va_start( argp, fmt ); 31 | vasprintf( &str, fmt, argp ); 32 | #else 33 | int maxlen = 1024 + strlen(fmt); 34 | str = (char*)(malloc(sizeof(char) * (maxlen + 1))); 35 | if (str != NULL) { 36 | va_start(argp, fmt); 37 | #ifdef HAVE_VSNPRINTF 38 | vsnprintf(str, maxlen, fmt, argp); 39 | #else 40 | vsprintf(str, fmt, argp); 41 | #endif 42 | } 43 | #endif // HAVE_VASPRINTF 44 | va_end(argp); 45 | return str; 46 | } 47 | 48 | /* the function formerly known as push was renamed to info_push and later 49 | * rrd_info_push because it is now used outside the scope of this file */ 50 | rrd_info_t 51 | * rrd_info_push(rrd_info_t * info, 52 | char *key, rrd_info_type_t type, rrd_infoval_t value) 53 | { 54 | rrd_info_t *next; 55 | 56 | next = (rrd_info_t*)(malloc(sizeof(*next))); 57 | next->next = (rrd_info_t *) 0; 58 | if (info) 59 | info->next = next; 60 | next->type = type; 61 | next->key = key; 62 | switch (type) { 63 | case RD_I_VAL: 64 | next->value.u_val = value.u_val; 65 | break; 66 | case RD_I_CNT: 67 | next->value.u_cnt = value.u_cnt; 68 | break; 69 | case RD_I_INT: 70 | next->value.u_int = value.u_int; 71 | break; 72 | case RD_I_STR: 73 | next->value.u_str = (char*)(malloc(sizeof(char) * (strlen(value.u_str) + 1))); 74 | strcpy(next->value.u_str, value.u_str); 75 | break; 76 | case RD_I_BLO: 77 | next->value.u_blo.size = value.u_blo.size; 78 | next->value.u_blo.ptr = 79 | (unsigned char*)malloc(sizeof(unsigned char) * value.u_blo.size); 80 | memcpy(next->value.u_blo.ptr, value.u_blo.ptr, value.u_blo.size); 81 | break; 82 | } 83 | return (next); 84 | } 85 | 86 | 87 | rrd_info_t *rrd_info( 88 | int argc, 89 | char **argv) 90 | { 91 | rrd_info_t *info; 92 | 93 | if (argc < 2) { 94 | rrd_set_error("please specify an rrd"); 95 | return NULL; 96 | } 97 | 98 | info = rrd_info_r(argv[1]); 99 | 100 | return (info); 101 | } 102 | 103 | 104 | 105 | rrd_info_t *rrd_info_r( 106 | char *filename) 107 | { 108 | unsigned int i, ii = 0; 109 | rrd_t rrd; 110 | rrd_info_t *data = NULL, *cd; 111 | rrd_infoval_t info; 112 | rrd_file_t *rrd_file; 113 | enum cf_en current_cf; 114 | enum dst_en current_ds; 115 | 116 | rrd_file = rrd_open(filename, &rrd, RRD_READONLY); 117 | if (rrd_file == NULL) 118 | goto err_free; 119 | 120 | info.u_str = filename; 121 | cd = rrd_info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info); 122 | data = cd; 123 | 124 | info.u_str = rrd.stat_head->version; 125 | cd = rrd_info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info); 126 | 127 | info.u_cnt = rrd.stat_head->pdp_step; 128 | cd = rrd_info_push(cd, sprintf_alloc("step"), RD_I_CNT, info); 129 | 130 | info.u_cnt = rrd.live_head->last_up; 131 | cd = rrd_info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info); 132 | 133 | for (i = 0; i < rrd.stat_head->ds_cnt; i++) { 134 | 135 | info.u_cnt=i; 136 | cd= rrd_info_push(cd,sprintf_alloc("ds[%s].index", 137 | rrd.ds_def[i].ds_nam), 138 | RD_I_CNT, info); 139 | 140 | info.u_str = rrd.ds_def[i].dst; 141 | cd = rrd_info_push(cd, sprintf_alloc("ds[%s].type", 142 | rrd.ds_def[i].ds_nam), 143 | RD_I_STR, info); 144 | 145 | current_ds = dst_conv(rrd.ds_def[i].dst); 146 | switch (current_ds) { 147 | case DST_CDEF: 148 | { 149 | char *buffer = NULL; 150 | 151 | rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]), 152 | rrd.ds_def, &buffer); 153 | info.u_str = buffer; 154 | cd = rrd_info_push(cd, 155 | sprintf_alloc("ds[%s].cdef", 156 | rrd.ds_def[i].ds_nam), RD_I_STR, 157 | info); 158 | free(buffer); 159 | } 160 | break; 161 | default: 162 | info.u_cnt = rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt; 163 | cd = rrd_info_push(cd, 164 | sprintf_alloc("ds[%s].minimal_heartbeat", 165 | rrd.ds_def[i].ds_nam), RD_I_CNT, 166 | info); 167 | 168 | info.u_val = rrd.ds_def[i].par[DS_min_val].u_val; 169 | cd = rrd_info_push(cd, 170 | sprintf_alloc("ds[%s].min", 171 | rrd.ds_def[i].ds_nam), RD_I_VAL, 172 | info); 173 | 174 | info.u_val = rrd.ds_def[i].par[DS_max_val].u_val; 175 | cd = rrd_info_push(cd, 176 | sprintf_alloc("ds[%s].max", 177 | rrd.ds_def[i].ds_nam), RD_I_VAL, 178 | info); 179 | break; 180 | } 181 | 182 | info.u_str = rrd.pdp_prep[i].last_ds; 183 | cd = rrd_info_push(cd, 184 | sprintf_alloc("ds[%s].last_ds", 185 | rrd.ds_def[i].ds_nam), RD_I_STR, 186 | info); 187 | 188 | info.u_val = rrd.pdp_prep[i].scratch[PDP_val].u_val; 189 | cd = rrd_info_push(cd, 190 | sprintf_alloc("ds[%s].value", 191 | rrd.ds_def[i].ds_nam), RD_I_VAL, 192 | info); 193 | 194 | info.u_cnt = rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt; 195 | cd = rrd_info_push(cd, 196 | sprintf_alloc("ds[%s].unknown_sec", 197 | rrd.ds_def[i].ds_nam), RD_I_CNT, 198 | info); 199 | } 200 | 201 | for (i = 0; i < rrd.stat_head->rra_cnt; i++) { 202 | info.u_str = rrd.rra_def[i].cf_nam; 203 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR, 204 | info); 205 | current_cf = cf_conv(rrd.rra_def[i].cf_nam); 206 | 207 | info.u_cnt = rrd.rra_def[i].row_cnt; 208 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT, 209 | info); 210 | 211 | info.u_cnt = rrd.rra_ptr[i].cur_row; 212 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cur_row", i), RD_I_CNT, 213 | info); 214 | 215 | info.u_cnt = rrd.rra_def[i].pdp_cnt; 216 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i), 217 | RD_I_CNT, info); 218 | 219 | switch (current_cf) { 220 | case CF_HWPREDICT: 221 | case CF_MHWPREDICT: 222 | info.u_val = rrd.rra_def[i].par[RRA_hw_alpha].u_val; 223 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].alpha", i), 224 | RD_I_VAL, info); 225 | info.u_val = rrd.rra_def[i].par[RRA_hw_beta].u_val; 226 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL, 227 | info); 228 | break; 229 | case CF_SEASONAL: 230 | case CF_DEVSEASONAL: 231 | info.u_val = rrd.rra_def[i].par[RRA_seasonal_gamma].u_val; 232 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].gamma", i), 233 | RD_I_VAL, info); 234 | if (atoi(rrd.stat_head->version) >= 4) { 235 | info.u_val = 236 | rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val; 237 | cd = rrd_info_push(cd, 238 | sprintf_alloc("rra[%d].smoothing_window", 239 | i), RD_I_VAL, info); 240 | } 241 | break; 242 | case CF_FAILURES: 243 | info.u_val = rrd.rra_def[i].par[RRA_delta_pos].u_val; 244 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_pos", i), 245 | RD_I_VAL, info); 246 | info.u_val = rrd.rra_def[i].par[RRA_delta_neg].u_val; 247 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_neg", i), 248 | RD_I_VAL, info); 249 | info.u_cnt = rrd.rra_def[i].par[RRA_failure_threshold].u_cnt; 250 | cd = rrd_info_push(cd, 251 | sprintf_alloc("rra[%d].failure_threshold", i), 252 | RD_I_CNT, info); 253 | info.u_cnt = rrd.rra_def[i].par[RRA_window_len].u_cnt; 254 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].window_length", i), 255 | RD_I_CNT, info); 256 | break; 257 | case CF_DEVPREDICT: 258 | break; 259 | default: 260 | info.u_val = rrd.rra_def[i].par[RRA_cdp_xff_val].u_val; 261 | cd = rrd_info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL, 262 | info); 263 | break; 264 | } 265 | 266 | for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++) { 267 | switch (current_cf) { 268 | case CF_HWPREDICT: 269 | case CF_MHWPREDICT: 270 | info.u_val = 271 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 272 | ii].scratch[CDP_hw_intercept].u_val; 273 | cd = rrd_info_push(cd, 274 | sprintf_alloc 275 | ("rra[%d].cdp_prep[%d].intercept", i, ii), 276 | RD_I_VAL, info); 277 | info.u_val = 278 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 279 | ii].scratch[CDP_hw_slope].u_val; 280 | cd = rrd_info_push(cd, 281 | sprintf_alloc("rra[%d].cdp_prep[%d].slope", 282 | i, ii), RD_I_VAL, info); 283 | info.u_cnt = 284 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 285 | ii].scratch[CDP_null_count].u_cnt; 286 | cd = rrd_info_push(cd, 287 | sprintf_alloc 288 | ("rra[%d].cdp_prep[%d].NaN_count", i, ii), 289 | RD_I_CNT, info); 290 | break; 291 | case CF_SEASONAL: 292 | info.u_val = 293 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 294 | ii].scratch[CDP_hw_seasonal].u_val; 295 | cd = rrd_info_push(cd, 296 | sprintf_alloc 297 | ("rra[%d].cdp_prep[%d].seasonal", i, ii), 298 | RD_I_VAL, info); 299 | break; 300 | case CF_DEVSEASONAL: 301 | info.u_val = 302 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 303 | ii].scratch[CDP_seasonal_deviation].u_val; 304 | cd = rrd_info_push(cd, 305 | sprintf_alloc 306 | ("rra[%d].cdp_prep[%d].deviation", i, ii), 307 | RD_I_VAL, info); 308 | break; 309 | case CF_DEVPREDICT: 310 | break; 311 | case CF_FAILURES: 312 | { 313 | unsigned short j; 314 | char *violations_array; 315 | char history[MAX_FAILURES_WINDOW_LEN + 1]; 316 | 317 | violations_array = 318 | (char *) rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 319 | ii].scratch; 320 | for (j = 0; j < rrd.rra_def[i].par[RRA_window_len].u_cnt; ++j) 321 | history[j] = (violations_array[j] == 1) ? '1' : '0'; 322 | history[j] = '\0'; 323 | info.u_str = history; 324 | cd = rrd_info_push(cd, 325 | sprintf_alloc 326 | ("rra[%d].cdp_prep[%d].history", i, ii), 327 | RD_I_STR, info); 328 | } 329 | break; 330 | default: 331 | info.u_val = 332 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 333 | ii].scratch[CDP_val].u_val; 334 | cd = rrd_info_push(cd, 335 | sprintf_alloc("rra[%d].cdp_prep[%d].value", 336 | i, ii), RD_I_VAL, info); 337 | info.u_cnt = 338 | rrd.cdp_prep[i * rrd.stat_head->ds_cnt + 339 | ii].scratch[CDP_unkn_pdp_cnt].u_cnt; 340 | cd = rrd_info_push(cd, 341 | sprintf_alloc 342 | ("rra[%d].cdp_prep[%d].unknown_datapoints", 343 | i, ii), RD_I_CNT, info); 344 | break; 345 | } 346 | } 347 | } 348 | 349 | rrd_close(rrd_file); 350 | err_free: 351 | rrd_free(&rrd); 352 | return (data); 353 | } 354 | 355 | 356 | void rrd_info_print( 357 | rrd_info_t * data) 358 | { 359 | while (data) { 360 | printf("%s = ", data->key); 361 | 362 | switch (data->type) { 363 | case RD_I_VAL: 364 | if (isnan(data->value.u_val)) 365 | printf("NaN\n"); 366 | else 367 | printf("%0.10e\n", data->value.u_val); 368 | break; 369 | case RD_I_CNT: 370 | printf("%lu\n", data->value.u_cnt); 371 | break; 372 | case RD_I_INT: 373 | printf("%d\n", data->value.u_int); 374 | break; 375 | case RD_I_STR: 376 | printf("\"%s\"\n", data->value.u_str); 377 | break; 378 | case RD_I_BLO: 379 | printf("BLOB_SIZE:%lu\n", data->value.u_blo.size); 380 | fwrite(data->value.u_blo.ptr, data->value.u_blo.size, 1, stdout); 381 | break; 382 | } 383 | data = data->next; 384 | } 385 | } 386 | 387 | void rrd_info_free( 388 | rrd_info_t * data) 389 | { 390 | rrd_info_t *save; 391 | 392 | while (data) { 393 | save = data; 394 | if (data->key) { 395 | if (data->type == RD_I_STR) { 396 | free(data->value.u_str); 397 | } 398 | if (data->type == RD_I_BLO) { 399 | free(data->value.u_blo.ptr); 400 | } 401 | free(data->key); 402 | } 403 | data = data->next; 404 | free(save); 405 | } 406 | } 407 | -------------------------------------------------------------------------------- /src/rrd_is_thread_safe.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | * This file: Copyright 2003 Peter Stamfest 4 | * & Tobias Oetiker 5 | * Distributed under the GPL 6 | ***************************************************************************** 7 | * rrd_is_thread_safe.c Poisons some nasty function calls using GNU cpp 8 | ***************************************************************************** 9 | * $Id: rrd_is_thread_safe.h 1946 2009-10-24 10:46:42Z oetiker $ 10 | *************************************************************************** */ 11 | 12 | #ifndef _RRD_IS_THREAD_SAFE_H 13 | #define _RRD_IS_THREAD_SAFE_H 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #undef strerror 20 | 21 | #if( 2 < __GNUC__ ) 22 | #pragma GCC poison strtok asctime ctime gmtime localtime tmpnam strerror 23 | #endif 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | #endif /*_RRD_IS_THREAD_SAFE_H */ 29 | -------------------------------------------------------------------------------- /src/rrd_last.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_last.c 5 | ***************************************************************************** 6 | * Initial version by Russ Wright, @Home Network, 9/28/98 7 | *****************************************************************************/ 8 | 9 | #include "rrd_tool.h" 10 | 11 | time_t rrd_last( 12 | int argc, 13 | char **argv) 14 | { 15 | if (argc < 2) { 16 | rrd_set_error("please specify an rrd"); 17 | return (-1); 18 | } 19 | 20 | return (rrd_last_r(argv[1])); 21 | } 22 | 23 | 24 | time_t rrd_last_r( 25 | const char *filename) 26 | { 27 | time_t lastup = -1; 28 | rrd_file_t *rrd_file; 29 | 30 | rrd_t rrd; 31 | 32 | rrd_file = rrd_open(filename, &rrd, RRD_READONLY); 33 | if (rrd_file != NULL) { 34 | lastup = rrd.live_head->last_up; 35 | rrd_close(rrd_file); 36 | } 37 | rrd_free(&rrd); 38 | return (lastup); 39 | } 40 | -------------------------------------------------------------------------------- /src/rrd_lastupdate.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_lastupdate Get the last datum entered for each DS 5 | *****************************************************************************/ 6 | 7 | #include "rrd_tool.h" 8 | #include "rrd_rpncalc.h" 9 | #include 10 | 11 | #ifdef WIN32 12 | #include 13 | #endif 14 | 15 | int rrd_lastupdate( 16 | int argc, 17 | char **argv, 18 | time_t *last_update, 19 | unsigned long *ds_cnt, 20 | char ***ds_namv, 21 | char ***last_ds) 22 | { 23 | unsigned long i = 0; 24 | char *filename; 25 | rrd_t rrd; 26 | rrd_file_t *rrd_file; 27 | 28 | if (argc < 2) { 29 | rrd_set_error("please specify an rrd"); 30 | goto err_out; 31 | } 32 | filename = argv[1]; 33 | 34 | rrd_file = rrd_open(filename, &rrd, RRD_READONLY); 35 | if (rrd_file == NULL) 36 | goto err_free; 37 | 38 | *last_update = rrd.live_head->last_up; 39 | *ds_cnt = rrd.stat_head->ds_cnt; 40 | if (((*ds_namv) = 41 | (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) { 42 | rrd_set_error("malloc fetch ds_namv array"); 43 | goto err_close; 44 | } 45 | 46 | if (((*last_ds) = 47 | (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) { 48 | rrd_set_error("malloc fetch last_ds array"); 49 | goto err_free_ds_namv; 50 | } 51 | 52 | for (i = 0; i < rrd.stat_head->ds_cnt; i++) { 53 | (*ds_namv)[i] = sprintf_alloc("%s", rrd.ds_def[i].ds_nam); 54 | (*last_ds)[i] = sprintf_alloc("%s", rrd.pdp_prep[i].last_ds); 55 | } 56 | 57 | rrd_free(&rrd); 58 | rrd_close(rrd_file); 59 | return (0); 60 | 61 | err_free_ds_namv: 62 | free(*ds_namv); 63 | err_close: 64 | rrd_close(rrd_file); 65 | err_free: 66 | rrd_free(&rrd); 67 | err_out: 68 | return (-1); 69 | } 70 | -------------------------------------------------------------------------------- /src/rrd_nan_inf.c: -------------------------------------------------------------------------------- 1 | int done_nan = 0; 2 | int done_inf = 0; 3 | 4 | double dnan; 5 | double dinf; 6 | 7 | #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) 8 | #include 9 | #include "rrd.h" 10 | 11 | #define NAN_FUNC (double)fmod(0.0,0.0) 12 | #define INF_FUNC (double)fabs((double)log(0.0)) 13 | 14 | #else 15 | #include "rrd.h" 16 | 17 | #define NAN_FUNC (double)(0.0/0.0) 18 | #define INF_FUNC (double)(1.0/0.0) 19 | 20 | #endif 21 | 22 | double rrd_set_to_DNAN( 23 | void) 24 | { 25 | if (!done_nan) { 26 | dnan = NAN_FUNC; 27 | done_nan = 1; 28 | } 29 | return dnan; 30 | } 31 | 32 | double rrd_set_to_DINF( 33 | void) 34 | { 35 | if (!done_inf) { 36 | dinf = INF_FUNC; 37 | done_inf = 1; 38 | } 39 | return dinf; 40 | } 41 | -------------------------------------------------------------------------------- /src/rrd_parsetime.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARSETIME_H__ 2 | #define __PARSETIME_H__ 3 | 4 | #include 5 | 6 | #include "rrd.h" 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/rrd_resize.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_resize.c Alters size of an RRA 5 | ***************************************************************************** 6 | * Initial version by Alex van den Bogaerdt 7 | *****************************************************************************/ 8 | 9 | #include "rrd_tool.h" 10 | 11 | #ifdef WIN32 12 | #include 13 | #endif 14 | 15 | int rrd_resize( 16 | int argc, 17 | char **argv) 18 | { 19 | char *infilename, outfilename[11] = "resize.rrd"; 20 | rrd_t rrdold, rrdnew; 21 | rrd_value_t buffer; 22 | int version; 23 | unsigned long l, rra; 24 | long modify; 25 | unsigned long target_rra; 26 | int grow = 0, shrink = 0; 27 | char *endptr; 28 | rrd_file_t *rrd_file, *rrd_out_file; 29 | 30 | infilename = argv[1]; 31 | if (!strcmp(infilename, "resize.rrd")) { 32 | rrd_set_error("resize.rrd is a reserved name"); 33 | return (-1); 34 | } 35 | if (argc != 5) { 36 | rrd_set_error("wrong number of parameters"); 37 | return (-1); 38 | } 39 | 40 | target_rra = strtol(argv[2], &endptr, 0); 41 | 42 | if (!strcmp(argv[3], "GROW")) 43 | grow = 1; 44 | else if (!strcmp(argv[3], "SHRINK")) 45 | shrink = 1; 46 | else { 47 | rrd_set_error("I can only GROW or SHRINK"); 48 | return (-1); 49 | } 50 | 51 | modify = strtol(argv[4], &endptr, 0); 52 | 53 | if ((modify < 1)) { 54 | rrd_set_error("Please grow or shrink with at least 1 row"); 55 | return (-1); 56 | } 57 | 58 | if (shrink) 59 | modify = -modify; 60 | 61 | 62 | rrd_file = rrd_open(infilename, &rrdold, RRD_READWRITE | RRD_COPY); 63 | if (rrd_file == NULL) { 64 | rrd_free(&rrdold); 65 | return (-1); 66 | } 67 | 68 | #ifndef ESP32 69 | if (rrd_lock(rrd_file) != 0) { 70 | rrd_set_error("could not lock original RRD"); 71 | rrd_free(&rrdold); 72 | rrd_close(rrd_file); 73 | return (-1); 74 | } 75 | #endif 76 | 77 | 78 | if (target_rra >= rrdold.stat_head->rra_cnt) { 79 | rrd_set_error("no such RRA in this RRD"); 80 | rrd_free(&rrdold); 81 | rrd_close(rrd_file); 82 | return (-1); 83 | } 84 | 85 | if (modify < 0) 86 | if ((long) rrdold.rra_def[target_rra].row_cnt <= -modify) { 87 | rrd_set_error("This RRA is not that big"); 88 | rrd_free(&rrdold); 89 | rrd_close(rrd_file); 90 | return (-1); 91 | } 92 | /* the size of the new file */ 93 | /* yes we are abusing the float cookie for this, aargh */ 94 | if ((rrdnew.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) { 95 | rrd_set_error("allocating stat_head for new RRD"); 96 | rrd_free(&rrdold); 97 | rrd_close(rrd_file); 98 | return (-1); 99 | } 100 | rrdnew.stat_head->float_cookie = rrd_file->file_len + 101 | (rrdold.stat_head->ds_cnt * sizeof(rrd_value_t) * modify); 102 | rrd_out_file = rrd_open(outfilename, &rrdnew, RRD_READWRITE | RRD_CREAT); 103 | if (rrd_out_file == NULL) { 104 | rrd_set_error("Can't create '%s': %s", outfilename, 105 | rrd_strerror(errno)); 106 | rrd_free(&rrdnew); 107 | rrd_free(&rrdold); 108 | rrd_close(rrd_file); 109 | rrd_close(rrd_out_file); 110 | return (-1); 111 | } 112 | #ifndef ESP32 113 | if (rrd_lock(rrd_out_file) != 0) { 114 | rrd_set_error("could not lock new RRD"); 115 | rrd_free(&rrdnew); 116 | rrd_free(&rrdold); 117 | rrd_close(rrd_file); 118 | rrd_close(rrd_out_file); 119 | return (-1); 120 | } 121 | #endif 122 | /*XXX: do one write for those parts of header that are unchanged */ 123 | if ((rrdnew.stat_head = (stat_head_t*)malloc(sizeof(stat_head_t))) == NULL) { 124 | rrd_set_error("allocating stat_head for new RRD"); 125 | rrd_free(&rrdnew); 126 | rrd_free(&rrdold); 127 | rrd_close(rrd_file); 128 | rrd_close(rrd_out_file); 129 | return (-1); 130 | } 131 | 132 | if ((rrdnew.rra_ptr = (rra_ptr_t*)malloc(sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt)) == NULL) { 133 | rrd_set_error("allocating rra_ptr for new RRD"); 134 | rrd_free(&rrdnew); 135 | rrd_free(&rrdold); 136 | rrd_close(rrd_file); 137 | rrd_close(rrd_out_file); 138 | return (-1); 139 | } 140 | 141 | if ((rrdnew.rra_def = (rra_def_t*)malloc(sizeof(rra_def_t) * rrdold.stat_head->rra_cnt)) == NULL) { 142 | rrd_set_error("allocating rra_def for new RRD"); 143 | rrd_free(&rrdnew); 144 | rrd_free(&rrdold); 145 | rrd_close(rrd_file); 146 | rrd_close(rrd_out_file); 147 | return (-1); 148 | } 149 | 150 | memcpy(rrdnew.stat_head,rrdold.stat_head,sizeof(stat_head_t)); 151 | rrdnew.ds_def = rrdold.ds_def; 152 | 153 | /* we are going to free rrdold later on, so make sure its not still pointing to the new stuff */ 154 | rrdold.live_head = NULL; 155 | memcpy(rrdnew.rra_def,rrdold.rra_def,sizeof(rra_def_t) * rrdold.stat_head->rra_cnt); 156 | rrdnew.live_head = rrdold.live_head; 157 | rrdold.live_head = NULL; 158 | rrdnew.pdp_prep = rrdold.pdp_prep; 159 | rrdold.pdp_prep = NULL; 160 | rrdnew.cdp_prep = rrdold.cdp_prep; 161 | rrdold.cdp_prep = NULL; 162 | memcpy(rrdnew.rra_ptr,rrdold.rra_ptr,sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt); 163 | 164 | version = atoi(rrdold.stat_head->version); 165 | switch (version) { 166 | case 4: 167 | break; 168 | case 3: 169 | break; 170 | case 1: 171 | rrdnew.stat_head->version[3] = '3'; 172 | break; 173 | default: 174 | rrd_set_error("Do not know how to handle RRD version %s", 175 | rrdold.stat_head->version); 176 | rrd_free(&rrdnew); 177 | rrd_free(&rrdold); 178 | rrd_close(rrd_file); 179 | rrd_close(rrd_out_file); 180 | return (-1); 181 | break; 182 | } 183 | 184 | /* XXX: Error checking? */ 185 | rrd_write(rrd_out_file, rrdnew.stat_head, sizeof(stat_head_t) * 1); 186 | rrd_write(rrd_out_file, rrdnew.ds_def, 187 | sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt); 188 | rrd_write(rrd_out_file, rrdnew.rra_def, 189 | sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt); 190 | rrd_write(rrd_out_file, rrdnew.live_head, sizeof(live_head_t) * 1); 191 | rrd_write(rrd_out_file, rrdnew.pdp_prep, 192 | sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt); 193 | rrd_write(rrd_out_file, rrdnew.cdp_prep, 194 | sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt * 195 | rrdnew.stat_head->rra_cnt); 196 | rrd_write(rrd_out_file, rrdnew.rra_ptr, 197 | sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt); 198 | 199 | /* Move the CDPs from the old to the new database. 200 | ** This can be made (much) faster but isn't worth the effort. Clarity 201 | ** is much more important. 202 | */ 203 | 204 | /* Move data in unmodified RRAs 205 | */ 206 | l = 0; 207 | for (rra = 0; rra < target_rra; rra++) { 208 | l += rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt; 209 | } 210 | while (l > 0) { 211 | rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1); 212 | rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); 213 | l--; 214 | } 215 | /* Move data in this RRA, either removing or adding some rows 216 | */ 217 | if (modify > 0) { 218 | /* Adding extra rows; insert unknown values just after the 219 | ** current row number. 220 | */ 221 | l = rrdnew.stat_head->ds_cnt * 222 | (rrdnew.rra_ptr[target_rra].cur_row + 1); 223 | while (l > 0) { 224 | rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1); 225 | rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); 226 | l--; 227 | } 228 | buffer = DNAN; 229 | l = rrdnew.stat_head->ds_cnt * modify; 230 | while (l > 0) { 231 | rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); 232 | l--; 233 | } 234 | } else { 235 | /* Removing rows. Normally this would be just after the cursor 236 | ** however this may also mean that we wrap to the beginning of 237 | ** the array. 238 | */ 239 | signed long int remove_end = 0; 240 | 241 | remove_end = 242 | (rrdnew.rra_ptr[target_rra].cur_row - 243 | modify) % rrdnew.rra_def[target_rra].row_cnt; 244 | if (remove_end <= 245 | (signed long int) rrdnew.rra_ptr[target_rra].cur_row) { 246 | while (remove_end >= 0) { 247 | rrd_seek(rrd_file, 248 | sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt, 249 | SEEK_CUR); 250 | rrdnew.rra_ptr[target_rra].cur_row--; 251 | rrdnew.rra_def[target_rra].row_cnt--; 252 | remove_end--; 253 | modify++; 254 | } 255 | remove_end = rrdnew.rra_def[target_rra].row_cnt - 1; 256 | } 257 | for (l = 0; l <= rrdnew.rra_ptr[target_rra].cur_row; l++) { 258 | unsigned int tmp; 259 | 260 | for (tmp = 0; tmp < rrdnew.stat_head->ds_cnt; tmp++) { 261 | rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1); 262 | rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); 263 | } 264 | } 265 | while (modify < 0) { 266 | rrd_seek(rrd_file, 267 | sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt, 268 | SEEK_CUR); 269 | rrdnew.rra_def[target_rra].row_cnt--; 270 | modify++; 271 | } 272 | } 273 | /* Move the rest of the CDPs 274 | */ 275 | while (1) { 276 | if (rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1) <= 0) 277 | break; 278 | rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); 279 | } 280 | rrdnew.rra_def[target_rra].row_cnt += modify; 281 | rrd_seek(rrd_out_file, 282 | sizeof(stat_head_t) + 283 | sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt, SEEK_SET); 284 | rrd_write(rrd_out_file, rrdnew.rra_def, 285 | sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt); 286 | rrd_seek(rrd_out_file, sizeof(live_head_t), SEEK_CUR); 287 | rrd_seek(rrd_out_file, sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt, 288 | SEEK_CUR); 289 | rrd_seek(rrd_out_file, 290 | sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt * 291 | rrdnew.stat_head->rra_cnt, SEEK_CUR); 292 | rrd_write(rrd_out_file, rrdnew.rra_ptr, 293 | sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt); 294 | rrd_close(rrd_file); 295 | rrd_close(rrd_out_file); 296 | rrd_free(&rrdold); 297 | rrd_free(&rrdnew); 298 | return (0); 299 | } 300 | -------------------------------------------------------------------------------- /src/rrd_rpncalc.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | **************************************************************************** 4 | * rrd_rpncalc.h RPN calculator functions 5 | ****************************************************************************/ 6 | #ifndef _RRD_RPNCALC_H 7 | #define _RRD_RPNCALC_H 8 | 9 | /* WARNING: if new operators are added, they MUST be added at the very end of the list. 10 | * This is because COMPUTE (CDEF) DS store OP nodes by number (name is not 11 | * an option due to limited par array size). OP nodes must have the same 12 | * numeric values, otherwise the stored numbers will mean something different. */ 13 | enum op_en { OP_NUMBER = 0, OP_VARIABLE, OP_INF, OP_PREV, OP_NEGINF, 14 | OP_UNKN, OP_NOW, OP_TIME, OP_ADD, OP_MOD, OP_SUB, OP_MUL, 15 | OP_DIV, OP_SIN, OP_DUP, OP_EXC, OP_POP, 16 | OP_COS, OP_LOG, OP_EXP, OP_LT, OP_LE, OP_GT, OP_GE, OP_EQ, OP_IF, 17 | OP_MIN, OP_MAX, OP_LIMIT, OP_FLOOR, OP_CEIL, 18 | OP_UN, OP_END, OP_LTIME, OP_NE, OP_ISINF, OP_PREV_OTHER, OP_COUNT, 19 | OP_ATAN, OP_SQRT, OP_SORT, OP_REV, OP_TREND, OP_TRENDNAN, 20 | OP_ATAN2, OP_RAD2DEG, OP_DEG2RAD, 21 | OP_AVG, OP_ABS, OP_ADDNAN 22 | }; 23 | 24 | typedef struct rpnp_t { 25 | enum op_en op; 26 | double val; /* value for a OP_NUMBER */ 27 | long ptr; /* pointer into the gdes array for OP_VAR */ 28 | double *data; /* pointer to the current value from OP_VAR DAS */ 29 | long ds_cnt; /* data source count for data pointer */ 30 | long step; /* time step for OP_VAR das */ 31 | } rpnp_t; 32 | 33 | /* a compact representation of rpnp_t for computed data sources */ 34 | typedef struct rpn_cdefds_t { 35 | char op; /* rpn operator type */ 36 | short val; /* used by OP_NUMBER and OP_VARIABLE */ 37 | } rpn_cdefds_t; 38 | 39 | #define MAX_VNAME_LEN 255 40 | #define DEF_NAM_FMT "%255[-_A-Za-z0-9]" 41 | 42 | /* limit imposed by sizeof(rpn_cdefs_t) and rrd.ds_def.par */ 43 | #define DS_CDEF_MAX_RPN_NODES 26 44 | 45 | typedef struct rpnstack_t { 46 | double *s; 47 | long dc_stacksize; 48 | long dc_stackblock; 49 | } rpnstack_t; 50 | 51 | void rpnstack_init( 52 | rpnstack_t *rpnstack); 53 | void rpnstack_free( 54 | rpnstack_t *rpnstack); 55 | 56 | void parseCDEF_DS( 57 | const char *def, 58 | rrd_t *rrd, 59 | int ds_idx); 60 | long lookup_DS( 61 | void *rrd_vptr, 62 | char *ds_name); 63 | 64 | short rpn_compact( 65 | rpnp_t *rpnp, 66 | rpn_cdefds_t **rpnc, 67 | short *count); 68 | rpnp_t *rpn_expand( 69 | rpn_cdefds_t *rpnc); 70 | void rpn_compact2str( 71 | rpn_cdefds_t *rpnc, 72 | ds_def_t *ds_def, 73 | char **str); 74 | rpnp_t *rpn_parse( 75 | void *key_hash, 76 | const char *const expr, 77 | long (*lookup) (void *, 78 | char *)); 79 | short rpn_calc( 80 | rpnp_t *rpnp, 81 | rpnstack_t *rpnstack, 82 | long data_idx, 83 | rrd_value_t *output, 84 | int output_idx); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/rrd_thread_safe.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | * This file: Copyright 2003 Peter Stamfest 4 | * & Tobias Oetiker 5 | * Distributed under the GPL 6 | ***************************************************************************** 7 | * rrd_thread_safe.c Contains routines used when thread safety is required 8 | ***************************************************************************** 9 | * $Id: rrd_thread_safe.c 1946 2009-10-24 10:46:42Z oetiker $ 10 | *************************************************************************** */ 11 | 12 | #include 13 | #include 14 | /* #include */ 15 | #include "rrd.h" 16 | #include "rrd_tool.h" 17 | 18 | /* Key for the thread-specific rrd_context */ 19 | static pthread_key_t context_key; 20 | 21 | /* Once-only initialisation of the key */ 22 | static pthread_once_t context_key_once = PTHREAD_ONCE_INIT; 23 | 24 | /* Free the thread-specific rrd_context - we might actually use 25 | rrd_free_context instead... 26 | */ 27 | static void context_destroy_context( 28 | void *ctx_) 29 | { 30 | rrd_context_t *ctx = ctx_; 31 | 32 | if (ctx) 33 | rrd_free_context(ctx); 34 | } 35 | 36 | /* Allocate the key */ 37 | static void context_get_key( 38 | void) 39 | { 40 | pthread_key_create(&context_key, context_destroy_context); 41 | } 42 | 43 | rrd_context_t *rrd_get_context( 44 | void) 45 | { 46 | rrd_context_t *ctx; 47 | 48 | pthread_once(&context_key_once, context_get_key); 49 | ctx = pthread_getspecific(context_key); 50 | if (!ctx) { 51 | ctx = rrd_new_context(); 52 | pthread_setspecific(context_key, ctx); 53 | } 54 | return ctx; 55 | } 56 | 57 | #ifdef HAVE_STRERROR_R 58 | const char *rrd_strerror( 59 | int err) 60 | { 61 | rrd_context_t *ctx = rrd_get_context(); 62 | char *ret = "unknown error"; 63 | 64 | *ctx->lib_errstr = '\0'; 65 | 66 | /* Even though POSIX/XSI requires "strerror_r" to return an "int", some 67 | * systems (e.g. the GNU libc) return a "char *" _and_ ignore the second 68 | * argument ... -tokkee */ 69 | #if STRERROR_R_CHAR_P 70 | ret = strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr)); 71 | if ((! ret) || (*ret == '\0')) { 72 | if (*ctx->lib_errstr != '\0') 73 | ret = ctx->lib_errstr; 74 | else { 75 | /* according to the manpage this should not happen - 76 | let's handle it somehow sanely anyway */ 77 | snprintf(ctx->lib_errstr, sizeof(ctx->lib_errstr), 78 | "unknown error %i - strerror_r did not return anything", 79 | err); 80 | ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0'; 81 | ret = ctx->lib_errstr; 82 | } 83 | } 84 | #else /* ! STRERROR_R_CHAR_P */ 85 | if (strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr))) { 86 | snprintf(ctx->lib_errstr, sizeof(ctx->lib_errstr), 87 | "unknown error %i - strerror_r returned with errno = %i", 88 | err, errno); 89 | ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0'; 90 | } 91 | ret = ctx->lib_errstr; 92 | #endif 93 | return ret; 94 | } 95 | #else 96 | #undef strerror 97 | const char *rrd_strerror( 98 | int err) 99 | { 100 | static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 101 | rrd_context_t *ctx; 102 | 103 | ctx = rrd_get_context(); 104 | pthread_mutex_lock(&mtx); 105 | strncpy(ctx->lib_errstr, strerror(err), sizeof(ctx->lib_errstr)); 106 | ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0'; 107 | pthread_mutex_unlock(&mtx); 108 | return ctx->lib_errstr; 109 | } 110 | #endif 111 | -------------------------------------------------------------------------------- /src/rrd_tool.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_tool.h Common Header File 5 | *****************************************************************************/ 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #ifndef _RRD_TOOL_H 11 | #define _RRD_TOOL_H 12 | 13 | #ifdef HAVE_CONFIG_H 14 | #include "rrd_config.h" 15 | #elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) 16 | #include "../win32/config.h" 17 | #endif 18 | 19 | #include "rrd.h" 20 | 21 | #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) 22 | 23 | /* Win32 only includes */ 24 | 25 | #include /* for _isnan */ 26 | #include /* for chdir */ 27 | 28 | struct tm *localtime_r( 29 | const time_t *timep, 30 | struct tm *result); 31 | char *ctime_r( 32 | const time_t *timep, 33 | char *result); 34 | struct tm *gmtime_r( 35 | const time_t *timep, 36 | struct tm *result); 37 | char *strtok_r( 38 | char *str, 39 | const char *sep, 40 | char **last); 41 | 42 | #else 43 | 44 | /* unix-only includes */ 45 | #if !defined isnan && !defined HAVE_ISNAN 46 | int isnan( 47 | double value); 48 | #endif 49 | 50 | #endif 51 | 52 | /* local include files -- need to be after the system ones */ 53 | #ifdef HAVE_GETOPT_LONG 54 | #define _GNU_SOURCE 55 | #include 56 | #else 57 | #include "rrd_getopt.h" 58 | #endif 59 | 60 | #include "rrd_format.h" 61 | 62 | #ifndef max 63 | #define max(a,b) ((a) > (b) ? (a) : (b)) 64 | #endif 65 | 66 | #ifndef min 67 | #define min(a,b) ((a) < (b) ? (a) : (b)) 68 | #endif 69 | 70 | #define DIM(x) (sizeof(x)/sizeof(x[0])) 71 | 72 | char *sprintf_alloc( 73 | char *, 74 | ...); 75 | 76 | /* HELPER FUNCTIONS */ 77 | 78 | int PngSize( 79 | FILE *, 80 | long *, 81 | long *); 82 | 83 | int rrd_create_fn( 84 | const char *file_name, 85 | rrd_t *rrd); 86 | int rrd_fetch_fn( 87 | const char *filename, 88 | enum cf_en cf_idx, 89 | time_t *start, 90 | time_t *end, 91 | unsigned long *step, 92 | unsigned long *ds_cnt, 93 | char ***ds_namv, 94 | rrd_value_t **data); 95 | 96 | #define RRD_READONLY (1<<0) 97 | #define RRD_READWRITE (1<<1) 98 | #define RRD_CREAT (1<<2) 99 | #define RRD_READAHEAD (1<<3) 100 | #define RRD_COPY (1<<4) 101 | 102 | enum cf_en cf_conv( 103 | const char *string); 104 | enum dst_en dst_conv( 105 | char *string); 106 | long ds_match( 107 | rrd_t *rrd, 108 | char *ds_nam); 109 | double rrd_diff( 110 | char *a, 111 | char *b); 112 | 113 | #endif 114 | 115 | #ifdef __cplusplus 116 | } 117 | #endif 118 | -------------------------------------------------------------------------------- /src/rrd_tune.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * change header parameters of an rrd 5 | ***************************************************************************** 6 | * $Id: rrd_tune.c 1946 2009-10-24 10:46:42Z oetiker $ 7 | * $Log$ 8 | * Revision 1.6 2004/05/26 22:11:12 oetiker 9 | * reduce compiler warnings. Many small fixes. -- Mike Slifcak 10 | * 11 | * Revision 1.5 2002/02/01 20:34:49 oetiker 12 | * fixed version number and date/time 13 | * 14 | * Revision 1.4 2001/08/22 22:29:07 jake 15 | * Contents of this patch: 16 | * (1) Adds/revises documentation for rrd tune in rrd_tool.c and pod files. 17 | * (2) Moves some initialization code from rrd_create.c to rrd_hw.c. 18 | * (3) Adds another pass to smoothing for SEASONAL and DEVSEASONAL RRAs. 19 | * This pass computes the coefficients as deviations from an average; the 20 | * average is added the baseline coefficient of HWPREDICT. Statistical texts 21 | * suggest this to preserve algorithm stability. It will not invalidate 22 | * RRD files created and smoothed with the old code. 23 | * (4) Adds the aberrant-reset flag to rrd tune. This operation, which is 24 | * specified for a single data source, causes the holt-winters algorithm to 25 | * forget everthing it has learned and start over. 26 | * (5) Fixes a few out-of-date code comments. 27 | * 28 | * Revision 1.3 2001/03/07 21:21:54 oetiker 29 | * complete rewrite of rrdgraph documentation. This also includs info 30 | * on upcomming/planned changes to the rrdgraph interface and functionality 31 | * -- Alex van den Bogaerdt 32 | * 33 | * Revision 1.2 2001/03/04 13:01:55 oetiker 34 | * Aberrant Behavior Detection support. A brief overview added to rrdtool.pod. 35 | * Major updates to rrd_update.c, rrd_create.c. Minor update to other core files. 36 | * This is backwards compatible! But new files using the Aberrant stuff are not readable 37 | * by old rrdtool versions. See http://cricket.sourceforge.net/aberrant/rrd_hw.htm 38 | * -- Jake Brutlag 39 | * 40 | *****************************************************************************/ 41 | 42 | #include "rrd_tool.h" 43 | #include "rrd_rpncalc.h" 44 | #include "rrd_hw.h" 45 | #include 46 | 47 | #ifdef WIN32 48 | #include 49 | #endif 50 | 51 | int set_hwarg( 52 | rrd_t *rrd, 53 | enum cf_en cf, 54 | enum rra_par_en rra_par, 55 | char *arg); 56 | int set_deltaarg( 57 | rrd_t *rrd, 58 | enum rra_par_en rra_par, 59 | char *arg); 60 | int set_windowarg( 61 | rrd_t *rrd, 62 | enum rra_par_en, 63 | char *arg); 64 | 65 | int rrd_tune( 66 | int argc, 67 | char **argv) 68 | { 69 | rrd_t rrd; 70 | int matches; 71 | int optcnt = 0; 72 | long ds; 73 | char ds_nam[DS_NAM_SIZE]; 74 | char ds_new[DS_NAM_SIZE]; 75 | long heartbeat; 76 | double min; 77 | double max; 78 | char dst[DST_SIZE]; 79 | rrd_file_t *rrd_file; 80 | struct option long_options[] = { 81 | {"heartbeat", required_argument, 0, 'h'}, 82 | {"minimum", required_argument, 0, 'i'}, 83 | {"maximum", required_argument, 0, 'a'}, 84 | {"data-source-type", required_argument, 0, 'd'}, 85 | {"data-source-rename", required_argument, 0, 'r'}, 86 | /* added parameter tuning options for aberrant behavior detection */ 87 | {"deltapos", required_argument, 0, 'p'}, 88 | {"deltaneg", required_argument, 0, 'n'}, 89 | {"window-length", required_argument, 0, 'w'}, 90 | {"failure-threshold", required_argument, 0, 'f'}, 91 | {"alpha", required_argument, 0, 'x'}, 92 | {"beta", required_argument, 0, 'y'}, 93 | {"gamma", required_argument, 0, 'z'}, 94 | {"gamma-deviation", required_argument, 0, 'v'}, 95 | {"smoothing-window", required_argument, 0, 's'}, 96 | {"smoothing-window-deviation", required_argument, 0, 'S'}, 97 | {"aberrant-reset", required_argument, 0, 'b'}, 98 | {0, 0, 0, 0} 99 | }; 100 | 101 | optind = 0; 102 | opterr = 0; /* initialize getopt */ 103 | 104 | 105 | rrd_file = rrd_open(argv[1], &rrd, RRD_READWRITE); 106 | if (rrd_file == NULL) { 107 | rrd_free(&rrd); 108 | return -1; 109 | } 110 | 111 | while (1) { 112 | int option_index = 0; 113 | int opt; 114 | char *old_locale = ""; 115 | 116 | opt = getopt_long(argc, argv, "h:i:a:d:r:p:n:w:f:x:y:z:v:b:", 117 | long_options, &option_index); 118 | if (opt == EOF) 119 | break; 120 | 121 | optcnt++; 122 | switch (opt) { 123 | case 'h': 124 | old_locale = setlocale(LC_NUMERIC, "C"); 125 | if ((matches = 126 | sscanf(optarg, DS_NAM_FMT ":%ld", ds_nam, 127 | &heartbeat)) != 2) { 128 | rrd_set_error("invalid arguments for heartbeat"); 129 | rrd_free(&rrd); 130 | rrd_close(rrd_file); 131 | setlocale(LC_NUMERIC, old_locale); 132 | return -1; 133 | } 134 | setlocale(LC_NUMERIC, old_locale); 135 | if ((ds = ds_match(&rrd, ds_nam)) == -1) { 136 | rrd_free(&rrd); 137 | rrd_close(rrd_file); 138 | return -1; 139 | } 140 | rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat; 141 | break; 142 | 143 | case 'i': 144 | old_locale = setlocale(LC_NUMERIC, "C"); 145 | if ((matches = 146 | sscanf(optarg, DS_NAM_FMT ":%lf", ds_nam, &min)) < 1) { 147 | rrd_set_error("invalid arguments for minimum ds value"); 148 | rrd_free(&rrd); 149 | rrd_close(rrd_file); 150 | setlocale(LC_NUMERIC, old_locale); 151 | return -1; 152 | } 153 | setlocale(LC_NUMERIC, old_locale); 154 | if ((ds = ds_match(&rrd, ds_nam)) == -1) { 155 | rrd_free(&rrd); 156 | rrd_close(rrd_file); 157 | return -1; 158 | } 159 | 160 | if (matches == 1) 161 | min = DNAN; 162 | rrd.ds_def[ds].par[DS_min_val].u_val = min; 163 | break; 164 | 165 | case 'a': 166 | old_locale = setlocale(LC_NUMERIC, "C"); 167 | if ((matches = 168 | sscanf(optarg, DS_NAM_FMT ":%lf", ds_nam, &max)) < 1) { 169 | rrd_set_error("invalid arguments for maximum ds value"); 170 | rrd_free(&rrd); 171 | rrd_close(rrd_file); 172 | setlocale(LC_NUMERIC, old_locale); 173 | return -1; 174 | } 175 | setlocale(LC_NUMERIC, old_locale); 176 | if ((ds = ds_match(&rrd, ds_nam)) == -1) { 177 | rrd_free(&rrd); 178 | rrd_close(rrd_file); 179 | return -1; 180 | } 181 | if (matches == 1) 182 | max = DNAN; 183 | rrd.ds_def[ds].par[DS_max_val].u_val = max; 184 | break; 185 | 186 | case 'd': 187 | if ((matches = 188 | sscanf(optarg, DS_NAM_FMT ":" DST_FMT, ds_nam, dst)) != 2) { 189 | rrd_set_error("invalid arguments for data source type"); 190 | rrd_free(&rrd); 191 | rrd_close(rrd_file); 192 | return -1; 193 | } 194 | if ((ds = ds_match(&rrd, ds_nam)) == -1) { 195 | rrd_free(&rrd); 196 | rrd_close(rrd_file); 197 | return -1; 198 | } 199 | if ((int) dst_conv(dst) == -1) { 200 | rrd_free(&rrd); 201 | rrd_close(rrd_file); 202 | return -1; 203 | } 204 | /* only reset when something is changed */ 205 | if (strncmp(rrd.ds_def[ds].dst, dst, DST_SIZE - 1) != 0) { 206 | strncpy(rrd.ds_def[ds].dst, dst, DST_SIZE - 1); 207 | rrd.ds_def[ds].dst[DST_SIZE - 1] = '\0'; 208 | 209 | rrd.pdp_prep[ds].last_ds[0] = 'U'; 210 | rrd.pdp_prep[ds].last_ds[1] = 'N'; 211 | rrd.pdp_prep[ds].last_ds[2] = 'K'; 212 | rrd.pdp_prep[ds].last_ds[3] = 'N'; 213 | rrd.pdp_prep[ds].last_ds[4] = '\0'; 214 | } 215 | break; 216 | case 'r': 217 | if ((matches = 218 | sscanf(optarg, DS_NAM_FMT ":" DS_NAM_FMT, ds_nam, 219 | ds_new)) != 2) { 220 | rrd_set_error("invalid arguments for data source type"); 221 | rrd_free(&rrd); 222 | rrd_close(rrd_file); 223 | return -1; 224 | } 225 | if ((ds = ds_match(&rrd, ds_nam)) == -1) { 226 | rrd_free(&rrd); 227 | rrd_close(rrd_file); 228 | return -1; 229 | } 230 | strncpy(rrd.ds_def[ds].ds_nam, ds_new, DS_NAM_SIZE - 1); 231 | rrd.ds_def[ds].ds_nam[DS_NAM_SIZE - 1] = '\0'; 232 | break; 233 | case 'p': 234 | if (set_deltaarg(&rrd, RRA_delta_pos, optarg)) { 235 | rrd_free(&rrd); 236 | return -1; 237 | } 238 | break; 239 | case 'n': 240 | if (set_deltaarg(&rrd, RRA_delta_neg, optarg)) { 241 | rrd_free(&rrd); 242 | return -1; 243 | } 244 | break; 245 | case 'f': 246 | if (set_windowarg(&rrd, RRA_failure_threshold, optarg)) { 247 | rrd_free(&rrd); 248 | return -1; 249 | } 250 | break; 251 | case 'w': 252 | if (set_windowarg(&rrd, RRA_window_len, optarg)) { 253 | rrd_free(&rrd); 254 | return -1; 255 | } 256 | break; 257 | case 'x': 258 | if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_alpha, optarg)) { 259 | if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_alpha, optarg)) { 260 | rrd_free(&rrd); 261 | return -1; 262 | } 263 | rrd_clear_error(); 264 | } 265 | break; 266 | case 'y': 267 | if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_beta, optarg)) { 268 | if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_beta, optarg)) { 269 | rrd_free(&rrd); 270 | return -1; 271 | } 272 | rrd_clear_error(); 273 | } 274 | break; 275 | case 'z': 276 | if (set_hwarg(&rrd, CF_SEASONAL, RRA_seasonal_gamma, optarg)) { 277 | rrd_free(&rrd); 278 | return -1; 279 | } 280 | break; 281 | case 'v': 282 | if (set_hwarg(&rrd, CF_DEVSEASONAL, RRA_seasonal_gamma, optarg)) { 283 | rrd_free(&rrd); 284 | return -1; 285 | } 286 | break; 287 | case 'b': 288 | if (sscanf(optarg, DS_NAM_FMT, ds_nam) != 1) { 289 | rrd_set_error("invalid argument for aberrant-reset"); 290 | rrd_free(&rrd); 291 | rrd_close(rrd_file); 292 | return -1; 293 | } 294 | if ((ds = ds_match(&rrd, ds_nam)) == -1) { 295 | /* ds_match handles it own errors */ 296 | rrd_free(&rrd); 297 | rrd_close(rrd_file); 298 | return -1; 299 | } 300 | reset_aberrant_coefficients(&rrd, rrd_file, (unsigned long) ds); 301 | if (rrd_test_error()) { 302 | rrd_free(&rrd); 303 | rrd_close(rrd_file); 304 | return -1; 305 | } 306 | break; 307 | case 's': 308 | strcpy(rrd.stat_head->version, RRD_VERSION); /* smoothing_window causes Version 4 */ 309 | if (set_hwarg 310 | (&rrd, CF_SEASONAL, RRA_seasonal_smoothing_window, optarg)) { 311 | rrd_free(&rrd); 312 | return -1; 313 | } 314 | break; 315 | case 'S': 316 | strcpy(rrd.stat_head->version, RRD_VERSION); /* smoothing_window causes Version 4 */ 317 | if (set_hwarg 318 | (&rrd, CF_DEVSEASONAL, RRA_seasonal_smoothing_window, 319 | optarg)) { 320 | rrd_free(&rrd); 321 | return -1; 322 | } 323 | break; 324 | case '?': 325 | if (optopt != 0) 326 | rrd_set_error("unknown option '%c'", optopt); 327 | else 328 | rrd_set_error("unknown option '%s'", argv[optind - 1]); 329 | rrd_free(&rrd); 330 | rrd_close(rrd_file); 331 | return -1; 332 | } 333 | } 334 | if (optcnt > 0) { 335 | rrd_seek(rrd_file, 0, SEEK_SET); 336 | rrd_write(rrd_file, rrd.stat_head, sizeof(stat_head_t) * 1); 337 | rrd_write(rrd_file, rrd.ds_def, 338 | sizeof(ds_def_t) * rrd.stat_head->ds_cnt); 339 | /* need to write rra_defs for RRA parameter changes */ 340 | rrd_write(rrd_file, rrd.rra_def, 341 | sizeof(rra_def_t) * rrd.stat_head->rra_cnt); 342 | } else { 343 | int i; 344 | 345 | for (i = 0; i < (int) rrd.stat_head->ds_cnt; i++) 346 | if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) { 347 | printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n", 348 | rrd.ds_def[i].ds_nam, 349 | rrd.ds_def[i].dst, 350 | rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt, 351 | rrd.ds_def[i].par[DS_min_val].u_val, 352 | rrd.ds_def[i].par[DS_max_val].u_val); 353 | } else { 354 | char *buffer = NULL; 355 | 356 | rpn_compact2str((rpn_cdefds_t *) & 357 | (rrd.ds_def[i].par[DS_cdef]), rrd.ds_def, 358 | &buffer); 359 | printf("DS[%s] typ: %s\tcdef: %s\n", rrd.ds_def[i].ds_nam, 360 | rrd.ds_def[i].dst, buffer); 361 | free(buffer); 362 | } 363 | } 364 | rrd_close(rrd_file); 365 | rrd_free(&rrd); 366 | return 0; 367 | } 368 | 369 | int set_hwarg( 370 | rrd_t *rrd, 371 | enum cf_en cf, 372 | enum rra_par_en rra_par, 373 | char *arg) 374 | { 375 | double param; 376 | unsigned long i; 377 | signed short rra_idx = -1; 378 | 379 | /* read the value */ 380 | param = atof(arg); 381 | if (param <= 0.0 || param >= 1.0) { 382 | rrd_set_error("Holt-Winters parameter must be between 0 and 1"); 383 | return -1; 384 | } 385 | /* does the appropriate RRA exist? */ 386 | for (i = 0; i < rrd->stat_head->rra_cnt; ++i) { 387 | if (cf_conv(rrd->rra_def[i].cf_nam) == cf) { 388 | rra_idx = i; 389 | break; 390 | } 391 | } 392 | if (rra_idx == -1) { 393 | rrd_set_error("Holt-Winters RRA does not exist in this RRD"); 394 | return -1; 395 | } 396 | 397 | /* set the value */ 398 | rrd->rra_def[rra_idx].par[rra_par].u_val = param; 399 | return 0; 400 | } 401 | 402 | int set_deltaarg( 403 | rrd_t *rrd, 404 | enum rra_par_en rra_par, 405 | char *arg) 406 | { 407 | rrd_value_t param; 408 | unsigned long i; 409 | signed short rra_idx = -1; 410 | 411 | param = atof(arg); 412 | if (param < 0.1) { 413 | rrd_set_error("Parameter specified is too small"); 414 | return -1; 415 | } 416 | /* does the appropriate RRA exist? */ 417 | for (i = 0; i < rrd->stat_head->rra_cnt; ++i) { 418 | if (cf_conv(rrd->rra_def[i].cf_nam) == CF_FAILURES) { 419 | rra_idx = i; 420 | break; 421 | } 422 | } 423 | if (rra_idx == -1) { 424 | rrd_set_error("Failures RRA does not exist in this RRD"); 425 | return -1; 426 | } 427 | 428 | /* set the value */ 429 | rrd->rra_def[rra_idx].par[rra_par].u_val = param; 430 | return 0; 431 | } 432 | 433 | int set_windowarg( 434 | rrd_t *rrd, 435 | enum rra_par_en rra_par, 436 | char *arg) 437 | { 438 | unsigned long param; 439 | unsigned long i, cdp_idx; 440 | signed short rra_idx = -1; 441 | 442 | /* read the value */ 443 | param = atoi(arg); 444 | if (param < 1 || param > MAX_FAILURES_WINDOW_LEN) { 445 | rrd_set_error("Parameter must be between %d and %d", 446 | 1, MAX_FAILURES_WINDOW_LEN); 447 | return -1; 448 | } 449 | /* does the appropriate RRA exist? */ 450 | for (i = 0; i < rrd->stat_head->rra_cnt; ++i) { 451 | if (cf_conv(rrd->rra_def[i].cf_nam) == CF_FAILURES) { 452 | rra_idx = i; 453 | break; 454 | } 455 | } 456 | if (rra_idx == -1) { 457 | rrd_set_error("Failures RRA does not exist in this RRD"); 458 | return -1; 459 | } 460 | 461 | /* set the value */ 462 | rrd->rra_def[rra_idx].par[rra_par].u_cnt = param; 463 | 464 | /* erase existing violations */ 465 | for (i = 0; i < rrd->stat_head->ds_cnt; i++) { 466 | cdp_idx = rra_idx * (rrd->stat_head->ds_cnt) + i; 467 | erase_violations(rrd, cdp_idx, rra_idx); 468 | } 469 | return 0; 470 | } 471 | -------------------------------------------------------------------------------- /src/rrd_version.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | ***************************************************************************** 4 | * rrd_version Return 5 | ***************************************************************************** 6 | * Initial version by Burton Strauss, ntopSupport.com - 5/2005 7 | *****************************************************************************/ 8 | 9 | #include "rrd_tool.h" 10 | 11 | double rrd_version( 12 | void) 13 | { 14 | return NUMVERS; 15 | } 16 | 17 | char *rrd_strversion( 18 | void) 19 | { 20 | return PACKAGE_VERSION; 21 | } 22 | -------------------------------------------------------------------------------- /src/rrd_xport.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009 3 | **************************************************************************** 4 | * rrd_xport.h contains XML related constants 5 | ****************************************************************************/ 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #ifndef _RRD_XPORT_H 11 | #define _RRD_XPORT_H 12 | 13 | #define XML_ENCODING "ISO-8859-1" 14 | #define ROOT_TAG "xport" 15 | #define META_TAG "meta" 16 | #define META_START_TAG "start" 17 | #define META_STEP_TAG "step" 18 | #define META_END_TAG "end" 19 | #define META_ROWS_TAG "rows" 20 | #define META_COLS_TAG "columns" 21 | #define LEGEND_TAG "legend" 22 | #define LEGEND_ENTRY_TAG "entry" 23 | #define DATA_TAG "data" 24 | #define DATA_ROW_TAG "row" 25 | #define COL_TIME_TAG "t" 26 | #define COL_DATA_TAG "v" 27 | 28 | 29 | #endif 30 | 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /src/strftime.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * strftime.c 4 | * 5 | * implements the ansi c function strftime() 6 | * 7 | * written 6 september 1989 by jim nutt 8 | * released into the public domain by jim nutt 9 | * 10 | * modified 21-Oct-89 by Rob Duff 11 | * 12 | * modified 08-Dec-04 by Tobi Oetiker (added %V) 13 | **/ 14 | 15 | #include /* for size_t */ 16 | #include /* for va_arg */ 17 | #include /* for struct tm */ 18 | #include "strftime.h" 19 | 20 | /* Define your own defaults in config.h if necessary */ 21 | #if defined(TZNAME_STD) && defined(TZNAME_DST) 22 | char *tzname_[2] = { TZNAME_STD, TZNAME_DST }; 23 | #else 24 | #define tzname_ tzname 25 | #endif 26 | 27 | static char *aday[] = { 28 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 29 | }; 30 | 31 | static char *day[] = { 32 | "Sunday", "Monday", "Tuesday", "Wednesday", 33 | "Thursday", "Friday", "Saturday" 34 | }; 35 | 36 | static char *amonth[] = { 37 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", 38 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 39 | }; 40 | 41 | static char *month[] = { 42 | "January", "February", "March", "April", "May", "June", 43 | "July", "August", "September", "October", "November", "December" 44 | }; 45 | 46 | static char buf[26]; 47 | 48 | static void strfmt( 49 | char *str, 50 | const char *fmt, 51 | ...); 52 | 53 | /** 54 | * 55 | * size_t strftime_(char *str, 56 | * size_t maxs, 57 | * const char *fmt, 58 | * const struct tm *t) 59 | * 60 | * this functions acts much like a sprintf for time/date output. 61 | * given a pointer to an output buffer, a format string and a 62 | * time, it copies the time to the output buffer formatted in 63 | * accordance with the format string. the parameters are used 64 | * as follows: 65 | * 66 | * str is a pointer to the output buffer, there should 67 | * be at least maxs characters available at the address 68 | * pointed to by str. 69 | * 70 | * maxs is the maximum number of characters to be copied 71 | * into the output buffer, included the '\0' terminator 72 | * 73 | * fmt is the format string. a percent sign (%) is used 74 | * to indicate that the following character is a special 75 | * format character. the following are valid format 76 | * characters: 77 | * 78 | * %A full weekday name (Monday) 79 | * %a abbreviated weekday name (Mon) 80 | * %B full month name (January) 81 | * %b abbreviated month name (Jan) 82 | * %c standard date and time representation 83 | * %d day-of-month (01-31) 84 | * %H hour (24 hour clock) (00-23) 85 | * %I hour (12 hour clock) (01-12) 86 | * %j day-of-year (001-366) 87 | * %M minute (00-59) 88 | * %m month (01-12) 89 | * %p local equivalent of AM or PM 90 | * %S second (00-59) 91 | * %U week-of-year, first day sunday (00-53) 92 | * %W week-of-year, first day monday (00-53) 93 | * %V ISO 8601 Week number 94 | * %w weekday (0-6, sunday is 0) 95 | * %X standard time representation 96 | * %x standard date representation 97 | * %Y year with century 98 | * %y year without century (00-99) 99 | * %Z timezone name 100 | * %% percent sign 101 | * 102 | * the standard date string is equivalent to: 103 | * 104 | * %a %b %d %Y 105 | * 106 | * the standard time string is equivalent to: 107 | * 108 | * %H:%M:%S 109 | * 110 | * the standard date and time string is equivalent to: 111 | * 112 | * %a %b %d %H:%M:%S %Y 113 | * 114 | * strftime_() returns the number of characters placed in the 115 | * buffer, not including the terminating \0, or zero if more 116 | * than maxs characters were produced. 117 | * 118 | **/ 119 | 120 | size_t strftime_( 121 | char *s, 122 | size_t maxs, 123 | const char *f, 124 | const struct tm *t) 125 | { 126 | int w, d; 127 | char *p, *q, *r; 128 | 129 | p = s; 130 | q = s + maxs - 1; 131 | while ((*f != '\0')) { 132 | if (*f++ == '%') { 133 | r = buf; 134 | switch (*f++) { 135 | case '%': 136 | r = "%"; 137 | break; 138 | 139 | case 'a': 140 | r = aday[t->tm_wday]; 141 | break; 142 | 143 | case 'A': 144 | r = day[t->tm_wday]; 145 | break; 146 | 147 | case 'b': 148 | r = amonth[t->tm_mon]; 149 | break; 150 | 151 | case 'B': 152 | r = month[t->tm_mon]; 153 | break; 154 | 155 | case 'c': 156 | strfmt(r, "%0 %0 %2 %2:%2:%2 %4", 157 | aday[t->tm_wday], amonth[t->tm_mon], 158 | t->tm_mday, t->tm_hour, t->tm_min, 159 | t->tm_sec, t->tm_year + 1900); 160 | break; 161 | 162 | case 'd': 163 | strfmt(r, "%2", t->tm_mday); 164 | break; 165 | 166 | case 'H': 167 | strfmt(r, "%2", t->tm_hour); 168 | break; 169 | 170 | case 'I': 171 | strfmt(r, "%2", (t->tm_hour % 12) ? t->tm_hour % 12 : 12); 172 | break; 173 | 174 | case 'j': 175 | strfmt(r, "%3", t->tm_yday + 1); 176 | break; 177 | 178 | case 'm': 179 | strfmt(r, "%2", t->tm_mon + 1); 180 | break; 181 | 182 | case 'M': 183 | strfmt(r, "%2", t->tm_min); 184 | break; 185 | 186 | case 'p': 187 | r = (t->tm_hour > 11) ? "PM" : "AM"; 188 | break; 189 | 190 | case 'S': 191 | strfmt(r, "%2", t->tm_sec); 192 | break; 193 | 194 | case 'U': 195 | w = t->tm_yday / 7; 196 | if (t->tm_yday % 7 > t->tm_wday) 197 | w++; 198 | strfmt(r, "%2", w); 199 | break; 200 | 201 | case 'W': 202 | w = t->tm_yday / 7; 203 | if (t->tm_yday % 7 > (t->tm_wday + 6) % 7) 204 | w++; 205 | strfmt(r, "%2", w); 206 | break; 207 | 208 | case 'V': 209 | 210 | /* ISO 8601 Week Of Year: 211 | If the week (Monday - Sunday) containing January 1 has four or more 212 | days in the new year, then it is week 1; otherwise it is week 53 of 213 | the previous year and the next week is week one. */ 214 | 215 | w = (t->tm_yday + 7 - (t->tm_wday ? t->tm_wday - 1 : 6)) / 7; 216 | d = (t->tm_yday + 7 - (t->tm_wday ? t->tm_wday - 1 : 6)) % 7; 217 | 218 | if (d >= 4) { 219 | w++; 220 | } else if (w == 0) { 221 | w = 53; 222 | } 223 | strfmt(r, "%2", w); 224 | break; 225 | 226 | case 'w': 227 | strfmt(r, "%1", t->tm_wday); 228 | break; 229 | 230 | case 'x': 231 | strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday], 232 | amonth[t->tm_mon], t->tm_mday, t->tm_year + 1900); 233 | break; 234 | 235 | case 'X': 236 | strfmt(r, "%2:%2:%2", t->tm_hour, t->tm_min, t->tm_sec); 237 | break; 238 | 239 | case 'y': 240 | strfmt(r, "%2", t->tm_year % 100); 241 | break; 242 | 243 | case 'Y': 244 | strfmt(r, "%4", t->tm_year + 1900); 245 | break; 246 | 247 | case 'Z': 248 | r = (t->tm_isdst && tzname_[1][0]) ? tzname_[1] : tzname_[0]; 249 | break; 250 | 251 | default: 252 | buf[0] = '%'; /* reconstruct the format */ 253 | buf[1] = f[-1]; 254 | buf[2] = '\0'; 255 | if (buf[1] == 0) 256 | f--; /* back up if at end of string */ 257 | } 258 | while (*r) { 259 | if (p == q) { 260 | *q = '\0'; 261 | return 0; 262 | } 263 | *p++ = *r++; 264 | } 265 | } else { 266 | if (p == q) { 267 | *q = '\0'; 268 | return 0; 269 | } 270 | *p++ = f[-1]; 271 | } 272 | } 273 | *p = '\0'; 274 | return p - s; 275 | } 276 | 277 | /* 278 | * stdarg.h 279 | * 280 | typedef void *va_list; 281 | #define va_start(vp,v) (vp=((char*)&v)+sizeof(v)) 282 | #define va_arg(vp,t) (*((t*)(vp))++) 283 | #define va_end(vp) 284 | * 285 | */ 286 | 287 | static int powers[5] = { 1, 10, 100, 1000, 10000 }; 288 | 289 | /** 290 | * static void strfmt(char *str, char *fmt); 291 | * 292 | * simple sprintf for strftime 293 | * 294 | * each format descriptor is of the form %n 295 | * where n goes from zero to four 296 | * 297 | * 0 -- string %s 298 | * 1..4 -- int %?.?d 299 | * 300 | **/ 301 | 302 | static void strfmt( 303 | char *str, 304 | const char *fmt, 305 | ...) 306 | { 307 | int ival, ilen; 308 | char *sval; 309 | va_list vp; 310 | 311 | va_start(vp, fmt); 312 | while (*fmt) { 313 | if (*fmt++ == '%') { 314 | ilen = *fmt++ - '0'; 315 | if (ilen == 0) { /* zero means string arg */ 316 | sval = va_arg(vp, char *); 317 | 318 | while (*sval) 319 | *str++ = *sval++; 320 | } else { /* always leading zeros */ 321 | 322 | ival = va_arg(vp, int); 323 | 324 | while (ilen) { 325 | ival %= powers[ilen--]; 326 | *str++ = (char) ('0' + ival / powers[ilen]); 327 | } 328 | } 329 | } else 330 | *str++ = fmt[-1]; 331 | } 332 | *str = '\0'; 333 | va_end(vp); 334 | } 335 | 336 | #ifdef TEST 337 | 338 | #include /* for printf */ 339 | #include /* for strftime */ 340 | 341 | char test[80]; 342 | 343 | int main( 344 | int argc, 345 | char *argv[]) 346 | { 347 | int len; 348 | char *fmt; 349 | time_t now; 350 | 351 | time(&now); 352 | 353 | fmt = (argc == 1) ? "%I:%M %p\n%c\n" : argv[1]; 354 | len = strftime_(test, sizeof test, fmt, localtime(&now)); 355 | printf("%d: %s\n", len, test); 356 | return !len; 357 | } 358 | 359 | #endif /* TEST */ 360 | -------------------------------------------------------------------------------- /src/strftime.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** STRFTIME.H - For older compilers which lack strftime() 3 | ** 4 | ** Note: To avoid name collision with newer compilers, the function name 5 | ** strftime_() is used. 6 | */ 7 | 8 | #ifndef STRFTIME__H 9 | #define STRFTIME__H 10 | 11 | #include /* for size_t */ 12 | #include /* for struct tm */ 13 | 14 | size_t strftime_( 15 | char *s, 16 | size_t maxs, 17 | const char *f, 18 | const struct tm *t); 19 | 20 | #if defined(TZNAME_STD) && defined(TZNAME_DST) 21 | extern char *tzname_[2]; 22 | #endif 23 | 24 | #endif /* STRFTIME__H */ 25 | -------------------------------------------------------------------------------- /src/unused.h: -------------------------------------------------------------------------------- 1 | /* define a macro to wrap variables that would 2 | otherwise generate UNUSED variable warnings 3 | Note that GCC's attribute unused only supresses the warning, so 4 | it is perfectly safe to declare something unused although it is not. 5 | */ 6 | 7 | #ifdef UNUSED 8 | #elif defined(__GNUC__) 9 | # define UNUSED(x) x __attribute__((unused)) 10 | #elif defined(__LCLINT__) 11 | # define UNUSED(x) /*@unused@*/ x 12 | #else 13 | # define UNUSED(x) x 14 | #endif 15 | --------------------------------------------------------------------------------