cmd: remove sparc-only drd
[unleashed.git] / usr / src / cmd / device_remap / device_remap.pl
bloba3efb2cec0b48a51e4fd0dcb5a1acd22a97a309b
1 #!/usr/bin/perl
4 # CDDL HEADER START
6 # The contents of this file are subject to the terms of the
7 # Common Development and Distribution License (the "License").
8 # You may not use this file except in compliance with the License.
10 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 # or http://www.opensolaris.org/os/licensing.
12 # See the License for the specific language governing permissions
13 # and limitations under the License.
15 # When distributing Covered Code, include this CDDL HEADER in each
16 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 # If applicable, add the following below this CDDL HEADER, with the
18 # fields enclosed by brackets "[]" replaced with your own identifying
19 # information: Portions Copyright [yyyy] [name of copyright owner]
21 # CDDL HEADER END
25 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
26 # Use is subject to license terms.
29 use Getopt::Std;
30 use Cwd;
32 use strict;
34 package MDesc;
36 use constant {
37 MDEND => 0x45,
38 MDNODE => 0x4e,
39 MDARC => 0x61,
40 MDDATA => 0x64,
41 MDSTR => 0x73,
42 MDVAL => 0x76,
46 sub new {
47 my $class = shift;
48 my $self = {};
49 $self->{FILE} = undef;
50 $self->{MAJOR} = undef;
51 $self->{MINOR} = undef;
52 $self->{NODE_SEC_SZ} = undef;
53 $self->{NAME_SEC_SZ} = undef;
54 $self->{DATA_SEC_SZ} = undef;
55 $self->{NODES} = undef;
56 $self->{NAMES} = undef;
57 $self->{DATA} = undef;
58 bless($self, $class);
59 return $self;
62 sub open {
63 my $self = shift;
64 my ($mdhdr, $size);
66 if (@_) {
67 $self->{NAME} = shift;
68 } else {
69 $self->{NAME} = '/dev/mdesc';
71 return unless open(MD, "$self->{NAME}");
73 # Read and parse MD header
74 unless (read(MD, $mdhdr, 16) == 16) {
75 close (MD);
76 return;
79 ($self->{MAJOR}, $self->{MINOR},
80 $self->{NODE_SEC_SZ},
81 $self->{NAME_SEC_SZ},
82 $self->{DATA_SEC_SZ}) = unpack("nnNNN", $mdhdr);
84 $size = read(MD, $self->{NODES}, $self->{NODE_SEC_SZ});
85 $size = read(MD, $self->{NAMES}, $self->{NAME_SEC_SZ});
86 $size = read(MD, $self->{DATA}, $self->{DATA_SEC_SZ});
92 # return hash of given node's information
94 sub getnode {
95 my ($self, $nodeid) = @_;
96 my ($tag, $name, $namelen, $nameoff, $datalen, $dataoff, %node);
98 ($tag, $namelen, $nameoff, $datalen, $dataoff) =
99 unpack("CCx2NNN", substr($self->{NODES}, $nodeid * 16, 16));
100 $name = substr($self->{NAMES}, $nameoff, $namelen);
101 %node = (tag => $tag, name => $name, nameid => $nameoff);
103 if ($tag == MDSTR || $tag == MDDATA) {
104 $node{'datalen'} = $datalen;
105 $node{'dataoff'} = $dataoff;
106 } elsif ($tag == MDVAL) {
107 $node{'val'} = ($datalen << 32) | $dataoff;
108 } elsif ($tag == MDARC || $tag == MDNODE) {
109 $node{'idx'} = ($datalen << 32) | $dataoff;
112 return %node;
117 # return hash of given property's information
119 sub getprop {
120 my ($self, $propid) = @_;
121 my (%node, $tag, %prop);
123 %node = $self->getnode($propid);
124 $tag = $node{'tag'};
125 %prop = (name => $node{'name'}, tag => $tag);
127 if ($tag == MDSTR) {
128 $prop{'string'} =
129 substr($self->{DATA}, $node{'dataoff'}, $node{'datalen'} - 1);
130 } elsif ($tag == MDARC) {
131 $prop{'arc'} = $node{'idx'};
132 } elsif ($tag == MDVAL) {
133 $prop{'val'} = $node{'val'};
134 } elsif ($tag == MDDATA) {
135 $prop{'length'} = $node{'datalen'};
136 $prop{'offset'} = $node{'dataoff'};
137 } else {
138 return undef;
141 return %prop;
146 # find name table index of given name
148 sub findname {
149 my ($self, $name) = @_;
150 my ($idx, $next, $p);
152 for ($idx = 0; $idx < $self->{NAME_SEC_SZ}; $idx = $next + 1) {
153 $next = index($self->{NAMES}, "\0", $idx);
154 $p = substr($self->{NAMES}, $idx, $next - $idx);
155 return $idx if ($p eq $name);
158 return -1;
163 # find given property in node
165 sub findprop {
166 my ($self, $nodeid, $propname, $type) = @_;
167 my (%node, $nameid);
169 %node = $self->getnode($nodeid);
170 return -1 if ($node{'tag'} != MDNODE);
172 $nameid = $self->findname($propname);
173 return -1 if ($nameid == -1);
175 do {
176 $nodeid++;
177 %node = $self->getnode($nodeid);
178 if ($node{'tag'} == $type && $node{'nameid'} == $nameid) {
179 return $nodeid;
181 } while ($node{'tag'} != MDEND);
183 return -1;
188 # lookup property in node and return its hash
190 sub lookup {
191 my ($self, $nodeid, $propname, $type) = @_;
192 my ($propid);
194 $propid = $self->findprop($nodeid, $propname, $type);
195 return undef if ($propid == -1);
197 return $self->getprop($propid);
201 sub scan_node {
202 my ($self, $nodeid, $nameid, $arcid, $ret, $seen) = @_;
203 my (%node);
205 return if ($seen->[$nodeid] == 1);
206 $seen->[$nodeid] = 1;
208 %node = $self->getnode($nodeid);
209 return if ($node{'tag'} != MDNODE);
210 push(@$ret, $nodeid) if ($node{'nameid'} == $nameid);
212 do {
213 $nodeid++;
214 %node = $self->getnode($nodeid);
215 if ($node{'tag'} == MDARC && $node{'nameid'} == $arcid) {
216 $self->scan_node($node{'idx'}, $nameid, $arcid, $ret, $seen);
218 } while ($node{'tag'} != MDEND);
223 # scan dag from 'start' via 'arcname'
224 # return list of nodes named 'nodename'
226 sub scan {
227 my ($self, $start, $nodename, $arcname) = @_;
228 my ($nameid, $arcid, @ret, @seen);
230 $nameid = $self->findname($nodename);
231 $arcid = $self->findname($arcname);
232 $self->scan_node($start, $nameid, $arcid, \@ret, \@seen);
233 return @ret;
238 package main;
242 # 'find' needs to use globals anyway,
243 # so we might as well use the same ones
244 # everywhere
246 our ($old, $new);
247 our %opts;
251 # fix path_to_inst
253 sub fixinst {
254 use File::Copy;
255 my ($oldpat, $newpat);
256 my ($in, $out);
258 $oldpat = '"' . $old . '/';
259 $newpat = '"' . $new . '/';
261 $in = "etc/path_to_inst";
262 $out = "/tmp/path$$";
264 open(IN, "<", $in) or die "can't open $in\n";
265 open(OUT, ">", $out) or die "can't open $out\n";
267 my ($found, $path);
269 # first pass
270 # see if there are any old paths that need to be re-written
272 $found = 0;
273 while (<IN>) {
274 ($path, undef, undef) = split;
275 if ($path =~ /^$oldpat/) {
276 $found = 1;
277 last;
280 # return if no old paths found
281 if ($found == 0) {
282 close(IN);
283 close(OUT);
284 unlink $out;
285 return 0;
288 print "replacing $old with $new in /etc/path_to_inst\n";
290 # 2nd pass
291 # substitute new for old
293 seek(IN, 0, 0);
294 while (<IN>) {
295 ($path, undef, undef) = split;
296 if ($path =~ /^$oldpat/) {
297 s/$oldpat/$newpat/;
299 print OUT;
301 close(IN);
302 close(OUT);
304 if ($opts{v}) {
305 print "path_to_inst changes:\n";
306 system("/usr/bin/diff", $in, $out);
307 print "\n";
310 move $out, $in or die "can't modify $in\n";
312 return 1;
316 our $oldpat;
318 sub wanted {
319 my $targ;
321 -l or return;
322 $targ = readlink;
323 if ($targ =~ /$oldpat/) {
324 $targ =~ s/$old/$new/;
325 unlink;
326 symlink $targ, $_;
327 print "symlink $_ changed to $targ\n" if ($opts{v});
332 # fix symlinks
334 sub fixdev {
335 use File::Find;
336 $oldpat = "/devices" . $old;
338 print "updating /dev symlinks\n";
339 find \&wanted, "dev";
344 # fixup path_to_inst and /dev symlinks
346 sub fixup {
347 # setup globals
348 ($old, $new) = @_;
350 # if fixinst finds no matches, no need to run fixdev
351 return if (fixinst == 0);
352 fixdev;
353 print "\n" if ($opts{v});
357 # remove caches
359 sub rmcache {
360 unlink "etc/devices/devid_cache";
361 unlink "etc/devices/devname_cache";
362 unlink <etc/devices/mdi_*_cache>;
363 unlink "etc/devices/retire_store";
364 unlink "etc/devices/snapshot_cache";
365 unlink "dev/.devlink_db";
369 # $< == 0 or die "$0: must be run as root\n";
371 getopts("vR:", \%opts);
373 if ($opts{R}) {
374 chdir $opts{R} or die "can't chdir to $opts{R}\n";
376 cwd() ne "/" or die "can't run on root directory\n";
378 if ($#ARGV == 1) {
380 # manual run (no MD needed)
382 fixup @ARGV;
383 rmcache;
384 exit;
388 my ($md, @nodes, $nodeid, @aliases, $alias);
389 my (%newpath, %roots);
392 # scan MD for ioaliases
394 $md = MDesc->new;
395 $md->open;
397 @nodes = $md->scan(0, "ioaliases", "fwd");
398 $#nodes == 0 or die "missing ioaliases node\n";
401 # foreach ioalias node, replace any 'alias' paths
402 # with the 'current' one
404 # complicating this is that the alias paths can be
405 # substrings of each other, which can cause false
406 # hits in /etc/path_to_inst, so first gather all
407 # aliases with the same root into a list, then sort
408 # it by length so we always fix the longer alias
409 # paths before the shorter ones
411 @nodes = $md->scan(@nodes[0], "ioalias", "fwd");
412 foreach $nodeid (@nodes) {
413 my (%prop, $current);
415 %prop = $md->lookup($nodeid, "aliases", $md->MDSTR);
416 @aliases = split(/ /, $prop{'string'});
418 %prop = $md->lookup($nodeid, "current", $md->MDSTR);
419 $current = $prop{'string'};
421 foreach $alias (@aliases) {
422 next if ($alias eq $current);
424 my ($slash, $root);
425 $newpath{$alias} = $current;
426 $slash = index($alias, '/', 1);
427 if ($slash == -1) {
428 $root = $alias;
429 } else {
430 $root = substr($alias, 0, $slash);
432 push(@{ $roots{$root} }, $alias);
436 my $aref;
437 foreach $aref (values %roots) {
438 @aliases = sort { length($b) <=> length($a) } @$aref;
439 foreach $alias (@aliases) {
440 fixup $alias, $newpath{$alias};
444 rmcache;