blob: d0e71134b5c152339da7762d1bf8cb6d593f7503 [file] [log] [blame]
Vishwanatha81ee91f2016-08-30 17:17:13 +05301#define _XOPEN_SOURCE
2#include <chrono>
3#include <sstream>
4#include <iostream>
5#include <iomanip>
6#include <array>
7#include <unistd.h>
8#include <assert.h>
9#include <sys/timerfd.h>
10#include <systemd/sd-event.h>
11#include <systemd/sd-bus.h>
12#include <systemd/sd-daemon.h>
13#include "time-register.hpp"
14#include "time-manager.hpp"
15
16// Neeed to do this since its not exported outside of the kernel.
17// Refer : https://gist.github.com/lethean/446cea944b7441228298
18#ifndef TFD_TIMER_CANCEL_ON_SET
19#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
20#endif
21
22// Needed to make sure timerfd does not misfire eventhough we set CANCEL_ON_SET
23#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
24
25// Used in time-register.c
26extern sd_bus_vtable timeServicesVtable[];
27
28Time::Time(const TimeConfig& timeConfig) : config(timeConfig)
29{
30 // Nothing to do here
31}
32
33BmcTime::BmcTime(const TimeConfig& timeConfig) : Time(timeConfig)
34{
35 // Nothing to do here
36}
37
38HostTime::HostTime(const TimeConfig& timeConfig,
39 const std::chrono::microseconds& hostOffset)
40 : Time(timeConfig),
41 iv_Offset(hostOffset)
42{
43 // Nothing to do here
44}
45
46TimeManager::TimeManager() :
47 iv_HostOffset(std::chrono::microseconds(0)),
48 iv_UptimeUsec(std::chrono::microseconds(0)),
49 iv_EventSource(nullptr),
50 iv_Event(nullptr)
51{
52 assert(setupTimeManager() >= 0);
53}
54
55// Needed to be standalone extern "C" to register
56// as a callback routine with sd_bus_vtable
57int GetTime(sd_bus_message* m, void* userdata,
58 sd_bus_error* retError)
59{
60 auto tmgr = static_cast<TimeManager*>(userdata);
61 return tmgr->getTime(m, userdata, retError);
62}
63
64int SetTime(sd_bus_message* m, void* userdata,
65 sd_bus_error* retError)
66{
67 auto tmgr = static_cast<TimeManager*>(userdata);
68 return tmgr->setTime(m, userdata, retError);
69}
70
71// Property reader
72int getCurrTimeModeProperty(sd_bus* bus, const char* path,
73 const char* interface, const char* property,
74 sd_bus_message* m, void* userdata,
75 sd_bus_error* error)
76{
77 auto tmgr = static_cast<TimeManager*>(userdata);
78 return sd_bus_message_append(m, "s",
79 TimeConfig::modeStr(tmgr->config.getCurrTimeMode()));
80}
81
82int getCurrTimeOwnerProperty(sd_bus* bus, const char* path,
83 const char* interface, const char* property,
84 sd_bus_message* m, void* userdata,
85 sd_bus_error* error)
86{
87 auto tmgr = static_cast<TimeManager*>(userdata);
88 return sd_bus_message_append(m, "s",
89 TimeConfig::ownerStr(tmgr->config.getCurrTimeOwner()));
90}
91
92int getReqTimeModeProperty(sd_bus* bus, const char* path,
93 const char* interface, const char* property,
94 sd_bus_message* m, void* userdata,
95 sd_bus_error* error)
96{
97 auto tmgr = static_cast<TimeManager*>(userdata);
98 return sd_bus_message_append(m, "s",
99 TimeConfig::modeStr(tmgr->config.getRequestedTimeMode()));
100}
101
102int getReqTimeOwnerProperty(sd_bus* bus, const char* path,
103 const char* interface, const char* property,
104 sd_bus_message* m, void* userdata,
105 sd_bus_error* error)
106{
107 auto tmgr = static_cast<TimeManager*>(userdata);
108 return sd_bus_message_append(m, "s",
109 TimeConfig::ownerStr(tmgr->config.getRequestedTimeOwner()));
110}
111
112int TimeManager::getTime(sd_bus_message* m, void* userdata,
113 sd_bus_error* retError)
114{
115 const char* target = nullptr;
116
117 // Extract the target and call respective GetTime
118 auto r = sd_bus_message_read(m, "s", &target);
119 if (r < 0)
120 {
121 std::cerr << "Error:" << strerror(-r)
122 <<" reading user time" << std::endl;
123 *retError = SD_BUS_ERROR_MAKE_CONST(
124 SD_BUS_ERROR_IO_ERROR, "Error reading input");
125
126 return sd_bus_reply_method_error(m, retError);
127 }
128
129 if (!strcasecmp(target, "bmc"))
130 {
131 auto time = BmcTime(config);
132 return time.getTime(m, retError);
133 }
134 else if (!strcasecmp(target, "host"))
135 {
136 auto time = HostTime(config, iv_HostOffset);
137 return time.getTime(m, retError);
138 }
139 else
140 {
141 std::cerr << "Error:" << strerror(-r)
142 <<" Invalid Target" << std::endl;
143 *retError = SD_BUS_ERROR_MAKE_CONST(
144 SD_BUS_ERROR_IO_ERROR, "Valid targets are BMC or HOST");
145
146 return sd_bus_reply_method_error(m, retError);
147 }
148}
149
150int TimeManager::setTime(sd_bus_message* m, void* userdata,
151 sd_bus_error* retError)
152{
Vishwanatha81ee91f2016-08-30 17:17:13 +0530153 const char* target = nullptr;
154 auto r = sd_bus_message_read(m, "s", &target);
155 if (r < 0)
156 {
157 std::cerr << "Error:" << strerror(-r)
158 <<" reading user time" << std::endl;
159 *retError = SD_BUS_ERROR_MAKE_CONST(
160 SD_BUS_ERROR_IO_ERROR, "Error reading input");
161
162 return sd_bus_reply_method_error(m, retError);
163 }
164
165 if (!strcasecmp(target, "bmc"))
166 {
167 auto time = BmcTime(config);
168 auto r = time.setTime(m, retError);
169 if (r < 0)
170 {
171 // This would have the error populated
172 return sd_bus_reply_method_error(m, retError);
173 }
174 }
175 else if (!strcasecmp(target, "host"))
176 {
177 auto time = HostTime(config, iv_HostOffset);
178
179 auto r = time.setTime(m, retError);
180 if (r < 0)
181 {
182 // This would have the error populated
183 return sd_bus_reply_method_error(m, retError);
184 }
185
186 if (config.getCurrTimeOwner() == TimeConfig::timeOwners::SPLIT)
187 {
188 iv_HostOffset = time.getChangedOffset();
Patrick Williamsf0c91c02016-11-09 21:35:04 -0600189 r = config.writeData(cv_HostOffsetFile, iv_HostOffset.count());
Vishwanatha81ee91f2016-08-30 17:17:13 +0530190 if (r < 0)
191 {
192 // probably does not make sense to crash on these..
193 // The next NTP sync will set things right.
194 std::cerr << "Error saving host_offset: "
195 << iv_HostOffset.count() << std::endl;
196 }
197 }
198 }
199 return sd_bus_reply_method_return(m, "i", 0);
200}
201
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +0530202int Time::setTimeOfDay(const std::chrono::microseconds& timeOfDayUsec,
203 sd_bus_error *retError)
Vishwanatha81ee91f2016-08-30 17:17:13 +0530204{
205 // These 2 are for bypassing some policy
206 // checking in the timedate1 service
207 auto relative = false;
208 auto interactive = false;
209
210 return sd_bus_call_method(config.getDbus(),
211 "org.freedesktop.timedate1",
212 "/org/freedesktop/timedate1",
213 "org.freedesktop.timedate1",
214 "SetTime",
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +0530215 retError,
Vishwanatha81ee91f2016-08-30 17:17:13 +0530216 nullptr, // timedate1 does not return response
217 "xbb",
218 (int64_t)timeOfDayUsec.count(), //newTimeUsec,
219 relative, // Time in absolute seconds since epoch
220 interactive); // bypass polkit checks
221}
222
223// Common routine for BMC and HOST Get Time operations
224std::chrono::microseconds Time::getBaseTime()
225{
226 auto currBmcTime = std::chrono::system_clock::now();
227 return std::chrono::duration_cast<std::chrono::microseconds>
228 (currBmcTime.time_since_epoch());
229}
230
231// Accepts the time in microseconds and converts to Human readable format.
232std::string Time::convertToStr(const std::chrono::microseconds& timeInUsec)
233{
234 using namespace std::chrono;
235
236 // Convert this to number of seconds;
237 auto timeInSec = duration_cast<seconds>(microseconds(timeInUsec));
238 auto time_T = static_cast<std::time_t>(timeInSec.count());
239
240 std::ostringstream timeFormat {};
241 timeFormat << std::put_time(std::gmtime(&time_T), "%c %Z");
242
243 auto timeStr = timeFormat.str();
244 std::cout << timeStr.c_str() << std::endl;
245 return timeStr;
246}
247
248// Reads timeofday and returns time string
249// and also number of microseconds.
250// Ex : Tue Aug 16 22:49:43 2016
251int BmcTime::getTime(sd_bus_message *m, sd_bus_error *retError)
252{
253 std::cout << "Request to get BMC time: ";
254
255 // Get BMC time
256 auto timeInUsec = getBaseTime();
257 auto timeStr = convertToStr(timeInUsec);
258 return sd_bus_reply_method_return(
259 m, "sx", timeStr.c_str(), (uint64_t)timeInUsec.count());
260}
261
262// Designated to be called by IPMI_GET_SEL time from host
263int HostTime::getTime(sd_bus_message *m, sd_bus_error *retError)
264{
265 using namespace std::chrono;
266
267 std::cout << "Request to get HOST time" << std::endl;
268
269 // Get BMC time and add Host's offset
270 // Referencing the iv_hostOffset of TimeManager object
271 auto timeInUsec = getBaseTime();
272 auto hostTime = timeInUsec.count() + iv_Offset.count();
273
274 auto timeStr = convertToStr(duration_cast<microseconds>
275 (microseconds(hostTime)));
276
277 std::cout << " Host_time_str: [ " << timeStr
278 << " ] host_time usec: [ " << hostTime
279 << " ] host_offset: [ " << iv_Offset.count()
280 << " ] " << std::endl;
281
282 return sd_bus_reply_method_return(m, "sx", timeStr.c_str(),
283 (uint64_t)hostTime);
284 return 0;
285}
286
287// Gets the time string and verifies if it conforms to format %Y-%m-%d %H:%M:%S
288// and then sets the BMC time. If the input time string does not conform to the
289// format, an error message is returned.
290int BmcTime::setTime(sd_bus_message *m, sd_bus_error *retError)
291{
292 tm userTm {};
293 const char* userTimeStr = nullptr;
294
295 std::cout << "Request to set BMC time" << std::endl;
296
297 std::cout << "Curr_Mode: " << TimeConfig::modeStr(config.getCurrTimeMode())
298 << " Curr_Owner: " << TimeConfig::ownerStr(config.getCurrTimeOwner())
299 << std::endl;
300
Vishwanatha81ee91f2016-08-30 17:17:13 +0530301 if(config.getCurrTimeOwner() == TimeConfig::timeOwners::HOST)
302 {
303 std::cerr << "Can not set time. Owner is HOST" << std::endl;
304 *retError = SD_BUS_ERROR_MAKE_CONST(
305 SD_BUS_ERROR_FAILED, "Current owner is HOST");
306
307 return -1;
308 }
309
310 auto r = sd_bus_message_read(m, "s", &userTimeStr);
311 if (r < 0)
312 {
313 std::cerr << "Error:" << strerror(-r)
314 <<" reading user time" << std::endl;
315 *retError = SD_BUS_ERROR_MAKE_CONST(
316 SD_BUS_ERROR_IO_ERROR, "Error reading input");
317 return r;
318 }
319
320 std::cout <<" BMC TIME : " << userTimeStr << std::endl;
321
322 // Convert the time string into tm structure
323 std::istringstream timeString {};
324 timeString.str(userTimeStr);
325 timeString >> std::get_time(&userTm, "%Y-%m-%d %H:%M:%S");
326 if (timeString.fail())
327 {
328 std::cerr << "Error: Incorrect time format" << std::endl;
329 *retError = SD_BUS_ERROR_MAKE_CONST(
330 SD_BUS_ERROR_INVALID_ARGS, "Incorrect time format");
331 return -1;
332 }
333
334 // Convert the time structure into number of
335 // seconds maintained in GMT. Followed the same that is in
336 // systemd/timedate1
337 auto timeOfDay = timegm(&userTm);
338 if (timeOfDay < 0)
339 {
340 std::cerr <<"Error converting tm to seconds" << std::endl;
341 *retError = SD_BUS_ERROR_MAKE_CONST(
342 SD_BUS_ERROR_FAILED, "Error converting tm to seconds");
343 return -1;
344 }
345
346 // Set REALTIME and also update hwclock
347 auto timeInUsec = std::chrono::microseconds(
348 std::chrono::seconds(timeOfDay));
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +0530349 return setTimeOfDay(timeInUsec, retError);
Vishwanatha81ee91f2016-08-30 17:17:13 +0530350}
351
352// Gets the time string from IPMI ( which is currently in seconds since epoch )
353// and then sets the BMC time / adjusts the offset depending on current owner
354// policy.
355int HostTime::setTime(sd_bus_message *m, sd_bus_error *retError)
356{
357 using namespace std::chrono;
358
359 std::cout << "Request to SET Host time" << std::endl;
360
361 std::cout << "Curr_Mode: " << TimeConfig::modeStr(config.getCurrTimeMode())
362 << "Curr_Owner: " << TimeConfig::ownerStr(config.getCurrTimeOwner())
363 << "host_offset: " << iv_Offset.count() << std::endl;
364
365 if (config.getCurrTimeOwner() == TimeConfig::timeOwners::BMC)
366 {
367 *retError = SD_BUS_ERROR_MAKE_CONST(
368 SD_BUS_ERROR_FAILED, "Current Owner is BMC");
369 return -1;
370 }
371
372 const char* newHostTime = nullptr;
373 auto r = sd_bus_message_read(m, "s", &newHostTime);
374 if (r < 0)
375 {
376 std::cerr << "Error: " << strerror(-r)
377 << "reading host time" << std::endl;
378 *retError = SD_BUS_ERROR_MAKE_CONST(
379 SD_BUS_ERROR_IO_ERROR, "Error reading input");
380 return -1;
381 }
382
383 // We need to convert the string input to decimal.
384 auto hostTimeSec = std::stol(std::string(newHostTime));
385
386 // And then to microseconds
387 auto hostTimeUsec = duration_cast<microseconds>(seconds(hostTimeSec));
388 std::cout << "setHostTime: HostTimeInUSec: "
389 << hostTimeUsec.count() << std::endl;
390
391 if (config.getCurrTimeOwner() == TimeConfig::timeOwners::SPLIT)
392 {
393 // Adjust the host offset
394 auto bmcTimeUsec = duration_cast<microseconds>
395 (system_clock::now().time_since_epoch());
396
397 // We are not doing any time settings in BMC
398 std::cout << "Updated: host_time: [ " << hostTimeUsec.count()
399 << " ] host_offset: [ " << iv_Offset.count()
400 << " ] " << std::endl;
401
402 // Communicate the offset back to manager to update needed.
403 changedOffset = hostTimeUsec - bmcTimeUsec;
404
405 return 0;
406 }
407
408 // We are okay to update time in as long as BMC is not the owner
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +0530409 return setTimeOfDay(hostTimeUsec, retError);
Vishwanatha81ee91f2016-08-30 17:17:13 +0530410}
411
412// Gets called into by sd_event on an activity seen on sd_bus
413int TimeManager::processSdBusMessage(sd_event_source* es, int fd,
414 uint32_t revents, void* userdata)
415{
416 auto tmgr = static_cast<TimeManager*>(userdata);
417 auto r = sd_bus_process(tmgr->getTimeBus(), nullptr);
418 if (r < 0)
419 {
420 std::cerr <<"Error: " << strerror(-r)
421 <<" processing sd_bus message:" << std::endl;
422 }
423 return r;
424}
425
426// Gets called into by sd_event on any time SET event
427int TimeManager::processTimeChange(sd_event_source* es, int fd,
428 uint32_t revents, void* userdata)
429{
430 using namespace std::chrono;
431 std::cout << "BMC time changed" << std::endl;
432
433 auto tmgr = static_cast<TimeManager*>(userdata);
434
435 std::array<char, 64> time {};
436
437 // We are not interested in the data here. Need to read time again .
438 // So read until there is something here in the FD
439 while (read(fd, time.data(), time.max_size()) > 0);
440
441 std::cout <<" Curr_Mode: " << TimeConfig::modeStr(tmgr->config.getCurrTimeMode())
442 << " Curr_Owner : " << TimeConfig::ownerStr(tmgr->config.getCurrTimeOwner())
443 << " Host_Offset: " << tmgr->getHostOffset().count() << std::endl;
444
445 // Read the current BMC time and adjust the
446 // host time offset if the mode is SPLIT
447 if (tmgr->config.getCurrTimeOwner() == TimeConfig::timeOwners::SPLIT)
448 {
449 // Delta between REAL and Monotonic.
450 auto uptimeUsec = duration_cast<microseconds>
451 (system_clock::now().time_since_epoch() -
452 steady_clock::now().time_since_epoch());
453
454 auto deltaTimeUsec = uptimeUsec - tmgr->getUptimeUsec();
455
456 // If the BMC time goes backwards, then - of - will handle that.
457 auto newHostOffset = tmgr->getHostOffset() - deltaTimeUsec;
458 tmgr->updateHostOffset(newHostOffset);
459
460 std::cout << " UPDATED HOST_OFFSET: "
461 << tmgr->getHostOffset().count() << std::endl;
462 tmgr->updateUptimeUsec(uptimeUsec);
463
464 // Persist this
Patrick Williamsf0c91c02016-11-09 21:35:04 -0600465 auto r = tmgr->config.writeData(TimeManager::cv_HostOffsetFile,
466 tmgr->getHostOffset().count());
Vishwanatha81ee91f2016-08-30 17:17:13 +0530467 if (r < 0)
468 {
469 std::cerr << "Error saving host_offset: "
470 << tmgr->getHostOffset().count() << std::endl;
471 return r;
472 }
473 std::cout << " Updated: Host_Offset: "
474 << tmgr->getHostOffset().count() << std::endl;
475 }
476 return 0;
477}
478
479// Resets iv_HostOffset. Needed when we move away from SPLIT.
480int TimeManager::resetHostOffset()
481{
482 iv_HostOffset = std::chrono::microseconds(0);
Patrick Williamsf0c91c02016-11-09 21:35:04 -0600483 auto r = config.writeData(cv_HostOffsetFile, iv_HostOffset.count());
Vishwanatha81ee91f2016-08-30 17:17:13 +0530484 config.updateSplitModeFlag(false);
485 return r;
486}
487
488// Called by sd_event when Pgood is changed in Power
489int TimeManager::processPgoodChange(sd_bus_message* m, void* userdata,
490 sd_bus_error* retError)
491{
492 auto tmgr = static_cast<TimeManager*>(userdata);
493 const char* key = nullptr;
Vishwanatha81ee91f2016-08-30 17:17:13 +0530494
495 auto newPgood = -1;
496 auto r = 0;
497
498 std::cout <<" PGOOD has changed.." << std::endl;
499
500 // input data is "sa{sv}as" and we are just interested in a{sv}
501 r = sd_bus_message_skip(m, "s");
502 if (r < 0)
503 {
504 std::cerr << "Error: " << strerror(-r) <<
505 "skipping interface name in data" << std::endl;
506 return r;
507 }
508
509 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
510 if (r < 0)
511 {
512 std::cerr << "Error: " << strerror(-r)
513 <<"entering the dictionary" << std::endl;
514 return r;
515 }
516
517 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
518 "sv")) > 0)
519 {
520 r = sd_bus_message_read(m, "s", &key);
521 if (r < 0)
522 {
523 std::cerr << "Error: " << strerror(-r)
524 <<" reading the key from dict" << std::endl;
525 // Can not continue here since the next
526 // enter would result in error anyway
527 return r;
528 }
529
530 if (!strcmp(key, "pgood"))
531 {
532 r = sd_bus_message_read(m, "v", "i", &newPgood);
533 if (r < 0)
534 {
535 std::cerr << "Error: " << strerror(-r)
536 << "reading pgood" << std::endl;
537 return r;
538 }
539 r = tmgr->config.updatePropertyVal(key, std::to_string(newPgood));
540 if (r < 0)
541 {
542 std::cerr << "Error: " << strerror(-r)
543 << "processing pgood" << std::endl;
544 return r;
545 }
546 }
547 else
548 {
549 sd_bus_message_skip(m, "v");
550 }
551 }
552 return 0;
553}
554
555// Called by sd_event when Properties are changed in settingsd.
556// Interested in changes to 'timeMode', 'timeOwner' and 'use_dhcp_ntp'
557int TimeManager::processPropertyChange(sd_bus_message* m, void* userdata,
558 sd_bus_error* retError)
559{
560 auto tmgr = static_cast<TimeManager*>(userdata);
561 const char* key = nullptr;
562 const char* value = nullptr;
563 auto r = 0;
564
565 std::cout <<" User Settings have changed.." << std::endl;
566
567 // input data is "sa{sv}as" and we are just interested in a{sv}
568 r = sd_bus_message_skip(m, "s");
569 if (r < 0)
570 {
571 std::cerr << "Error: " << strerror(-r) <<
572 "skipping interface name in data" << std::endl;
573 goto finish;
574 }
575
576 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
577 if (r < 0)
578 {
579 std::cerr << "Error: " << strerror(-r)
580 <<"entering the dictionary" << std::endl;
581 goto finish;
582 }
583
584 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
585 "sv")) > 0)
586 {
587 r = sd_bus_message_read(m, "s", &key);
588 if (r < 0)
589 {
590 std::cerr << "Error: " << strerror(-r)
591 <<" reading the key from dict" << std::endl;
592 // Can not continue here since the next
593 // enter would result in error anyway
594 goto finish;
595 }
596
Deepak Kodihalli41885672017-07-25 06:49:45 -0500597 if (!strcmp(key, "use_dhcp_ntp"))
Vishwanatha81ee91f2016-08-30 17:17:13 +0530598 {
599 r = sd_bus_message_read(m, "v", "s", &value);
600 if (r < 0)
601 {
602 std::cerr << "Error: " << strerror(-r)
603 <<"reading use_dhcp_ntp" << std::endl;
604 goto finish;
605 }
606 r = tmgr->config.updatePropertyVal(key, value);
607 if (r < 0)
608 {
609 std::cerr << "Error: " << strerror(-r)
610 << "processing dhcp_ntp" << std::endl;
611 goto finish;
612 }
613 }
614 else
615 {
616 sd_bus_message_skip(m, "v");
617 }
618 }
619finish:
620 return r;
621}
622
623// Sets up callback handlers for activities on :
624// 1) user request on SD_BUS
625// 2) Time change
626// 3) Settings change
627// 4) System state change;
628int TimeManager::registerCallbackHandlers()
629{
630 constexpr auto WATCH_SETTING_CHANGE =
631 "type='signal',interface='org.freedesktop.DBus.Properties',"
632 "path='/org/openbmc/settings/host0',member='PropertiesChanged'";
633
634 constexpr auto WATCH_PGOOD_CHANGE =
635 "type='signal',interface='org.freedesktop.DBus.Properties',"
636 "path='/org/openbmc/control/power0',member='PropertiesChanged'";
637
638 // Extract the descriptor out of sd_bus construct.
639 auto sdBusFd = sd_bus_get_fd(iv_TimeBus);
640
641 auto r = sd_event_add_io(iv_Event, &iv_EventSource, sdBusFd, EPOLLIN,
642 processSdBusMessage, this);
643 if (r < 0)
644 {
645 std::cerr << "Error: " << strerror(-r)
646 <<" adding sd_bus_message handler" << std::endl;
647 return r;
648 }
649
650 // Choose the MAX time that is possible to aviod mis fires.
651 itimerspec maxTime {};
652 maxTime.it_value.tv_sec = TIME_T_MAX;
653
654 auto timeFd = timerfd_create(CLOCK_REALTIME, 0);
655 if (timeFd < 0)
656 {
657 std::cerr << "Errorno: " << errno << " creating timerfd" << std::endl;
658 return -1;
659 }
660
661 r = timerfd_settime(timeFd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET,
662 &maxTime, nullptr);
663 if (r)
664 {
665 std::cerr << "Errorno: " << errno << "Setting timerfd" << std::endl;
666 return -1;
667 }
668
669 // Wake me up *only* if someone SETS the time
670 r = sd_event_add_io(iv_Event, &iv_EventSource, timeFd, EPOLLIN,
671 processTimeChange, this);
672 if (r < 0)
673 {
674 std::cerr << "Error: " << strerror(-r)
675 << "adding time_change handler" << std::endl;
676 return r;
677 }
678
679 // Watch for property changes in settingsd
680 r = sd_bus_add_match(iv_TimeBus, NULL, WATCH_SETTING_CHANGE,
681 processPropertyChange, this);
682 if (r < 0)
683 {
684 std::cerr << "Error: " << strerror(-r)
685 <<" adding property change listener" << std::endl;
686 return r;
687 }
688
689 // Watch for state change. Only reliable one to count on is
690 // state of [pgood]. value of [1] meaning host is powering on / powered
691 // on. [0] means powered off.
692 r = sd_bus_add_match(iv_TimeBus, NULL, WATCH_PGOOD_CHANGE,
693 processPgoodChange, this);
694 if (r < 0)
695 {
696 std::cerr << "Error: " << strerror(-r)
697 << " adding pgood change listener" << std::endl;
698 }
699 return r;
700}
701
702int TimeManager::setupTimeManager()
703{
704 auto r = sd_bus_default_system(&iv_TimeBus);
705 if (r < 0)
706 {
707 std::cerr << "Error" << strerror(-r)
708 <<" connecting to system bus" << std::endl;
709 goto finish;
710 }
711
712 r = sd_bus_add_object_manager(iv_TimeBus, NULL, cv_ObjPath);
713 if (r < 0)
714 {
715 std::cerr << "Error" << strerror(-r)
716 <<" adding object manager" << std::endl;
717 goto finish;
718 }
719
720 std::cout <<"Registering dbus methods" << std::endl;
721 r = sd_bus_add_object_vtable(iv_TimeBus,
722 NULL,
723 cv_ObjPath,
724 cv_BusName,
725 timeServicesVtable,
726 this);
727 if (r < 0)
728 {
729 std::cerr << "Error: " << strerror(-r)
730 <<" adding timer services vtable" << std::endl;
731 goto finish;
732 }
733
734 // create a sd_event object and add handlers
735 r = sd_event_default(&iv_Event);
736 if (r < 0)
737 {
738 std::cerr << "Error: " << strerror(-r)
739 <<"creating an sd_event" << std::endl;
740 goto finish;
741 }
742
743 // Handlers called by sd_event when an activity
744 // is observed in event loop
745 r = registerCallbackHandlers();
746 if (r < 0)
747 {
748 std::cerr << "Error setting up callback handlers" << std::endl;
749 goto finish;
750 }
751
752 // Need to do this here since TimeConfig may update the necessary owners
753 r = config.processInitialSettings(iv_TimeBus);
754 if (r < 0)
755 {
756 std::cerr << "Error setting up configuration params" << std::endl;
757 goto finish;
758 }
759
760 // Read saved values from previous run
761 r = readPersistentData();
762 if (r < 0)
763 {
764 std::cerr << "Error reading persistent data" << std::endl;
765 goto finish;
766 }
767
768 // Claim the bus
769 r = sd_bus_request_name(iv_TimeBus, cv_BusName, 0);
770 if (r < 0)
771 {
772 std::cerr << "Error: " << strerror(-r)
773 << "acquiring service name" << std::endl;
774 goto finish;
775 }
776finish:
777 if (r < 0)
778 {
779 iv_EventSource = sd_event_source_unref(iv_EventSource);
780 iv_Event = sd_event_unref(iv_Event);
781 }
782 return r;
783}
784
785int TimeManager::readPersistentData()
786{
787 using namespace std::chrono;
788
789 // Get current host_offset
790 // When we reach here, TimeConfig would have been populated and would have
791 // applied the owner to SPLIT *if* the system allowed it. So check if we
792 // moved away from SPLIT and if so, make offset:0
793 if (config.isSplitModeChanged())
794 {
795 iv_HostOffset = microseconds(0);
Patrick Williamsf0c91c02016-11-09 21:35:04 -0600796 auto r = config.writeData(cv_HostOffsetFile, iv_HostOffset.count());
Vishwanatha81ee91f2016-08-30 17:17:13 +0530797 if (r < 0)
798 {
799 std::cerr <<" Error saving offset to file" << std::endl;
800 return r;
801 }
802 }
803 else
804 {
805 auto hostTimeOffset = config.readData<long long int>(cv_HostOffsetFile);
806 iv_HostOffset = microseconds(hostTimeOffset);
807 std::cout <<"Last known host_offset:" << hostTimeOffset << std::endl;
808 }
809
810 //How long was the FSP up prior to 'this' start
811 iv_UptimeUsec = duration_cast<microseconds>
812 (system_clock::now().time_since_epoch() -
813 steady_clock::now().time_since_epoch());
814 if (iv_UptimeUsec.count() < 0)
815 {
816 std::cerr <<"Error reading uptime" << std::endl;
817 return -1;
818 }
819 std::cout <<"Initial Uptime Usec: "
820 << iv_UptimeUsec.count() << std::endl;
821 return 0;
822}
823
824// Forever loop
825int TimeManager::waitForClientRequest()
826{
827 return sd_event_loop(iv_Event);
828}
829
830int main(int argc, char* argv[])
831{
832 auto tmgr = std::make_unique<TimeManager>();
833
834 // Wait for the work
835 auto r = tmgr->waitForClientRequest();
836
837 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
838}