#! /usr/local/bin/scotty -nf
## -*- tcl -*-
##
## This file contains a sample script to fill the bones database with
## already existing information, usually taken from nis aka yp maps.
##
## Copyright (c) 1995
##
## J. Schoenwaelder
## TU Braunschweig, Germany
## Institute for Operating Systems and Computer Networks
##
## Permission to use, copy, modify, and distribute this
## software and its documentation for any purpose and without
## fee is hereby granted, provided that the above copyright
## notice appear in all copies.  The University of Braunschweig
## makes no representations about the suitability of this
## software for any purpose.  It is provided "as is" without
## express or implied warranty.
##

##
## The following procs are used to read the information either
## from NIS (aka yp) files or from the /etc/ directory. The information
## is stored in some global arrays for later access.
##

proc forevery {var file body} {
    upvar $var line

    # check for yellow pages
    set noyp [catch {exec ypcat $file}]
    if {$noyp} {
	set f [open "/etc/$file" r]
	puts -nonewline stderr "Reading /etc/$file "
    } else {
	set f [open "|ypcat $file" r]
	puts -nonewline stderr "Reading YP $file "
    }
    while {[gets $f line] >= 0} {
	set line [string trim $line]
	if {$line == "" || [string index $line 0] == "#"} continue
	puts -nonewline stderr "."
	uplevel 1 $body
    }
    close $f
    puts stderr " done"
}

proc readLogins {} {
    global login
    forevery line passwd {
	set line [split $line :]
	set uid	[lindex $line 2]
	set login(name,$uid)	[lindex $line 0]
	set login(passwd,$uid)	[lindex $line 1]
	set login(uid,$uid)	[lindex $line 2]
	set login(gid,$uid)	[lindex $line 3]
	set login(gcos,$uid)	[lindex $line 4]
	set login(home,$uid)	[lindex $line 5]
	set login(shell,$uid)	[lindex $line 6]
    }
}

proc readGroups {} {
    global group
    forevery line group {
        set line [split $line :]
        set gid [lindex $line 2]
        set group(name,$gid)    [lindex $line 0]
        set group(passwd,$gid)  [lindex $line 1]
        set group(gid,$gid)     [lindex $line 2]
	if {[info exists group(user,$gid)]} {
	    set list [concat $group(user,$gid) [split [lindex $line 3] ,] ] 
	    set group(user,$gid)    $list
	} else {
	    set group(user,$gid)    [split [lindex $line 3] ,]
	}
    }
}

proc readNetworks {} {
    global network
    forevery line networks {
        set ip [lindex $line 0]
        set network(ip,$ip)	[lindex $line 0]
	set network(name,$ip)	[lindex $line 1]
        set network(alias,$ip)	[lrange $line 2 end]
    }
}

proc readHosts {} {
    global host
    forevery line hosts {
        set ip [lindex $line 0]
        set host(ip,$ip)	[lindex $line 0]
	set host(name,$ip)	[lindex $line 1]
        set host(alias,$ip)	[lrange $line 2 end]
    }
}

proc readServices {} {
    global service
    forevery line services {
        set port [lindex $line 1]
	set service(name,$port)		[lindex $line 0]
        set service(port,$port)		[lindex $line 1]
        set service(alias,$port)	[lrange $line 2 end]
    }
}

##
## Here are some procedures that create bones objects. There is
## one proc foreach class that will be set up with this script.
##

proc writeNetworks {} {
    global network
    puts -nonewline stderr "Network "
    set id 42
    foreach a [lsort [array names network]] {
	if {[string match "ip,*" $a]} {
	    puts -nonewline stderr "."
	    set a [lindex [split $a ,] 1]
	    set name $network(name,$a)
	    set address $network(ip,$a)
	    set aliases $network(alias,$a)
	    incr id
	    puts "insert into Network (id,name,address) \
		    values ($id,'$name','$address') \\g"
	}
    }
    puts stderr " done"
}

proc writeHosts {} {
    global host
    puts -nonewline stderr "Device Interface"
    set date [exec date]
    set devId 42
    set ifId 42
    foreach a [lsort [array names host]] {
        if {[string match "ip,*" $a]} {
            puts -nonewline stderr "."
            set a [lindex [split $a ,] 1]
	    set name $host(name,$a)
	    set address $host(ip,$a)
	    set os "unknown"
	    incr devId
	    incr ifId
	    puts "insert into Device (id,name,type) \
                    values ($devId, '$name','computer') \\g"
	    puts "insert into Interface (id,name,address,device) \
                    values ($ifId,'$name','$address',$devId) \\g"
        }
    }
    puts stderr " done"
}

proc writeGroup {} {
    global group
    puts -nonewline stderr "Group "
    foreach a [lsort [array names group]] {
	if {[string match "gid,*" $a]} {
	    puts -nonewline stderr "."
	    set a [lindex [split $a ,] 1]
	    set name $group(name,$a)
	    set id $group(gid,$a)
	    puts "insert into Group (id,name) values ($id,'$name') \\g"
	}
    }
    puts stderr " done"
}

proc writeLogin {} {
    global login group
    puts -nonewline stderr "Login Person "
    set perId 42
    foreach a [lsort [array names login]] {
	if {[string match "uid,*" $a]} {
	    puts -nonewline stderr "."
	    set a [lindex [split $a ,] 1]
	    set name $login(name,$a)
	    set passwd $login(passwd,$a)
	    set uid $login(uid,$a)
	    set home $login(home,$a)
	    set shell $login(shell,$a)
	    set gid $login(gid,$a)
	    puts "insert into Login \
		    (id,name,passwd,home,shell,group) \
                    values ($uid,'$name','$passwd','$home','$shell',$gid) \\g"
	    if {$login(gcos,$a) != ""} {
		set pname $login(gcos,$a)
		incr perId
		puts "insert into Person (id,name) \
			values ($perId,'$pname') \\g"
		puts "update Login set owner = $perId where id = $uid \\g"
	    }
	    set login(id,$name) $uid
	}
    }
    puts stderr " done"
}

proc writeGroupMember {} {
    global group login
    puts -nonewline stderr "Updating Group member "
    foreach a [lsort [array names group]] {
        if {[string match "gid,*" $a]} {
            set a [lindex [split $a ,] 1]
	    set gid $group(gid,$a)
	    set member ""
	    foreach l $group(user,$gid) {
		if {[info exists login(id,$l)]} {
		    lappend member $login(id,$l)
		}
	    }
	    if {$member == ""} continue
	    foreach uid $member {
		puts -nonewline stderr "."
		puts "insert into GroupMember (uid,gid) \
			values ($uid,$gid) \\g"
	    }
	}
    }
    puts stderr " done"
}

proc writeService {} {
    global service
    puts -nonewline stderr "Service "
    set id 0
    foreach a [lsort [array names service]] {
	if {[string match "port,*" $a]} {
	    puts -nonewline stderr "."
	    set a [lindex [split $a ,] 1]
	    set name $service(name,$a)
	    set port [lindex [split $service(port,$a) /] 0]
	    set protocol [lindex [split $service(port,$a) /] 1]
	    set aliases $service(alias,$a)
	    incr id
	    puts "insert into Service (id,name,protocol,port) \
		    values ($id,'$name','$protocol',$port) \\g"
	}
    }
    puts stderr " done"
}

##
## Here we start the whole thing. First, we read in all information
## available on this machine. Afterward, we clear/create all classes.
##

readLogins
readGroups
readNetworks
readHosts
readServices

writeNetworks
writeHosts
writeGroup
writeLogin
writeGroupMember
writeService

exit
