File: resFsDarwin.py

package info (click to toggle)
opensvc 1.8~20170412-3
  • links: PTS
  • area: main
  • in suites: buster
  • size: 6,492 kB
  • ctags: 7,845
  • sloc: python: 77,169; sh: 339; xml: 39; makefile: 7
file content (224 lines) | stat: -rw-r--r-- 6,838 bytes parent folder | download
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
import os

import rcMountsDarwin as rcMounts
import resFs as Res
from rcUtilities import qcall, protected_mount, getmount
from rcGlobalEnv import rcEnv
from rcLoopDarwin import file_to_loop
import rcExceptions as ex
from stat import *

def try_umount(self):
    cmd = ['diskutil', 'umount', self.mount_point]
    (ret, out, err) = self.vcall(cmd, err_to_info=True)
    if ret == 0:
        return 0

    cmd = ['diskutil', 'umount', 'force', self.mount_point]
    (ret, out, err) = self.vcall(cmd, err_to_info=True)
    if ret == 0:
        return 0

    cmd = ['umount', self.mount_point]
    (ret, out, err) = self.vcall(cmd, err_to_info=True)
    if ret == 0:
        return 0

    """ don't try to kill process using the source of a
        protected bind mount
    """
    if protected_mount(self.mount_point):
        return 1

    """ best effort kill of all processes that might block
        the umount operation. The priority is given to mass
        action reliability, ie don't contest oprator's will
    """
    cmd = ['sync']
    (ret, out, err) = self.vcall(cmd, err_to_info=True)

    for i in range(4):
        nb_killed = self.killfuser(self.mount_point)
        self.log.info('umount %s'%self.mount_point)
        cmd = ['umount', self.mount_point]
        ret = qcall(cmd)
        if ret == 0 or nb_killed == 0:
            break

    if ret != 0:
        self.log.info("no more process using %s, yet umount fails. try forced umount."%self.mount_point)
        cmd = ['umount', '-f', self.mount_point]
        (ret, out, err) = self.vcall(cmd, err_to_info=True)

    return ret


class Mount(Res.Mount):
    """ define FreeBSD mount/umount doAction """
    def __init__(self,
                 rid,
                 mount_point,
                 device,
                 fs_type,
                 mount_options,
                 snap_size=None,
                 **kwargs):
        self.Mounts = None
        self.loopdevice = None
        self.isloop = False
        Res.Mount.__init__(self,
                           rid,
                           mount_point=mount_point,
                           device=device,
                           fs_type=fs_type,
                           mount_options=mount_options,
                           snap_size=snap_size,
                           **kwargs)
        self.fsck_h = {
            'hfs': {
                'bin': 'fsck',
                'cmd': ['diskutil', 'repairVolume', self.device]
            },
        }

    def killfuser(self, dir):
        cmd = ['fuser', '-kmc', dir]
        (ret, out, err) = self.vcall(cmd, err_to_info=True)

        """ return the number of process we sent signal to
        """
        l = out.split(':')
        if len(l) < 2:
            return 0
        return len(l[1].split())

    def is_up(self):
        self.Mounts = rcMounts.Mounts()
        ret = self.Mounts.has_mount(self.device, self.mount_point)
        if ret:
            return True

        if self.fs_type not in self.netfs:
            try:
                st = os.stat(self.device)
                mode = st[ST_MODE]
            except:
                self.log.debug("can not stat %s" % self.device)
                return False

            if S_ISREG(mode):
                # might be a loopback mount
                devs = file_to_loop(self.device)
                for dev in devs:
                    ret = self.Mounts.has_mount(dev, self.mount_point)
                    if ret:
                        return True

        return False

    def realdev(self):
        dev = None
        try:
            mode = os.stat(self.device)[ST_MODE]
        except:
            self.log.debug("can not stat %s" % self.device)
            return None
        if S_ISCHR(mode):
            dev = self.device
        else:
            mnt = getmount(self.device)
            if self.Mounts is None:
                self.Mounts = rcMounts.Mounts()
            m = self.Mounts.has_param("mnt", mnt)
            if m is None:
                self.log.debug("can't find dev %(dev)s mounted in %(mnt)s in mnttab"%dict(mnt=mnt, dev=self.device))
                return None
            dev = m.dev

        return dev

    def disklist(self):
        dev = self.realdev()
        if dev is None:
            return set([])

        try:
            statinfo = os.stat(dev)
        except:
            self.log.error("can not stat %s" % dev)
            raise ex.excError

        return set([dev])

    def can_check_writable(self):
        return True

    def start(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        Res.Mount.start(self)

        if self.fs_type in self.netfs or self.device == "none":
            # TODO showmount -e
            pass
        else:
            try:
                mode = os.stat(self.device)[ST_MODE]
                if S_ISREG(mode):
                    devs = file_to_loop(self.device)
                    if len(devs) > 0:
                        self.loopdevice = devs[0]
                    self.isloop = True
            except:
                self.log.debug("can not stat %s" % self.device)
                return False

        if self.is_up() is True:
            self.log.info("%s is already mounted" % self.label)
            return 0

        if not os.path.exists(self.mount_point):
            os.makedirs(self.mount_point, 0o755)

        if self.isloop is True:
            cmd = ['hdiutil', 'attach', '-mountpoint', self.mount_point , self.device]
            (ret, out, err) = self.vcall(cmd)
        else:
            self.fsck()
            try:
                cmd = ['diskutil', 'mount', '-mount_point', self.mount_point , self.device]
                (ret, out, err) = self.vcall(cmd)
            except:
                if self.fs_type != "":
                    fstype = ['-t', self.fs_type]
                else:
                    fstype = []
                if self.mount_options != "":
                    mntopt = ['-o', self.mount_options]
                else:
                    mntopt = []
                cmd = ['mount']+fstype+mntopt+[self.device, self.mount_point]
                (ret, out, err) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.Mounts = None
        self.can_rollback = True

    def stop(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        if self.is_up() is False:
            self.log.info("%s is already umounted" % self.label)
            return
        for i in range(3):
            ret = try_umount(self)
            if ret == 0: break
        if ret != 0:
            self.log.error('failed to umount %s'%self.mount_point)
            raise ex.excError
        self.Mounts = None

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)