]> scripts.mit.edu Git - xen.git/blob - scripts/vtpm-common.sh
Change hard-coded source_server to a currently existing one
[xen.git] / scripts / vtpm-common.sh
1 #
2 # Copyright (c) 2005 IBM Corporation
3 # Copyright (c) 2005 XenSource Ltd.
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 #
18
19 dir=$(dirname "$0")
20 . "$dir/logging.sh"
21 . "$dir/locking.sh"
22
23 VTPMDB="/var/vtpm/vtpm.db"
24
25 #In the vtpm-impl file some commands should be defined:
26 #      vtpm_create, vtpm_setup, vtpm_start, etc. (see below)
27 if [ -r "$dir/vtpm-impl.alt" ]; then
28         . "$dir/vtpm-impl.alt"
29 elif [ -r "$dir/vtpm-impl" ]; then
30         . "$dir/vtpm-impl"
31 else
32         function vtpm_create () {
33                 true
34         }
35         function vtpm_setup() {
36                 true
37         }
38         function vtpm_start() {
39                 true
40         }
41         function vtpm_suspend() {
42                 true
43         }
44         function vtpm_resume() {
45                 true
46         }
47         function vtpm_delete() {
48                 true
49         }
50         function vtpm_migrate() {
51                 echo "Error: vTPM migration accross machines not implemented."
52         }
53         function vtpm_migrate_local() {
54                 echo "Error: local vTPM migration not supported"
55         }
56         function vtpm_migrate_recover() {
57                 true
58         }
59 fi
60
61
62 #Find the instance number for the vtpm given the name of the domain
63 # Parameters
64 # - vmname : the name of the vm
65 # Return value
66 #  Returns '0' if instance number could not be found, otherwise
67 #  it returns the instance number in the variable 'instance'
68 function vtpmdb_find_instance () {
69         local vmname ret instance
70         vmname=$1
71         ret=0
72
73         instance=$(cat $VTPMDB |                   \
74                   awk -vvmname=$vmname             \
75                   '{                               \
76                      if ( 1 != index($1,"#")) {    \
77                        if ( $1 == vmname ) {       \
78                          print $2;                 \
79                          exit;                     \
80                        }                           \
81                      }                             \
82                    }')
83         if [ "$instance" != "" ]; then
84                 ret=$instance
85         fi
86         echo "$ret"
87 }
88
89
90 # Check whether a particular instance number is still available
91 # returns "0" if it is not available, "1" otherwise.
92 function vtpmdb_is_free_instancenum () {
93         local instance instances avail i
94         instance=$1
95         avail=1
96         #Allowed instance number range: 1-255
97         if [ $instance -eq 0 -o $instance -gt 255 ]; then
98                 avail=0
99         else
100                 instances=$(cat $VTPMDB |                \
101                            gawk                          \
102                            '{                            \
103                                if (1 != index($1,"#")) { \
104                                  printf("%s ",$2);       \
105                                }                         \
106                             }')
107                 for i in $instances; do
108                         if [ $i -eq $instance ]; then
109                                 avail=0
110                                 break
111                         fi
112                 done
113         fi
114         echo "$avail"
115 }
116
117
118 # Get an available instance number given the database
119 # Returns an unused instance number
120 function vtpmdb_get_free_instancenum () {
121         local ctr instances don found
122         instances=$(cat $VTPMDB |                \
123                    gawk                          \
124                    '{                            \
125                        if (1 != index($1,"#")) { \
126                          printf("%s ",$2);       \
127                        }                         \
128                     }')
129         ctr=1
130         don=0
131         while [ $don -eq 0 ]; do
132                 found=0
133                 for i in $instances; do
134                         if [ $i -eq $ctr ]; then
135                                 found=1;
136                                 break;
137                         fi
138                 done
139
140                 if [ $found -eq 0 ]; then
141                         don=1
142                         break
143                 fi
144                 let ctr=ctr+1
145         done
146         echo "$ctr"
147 }
148
149
150 # Add a domain name and instance number to the DB file
151 function vtpmdb_add_instance () {
152         local res vmname inst
153         vmname=$1
154         inst=$2
155
156         if [ ! -f $VTPMDB ]; then
157                 echo "#Database for VM to vTPM association" > $VTPMDB
158                 echo "#1st column: domain name" >> $VTPMDB
159                 echo "#2nd column: TPM instance number" >> $VTPMDB
160         fi
161         res=$(vtpmdb_validate_entry $vmname $inst)
162         if [ $res -eq 0 ]; then
163                 echo "$vmname $inst" >> $VTPMDB
164         fi
165 }
166
167
168 #Validate whether an entry is the same as passed to this
169 #function
170 function vtpmdb_validate_entry () {
171         local res rc vmname inst
172         rc=0
173         vmname=$1
174         inst=$2
175
176         res=$(cat $VTPMDB |            \
177              gawk -vvmname=$vmname     \
178                   -vinst=$inst         \
179              '{                        \
180                  if ( 1 == index($1,"#")) {\
181                  } else                \
182                  if ( $1 == vmname &&  \
183                       $2 == inst) {    \
184                     printf("1");       \
185                     exit;              \
186                  } else                \
187                  if ( $1 == vmname ||  \
188                       $2 == inst) {    \
189                     printf("2");       \
190                     exit;              \
191                  }                     \
192              }')
193
194         if [ "$res" == "1" ]; then
195                 rc=1
196         elif [ "$res" == "2" ]; then
197                 rc=2
198         fi
199         echo "$rc"
200 }
201
202
203 #Remove an entry from the vTPM database given its domain name
204 #and instance number
205 function vtpmdb_remove_entry () {
206         local vmname instance VTPMDB_TMP
207         vmname=$1
208         instance=$2
209         VTPMDB_TMP="$VTPMDB".tmp
210
211         $(cat $VTPMDB |            \
212          gawk -vvmname=$vmname     \
213          '{                        \
214             if ( $1 != vmname ) {  \
215               print $0;            \
216             }                      \
217          '} > $VTPMDB_TMP)
218         if [ -e $VTPMDB_TMP ]; then
219                 mv -f $VTPMDB_TMP $VTPMDB
220                 vtpm_delete $instance
221         else
222                 log err "Error creating temporary file '$VTPMDB_TMP'."
223         fi
224 }
225
226
227 # Find the reason for the creation of this device:
228 # Returns 'resume' or 'create'
229 function vtpm_get_create_reason () {
230         local resume
231         resume=$(xenstore_read $XENBUS_PATH/resume)
232         if [ "$resume" == "True" ]; then
233                 echo "resume"
234         else
235                 echo "create"
236         fi
237 }
238
239
240 #Create a vTPM instance
241 # If no entry in the TPM database is found, the instance is
242 # created and an entry added to the database.
243 function vtpm_create_instance () {
244         local res instance domname reason uuid
245         uuid=$(xenstore_read "$XENBUS_PATH"/uuid)
246         reason=$(vtpm_get_create_reason)
247
248         claim_lock vtpmdb
249
250         instance="0"
251
252         if [ "$uuid" != "" ]; then
253                 instance=$(vtpmdb_find_instance $uuid)
254         fi
255         if [ "$instance" == "0" ]; then
256                 domname=$(xenstore_read "$XENBUS_PATH"/domain)
257                 instance=$(vtpmdb_find_instance $domname)
258         fi
259
260         if [ "$instance" == "0" -a "$reason" != "create" ]; then
261                 release_lock vtpmdb
262                 return
263         fi
264
265         if [ "$instance" == "0" ]; then
266                 #Try to give the preferred instance to the domain
267                 instance=$(xenstore_read "$XENBUS_PATH"/pref_instance)
268                 if [ "$instance" != "" ]; then
269                         res=$(vtpmdb_is_free_instancenum $instance)
270                         if [ $res -eq 0 ]; then
271                                 instance=$(vtpmdb_get_free_instancenum)
272                         fi
273                 else
274                         instance=$(vtpmdb_get_free_instancenum)
275                 fi
276
277                 vtpm_create $instance
278
279                 if [ $vtpm_fatal_error -eq 0 ]; then
280                         if [ "$uuid" != "" ]; then
281                                 vtpmdb_add_instance $uuid $instance
282                         else
283                                 vtpmdb_add_instance $domname $instance
284                         fi
285                 fi
286         else
287                 if [ "$reason" == "resume" ]; then
288                         vtpm_resume $instance
289                 else
290                         vtpm_start $instance
291                 fi
292         fi
293
294         release_lock vtpmdb
295
296         xenstore_write $XENBUS_PATH/instance $instance
297 }
298
299
300 #Remove an instance when a VM is terminating or suspending.
301 #Since it is assumed that the VM will appear again, the
302 #entry is kept in the VTPMDB file.
303 function vtpm_remove_instance () {
304         local instance reason domname uuid
305         #Stop script execution quietly if path does not exist (anymore)
306         xenstore-exists "$XENBUS_PATH"/domain
307         uuid=$(xenstore_read "$XENBUS_PATH"/uuid)
308
309         claim_lock vtpmdb
310
311         instance="0"
312
313         if [ "$uuid" != "" ]; then
314                 instance=$(vtpmdb_find_instance $uuid)
315         fi
316
317         if [ "$instance" == "0" ]; then
318                 domname=$(xenstore_read "$XENBUS_PATH"/domain)
319                 instance=$(vtpmdb_find_instance $domname)
320         fi
321
322         if [ "$instance" != "0" ]; then
323                 vtpm_suspend $instance
324         fi
325
326         release_lock vtpmdb
327 }
328
329
330 #Remove an entry in the VTPMDB file given the domain's name
331 #1st parameter: The name of the domain
332 function vtpm_delete_instance () {
333         local instance
334
335         claim_lock vtpmdb
336
337         instance=$(vtpmdb_find_instance $1)
338         if [ "$instance" != "0" ]; then
339                 vtpmdb_remove_entry $1 $instance
340         fi
341
342         release_lock vtpmdb
343 }
344
345 # Determine whether the given address is local to this machine
346 # Return values:
347 #  "-1" : the given machine name is invalid
348 #  "0"  : this is not an address of this machine
349 #  "1"  : this is an address local to this machine
350 function vtpm_isLocalAddress() {
351         local addr res
352         addr=$(ping $1 -c 1 |  \
353                gawk '{ print substr($3,2,length($3)-2); exit }')
354         if [ "$addr" == "" ]; then
355                 echo "-1"
356                 return
357         fi
358         res=$(ifconfig | grep "inet addr" |  \
359              gawk -vaddr=$addr               \
360              '{                              \
361                 if ( addr == substr($2, 6)) {\
362                   print "1";                 \
363                 }                            \
364              }'                              \
365             )
366         if [ "$res" == "" ]; then
367                 echo "0"
368                 return
369         fi
370         echo "1"
371 }
372
373 # Perform a migration step. This function differentiates between migration
374 # to the local host or to a remote machine.
375 # Parameters:
376 # 1st: destination host to migrate to
377 # 2nd: name of the domain to migrate
378 # 3rd: the migration step to perform
379 function vtpm_migration_step() {
380         local res=$(vtpm_isLocalAddress $1)
381         if [ "$res" == "0" ]; then
382                 vtpm_migrate $1 $2 $3
383         else
384                 vtpm_migrate_local
385         fi
386 }
387
388 # Recover from migration due to an error. This function differentiates
389 # between migration to the local host or to a remote machine.
390 # Parameters:
391 # 1st: destination host the migration was going to
392 # 2nd: name of the domain that was to be migrated
393 # 3rd: the last successful migration step that was done
394 function vtpm_recover() {
395         local res
396         res=$(vtpm_isLocalAddress $1)
397         if [ "$res" == "0" ]; then
398                 vtpm_migrate_recover $1 $2 $3
399         fi
400 }
401
402
403 #Determine the domain id given a domain's name.
404 #1st parameter: name of the domain
405 #return value: domain id  or -1 if domain id could not be determined
406 function vtpm_domid_from_name () {
407         local id name ids
408         ids=$(xenstore-list /local/domain)
409         for id in $ids; do
410                 name=$(xenstore-read /local/domain/$id/name)
411                 if [ "$name" == "$1" ]; then
412                         echo "$id"
413                         return
414                 fi
415         done
416         echo "-1"
417 }
418
419 #Determine the virtual TPM's instance number using the domain ID.
420 #1st parm: domain ID
421 function vtpm_uuid_by_domid() {
422         echo $(xenstore-read /local/domain/0/backend/vtpm/$1/0/uuid)
423 }
424
425
426 # Determine the vTPM's UUID by the name of the VM
427 function vtpm_uuid_from_vmname() {
428         local domid=$(vtpm_domid_from_name $1)
429         if [ "$domid" != "-1" ]; then
430                 echo $(vtpm_uuid_by_domid $domid)
431                 return
432         fi
433         echo ""
434 }
435
436 #Add a virtual TPM instance number and its associated domain name
437 #to the VTPMDB file and activate usage of this virtual TPM instance
438 #by writing the instance number into the xenstore
439 #1st parm: name of virtual machine
440 #2nd parm: instance of associated virtual TPM
441 function vtpm_add_and_activate() {
442         local domid=$(vtpm_domid_from_name $1)
443         local vtpm_uuid=$(vtpm_uuid_from_vmname $1)
444         if [ "$vtpm_uuid" != "" -a "$domid" != "-1" ]; then
445                 vtpmdb_add_instance $vtpm_uuid $2
446                 xenstore-write backend/vtpm/$domid/0/instance $2
447         fi
448 }