#!/bin/bash # mkatinit by Ivan Drucker, http://appleii.ivanx.com # not licensed; please modify and redistribute as you like # 1.0b4 1-30-11 # 1.1d1 -- uses bashByter. NOT TESTED. # This script creates the ATINIT file required for netbooting Apple IIe and # IIGS clients from a netatalk server. ATINIT is put in the in the # (sharename)/USERS hierarchy, or the current directory if it can't. # The user can specify the ProDOS startup system program and default prefix. # If an argument is supplied, it is used as the username and the prompt is # skipped. # The ATINIT file is not as complete as the ones generated by AppleShare 3.0, # and features such as default printer are not used. # to do # possibly require confirmation if AFPD_GUEST is not set correctly # or offer to change it # from ID-bashByter library decToChar () { # converts single-byte decimal value to equivalent character # arg: decimal number from 0-255 # out: one character #exit: 8=extraneous arg, 11=missing arg, 21=invalid arg [[ $1 ]] || return 11 [[ $2 ]] && return 8 [[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \ && ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21 # args are valid echo -n -e "\x$(printf %02X "$1")" } writechars () { # write one or more characters (bytes) to file # arg1: filename # arg2: (optional) offset (# of bytes to skip before writing) # arg3 OR stdin: sequence of characters # [stdin required if writing NUL (0) or trailing LF (0x0A) chars] # out: nothing # exit: 8=extraneous arg, 11=missing arg1, # 13=missing stdin/arg3, 22=invalid arg2 [[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; } [[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \ ( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } } [[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; } [[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; } # args are valid if [[ -t 0 ]]; then echo -n "$3" | \ dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null else dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null fi } #---- mkatinit starts here IFS='' #defaults sharepath=$(grep options:prodos /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f1) prefix=/$(grep options:prodos /usr/local/etc/netatalk/AppleVolumes.default | tail -1 | cut -d" " -f2) gsprefix=$prefix startprog="$prefix/BASIC.SYSTEM" gsstartprog="$prefix/SYSTEM/FINDER" filename="ATINIT" user=$(whoami) echo usersfolder=1 while [ -n "$1" ] && [ "${1:0:1}" = '-' ]; do flag="$1" if [ $flag = "-gs" ]; then gs=1 shift continue elif [ $flag = "-d" ]; then noprompt=1 shift continue elif [ $flag = "-f" ]; then overwrite=1 shift continue elif [ $flag = "-g" ]; then alsoguest=1 shift continue elif [ $flag = "-c" ]; then usersfolder=0 shift continue else badflag=1 break fi done if [ $usersfolder -eq 0 ] && [ -n "$alsoguest" ]; then badflag=1 fi if [ $badflag ]; then echo "usage: mkatinit [-gs] [-d] [-f] [-g | -c] [|guest]" echo echo " should be the name of a netatalk user, or 'guest'" echo "-gs sets the default ProDOS netboot system startup program and" echo " prefix for GS/OS (if omitted, ProDOS 8 defaults are used)" echo "-d use the default start program and prefix, without prompting" echo "-f overwrite existing ATINIT file if present, without warning" echo "-g create an ATINIT file for Guest as well as the specified user" echo "-c write ATNIT to current directory instead of USERS hierarchy" echo exit fi arg="$1" [[ -z $arg ]] && arg=$user while : ; do if [ ${#arg} -gt 32 ]; then echo "User name is too long. Exiting with no action." exit elif [ -n "$arg" ]; then if [ `echo $arg | tr '[:upper:]' '[:lower:]'` = "guest" ]; then username='' alsoguest= if [[ ! $(grep -F -s $(ls -1 /home) /etc/default/netatalk) ]]; then echo 'Warning: The AFPD_GUEST setting in /etc/default/netatalk is not assigned to a' echo 'user with a folder in /home. Guest users may be able to boot over the network' echo 'into ProDOS 8 for read-only access, but will not be able to boot into GS/OS.' if [ $gs ]; then echo ' Using ProDOS 8 defaults.' gs= else echo fi echo fi else username="$arg" if [[ ! $(ls -1 /home | grep -F -s $username) ]]; then echo "Warning: This username ($username) does not have a folder in /home. This user may" echo "not be able to boot over the network into ProDOS 8 or GS/OS." echo fi fi if [ $gs ]; then startprog="$gsstartprog" prefix="$gsprefix" fi fi # make username all caps username=`echo $username | tr '[:lower:]' '[:upper:]'` # prompt for folders if [ ! $doalsoguest ] && [ ! $noprompt ]; then while : ; do echo "Enter the ProDOS path to the startup system program." echo "default (CR to accept): $startprog" read if [ ${#REPLY} -gt 64 ]; then continue elif [ -n "$REPLY" ]; then startprog="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" echo fi break done while : ; do echo "Enter the initial ProDOS prefix:" echo "default (CR to accept): $prefix" read if [ ${#REPLY} -gt 64 ]; then continue elif [ -n "$REPLY" ]; then prefix="`echo $REPLY | tr '[:lower:]' '[:upper:]'`" echo fi break done fi # create folders if needed filepath="$PWD/$filename" while [ $usersfolder -eq 1 ]; do # create folders for ATINIT while [ ! -d "$sharepath" ]; do echo "Shared volume '$sharepath' not found. Edit mkatinit to change the default." echo "Enter the local path to the netatalk shared volume used for netboot:" read sharepath done if [ ! -d "$sharepath/USERS" ]; then mkdir "$sharepath/USERS" if [ $? -ne 0 ]; then break fi fi if [ ! -d "$sharepath/USERS/$username" ]; then mkdir "$sharepath/USERS/$username" if [ $? -ne 0 ]; then break fi fi if [ ! -d "$sharepath/USERS/$username/SETUP" ]; then mkdir "$sharepath/USERS/$username/SETUP" if [ $? -ne 0 ]; then break fi else if [ ! -w "$sharepath/USERS/$username/SETUP" ]; then break fi fi # we have a valid USERS folder target for ATINIT filepath="$sharepath/USERS/$username/SETUP/$filename" usersfolder=2 done if [ $usersfolder -eq 1 ]; then echo "Could not write to shared volume. Creating ATINIT in current directory." if [ -n "$alsoguest" ]; then echo "ATINIT for Guest user will not be created." fi echo alsoguest= fi if [ ! $doalsoguest ]; then echo "netboot start program: $startprog" echo "netboot start prefix : $prefix" echo fi #remove ATINIT if present if [ ! $overwrite ] && [ -f "$filepath" ]; then echo -n "$filepath already exists. Overwrite? " while read -s -n 1 > /dev/null 2>&1; do if [ -z "$REPLY" ]; then continue elif [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ]; then echo break elif [ "$REPLY" = "N" ] || [ "$REPLY" = "n" ]; then echo echo "Exiting with no action." exit fi done fi #write the file. start with zeroes dd if=/dev/zero of="$filepath" bs=1 count=276 2> /dev/null #put in startprog, prefix, username (first byte of each field is length) # ( echo -n "${#startprog}" | awk '{printf("%c",$0);}'; echo -n "$startprog"; ) | dd of="$filepath" bs=1 seek=7 conv=notrunc 2> /dev/null # ( echo -n "${#prefix}" | awk '{printf("%c",$0);}'; echo -n "$prefix"; ) | dd of="$filepath" bs=1 seek=78 conv=notrunc 2> /dev/null # ( echo -n "${#username}" | awk '{printf("%c",$0);}'; echo -n "$username"; ) | dd of="$filepath" bs=1 seek=143 conv=notrunc 2> /dev/null ( decToChar "${#startprog}"; echo -n "$startprog"; ) | writechars "$filepath" 7 ( decToChar "${#prefix}"; echo -n "$prefix"; ) | writechars "$filepath" 78 ( decToChar "${#username}"; echo -n "$username"; ) | writechars "$filepath" 143 echo "Created $filepath" if [ ! $alsoguest ]; then break fi if [ $usersfolder -eq 2 ]; then usersfolder=1 fi doalsoguest=1 arg='guest' done echo