summaryrefslogtreecommitdiffstats
path: root/plugins/freespace.py
blob: 1bcc0ed87fcb72d2d7863a02b98e854e930d36d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# First Aid Kit - diagnostic and repair tool for Linux
# Copyright (C) 2007 Martin Sivak <msivak@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import os
import shutil

from pyfirstaidkit.plugins import Plugin,Flow
from pyfirstaidkit.reporting import PLUGIN
from pyfirstaidkit.returns import *
from pyfirstaidkit.issue import SimpleIssue

class FreeSpacePlugin(Plugin):
    """Plugin to detect insufficient free space in /var directory."""
    name = "Free Space"
    version = "0.0.1"
    author = "Tomas Mlcoch"
    description = "Detects insufficient free space in /var directory."

    directory = '/var'
    del_dirs = ['/var/tmp',] # All content of this files will be
                             # removed (deleted) in "fix" step.

    @classmethod
    def getDeps(cls):
        return set(["root", "filesystem"])
    
    def __init__(self, *args, **kwargs):
        Plugin.__init__(self, *args, **kwargs)
        self._issue = SimpleIssue(self.name, self.description)

    def _reporter(self, msg):
        self._reporting.info(msg, origin=self, level=PLUGIN)

    def prepare(self):
        self._issue.set(reporting=self._reporting, origin=self, level=PLUGIN)
        self._result=ReturnSuccess

    def diagnose(self):
    
        # statvfs stucture:
        # -----------------
        # f_bsize   File system block size.
        # f_frsize  Fundamental file system block size (fragment size).
        # f_blocks  Total number of blocks on the file system, in units of f_frsize.
        # f_bfree   Total number of free blocks.
        # f_bavail  Total number of free blocks available to non-privileged processes.
        # f_files   Total number of file nodes (inodes) on the file system.
        # f_ffree   Total number of free file nodes (inodes).
        # f_favail  Total number of free file nodes (inodes) available to non-privileged processes.
        # f_flag    File system ID number.
        # f_namemax Maximum length of a file name (path element).
        
        # stat structure:
        # ---------------
        # st_dev        device
        # st_ino        inode
        # st_mode       protection
        # st_nlink      number of hard links
        # st_uid        user ID of owner
        # st_gid        group ID of owner
        # st_rdev       device type (if inode device)
        # st_size       total size, in bytes
        # st_blksize    blocksize for filesystem I/O
        # st_blocks     number of blocks allocated
        # st_atime      time of last access
        # st_mtime      time of last modification
        # st_ctime      time of last change

        # Get freespace
        stats = os.statvfs(self.directory)
        freespace = stats.f_bavail * stats.f_frsize / 1048576  # Freespace in Mb
        
        # Get freeable space
        self.freeable = 0
        for dir in self.del_dirs:
            stats_fa = os.statvfs(dir)
            for root, dirs, files in os.walk(dir):
                for d in dirs:
                    self.freeable += os.stat(os.path.join(root, d)).st_size
                for f in files:
                    self.freeable += os.stat(os.path.join(root, f)).st_size
        self.freeable /= 1024

        # Analyse results
        if freespace < 1:
            lhappened = True
            self._reporter("Free space seems to be insufficient.")
            self._reporter("Freeable space: %s Kb" % self.freeable)
            self._result=ReturnFailure
        else:
            lhappened = False
            self._reporter("Free space seems to be sufficient.")
            self._result=ReturnSuccess
        
        self._issue.set(checked=True, happened=lhappened,
            reporting=self._reporting, origin=self, level=PLUGIN)

    def backup(self):
        self._result=ReturnSuccess

    def restore(self):
        self._result=ReturnSuccess

    def fix(self):
        try:
            for dir in self.del_dirs:
                self._reporter("Deleting content of: %s" % dir)
                for root, dirs, files in os.walk(dir):
                    for d in dirs:
                        shutil.rmtree(os.path.join(root, d))
                    for f in files:
                        os.unlink(os.path.join(root, f))
        except (Exception) as e:
            self._reporter("Exception: %s" % e)
            self._result=ReturnFailure
        else:
            self._result=ReturnSuccess
            self._reporter("Fix successfully complete! (Freed space: %s Kb)" \
                                % self.freeable)        
            
        self._issue.set(fixed=(self._result == ReturnSuccess), 
                reporting=self._reporting, origin=self, level=PLUGIN)

    def clean(self):
        self._result=ReturnSuccess

def get_plugin():
    return FreeSpacePlugin