1 #!/usr/bin/bash
   2 
   3 #
   4 # This file and its contents are supplied under the terms of the
   5 # Common Development and Distribution License ("CDDL"), version 1.0.
   6 # You may only use this file in accordance with the terms of version
   7 # 1.0 of the CDDL.
   8 #
   9 # A full copy of the text of the CDDL should have accompanied this
  10 # source.  A copy of the CDDL is also available via the Internet at
  11 # http://www.illumos.org/license/CDDL.
  12 #
  13 
  14 #
  15 # Copyright 2017 OmniTI Computer Consulting, Inc.  All rights reserved.
  16 #
  17 
  18 LOG_SETUP=0
  19 
  20 ConsoleLog(){
  21   exec 4>/dev/console
  22   exec 1>>${1}
  23   exec 2>>${1}
  24   INSTALL_LOG=${1}
  25   LOG_SETUP=1
  26 }
  27 CopyInstallLog(){
  28   if [[ -n "$INSTALL_LOG" ]]; then
  29     cp $INSTALL_LOG $ALTROOT/var/log/install/kayak.log
  30   fi
  31 }
  32 SendInstallLog(){
  33   PUTURL=`echo $CONFIG | sed -e 's%/kayak/%/kayaklog/%g;'`
  34   PUTURL=`echo $PUTURL | sed -e 's%/kayak$%/kayaklog%g;'`
  35   curl -T $INSTALL_LOG $PUTURL/$ETHER
  36 }
  37 OutputLog(){
  38   if [[ "$LOG_SETUP" -eq "0" ]]; then
  39     exec 4>/dev/null
  40     LOG_SETUP=1
  41   fi
  42 }
  43 log() {
  44   OutputLog
  45   TS=`date +%Y/%m/%d-%H:%M:%S`
  46   echo "[$TS] $*" 1>&4
  47   echo "[$TS] $*"
  48 }
  49 bomb() {
  50   log
  51   log ======================================================
  52   log "$*"
  53   log ======================================================
  54   if [[ -n "$INSTALL_LOG" ]]; then
  55   log "For more information, check $INSTALL_LOG"
  56   log ======================================================
  57   fi
  58   exit 1
  59 }
  60 
  61 . /kayak/net_help.sh
  62 . /kayak/disk_help.sh
  63 
  64 ICFILE=/tmp/_install_config
  65 getvar(){
  66   prtconf -v /devices | sed -n '/'$1'/{;n;p;}' | cut -f2 -d\'
  67 }
  68 
  69 # Blank
  70 ROOTPW='$5$kr1VgdIt$OUiUAyZCDogH/uaxH71rMeQxvpDEY2yX.x0ZQRnmeb9'
  71 RootPW(){
  72   ROOTPW="$1"
  73 }
  74 SetRootPW(){
  75   sed -i -e 's%^root::%root:'$ROOTPW':%' $ALTROOT/etc/shadow
  76 }
  77 ForceDHCP(){
  78   log "Forcing all interfaces into DHCP..."
  79   /sbin/ifconfig -a plumb 2> /dev/null
  80   # for the logs
  81   for iface in `/sbin/dladm show-phys -o device -p` ; do
  82     /sbin/ifconfig $iface dhcp &
  83   done
  84   while [[ -z $(/sbin/dhcpinfo BootSrvA) ]]; do
  85     log "Waiting for dhcpinfo..."
  86     sleep 1
  87   done
  88   BOOTSRVA=`/sbin/dhcpinfo BootSrvA`
  89   log "Next server: $BOOTSRVA"
  90   sleep 1
  91 }
  92 
  93 BuildBE() {
  94   RPOOL=${1:-rpool}
  95   if [[ -z $2 ]]; then
  96       BOOTSRVA=`/sbin/dhcpinfo BootSrvA`
  97       MEDIA=`getvar install_media`
  98       MEDIA=`echo $MEDIA | sed -e "s%//\:%//$BOOTSRVA\:%g;"`
  99       MEDIA=`echo $MEDIA | sed -e "s%///%//$BOOTSRVA/%g;"`
 100       DECOMP="bzip2 -dc"
 101       GRAB="curl -s"
 102   else
 103       # ASSUME $2 is a file path.  TODO: Parse the URL...
 104       MEDIA=$2
 105       # TODO: make switch statement based on $MEDIA's extension.
 106       # e.g. "bz2" ==> "bzip -dc", "7z" ==> 
 107       DECOMP="bzip2 -dc"
 108       GRAB=cat
 109   fi
 110   zfs set compression=on $RPOOL
 111   zfs create $RPOOL/ROOT
 112   zfs set canmount=off $RPOOL/ROOT
 113   zfs set mountpoint=legacy $RPOOL/ROOT
 114   log "Receiving image: $MEDIA"
 115   $GRAB $MEDIA | pv -B 128m -w 78 | $DECOMP | zfs receive -u $RPOOL/ROOT/omnios
 116   zfs set canmount=noauto $RPOOL/ROOT/omnios
 117   zfs set mountpoint=legacy $RPOOL/ROOT/omnios
 118   log "Cleaning up boot environment"
 119   beadm mount omnios /mnt
 120   ALTROOT=/mnt
 121   cp $ALTROOT/lib/svc/seed/global.db $ALTROOT/etc/svc/repository.db
 122   chmod 0600 $ALTROOT/etc/svc/repository.db
 123   chown root:sys $ALTROOT/etc/svc/repository.db
 124   /usr/sbin/devfsadm -r /mnt
 125   [[ -L $ALTROOT/dev/msglog ]] || \
 126     ln -s ../devices/pseudo/sysmsg@0:msglog $ALTROOT/dev/msglog
 127   MakeSwapDump
 128   zfs destroy $RPOOL/ROOT/omnios@kayak
 129 }
 130 
 131 FetchConfig(){
 132   ETHER=`Ether`
 133   BOOTSRVA=`/sbin/dhcpinfo BootSrvA`
 134   CONFIG=`getvar install_config`
 135   CONFIG=`echo $CONFIG | sed -e "s%//\:%//$BOOTSRVA\:%g;"`
 136   CONFIG=`echo $CONFIG | sed -e "s%///%//$BOOTSRVA/%g;"`
 137   L=${#ETHER}
 138   while [[ "$L" -gt "0" ]]; do
 139     URL="$CONFIG/${ETHER:0:$L}"
 140     log "... trying $URL"
 141     /bin/curl -s -o $ICFILE $URL
 142     if [[ -f $ICFILE ]]; then
 143       if [[ -n $(grep BuildRpool $ICFILE) ]]; then
 144         log "fetched config."
 145         return 0
 146       fi
 147       rm -f $ICFILE
 148     fi
 149     L=$(($L - 1))
 150   done
 151   return 1
 152 }
 153 
 154 MakeBootable(){
 155   RPOOL=${1:-rpool}
 156   log "Making boot environment bootable"
 157   zpool set bootfs=$RPOOL/ROOT/omnios rpool
 158   # Must do beadm activate first on the off chance we're bootstrapping from
 159   # GRUB.
 160   beadm activate omnios || return 1
 161 
 162   if [[ ! -z $1 ]]; then
 163       # Generate kayak-disk-list from zpool status.
 164       # NOTE: If this is something on non-s0 slices, the installboot below
 165       # will fail most likely, which is possibly a desired result.
 166       zpool list -v $RPOOL | egrep -v "NAME|rpool|mirror" | \
 167           awk '{print $1}' | sed -E 's/s0$//g' > /tmp/kayak-disk-list
 168   fi
 169 
 170   # NOTE:  This installboot loop assumes we're doing GPT whole-disk rpools.
 171   for i in `cat /tmp/kayak-disk-list`
 172   do
 173       installboot -mfF /boot/pmbr /boot/gptzfsboot /dev/rdsk/${i}s0 || return 1
 174   done
 175 
 176   bootadm update-archive -R $ALTROOT || return 1
 177   return 0
 178 }
 179 
 180 SetHostname()
 181 {
 182   log "Setting hostname: ${1}"
 183   /bin/hostname "$1"
 184   echo "$1" > $ALTROOT/etc/nodename
 185   head -n 26 $ALTROOT/etc/hosts > /tmp/hosts
 186   echo "::1\t\t$1" >> /tmp/hosts
 187   echo "127.0.0.1\t$1" >> /tmp/hosts
 188   cat /tmp/hosts > $ALTROOT/etc/hosts
 189 }
 190 
 191 AutoHostname() {
 192   suffix=$1
 193   macadr=`/sbin/ifconfig -a | \
 194           /usr/bin/awk '/UP/{if($2 !~ /LOOPBACK/){iface=$1;}} /ether/{if(iface){print $2; exit;}}' | \
 195           /bin/tr '[:upper:]' '[:lower:]' | \
 196           /bin/sed -e 's/^/ 0/g;s/:/-0/g; s/0\([0-9a-f][0-9a-f]\)/\1/g; s/ //g;'`
 197   [ -z $suffix ] && suffix=omnios
 198   [ "$suffix" == "-" ] && suffix= || suffix=-$suffix
 199   SetHostname $macadr$suffix
 200 }
 201 
 202 SetTimezone()
 203 {
 204   log "Setting timezone: ${1}"
 205   sed -i -e "s:^TZ=.*:TZ=${1}:" $ALTROOT/etc/default/init
 206 }
 207 
 208 SetLang()
 209 {
 210   log "Setting language: ${1}"
 211   sed -i -e "s:^LANG=.*:LANG=${1}:" $ALTROOT/etc/default/init
 212 }
 213 
 214 SetKeyboardLayout()
 215 {
 216       # Put the new keyboard layout ($1) in
 217       # "setprop keyboard-layout <foo>" in the newly-installed root's
 218       # /boot/solaris/bootenv.rc (aka. eeprom(1M) storage for amd64/i386).
 219       layout=$1
 220       sed "s/keyboard-layout Unknown/keyboard-layout $layout/g" \
 221           < $ALTROOT/boot/solaris/bootenv.rc > /tmp/bootenv.rc
 222       mv /tmp/bootenv.rc $ALTROOT/boot/solaris/bootenv.rc
 223       # Also modify the SMF manifest, assuming US-English was set by default.
 224       sed "s/US-English/$layout/g" \
 225          < $ALTROOT/lib/svc/manifest/system/keymap.xml > /tmp/keymap.xml
 226       cp -f /tmp/keymap.xml $ALTROOT/lib/svc/manifest/system/keymap.xml
 227 }
 228 
 229 ApplyChanges(){
 230   SetRootPW
 231   [[ -L $ALTROOT/etc/svc/profile/generic.xml ]] || \
 232     ln -s generic_limited_net.xml $ALTROOT/etc/svc/profile/generic.xml
 233   [[ -L $ALTROOT/etc/svc/profile/name_service.xml ]] || \
 234     ln -s ns_dns.xml $ALTROOT/etc/svc/profile/name_service.xml
 235 
 236   # Extras from interactive ISO/USB install...
 237   # arg1 == hostname
 238   if [[ ! -z $1 ]]; then
 239       SetHostname $1
 240   fi
 241 
 242   # arg2 == timezone
 243   if [[ ! -z $2 ]]; then
 244       SetTimezone $2
 245   fi
 246 
 247   # arg3 == Language
 248   if [[ ! -z $3 ]]; then
 249       SetLang $3
 250   fi
 251 
 252   # arg4 == Keyboard layout
 253   if [[ ! -z $4 ]]; then
 254       SetKeyboardLayout $4
 255   fi
 256 
 257   return 0
 258 }
 259 
 260 Postboot() {
 261   [[ -f $ALTROOT/.initialboot ]] || touch $ALTROOT/.initialboot
 262   echo "$*" >> $ALTROOT/.initialboot
 263 }
 264 
 265 Reboot() {
 266   # This is an awful hack... we already setup bootadm
 267   # and we've likely deleted enough of the userspace that this
 268   # can't run successfully... The easiest way to skip it is to
 269   # remove the binary
 270   rm -f /sbin/bootadm
 271   svccfg -s "system/boot-config:default" setprop config/fastreboot_default=false
 272   svcadm refresh svc:/system/boot-config:default
 273   reboot
 274 }
 275 
 276 RunInstall(){
 277   FetchConfig || bomb "Could not fetch kayak config for target"
 278   # Set RPOOL if it wasn't done so already. We need it set.
 279   RPOOL=${RPOOL:-rpool}
 280   . $ICFILE
 281   Postboot 'exit $SMF_EXIT_OK'
 282   ApplyChanges || bomb "Could not apply all configuration changes"
 283   MakeBootable || bomb "Could not make new BE bootable"
 284   log "Install complete"
 285   return 0
 286 }