mdoc: Add a msgport(9) manual page documenting LWKT message passing interface.
[dragonfly.git] / tools / tools / kdrv / KernelDriver
CommitLineData
984263bc
MD
1#!/bin/sh
2# Tcl magic -*- tcl -*- \
3exec tclsh $0 $*
4################################################################################
5#
6# KernelDriver - FreeBSD driver source installer
7#
8################################################################################
9#
10# Copyright (C) 1997
11# Michael Smith. All rights reserved.
12#
13# Redistribution and use in source and binary forms, with or without
14# modification, are permitted provided that the following conditions
15# are met:
16# 1. Redistributions of source code must retain the above copyright
17# notice, this list of conditions and the following disclaimer.
18# 2. Redistributions in binary form must reproduce the above copyright
19# notice, this list of conditions and the following disclaimer in the
20# documentation and/or other materials provided with the distribution.
21# 3. Neither the name of the author nor the names of any co-contributors
22# may be used to endorse or promote products derived from this software
23# without specific prior written permission.
24#
25# THIS SOFTWARE IS PROVIDED BY Michael Smith AND CONTRIBUTORS ``AS IS'' AND
26# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28# ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith OR CONTRIBUTORS BE LIABLE
29# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35# SUCH DAMAGE.
36#
37################################################################################
38#
39# KernelDriver provides a means for installing source-form drivers into FreeBSD
40# kernel source trees in an automated fashion. It can also remove drivers it
41# has installed.
42#
43# Driver information is read from a control file, with the following syntax :
44#
45# description {<text>} Driver description; used in comments inserted into
46# files.
47# driver <name> The name of the driver. (Note that this can't end in .drvinfo :)
48# filei386 <path> <name> The file <name> in the driver package is installed into
49# <path> in the kernel source tree. Files whose names
50# end in '.c' have an entry added to i386/conf/files.i386.
51# fileconf <path> <name> The file <name> in the driver package is installed into
52# <path> in the kernel source tree. Files whose names
53# end in '.c' have an entry added to conf/files.
54# optioni386 <name> <hdr> Adds an entry to i386/conf/options.i386, such that
55# the option <name> will be placed in the header <hdr>.
56# optionconf <name> <hdr> Adds an entry to conf/options, such that
57# the option <name> will be placed in the header <hdr>.
58# linttext Lines between this and a subsequent 'end' line are added
59# to the LINT file to provide configuration examples,
60# comments, etc.
61# end Ends a text region.
62#
63# Possible additions :
64#
65# patch <name> Applies the patch contained in <name>; patch is invoked
66# at the top level of the kernel source tree, and the
67# patch must apply cleanly (this is checked).
68#
69# option <name> <file> Adds an entry to i386/conf/options.i386
70#
71# Lines beginning with '#' or blanks are considered comments, except in
72# 'linttext' regions.
73#
74################################################################################
75#
76# $FreeBSD: src/tools/tools/kdrv/KernelDriver,v 1.4.2.1 2001/03/05 12:17:23 kris Exp $
1de703da 77# $DragonFly: src/tools/tools/kdrv/KernelDriver,v 1.2 2003/06/17 04:29:11 dillon Exp $
984263bc
MD
78#
79################################################################################
80
81################################################################################
82# findDrvFile
83#
84# Given (hint), use it to locate a driver information file.
85# (Possible extension; support drivers in gzipped tarballs...)
86#
87proc findDrvFile_try {hint} {
88
89 # points to something already
90 if {[file exists $hint]} {
91 # unwind symbolic links
92 while {[file type $hint] == "link"} {
93 set hint [file readlink $hint];
94 }
95 switch [file type $hint] {
96 file {
97 # run with it as it is
98 return $hint;
99 }
100 directory {
101 # look for a drvinfo file in the directory
102 set candidate [glob -nocomplain "$hint/*.drvinfo"];
103 switch [llength $candidate] {
104 0 {
105 # nothing there
106 }
107 1 {
108 return $candidate;
109 }
110 default {
111 error "multiple driver info files in directory : $hint";
112 }
113 }
114 }
115 default {
116 error "driver info file may be a typewriter : $hint";
117 }
118 }
119 }
120 # maybe we need an extension
121 if {[file exists $hint.drvinfo]} {
122 return $hint.drvinfo;
123 }
124 error "can't find a driver info file using '$hint'";
125}
126
127proc findDrvFile {hint} {
128
129 set result [findDrvFile_try $hint];
130 if {$result != ""} {
131 return $result;
132 }
133 set result [findDrvFile_try ${hint}.drvinfo];
134 if {$result != ""} {
135 return $result;
136 }
137 error "can't find driver information file using : $hint";
138}
139
140################################################################################
141# readDrvFile
142#
143# Reads the contents of (fname), which are expected to be in the format
144# described above, and fill in the global Drv array.
145#
146proc readDrvFile {fname} {
147
148 global Drv Options;
149
150 if {$Options(verbose)} {puts "+ read options from '$fname'";}
151 set fh [open $fname r];
152
153 # set defaults
154 set Drv(description) "";
155 set Drv(driver) "";
156 set Drv(filesi386) "";
157 set Drv(filesconf) "";
158 set Drv(optionsi386) "";
159 set Drv(optionsconf) "";
160 set Drv(patches) "";
161 set Drv(linttext) "";
162
163 while {[gets $fh line] >= 0} {
164
165 # blank lines/comments
166 if {([llength $line] == 0) ||
167 ([string index $line 0] == "\#")} {
168 continue ;
169 }
170
171 # get keyword, process
172 switch -- [lindex $line 0] {
173 description {
174 set Drv(description) [lindex $line 1];
175 }
176 driver {
177 set Drv(driver) [lindex $line 1];
178 }
179 filei386 {
180 set path [lindex $line 1];
181 set plast [expr [string length $path] -1];
182 if {[string index $path $plast] != "/"} {
183 append path "/";
184 }
185 set name [lindex $line 2];
186 set Drv(filei386:$name) $path;
187 lappend Drv(filesi386) $name;
188 }
189 fileconf {
190 set path [lindex $line 1];
191 set plast [expr [string length $path] -1];
192 if {[string index $path $plast] != "/"} {
193 append path "/";
194 }
195 set name [lindex $line 2];
196 set Drv(fileconf:$name) $path;
197 lappend Drv(filesconf) $name;
198 }
199 optioni386 {
200 set opt [lindex $line 1];
201 set hdr [lindex $line 2];
202 lappend Drv(optionsi386) $opt;
203 set Drv(optioni386:$opt) $hdr;
204 }
205 optionconf {
206 set opt [lindex $line 1];
207 set hdr [lindex $line 2];
208 lappend Drv(optionsconf) $opt;
209 set Drv(optionconf:$opt) $hdr;
210 }
211 patch {
212 lappend Drv(patches) [lindex $line 1];
213 }
214 linttext {
215 while {[gets $fh line] >= 0} {
216 if {$line == "end"} {
217 break ;
218 }
219 lappend Drv(linttext) $line;
220 }
221 }
222 }
223 }
224 close $fh;
225 if {$Options(verbose)} {
226 printDrv;
227 }
228}
229
230################################################################################
231# validateDrvPackage
232#
233# With the global Drv filled in, check that the files required are all in
234# (dir), and that the kernel config at (kpath) can be written.
235#
236proc validateDrvPackage {dir kpath} {
237
238 global Drv Options;
239
240 if {$Options(verbose)} {puts "+ checking driver package...";}
241 set missing "";
242 set unwritable "";
243
244 # check files, patches
245 foreach f $Drv(filesi386) {
246 if {![file readable $dir$f]} {
247 lappend missing $f;
248 }
249 }
250 foreach f $Drv(filesconf) {
251 if {![file readable $dir$f]} {
252 lappend missing $f;
253 }
254 }
255 foreach f $Drv(patches) {
256 if {![file readable $dir$f]} {
257 lappend missing $f;
258 }
259 }
260 if {$missing != ""} {
261 error "missing files : $missing";
262 }
263
264 # check writability
265 if {$Options(verbose)} {puts "+ checking kernel source writability...";}
266 foreach f $Drv(filesi386) {
267 set p $Drv(filei386:$f);
268 if {![file isdirectory $kpath$p]} {
269 lappend missing $p;
270 } else {
271 if {![file writable $kpath$p]} {
272 if {[lsearch -exact $unwritable $p] == -1} {
273 lappend unwritable $p;
274 }
275 }
276 }
277 }
278 foreach f $Drv(filesconf) {
279 set p $Drv(fileconf:$f);
280 if {![file isdirectory $kpath$p]} {
281 lappend missing $p;
282 } else {
283 if {![file writable $kpath$p]} {
284 if {[lsearch -exact $unwritable $p] == -1} {
285 lappend unwritable $p;
286 }
287 }
288 }
289 }
290 foreach f [list \
291 "conf/files" \
292 "i386/conf/files.i386" \
293 "i386/conf/options.i386" \
294 "i386/conf/LINT"] {
295 if {![file writable $kpath$f]} {
296 lappend unwritable $f;
297 }
298 }
299 if {$missing != ""} {
300 error "missing directories : $missing";
301 }
302 if {$unwritable != ""} {
303 error "can't write to : $unwritable";
304 }
305}
306
307################################################################################
308# installDrvFiles
309#
310# Install the files listed in the global Drv into (kpath) from (dir)
311#
312proc installDrvFiles {dir kpath} {
313
314 global Drv Options;
315
316 # clear 'installed' record
317 set Drv(installedi386) "";
318 set Drv(installedconf) "";
319 set failed "";
320
321 if {$Options(verbose)} {puts "+ installing driver files...";}
322 foreach f $Drv(filesi386) {
323 if {$Options(verbose)} {puts "$f -> $kpath$Drv(filei386:$f)";}
324 if {$Options(real)} {
325 if {[catch {exec cp $dir$f $kpath$Drv(filei386:$f)} msg]} {
326 lappend failed $f;
327 } else {
328 lappend Drv(installedi386) $f;
329 }
330 }
331 }
332 foreach f $Drv(filesconf) {
333 if {$Options(verbose)} {puts "$f -> $kpath$Drv(fileconf:$f)";}
334 if {$Options(real)} {
335 if {[catch {exec cp $dir$f $kpath$Drv(fileconf:$f)} msg]} {
336 lappend failed $f;
337 } else {
338 lappend Drv(installedconf) $f;
339 }
340 }
341 }
342 if {$failed != ""} {
343 error "failed to install files : $failed";
344 }
345}
346
347################################################################################
348# backoutDrvChanges
349#
350# Remove files from a failed installation in (kpath)
351#
352proc backoutDrvChanges {kpath} {
353
354 global Drv Options;
355
356 if {$Options(verbose)} {puts "+ backing out installed files...";}
357 # delete installed files
358 foreach f $Drv(installedi386) {
359 exec rm -f $kpath$Drv(filei386:$f)$f;
360 }
361 foreach f $Drv(installedconf) {
362 exec rm -f $kpath$Drv(fileconf:$f)$f;
363 }
364}
365
366################################################################################
367# registerDrvFiles
368#
369# Adds an entry to i386/conf/files.i386 and conf/files for the .c files in the driver.
370# (kpath) points to the kernel.
371#
372# A comment is added to the file preceding the new entries :
373#
374# ## driver: <drivername>
375# # <description>
376# # filei386: <path><file>
377# <file spec (.c files only)>
378# ## enddriver
379#
380# We only append to the end of the file.
381#
382# Add linttext to the LINT file.
383# Add options to i386/conf/options.i386 if any are specified
384#
385proc registerDrvFiles {kpath} {
386
387 global Drv Options;
388
389 if {$Options(verbose)} {puts "+ registering installed files...";}
390
391# Add stuff to LINT
392 if {$Drv(linttext) != ""} {
393
394 if {$Options(verbose)} {puts "+ updating LINT...";}
395 if {$Options(real)} {
396 set fname [format "%si386/conf/LINT" $kpath];
397 set fh [open $fname a];
398
399 # header
400 puts $fh "\#\# driver: $Drv(driver)";
401 puts $fh "\# $Drv(description)";
402 foreach l $Drv(linttext) {
403 puts $fh $l;
404 }
405 puts $fh "\#\# enddriver";
406 close $fh;
407 }
408 }
409
410# Do filesi386 stuff
411 if {$Options(real)} {
412 set fname [format "%si386/conf/files.i386" $kpath];
413 set fh [open $fname a];
414
415 # header
416 puts $fh "\#\# driver: $Drv(driver)";
417 puts $fh "\# $Drv(description)";
418 # file information
419 foreach f $Drv(filesi386) {
420 puts $fh "\# file: $Drv(filei386:$f)$f";
421 # is it a compilable object?
422 if {[string match "*.c" $f]} {
423 puts $fh "$Drv(filei386:$f)$f\t\toptional\t$Drv(driver)\tdevice-driver";
424 }
425 }
426 puts $fh "\#\# enddriver";
427 close $fh;
428 }
429 if {$Drv(optionsi386) != ""} {
430 if {$Options(verbose)} {puts "+ adding options...";}
431 if {$Options(real)} {
432 set fname [format "%si386/conf/options.i386" $kpath];
433 set fh [open $fname a];
434
435 # header
436 puts $fh "\#\# driver: $Drv(driver)";
437 puts $fh "\# $Drv(description)";
438 # options
439 foreach opt $Drv(optionsi386) {
440 puts $fh "$opt\t$Drv(optioni386:$opt)";
441 }
442 puts $fh "\#\# enddriver";
443 close $fh;
444 }
445 }
446
447# Do filesconf stuff
448 if {$Options(real)} {
449 set fname [format "%sconf/files" $kpath];
450 set fh [open $fname a];
451
452 # header
453 puts $fh "\#\# driver: $Drv(driver)";
454 puts $fh "\# $Drv(description)";
455 # file information
456 foreach f $Drv(filesconf) {
457 puts $fh "\# file: $Drv(fileconf:$f)$f";
458 # is it a compilable object?
459 if {[string match "*.c" $f]} {
460 puts $fh "$Drv(fileconf:$f)$f\t\toptional\t$Drv(driver)\tdevice-driver";
461 }
462 }
463 puts $fh "\#\# enddriver";
464 close $fh;
465 }
466 if {$Drv(optionsconf) != ""} {
467 if {$Options(verbose)} {puts "+ adding options...";}
468 if {$Options(real)} {
469 set fname [format "%sconf/options" $kpath];
470 set fh [open $fname a];
471
472 # header
473 puts $fh "\#\# driver: $Drv(driver)";
474 puts $fh "\# $Drv(description)";
475 # options
476 foreach opt $Drv(optionsconf) {
477 puts $fh "$opt\t$Drv(optionconf:$opt)";
478 }
479 puts $fh "\#\# enddriver";
480 close $fh;
481 }
482 }
483
484}
485
486################################################################################
487# listInstalledDrv
488#
489# List all drivers recorded as installed, in the kernel at (kpath)
490#
491# XXX : fix me so I understand conf/{options,files} stuff!
492proc listInstalledDrv {kpath} {
493
494 global Drv;
495
496 # pick up all the i386 options information first
497 set fname [format "%si386/conf/options.i386" $kpath];
498 if {![file readable $fname]} {
499 error "not a kernel directory";
500 }
501 set fh [open $fname r];
502
503 while {[gets $fh line] >= 0} {
504
505 # got a driver?
506 if {[scan $line "\#\# driver: %s" driver] == 1} {
507 # read driver details, ignore
508 gets $fh line;
509 # loop reading option details
510 while {[gets $fh line] >= 0} {
511 # end of driver info
512 if {$line == "\#\# enddriver"} {
513 break ;
514 }
515 # parse option/header tuple
516 if {[scan $line "%s %s" opt hdr] == 2} {
517 # remember that this driver uses this option
518 lappend drivers($driver:optionsi386) $opt;
519 # remember that this option goes in this header
520 set optionsi386($opt) $hdr;
521 }
522 }
523 }
524 }
525 close $fh;
526
527 # pick up all the conf options information first
528 set fname [format "%sconf/options" $kpath];
529 if {![file readable $fname]} {
530 error "not a kernel directory";
531 }
532 set fh [open $fname r];
533
534 while {[gets $fh line] >= 0} {
535
536 # got a driver?
537 if {[scan $line "\#\# driver: %s" driver] == 1} {
538 # read driver details, ignore
539 gets $fh line;
540 # loop reading option details
541 while {[gets $fh line] >= 0} {
542 # end of driver info
543 if {$line == "\#\# enddriver"} {
544 break ;
545 }
546 # parse option/header tuple
547 if {[scan $line "%s %s" opt hdr] == 2} {
548 # remember that this driver uses this option
549 lappend drivers($driver:optionsconf) $opt;
550 # remember that this option goes in this header
551 set optionsconf($opt) $hdr;
552 }
553 }
554 }
555 }
556 close $fh;
557
558 set fname [format "%si386/conf/files.i386" $kpath];
559 set fh [open $fname r];
560
561 while {[gets $fh line] >= 0} {
562
563 # got a driver?
564 if {[scan $line "\#\# driver: %s" driver] == 1} {
565 # clear global and reset
566 catch {unset Drv};
567 set Drv(driver) $driver;
568 # read driver details
569 gets $fh line;
570 set Drv(description) [string range $line 2 end];
571 set Drv(filesi386) "";
572 # options?
573 if {[info exists drivers($Drv(driver):optionsi386)]} {
574 set Drv(optionsi386) $drivers($Drv(driver):optionsi386);
575 # get pathnames
576 foreach opt $Drv(optionsi386) {
577 set Drv(optioni386:$opt) $optionsi386($opt);
578 }
579 }
580 # loop reading file details
581 while {[gets $fh line] >= 0} {
582 if {$line == "\#\# enddriver"} {
583 # print this driver and loop
584 printDrv;
585 break ;
586 }
587 if {[scan $line "\# filei386: %s" fpath] == 1} {
588 set f [file tail $fpath];
589 set Drv(filei386:$f) "[file dirname $fpath]/";
590 lappend Drv(filesi386) $f;
591 }
592 }
593 }
594 }
595 close $fh;
596
597 set fname [format "%sconf/files" $kpath];
598 set fh [open $fname r];
599
600 while {[gets $fh line] >= 0} {
601
602 # got a driver?
603 if {[scan $line "\#\# driver: %s" driver] == 1} {
604 # clear global and reset
605 catch {unset Drv};
606 set Drv(driver) $driver;
607 # read driver details
608 gets $fh line;
609 set Drv(description) [string range $line 2 end];
610 set Drv(filesconf) "";
611 # options?
612 if {[info exists drivers($Drv(driver):optionsconf)]} {
613 set Drv(optionsconf) $drivers($Drv(driver):optionsconf);
614 # get pathnames
615 foreach opt $Drv(optionsconf) {
616 set Drv(optionconf:$opt) $optionsconf($opt);
617 }
618 }
619 # loop reading file details
620 while {[gets $fh line] >= 0} {
621 if {$line == "\#\# enddriver"} {
622 # print this driver and loop
623 printDrv;
624 break ;
625 }
626 if {[scan $line "\# fileconf: %s" fpath] == 1} {
627 set f [file tail $fpath];
628 set Drv(fileconf:$f) "[file dirname $fpath]/";
629 lappend Drv(filesconf) $f;
630 }
631 }
632 }
633 }
634 close $fh;
635}
636
637################################################################################
638# printDrv
639#
640# Print the contents of the global Drv.
641#
642proc printDrv {} {
643
644 global Drv Options;
645
646 puts "$Drv(driver) : $Drv(description)";
647 if {$Options(verbose)} {
648 foreach f $Drv(filesi386) {
649 puts " $Drv(filei386:$f)$f"
650 }
651 foreach f $Drv(filesconf) {
652 puts " $Drv(fileconf:$f)$f"
653 }
654 if {[info exists Drv(optionsi386)]} {
655 foreach opt $Drv(optionsi386) {
656 puts " $opt in $Drv(optioni386:$opt)";
657 }
658 }
659 if {[info exists Drv(optionsconf)]} {
660 foreach opt $Drv(optionsconf) {
661 puts " $opt in $Drv(optionconf:$opt)";
662 }
663 }
664 }
665}
666
667################################################################################
668# findInstalledDrv
669#
670# Given a kernel tree at (kpath), get driver details about an installed
671# driver (drvname)
672#
673
674proc findInstalledDrvi386 {drvname kpath} {
675
676 global Drv;
677
678 set fname [format "%si386/conf/files.i386" $kpath];
679 set fh [open $fname r];
680
681 puts "checking i386/conf/files.i386";
682
683 while {[gets $fh line] >= 0} {
684 if {[scan $line "\#\# driver: %s" name] == 1} {
685 if {$name != $drvname} {
686 continue ; # not us
687 }
688 # read information
689 set Drv(driver) $drvname;
690 set line [gets $fh];
691 set Drv(description) [string range $line 2 end];
692 set Drv(filesi386) "";
693 # loop reading file details
694 while {[gets $fh line] >= 0} {
695 if {$line == "\#\# enddriver"} {
696 close $fh;
697 return 1; # all done
698 }
699 if {[scan $line "\# file: %s" fpath] == 1} {
700 set f [file tail $fpath];
701 set Drv(filei386:$f) "[file dirname $fpath]/";
702 lappend Drv(filesi386) $f;
703 }
704 }
705 close $fh;
706 error "unexpected EOF reading '$fname'";
707 }
708 }
709 close $fh
710
711 return 0;
712}
713
714proc findInstalledDrvconf {drvname kpath} {
715
716 global Drv;
717
718 set fname [format "%sconf/files" $kpath];
719 set fh [open $fname r];
720
721 puts "checking conf/files";
722
723 while {[gets $fh line] >= 0} {
724 if {[scan $line "\#\# driver: %s" name] == 1} {
725 if {$name != $drvname} {
726 continue ; # not us
727 }
728 # read information
729 set Drv(driver) $drvname;
730 set line [gets $fh];
731 set Drv(description) [string range $line 2 end];
732 set Drv(filesconf) "";
733 # loop reading file details
734 while {[gets $fh line] >= 0} {
735 if {$line == "\#\# enddriver"} {
736 close $fh;
737 return 1; # all done
738 }
739 if {[scan $line "\# file: %s" fpath] == 1} {
740 set f [file tail $fpath];
741 set Drv(fileconf:$f) "[file dirname $fpath]/";
742 lappend Drv(filesconf) $f;
743 }
744 }
745 close $fh;
746 error "unexpected EOF reading '$fname'";
747 }
748 }
749 close $fh
750
751 return 0;
752}
753
754proc findInstalledDrv {drvname kpath} {
755
756 global Drv Options;
757
758 if {$Options(verbose)} {puts "+ look for driver '$drvname' in '$kpath'";}
759
760# Whoops... won't work in a single if statement due to expression shortcircuiting
761 set a [findInstalledDrvi386 $drvname $kpath];
762 set b [findInstalledDrvconf $drvname $kpath];
763 if {$a || $b} {
764 return;
765 }
766
767 error "driver '$drvname' not recorded as installed";
768}
769
770################################################################################
771# validateDrvRemoval
772#
773# Verify that we can remove the driver described in the global Drv installed
774# at (kpath).
775#
776proc validateDrvRemoval {kpath} {
777
778 global Drv Options;
779
780 set missing "";
781 set unwritable "";
782
783 if {$Options(verbose)} {puts "+ checking for removabilty...";}
784
785 # admin files?
786 foreach f [list \
787 "i386/conf/files.i386" \
788 "i386/conf/options.i386" \
789 "i386/conf/LINT" \
790 "conf/files" \
791 "conf/options" ] {
792 if {![file exists $kpath$f]} {
793 lappend missing $kpath$f;
794 } else {
795 if {![file writable $kpath$f]} {
796 lappend unwritable $f;
797 }
798 }
799 }
800 # driver components?
801 foreach f $Drv(filesi386) {
802 set p $Drv(filei386:$f);
803 if {![file isdirectory $kpath$p]} {
804 lappend missing $p;
805 } else {
806 if {![file writable $kpath$p]} {
807 if {[lsearch -exact $unwritable $p] == -1} {
808 lappend unwritable $p;
809 }
810 }
811 }
812 }
813 foreach f $Drv(filesconf) {
814 set p $Drv(fileconf:$f);
815 if {![file isdirectory $kpath$p]} {
816 lappend missing $p;
817 } else {
818 if {![file writable $kpath$p]} {
819 if {[lsearch -exact $unwritable $p] == -1} {
820 lappend unwritable $p;
821 }
822 }
823 }
824 }
825 if {$missing != ""} {
826 error "files/directories missing : $missing";
827 }
828 if {$unwritable != ""} {
829 error "can't write to : $unwritable";
830 }
831}
832
833################################################################################
834# deleteDrvFiles
835#
836# Delete the files belonging to the driver devfined in the global Drv in
837# the kernel tree at (kpath)
838#
839proc deleteDrvFiles {kpath} {
840
841 global Drv Options;
842
843 if {$Options(verbose)} {puts "+ delete driver files...";}
844
845 # loop deleting files
846 foreach f $Drv(filesi386) {
847 if {$Options(verbose)} {puts "- $Drv(filei386:$f)$f";}
848 if {$Options(real)} {
849 exec rm $kpath$Drv(filei386:$f)$f;
850 }
851 }
852 foreach f $Drv(filesconf) {
853 if {$Options(verbose)} {puts "- $Drv(fileconf:$f)$f";}
854 if {$Options(real)} {
855 exec rm $kpath$Drv(fileconf:$f)$f;
856 }
857 }
858}
859
860################################################################################
861# unregisterDrvFiles
862#
863# Remove any mention of the current driver from the files.i386 and LINT
864# files in (ksrc)
865#
866proc unregisterDrvFiles {ksrc} {
867
868 global Drv Options;
869
870 if {$Options(verbose)} {puts "+ deregister driver files...";}
871
872 # don't really do it?
873 if {!$Options(real)} { return ; }
874
875 foreach f [list \
876 "i386/conf/files.i386" \
877 "i386/conf/options.i386" \
878 "i386/conf/LINT" \
879 "conf/files" \
880 "conf/options" ] {
881 set ifh [open $ksrc$f r];
882 set ofh [open $ksrc$f.new w];
883 set copying 1;
884
885 while {[gets $ifh line] >= 0} {
886
887 if {[scan $line "\#\# driver: %s" name] == 1} {
888 if {$name == $Drv(driver)} {
889 set copying 0; # don't copy this one
890 }
891 }
892 if {$copying} {
893 puts $ofh $line; # copy through
894 }
895 if {$line == "\#\# enddriver"} { # end of driver detail
896 set copying 1;
897 }
898 }
899 close $ifh;
900 close $ofh;
901 exec mv $ksrc$f.new $ksrc$f; # move new over old
902 }
903}
904
905################################################################################
906# usage
907#
908# Remind the user what goes where
909#
910proc usage {} {
911
912 global argv0;
913
914 set progname [file tail $argv0];
915
916 puts stderr "Usage is :";
917 puts stderr " $progname \[-v -n\] add <drvinfo> \[<kpath>\]";
918 puts stderr " $progname \[-v -n\] delete <drvname> \[<kpath>\]";
919 puts stderr " $progname \[-v\] list \[<kpath>\]";
920 puts stderr " <drvinfo> is a driver info file";
921 puts stderr " <drvname> is a driver name";
922 puts stderr " <kpath> is the path to the kernel source (default /sys/)";
923 puts stderr " -v be verbose";
924 puts stderr " -n don't actually do anything";
925 exit ;
926}
927
928################################################################################
929# getOptions
930#
931# Parse commandline options, return anything that doesn't look like an option
932#
933proc getOptions {} {
934
935 global argv Options;
936
937 set Options(real) 1;
938 set Options(verbose) 0;
939 set ret "";
940
941 for {set index 0} {$index < [llength $argv]} {incr index} {
942
943 switch -- [lindex $argv $index] {
944
945 -n {
946 set Options(real) 0; # 'do-nothing' mode
947 }
948 -v {
949 set Options(verbose) 1; # brag
950 }
951 default {
952 lappend ret [lindex $argv $index];
953 }
954 }
955 }
956 return $ret;
957}
958
959################################################################################
960# getKpath
961#
962# Given (hint), return the kernel path. If (hint) is empty, return /sys.
963# If the kernel path is not a directory, complain and dump the usage.
964#
965proc getKpath {hint} {
966
967 set kpath "";
968
969 # check the kernel path
970 if {$hint == ""} {
971 set kpath "/sys/";
972 } else {
973 set kpath $hint;
974 }
975 if {![file isdirectory $kpath]} {
976 puts "not a directory : $kpath";
977 usage ;
978 }
979 set plast [expr [string length $kpath] -1];
980 if {[string index $kpath $plast] != "/"} {
981 append kpath "/";
982 }
983 return $kpath;
984}
985
986################################################################################
987# main
988#
989# Start somewhere here.
990#
991proc main {} {
992
993 global Options;
994
995 # Work out what we're trying to do
996 set cmdline [getOptions];
997 set mode [lindex $cmdline 0];
998
999 # do stuff
1000 switch -- $mode {
1001 add {
1002 set hint [lindex $cmdline 1];
1003 set kpath [getKpath [lindex $cmdline 2]];
1004
1005 # check driver file argument
1006 if {[catch {set drv [findDrvFile $hint]} msg]} {
1007 puts stderr $msg;
1008 usage ;
1009 }
1010 if {([file type $drv] != "file") ||
1011 ![file readable $drv]} {
1012 puts "can't read driver file : $drv";
1013 usage ;
1014 }
1015 set drvdir "[file dirname $drv]/";
1016
1017 # read driver file
1018 if {[catch {readDrvFile $drv} msg]} {
1019 puts stderr $msg;
1020 exit ;
1021 }
1022 # validate driver
1023 if {[catch {validateDrvPackage $drvdir $kpath} msg]} {
1024 puts stderr $msg;
1025 exit ;
1026 }
1027 # install new files
1028 if {[catch {installDrvFiles $drvdir $kpath} msg]} {
1029 backoutDrvChanges $kpath; # oops, unwind
1030 puts stderr $msg;
1031 exit ;
1032 }
1033 # register files in config
1034 if {[catch {registerDrvFiles $kpath} msg]} {
1035 backoutDrvChanges $kpath; # oops, unwind
1036 puts stderr $msg;
1037 exit ;
1038 }
1039 }
1040 delete {
1041 set drv [lindex $cmdline 1];
1042 set kpath [getKpath [lindex $cmdline 2]];
1043
1044 if {[string last ".drvinfo" $drv] != -1} {
1045 set drv [string range $drv 0 [expr [string length $drv] - 9]];
1046 puts "Driver name ends in .drvinfo, removing, is now $drv";
1047 }
1048
1049 if {[catch {findInstalledDrv $drv $kpath} msg]} {
1050 puts stderr $msg;
1051 exit ;
1052 }
1053 if {[catch {validateDrvRemoval $kpath} msg]} {
1054 puts stderr $msg;
1055 exit ;
1056 }
1057 if {[catch {unregisterDrvFiles $kpath} msg]} {
1058 puts stderr $msg;
1059 exit ;
1060 }
1061 if {[catch {deleteDrvFiles $kpath} msg]} {
1062 puts stderr $msg;
1063 exit ;
1064 }
1065 }
1066 list {
1067 set kpath [getKpath [lindex $cmdline 1]];
1068 if {[catch {listInstalledDrv $kpath} msg]} {
1069 puts stderr "can't list drivers in '$kpath' : $msg";
1070 }
1071 }
1072 default {
1073 puts stderr "unknown command '$mode'";
1074 usage ;
1075 }
1076 }
1077}
1078
1079
1080
1081################################################################################
1082main;