1#!/usr/bin/env python3

2

3# Test fstrim functionality on a disk device

4#

5# Copyright (C) 2020 Canonical Ltd.

6#

7# Authors:

8# Rod Smith <rod.smith@canonical.com>

9#

10# This program is free software: you can redistribute it and/or modify

11# it under the terms of the GNU General Public License version 3,

12# as published by the Free Software Foundation.

13#

14# This program is distributed in the hope that it will be useful,

15# but WITHOUT ANY WARRANTY; without even the implied warranty of

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

17# GNU General Public License for more details.

18#

19# You should have received a copy of the GNU General Public License

20# along with this program. If not, see <http://www.gnu.org/licenses/>.

21#

22"""

23 This script checks to see if a block device supports TRIM via a call to the

24 fstrim utility. This requires ensuring that a Linux partition on the target

25 device be mounted, so this script does this, if necessary.

26

27 The script returns 0 on success and 1 on failure, with output

28 via Python logging about the nature of the success/failure.

29"""

30

31

32 import logging

33 import shlex

34 import sys

35 from argparse import ArgumentParser

36 from subprocess import PIPE, Popen

37 from checkbox_support.disk_support import Disk

38

39

40 def mount_filesystem(device):

41 if "/dev" not in device and device != "":

42 device = "/dev/" + device

43

44 test_disk = Disk(device)

45 mount_point = None

46 if test_disk.mount_filesystem(False):

47 mount_point = test_disk.get_mount_point()

48 logging.info("mount point is {}".format(test_disk.get_mount_point()))

49 if not mount_point:

50 logging.error("Test failed; {} is not mounted!".format(device))

51

52 return mount_point

53

54

55 def run_fstrim(device):

56 mount_point = mount_filesystem(device)

57 if mount_point is not None:

58 command = "fstrim -v {}".format(mount_point)

59 triminfo = Popen(shlex.split(command), stdout=PIPE)

60 lsbinfo_bytes = triminfo.communicate()[0]

61 lsbinfo = lsbinfo_bytes.decode(

62 encoding="utf-8", errors="ignore"

63 ).rstrip()

64 logging.info(lsbinfo)

65 retval = triminfo.returncode

66 else:

67 retval = 1

68 return retval

69

70

71 def main():

72 parser = ArgumentParser()

73 parser.add_argument(

74 "--device-file",

75 default="sda",

76 help="The file within /dev that maps to the device",

77 )

78 args = parser.parse_args()

79 logger = logging.getLogger()

80 logger.setLevel(logging.INFO)

81 retval = run_fstrim(args.device_file)

82

83 return retval

84

85

86 if __name__ == "__main__":

87 sys.exit(main())