LCOV - code coverage report
Current view: top level - shared - watchdog.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 68 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2012 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <sys/ioctl.h>
      23             : #include <errno.h>
      24             : #include <fcntl.h>
      25             : #include <unistd.h>
      26             : #include <linux/watchdog.h>
      27             : 
      28             : #include "watchdog.h"
      29             : #include "log.h"
      30             : 
      31             : static int watchdog_fd = -1;
      32             : static usec_t watchdog_timeout = USEC_INFINITY;
      33             : 
      34           0 : static int update_timeout(void) {
      35             :         int r;
      36             : 
      37           0 :         if (watchdog_fd < 0)
      38           0 :                 return 0;
      39             : 
      40           0 :         if (watchdog_timeout == USEC_INFINITY)
      41           0 :                 return 0;
      42           0 :         else if (watchdog_timeout == 0) {
      43             :                 int flags;
      44             : 
      45           0 :                 flags = WDIOS_DISABLECARD;
      46           0 :                 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
      47           0 :                 if (r < 0)
      48           0 :                         return log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
      49             :         } else {
      50             :                 int sec, flags;
      51             :                 char buf[FORMAT_TIMESPAN_MAX];
      52             : 
      53           0 :                 sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
      54           0 :                 r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
      55           0 :                 if (r < 0)
      56           0 :                         return log_warning_errno(errno, "Failed to set timeout to %is: %m", sec);
      57             : 
      58           0 :                 watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
      59           0 :                 log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout, 0));
      60             : 
      61           0 :                 flags = WDIOS_ENABLECARD;
      62           0 :                 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
      63           0 :                 if (r < 0) {
      64             :                         /* ENOTTY means the watchdog is always enabled so we're fine */
      65           0 :                         log_full(errno == ENOTTY ? LOG_DEBUG : LOG_WARNING,
      66             :                                  "Failed to enable hardware watchdog: %m");
      67           0 :                         if (errno != ENOTTY)
      68           0 :                                 return -errno;
      69             :                 }
      70             : 
      71           0 :                 r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
      72           0 :                 if (r < 0)
      73           0 :                         return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
      74             :         }
      75             : 
      76           0 :         return 0;
      77             : }
      78             : 
      79           0 : static int open_watchdog(void) {
      80             :         struct watchdog_info ident;
      81             : 
      82           0 :         if (watchdog_fd >= 0)
      83           0 :                 return 0;
      84             : 
      85           0 :         watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
      86           0 :         if (watchdog_fd < 0)
      87           0 :                 return -errno;
      88             : 
      89           0 :         if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0)
      90           0 :                 log_info("Hardware watchdog '%s', version %x",
      91             :                          ident.identity,
      92             :                          ident.firmware_version);
      93             : 
      94           0 :         return update_timeout();
      95             : }
      96             : 
      97           0 : int watchdog_set_timeout(usec_t *usec) {
      98             :         int r;
      99             : 
     100           0 :         watchdog_timeout = *usec;
     101             : 
     102             :         /* If we didn't open the watchdog yet and didn't get any
     103             :          * explicit timeout value set, don't do anything */
     104           0 :         if (watchdog_fd < 0 && watchdog_timeout == USEC_INFINITY)
     105           0 :                 return 0;
     106             : 
     107           0 :         if (watchdog_fd < 0)
     108           0 :                 r = open_watchdog();
     109             :         else
     110           0 :                 r = update_timeout();
     111             : 
     112           0 :         *usec = watchdog_timeout;
     113             : 
     114           0 :         return r;
     115             : }
     116             : 
     117           0 : int watchdog_ping(void) {
     118             :         int r;
     119             : 
     120           0 :         if (watchdog_fd < 0) {
     121           0 :                 r = open_watchdog();
     122           0 :                 if (r < 0)
     123           0 :                         return r;
     124             :         }
     125             : 
     126           0 :         r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
     127           0 :         if (r < 0)
     128           0 :                 return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
     129             : 
     130           0 :         return 0;
     131             : }
     132             : 
     133           0 : void watchdog_close(bool disarm) {
     134             :         int r;
     135             : 
     136           0 :         if (watchdog_fd < 0)
     137           0 :                 return;
     138             : 
     139           0 :         if (disarm) {
     140             :                 int flags;
     141             : 
     142             :                 /* Explicitly disarm it */
     143           0 :                 flags = WDIOS_DISABLECARD;
     144           0 :                 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
     145           0 :                 if (r < 0)
     146           0 :                         log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
     147             : 
     148             :                 /* To be sure, use magic close logic, too */
     149             :                 for (;;) {
     150             :                         static const char v = 'V';
     151             : 
     152           0 :                         if (write(watchdog_fd, &v, 1) > 0)
     153           0 :                                 break;
     154             : 
     155           0 :                         if (errno != EINTR) {
     156           0 :                                 log_error_errno(errno, "Failed to disarm watchdog timer: %m");
     157           0 :                                 break;
     158             :                         }
     159           0 :                 }
     160             :         }
     161             : 
     162           0 :         watchdog_fd = safe_close(watchdog_fd);
     163             : }

Generated by: LCOV version 1.11