source: hwdetector/trunk/fuentes/hwdetector.install/hwdetector/modules/llxmounts.py @ 6466

Last change on this file since 6466 was 6466, checked in by mabarracus, 21 months ago

wip

File size: 9.2 KB
Line 
1#!/usr/bin/env python
2import hwdetector.Detector as Detector
3import hwdetector.utils.log as log
4import re
5import os
6
7log.debug(u'File '+__name__+u' loaded')
8
9class LlxMounts(Detector):
10
11    _PROVIDES = [u'MOUNTS_INFO',u'FSTAB',u'DISK_IDS',u'SERVER_SYNC_INFO']
12    _NEEDS = [u'HELPER_COMPRESS_FILE',u'HELPER_UNCOMMENT',u'HELPER_EXECUTE']
13
14    # def parse_findmnt(self,*args,**kwargs):
15    #     ltree=args[0]
16    #     output = []
17    #     if type(ltree) == type(dict()):
18    #         d={}
19    #         source=ltree[u'source']
20    #         m=re.search(r'(?P<source>/[\/\w:]+)(\[(?P<bind>\S+)\])?',source)
21    #         if m:
22    #             tmp=m.groupdict()
23    #             if tmp[u'bind']:
24    #                 d[u'mount_source'] = tmp[u'bind']
25    #                 d[u'binding'] = tmp[u'source']
26    #             else:
27    #                 d[u'mount_source'] = tmp[u'source']
28    #         d[u'mount_path'] = ltree[u'target']
29    #         d[u'fstype'] = ltree[u'fstype']
30    #         d[u'options'] = ltree[u'options'].split(u',')
31    #         output.append(d)
32    #         if u'children' in ltree:
33    #             for ch in ltree[u'children']:
34    #                 output.extend((self.parse_findmnt(ch)))
35    #     if type(ltree) == type(list()):
36    #         for x in ltree:
37    #             output.extend(self.parse_findmnt(x))
38    #
39    #     return output
40    #
41    # def complete_binding_mapping(self,*args,**kwargs):
42    #     list = args[0]
43    #     list_bindings = [ (x,list.index(x)) for x in list if u'binding' in x ]
44    #     list_sources = []
45    #     for b,idx in list_bindings:
46    #         list_sources = [ (x,list.index(x)) for x in list if u'device' in x and x[u'device'] == b[u'binding']]
47    #         k=0
48    #         for s,idx2 in list_sources:
49    #             k+=1
50    #             list[idx][u'binding_source_link'+str(k)]=s
51    #     return list
52
53    def parse_self_mountinfo(self,*args,**kwargs):
54        def unescape(string):
55            return re.sub(r'\\([0-7]{3})',(lambda m: chr(int(m.group(1),8))),string)
56
57        mounts = {}
58
59        with open(u'/proc/self/mountinfo',u'r') as f:
60            for line in f:
61                try:
62                    values = line.rstrip().split(u' ')
63                    mid, pid, devid, root, mp, mopt = tuple(values[0:6])
64                    tail = values [6:]
65                    extra = []
66                    for item in tail:
67                        if item != u'-':
68                            extra.append(item)
69                        else:
70                            break
71                    fstype, src, fsopt = tail[len(extra)+1:]
72                    mount = {u'mid':int(mid),u'pid':int(pid),u'devid':devid,u'root':unescape(root),u'mount_point':unescape(mp),u'mount_options':mopt,u'optional_fields':extra,u'fstype':fstype,u'mount_source':unescape(src),u'superblock_options':fsopt}
73                    mounts.setdefault(devid,[]).append(mount)
74                except Exception as e:
75                    log.error(u'Error processing line /proc/self/mountinfo {}'.format(line))
76                    log.error(e)
77        all_mounts=[]
78        for devid,mnts in mounts.items():
79            # Binding detection
80
81            # Skip single mounts
82            if len(mnts) <= 1:
83                for mnt in mnts:
84                    if mnt[u'mount_point'] not in [x[u'mount_point'] for x in all_mounts]:
85                        # skip duplicated mount points
86                        mnt.setdefault(u'is_binding', u'no')
87                        all_mounts.append(mnt)
88                continue
89            # Sort list to get the first mount of the device's root dir (if still mounted)
90            mnts.sort(key=lambda x: x[u'root'])
91            src = mnts[0]
92            src.setdefault(u'is_binding',u'no')
93            all_mounts.append(src)
94            binds = mnts[1:]
95            for bindmount in binds:
96                if src[u'root'] != bindmount[u'root']:
97                    bindmount[u'mount_source'] = src[u'mount_point']+u'/'+os.path.relpath(bindmount[u'root'],src[u'root'])
98                elif src[u'fstype'] == u'cifs':
99                    bindmount[u'mount_source'] = src[u'mount_point']
100                elif src[u'fstype'] == u'nfs':
101                    bindmount[u'mount_source'] = src[u'mount_point']+bindmount[u'mount_source'][len(src[u'mount_source']):]
102
103
104                bindmount.setdefault(u'is_binding',u'yes')
105                all_mounts.append(bindmount)
106        #        print u'{0} -> {1[mount_point]} ({1[mount_options]})'.format(src[u'mount_point'],bindmount)
107        #for x in all_mounts:
108        #    print u'{mount_source} {mount_point} {fstype} {is_binding}'.format(**x)
109        return all_mounts
110
111    def get_mounts(self,*args,**kwargs):
112        mounts=self.parse_self_mountinfo()
113        #findmnt = json.loads(subprocess.check_output([u'findmnt',u'-J'],stderr=open(os.devnull,u'w')))
114        #mounts = self.complete_binding_mapping(self.parse_findmnt(findmnt[u'filesystems']))
115        output = {u'PSEUDO':[],u'DISK':[],u'NETWORK':[],u'BIND':[],u'OTHER':[]}
116        #mounts =[]
117        #with open(u'/proc/mounts', u'r') as f:
118        #    reg = re.compile(r'^(?P<device>\S+)\s(?P<mount_path>\S+)\s(?P<type>\S+)\s(?P<options>\S+)\s(?P<dump>\S+)\s(?P<pass>\S+)$')
119        #    for line in f.readlines():
120        #        m = re.search(reg,line)
121        #        if m:
122        #            d=m.groupdict()
123        #            d[u'options']=d[u'options'].split(u',')
124        #            mounts.append(d)
125
126        mapping = {u'PSEUDO': {u'fstype':[u'sysfs',u'proc',u'devtmpfs',u'devpts',u'tmpfs',u'securityfs',u'cgroup',u'pstore',u'autofs',u'mqueue',u'debugfs',u'hugetlbfs',u'rpc_pipefs',u'fusectl',u'binfmt_misc',u'nfsd',u'gvfsd-fuse']},
127                   u'NETWORK':{u'fstype':[u'nfs',u'cifs']},
128                   u'DISK':{u'mount_source':[u'/dev/']},
129                   u'BIND':{u'is_binding':[u'yes']} # u'B'ind is tested first, before u'D'isc
130                   }
131        for mount in mounts:
132            done = False
133            for type_mapping in mapping:
134                for by in mapping[type_mapping]:
135                    if by in mount:
136                        for string in mapping[type_mapping][by]:
137                            if string in mount[by]:
138                                output[type_mapping].append(mount)
139                                done=True
140                                break
141                        if done:
142                            break
143                if done:
144                    break
145            if not done:
146                output[u'OTHER'].append(mount)
147
148        return output
149
150    def get_server_sync(self,*args,**kwargs):
151        if not os.path.isdir(u'/net/server-sync'):
152            return u'NO_EXIST'
153        lst=self.execute(run=u'getfacl -tp -R /net/server-sync/',stderr=None,asroot=True)
154        regexp=re.compile(u'^#\sfile:\s/net/server-sync(\S+)')
155        skip_search=False
156        d={}
157
158        def make_hierarchy(lkeys,value,d={}):
159            if len(lkeys) == 0:
160                return value
161            elif len(lkeys) == 1:
162                return d.setdefault(lkeys[0],value)
163            else:
164                return d.setdefault(lkeys[0],make_hierarchy(lkeys[1:],value,d[lkeys[0]]))
165
166        attrs={}
167        if lst:
168            for line in lst.split(u'\n'):
169                if line == u'':
170                    lsplit=[li for li in skip_search.split(u'/') if li != u'']
171                    if u'mask' in attrs:
172                        attrs[u'acls']=True
173                    else:
174                        attrs[u'acls']=False
175                    d.update(make_hierarchy(lsplit,attrs,d))
176                    skip_search=False
177                    attrs={}
178                    continue
179                if skip_search:
180                    fields=[ field for field in line.split(u' ') if field != u'']
181                    attrs.setdefault(u'__'+fields[0],{})
182                    perms={}
183                    if fields[0] not in [u'mask',u'other']:
184                        skip_field=0
185                    else:
186                        skip_field=1
187                    perms.setdefault(u'perms',fields[2-skip_field])
188                    try:
189                        perms.setdefault(u'defaults',fields[3-skip_field])
190                    except:
191                        perms.setdefault(u'defaults',None)
192
193                    attrs[u'__'+fields[0]].setdefault(fields[1],perms)
194                    #attrs[fields[0]][fields[1]].append(perms)
195
196                else:
197                    m = re.findall(regexp,line)
198                    if m:
199                        skip_search=m[0]
200                        if os.path.isdir(u'/net/server-sync'+skip_search):
201                            attrs[u'__is_dir']=True
202                            attrs[u'__is_file']=False
203                        else:
204                            attrs[u'__is_dir']=False
205                            attrs[u'__is_file']=True
206
207        d.setdefault(u'RAW',lst)
208        return d
209
210
211    def run(self,*args,**kwargs):
212        output = {u'MOUNTS_INFO':None}
213        output[u'MOUNTS_INFO']=self.get_mounts()
214        output[u'MOUNTS_INFO'][u'RAW']=self.compress_file(file=u'/proc/self/mounts')
215        output[u'FSTAB']=self.uncomment(u'/etc/fstab')
216        output[u'DISK_IDS']=self.execute(run=u'blkid',asroot=True,stderr=None)
217        output[u'SERVER_SYNC_INFO']=self.get_server_sync()
218
219        return output
Note: See TracBrowser for help on using the repository browser.