~ubuntu-branches/ubuntu/precise/tgt/precise

« back to all changes in this revision

Viewing changes to .pc/scripts-tgt-admin/scripts/tgt-admin

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2010-09-10 16:19:59 UTC
  • mfrom: (6.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20100910161959-mrtxqtgq5atinfp5
Tags: 1:1.0.4-2ubuntu1
* Merge from debian unstable.  Remaining changes:
  - debian/upstart: Add upstart job.
  - Dropped:
    + debian/patches/scripts-tgt-admin: Use debian's instead.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/perl
2
 
#
3
 
# This tools parses /etc/tgt/targets.conf file and configures tgt
4
 
#
5
 
# Author:  Tomasz Chmielewski
6
 
# License: GPLv2
7
 
#
8
 
 
9
 
use strict;
10
 
use Config::General qw(ParseConfig);
11
 
use Getopt::Long;
12
 
 
13
 
# Our config file
14
 
my $configfile = "/etc/tgt/targets.conf";
15
 
 
16
 
sub usage {
17
 
        print <<EOF;
18
 
Usage:
19
 
tgt-admin [OPTION]...
20
 
This tool configures tgt targets.
21
 
 
22
 
  -e, --execute                 read $configfile and execute tgtadm commands
23
 
      --delete <value>          delete all or selected targets
24
 
                                (see "--delete help" for more info)
25
 
      --offline <value>         put all or selected targets in offline state
26
 
                                (see "--offline help" for more info)
27
 
      --ready <value>           put all or selected targets in ready state
28
 
                                (see "--ready help" for more info)
29
 
      --update <value>          update configuration for all or selected targets
30
 
                                (see "--update help" for more info)
31
 
  -s, --show                    show all the targets
32
 
  -c, --conf <conf file>        specify an alternative configuration file
33
 
      --ignore-errors           continue even if tgtadm exits with non-zero code
34
 
  -f, --force                   force some operations even if the target is in use
35
 
  -p, --pretend                 only print tgtadm options
36
 
      --dump                    dump current tgtd configuration (note: does not
37
 
                                include detailed parameters, like write caching)
38
 
  -v, --verbose                 increase verbosity (show tgtadm commands)
39
 
  -h, --help                    show this help
40
 
 
41
 
EOF
42
 
        exit;
43
 
}
44
 
 
45
 
my %conf;
46
 
my $param = $ARGV[0];
47
 
my $execute = 0;
48
 
my $delete = 0;
49
 
my $offline = 0;
50
 
my $ready = 0;
51
 
my $update = 0;
52
 
my $show = 0;
53
 
my $alternate_conf="0";
54
 
my $ignore_errors = 0;
55
 
my $force = 0;
56
 
my $pretend = 0;
57
 
my $dump = 0;
58
 
my $verbose = 0;
59
 
my $help = 0;
60
 
my $result = GetOptions (
61
 
        "e|execute"     => \$execute,
62
 
        "delete=s"      => \$delete,
63
 
        "offline=s"     => \$offline,
64
 
        "ready=s"       => \$ready,
65
 
        "update=s"      => \$update,
66
 
        "s|show"        => \$show,
67
 
        "c|conf=s"      => \$alternate_conf,
68
 
        "ignore-errors" => \$ignore_errors,
69
 
        "f|force"       => \$force,
70
 
        "p|pretend"     => \$pretend,
71
 
        "dump"          => \$dump,
72
 
        "v|verbose"     => \$verbose,
73
 
        "h|help"        => \$help,
74
 
);
75
 
 
76
 
if (($help == 1) || ($param eq undef)) {
77
 
        usage;
78
 
}
79
 
 
80
 
# Show all the targets and exit
81
 
if ($show == 1) {
82
 
        execute("tgtadm --op show --mode target");
83
 
        exit;
84
 
}
85
 
 
86
 
# Some variables/arrays/hashes we will use globally
87
 
my %tgtadm_output;
88
 
my %tgtadm_output_tid;
89
 
my %tgtadm_output_name;
90
 
my @largest_tid;
91
 
my $next_tid;
92
 
 
93
 
# Look up which targets are configured
94
 
sub process_targets {
95
 
        # We need to run as root
96
 
        if ( $> ) {
97
 
                die("You must be root to run this program.\n");
98
 
        }
99
 
 
100
 
        my @show_target = `tgtadm --op show --mode target`;
101
 
        my $tid;
102
 
        my $targetname;
103
 
        # Here, we create hashes of target names (all target data) and target tids
104
 
        foreach my $show_target_line (@show_target) {
105
 
                if ( $show_target_line =~ m/^Target (\d*): (.+)/ ) {
106
 
                        $tid = $1;
107
 
                        $targetname = $2;
108
 
                        $tgtadm_output{$targetname} = $show_target_line;
109
 
                        $tgtadm_output_tid{$targetname} = $tid;
110
 
                        $tgtadm_output_name{$tid} = $targetname;
111
 
                } else {
112
 
                        $tgtadm_output{$targetname} .= $show_target_line;
113
 
                }
114
 
        }
115
 
        # What is the largest tid?
116
 
        my @tids = values %tgtadm_output_tid;
117
 
        @largest_tid = sort { $a <=> $b } @tids;
118
 
        $next_tid = $largest_tid[$#largest_tid];
119
 
}
120
 
 
121
 
# Parse config file(s)
122
 
sub parse_configs {
123
 
        # Parse the config
124
 
        if ($alternate_conf ne 0) {
125
 
                # Check if alternative configuration file exists
126
 
                if (-e "$alternate_conf") {
127
 
                        execute("# Using $alternate_conf as configuration file\n");
128
 
                        %conf = ParseConfig(-ConfigFile => "$alternate_conf", -UseApacheInclude => 1, -IncludeGlob => 1,);
129
 
                }
130
 
                else {
131
 
                        die("Config file $alternate_conf not found. Exiting...\n");
132
 
                }
133
 
        } else {
134
 
                # Parse the config file with Config::General
135
 
                if (-e "$configfile") {
136
 
                        %conf = ParseConfig(-ConfigFile => "$configfile", -UseApacheInclude => 1, -IncludeGlob => 1,);
137
 
                } else {
138
 
                        die("Config file $configfile not found. Exiting...\n");
139
 
                }
140
 
        }
141
 
}
142
 
 
143
 
# Add targets, if they are not configured already
144
 
my $default_driver;
145
 
my $target;
146
 
my $option;
147
 
my $value;
148
 
my $lun;
149
 
 
150
 
sub add_targets {
151
 
        my $single_target = $_[0];
152
 
        my $configured = $_[1];
153
 
        my $connected = $_[2];
154
 
        my $in_configfile = $_[3];
155
 
        foreach my $k (sort keys %conf) {
156
 
 
157
 
                if ($k eq "default-driver") {
158
 
                        if (not length ref($conf{$k})) {
159
 
                                $default_driver = $conf{$k};
160
 
                        } else {
161
 
                                print "Multiple default-driver definitions are not allowed!\n";
162
 
                                print "Check your config file for errors.\n";
163
 
                                exit 1;
164
 
                        }
165
 
                } elsif ($k eq "ignore-errors") {
166
 
                        if ($conf{$k} eq "yes") {
167
 
                                $ignore_errors = 1;
168
 
                        }
169
 
                }
170
 
        }
171
 
 
172
 
        # If $default_driver is empty, default to iscsi
173
 
        if (not defined $default_driver) {
174
 
                execute("# default-driver not defined, defaulting to iscsi.\n");
175
 
                $default_driver = "iscsi";
176
 
        }
177
 
 
178
 
        foreach my $k (sort keys %conf) {
179
 
                if ($k eq "target") {
180
 
                        foreach my $k2 (sort keys %{$conf{$k}}) {
181
 
                                # Do we run update or execute?
182
 
                                if (length $single_target) {
183
 
                                        if ($single_target ne $k2) {
184
 
                                                next;
185
 
                                        } else {
186
 
                                                $target = $single_target;
187
 
                                        }
188
 
                                } else {
189
 
                                        $target = $k2;
190
 
                                }
191
 
 
192
 
                                my $in_use = 0;
193
 
                                if (length $single_target) {
194
 
                                        $in_use = main_delete($target);
195
 
                                }
196
 
                                my $allowall = 1;
197
 
                                if ((not defined $tgtadm_output{$k2}) ||
198
 
                                        ($update ne 0 && $in_use == 0) ||
199
 
                                        ($update ne 0 && $in_use == 1 && $pretend == 1 && $force == 1))
200
 
                                        {
201
 
                                        # We have to find available tid
202
 
                                        if ($in_configfile == 1 && $configured == 0 && $pretend == 0) {
203
 
                                                my $maxtid = find_max_tid();
204
 
                                                $next_tid = $maxtid + 1;
205
 
                                        } elsif (length $single_target && $configured == 1) {
206
 
                                                $next_tid = $tgtadm_output_tid{$target};
207
 
                                        } else {
208
 
                                                $next_tid = $next_tid + 1;
209
 
                                        }
210
 
 
211
 
                                        # Before we add a target, we need to know its type
212
 
                                        # and other parameters which can be specified globally
213
 
                                        my %target_options;
214
 
                                        my $target_options_ref;
215
 
                                        my $data_key;
216
 
                                        foreach my $k3 (sort keys %{$conf{$k}{$k2}}) {
217
 
                                                $lun = 1;
218
 
                                                $option = $k3;
219
 
                                                $value = $conf{$k}{$k2}{$k3};
220
 
                                                check_value($value);
221
 
                                                $target_options{$option} = $value;
222
 
                                                $target_options_ref = \%target_options;
223
 
                                                $data_key = make_key($target_options_ref, "lun", "allow-in-use");
224
 
                                        }
225
 
 
226
 
                                        if (not defined $target_options{"driver"}) {
227
 
                                                $target_options{"driver"} = $default_driver;
228
 
                                        }
229
 
                                        my $driver = $target_options{"driver"};
230
 
                                        execute("# Adding target: $target");
231
 
                                        execute("tgtadm --lld $driver --op new --mode target --tid $next_tid -T $target");
232
 
                                        foreach my $k3 (sort keys %{$conf{$k}{$k2}}) {
233
 
                                                $option = $k3;
234
 
                                                $value = $conf{$k}{$k2}{$k3};
235
 
                                                check_value($value);
236
 
                                                process_options($target_options_ref,$data_key);
237
 
                                                # If there was no option called "initiator-address", it means
238
 
                                                # we want to allow ALL initiators for this target
239
 
                                                if ($option eq "initiator-address") {
240
 
                                                        $allowall = 0;
241
 
                                                }
242
 
                                        }
243
 
 
244
 
                                        if ($allowall == 1) {
245
 
                                                execute("tgtadm --lld $driver --op bind --mode target --tid $next_tid -I ALL");
246
 
                                        }
247
 
 
248
 
                                } else {
249
 
                                        if (not length $configured || $in_use eq 1) {
250
 
                                                execute("# Target $target already exists!");
251
 
                                        }
252
 
                                }
253
 
                        }
254
 
                        if (length $single_target && $in_configfile == 0 && $configured == 0) {
255
 
                                print "Target $single_target is currently not configured\n";
256
 
                                print "and does not exist in the config file - can't continue!\n";
257
 
                                exit 1;
258
 
                        }
259
 
                        execute();
260
 
                }
261
 
        }
262
 
}
263
 
 
264
 
# Pre-parse the config and get some values we need
265
 
sub make_key {
266
 
        my $target_options_ref = shift;
267
 
        my @actions = @_;
268
 
        my %data_key;
269
 
 
270
 
        foreach my $action (@actions) {
271
 
                if (ref $$target_options_ref{'backing-store'} eq "HASH") {
272
 
                        foreach my $testlun (keys %{$$target_options_ref{'backing-store'}}) {
273
 
                                $data_key{$testlun}{$action} = $$target_options_ref{'backing-store'}{$testlun}{$action};
274
 
                        }
275
 
                }
276
 
                if (ref $$target_options_ref{'direct-store'} eq "HASH") {
277
 
                        foreach my $testlun (keys %{$$target_options_ref{'direct-store'}}) {
278
 
                                $data_key{$testlun}{$action} = $$target_options_ref{'direct-store'}{$testlun}{$action};
279
 
                        }
280
 
                }
281
 
        }
282
 
        return \%data_key;
283
 
}
284
 
 
285
 
# Some options can be specified only once
286
 
sub check_if_hash_array {
287
 
        my $check = $_[0];
288
 
        my $definition = $_[1];
289
 
        if (ref($check) eq 'ARRAY' || ref($check) eq "HASH") {
290
 
                print "Multiple '$definition' definitions in '$option' not allowed!\n";
291
 
                print "Check your config file for errors (target: $target).\n";
292
 
                exit 1;
293
 
        }
294
 
}
295
 
 
296
 
# Force an array if we just have one command
297
 
sub force_array {
298
 
        unless (ref($value) eq 'ARRAY') {
299
 
                $value = [ $value ];
300
 
        }
301
 
}
302
 
 
303
 
# If we start any external command, we want to know if it exists
304
 
sub check_exe {
305
 
        my $command = $_[0];
306
 
        my $option = $_[1];
307
 
        my @path = split(":", $ENV{PATH});
308
 
        my $exists = 0;
309
 
        foreach my $path (@path) {
310
 
                if ( -x "$path/$command" && -f "$path/$command" ) { $exists = 1 }
311
 
        }
312
 
        if ($exists == 0) {
313
 
                if ($command eq "sg_inq") {
314
 
                        print "Command '$command' (needed by '$option') is not in your path - can't continue!\n";
315
 
                        exit 1;
316
 
                } elsif ($command eq "lsof") {
317
 
                        execute("# Command '$command' is not in your path.");
318
 
                        execute("# Can't reliably check if device is not in use.");
319
 
                        return 1;
320
 
                }
321
 
        }
322
 
}
323
 
 
324
 
# Apply additional parameters
325
 
sub add_params {
326
 
        my $param = shift;
327
 
        my $param_value = shift;
328
 
        my $lun = shift;
329
 
        my $driver = shift;
330
 
 
331
 
        if ($param eq "write-cache") {
332
 
                if ($param_value eq "off") {
333
 
                        return("tgtadm --lld $driver --op update --mode logicalunit --tid $next_tid --lun=$lun --params mode_page=8:0:18:0x10:0:0xff:0xff:0:0:0xff:0xff:0xff:0xff:0x80:0x14:0:0:0:0:0:0");
334
 
                } elsif ($param_value eq "on" || not length $param_value) {
335
 
                        return("# Write cache is enabled (default) for lun $lun.");
336
 
                } else {
337
 
                        return("# WARNING! Unknown value ($param_value) to write-cache! Accepted values are \"on\" and \"off\".");
338
 
                }
339
 
        }
340
 
 
341
 
        if ($param eq "scsi_id" || $param eq "scsi_sn" || $param eq "vendor_id" || $param eq "product_id" ||
342
 
            $param eq "product_rev" || $param eq "sense_format" || $param eq "removable" || $param eq "online" ||
343
 
            $param eq "path" || $param eq "mode_page") {
344
 
                return("tgtadm --lld $driver --op update --mode logicalunit --tid $next_tid --lun=$lun --params $param=\"$param_value\"");
345
 
        }
346
 
        if ($param eq "params") {
347
 
                return("tgtadm --lld $driver --op update --mode logicalunit --tid $next_tid --lun=$lun --params \"$param_value\"");
348
 
 
349
 
        }
350
 
}
351
 
 
352
 
# Find next available LUN
353
 
sub find_next_lun {
354
 
        my $backing_store = $_[0];
355
 
        my $data_key_ref = $_[1];
356
 
        my $lun_collision = 0;
357
 
        my $lun_is_free = 0;
358
 
        my $found_lun = 1;
359
 
        while ($lun_is_free == 0) {
360
 
                foreach my $testlun (keys %$data_key_ref) {
361
 
                        foreach my $testlun2 (values %{$$data_key_ref{$testlun}}) {
362
 
                                if ($found_lun eq $testlun2) {
363
 
                                        $lun_collision = 1;
364
 
                                }
365
 
                        }
366
 
                }
367
 
                if ($lun_collision == 0) {
368
 
                        $lun_is_free = 1;
369
 
                } else {
370
 
                        $found_lun += 1;
371
 
                }
372
 
                $lun_collision = 0;
373
 
        }
374
 
        $$data_key_ref{$backing_store}{'lun'} = $found_lun;
375
 
        return $found_lun;
376
 
}
377
 
 
378
 
# Add backing or direct store
379
 
sub add_backing_direct {
380
 
        my $backing_store = $_[0];
381
 
        my $target_options_ref = $_[1];
382
 
        my $data_key_ref = $_[2];
383
 
        my $direct_store = $_[3];
384
 
        my $driver = $$target_options_ref{"driver"};
385
 
 
386
 
        # Is the device in use?
387
 
        my $can_alloc = 1;
388
 
        if ($force != 1 && $$target_options_ref{'allow-in-use'} ne "yes") {
389
 
                $can_alloc = check_device($backing_store,$data_key_ref);
390
 
        }
391
 
 
392
 
        if (-e $backing_store && ! -d $backing_store && $can_alloc == 1) {
393
 
                my @exec_commands;
394
 
                my $device_type;
395
 
                my $bs_type;
396
 
                my %luns;
397
 
                my @added_luns;
398
 
                # Find out LUNs which are "reserved" in the config file
399
 
                if (ref $value eq "HASH") {
400
 
                        if (length $$data_key_ref{$backing_store}{'lun'}) {
401
 
                                $lun = $$data_key_ref{$backing_store}{'lun'};
402
 
                        } else {
403
 
                                # Find an available lun if it wasn't specified
404
 
                                $lun = find_next_lun($backing_store,$data_key_ref);
405
 
                        }
406
 
                }
407
 
                # Process parameters for each lun / backing store
408
 
                if (ref $value eq "HASH") {
409
 
                        my %params_added;
410
 
                        my @mode_page;
411
 
                        my @params;
412
 
                        foreach my $store (keys %$value) {
413
 
                                # lun
414
 
                                if (length $$target_options_ref{"lun"}) {
415
 
                                        check_if_hash_array($$target_options_ref{"lun"}, "lun");
416
 
                                        $lun = $$target_options_ref{"lun"};
417
 
                                }
418
 
 
419
 
                                if (ref $$value{$store} eq "HASH" && $store eq $backing_store) {
420
 
                                        foreach my $store_option (keys %{$$value{$store}}) {
421
 
                                                my $result = $$value{$store}{$store_option};
422
 
                                                check_value($result);
423
 
                                                if ($store_option ne "mode_page" && $store_option ne "params")
424
 
                                                        { check_if_hash_array($result,$store_option) }
425
 
                                                # write-cache can be set globally per target and overridden per lun,
426
 
                                                # so we treat it differently
427
 
                                                if ($store_option ne "mode_page" && $store_option ne "write-cache"
428
 
                                                        && $store_option ne "params") {
429
 
                                                        my $exec_command = add_params($store_option, $result, $lun, $driver);
430
 
                                                        push(@exec_commands, $exec_command);
431
 
                                                        $params_added{$store_option} = 1;
432
 
                                                }
433
 
                                                if ($store_option eq "write-cache") {
434
 
                                                        my $exec_command = add_params($store_option, $result, $lun, $driver);
435
 
                                                        $params_added{write_cache} = 1;
436
 
                                                        push(@exec_commands, $exec_command);
437
 
                                                }
438
 
                                                if ($store_option eq "device-type") {
439
 
                                                        $device_type = $result;
440
 
                                                        $params_added{$store_option} = 1;
441
 
                                                }
442
 
                                                if ($store_option eq "bs-type") {
443
 
                                                        $bs_type = $result;
444
 
                                                        $params_added{$store_option} = 1;
445
 
                                                }
446
 
                                                if ($store_option eq "mode_page") {
447
 
                                                        unless (ref($result) eq 'ARRAY') {
448
 
                                                                $result = [ $result ];
449
 
                                                        }
450
 
                                                        @mode_page = @$result;
451
 
                                                        foreach my $mode_page (@mode_page) {
452
 
                                                                my $exec_command = add_params($store_option, $mode_page, $lun, $driver);
453
 
                                                                push(@exec_commands, $exec_command);
454
 
                                                        }
455
 
                                                }
456
 
                                                if ($store_option eq "params") {
457
 
                                                        unless (ref($result) eq 'ARRAY') {
458
 
                                                                $result = [ $result ];
459
 
                                                        }
460
 
                                                        @params = @$result;
461
 
                                                        foreach my $param (@params) {
462
 
                                                                my $exec_command = add_params($store_option, $param, $lun, $driver);
463
 
                                                                push(@exec_commands, $exec_command);
464
 
                                                        }
465
 
                                                }
466
 
                                        }
467
 
                                }
468
 
                        }
469
 
                        # Used only if lun is a direct-store
470
 
                        my $sg_inq;
471
 
                        my %direct_params;
472
 
                        if ($direct_store == 1) {
473
 
                                $sg_inq=`sg_inq $backing_store`;
474
 
                                if ($sg_inq=~m {
475
 
                                        Vendor\ identification:\s+?(.*?)\n
476
 
                                        \s+Product\ identification:\s+(.*?)\n
477
 
                                        \s+Product\ revision\ level:\s+(.*?)\n
478
 
                                        (?:\s+Unit\ serial\ number:\s+(.*?)\n)?
479
 
                                        }xs ) {
480
 
                                        # If they were not defined globally for a target,
481
 
                                        # add them now
482
 
                                        if (not length $$target_options_ref{vendor_id}) {
483
 
                                                $direct_params{vendor_id} = $1;
484
 
                                        }
485
 
                                        if (not length $$target_options_ref{product_id}) {
486
 
                                                $direct_params{product_id} = $2;
487
 
                                        }
488
 
                                        if (not length $$target_options_ref{product_rev}) {
489
 
                                                $direct_params{product_rev} = $3;
490
 
                                        }
491
 
                                        if (not length $$target_options_ref{scsi_sn}) {
492
 
                                                $direct_params{scsi_sn} = $4;
493
 
                                        }
494
 
                                }
495
 
                        }
496
 
 
497
 
                        # Add these parameters if they were not overwritten in the config file
498
 
                        my @opts = ("scsi_id", "sense_format", "removable", "online", "path");
499
 
                        foreach my $single_opt (@opts) {
500
 
                                check_if_hash_array($$target_options_ref{$single_opt},$single_opt);
501
 
                                if ($params_added{$single_opt} ne 1 && length $$target_options_ref{$single_opt}) {
502
 
                                        my $exec_command = add_params($single_opt, $$target_options_ref{$single_opt}, $lun, $driver);
503
 
                                        push(@exec_commands, $exec_command);
504
 
                                        $params_added{$single_opt} = 1;
505
 
                                }
506
 
                        }
507
 
                        # These options can be fetched by sg_inq for direct-store
508
 
                        my @opts = ("vendor_id", "product_id", "product_rev", "scsi_sn");
509
 
                        foreach my $single_opt (@opts) {
510
 
                                check_if_hash_array($$target_options_ref{$single_opt},$single_opt);
511
 
                                my $this_opt;
512
 
                                if (length $$target_options_ref{$single_opt}) {
513
 
                                        $this_opt = $$target_options_ref{$single_opt};
514
 
                                } elsif (length $direct_params{$single_opt}) {
515
 
                                        $this_opt = $direct_params{$single_opt};
516
 
                                }
517
 
                                if ($params_added{$single_opt} ne 1 && length $this_opt) {
518
 
                                        my $exec_command = add_params($single_opt, $this_opt, $lun, $driver);
519
 
                                        push(@exec_commands, $exec_command);
520
 
                                        $params_added{$single_opt} = 1;
521
 
                                }
522
 
                        }
523
 
                        # write-cache
524
 
                        if ($params_added{write_cache} ne 1) {
525
 
                                my $exec_command = add_params("write-cache", $$target_options_ref{"write-cache"}, $lun, $driver);
526
 
                                push(@exec_commands, $exec_command);
527
 
                                $params_added{write_cache} = 1;
528
 
                        }
529
 
                        # mode_page
530
 
                        unless (ref($$target_options_ref{mode_page}) eq 'ARRAY') {
531
 
                                $$target_options_ref{mode_page} = [ $$target_options_ref{mode_page} ];
532
 
                        }
533
 
                        foreach my $mode_page (@{$$target_options_ref{"mode_page"}}) {
534
 
                                if (length $mode_page) {
535
 
                                        my $exec_command = add_params("mode_page", $mode_page, $lun, $driver);
536
 
                                        push(@exec_commands, $exec_command);
537
 
                                }
538
 
                        }
539
 
                        # params
540
 
                        unless (ref($$target_options_ref{params}) eq 'ARRAY') {
541
 
                                $$target_options_ref{params} = [ $$target_options_ref{params} ];
542
 
                        }
543
 
                        foreach my $param (@{$$target_options_ref{"params"}}) {
544
 
                                if (length $param) {
545
 
                                        my $exec_command = add_params("params", $param, $lun, $driver);
546
 
                                        push(@exec_commands, $exec_command);
547
 
                                }
548
 
                        }
549
 
                        # device-type
550
 
                        if ($params_added{"device-type"} ne 1) {
551
 
                                check_if_hash_array($$target_options_ref{"device-type"}, "device-type");
552
 
                                $device_type = $$target_options_ref{"device-type"};
553
 
                        }
554
 
                        # bs-type
555
 
                        if ($params_added{"bs-type"} ne 1) {
556
 
                                check_if_hash_array($$target_options_ref{"bs-type"}, "bs-type");
557
 
                                $bs_type = $$target_options_ref{"bs-type"};
558
 
                        }
559
 
                } else {
560
 
                        print "If you got here, this means your config file is not supported.\n";
561
 
                        print "Please report it to stgt mailing list and attach your config files.\n";
562
 
                        exit 1;
563
 
                }
564
 
                # Execute commands for a given LUN
565
 
                if (length $device_type) { $device_type = "--device-type $device_type" };
566
 
                if (length $bs_type) { $bs_type = "--bstype $bs_type" };
567
 
                execute("tgtadm --lld $driver --op new --mode logicalunit --tid $next_tid --lun $lun -b $backing_store $device_type $bs_type");
568
 
 
569
 
                # Commands should be executed in order
570
 
                my @execute_last;
571
 
                foreach my $exec_command (@exec_commands) {
572
 
                        if (length $exec_command) {
573
 
                                if ($exec_command =~ m/params mode_page/) {
574
 
                                        execute($exec_command);
575
 
                                } else {
576
 
                                        push(@execute_last, $exec_command);
577
 
                                }
578
 
                        }
579
 
                }
580
 
                foreach my $exec_command (@execute_last) {
581
 
                        execute($exec_command);
582
 
                }
583
 
                $lun += 1;
584
 
                return $lun;
585
 
        } elsif ($can_alloc == 0) {
586
 
                execute("# Skipping device $backing_store - it is in use.");
587
 
                execute("# You can override it with --force or 'allow-in-use yes' config option.");
588
 
                execute("# Note - do so only if you know what you're doing, you may damage your data.");
589
 
        } else {
590
 
                execute("# Skipping device: $backing_store");
591
 
                execute("# $backing_store does not exist - please check the configuration file");
592
 
        }
593
 
}
594
 
 
595
 
# Process options from the config file
596
 
sub process_options {
597
 
        my $target_options_ref = $_[0];
598
 
        my $data_key_ref = $_[1];
599
 
        my $driver = $$target_options_ref{"driver"};
600
 
        if ($option eq "backing-store" || $option eq "direct-store") {
601
 
                my $direct_store = 0;
602
 
                if ($option eq "direct-store") {
603
 
                        check_exe("sg_inq", "option direct-store");
604
 
                        $direct_store = 1;
605
 
                }
606
 
 
607
 
                # We want to make everything a hash to use it
608
 
                # in the same way later on
609
 
                unless (ref($value)) {
610
 
                        $value = { $value }
611
 
                }
612
 
 
613
 
                my %arrvalue;
614
 
                if (ref($value) eq "ARRAY") {
615
 
                        foreach my $backing_store (@$value) {
616
 
                                $arrvalue{$backing_store} = 1;
617
 
                        }
618
 
                        $value = \%arrvalue;
619
 
                }
620
 
 
621
 
                if (ref($value) eq "HASH") {
622
 
                        foreach my $backing_store (sort keys %$value) {
623
 
                                if ($backing_store =~ m/HASH/) {
624
 
                                        print "\nYour config file is not supported. See targets.conf.example for details.\n";
625
 
                                        exit 1;
626
 
                                }
627
 
                        }
628
 
                        foreach my $backing_store (sort keys %$value) {
629
 
                                add_backing_direct($backing_store,$target_options_ref,$data_key_ref,$direct_store);
630
 
                        }
631
 
                }
632
 
        }
633
 
 
634
 
        if ($option eq "incominguser") {
635
 
                # if we have one command, force it to be an array anyway
636
 
                force_array();
637
 
                my @value_arr = @$value;
638
 
                foreach my $incominguser (@value_arr) {
639
 
                        my @userpass = split(/ /, $incominguser);
640
 
                        check_value($userpass[1]);
641
 
                        execute("tgtadm --lld $driver --mode account --op delete --user=$userpass[0]");
642
 
                        execute("tgtadm --lld $driver --mode account --op new --user=$userpass[0] --password=$userpass[1]");
643
 
                        execute("tgtadm --lld $driver --mode account --op bind --tid=$next_tid --user=$userpass[0]");
644
 
                }
645
 
        }
646
 
 
647
 
        if ($option eq "outgoinguser") {
648
 
                # if we have one command, force it to be an array anyway
649
 
                force_array();
650
 
                if (length @$value[1]) {
651
 
                        execute("# Warning: only one $option is allowed. Will only use the first one.");
652
 
                }
653
 
                my @userpass = split(/ /, @$value[0]);
654
 
                check_value($userpass[1]);
655
 
                execute("tgtadm --lld $driver --mode account --op delete --user=$userpass[0]");
656
 
                execute("tgtadm --lld $driver --mode account --op new --user=$userpass[0] --password=$userpass[1]");
657
 
                execute("tgtadm --lld $driver --mode account --op bind --tid=$next_tid --user=$userpass[0] --outgoing");
658
 
        }
659
 
 
660
 
        if ($option eq "initiator-address") {
661
 
                # if we have one command, force it to be an array anyway
662
 
                force_array();
663
 
                my @value_arr = @$value;
664
 
                foreach my $initiator_address (@value_arr) {
665
 
                        check_value($initiator_address);
666
 
                        execute("tgtadm --lld $driver --op bind --mode target --tid $next_tid -I $initiator_address");
667
 
                }
668
 
        }
669
 
 
670
 
        if ($option =~ m/^MaxRecvDataSegmentLength$|
671
 
                        ^MaxXmitDataSegmentLength$|
672
 
                        ^HeaderDigest$|
673
 
                        ^DataDigest$|
674
 
                        ^InitialR2T$|
675
 
                        ^MaxOutstandingR2T$|
676
 
                        ^ImmediateData$|
677
 
                        ^FirstBurstLength$|
678
 
                        ^MaxBurstLength$|
679
 
                        ^DataPDUInOrder$|
680
 
                        ^DataSequenceInOrder$|
681
 
                        ^ErrorRecoveryLevel$|
682
 
                        ^IFMarker$|
683
 
                        ^OFMarker$|
684
 
                        ^DefaultTime2Wait$|
685
 
                        ^DefaultTime2Retain$|
686
 
                        ^OFMarkInt$|
687
 
                        ^IFMarkInt$|
688
 
                        ^MaxConnections/x) {
689
 
                # if we have one command, force it to be an array anyway
690
 
                force_array();
691
 
                if (length @$value[1]) {
692
 
                        execute("# Warning: only one $option is allowed. Will only use the first one.");
693
 
                }
694
 
                check_value($option);
695
 
                execute("tgtadm --lld $driver --mode target --op update --tid $next_tid --name $option --value $$value[0]");
696
 
        }
697
 
 
698
 
}
699
 
 
700
 
# If the target is configured, but not present in the config file,
701
 
# try to remove it
702
 
sub remove_targets {
703
 
 
704
 
        process_targets;
705
 
        my @all_targets = keys %tgtadm_output_tid;
706
 
 
707
 
        foreach my $existing_target (@all_targets) {
708
 
                my $dontremove = 0;
709
 
                my $k2;
710
 
                foreach my $k (sort keys %conf) {
711
 
                        if ( $k eq "target" ) {
712
 
                                foreach $k2 (sort keys %{$conf{$k}}) {
713
 
                                        if ( $k2 eq $existing_target ) {
714
 
                                                $dontremove = 1;
715
 
                                        }
716
 
                                }
717
 
 
718
 
                                if ( $dontremove == 0 ) {
719
 
                                        # Remove the target
720
 
                                        main_delete($existing_target);
721
 
                                }
722
 
                        }
723
 
                }
724
 
        }
725
 
}
726
 
 
727
 
# Dump current tgtd configuration
728
 
sub dump_config {
729
 
 
730
 
        process_targets;
731
 
 
732
 
        my @all_targets = keys %tgtadm_output_tid;
733
 
 
734
 
        # If all targets use the same driver, use it only once in the config
735
 
        my $skip_driver = 0;
736
 
        my @drivers_combined;
737
 
        foreach my $current_target (@all_targets) {
738
 
                my $driver = show_target_info($current_target, "driver");
739
 
                push (@drivers_combined, $driver);
740
 
        }
741
 
 
742
 
        my %drivers_uniq;
743
 
        @drivers_uniq{@drivers_combined} = ();
744
 
        my @drivers_combined_uniq = sort keys %drivers_uniq;
745
 
 
746
 
        if (scalar @drivers_combined_uniq == 1) {
747
 
                print "default-driver $drivers_combined_uniq[0]\n\n";
748
 
        }
749
 
 
750
 
        # Print everything else in the config
751
 
        foreach my $current_target (@all_targets) {
752
 
                my $target_name = show_target_info($current_target, "target_name");
753
 
                print "<target $target_name>\n";
754
 
 
755
 
                if (scalar @drivers_combined_uniq gt 1) {
756
 
                        my $driver = show_target_info($current_target, "driver");
757
 
                        print "\tdriver $driver\n";
758
 
                }
759
 
 
760
 
                my @backing_stores = show_target_info($current_target, "backing_stores");
761
 
                foreach my $backing_store (@backing_stores) {
762
 
                        print "\tbacking-store $backing_store\n";
763
 
                }
764
 
 
765
 
                my @account_information = show_target_info($current_target, "account_information");
766
 
                foreach my $account (@account_information) {
767
 
                        if ($account =~ /(.+)\ \(outgoing\)/) {
768
 
                                print "\toutgoinguser $1 PLEASE_CORRECT_THE_PASSWORD\n";
769
 
                        } elsif (length $account) {
770
 
                                print "\tincominguser $account PLEASE_CORRECT_THE_PASSWORD\n";
771
 
                        }
772
 
                }
773
 
 
774
 
                my @acl_information = show_target_info($current_target, "acl_information");
775
 
                if (scalar(@acl_information) != 1 || $acl_information[0] ne "ALL") {
776
 
                        foreach my $ini_address (@acl_information) {
777
 
                                print "\tinitiator-address $ini_address\n";
778
 
                        }
779
 
                }
780
 
                print "</target>\n\n";
781
 
        }
782
 
}
783
 
 
784
 
# Offline or ready targets
785
 
sub ready_offline_targets {
786
 
        my $var = $_[0]; # This variable is either "offline" or "ready"
787
 
        my $off_ready;
788
 
        if ($ready eq 0) {
789
 
                $off_ready = $offline
790
 
        } elsif ($offline eq 0) {
791
 
                $off_ready = $ready
792
 
        } else {
793
 
                print "Invalid value (you can't use both ready and offline)!\n";
794
 
                exit 1;
795
 
        }
796
 
        if ($off_ready eq "help") {
797
 
                print <<EOF;
798
 
      --$var <value>            $var all or selected targets
799
 
 
800
 
Example usage:
801
 
      --$var help             - display this help
802
 
      --$var ALL              - $var all targets
803
 
      --$var tid=4            - $var target 4 (target with tid 4)
804
 
      --$var iqn.2008-08.com.example:some.target - $var this target
805
 
 
806
 
EOF
807
 
        } elsif ($off_ready eq "ALL") {
808
 
                process_targets;
809
 
                # Run over all targets and offline/ready them
810
 
                my @all_targets = keys %tgtadm_output_tid;
811
 
                foreach my $existing_target (@all_targets) {
812
 
                        execute("tgtadm --op update --mode target --tid=$tgtadm_output_tid{$existing_target} -n state -v $var");
813
 
                }
814
 
        } elsif ($off_ready =~ m/tid=(.+)/) {
815
 
                process_targets;
816
 
                execute("tgtadm --op update --mode target --tid=$1 -n state -v $var");
817
 
        } else {
818
 
                process_targets;
819
 
                if (length $tgtadm_output_tid{$off_ready}) {
820
 
                        execute("tgtadm --op update --mode target --tid=$tgtadm_output_tid{$off_ready} --name=\"$off_ready\" -n state -v $var");
821
 
                } else {
822
 
                        print "There is no target with name \"$off_ready\", can't $var it!\n";
823
 
                        exit 1;
824
 
                }
825
 
        }
826
 
}
827
 
 
828
 
# Show info for a given target
829
 
sub show_target_info {
830
 
        my $existing_target = $_[0];
831
 
        my $task = $_[1];
832
 
        # Returns target information
833
 
        if ($task eq "target_name") {
834
 
                if ($tgtadm_output{$existing_target} =~ m/^Target (\d*): (.+)/ ) {
835
 
                        return $2;
836
 
                }
837
 
        # Returns driver information
838
 
        } elsif ($task eq "driver") {
839
 
                if ($tgtadm_output{$existing_target} =~ m/\s+Driver: (.+)/ ) {
840
 
                        return $1;
841
 
                }
842
 
        # Returns backing store
843
 
        } elsif ($task eq "backing_stores") {
844
 
                if ($tgtadm_output{$existing_target} =~ m/\s+Backing store path: (?!None)(.+)/ ) {
845
 
                        my @backing_stores = $tgtadm_output{$existing_target} =~ m{\s+Backing store path: (?!None\n)(.+)}g;
846
 
                        return @backing_stores;
847
 
                }
848
 
                return;
849
 
        # Returns account information:
850
 
        } elsif ($task eq "account_information") {
851
 
                if ($tgtadm_output{$existing_target} =~ m{
852
 
                        \s+Account\ information:\n(.*)\n\s+ACL\ information:
853
 
                             }xs
854
 
                      ) {
855
 
                        my @accounts = split(/\n/, $1);
856
 
                        my @account_information;
857
 
                        foreach my $user (@accounts) {
858
 
                                my @var = split(/^\s+/, $user);
859
 
                                push(@account_information, $var[1]);
860
 
                        }
861
 
                        return @account_information;
862
 
                }
863
 
        # Returns ACL information
864
 
        } elsif ($task eq "acl_information") {
865
 
                if ($tgtadm_output{$existing_target} =~ m{
866
 
                        \s+ACL\ information:\n(.*)
867
 
                                }xs
868
 
                        ) {
869
 
                        my @ini_addresses = split(/\n/, $1);
870
 
                        my @acls;
871
 
                        foreach my $ini_address (@ini_addresses) {
872
 
                                my @var = split(/^\s+/, $ini_address);
873
 
                                push(@acls, $var[1]);
874
 
                        }
875
 
                        return @acls;
876
 
                }
877
 
        # Returns sessions
878
 
        } elsif ($task eq "sessions") {
879
 
                my %sessions;
880
 
                if ($tgtadm_output{$existing_target} =~ m{
881
 
                        \s+I_T\ nexus\ information:\n(.*)LUN\ information:
882
 
                                }xs
883
 
                        ) {
884
 
                        my @var = split(/\n/, $1);
885
 
                        my $sid;
886
 
                        my $cid;
887
 
 
888
 
                        foreach my $line (@var) {
889
 
                        if ($line =~ m/\s+I_T nexus:\ (.+)/) {
890
 
                                        $sid = $1;
891
 
                                } else {
892
 
                                        if ($line =~ m/\s+Connection:\ (.+)/) {
893
 
                                                $cid = $1;
894
 
                                                $sessions{$sid} = $cid;
895
 
                                        }
896
 
                                }
897
 
                        }
898
 
                }
899
 
                return %sessions;
900
 
        }
901
 
}
902
 
 
903
 
# Main subroutine for deleting targets
904
 
sub main_delete {
905
 
        my $current_target = $_[0];
906
 
        my $current_tid = $_[1];
907
 
        my $configured = check_configured($current_target);
908
 
        my $del_upd_text;
909
 
        # Check if the target has initiators connected
910
 
        if ($tgtadm_output{$current_target} =~ m/\s+Connection:/) {
911
 
                if ($force == 1) {
912
 
                        execute("# Removing target: $current_target");
913
 
                        # Remove ACLs first
914
 
                        my @acl_info = show_target_info($current_target, "acl_information");
915
 
                        foreach my $acl (@acl_info) {
916
 
                                execute("tgtadm --op unbind --mode target --tid $tgtadm_output_tid{$current_target} -I $acl");
917
 
                        }
918
 
                        # Now, remove all sessions / connections from that tid
919
 
                        my %sessions = show_target_info($current_target, "sessions");
920
 
                        foreach my $sid (keys %sessions) {
921
 
                                foreach my $cid ($sessions{$sid}) {
922
 
                                        execute("tgtadm --op delete --mode conn --tid $tgtadm_output_tid{$current_target} --sid $sid --cid $cid");
923
 
                                }
924
 
                        }
925
 
                        execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$current_target}");
926
 
                } else {
927
 
                        if ($update ne 0) {
928
 
                                $del_upd_text = "updated";
929
 
                        } else {
930
 
                                $del_upd_text = "deleted";
931
 
                        }
932
 
                        execute("# Target with tid $tgtadm_output_tid{$current_target} ($current_target) is in use, it won't be $del_upd_text.");
933
 
                        return 1;
934
 
                }
935
 
        } elsif (length $tgtadm_output_tid{$current_target}) {
936
 
                execute("# Removing target: $current_target");
937
 
                execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$current_target}");
938
 
        } else {
939
 
                if (length $current_tid) {
940
 
                        execute("# Target with tid $current_tid does not exist!");
941
 
                } else {
942
 
                        execute("# Target with name $current_target does not exist!");
943
 
                }
944
 
        }
945
 
        if ($configured ne 0) {
946
 
                execute();
947
 
        }
948
 
        return 0;
949
 
}
950
 
 
951
 
# Delete the targets
952
 
sub delete_targets {
953
 
 
954
 
        if ($delete eq "help") {
955
 
                print <<EOF;
956
 
      --delete <value>          delete all or selected targets
957
 
                                The target will be deleted only if it's not used
958
 
                                (no initiator is connected to it).
959
 
                                If you want to delete targets which are in use,
960
 
                                you have to add "--force" flag.
961
 
 
962
 
Example usage:
963
 
      --delete help           - display this help
964
 
      --delete ALL            - delete all targets
965
 
      --delete tid=4          - delete target 4 (target with tid 4)
966
 
      --delete iqn.2008-08.com.example:some.target - delete this target
967
 
 
968
 
EOF
969
 
                exit;
970
 
        } elsif ($delete eq "ALL") {
971
 
                process_targets;
972
 
                # Run over all targets and delete them
973
 
                my @all_targets = keys %tgtadm_output_tid;
974
 
                foreach my $current_target (@all_targets) {
975
 
                        main_delete($current_target);
976
 
                }
977
 
        } elsif ($delete =~ m/^tid=(.+)/) {
978
 
                # Delete by tid
979
 
                process_targets;
980
 
                my $current_target = $tgtadm_output_name{$1};
981
 
                main_delete($current_target, $1);
982
 
        } else {
983
 
                # Delete by name
984
 
                process_targets;
985
 
                my $current_target = $delete;
986
 
                main_delete($current_target);
987
 
        }
988
 
}
989
 
 
990
 
# Update targets
991
 
sub update_targets {
992
 
        if ($update eq "help") {
993
 
                print <<EOF;
994
 
      --update <value>          update all or selected targets
995
 
                                The target will be updated only if it's not used
996
 
                                (no initiator is connected to it).
997
 
                                If you want to update targets which are in use,
998
 
                                you have to add "--force" flag.
999
 
 
1000
 
Example usage:
1001
 
      --update help           - display this help
1002
 
      --update ALL            - update all targets
1003
 
      --update tid=4          - update target 4 (target with tid 4)
1004
 
      --update iqn.2008-08.com.example:some.target - update this target
1005
 
 
1006
 
EOF
1007
 
                exit;
1008
 
        } elsif ($update eq "ALL") {
1009
 
                # Run over all targets and delete them if they are not in use
1010
 
                parse_configs;
1011
 
                process_targets;
1012
 
                my @targets_combined = combine_targets();
1013
 
                foreach my $current_target (@targets_combined) {
1014
 
                        my $configured = check_configured($current_target);
1015
 
                        my $connected = check_connected($current_target);
1016
 
                        my $in_configfile = check_in_configfile($current_target);
1017
 
                        combine_targets();
1018
 
                        if (($in_configfile == 0) && ($configured == 1)) {
1019
 
                                # Delete the target if it's not in the config file
1020
 
                                main_delete($current_target);
1021
 
                        } else {
1022
 
                                add_targets($current_target, $configured, $connected, $in_configfile);
1023
 
                        }
1024
 
 
1025
 
                }
1026
 
        } elsif ($update =~ m/^tid=(.+)/) {
1027
 
                # Update by tid
1028
 
                parse_configs;
1029
 
                process_targets;
1030
 
                my $current_target = $tgtadm_output_name{$1};
1031
 
                my $configured = check_configured($current_target);
1032
 
                my $connected = check_connected($current_target);
1033
 
                my $in_configfile = check_in_configfile($current_target);
1034
 
                if (($in_configfile == 0) && ($configured == 1)) {
1035
 
                        # Delete the target if it's not in the config file
1036
 
                        main_delete($current_target);
1037
 
                } elsif ($configured == 1) {
1038
 
                        add_targets($current_target, $configured, $connected, $in_configfile);
1039
 
                } else {
1040
 
                        print "There is no target with tid $1, can't continue!\n";
1041
 
                        exit 1;
1042
 
                }
1043
 
        } else {
1044
 
                # Update by name
1045
 
                parse_configs;
1046
 
                process_targets;
1047
 
                my $current_target = $update;
1048
 
                my $configured = check_configured($current_target);
1049
 
                my $connected = check_connected($current_target);
1050
 
                my $in_configfile = check_in_configfile($current_target);
1051
 
                if ($in_configfile == 0 && $configured == 1) {
1052
 
                        # Delete the target if it's not in the config file
1053
 
                        main_delete($current_target);
1054
 
                } else {
1055
 
                        add_targets($current_target, $configured, $connected, $in_configfile);
1056
 
                }
1057
 
        }
1058
 
}
1059
 
 
1060
 
# Find the biggest tid
1061
 
sub find_max_tid {
1062
 
        process_targets;
1063
 
        my @all_targets = keys %tgtadm_output_tid;
1064
 
        my $maxtid = 0;
1065
 
        foreach my $var (@all_targets) {
1066
 
                if ($tgtadm_output_tid{$var} > $maxtid) {
1067
 
                        $maxtid = $tgtadm_output_tid{$var};
1068
 
                }
1069
 
        }
1070
 
        return $maxtid;
1071
 
}
1072
 
 
1073
 
# Combine targets from the config file and currently configured targets
1074
 
sub combine_targets {
1075
 
        my @targets_in_configfile;
1076
 
        my @all_targets = keys %tgtadm_output_tid;
1077
 
        my @targets_combined;
1078
 
        # Make an array of targets in the config file
1079
 
        foreach my $k (sort keys %conf) {
1080
 
                if ( $k eq "target" ) {
1081
 
                        foreach my $k2 (sort keys %{$conf{$k}}) {
1082
 
                                push(@targets_in_configfile, $k2)
1083
 
                        }
1084
 
                }
1085
 
        }
1086
 
        # Use only unique elements from both arrays
1087
 
        foreach my $current_target (@all_targets) {
1088
 
                push (@targets_combined, $current_target) unless grep { $_ eq $current_target } @targets_in_configfile;
1089
 
        }
1090
 
        @targets_combined = (@targets_combined, @targets_in_configfile);
1091
 
        return @targets_combined;
1092
 
}
1093
 
 
1094
 
# Check if a value is correct
1095
 
sub check_value {
1096
 
        if ( not defined $_[0] or not length $_[0] ) {
1097
 
                print "\nOption $option has a missing value!\n";
1098
 
                print "Check your config file for errors (target: $target)\n";
1099
 
                exit 1;
1100
 
        }
1101
 
}
1102
 
 
1103
 
# Check if the target is in the config file
1104
 
sub check_in_configfile {
1105
 
        my $current_target = $_[0];
1106
 
        my $result;
1107
 
        foreach my $k (sort keys %conf) {
1108
 
                if ( $k eq "target" ) {
1109
 
                        foreach my $k2 (sort keys %{$conf{$k}}) {
1110
 
                                if ($k2 eq $current_target) {
1111
 
                                        return 1;
1112
 
                                }
1113
 
                        }
1114
 
                        # If we're here, we didn't find a match
1115
 
                        return 0;
1116
 
                }
1117
 
        }
1118
 
}
1119
 
 
1120
 
# Check if the target is configured in tgtd
1121
 
sub check_configured {
1122
 
        my $current_target = $_[0];
1123
 
        if (length $tgtadm_output_tid{$current_target}) {
1124
 
                return 1;
1125
 
        } else {
1126
 
                return 0;
1127
 
        }
1128
 
}
1129
 
 
1130
 
# Check if any initiators are connected to the target
1131
 
sub check_connected {
1132
 
        my $current_target = $_[0];
1133
 
        if ($tgtadm_output{$current_target} =~ m/\s+Connection:/) {
1134
 
                return 1;
1135
 
        } else {
1136
 
                return 0;
1137
 
        }
1138
 
}
1139
 
 
1140
 
# Check if a device can be allocated
1141
 
# Device can be used "by system" (i.e. mounted, used as swap, as a part of
1142
 
# a RAID array etc.) or "by user" - i.e., already by tgtd, or someone doing:
1143
 
#    dd if=/dev/1st_device of=/dev/2nd_device
1144
 
# We shouldn't allow a device to be used more than one time, as it could
1145
 
# cause corruption when written several times. Unless the user really wants to.
1146
 
sub check_device {
1147
 
        my $backing_store = $_[0];
1148
 
        my $data_key_ref = $_[1];
1149
 
 
1150
 
        # If allow-in-use is "yes", there is no need to do
1151
 
        # farther tests
1152
 
        if ($$data_key_ref{$backing_store}{'allow-in-use'} eq "yes") {
1153
 
                return 1;
1154
 
        }
1155
 
 
1156
 
        # Check if the system uses this device
1157
 
        use Fcntl qw(O_RDONLY O_EXCL);
1158
 
        use Errno;
1159
 
        sysopen(FH, $backing_store, O_RDONLY | O_EXCL);
1160
 
        if ($!{EBUSY}) {
1161
 
                execute("# Device $backing_store is used by the system (mounted, used by swap?).");
1162
 
                return 0;
1163
 
        }
1164
 
        close(FH);
1165
 
 
1166
 
        # Check if userspace uses this device
1167
 
        my $lsof_check = check_exe("lsof");
1168
 
        if ($lsof_check ne 1) {
1169
 
                system("lsof $backing_store &>/dev/null");
1170
 
                my $exit_value  = $? >> 8;
1171
 
                if ($exit_value eq 0) {
1172
 
                        execute("# Device $backing_store is used (already tgtd target?).");
1173
 
                        execute("# Run 'lsof $backing_store' to see the details.");
1174
 
                        return 0;
1175
 
                }
1176
 
        }
1177
 
        return 1;
1178
 
}
1179
 
 
1180
 
# Execute or just print (or both) everything we start or would start
1181
 
sub execute {
1182
 
        if ($pretend == 0) {
1183
 
 
1184
 
                my $args = "@_";
1185
 
                if ($verbose == 1) {
1186
 
                        print "$args\n";
1187
 
                }
1188
 
                # Don't try to execute if it's a comment
1189
 
                my @execargs = split(/#/, $args);
1190
 
                if ($execargs[0] ne undef) {
1191
 
                        system($args);
1192
 
 
1193
 
                        # If non-zero exit code was return, exit
1194
 
                        my $exit_value  = $? >> 8;
1195
 
                        if (($exit_value != 0) && ($ignore_errors == 0)) {
1196
 
                                print "Command:\n\t$args\nexited with code: $exit_value.\n";
1197
 
                                exit $exit_value;
1198
 
                        }
1199
 
                }
1200
 
 
1201
 
        } elsif ($pretend == 1) {
1202
 
                print "@_\n";
1203
 
        }
1204
 
}
1205
 
 
1206
 
if ($execute == 1) {
1207
 
        process_targets;
1208
 
        parse_configs;
1209
 
        add_targets;
1210
 
        remove_targets;
1211
 
} elsif ($delete ne 0) {
1212
 
        delete_targets;
1213
 
} elsif ($update ne 0) {
1214
 
        update_targets;
1215
 
} elsif ($dump == 1) {
1216
 
        dump_config;
1217
 
} elsif ($offline ne 0) {
1218
 
        ready_offline_targets("offline");
1219
 
} elsif ($ready ne 0) {
1220
 
        ready_offline_targets("ready");
1221
 
} else {
1222
 
        print "No action specified.\n";
1223
 
}
1224