Class: Hal

Inherits:
Object
  • Object
show all
Defined in:
lib/libisi/hal.rb

Overview

Copyright © 2007-2010 Logintas AG Switzerland

This file is part of Libisi.

Libisi 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 3 of the License, or (at your option) any later version.

Libisi 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 Libisi. If not, see <www.gnu.org/licenses/>.

Constant Summary collapse

HAL_PREFIX =
"/org/freedesktop/Hal/devices"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(udi, hash) ⇒ Hal

Returns a new instance of Hal.



85
86
87
88
89
90
# File 'lib/libisi/hal.rb', line 85

def initialize(udi, hash)
  raise "udi is nil" unless udi
  raise "hash is nil for #{udi}" unless hash
  @udi = udi
  @hash = hash
end

Instance Attribute Details

#hashObject

Returns the value of attribute hash.



84
85
86
# File 'lib/libisi/hal.rb', line 84

def hash
  @hash
end

#udiObject

Returns the value of attribute udi.



84
85
86
# File 'lib/libisi/hal.rb', line 84

def udi
  @udi
end

Class Method Details

.floppy_is_mounted?Boolean

check whether a floppy is mounted

Returns:

  • (Boolean)


352
353
354
# File 'lib/libisi/hal.rb', line 352

def self.floppy_is_mounted?
  get_floppies.select {|f| f.mounted?}.length > 0
end

.floppy_is_mounted_readonly?Boolean

check whether a floppy is mounted read-only

Returns:

  • (Boolean)


357
358
359
# File 'lib/libisi/hal.rb', line 357

def self.floppy_is_mounted_readonly?
  get_floppies.select {|f| f.mounted? and f.mounted_readonly?}.length > 0
end

.get_block_device(block_device_name) ⇒ Object



341
342
343
# File 'lib/libisi/hal.rb', line 341

def self.get_block_device(block_device_name)
  list.select {|h| h.block_device == block_device_name}[0]
end

.get_by_block_device_name(block_device_name) ⇒ Object



332
333
334
335
336
# File 'lib/libisi/hal.rb', line 332

def self.get_by_block_device_name(block_device_name)
  list.select {|h|
    h.block_device == block_device_name
  }[0]
end

.get_by_label(label) ⇒ Object



337
338
339
# File 'lib/libisi/hal.rb', line 337

def self.get_by_label(label)
  list.select {|h| h.label == label}[0]
end

.get_by_udi(udi) ⇒ Object



327
328
329
330
331
# File 'lib/libisi/hal.rb', line 327

def self.get_by_udi(udi)
  hash = Hal.parse_hal[udi]
  return nil unless hash
  Hal.new(udi, hash)
end

.get_floppiesObject

list floppy storage udis on stdout; one udi per line usage: hal_get_floppies



347
348
349
# File 'lib/libisi/hal.rb', line 347

def self.get_floppies
  list.select {|h| h.storage? and h.floppy? }
end

.get_removable_volumesObject

list removable volume udis on stdout; one udi per line usage: hal_get_removable_volumes



323
324
325
# File 'lib/libisi/hal.rb', line 323

def self.get_removable_volumes
  list.select {|h| h.removable? }
end

.get_volumesObject

list volume udis on stdout; one udi per line usage: hal_get_volumes



317
318
319
# File 'lib/libisi/hal.rb', line 317

def self.get_volumes
  list.select {|h| h.volume? }
end

.listObject



79
80
81
# File 'lib/libisi/hal.rb', line 79

def self.list
  parse_hal.map {|udi, hash| Hal.new(udi,hash)}    
end

.parse_halObject



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
# File 'lib/libisi/hal.rb', line 21

def self.parse_hal
  debughal = false
  udis = {}
  open("|lshal") {|f|
    current_item = nil
    current_udi = nil
    while true
	current = f.readline
	
	$log.debug("Current line is: #{current.inspect}") if debughal
	case current
	when /^udi = \'(.*)\'\s*$/
 $log.debug("UDI: #{$1}") if debughal
 current_udi = $1
 current_item ={}
	when /^\s+(\S+) = \{(.*)\} \(string list\)\s*$/
	# list
 name = $1
 $log.debug("Array is: #{$2.inspect}") if debughal
 current_item[name] = $2.split("', '")	
 current_item[name][0] = current_item[name][0].sub(/^\'/,"") if current_item[name][0]
 current_item[name][-1] = current_item[name][-1].sub(/\'$/,"") if current_item[name][-1]
	when /^\s+(\S+) = \'(.*)\'  \(string\)\s*$/
 # string
 current_item[$1] = $2
	when /^\s+(\S+) = (false|true)  \(bool\)\s*$/
 # boolean
 case $2
 when "false"
   current_item[$1] = false
 when "true"
   current_item[$1] = true
 else
   raise "Unexpected boolean value #{$2}"
 end
	when /^\s+(\S+) = (\-?\d+)  \(.*\)  \(int\)\s*$/,/^\s+(\S+) = (\d+)  \(.*\)  \(uint64\)\s*$/
 raise "Convert to integer failed #{$2.to_i.to_s} != #{$2}." if $2.to_i.to_s != $2
 current_item[$1] = $2.to_i
	when /^\s+(\S+) = (\-?\d+\.\d+) \(.*\) \(double\)\s*$/
 current_item[$1] = $2.to_f
	when /^\s*$/
 if current_udi
   udis["udi"] = current_udi
   udis[current_udi] = current_item 
 end
 current_item = nil
 current_udi = nil
	when /^Dumping/,/^----/
	when /^Dumped/
	else
 raise "Unexpected line in lshal #{current.inspect}"
	end
    end
  }
rescue EOFError
  udis
end

Instance Method Details

#block_deviceObject

# mount a luks volume given its backing volume

def luks_mount (name)
  local lUdi=$1
  local lName=$2

  if [ -z "$lUdi" ]; then
    return
    fi

    lSetupVolumeUdi=$(hal_luks_get_setup_volume $lUdi)

hal_volume_mount $lSetupVolumeUdi $lName
lRet=$?
return $lRet

}

# get the assigned volume in case this luks volume has been set up # usage: hal_luks_get_setup_volume <luks udi> def luks_get_setup_volume

 local lUdi=$1

local lVolumeUdis=$(hal_get_volumes)
if [ -n "$lVolumeUdis" ]; then
  for lVolumeUdi in $lVolumeUdis; do
    if lshal -l -u $lVolumeUdi | grep -q "volume.crypto_luks.clear.backing_volume.*=.*$lHalPrefix/$lUdi"; then
      echo $lVolumeUdi
      return
    fi
  done
fi

# not found
echo ""

}



299
300
301
# File 'lib/libisi/hal.rb', line 299

def block_device
  hash["block.device"]
end

#dbus_send(*arguments) ⇒ Object



163
164
165
166
167
168
169
170
171
172
# File 'lib/libisi/hal.rb', line 163

def dbus_send(*arguments)
  cmd = ["dbus-send","--print-reply", "--system","--dest=org.freedesktop.Hal","#{udi}"]
  cmd += arguments
  if arguments[0].include?("Lock")
    execute_command_popen3(cmd)
  else
    hal_lock {execute_command_popen3(cmd)}
  end
  reload
end

#dbus_send_with_password(*arguments) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/libisi/hal.rb', line 155

def dbus_send_with_password(*arguments)
  cmd = ["dbus-send","--print-reply", "--system","--dest=org.freedesktop.Hal","#{udi}"]
  cmd += arguments
  hal_lock {
    raise "Dbus send error" unless system(*cmd)
  }
  reload
end

#exist?Boolean

Returns:

  • (Boolean)


129
130
131
132
# File 'lib/libisi/hal.rb', line 129

def exist?
  reload
  return !hash.nil?
end

#floppy?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/libisi/hal.rb', line 109

def floppy?
  hash["storage.drive_type"] == "floppy"
end

#fstypeObject



311
312
313
# File 'lib/libisi/hal.rb', line 311

def fstype
  hash["volume.fstype"]
end

#hal_lockObject



146
147
148
149
150
151
152
153
154
# File 'lib/libisi/hal.rb', line 146

def hal_lock
  # DISABLED, because commands do not work
  # DISABLED dbus_send("org.freedesktop.Hal.Device.Lock","string:litkeys")
  begin
    return yield
  ensure
    # DISABLED dbus_send("org.freedesktop.Hal.Device.UnLock")
  end
end

#is_luks?Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/libisi/hal.rb', line 126

def is_luks?
  hash["volume.fstype"] == "crypto_LUKS"
end

#labelObject



308
309
310
# File 'lib/libisi/hal.rb', line 308

def label
  hash["volume.label"]
end

#luks_backing_volumeObject



256
257
258
259
# File 'lib/libisi/hal.rb', line 256

def luks_backing_volume
  $log.debug("Looking for backing volume: #{hash["volume.crypto_luks.clear.backing_volume"]}")
  Hal.get_by_udi(hash["volume.crypto_luks.clear.backing_volume"])
end

#luks_setup(options = {}) ⇒ Object

LUKS setup a luks volume, given its backingn volume



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/libisi/hal.rb', line 213

def luks_setup(options = {})
  raise "Device is no luksdevice." unless is_luks?
  
  storage_device = parent
  device_name = nil
  partition_no = nil
  if parent.hash["info.category"] == 'storage'
    device_name = "#{parent.hash["info.vendor"]} #{parent.hash["info.product"]}"
    partition_no = hash["volume.partition.number"]
  end

  if device_name and partition_no
    prompt_description = "partition #{partition_no} on \"#{device_name}\" (#{block_device})"
  else
    prompt_description = block_device
  end

  password = (options[:password] or $ui.password("Enter LUKS password for #{prompt_description}"))

  5.times {|t|
    # BUG in HAL. Sometimes the label is not set.
    # Retry with Luks Teardown and Setup again.
    # Reload is not permitted for user.
    dbus_send_with_password("org.freedesktop.Hal.Device.Volume.Crypto.Setup","string:#{password}")
    sleep(t + 1)
    if luks_volume.label != ""
	break
    else
	$log.warn("Luks partition of device #{udi} has no label defined. Probably this is a bug in HAL, Teardown Luks again.")
	dbus_send("org.freedesktop.Hal.Device.Volume.Crypto.Teardown")
    end      
  }
  
  luks_volume
end

#luks_setup?Boolean

Returns:

  • (Boolean)


253
254
255
# File 'lib/libisi/hal.rb', line 253

def luks_setup?
  !luks_volume.nil?
end

#luks_teardownObject

teardown a luks volume, given its backing volume



249
250
251
# File 'lib/libisi/hal.rb', line 249

def luks_teardown
  dbus_send("org.freedesktop.Hal.Device.Volume.Crypto.Teardown")
end

#luks_volumeObject



260
261
262
# File 'lib/libisi/hal.rb', line 260

def luks_volume
  Hal.list.select {|h| h.hash["volume.crypto_luks.clear.backing_volume"] == udi}[0]
end

#mount(name = nil, options = {}) ⇒ Object

mount a volume usage: hal_volume_mount <volume_id> [<mountpoint name>]



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/libisi/hal.rb', line 176

def mount(name = nil, options = {})
  $log.debug("Mount #{udi} to #{name.inspect}")
  raise "Volume #{block_device.inspect} is not mountable" unless mountable?
  return (luks_volume or luks_setup(options)).mount(name,options) if is_luks?

  name ||= label
  name ||= hash["storage.model"]
  name = name.gsub(/\s/,"_")

  if mounted? 
    raise "already mounted to another mount point #{mount_point.inspect}" if mount_point != "/media/#{name}"
    return
  end

  $log.info("Going to mount under #{name.inspect}")
  raise "Cannot mount with name #{name.inspect}" if name.nil? or name.to_s.strip == ""
  #id = open("|id -u") {|f| f.readlines[0].to_i }
  #"array:string:noexec,uid=#{id}
  mount_options = ((options[:mount_options] or "").split(",") + ["noexec"]).uniq.join(",")
  dbus_send("org.freedesktop.Hal.Device.Volume.Mount",
     "string:#{$name}","string:","array:string:#{mount_options}")
end

#mount_pointObject



134
135
136
137
# File 'lib/libisi/hal.rb', line 134

def mount_point
  return nil unless mounted?
  hash["volume.mount_point"]
end

#mountable?Boolean

Returns:

  • (Boolean)


112
113
114
115
# File 'lib/libisi/hal.rb', line 112

def mountable?
  return true if hash["volume.crypto_luks.clear.backing_volume"]
  (hash["volume.fstype"] or "") != "" or is_luks?
end

#mounted?Boolean

Returns:

  • (Boolean)


116
117
118
119
120
121
122
# File 'lib/libisi/hal.rb', line 116

def mounted?
  if is_luks?
    luks_volume and luks_volume.mounted?
  else
    (hash["volume.is_mounted"] or "") != ""
  end   
end

#mounted_readonly?Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/libisi/hal.rb', line 123

def mounted_readonly?
  hash["volume.is_mounted_read_only"]
end

#parentObject



92
93
94
# File 'lib/libisi/hal.rb', line 92

def parent
  Hal.get_by_udi(hash["info.parent"])
end

#partition?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/libisi/hal.rb', line 99

def partition?
  hash["volume.is_partition"] and hash["volume.is_partition"] == true
end

#productObject



305
306
307
# File 'lib/libisi/hal.rb', line 305

def product
  hash["info.product"]
end

#reloadObject



139
140
141
142
143
144
145
# File 'lib/libisi/hal.rb', line 139

def reload

#    dbus_send("org.freedesktop.Hal.Device.Rescan",
#	      "string:#{$name}","string:","array:string:noexec")

  @hash = Hal.parse_hal[udi]
end

#removable?Boolean

Returns:

  • (Boolean)


102
103
104
105
# File 'lib/libisi/hal.rb', line 102

def removable?
  return parent.removable? if partition?
  hash["storage.removable"] or (hash["storage.drive_type"] == "sd_mmc")
end

#storage?Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/libisi/hal.rb', line 106

def storage?
  hash["info.category"] == "storage"
end

#storage_deviceObject



302
303
304
# File 'lib/libisi/hal.rb', line 302

def storage_device
  hash["block.storage_device"]
end

#to_sObject



361
362
363
364
365
# File 'lib/libisi/hal.rb', line 361

def to_s
  ret =  "#{udi}:\n"
  hash.each {|key, val| ret += "  #{key}: #{val.inspect}\n" }
  ret
end

#umountObject

unmount a volume



200
# File 'lib/libisi/hal.rb', line 200

def umount; unmount ; end

#unmountObject



201
202
203
204
205
206
207
208
209
# File 'lib/libisi/hal.rb', line 201

def unmount
  if luks_setup?
    ret = luks_volume.unmount
    luks_teardown
    return ret
  end
  raise "Not mounted." unless mounted?
  dbus_send("org.freedesktop.Hal.Device.Volume.Unmount","array:string:")
end

#volume?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/libisi/hal.rb', line 96

def volume?
  hash["info.category"] == "volume"
end